├── assets
├── body.png
├── food.png
├── mask1.png
├── spyro.png
├── stats.png
├── azo-fire.png
├── short-stack.png
├── short-stack.xml
└── azo-fire.xml
├── .gitignore
├── README.md
├── src
├── test.js
├── boot.js
├── share.js
├── preloader.js
├── player.js
├── data.js
├── stats.js
├── mainmenu.js
├── game.js
└── snake.js
├── package.json
├── LICENSE
├── index.html
├── cert.pem
└── key.pem
/assets/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/body.png
--------------------------------------------------------------------------------
/assets/food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/food.png
--------------------------------------------------------------------------------
/assets/mask1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/mask1.png
--------------------------------------------------------------------------------
/assets/spyro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/spyro.png
--------------------------------------------------------------------------------
/assets/stats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/stats.png
--------------------------------------------------------------------------------
/assets/azo-fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/azo-fire.png
--------------------------------------------------------------------------------
/assets/short-stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phaserjs/facebook-instant-games/HEAD/assets/short-stack.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # System and IDE files
2 | Thumbs.db
3 | .DS_Store
4 | .idea
5 | .vscode
6 | *.suo
7 | *.sublime-project
8 | *.sublime-workspace
9 |
10 | # Vendors
11 | node_modules/
12 |
13 | # Build
14 | /npm-debug.log
15 | build/
16 | out/
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Phaser 3 Facebook Instant Games Examples
2 |
3 | The code in this repository is to go with the tutorial located at [http://phaser.io/tutorials/getting-started-facebook-instant-games/](http://phaser.io/tutorials/getting-started-facebook-instant-games/)
--------------------------------------------------------------------------------
/src/test.js:
--------------------------------------------------------------------------------
1 | this.add.text(0, 0).setText([
2 | 'Player ID: ' + this.facebook.playerID,
3 | 'Player Name: ' + this.facebook.playerName
4 | ]);
5 |
6 | this.facebook.loadPlayerPhoto(this, 'dude').once('photocomplete', this.addPlayerPhoto, this);
7 |
--------------------------------------------------------------------------------
/src/boot.js:
--------------------------------------------------------------------------------
1 | FBInstant.initializeAsync().then(function() {
2 |
3 | var config = {
4 | type: Phaser.CANVAS,
5 | width: 800,
6 | height: 600,
7 | backgroundColor: '#222448',
8 | scene: [ Preloader, GameShare ]
9 | };
10 |
11 | new Phaser.Game(config);
12 |
13 | });
14 |
--------------------------------------------------------------------------------
/src/share.js:
--------------------------------------------------------------------------------
1 | class GameShare extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super({ key: 'GameShare', active: false });
6 | }
7 |
8 | create ()
9 | {
10 | this.input.keyboard.on('keydown_P', function () {
11 | this.facebook.openRequest('Play this now!', 'spyro');
12 | }, this);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phaser-facebook-instant-games",
3 | "version": "1.0.0",
4 | "description": "Phaser Facebook Instant Games Examples",
5 | "main": "src/boot.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "scripts": {
10 | "start": "http-server --ssl -c-1 -p 8080 -a 127.0.0.1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/photonstorm/phaser-facebook-instant-games.git"
15 | },
16 | "author": "Richard Davey",
17 | "license": "MIT",
18 | "bugs": {
19 | "url": "https://github.com/photonstorm/phaser-facebook-instant-games/issues"
20 | },
21 | "homepage": "https://github.com/photonstorm/phaser-facebook-instant-games#readme",
22 | "dependencies": {
23 | "http-server": "^0.11.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/preloader.js:
--------------------------------------------------------------------------------
1 | class Preloader extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super('Preloader');
6 | }
7 |
8 | preload ()
9 | {
10 | this.facebook.showLoadProgress(this);
11 | this.facebook.once('startgame', this.startGame, this);
12 |
13 | this.load.image('spyro', 'assets/spyro.png');
14 | this.load.image('mask', 'assets/mask1.png');
15 | this.load.image('stats', 'assets/stats.png');
16 | this.load.bitmapFont('short', 'assets/short-stack.png', 'assets/short-stack.xml');
17 | this.load.bitmapFont('azo', 'assets/azo-fire.png', 'assets/azo-fire.xml');
18 |
19 | }
20 |
21 | startGame ()
22 | {
23 | // this.scene.start('MainMenu');
24 | // this.scene.start('PlayerDetails');
25 | // this.scene.start('GameStats');
26 | // this.scene.start('GameData');
27 | this.scene.start('GameShare');
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Richard Davey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Phaser 3 Facebook Instant Games Test 1
5 |
6 |
7 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDdTCCAl2gAwIBAgIJAJliW1PFjb1QMA0GCSqGSIb3DQEBCwUAMFExCzAJBgNV
3 | BAYTAlVTMRAwDgYDVQQIDAdBbGFiYW1hMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkx
4 | GTAXBgNVBAoMEFBob3RvbiBTdG9ybSBMdGQwHhcNMTgwNzI3MDM0NTE3WhcNMjEw
5 | NDIyMDM0NTE3WjBRMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHQWxhYmFtYTEVMBMG
6 | A1UEBwwMRGVmYXVsdCBDaXR5MRkwFwYDVQQKDBBQaG90b24gU3Rvcm0gTHRkMIIB
7 | IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfiyProDQh1QADYItWam3KkP
8 | zsMpCWsw16YSpvDNUvYiw0E3UKg0ZxNQ/c3tINZBl8UwZ7R6Y14zkpFjF2b4hv7Q
9 | v2W/nN2ZE/PyvDzy2rJOzzS7k4C2UHm2M1M8o3eZaa0WMZWoKPxcs3kepU5hmAjb
10 | 2UmNzecUVU1fBAznUlzmVziayN6K/fSHShMURsCspZJjxl+l3qZFgv8qGC4yBn2+
11 | H1pxiwyZ4bf3qzSCyOcsrqUr8Bfqj7O1vYOKVwNJKfG944IF/HsEuVd3TNK9vQGo
12 | qs0mhYAqcp+/Emkogddj1cSE70yrCnrBCM4/M0XT/EoTGS3k6zkjTOI9MI/4+wID
13 | AQABo1AwTjAdBgNVHQ4EFgQU0uc5mvzeYSdUE0nVv3Bcbt1cmncwHwYDVR0jBBgw
14 | FoAU0uc5mvzeYSdUE0nVv3Bcbt1cmncwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
15 | AQsFAAOCAQEAI1Js3M3hJ7m2XHFcHs5/Zfybms+sZRO3qlRjFkfU0jNfBnsJxh5P
16 | l2Gmze7eO84UOJJXcR5BApOQ2oDwSegW5AUg+NnLKNCRX2CLkPwHZu3sKGpkqaQ9
17 | ANXlCUVDxtMeCghXukfD/Ki2xBhuTpta9mVt4bscxCbtIe0qY8SDU6wJKaR9m+ls
18 | 7nBesyzfF0OD5J20/DgZuv5ZOunRFMupDpRNPXzryiTl2+Bzie0g90onn8eYLfuH
19 | QihgFjd/1/os4RRT3PkcvrvP/4hGNdsTqxlYx49H05IliYXaQzeO347L1hTlAKGr
20 | WfSDr2kQjIE8/i0Go1RVgCWnT8i6dvNemQ==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpAIBAAKCAQEAxfiyProDQh1QADYItWam3KkPzsMpCWsw16YSpvDNUvYiw0E3
3 | UKg0ZxNQ/c3tINZBl8UwZ7R6Y14zkpFjF2b4hv7Qv2W/nN2ZE/PyvDzy2rJOzzS7
4 | k4C2UHm2M1M8o3eZaa0WMZWoKPxcs3kepU5hmAjb2UmNzecUVU1fBAznUlzmVzia
5 | yN6K/fSHShMURsCspZJjxl+l3qZFgv8qGC4yBn2+H1pxiwyZ4bf3qzSCyOcsrqUr
6 | 8Bfqj7O1vYOKVwNJKfG944IF/HsEuVd3TNK9vQGoqs0mhYAqcp+/Emkogddj1cSE
7 | 70yrCnrBCM4/M0XT/EoTGS3k6zkjTOI9MI/4+wIDAQABAoIBAA+dQunBoBop17J8
8 | kIlGNGj5CJ8lM2pjwvFvTs9N9NPTSACgdy1sZt2uX1f1UvuhCoFe8ydqy7BksKqh
9 | vvAMlhOHq409CDTmIXm6Zu3D3N+06pRbM2Q55adJQj6gFQtLlpUIKtT0WdQJu4II
10 | Tot5OCdWo4hqzb1suWTU+maGYgRT3eSv0weiOAfgV6cxEYkG1UN27nl1dAizIRod
11 | xa/FUfAGQ5PkO1a/J+Y0pzu7AgopPPG38rQgZ9xQQRqS5iJf7uXFj70LDSMyQaxO
12 | 2M9Xp7JgVlPtIqIFRfaAoq+7NWX0W5reUt2qyiitXh6zb+1kTMYQ32/SBEPhtDm/
13 | zXcXLvECgYEA7JbqRjXPPLu0EIYwZMeKAIj92/KYbLnWSuTbO1V2gwjLTbRAs6Nv
14 | 2O2rIKvJgyptQuvIFF+ZLUGJomc6ze90uLxu+7Tv8TBh8W12U4TWqGC/gLI9astZ
15 | XqdnVX5MZRURevjQxC4Jf3mRkCVu96mtbi1qeZ8lbNAd3dOLHMwh8jkCgYEA1jav
16 | 6SE8ls9Ij1poqrza740kp4EsIgHwIZUiAsqw3Qh71OYh86Q7gI007yW9ORxCMO6m
17 | ZPhL083WNRKhpk1nYCeOq0Vc7k2jdSHBr1YNRFvo+XP1FdtWsES6QqIIzEgveKzq
18 | Wy1xu7aS+ekwTDOOrrE5kDsDdnn/+iwHYQdv9NMCgYEAxOTPsYCkqGmZ8EqMycJa
19 | MhnQExTxD0MVeRy+6sE0MNbHwzIoypdQxNr+mOD+gl9zsMbiqznoE4bAUVzRzoLi
20 | w79mKaoqKbJXQIIVgGpD7rsdhLBRdqgnByQQVlEWqOUAuDOMIkgh9Wmp36mXkRsv
21 | z0qSmwb8MXN995dO5bdo5NkCgYEAuiSZZfb4xH/pKJDChSNJCILYyCnKJN8UQMpr
22 | 3Isvd1Lo8E7uT951yjZqOinMLTVuG0E2HGVa1vl123aOO4nle7vEEPZcU8Ppd15X
23 | BTq8mptXbnUiEtUfllqSlFZjWMidX7q6h3KM8zYqr7m/u2fN4+WjBL8TOj+3fTgH
24 | TXx9//sCgYA0oJvGtyCyaFJBJEo/fR1D8710jTByQhLvDlRO+f9rXXXrYg/7PuoS
25 | iMPaHKhauyi+XNpZgnXYmkpEIympzdJdfZ/3zvWVER4+N676pJNz5yygkvBE3INK
26 | JinBW3sXzTF0WkXVrycD+mW3eLkOl1pdKC0fKwobQsB1nT6FOAawpQ==
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/src/player.js:
--------------------------------------------------------------------------------
1 | class PlayerDetails extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super({ key: 'PlayerDetails', active: false });
6 | }
7 |
8 | create ()
9 | {
10 | this.add.bitmapText(400, 400, 'azo', this.facebook.playerName).setOrigin(0.5);
11 |
12 | this.load.image('player', this.facebook.playerPhotoURL);
13 |
14 | this.load.once('filecomplete-image-player', this.addPlayerPhoto, this);
15 |
16 | // this.load.once('filecomplete-image-player', this.addRoundedPlayerPhoto, this);
17 | // this.load.once('filecomplete-image-player', this.addMaskedPlayerPhoto, this);
18 |
19 | this.load.start();
20 |
21 | // this.facebook.loadPlayerPhoto(this, 'player').once('photocomplete', this.addPlayerPhoto, this);
22 | }
23 |
24 | addPlayerPhoto (key)
25 | {
26 | this.add.image(400, 200, key);
27 | }
28 |
29 | addRoundedPlayerPhoto (key)
30 | {
31 | var photo = this.textures.createCanvas('playerMasked', 196, 196);
32 |
33 | var source = this.textures.get('player').getSourceImage();
34 |
35 | photo.context.beginPath();
36 |
37 | photo.context.arc(98, 98, 98, 0, Math.PI * 2, false);
38 |
39 | photo.context.clip();
40 |
41 | photo.draw(0, 0, source);
42 |
43 | this.add.image(400, 200, 'playerMasked');
44 | }
45 |
46 | addMaskedPlayerPhoto (key)
47 | {
48 | var photo = this.textures.createCanvas('playerMasked', 196, 196);
49 |
50 | var source = this.textures.get('player').getSourceImage();
51 | var mask = this.textures.get('mask').getSourceImage();
52 |
53 | photo.draw(0, 0, mask);
54 |
55 | photo.context.globalCompositeOperation = 'source-in';
56 |
57 | photo.draw(0, 0, source);
58 |
59 | this.add.image(400, 200, 'playerMasked');
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | class GameData extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super({ key: 'GameData', active: false });
6 |
7 | this.mana;
8 | this.gems;
9 | }
10 |
11 | create ()
12 | {
13 | this.mana = this.add.text(20, 20, 'Mana: 0');
14 | this.gems = this.add.text(20, 80, 'Gems: 0');
15 |
16 | this.facebook.on('getdata', this.dataLoaded, this);
17 | this.facebook.on('savedata', this.dataSaved, this);
18 |
19 | this.facebook.on('getdatafail', function (error) {
20 | console.log('data failed', error);
21 | });
22 |
23 | this.facebook.on('savedatafail', function (error) {
24 | console.log('save data failed', error);
25 | });
26 |
27 | this.facebook.getData([ 'mana', 'gems', 'color', 'shaz', 'music' ]);
28 |
29 | this.input.keyboard.on('keydown_M', function () {
30 | this.facebook.data.values.mana += 10;
31 | }, this);
32 |
33 | this.input.keyboard.on('keydown_G', function () {
34 | this.facebook.data.values.gems++;
35 | }, this);
36 |
37 | this.input.keyboard.on('keydown_C', function () {
38 |
39 | this.facebook.saveData({
40 | mana: 10,
41 | gems: 4,
42 | music: 'rock'
43 | });
44 |
45 | }, this);
46 |
47 | /*
48 | this.input.keyboard.on('keydown_L', function () {
49 |
50 | console.log('load');
51 | this.facebook.getData([ 'mana', 'gems' ]).on('getdata', this.updateStats, this);
52 |
53 | }, this);
54 |
55 | this.input.keyboard.on('keydown_P', function () {
56 | this.facebook.openShare('Play this now!', 'zero2');
57 | }, this);
58 | */
59 | }
60 |
61 | dataLoaded (data)
62 | {
63 | console.log('data loaded', data);
64 |
65 | this.dataUpdated(data);
66 | }
67 |
68 | dataSaved (data)
69 | {
70 | console.log('data saved', data);
71 |
72 | this.dataUpdated(data);
73 | }
74 |
75 | dataUpdated (data)
76 | {
77 | if (data.mana)
78 | {
79 | this.mana.setText('Mana: ' + data.mana);
80 | }
81 |
82 | if (data.gems)
83 | {
84 | this.gems.setText('Gems: ' + data.gems);
85 | }
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/stats.js:
--------------------------------------------------------------------------------
1 | class GameStats extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super({ key: 'GameStats', active: false });
6 | }
7 |
8 | create ()
9 | {
10 | this.add.image(25, 100, 'stats').setOrigin(0);
11 | this.add.text(65 + 25, 120, this.facebook.playerName);
12 | // this.mana = this.add.text(280 + 25, 120, '0');
13 | // this.gems = this.add.text(470 + 25, 120, '0');
14 |
15 | // this.facebook.getData([ 'mana', 'gems' ]);
16 |
17 | // this.facebook.on('getdata', this.statsLoaded, this);
18 | // this.facebook.on('savedata', this.updateStats, this);
19 |
20 | this.facebook.on('savestats', this.statsSaved, this);
21 |
22 | this.facebook.on('getstats', this.statsLoaded, this);
23 |
24 | this.facebook.on('getstatsfail', function (error) {
25 | console.log('stats failed', error);
26 | });
27 |
28 | this.facebook.on('savestatsfail', function (error) {
29 | console.log('save stats failed', error);
30 | });
31 |
32 | this.input.keyboard.on('keydown_S', function () {
33 | console.log('save1');
34 | this.facebook.saveStats({ level: 1, gold: 100, lives: 4 });
35 | }, this);
36 |
37 | this.input.keyboard.on('keydown_L', function () {
38 |
39 | console.log('load');
40 | this.facebook.getStats();
41 |
42 | }, this);
43 |
44 | this.input.keyboard.on('keydown_I', function () {
45 | this.facebook.incStats({ gold: 3 }).once('incstats', function (data) {
46 | console.log('stats modified', data);
47 | }, this);
48 | }, this);
49 |
50 | this.input.keyboard.on('keydown_K', function () {
51 | console.log('save2');
52 | this.facebook.saveStats({ level: 2, gold: 200, hp: 100, tommy: 33 });
53 | }, this);
54 |
55 | /*
56 | this.input.keyboard.on('keydown_L', function () {
57 |
58 | console.log('load');
59 | this.facebook.getData([ 'mana', 'gems' ]).on('getdata', this.updateStats, this);
60 |
61 | }, this);
62 |
63 | this.input.keyboard.on('keydown_M', function () {
64 | this.facebook.data.values.mana += 10;
65 | }, this);
66 |
67 | this.input.keyboard.on('keydown_G', function () {
68 | this.facebook.data.values.gems++;
69 | }, this);
70 |
71 | this.input.keyboard.on('keydown_S', function () {
72 | this.facebook.saveStats({ level: 2, gold: 1500, bullets: 500, bombs: 4, lives: 9, hp: 100, exp: 80, wisdom: 9, dex: 4 });
73 | }, this);
74 |
75 | this.input.keyboard.on('keydown_T', function () {
76 | this.facebook.getStats(['gold']).once('getstats', function (data) {
77 | console.log('stats loaded', data);
78 | }, this);
79 | }, this);
80 |
81 | this.input.keyboard.on('keydown_I', function () {
82 | this.facebook.incStats({ gold: 50, hp: -1 }).once('incstats', function (data) {
83 | console.log('stats modified', data);
84 | }, this);
85 | }, this);
86 |
87 | this.input.keyboard.on('keydown_P', function () {
88 | this.facebook.openShare('Play this now!', 'zero2');
89 | }, this);
90 | */
91 | }
92 |
93 | statsLoaded (data)
94 | {
95 | console.log('stats loaded', data);
96 | }
97 |
98 | statsSaved (data)
99 | {
100 | console.log('stats saved', data);
101 | }
102 |
103 | statsUpdated (data)
104 | {
105 | console.log('stats updated', data);
106 |
107 | // if (data.mana)
108 | // {
109 | // this.mana.setText(data.mana);
110 | // }
111 |
112 | // if (data.gems)
113 | // {
114 | // this.gems.setText(data.gems);
115 | // }
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/mainmenu.js:
--------------------------------------------------------------------------------
1 | class MainMenu extends Phaser.Scene {
2 |
3 | constructor ()
4 | {
5 | super({ key: 'MainMenu', active: false });
6 |
7 | this.leaderboard;
8 | this.mana;
9 | this.gems;
10 | }
11 |
12 | create ()
13 | {
14 | this.add.image((this.sys.game.config.width / 2) - 80, this.sys.game.config.height / 2, 'zero2');
15 |
16 | this.add.text(0, 0).setText([
17 | 'Player ID: ' + this.facebook.playerID,
18 | 'Player Name: ' + this.facebook.playerName
19 | ]);
20 |
21 | // 1012910592203052_1042671442560300
22 |
23 | this.facebook.once('getleaderboard', function (leaderboard)
24 | {
25 | this.leaderboard = leaderboard;
26 |
27 | console.log(leaderboard);
28 |
29 | leaderboard.getPlayerScore();
30 |
31 | this.input.keyboard.on('keydown_S', function () {
32 | console.log('save score');
33 | leaderboard.setScore(16, '{race: "elf", level: 3}');
34 | }, this);
35 |
36 | }, this);
37 |
38 | this.facebook.getLeaderboard('test1');
39 |
40 | this.facebook.preloadAds('1012910592203052_1042671442560300');
41 |
42 | this.facebook.loadPlayerPhoto(this, 'dude').once('photocomplete', this.addPlayerPhoto, this);
43 |
44 | /*
45 | this.add.image(50, 100, 'stats').setOrigin(0);
46 | this.add.text(65 + 50, 120, this.facebook.playerName);
47 | this.mana = this.add.text(280 + 50, 120, '0');
48 | this.gems = this.add.text(470 + 50, 120, '0');
49 |
50 | this.facebook.getData([ 'mana', 'gems' ]);
51 | this.facebook.on('getdata', this.updateStats, this);
52 | this.facebook.on('savedata', this.updateStats, this);
53 |
54 | this.input.keyboard.on('keydown_L', function () {
55 |
56 | console.log('load');
57 | this.facebook.getData([ 'mana', 'gems' ]).on('getdata', this.updateStats, this);
58 |
59 | }, this);
60 |
61 | this.input.keyboard.on('keydown_M', function () {
62 | this.facebook.data.values.mana += 10;
63 | }, this);
64 |
65 | this.input.keyboard.on('keydown_G', function () {
66 | this.facebook.data.values.gems++;
67 | }, this);
68 |
69 | this.input.keyboard.on('keydown_S', function () {
70 | this.facebook.saveStats({ level: 2, gold: 1500, bullets: 500, bombs: 4, lives: 9, hp: 100, exp: 80, wisdom: 9, dex: 4 });
71 | }, this);
72 |
73 | this.input.keyboard.on('keydown_T', function () {
74 | this.facebook.getStats(['gold']).once('getstats', function (data) {
75 | console.log('stats loaded', data);
76 | }, this);
77 | }, this);
78 |
79 | this.input.keyboard.on('keydown_I', function () {
80 | this.facebook.incStats({ gold: 50, hp: -1 }).once('incstats', function (data) {
81 | console.log('stats modified', data);
82 | }, this);
83 | }, this);
84 |
85 | this.input.keyboard.on('keydown_P', function () {
86 | this.facebook.openShare('Play this now!', 'zero2');
87 | }, this);
88 | */
89 | }
90 |
91 | updateStats (data)
92 | {
93 | console.log('stats', data);
94 |
95 | if (data.mana)
96 | {
97 | this.mana.setText(data.mana);
98 | }
99 |
100 | if (data.gems)
101 | {
102 | this.gems.setText(data.gems);
103 | }
104 | }
105 |
106 | addPlayerPhoto (key)
107 | {
108 | console.log('addplayerphoto');
109 |
110 | var photo = this.add.image(this.sys.game.config.width / 2, 700, key);
111 |
112 | photo.setInteractive();
113 |
114 | photo.on('pointerup', function () {
115 |
116 | // this.facebook.data.set('mana', 2000);
117 | // this.facebook.data.set('gems', 43);
118 |
119 | console.log('savedata');
120 |
121 | this.facebook.saveData({
122 | 'mana': 2000,
123 | 'gems': 45
124 | });
125 |
126 | }, this);
127 | }
128 |
129 | }
130 |
131 | console.log('menu');
132 |
--------------------------------------------------------------------------------
/assets/short-stack.xml:
--------------------------------------------------------------------------------
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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/game.js:
--------------------------------------------------------------------------------
1 | FBInstant.initializeAsync().then(function() {
2 |
3 | FBInstant.setLoadingProgress(100);
4 |
5 | FBInstant.startGameAsync().then(function() {
6 |
7 | var config = {
8 | type: Phaser.AUTO,
9 | width: window.innerWidth,
10 | height: window.innerHeight,
11 | backgroundColor: '#bfcc00',
12 | scene: {
13 | preload: preload,
14 | create: create,
15 | update: update
16 | }
17 | };
18 |
19 | var snake;
20 | var food;
21 | var gridWidth = Phaser.Math.Snap.Floor(window.innerWidth, 16) / 16;
22 | var gridHeight = Phaser.Math.Snap.Floor(window.innerHeight, 16) / 16;
23 |
24 | // Direction consts
25 | var UP = 0;
26 | var DOWN = 1;
27 | var LEFT = 2;
28 | var RIGHT = 3;
29 |
30 | new Phaser.Game(config);
31 |
32 | function preload ()
33 | {
34 | this.load.image('food', 'assets/food.png');
35 | this.load.image('body', 'assets/body.png');
36 | }
37 |
38 | function create ()
39 | {
40 | var Food = new Phaser.Class({
41 |
42 | Extends: Phaser.GameObjects.Image,
43 |
44 | initialize:
45 |
46 | function Food (scene, x, y)
47 | {
48 | Phaser.GameObjects.Image.call(this, scene)
49 |
50 | this.setTexture('food');
51 | this.setPosition(x * 16, y * 16);
52 | this.setOrigin(0);
53 |
54 | this.total = 0;
55 |
56 | scene.children.add(this);
57 | },
58 |
59 | eat: function ()
60 | {
61 | this.total++;
62 | }
63 |
64 | });
65 |
66 | var Snake = new Phaser.Class({
67 |
68 | initialize:
69 |
70 | function Snake (scene, x, y)
71 | {
72 | this.headPosition = new Phaser.Geom.Point(x, y);
73 |
74 | this.body = scene.add.group();
75 |
76 | this.head = this.body.create(x * 16, y * 16, 'body');
77 | this.head.setOrigin(0);
78 |
79 | this.alive = true;
80 |
81 | this.speed = 100;
82 |
83 | this.moveTime = 0;
84 |
85 | this.tail = new Phaser.Geom.Point(x, y);
86 |
87 | this.heading = RIGHT;
88 | this.direction = RIGHT;
89 | },
90 |
91 | update: function (time)
92 | {
93 | if (time >= this.moveTime)
94 | {
95 | return this.move(time);
96 | }
97 | },
98 |
99 | faceLeft: function ()
100 | {
101 | if (this.direction === UP || this.direction === DOWN)
102 | {
103 | this.heading = LEFT;
104 | }
105 | },
106 |
107 | faceRight: function ()
108 | {
109 | if (this.direction === UP || this.direction === DOWN)
110 | {
111 | this.heading = RIGHT;
112 | }
113 | },
114 |
115 | faceUp: function ()
116 | {
117 | if (this.direction === LEFT || this.direction === RIGHT)
118 | {
119 | this.heading = UP;
120 | }
121 | },
122 |
123 | faceDown: function ()
124 | {
125 | if (this.direction === LEFT || this.direction === RIGHT)
126 | {
127 | this.heading = DOWN;
128 | }
129 | },
130 |
131 | move: function (time)
132 | {
133 | /**
134 | * Based on the heading property (which is the direction the pgroup pressed)
135 | * we update the headPosition value accordingly.
136 | *
137 | * The Math.wrap call allow the snake to wrap around the screen, so when
138 | * it goes off any of the sides it re-appears on the other.
139 | */
140 | switch (this.heading)
141 | {
142 | case LEFT:
143 | this.headPosition.x = Phaser.Math.Wrap(this.headPosition.x - 1, 0, gridWidth);
144 | break;
145 |
146 | case RIGHT:
147 | this.headPosition.x = Phaser.Math.Wrap(this.headPosition.x + 1, 0, gridWidth);
148 | break;
149 |
150 | case UP:
151 | this.headPosition.y = Phaser.Math.Wrap(this.headPosition.y - 1, 0, gridHeight);
152 | break;
153 |
154 | case DOWN:
155 | this.headPosition.y = Phaser.Math.Wrap(this.headPosition.y + 1, 0, gridHeight);
156 | break;
157 | }
158 |
159 | this.direction = this.heading;
160 |
161 | // Update the body segments and place the last coordinate into this.tail
162 | Phaser.Actions.ShiftPosition(this.body.getChildren(), this.headPosition.x * 16, this.headPosition.y * 16, 1, this.tail);
163 |
164 | // Check to see if any of the body pieces have the same x/y as the head
165 | // If they do, the head ran into the body
166 |
167 | var hitBody = Phaser.Actions.GetFirst(this.body.getChildren(), { x: this.head.x, y: this.head.y }, 1);
168 |
169 | if (hitBody)
170 | {
171 | console.log('dead');
172 |
173 | this.alive = false;
174 |
175 | return false;
176 | }
177 | else
178 | {
179 | // Update the timer ready for the next movement
180 | this.moveTime = time + this.speed;
181 |
182 | return true;
183 | }
184 | },
185 |
186 | grow: function ()
187 | {
188 | var newPart = this.body.create(this.tail.x, this.tail.y, 'body');
189 |
190 | newPart.setOrigin(0);
191 | },
192 |
193 | collideWithFood: function (food)
194 | {
195 | if (this.head.x === food.x && this.head.y === food.y)
196 | {
197 | this.grow();
198 |
199 | food.eat();
200 |
201 | // For every 5 items of food eaten we'll increase the snake speed a little
202 | if (this.speed > 20 && food.total % 5 === 0)
203 | {
204 | this.speed -= 5;
205 | }
206 |
207 | return true;
208 | }
209 | else
210 | {
211 | return false;
212 | }
213 | },
214 |
215 | updateGrid: function (grid)
216 | {
217 | // Remove all body pieces from valid positions list
218 | this.body.children.each(function (segment) {
219 |
220 | var bx = segment.x / 16;
221 | var by = segment.y / 16;
222 |
223 | grid[by][bx] = false;
224 |
225 | });
226 |
227 | return grid;
228 | }
229 |
230 | });
231 |
232 | food = new Food(this, 3, 4);
233 |
234 | snake = new Snake(this, 8, 8);
235 |
236 | /**
237 | * Check which direction is pressed, and then change the direction the snake
238 | * is heading based on that. The checks ensure you don't double-back
239 | * on yourself, for example if you're moving to the right and you press
240 | * the LEFT cursor, it ignores it, because the only valid directions you
241 | * can move in at that time is up and down.
242 | */
243 | this.input.on('pointerdown', function (pointer) {
244 |
245 | if (!snake.alive)
246 | {
247 | return;
248 | }
249 |
250 | if (pointer.x < this.sys.game.config.width / 2)
251 | {
252 | // Left of the screen
253 | if (snake.heading === LEFT)
254 | {
255 | snake.faceDown();
256 | }
257 | else if (snake.heading === RIGHT)
258 | {
259 | snake.faceUp();
260 | }
261 | else if (snake.heading === UP)
262 | {
263 | snake.faceLeft();
264 | }
265 | else if (snake.heading === DOWN)
266 | {
267 | snake.faceRight();
268 | }
269 | }
270 | else
271 | {
272 | // Right of the screen
273 | if (snake.heading === LEFT)
274 | {
275 | snake.faceUp();
276 | }
277 | else if (snake.heading === RIGHT)
278 | {
279 | snake.faceDown();
280 | }
281 | else if (snake.heading === UP)
282 | {
283 | snake.faceRight();
284 | }
285 | else if (snake.heading === DOWN)
286 | {
287 | snake.faceLeft();
288 | }
289 | }
290 |
291 | }, this);
292 | }
293 |
294 | function update (time, delta)
295 | {
296 | if (!snake.alive)
297 | {
298 | return;
299 | }
300 |
301 | if (snake.update(time))
302 | {
303 | // If the snake updated, we need to check for collision against food
304 |
305 | if (snake.collideWithFood(food))
306 | {
307 | repositionFood();
308 | }
309 | }
310 | }
311 |
312 | /**
313 | * We can place the food anywhere in our gridWidthxgridHeight grid
314 | * *except* on-top of the snake, so we need
315 | * to filter those out of the possible food locations.
316 | * If there aren't any locations left, they've won!
317 | *
318 | * @method repositionFood
319 | * @return {boolean} true if the food was placed, otherwise false
320 | */
321 | function repositionFood ()
322 | {
323 | // First create an array that assumes all positions
324 | // are valid for the new piece of food
325 |
326 | // A Grid we'll use to reposition the food each time it's eaten
327 | var testGrid = [];
328 |
329 | for (var y = 0; y < gridHeight; y++)
330 | {
331 | testGrid[y] = [];
332 |
333 | for (var x = 0; x < gridWidth; x++)
334 | {
335 | testGrid[y][x] = true;
336 | }
337 | }
338 |
339 | snake.updateGrid(testGrid);
340 |
341 | // Purge out false positions
342 | var validLocations = [];
343 |
344 | for (var y = 0; y < gridHeight; y++)
345 | {
346 | for (var x = 0; x < gridWidth; x++)
347 | {
348 | if (testGrid[y][x] === true)
349 | {
350 | // Is this position valid for food? If so, add it here ...
351 | validLocations.push({ x: x, y: y });
352 | }
353 | }
354 | }
355 |
356 | if (validLocations.length > 0)
357 | {
358 | // Use the RNG to pick a random food position
359 | var pos = Phaser.Math.RND.pick(validLocations);
360 |
361 | // And place it
362 | food.setPosition(pos.x * 16, pos.y * 16);
363 |
364 | return true;
365 | }
366 | else
367 | {
368 | return false;
369 | }
370 | }
371 |
372 | });
373 |
374 | });
375 |
--------------------------------------------------------------------------------
/src/snake.js:
--------------------------------------------------------------------------------
1 | // https://www.facebook.com/embed/instantgames/1012910592203052/player?game_url=https://localhost:8080
2 |
3 | FBInstant.initializeAsync().then(function() {
4 |
5 | FBInstant.setLoadingProgress(100);
6 |
7 | FBInstant.startGameAsync().then(function() {
8 |
9 | var config = {
10 | type: Phaser.AUTO,
11 | width: window.innerWidth,
12 | height: window.innerHeight,
13 | backgroundColor: '#bfcc00',
14 | scene: {
15 | preload: preload,
16 | create: create,
17 | update: update
18 | }
19 | };
20 |
21 | var snake;
22 | var food;
23 | var gridWidth = Phaser.Math.Snap.Floor(window.innerWidth, 16) / 16;
24 | var gridHeight = Phaser.Math.Snap.Floor(window.innerHeight, 16) / 16;
25 |
26 | // Direction consts
27 | var UP = 0;
28 | var DOWN = 1;
29 | var LEFT = 2;
30 | var RIGHT = 3;
31 |
32 | new Phaser.Game(config);
33 |
34 | function preload ()
35 | {
36 | this.load.image('food', 'assets/food.png');
37 | this.load.image('body', 'assets/body.png');
38 | }
39 |
40 | function create ()
41 | {
42 | var Food = new Phaser.Class({
43 |
44 | Extends: Phaser.GameObjects.Image,
45 |
46 | initialize:
47 |
48 | function Food (scene, x, y)
49 | {
50 | Phaser.GameObjects.Image.call(this, scene)
51 |
52 | this.setTexture('food');
53 | this.setPosition(x * 16, y * 16);
54 | this.setOrigin(0);
55 |
56 | this.total = 0;
57 |
58 | scene.children.add(this);
59 | },
60 |
61 | eat: function ()
62 | {
63 | this.total++;
64 | }
65 |
66 | });
67 |
68 | var Snake = new Phaser.Class({
69 |
70 | initialize:
71 |
72 | function Snake (scene, x, y)
73 | {
74 | this.headPosition = new Phaser.Geom.Point(x, y);
75 |
76 | this.body = scene.add.group();
77 |
78 | this.head = this.body.create(x * 16, y * 16, 'body');
79 | this.head.setOrigin(0);
80 |
81 | this.alive = true;
82 |
83 | this.speed = 100;
84 |
85 | this.moveTime = 0;
86 |
87 | this.tail = new Phaser.Geom.Point(x, y);
88 |
89 | this.heading = RIGHT;
90 | this.direction = RIGHT;
91 | },
92 |
93 | update: function (time)
94 | {
95 | if (time >= this.moveTime)
96 | {
97 | return this.move(time);
98 | }
99 | },
100 |
101 | faceLeft: function ()
102 | {
103 | if (this.direction === UP || this.direction === DOWN)
104 | {
105 | this.heading = LEFT;
106 | }
107 | },
108 |
109 | faceRight: function ()
110 | {
111 | if (this.direction === UP || this.direction === DOWN)
112 | {
113 | this.heading = RIGHT;
114 | }
115 | },
116 |
117 | faceUp: function ()
118 | {
119 | if (this.direction === LEFT || this.direction === RIGHT)
120 | {
121 | this.heading = UP;
122 | }
123 | },
124 |
125 | faceDown: function ()
126 | {
127 | if (this.direction === LEFT || this.direction === RIGHT)
128 | {
129 | this.heading = DOWN;
130 | }
131 | },
132 |
133 | move: function (time)
134 | {
135 | /**
136 | * Based on the heading property (which is the direction the pgroup pressed)
137 | * we update the headPosition value accordingly.
138 | *
139 | * The Math.wrap call allow the snake to wrap around the screen, so when
140 | * it goes off any of the sides it re-appears on the other.
141 | */
142 | switch (this.heading)
143 | {
144 | case LEFT:
145 | this.headPosition.x = Phaser.Math.Wrap(this.headPosition.x - 1, 0, gridWidth);
146 | break;
147 |
148 | case RIGHT:
149 | this.headPosition.x = Phaser.Math.Wrap(this.headPosition.x + 1, 0, gridWidth);
150 | break;
151 |
152 | case UP:
153 | this.headPosition.y = Phaser.Math.Wrap(this.headPosition.y - 1, 0, gridHeight);
154 | break;
155 |
156 | case DOWN:
157 | this.headPosition.y = Phaser.Math.Wrap(this.headPosition.y + 1, 0, gridHeight);
158 | break;
159 | }
160 |
161 | this.direction = this.heading;
162 |
163 | // Update the body segments and place the last coordinate into this.tail
164 | Phaser.Actions.ShiftPosition(this.body.getChildren(), this.headPosition.x * 16, this.headPosition.y * 16, 1, this.tail);
165 |
166 | // Check to see if any of the body pieces have the same x/y as the head
167 | // If they do, the head ran into the body
168 |
169 | var hitBody = Phaser.Actions.GetFirst(this.body.getChildren(), { x: this.head.x, y: this.head.y }, 1);
170 |
171 | if (hitBody)
172 | {
173 | console.log('dead');
174 |
175 | this.alive = false;
176 |
177 | return false;
178 | }
179 | else
180 | {
181 | // Update the timer ready for the next movement
182 | this.moveTime = time + this.speed;
183 |
184 | return true;
185 | }
186 | },
187 |
188 | grow: function ()
189 | {
190 | var newPart = this.body.create(this.tail.x, this.tail.y, 'body');
191 |
192 | newPart.setOrigin(0);
193 | },
194 |
195 | collideWithFood: function (food)
196 | {
197 | if (this.head.x === food.x && this.head.y === food.y)
198 | {
199 | this.grow();
200 |
201 | food.eat();
202 |
203 | // For every 5 items of food eaten we'll increase the snake speed a little
204 | if (this.speed > 20 && food.total % 5 === 0)
205 | {
206 | this.speed -= 5;
207 | }
208 |
209 | return true;
210 | }
211 | else
212 | {
213 | return false;
214 | }
215 | },
216 |
217 | updateGrid: function (grid)
218 | {
219 | // Remove all body pieces from valid positions list
220 | this.body.children.each(function (segment) {
221 |
222 | var bx = segment.x / 16;
223 | var by = segment.y / 16;
224 |
225 | grid[by][bx] = false;
226 |
227 | });
228 |
229 | return grid;
230 | }
231 |
232 | });
233 |
234 | food = new Food(this, 3, 4);
235 |
236 | snake = new Snake(this, 8, 8);
237 |
238 | /**
239 | * Check which direction is pressed, and then change the direction the snake
240 | * is heading based on that. The checks ensure you don't double-back
241 | * on yourself, for example if you're moving to the right and you press
242 | * the LEFT cursor, it ignores it, because the only valid directions you
243 | * can move in at that time is up and down.
244 | */
245 | this.input.on('pointerdown', function (pointer) {
246 |
247 | if (!snake.alive)
248 | {
249 | return;
250 | }
251 |
252 | if (pointer.x < this.sys.game.config.width / 2)
253 | {
254 | // Left of the screen
255 | if (snake.heading === LEFT)
256 | {
257 | snake.faceDown();
258 | }
259 | else if (snake.heading === RIGHT)
260 | {
261 | snake.faceUp();
262 | }
263 | else if (snake.heading === UP)
264 | {
265 | snake.faceLeft();
266 | }
267 | else if (snake.heading === DOWN)
268 | {
269 | snake.faceRight();
270 | }
271 | }
272 | else
273 | {
274 | // Right of the screen
275 | if (snake.heading === LEFT)
276 | {
277 | snake.faceUp();
278 | }
279 | else if (snake.heading === RIGHT)
280 | {
281 | snake.faceDown();
282 | }
283 | else if (snake.heading === UP)
284 | {
285 | snake.faceRight();
286 | }
287 | else if (snake.heading === DOWN)
288 | {
289 | snake.faceLeft();
290 | }
291 | }
292 |
293 | }, this);
294 | }
295 |
296 | function update (time, delta)
297 | {
298 | if (!snake.alive)
299 | {
300 | return;
301 | }
302 |
303 | if (snake.update(time))
304 | {
305 | // If the snake updated, we need to check for collision against food
306 |
307 | if (snake.collideWithFood(food))
308 | {
309 | repositionFood();
310 | }
311 | }
312 | }
313 |
314 | /**
315 | * We can place the food anywhere in our gridWidthxgridHeight grid
316 | * *except* on-top of the snake, so we need
317 | * to filter those out of the possible food locations.
318 | * If there aren't any locations left, they've won!
319 | *
320 | * @method repositionFood
321 | * @return {boolean} true if the food was placed, otherwise false
322 | */
323 | function repositionFood ()
324 | {
325 | // First create an array that assumes all positions
326 | // are valid for the new piece of food
327 |
328 | // A Grid we'll use to reposition the food each time it's eaten
329 | var testGrid = [];
330 |
331 | for (var y = 0; y < gridHeight; y++)
332 | {
333 | testGrid[y] = [];
334 |
335 | for (var x = 0; x < gridWidth; x++)
336 | {
337 | testGrid[y][x] = true;
338 | }
339 | }
340 |
341 | snake.updateGrid(testGrid);
342 |
343 | // Purge out false positions
344 | var validLocations = [];
345 |
346 | for (var y = 0; y < gridHeight; y++)
347 | {
348 | for (var x = 0; x < gridWidth; x++)
349 | {
350 | if (testGrid[y][x] === true)
351 | {
352 | // Is this position valid for food? If so, add it here ...
353 | validLocations.push({ x: x, y: y });
354 | }
355 | }
356 | }
357 |
358 | if (validLocations.length > 0)
359 | {
360 | // Use the RNG to pick a random food position
361 | var pos = Phaser.Math.RND.pick(validLocations);
362 |
363 | // And place it
364 | food.setPosition(pos.x * 16, pos.y * 16);
365 |
366 | return true;
367 | }
368 | else
369 | {
370 | return false;
371 | }
372 | }
373 |
374 | });
375 |
376 | });
377 |
--------------------------------------------------------------------------------
/assets/azo-fire.xml:
--------------------------------------------------------------------------------
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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
--------------------------------------------------------------------------------