├── src
├── react-app-env.d.ts
├── assets
│ ├── atlas
│ │ ├── player.png
│ │ ├── anims_ui.png
│ │ ├── anims_ui_frames
│ │ │ ├── dots.png
│ │ │ ├── material-icons.txt
│ │ │ ├── sound.png
│ │ │ ├── anims_ui.xcf
│ │ │ ├── computer.png
│ │ │ ├── fountain.png
│ │ │ ├── nosound.png
│ │ │ ├── bigcomputer.png
│ │ │ ├── fullscreen.png
│ │ │ ├── fullscreen2.png
│ │ │ └── purple_tile.png
│ │ ├── player_frames
│ │ │ ├── back-000.png
│ │ │ ├── back-001.png
│ │ │ ├── back-002.png
│ │ │ ├── left-000.png
│ │ │ ├── left-001.png
│ │ │ ├── left-002.png
│ │ │ ├── wave-000.png
│ │ │ ├── wave-001.png
│ │ │ ├── wave-002.png
│ │ │ ├── front-000.png
│ │ │ ├── front-001.png
│ │ │ ├── front-002.png
│ │ │ ├── right-000.png
│ │ │ ├── right-001.png
│ │ │ └── right-002.png
│ │ ├── player_watch_gif
│ │ │ ├── watch.gif
│ │ │ ├── watch.xcf
│ │ │ ├── watch-000.png
│ │ │ ├── watch-001.png
│ │ │ └── watch-002.png
│ │ ├── anims_ui.json
│ │ └── player.json
│ ├── fonts
│ │ ├── pixelop.png
│ │ ├── PixelOperator.ttf
│ │ └── pixelop.xml
│ ├── tilesets
│ │ ├── tileset.png
│ │ └── tileset_extruded.png
│ └── maps
│ │ ├── software_v.tmx
│ │ ├── university-new.tmx
│ │ └── software_v.json
├── setupTests.ts
├── App.test.tsx
├── index.tsx
├── index.css
├── scenes
│ ├── interactive
│ │ ├── factory.js
│ │ ├── door.js
│ │ ├── sign.js
│ │ └── player.js
│ ├── SoftwareScene.js
│ ├── OverWorldScene.js
│ └── base.js
├── store
│ ├── localStorage.js
│ ├── types.tsx
│ ├── utils.ts
│ └── index.tsx
├── components
│ ├── PhoneCall.tsx
│ ├── PhoneMail.tsx
│ ├── PhoneMessage.tsx
│ ├── PhoneContact.tsx
│ ├── NavBar.tsx
│ ├── PixelPhone.tsx
│ ├── PhoneWifi.tsx
│ ├── PhoneAim.tsx
│ └── ComputerScreen.tsx
├── PhaserGame.ts
├── App.css
├── config.ts
└── App.tsx
├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── manifest.json
└── index.html
├── .gitignore
├── tsconfig.json
├── LICENSE
├── package.json
└── README.md
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/assets/atlas/player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player.png
--------------------------------------------------------------------------------
/src/assets/fonts/pixelop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/fonts/pixelop.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui.png
--------------------------------------------------------------------------------
/src/assets/tilesets/tileset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/tilesets/tileset.png
--------------------------------------------------------------------------------
/src/assets/fonts/PixelOperator.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/fonts/PixelOperator.ttf
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/dots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/dots.png
--------------------------------------------------------------------------------
/src/assets/tilesets/tileset_extruded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/tilesets/tileset_extruded.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/material-icons.txt:
--------------------------------------------------------------------------------
1 | size 40
2 | padding 2
3 | rounded 2
4 | background #a9a9a9 transp 0.82
5 | foreground #861388
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/sound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/sound.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/back-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/back-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/back-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/back-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/back-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/back-002.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/left-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/left-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/left-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/left-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/left-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/left-002.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/wave-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/wave-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/wave-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/wave-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/wave-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/wave-002.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_watch_gif/watch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_watch_gif/watch.gif
--------------------------------------------------------------------------------
/src/assets/atlas/player_watch_gif/watch.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_watch_gif/watch.xcf
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/anims_ui.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/anims_ui.xcf
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/computer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/computer.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/fountain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/fountain.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/nosound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/nosound.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/front-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/front-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/front-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/front-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/front-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/front-002.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/right-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/right-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/right-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/right-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_frames/right-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_frames/right-002.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/bigcomputer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/bigcomputer.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/fullscreen.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/fullscreen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/fullscreen2.png
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui_frames/purple_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/anims_ui_frames/purple_tile.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_watch_gif/watch-000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_watch_gif/watch-000.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_watch_gif/watch-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_watch_gif/watch-001.png
--------------------------------------------------------------------------------
/src/assets/atlas/player_watch_gif/watch-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VBoureaud/CTFBourgPalette/HEAD/src/assets/atlas/player_watch_gif/watch-002.png
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom'
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | node_modules/*
3 | .expo/
4 | .expo/*
5 | package-lock.json
6 | __pycache__/
7 | npm-debug.*
8 | *.jks
9 | *.p8
10 | *.p12
11 | *.key
12 | *.mobileprovision
13 | *.orig.*
14 | web-build/
15 | web-report/
16 | dist/
17 |
18 | tmp.txt
19 |
20 | # macOS
21 | .DS_Store
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render, screen } from '@testing-library/react'
3 | import App from './App'
4 |
5 | test('renders learn react link', () => {
6 | render( )
7 | const linkElement = screen.getByText(/learn react/i)
8 | expect(linkElement).toBeInTheDocument()
9 | })
10 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import { GameContextProvider } from "./store";
6 |
7 | import './PhaserGame'
8 |
9 | ReactDOM.render(
10 |
11 |
12 |
13 |
14 | ,
15 | document.getElementById('root')
16 | )
17 |
18 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'PixelOp';
3 | src: url('./assets/fonts/PixelOperator.ttf') format('ttf');
4 | }
5 |
6 | body {
7 | margin: 0;
8 | font-family: 'PixelOp', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
9 | 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
10 | -webkit-font-smoothing: antialiased;
11 | -moz-osx-font-smoothing: grayscale;
12 | }
13 |
14 | code {
15 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
16 | }
17 |
18 | canvas {
19 | display: block;
20 | }
21 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "CTFB",
3 | "name": "CTFBourgPalette",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/src/scenes/interactive/factory.js:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser'
2 |
3 | import {Sign} from "./sign.js";
4 | import {Door} from "./door.js"
5 | import {Player} from "./player.js";
6 |
7 | // To be able to do scene.add.sign(...)
8 | Phaser.GameObjects.GameObjectFactory.register('sign', function (x, y, text, direction) {
9 | return new Sign(this.scene, x, y, text, direction);
10 | })
11 |
12 | // To be able to do scene.add.door(...)
13 | Phaser.GameObjects.GameObjectFactory.register('door', function (x, y, width, height, destination, link) {
14 | return new Door(this.scene, x, y, width, height, destination, link);
15 | })
16 |
17 | // To be able to do scene.add.player(...)
18 | Phaser.GameObjects.GameObjectFactory.register('player', function (x, y, texture, frame) {
19 | return new Player(this.scene, x, y, texture, frame);
20 | })
21 |
--------------------------------------------------------------------------------
/src/store/localStorage.js:
--------------------------------------------------------------------------------
1 | export const storageData = (key='auth', value) => {
2 | try {
3 | const jsonObj = JSON.stringify(value);
4 | localStorage.setItem(key, jsonObj);
5 | } catch(e) {
6 | // saving error
7 | console.log({ fail: e });
8 | }
9 | }
10 |
11 | export const getStorage = (key='auth') => {
12 | try {
13 | const localStorageAuth = localStorage.getItem(key)
14 | let storage = null;
15 | if (localStorageAuth) {
16 | storage = JSON.parse(localStorageAuth)
17 | }
18 | return storage;
19 | } catch(e) {
20 | // error reading value
21 | console.log({ fail: e });
22 | }
23 | }
24 |
25 | export const rmStorage = (key='auth') => {
26 | try {
27 | const localStorageAuth = localStorage.getItem(key)
28 | if (localStorageAuth) {
29 | localStorage.removeItem(key);
30 | }
31 | return true;
32 | } catch(e) {
33 | // error reading value
34 | console.log({ fail: e });
35 | }
36 | }
--------------------------------------------------------------------------------
/src/scenes/SoftwareScene.js:
--------------------------------------------------------------------------------
1 | import {BaseScene} from "./base.js";
2 |
3 | import Software from "../assets/maps/software_v.json";
4 |
5 | export default class SoftwareScene extends BaseScene {
6 |
7 | constructor() {
8 | super('SoftwareScene');
9 | }
10 |
11 | preload() {
12 | this.load.tilemapTiledJSON("SoftwareMap", Software);
13 | }
14 |
15 | create() {
16 | super.create("SoftwareMap");
17 |
18 | // Resize the world and camera bounds
19 | this.physics.world.setBounds(0, 0, 960, 768);
20 | this.cameras.main.setBounds(0, 0, 960, 768);
21 |
22 | // On scene switch (after entering through the door) display the walking UP texture
23 | this.events.on('create', () => {this.player.setTexture("atlas", "ariel-back")}, this);
24 | this.events.on('wake', () => {this.player.setTexture("atlas", "ariel-back")}, this);
25 |
26 | this.collide_with_world(); // Has to be called after the rest of the colliders are defined
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/scenes/interactive/door.js:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser'
2 |
3 | export class Door extends Phaser.GameObjects.Zone
4 | {
5 | constructor(scene, x, y, width, height, destination, link) {
6 | super(scene, x, y, width, height);
7 |
8 | // Tiled coordinate is of the bottom left of the object
9 | this.setOrigin(0, 1);
10 |
11 | // Add the GameObject and collider to the scene
12 | scene.add.existing(this);
13 | scene.physics.world.enable(this, 1); // 1 is for static body
14 |
15 | this.destination = destination;
16 | this.link = link;
17 | scene.physics.add.collider(scene.player, this, () => this.enterDoor(scene));
18 | }
19 |
20 | enterDoor(scene) {
21 | if (!scene.player.body.touching.none && scene.player.body.wasTouching.none) {
22 | scene.scene.switch(this.destination);
23 | /*if (this.link) {
24 | console.log(this.link);
25 | console.log(this.destination);
26 | //window.location.href = "./home#" + this.destination;
27 | } else {
28 | //scene.scene.switch(this.destination);
29 | }*/
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/PhoneCall.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { PhoneOutlined } from '@ant-design/icons';
4 |
5 | const styles = {
6 | tiled: {
7 | width: '100%',
8 | height: '100%',
9 | //background: 'blue',
10 | background: 'grey',
11 | display: 'flex',
12 | flexDirection: 'column',
13 | } as React.CSSProperties,
14 | content: {
15 | display: "flex",
16 | justifyContent: "center",
17 | fontFamily: "Roboto, sans-serif",
18 | color: "#041836",
19 | } as React.CSSProperties,
20 | };
21 |
22 | type PhoneCallType = {
23 | onClick?: Function;
24 | };
25 | type PhoneCallTiledType = {
26 | onClick?: Function;
27 | };
28 |
29 | function PhoneCall(props: PhoneCallType) {
30 | return (
31 |
32 |
33 | )
34 | }
35 |
36 | export const PhoneCallTiled = (props: PhoneCallTiledType) => {
37 | return (
38 |
42 | )
43 | }
44 |
45 | export default PhoneCall;
--------------------------------------------------------------------------------
/src/components/PhoneMail.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { MailOutlined } from '@ant-design/icons';
4 |
5 | const styles = {
6 | tiled: {
7 | width: '100%',
8 | height: '100%',
9 | //background: 'blue',
10 | background: 'grey',
11 | display: 'flex',
12 | flexDirection: 'column',
13 | } as React.CSSProperties,
14 | content: {
15 | display: "flex",
16 | justifyContent: "center",
17 | fontFamily: "Roboto, sans-serif",
18 | color: "#041836",
19 | } as React.CSSProperties,
20 | };
21 |
22 | type PhoneMailType = {
23 | onClick?: Function;
24 | };
25 | type PhoneMailTiledType = {
26 | onClick?: Function;
27 | };
28 |
29 | function PhoneMail(props: PhoneMailType) {
30 | return (
31 |
32 |
33 | )
34 | }
35 |
36 | export const PhoneMailTiled = (props: PhoneMailTiledType) => {
37 | return (
38 |
42 | )
43 | }
44 |
45 | export default PhoneMail;
--------------------------------------------------------------------------------
/src/components/PhoneMessage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { MessageOutlined } from '@ant-design/icons';
4 |
5 | const styles = {
6 | tiled: {
7 | width: '100%',
8 | height: '100%',
9 | //background: 'blue',
10 | background: 'grey',
11 | display: 'flex',
12 | flexDirection: 'column',
13 | } as React.CSSProperties,
14 | content: {
15 | display: "flex",
16 | justifyContent: "center",
17 | fontFamily: "Roboto, sans-serif",
18 | color: "#041836",
19 | } as React.CSSProperties,
20 | };
21 |
22 | type PhoneMessageType = {
23 | onClick?: Function;
24 | };
25 | type PhoneMessageTiledType = {
26 | onClick?: Function;
27 | };
28 |
29 | function PhoneMessage(props: PhoneMessageType) {
30 | return (
31 |
32 |
33 | )
34 | }
35 |
36 | export const PhoneMessageTiled = (props: PhoneMessageTiledType) => {
37 | return (
38 |
42 | )
43 | }
44 |
45 | export default PhoneMessage;
--------------------------------------------------------------------------------
/src/components/PhoneContact.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { ContactsOutlined } from '@ant-design/icons';
4 |
5 | const styles = {
6 | tiled: {
7 | width: '100%',
8 | height: '100%',
9 | //background: 'blue',
10 | background: 'grey',
11 | display: 'flex',
12 | flexDirection: 'column',
13 | } as React.CSSProperties,
14 | content: {
15 | display: "flex",
16 | justifyContent: "center",
17 | fontFamily: "Roboto, sans-serif",
18 | color: "#041836",
19 | } as React.CSSProperties,
20 | };
21 |
22 | type PhoneContactType = {
23 | onClick?: Function;
24 | };
25 | type PhoneContactTiledType = {
26 | onClick?: Function;
27 | };
28 |
29 | function PhoneContact(props: PhoneContactType) {
30 | return (
31 |
32 |
33 | )
34 | }
35 |
36 | export const PhoneContactTiled = (props: PhoneContactTiledType) => {
37 | return (
38 |
42 | )
43 | }
44 |
45 | export default PhoneContact;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Valentin Boureaud
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 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 | CTFBourgPalette
21 |
22 |
23 | You need to enable JavaScript to run this app.
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/scenes/OverWorldScene.js:
--------------------------------------------------------------------------------
1 | import {BaseScene} from "./base.js";
2 | import './interactive/factory.js'; // This has to run before the first scene in order to add the commands
3 |
4 | import TilesetImage from "../assets/tilesets/tileset_extruded.png";
5 | import OverWorld from "../assets/maps/overworld_v.json";
6 | import Player from "../assets/atlas/player.json";
7 | import PlayerImg from "../assets/atlas/player.png";
8 |
9 | export default class OverWorldScene extends BaseScene {
10 |
11 | constructor() {
12 | super('OverWorldScene');
13 | }
14 |
15 | preload() {
16 | // The keys have to be unique! Otherwise they will not be preloaded again.
17 | // this.load.image("OverworldTiles", "./assets/prod/tilesets_and_maps/tileset.png");
18 | this.load.image("TilesetImage", TilesetImage);
19 | this.load.tilemapTiledJSON("OverWorldMap", OverWorld);
20 | this.load.atlas("atlas", PlayerImg, Player);
21 | }
22 |
23 | create() {
24 | super.create("OverWorldMap");
25 |
26 | // Resize the world and camera bounds
27 | this.physics.world.setBounds(0, 0, 1920, 1088);
28 | this.cameras.main.setBounds(0, 0, 1920, 1088);
29 |
30 | this.collide_with_world(); // Has to be called after the rest of the colliders are defined
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/store/types.tsx:
--------------------------------------------------------------------------------
1 | export type User = {
2 | name: string;
3 | level: number;
4 | newLevel: boolean;
5 | loadingLevel: boolean;
6 | wifiKnow: string[];
7 | imsiHandler: number;
8 | }
9 |
10 | export type Quests = {
11 | [index: string]: Quest;
12 | }
13 |
14 | export type Quest = {
15 | level: number;
16 | title: string;
17 | desc: string;
18 | map: string;
19 | wifiKnow: string[];
20 | goalOrder: GoalObj;
21 | imsiHandler: boolean;
22 | success?: string;
23 | orderFix: boolean;
24 | }
25 |
26 | export type GoalObj = {
27 | [index: string]: {
28 | break?: boolean;
29 | method?: string;
30 | name?: string;
31 | optional?: boolean;
32 | computerScreen?: boolean;
33 | computerMode?: string;
34 | dialog?: string[];
35 | };
36 | }
37 |
38 | export type Objects = {
39 | [index: string]: {
40 | name: string;
41 | default: string;
42 | };
43 | }
44 |
45 | export type WifiType = {
46 | actif: boolean;
47 | name: string;
48 | pwd: string;
49 | coord: number[];
50 | devices?: Device[];
51 | };
52 |
53 | export type Device = {
54 | name: string;
55 | proba: number;
56 | ip: string;
57 | type: string;
58 | actif?: boolean;
59 | credentials?: string | string[];
60 | probaCredential?: number;
61 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CTFBourgPalette",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@ant-design/icons": "^4.7.0",
7 | "@testing-library/jest-dom": "^5.14.1",
8 | "@testing-library/react": "^12.0.0",
9 | "@testing-library/user-event": "^13.2.1",
10 | "@types/jest": "^27.0.1",
11 | "@types/node": "^16.7.13",
12 | "@types/react": "^17.0.20",
13 | "@types/react-dom": "^17.0.9",
14 | "antd": "^4.20.2",
15 | "chart.js": "^3.7.1",
16 | "nes.css": "^2.3.0",
17 | "phaser": "^3.55.2",
18 | "react": "^17.0.2",
19 | "react-chartjs-2": "^4.1.0",
20 | "react-dom": "^17.0.2",
21 | "react-scripts": "5.0.0",
22 | "typescript": "^4.4.2",
23 | "web-vitals": "^2.1.0"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject"
30 | },
31 | "eslintConfig": {
32 | "extends": [
33 | "react-app",
34 | "react-app/jest"
35 | ]
36 | },
37 | "browserslist": {
38 | "production": [
39 | ">0.2%",
40 | "not dead",
41 | "not op_mini all"
42 | ],
43 | "development": [
44 | "last 1 chrome version",
45 | "last 1 firefox version",
46 | "last 1 safari version"
47 | ]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/store/utils.ts:
--------------------------------------------------------------------------------
1 |
2 | export const calculateDistance = (player: number[], coord: number[]) => {
3 | const playerX = player[0];
4 | const playerY = player[1];
5 | const wifiX = coord[0];
6 | const wifiY = coord[1];
7 | const distance = Math.sqrt((Math.pow(wifiX-playerX,2))+(Math.pow(wifiY-playerY,2)));
8 | return 5 - parseInt('' + distance / 100);
9 | }
10 |
11 | export const getHour = () => {
12 | const d = new Date();
13 | const hour = ('0' + d.getHours()).slice(-2)
14 | + ':' + ('0' + d.getMinutes()).slice(-2);
15 | return hour;
16 | }
17 |
18 | export const displayDate = (dayToRm: number) => {
19 | const myDate = new Date();
20 | if (dayToRm)
21 | myDate.setDate(myDate.getDate() - dayToRm);
22 | const fullDate = ('0' + (myDate.getMonth() + 1)).slice(-2) + '/'
23 | + ('0' + myDate.getDate()).slice(-2) + '/' +
24 | + myDate.getFullYear();
25 | return fullDate;
26 | }
27 |
28 | export const shuffle = (array: any) => {
29 | let currentIndex = array.length, temporaryValue, randomIndex, arrayCopy;
30 |
31 | arrayCopy = array.slice();
32 | // While there remain elements to shuffle...
33 | while (0 !== currentIndex) {
34 |
35 | // Pick a remaining element...
36 | randomIndex = Math.floor(Math.random() * currentIndex);
37 | currentIndex -= 1;
38 |
39 | // And swap it with the current element.
40 | temporaryValue = arrayCopy[currentIndex];
41 | arrayCopy[currentIndex] = arrayCopy[randomIndex];
42 | arrayCopy[randomIndex] = temporaryValue;
43 | }
44 |
45 | return arrayCopy;
46 | }
47 |
48 | export const levelDisplay = (xp: number, coef: number, max?: number) => {
49 | if (xp === 0) return 0;
50 | const res = parseInt((coef * Math.log(xp)) + '');
51 | return max && res > max ? max : res;
52 | };
--------------------------------------------------------------------------------
/src/components/NavBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Typography } from "antd";
3 | const { Title } = Typography;
4 |
5 | const styles = {
6 | content: {
7 | display: "flex",
8 | justifyContent: "center",
9 | fontFamily: "Roboto, sans-serif",
10 | color: "#041836",
11 | } as React.CSSProperties,
12 | header: {
13 | position: "absolute",
14 | zIndex: 1,
15 | width: "100%",
16 | //background: "rgba(89, 89, 89, 0.74) none repeat scroll 0% 0%",
17 | padding: 0,
18 | } as React.CSSProperties,
19 | headerContainer: {
20 | padding: '10px',
21 | boxSizing: 'border-box',
22 | margin: 'auto',
23 | display: "flex",
24 | height: '100%',
25 | justifyContent: "space-between",
26 | alignItems: "center",
27 | //fontFamily: "Roboto, sans-serif",
28 | } as React.CSSProperties,
29 | rightHeader: {
30 | display: 'flex',
31 | alignItems: 'center'
32 | } as React.CSSProperties,
33 | btnBox: {
34 | position: 'relative',
35 | top: '12px',
36 | } as React.CSSProperties
37 | };
38 |
39 | type NavBarType = {
40 | onClick?: Function;
41 | };
42 |
43 | function NavBar(props: NavBarType) {
44 | return (
45 |
46 |
47 |
48 | CTFBourgPalette
49 |
50 |
props && props.onClick && props.onClick()} style={styles.rightHeader}>
51 |
52 | Menu
53 |
54 |
55 |
56 |
57 | )
58 | }
59 |
60 | export default NavBar;
--------------------------------------------------------------------------------
/src/components/PixelPhone.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const styles = {
4 | phone: {
5 | display: "flex",
6 | justifyContent: "space-between",
7 | flexDirection: "column",
8 | width: '100%',
9 | minWidth: '270px',
10 | maxWidth: '330px',
11 | height: '90vh',
12 | maxHeight: '600px',
13 | } as React.CSSProperties,
14 | lineHorizontal: {
15 | background: 'black',
16 | height: '3%',
17 | width: '95%',
18 | margin: 'auto',
19 | } as React.CSSProperties,
20 | containVertical: {
21 | background: "white",
22 | display: 'flex',
23 | justifyContent: 'space-between',
24 | height: '100%',
25 | } as React.CSSProperties,
26 | lineVertical: {
27 | background: 'black',
28 | width: '5%',
29 | height: '100%',
30 | } as React.CSSProperties,
31 | containScreen: {
32 | display: 'flex',
33 | alignItems: 'center',
34 | height: '100%',
35 | width: '100%',
36 | maxWidth: '273px',
37 | flexDirection: 'column',
38 | } as React.CSSProperties,
39 | soundBar: {
40 | margin: 'auto',
41 | background: 'black',
42 | width: '50%',
43 | height: '3%',
44 | } as React.CSSProperties,
45 | screen: {
46 | color: 'white',
47 | padding: '2%',
48 | boxSizing: 'border-box',
49 | background: 'black',
50 | width: '93%',
51 | height: '78%',
52 | } as React.CSSProperties,
53 | button: {
54 | margin: '4% 0',
55 | background: 'black',
56 | width: '10%',
57 | height: '5%',
58 | } as React.CSSProperties,
59 | };
60 |
61 | type PixelPhoneType = {
62 | children?: any;
63 | };
64 |
65 | function PixelPhone(props: PixelPhoneType) {
66 | return (
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | {props.children}
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | )
83 | }
84 |
85 | export default PixelPhone;
--------------------------------------------------------------------------------
/src/scenes/interactive/sign.js:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | export class Sign extends Phaser.GameObjects.Zone
4 | {
5 | constructor(scene, x, y, text, direction) {
6 | super(scene, x, y, 32, 32);
7 |
8 | // Add the GameObject and collider to the scene
9 | scene.add.existing(this).setOrigin(0, 1);
10 | scene.physics.world.enable(this, 1); // 1 is for static body
11 |
12 | // Direction
13 | this.direction = direction;
14 |
15 | // This assumes that the hitbox for the body is the same as the empty tile image (32 x 32), see door.js if not
16 | scene.physics.add.collider(scene.player, this, () => this.collideSign(scene.player));
17 |
18 | // By click or touch it activates within a given distance (clickRadius)
19 | // this.setInteractive().on('pointerdown', this.clickSign);
20 | this.clickRadius = 100;
21 | this.showByClick = false;
22 | this.text = text;
23 | this.activated = false;
24 | }
25 |
26 | collideSign(player) {
27 | if (!this.activated) {
28 | // Center hits from every direction
29 | if (this.direction === 'center') {
30 | this.showSignText();
31 | } else if (this.direction === 'left' && player.body.touching.left) {
32 | this.showSignText();
33 | } else if (this.direction === 'right' && player.body.touching.right) {
34 | this.showSignText();
35 | } else if (this.direction === 'up' && player.body.touching.up) {
36 | this.showSignText();
37 | } else if (this.direction === 'down' && player.body.touching.down) {
38 | this.showSignText();
39 | }
40 | }
41 | }
42 |
43 | showSignText() {
44 | this.scene.events.emit('sign', this.text);
45 | this.scene.showingSign = true; // A property of the scene, see BaseScene's update
46 | this.activated = true;
47 | }
48 |
49 | playerMovement(moveleft, moveright, moveup, movedown) {
50 | // A check for activated is done in BaseScene before calling this
51 | if (this.showByClick) {
52 | // If the player activated the sign via pointerdown, then remove it only when she goes away
53 | if (Phaser.Math.Distance.BetweenPoints(this.getCenter(), this.scene.player) > this.clickRadius) {
54 | this.hideSignText();
55 | }
56 | } else { // Otherwise, the player activated the sign via collision
57 | if (moveleft || moveright) {
58 | this.hideSignText();
59 | } else if (this.direction === 'up' && movedown) {
60 | this.hideSignText();
61 | } else if ((this.direction === 'down' || this.direction === 'center') && !movedown) {
62 | this.hideSignText();
63 | }
64 | }
65 | }
66 |
67 | hideSignText() {
68 | this.scene.events.emit('sign');
69 | this.scene.showingSign = false; // A property of the scene, see BaseScene's update
70 | this.activated = false;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/PhaserGame.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser'
2 |
3 | import configGlobal from './config';
4 | import OverWorldScene from './scenes/OverWorldScene'
5 | import SoftwareScene from './scenes/SoftwareScene'
6 |
7 | declare global {
8 | interface Window {
9 | mouseOverMenu:any;
10 | }
11 | }
12 |
13 | const config: Phaser.Types.Core.GameConfig = {
14 | title: configGlobal.game.name,
15 | version: configGlobal.version,
16 | type: Phaser.AUTO,
17 | parent: 'phaser-container',
18 | //backgroundColor: '#282c34',
19 | pixelArt: true,
20 | autoFocus: true,
21 | scale: {
22 | mode: Phaser.Scale.NONE,
23 | autoCenter: Phaser.Scale.NO_CENTER,
24 | width: getWidth(),
25 | height: getHeight(),
26 | zoom: (resizeDPR() ? Math.floor(window.devicePixelRatio) / window.devicePixelRatio : 1),
27 | },
28 | physics: {
29 | default: 'arcade',
30 | arcade: {
31 | debug: configGlobal.debug,
32 | gravity: { y: 0 },
33 | },
34 | },
35 | scene: [OverWorldScene, SoftwareScene],
36 | }
37 |
38 | const game = new Phaser.Game(config);
39 |
40 | // ------------------------------------------------------------------------------------
41 | // DevicePixelRatio handling
42 |
43 | function mobileOrTablet() {
44 | if (navigator.userAgent.match(/Android/i)
45 | || navigator.userAgent.match(/webOS/i)
46 | || navigator.userAgent.match(/iPhone/i)
47 | || navigator.userAgent.match(/iPad/i)
48 | || navigator.userAgent.match(/iPod/i)
49 | || navigator.userAgent.match(/BlackBerry/i)
50 | || navigator.userAgent.match(/Windows Phone/i))
51 | return true;
52 | return false;
53 | }
54 | function resizeDPR() {
55 | // Integer DPR return false
56 | if (Number.isInteger(window.devicePixelRatio)) {
57 | return false
58 | // Non-mobile, non-integer DPR between 1 and 2 (e.g. my laptop screen on Win has 1.25), return true
59 | } else if (!mobileOrTablet() && 1 < window.devicePixelRatio && window.devicePixelRatio < 2) {
60 | return true
61 | // Everything else return false (see if this works)
62 | } else {
63 | return false
64 | }
65 | }
66 |
67 | // ------------------------------------------------------------------------------------
68 | // RESIZE BEHAVIOR
69 | function getWidth() {
70 | return (resizeDPR() ? window.innerWidth * window.devicePixelRatio : window.innerWidth)
71 | }
72 | function getHeight() {
73 | return (resizeDPR() ? window.innerHeight * window.devicePixelRatio : window.innerHeight)
74 | }
75 | window.addEventListener('resize', function (event) {
76 | // Has to be done here instead of in the scene's resize event handler
77 | // bc otherwise we get infinite recursion (game.scale.resize emits 'resize')
78 | game.scale.resize(getWidth(), getHeight());
79 | }, false);
80 |
81 |
82 | export default game;
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CTF BourgPalette
2 |
3 | A pokemon-like project game where you level up by hacking your neighbor.
4 |
5 | You play as a new hacker. You are not trying to capture all the pokemons but to capture all the flags! CTF is for Capture the Flag, a famous term in cybersecurity where you can try to figure out how to infiltrate and exploit on a simulation ecosystem. It's the same in CTFBourgPalette.
6 |
7 | Built during the Secureworks Cybersecurity Literacy Challenge 2022.
8 |
9 | ## Table of Contents
10 | 1. [Dependencies](#dependencies)
11 | 3. [Installation and launch](#installation-and-launch)
12 | 6. [Demo](#demo)
13 | 8. [Update the maps](#update-map)
14 | 7. [In the Future](#in-the-future)
15 | 8. [Known issues](#known-issues)
16 | 8. [Credits](#credits)
17 | 9. [Contributing](#contributing)
18 | 10. [License](#license)
19 |
20 |
21 | ## Usage
22 |
23 | #### Dependencies
24 |
25 | Before running CTF BourgPalette the following dependencies need to be installed.
26 |
27 | | Dependencies | Version |
28 | | ------------ | ------- |
29 | | npm | 8+ |
30 |
31 |
32 | ### Installation and launch
33 |
34 | ```bash
35 | $ git clone https://github.com/VBoureaud/CTFBourgPalette.git
36 | $ cd CTFBourgPalette
37 | $ npm install
38 | $ npm start
39 | ```
40 |
41 | ### Demo
42 |
43 | There is a live demo running on vercel.
44 | You can find it [here](https://ctf-bourgpalette.vercel.app)
45 |
46 | ### Update the maps
47 | To update the maps you will need a software named [Tiled](https://www.mapeditor.org).
48 | Open a map file map.tmx, and locate your tilesets assets/tilesets.png.
49 | Then you can edit your map but be careful, respect the layers.
50 | When you are done save your map.tmx and export as a map.json.
51 |
52 | ### In the Future
53 | Still a lot of ideas that I would like to implement:
54 |
55 | | Ideas |
56 | |--------------|
57 | | Quests about Phising, Sim Swap, Multi-Auth, OSINT, Rogue Access Point, Cryptographic |
58 | | P5.js game to simulate Bruteforce Attack |
59 | | Click on flag to auto copy |
60 |
61 | ### Known issues
62 | To be corrected in the next version.
63 |
64 | | Issues |
65 | |--------------|
66 | | Some events are launched asynchronously with PhaserJS and can cause a pause movement for the player who needs to reload the page. |
67 |
68 | Find an issue ? Contact me at valentin@boureaud.com
69 |
70 | ## Credits
71 | Some awesome libraries/projects help power this one:
72 |
73 | * [PhaserJS](https://github.com/phaserjs/phaser), for the game engine
74 | * [Create-React-Phaser3-App](https://github.com/kevinshen56714/create-react-phaser3-app), for the boilerplate ReactJS + PhaserJS
75 | * [Ariel Roffe](https://arielroffe.quest), for the structure of the phaserJS game
76 | * [NES.css](https://nostalgic-css.github.io/NES.css) for the crazy NES design
77 | * [Ant Design](https://github.com/ant-design/ant-design) for the reactJs design part
78 | * [TypeScript](https://www.typescriptlang.org/), write JS with syntax for types
79 | * [Reactjs](https://reactjs.org) - Library for building user interfaces
80 |
81 | ## Contributing
82 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
83 | Please make sure to update tests as appropriate.
84 |
85 | ## License
86 | [MIT](https://choosealicense.com/licenses/mit/)
87 |
88 | ##
89 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | position: absolute;
4 | height: 100%;
5 | width: 100%;
6 | }
7 |
8 | .phoneContainer {
9 | display: flex;
10 | flex-direction: row;
11 | height: calc(100% - 13px);
12 | flex-wrap: wrap;
13 | overflow-y: auto;
14 | align-content: flex-start;
15 | }
16 | .barPhone {
17 | position: relative;
18 | height: 13px;
19 | font-size: 8px;
20 | padding: 0 5px;
21 | }
22 | .barPhone > p:last-child {
23 | margin-bottom: 0;
24 | position: absolute;
25 | top: 0;
26 | right: 5px;
27 | }
28 | .phoneContainer > div {
29 | max-width: 48%;
30 | height: 100%;
31 | max-height: 30%;
32 | width: 100%;
33 | background-color: tomato;
34 | margin: 1%;
35 | display: flex;
36 | justify-content: center;
37 | align-items: center;
38 | }
39 |
40 | .phoneGame .ant-modal-content {
41 | background-color: inherit;
42 | box-shadow: none;
43 | display: flex;
44 | justify-content: center;
45 | width: 100%;
46 | max-width: 40vw;
47 | align-items: center;
48 | height: 100%;
49 | }
50 | .phoneGame .ant-modal {
51 | top: 0;
52 | bottom: 50px;
53 | width: 100%;
54 | max-width: 40vw;
55 | max-height: 100vh;
56 | padding-bottom: 0;
57 | height: 100%;
58 | }
59 | .phoneGame .ant-modal-footer {
60 | display: none;
61 | }
62 |
63 | .computerScreen {
64 |
65 | }
66 | .computerScreen > .ant-modal, .computerScreen .ant-modal-content {
67 | width: 100vw;
68 | margin: 0;
69 | top: 5px;
70 | }
71 | .computerScreen .ant-modal-body {
72 | padding: 1px;
73 | }
74 | .computerScreen > .ant-modal > .ant-modal-content {
75 | border: 5px double black;
76 | border-radius: 5px;
77 | }
78 | .menuGame {
79 |
80 | }
81 | .menuGame .ant-modal-footer {
82 | display: none;
83 | }
84 | .menuGame > .ant-modal {
85 | background-color: white;
86 | border-radius: 5px;
87 | min-width: 270px;
88 | width: 100%;
89 | padding-bottom: 0;
90 | }
91 | .menuGame > .ant-modal > .ant-modal-content {
92 | border: 5px double black;
93 | border-radius: 5px;
94 | min-width: 270px;
95 | max-height: 60vh;
96 | overflow-y: auto;
97 | }
98 | .menuGame .ant-modal-body > p {
99 | //cursor: pointer;
100 | }
101 | .menuGame .ant-modal-body > div > p:last-child {
102 | margin-bottom: 0;
103 | }
104 |
105 | .phoneBtn {
106 | position: absolute;
107 | bottom: 15px;
108 | left: 15px;
109 | }
110 | .white {
111 | color: white;
112 | }
113 |
114 | .dialogSign {
115 | background: white;
116 | position: absolute!important;
117 | bottom: 15px;
118 | right: 5px;
119 | left: 5px;
120 | }
121 | .dialogCursor {
122 | position: absolute;
123 | right: 10px;
124 | bottom: 20px;
125 | width: 2px;
126 | height: 2px;
127 | color: #212529;
128 | rotate: 90deg;
129 | box-shadow: 2px 2px,4px 2px,2px 4px,4px 4px,6px 4px,8px 4px,2px 6px,4px 6px,6px 6px,8px 6px,10px 6px,2px 8px,4px 8px,6px 8px,8px 8px,10px 8px,12px 8px,2px 10px,4px 10px,6px 10px,8px 10px,10px 10px,2px 12px,4px 12px,6px 12px,8px 12px,2px 14px,4px 14px;
130 | }
131 |
132 | .questDoneIcon {
133 | display: inline-block;
134 | position: relative;
135 | bottom: 15px;
136 | left: 5px;
137 | width: 2px;
138 | height: 2px;
139 | color: #212529;
140 | box-shadow: 2px 2px 0 .020em,4px 2px 0 .020em,6px 2px 0 .020em,8px 2px 0 .020em,10px 2px 0 .020em,12px 2px 0 .020em,14px 2px 0 .020em,18px 2px 0 .020em,20px 2px 0 .020em,2px 4px 0 .020em,16px 4px 0 .020em,18px 4px 0 .020em,20px 4px 0 .020em,2px 6px 0 .020em,14px 6px 0 .020em,16px 6px 0 .020em,2px 8px 0 .020em,4px 8px 0 .020em,12px 8px 0 .020em,14px 8px 0 .020em,2px 10px 0 .020em,4px 10px 0 .020em,6px 10px 0 .020em,10px 10px 0 .020em,12px 10px 0 .020em,16px 10px 0 .020em,2px 12px 0 .020em,6px 12px 0 .020em,8px 12px 0 .020em,10px 12px 0 .020em,16px 12px 0 .020em,2px 14px 0 .020em,8px 14px 0 .020em,16px 14px 0 .020em,2px 16px 0 .020em,4px 16px 0 .020em,6px 16px 0 .020em,8px 16px 0 .020em,10px 16px 0 .020em,12px 16px 0 .020em,14px 16px 0 .020em,16px 16px 0 .020em;
141 | }
--------------------------------------------------------------------------------
/src/scenes/interactive/player.js:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser'
2 |
3 | export class Player extends Phaser.GameObjects.Sprite
4 | {
5 | constructor(scene, x, y, texture, frame) {
6 | super(scene, x, y, texture, frame);
7 |
8 | // Add the sprite and the physics body to the scene
9 | scene.add.existing(this);
10 | scene.physics.add.existing(this);
11 |
12 | // Set the depth and the size
13 | this.setDepth(5);
14 | this.body.setSize(26, 41);
15 |
16 | // Create animations
17 | this.createAnims(scene);
18 |
19 | // Speed of movement
20 | this.speed = 175;
21 | }
22 |
23 | createAnims(scene) {
24 | // Create the player's walking animations from the texture atlas
25 | const anims = scene.anims;
26 | anims.create({
27 | key: "ariel-left-walk",
28 | frames: anims.generateFrameNames("atlas", {
29 | prefix: "ariel-left-walk.",
30 | start: 0,
31 | end: 3,
32 | zeroPad: 3
33 | }),
34 | frameRate: 10,
35 | repeat: -1
36 | });
37 | anims.create({
38 | key: "ariel-right-walk",
39 | frames: anims.generateFrameNames("atlas", {
40 | prefix: "ariel-right-walk.",
41 | start: 0,
42 | end: 3,
43 | zeroPad: 3
44 | }),
45 | frameRate: 10,
46 | repeat: -1
47 | });
48 | anims.create({
49 | key: "ariel-front-walk",
50 | frames: anims.generateFrameNames("atlas", {
51 | prefix: "ariel-front-walk.",
52 | start: 0,
53 | end: 3,
54 | zeroPad: 3
55 | }),
56 | frameRate: 10,
57 | repeat: -1
58 | });
59 | anims.create({
60 | key: "ariel-back-walk",
61 | frames: anims.generateFrameNames("atlas", {
62 | prefix: "ariel-back-walk.",
63 | start: 0,
64 | end: 3,
65 | zeroPad: 3
66 | }),
67 | frameRate: 10,
68 | repeat: -1
69 | });
70 | anims.create({
71 | key: "ariel-wave",
72 | frames: anims.generateFrameNames("atlas", {
73 | prefix: "ariel-wave.",
74 | start: 0,
75 | end: 4,
76 | zeroPad: 3
77 | }),
78 | frameRate: 10,
79 | repeat: -1
80 | });
81 | }
82 |
83 | update(moveleft, moveright, moveup, movedown) {
84 | const prevVelocity = this.body.velocity.clone();
85 |
86 | // Stop any previous movement from the last frame
87 | this.body.setVelocity(0);
88 |
89 | // Update the animation and give left/right animations precedence over up/down animations in diagonal movement
90 | if (moveleft) {
91 | this.body.setVelocityX(-this.speed);
92 | this.anims.play("ariel-left-walk", true);
93 | } else if (moveright) {
94 | this.body.setVelocityX(this.speed);
95 | this.anims.play("ariel-right-walk", true);
96 | }
97 | if (moveup) {
98 | this.body.setVelocityY(-this.speed);
99 | if (!(moveleft || moveright)) { // When moving diagonally display the left / right animation
100 | this.anims.play("ariel-back-walk", true);
101 | }
102 | } else if (movedown) {
103 | this.body.setVelocityY(this.speed);
104 | if (!(moveleft || moveright)) { // When moving diagonally display the left / right animation
105 | this.anims.play("ariel-front-walk", true);
106 | }
107 | }
108 |
109 | // Normalize and scale the velocity so that player doesn't move faster along a diagonal
110 | this.body.velocity.normalize().scale(this.speed);
111 |
112 | // If not moving (and not waving or at the start of the game), stop animations and pick and idle frame
113 | if (!(moveleft || moveright || moveup || movedown) &&
114 | // This next part is so that it doesn't stop the waving animation in the overworld
115 | // Second disjunct is if it was already playing it (from prev iteration of Overworld's update)
116 | // First disjunct is bc at the start of the game currentAnim is null, comparing with .key gives an error
117 | !(this.anims.currentAnim == null || this.anims.currentAnim.key === 'ariel-wave'))
118 | {
119 | this.anims.stop();
120 | if (prevVelocity.x < 0) this.setTexture("atlas", "ariel-left");
121 | else if (prevVelocity.x > 0) this.setTexture("atlas", "ariel-right");
122 | else if (prevVelocity.y < 0) this.setTexture("atlas", "ariel-back");
123 | else if (prevVelocity.y > 0) this.setTexture("atlas", "ariel-front");
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/components/PhoneWifi.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { WifiType } from '../store/types';
3 |
4 | import "antd/dist/antd.css";
5 | import "nes.css/css/nes.min.css";
6 |
7 | import { WifiOutlined, LockOutlined } from '@ant-design/icons';
8 | import { List, Input, Button } from 'antd';
9 |
10 | import { calculateDistance } from '../store/utils';
11 |
12 | const styles = {
13 | tiled: {
14 | width: '100%',
15 | height: '100%',
16 | background: 'blue',
17 | display: 'flex',
18 | flexDirection: 'column',
19 | } as React.CSSProperties,
20 | content: {
21 | position: 'relative',
22 | display: "flex",
23 | flexDirection: "column",
24 | height: '100%',
25 | overflowY: 'auto',
26 | justifyContent: "center",
27 | fontFamily: "Roboto, sans-serif",
28 | color: "white",
29 | } as React.CSSProperties,
30 | backBtn: {
31 | background: '#373737',
32 | textAlign: 'center',
33 | padding: '5px',
34 | position: 'absolute',
35 | bottom: 0,
36 | right: 0,
37 | left: 0,
38 | } as React.CSSProperties,
39 | iconStyle: {
40 | marginRight: '4px',
41 | position: 'relative',
42 | bottom: '5px',
43 | } as React.CSSProperties,
44 | };
45 |
46 | type PhoneWifiType = {
47 | onCancel: Function;
48 | position: number[];
49 | wifiKnow?: string[];
50 | onConfirm?: Function;
51 | data: WifiType[];
52 | };
53 | type PhoneWifiTiledType = {
54 | onClick: Function;
55 | };
56 |
57 | function PhoneWifi(props: PhoneWifiType) {
58 | const [step, setStep] = useState('listWifi');
59 | const [tryWifi, setTryWifi] = useState(null);
60 | const [successWifi, setSuccessWifi] = useState(false);
61 | const [errorWifi, setErrorWifi] = useState(false);
62 | const [pwdValue, setPwdValue] = useState('');
63 |
64 | const handleReset = () => {
65 | setStep('listWifi');
66 | setSuccessWifi(false);
67 | setErrorWifi(false);
68 | setPwdValue('');
69 | }
70 |
71 | const handleChooseWifi = (item: WifiType) => {
72 | if (props.wifiKnow && props.wifiKnow.indexOf(item.name) !== -1) {
73 | setStep('wifiKnow');
74 | }
75 | else {
76 | setTryWifi(item);
77 | setStep('password');
78 | }
79 | }
80 |
81 | const handleConfirm = () => {
82 | if (tryWifi && tryWifi.pwd === pwdValue) {
83 | setSuccessWifi(true);
84 | setPwdValue('');
85 | if (props.onConfirm)
86 | setTimeout(() => {
87 | if (props.onConfirm)
88 | props.onConfirm(tryWifi.name)
89 | handleReset();
90 | }, 3000);
91 | } else {
92 | setErrorWifi(true);
93 | }
94 | }
95 |
96 | return (
97 |
98 | {step === 'listWifi' && WI-FI LIST
}
101 | bordered
102 | dataSource={props.data.filter(elt => elt.actif)}
103 | style={{ background: 'white' }}
104 | renderItem={item => (
105 | = 0 ? 'block' : 'none' }}>
106 | handleChooseWifi(item)}>
107 |
108 |
109 | {item.name}
110 | {calculateDistance(props.position, item.coord)}/5
111 |
112 |
113 | )}
114 | />}
115 |
116 | {step === 'password' &&
117 | {successWifi &&
Success
}
118 | {errorWifi &&
Fail
}
119 |
{tryWifi && tryWifi.name}
120 |
) => setPwdValue(e.target.value)} placeholder="Password" prefix={
} />
121 |
Connect
122 |
}
123 |
124 | {step === 'wifiKnow' && You already know this Wi-Fi.
}
125 |
126 | { setStep('wifi');props.onCancel(); }}>Back
127 |
128 | )
129 | }
130 |
131 | export const PhoneWifiTiled = (props: PhoneWifiTiledType) => {
132 | return (
133 | props.onClick()} style={styles.tiled}>
134 |
135 |
WIFI
136 |
137 | )
138 | }
139 |
140 | export default PhoneWifi;
--------------------------------------------------------------------------------
/src/assets/atlas/anims_ui.json:
--------------------------------------------------------------------------------
1 | {
2 | "meta": {
3 | "image": "anims_ui.png",
4 | "format": "RGBA8888",
5 | "size": {
6 | "w": 700,
7 | "h": 64
8 | },
9 | "scale": 1
10 | },
11 | "frames": {
12 | "purple.000": {
13 | "rotated": false,
14 | "trimmed": false,
15 | "sourceSize": {
16 | "w": 32,
17 | "h": 32
18 | },
19 | "spriteSourceSize": {
20 | "x": 0,
21 | "y": 0,
22 | "w": 32,
23 | "h": 32
24 | },
25 | "frame": {
26 | "x": 0,
27 | "y": 0,
28 | "w": 32,
29 | "h": 32
30 | }
31 | },
32 | "purple.001": {
33 | "rotated": false,
34 | "trimmed": false,
35 | "sourceSize": {
36 | "w": 32,
37 | "h": 32
38 | },
39 | "spriteSourceSize": {
40 | "x": 0,
41 | "y": 0,
42 | "w": 32,
43 | "h": 32
44 | },
45 | "frame": {
46 | "x": 32,
47 | "y": 0,
48 | "w": 32,
49 | "h": 32
50 | }
51 | },
52 | "purple.002": {
53 | "rotated": false,
54 | "trimmed": false,
55 | "sourceSize": {
56 | "w": 32,
57 | "h": 32
58 | },
59 | "spriteSourceSize": {
60 | "x": 0,
61 | "y": 0,
62 | "w": 32,
63 | "h": 32
64 | },
65 | "frame": {
66 | "x": 64,
67 | "y": 0,
68 | "w": 32,
69 | "h": 32
70 | }
71 | },
72 | "comput.000": {
73 | "rotated": false,
74 | "trimmed": false,
75 | "sourceSize": {
76 | "w": 32,
77 | "h": 32
78 | },
79 | "spriteSourceSize": {
80 | "x": 0,
81 | "y": 0,
82 | "w": 32,
83 | "h": 32
84 | },
85 | "frame": {
86 | "x": 96,
87 | "y": 0,
88 | "w": 32,
89 | "h": 32
90 | }
91 | },
92 | "comput.001": {
93 | "rotated": false,
94 | "trimmed": false,
95 | "sourceSize": {
96 | "w": 32,
97 | "h": 32
98 | },
99 | "spriteSourceSize": {
100 | "x": 0,
101 | "y": 0,
102 | "w": 32,
103 | "h": 32
104 | },
105 | "frame": {
106 | "x": 128,
107 | "y": 0,
108 | "w": 32,
109 | "h": 32
110 | }
111 | },
112 | "comput2.000": {
113 | "rotated": false,
114 | "trimmed": false,
115 | "sourceSize": {
116 | "w": 32,
117 | "h": 32
118 | },
119 | "spriteSourceSize": {
120 | "x": 0,
121 | "y": 0,
122 | "w": 32,
123 | "h": 32
124 | },
125 | "frame": {
126 | "x": 160,
127 | "y": 0,
128 | "w": 32,
129 | "h": 32
130 | }
131 | },
132 | "comput2.001": {
133 | "rotated": false,
134 | "trimmed": false,
135 | "sourceSize": {
136 | "w": 32,
137 | "h": 32
138 | },
139 | "spriteSourceSize": {
140 | "x": 0,
141 | "y": 0,
142 | "w": 32,
143 | "h": 32
144 | },
145 | "frame": {
146 | "x": 192,
147 | "y": 0,
148 | "w": 32,
149 | "h": 32
150 | }
151 | },
152 | "fountain.000": {
153 | "rotated": false,
154 | "trimmed": false,
155 | "sourceSize": {
156 | "w": 64,
157 | "h": 64
158 | },
159 | "spriteSourceSize": {
160 | "x": 0,
161 | "y": 0,
162 | "w": 64,
163 | "h": 64
164 | },
165 | "frame": {
166 | "x": 224,
167 | "y": 0,
168 | "w": 64,
169 | "h": 64
170 | }
171 | },
172 | "fountain.001": {
173 | "rotated": false,
174 | "trimmed": false,
175 | "sourceSize": {
176 | "w": 64,
177 | "h": 64
178 | },
179 | "spriteSourceSize": {
180 | "x": 0,
181 | "y": 0,
182 | "w": 64,
183 | "h": 64
184 | },
185 | "frame": {
186 | "x": 288,
187 | "y": 0,
188 | "w": 64,
189 | "h": 64
190 | }
191 | },
192 | "fountain.002": {
193 | "rotated": false,
194 | "trimmed": false,
195 | "sourceSize": {
196 | "w": 64,
197 | "h": 64
198 | },
199 | "spriteSourceSize": {
200 | "x": 0,
201 | "y": 0,
202 | "w": 64,
203 | "h": 64
204 | },
205 | "frame": {
206 | "x": 352,
207 | "y": 0,
208 | "w": 64,
209 | "h": 64
210 | }
211 | },
212 | "fountain.003": {
213 | "rotated": false,
214 | "trimmed": false,
215 | "sourceSize": {
216 | "w": 64,
217 | "h": 64
218 | },
219 | "spriteSourceSize": {
220 | "x": 0,
221 | "y": 0,
222 | "w": 64,
223 | "h": 64
224 | },
225 | "frame": {
226 | "x": 416,
227 | "y": 0,
228 | "w": 64,
229 | "h": 64
230 | }
231 | },
232 | "play": {
233 | "rotated": false,
234 | "trimmed": false,
235 | "sourceSize": {
236 | "w": 44,
237 | "h": 44
238 | },
239 | "spriteSourceSize": {
240 | "x": 0,
241 | "y": 0,
242 | "w": 44,
243 | "h": 44
244 | },
245 | "frame": {
246 | "x": 480,
247 | "y": 0,
248 | "w": 44,
249 | "h": 44
250 | }
251 | },
252 | "mute": {
253 | "rotated": false,
254 | "trimmed": false,
255 | "sourceSize": {
256 | "w": 44,
257 | "h": 44
258 | },
259 | "spriteSourceSize": {
260 | "x": 0,
261 | "y": 0,
262 | "w": 44,
263 | "h": 44
264 | },
265 | "frame": {
266 | "x": 524,
267 | "y": 0,
268 | "w": 44,
269 | "h": 44
270 | }
271 | },
272 | "dots": {
273 | "rotated": false,
274 | "trimmed": false,
275 | "sourceSize": {
276 | "w": 44,
277 | "h": 44
278 | },
279 | "spriteSourceSize": {
280 | "x": 0,
281 | "y": 0,
282 | "w": 44,
283 | "h": 44
284 | },
285 | "frame": {
286 | "x": 568,
287 | "y": 0,
288 | "w": 44,
289 | "h": 44
290 | }
291 | },
292 | "fullscreen": {
293 | "rotated": false,
294 | "trimmed": false,
295 | "sourceSize": {
296 | "w": 44,
297 | "h": 44
298 | },
299 | "spriteSourceSize": {
300 | "x": 0,
301 | "y": 0,
302 | "w": 44,
303 | "h": 44
304 | },
305 | "frame": {
306 | "x": 612,
307 | "y": 0,
308 | "w": 44,
309 | "h": 44
310 | }
311 | },
312 | "fullscreen2": {
313 | "rotated": false,
314 | "trimmed": false,
315 | "sourceSize": {
316 | "w": 44,
317 | "h": 44
318 | },
319 | "spriteSourceSize": {
320 | "x": 0,
321 | "y": 0,
322 | "w": 44,
323 | "h": 44
324 | },
325 | "frame": {
326 | "x": 656,
327 | "y": 0,
328 | "w": 44,
329 | "h": 44
330 | }
331 | }
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/src/scenes/base.js:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser'
2 |
3 | export class BaseScene extends Phaser.Scene {
4 |
5 | movable = true;
6 |
7 | // --------------------------------------------------------------------------------------------------
8 | // CREATE
9 | create(tilemapKey) {
10 | // ----------------
11 | // MAP AND TILESET
12 | this.map = this.make.tilemap({key: tilemapKey});
13 |
14 | //const tileset = this.map.addTilesetImage("tileset", "TilesetImage");
15 | // With added margin and spacing for the extruded image:
16 | const tileset = this.map.addTilesetImage("tileset", "TilesetImage", 32, 32, 1, 2);
17 |
18 | // Map layers (defined in Tiled)
19 | this.map.createLayer("Ground1", tileset, 0, 0);
20 | this.map.createLayer("Ground2", tileset, 0, 0);
21 | this.map.createLayer("Collision1", tileset, 0, 0);
22 | this.map.createLayer("Collision2", tileset, 0, 0);
23 | this.map.createLayer("Above", tileset, 0, 0).setDepth(10); // To have the "Above" layer sit on top of the player, we give it a depth.
24 | // The layer with wich the player will collide
25 | this.LayerToCollide = this.map.createLayer("CollisionLayer", tileset, 0, 0);
26 | this.LayerToCollide.setVisible(false); // Comment out this line if you wish to see which objects the player will collide with
27 |
28 | // ----------------
29 | // PLAYER
30 | // Get the spawn point
31 | const spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point");
32 |
33 | // Create the player and the player animations (see player.js)
34 | this.player = this.add.player(spawnPoint.x, spawnPoint.y, "atlas", "ariel-front")
35 |
36 | // ----------------
37 | // CAMERA AND CURSORS
38 | const camera = this.cameras.main;
39 | camera.startFollow(this.player);
40 | camera.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);
41 | this.cursors = this.input.keyboard.createCursorKeys();
42 | this.wasd = { // TODO FR OR EN ?
43 | w: this.input.keyboard.addKey('W'),
44 | a: this.input.keyboard.addKey('A'),
45 | //w: this.input.keyboard.addKey('Z'),
46 | //a: this.input.keyboard.addKey('Q'),
47 | s: this.input.keyboard.addKey('S'),
48 | d: this.input.keyboard.addKey('D'),
49 | }
50 |
51 | // Camera resize behavior
52 | this.scale.on('resize', this.resize, this);
53 |
54 | // ----------------
55 | // INTERACTIVE OBJECTS
56 | this.signs = [];
57 | this.showingSign = false;
58 | this.map.filterObjects("Objects", obj => {
59 | // DOORS
60 | if (obj.name === 'door') {
61 | this.add.door(Math.round(obj.x), Math.round(obj.y), obj.width, obj.height, obj.properties[0].value, obj.properties[1].value);
62 | // last 2: destination (str) and link (bool, if true leads to a redirect)
63 | }
64 |
65 | // SIGNS
66 | if (obj.name === 'sign') {
67 | this.signs.push(this.add.sign(obj.x, obj.y, obj.properties[1].value, obj.properties[0].value))
68 | // Last parameters are the text to show and the direction of the text in relation to the object
69 | }
70 | });
71 |
72 | this.events.on('break', this.catchDoBreak, this);
73 | this.events.on('position', this.getPlayerPosition, this);
74 | }
75 |
76 | getPlayerPosition() {
77 | this.events.emit('player', this.player);
78 | }
79 |
80 | catchDoBreak() {
81 | this.movable = !this.movable;
82 | }
83 |
84 | // ---------------------------------------------------
85 | resize (gameSize, baseSize, displaySize, resolution) {
86 | this.cameras.resize(gameSize.width, gameSize.height);
87 | }
88 |
89 | collide_with_world() {
90 | // Collision with the world layers. Has to come after the rest of the colliders in order for them to detect.
91 | // We need to call this at the end of the children's create
92 | this.physics.add.collider(this.player, this.LayerToCollide);
93 | this.LayerToCollide.setCollisionBetween(40, 41);
94 |
95 | // Set the player to collide with the world bounds
96 | this.player.body.setCollideWorldBounds(true);
97 | this.player.body.onWorldBounds = true;
98 | }
99 |
100 | // --------------------------------------------------------------------------------------------------
101 | // UPDATE
102 | update(time, delta) {
103 | let moveleft = false;
104 | let moveright = false;
105 | let moveup = false;
106 | let movedown = false;
107 |
108 | // Not movable? stop movement and return
109 | if (!this.movable) {
110 | this.player.update(moveleft, moveright, moveup, movedown);
111 | return false;
112 | }
113 |
114 | // ----------------
115 | // MOUSE MOVEMENT
116 | let pointer = this.input.activePointer;
117 | if (pointer.primaryDown && !window.mouseOverMenu) {
118 | // let pointerPosition = pointer.position;
119 | // So that the x and y update if the camera moves and the mouse does not
120 | let pointerPosition = this.cameras.main.getWorldPoint(pointer.x, pointer.y);
121 |
122 | // Horizontal movement
123 | if (Math.abs(pointerPosition.x - this.player.x) > 15) { // To avoid glitching when the player hits the cursor
124 | if (pointerPosition.x > this.player.x) {
125 | moveright = true;
126 | } else if (pointerPosition.x < this.player.x) {
127 | moveleft = true;
128 | }
129 | }
130 |
131 | // Vertical movement
132 | if (Math.abs(pointerPosition.y - this.player.y) > 15) { // To avoid glitching when the player hits the cursor
133 | if (pointerPosition.y > this.player.y) {
134 | movedown = true;
135 | } else if (pointerPosition.y < this.player.y) {
136 | moveup = true;
137 | }
138 | }
139 | }
140 |
141 | // ----------------
142 | // KEYBOARD MOVEMENT
143 | // Horizontal movement
144 | if (this.cursors.left.isDown || this.wasd.a.isDown) {
145 | moveleft = true;
146 | } else if (this.cursors.right.isDown || this.wasd.d.isDown) {
147 | moveright = true;
148 | }
149 |
150 | // Vertical movement
151 | if (this.cursors.up.isDown || this.wasd.w.isDown) {
152 | moveup = true;
153 | } else if (this.cursors.down.isDown || this.wasd.s.isDown) {
154 | movedown = true;
155 | }
156 |
157 | // Update player velocity and animation
158 | this.player.update(moveleft, moveright, moveup, movedown);
159 |
160 | // ---------------------
161 | // INTERACTIVE OBJECTS
162 | // Hide the signs
163 | if (this.showingSign && (moveleft || moveright || moveup || movedown)) {
164 | this.signs.forEach((sign) => {
165 | if (sign.activated) sign.playerMovement(moveleft, moveright, moveup, movedown)
166 | });
167 | }
168 |
169 | }
170 |
171 | }
--------------------------------------------------------------------------------
/src/store/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect, createContext, useState} from "react";
2 |
3 | import config from '../config';
4 | import { storageData, getStorage, rmStorage } from './localStorage';
5 | import { User, Quests, Quest, WifiType } from './types';
6 |
7 | const defaultUser: User = {
8 | name: 'User 1',
9 | level: 1,
10 | newLevel: false,
11 | loadingLevel: false,
12 | wifiKnow: [],
13 | imsiHandler: 0,
14 | };
15 |
16 | interface IContextStore {
17 | quests: Quests;
18 | quest: Quest | null;
19 | currentQ: string;
20 | wifi: WifiType[],
21 | user: User | null;
22 | getNextQuest: Function;
23 | getPrevQuest: Function;
24 | setNewQuestViewed: Function;
25 | setNewLevelViewed: Function;
26 | addWifiKnow: Function;
27 | resetGame: Function;
28 | getDevicesFromWifi: Function;
29 | loadAFlag: Function;
30 | ddosWifi: Function;
31 | };
32 |
33 | const GameContext = createContext({
34 | quests: config.game.quests,
35 | quest: null,
36 | currentQ: '',
37 | wifi: [],
38 | user: null,
39 | getNextQuest: () => {},
40 | getPrevQuest: () => {},
41 | setNewQuestViewed: () => {},
42 | setNewLevelViewed: () => {},
43 | addWifiKnow: () => {},
44 | resetGame: () => {},
45 | getDevicesFromWifi: () => {},
46 | loadAFlag: () => {},
47 | ddosWifi: () => {},
48 | } as IContextStore);
49 |
50 | export const GameContextProvider = (props: any) => {
51 | const [user, setUser] = useState(null);
52 | const [wifi, setWifi] = useState([]);
53 | const [quest, setQuest] = useState(null);
54 | const [currentQ, setCurrentQ] = useState('');
55 |
56 | useEffect(() => {
57 | const initGame = async () => {
58 | const u = await getStorage('user');
59 | await setUser(u ? u : defaultUser);
60 | await storageData('user', u ? u : defaultUser);
61 | await setWifi(config.game.wifi)
62 | await initQuest(u ? (u.level - 1) : 0, u ? u : defaultUser);
63 | console.log(config.game.name + ' ready to play!');
64 | }
65 |
66 | initGame();
67 | }, []);
68 |
69 | // get flag for current quest
70 | const initQuest = (index: number, pUser?: User) => {
71 | const quests: Quests = config.game.quests;
72 | const keys = Object.keys(quests);
73 | if (index < keys.length) {
74 | setCurrentQ(keys[index]);
75 | setQuest(quests[keys[index]]);
76 | const checkUser = pUser ? pUser : user;
77 | if (quests[keys[index]].imsiHandler && checkUser && checkUser.imsiHandler === 0) {
78 | setImsiCatcherStart();
79 | }
80 | }
81 | }
82 |
83 | // change level user + save in localstorage
84 | const increaseUser = (newLevel: boolean) => {
85 | const newU = user;
86 | if (newU) {
87 | newU.level = newU.level + 1;
88 | newU.newLevel = newLevel;
89 | setUser(newU);
90 | storageData('user', newU);
91 | }
92 | }
93 |
94 | const getPrevQuest = () => {
95 | const quests: Quests = config.game.quests;
96 | const keys = Object.keys(quests);
97 | const index = keys.indexOf(currentQ);
98 | if (index - 1 >= 0)
99 | return keys[index - 1];
100 | return '';
101 | }
102 |
103 | // if return '' => no more quest
104 | const getNextQuest = () => {
105 | const quests: Quests = config.game.quests;
106 | const keys = Object.keys(quests);
107 | const index = keys.indexOf(currentQ);
108 | if (index + 1 < keys.length) {
109 | increaseUser(true);
110 | initQuest(index + 1);
111 | return keys[index + 1];
112 | } else {
113 | // end of the game
114 | increaseUser(false);
115 | }
116 | return '';
117 | }
118 |
119 | const setNewQuestViewed = () => {
120 | const newU = user;
121 | if (newU) {
122 | newU.newLevel = false;
123 | setUser(newU);
124 | storageData('user', newU);
125 | }
126 | }
127 |
128 | const setNewLevelViewed = () => {
129 | const newU = user;
130 | if (newU) {
131 | newU.loadingLevel = false;
132 | setUser(newU);
133 | storageData('user', newU);
134 | }
135 | }
136 |
137 | const setImsiCatcherStart = async () => {
138 | const newU = await getStorage('user');
139 | if (newU) {
140 | const d = new Date();
141 | newU.imsiHandler = d.getTime();
142 | setUser(newU);
143 | storageData('user', newU);
144 | }
145 | }
146 |
147 | const addWifiKnow = (name: string) => {
148 | const newU = user;
149 | if (newU && newU.wifiKnow.indexOf(name) === -1) {
150 | newU.wifiKnow.push(name);
151 | setUser(newU);
152 | storageData('user', newU);
153 | }
154 | }
155 |
156 | const resetGame = () => {
157 | rmStorage('user');
158 | window.location.href = window.location.href;
159 | }
160 |
161 | const getDevicesFromWifi = (wifiName: string) => {
162 | const wifiList = wifi.filter(elt => elt.name === wifiName);
163 | if (!wifiList) return [];
164 | return wifiList[0] ? wifiList[0].devices : [];
165 | }
166 |
167 | const loadAFlag = (flag: string) => {
168 | const quests: Quests = config.game.quests;
169 | const flagList = Object.keys(quests);
170 | const questIndex = flagList.indexOf(flag);
171 | if (questIndex === -1 || !user) {
172 | return false;
173 | }
174 | const newU = user;
175 | const quest = quests[flagList[questIndex]];
176 | newU.level = questIndex + 1;
177 | newU.newLevel = true;
178 | newU.loadingLevel = true;
179 | for (let i = 0; i < quest.wifiKnow.length; i++) {
180 | if (newU.wifiKnow.indexOf(quest.wifiKnow[i]) === -1)
181 | newU.wifiKnow.push(quest.wifiKnow[i]);
182 | }
183 | storageData('user', newU);
184 |
185 | //relaunch
186 | window.location.href = window.location.href;
187 | }
188 |
189 | const ddosWifi = (name: string) => {
190 | const cWifi = wifi;
191 | for (let i = 0; i < cWifi.length; i++)
192 | if (cWifi[i].name === name)
193 | cWifi[i].actif = !cWifi[i].actif;
194 | setWifi(cWifi);
195 | }
196 |
197 | return (
198 |
215 | {props.children}
216 |
217 | )
218 | }
219 |
220 | export default GameContext;
--------------------------------------------------------------------------------
/src/assets/atlas/player.json:
--------------------------------------------------------------------------------
1 | {
2 | "meta": {
3 | "image": "player.png",
4 | "format": "RGBA8888",
5 | "size": {
6 | "w": 510,
7 | "h": 43
8 | },
9 | "scale": 1
10 | },
11 | "frames": {
12 | "ariel-back": {
13 | "rotated": false,
14 | "trimmed": false,
15 | "sourceSize": {
16 | "w": 32,
17 | "h": 41
18 | },
19 | "spriteSourceSize": {
20 | "x": 0,
21 | "y": 0,
22 | "w": 32,
23 | "h": 41
24 | },
25 | "frame": {
26 | "x": 35,
27 | "y": 1,
28 | "w": 32,
29 | "h": 41
30 | }
31 | },
32 | "ariel-back-walk.000": {
33 | "rotated": false,
34 | "trimmed": false,
35 | "sourceSize": {
36 | "w": 32,
37 | "h": 41
38 | },
39 | "spriteSourceSize": {
40 | "x": 0,
41 | "y": 0,
42 | "w": 32,
43 | "h": 41
44 | },
45 | "frame": {
46 | "x": 1,
47 | "y": 1,
48 | "w": 32,
49 | "h": 41
50 | }
51 | },
52 | "ariel-back-walk.001": {
53 | "rotated": false,
54 | "trimmed": false,
55 | "sourceSize": {
56 | "w": 32,
57 | "h": 41
58 | },
59 | "spriteSourceSize": {
60 | "x": 0,
61 | "y": 0,
62 | "w": 32,
63 | "h": 41
64 | },
65 | "frame": {
66 | "x": 35,
67 | "y": 1,
68 | "w": 32,
69 | "h": 41
70 | }
71 | },
72 | "ariel-back-walk.002": {
73 | "rotated": false,
74 | "trimmed": false,
75 | "sourceSize": {
76 | "w": 32,
77 | "h": 41
78 | },
79 | "spriteSourceSize": {
80 | "x": 0,
81 | "y": 0,
82 | "w": 32,
83 | "h": 41
84 | },
85 | "frame": {
86 | "x": 69,
87 | "y": 1,
88 | "w": 32,
89 | "h": 41
90 | }
91 | },
92 | "ariel-back-walk.003": {
93 | "rotated": false,
94 | "trimmed": false,
95 | "sourceSize": {
96 | "w": 32,
97 | "h": 41
98 | },
99 | "spriteSourceSize": {
100 | "x": 0,
101 | "y": 0,
102 | "w": 32,
103 | "h": 41
104 | },
105 | "frame": {
106 | "x": 35,
107 | "y": 1,
108 | "w": 32,
109 | "h": 41
110 | }
111 | },
112 | "ariel-front": {
113 | "rotated": false,
114 | "trimmed": false,
115 | "sourceSize": {
116 | "w": 32,
117 | "h": 41
118 | },
119 | "spriteSourceSize": {
120 | "x": 0,
121 | "y": 0,
122 | "w": 32,
123 | "h": 41
124 | },
125 | "frame": {
126 | "x": 137,
127 | "y": 1,
128 | "w": 32,
129 | "h": 41
130 | }
131 | },
132 | "ariel-front-walk.000": {
133 | "rotated": false,
134 | "trimmed": false,
135 | "sourceSize": {
136 | "w": 32,
137 | "h": 41
138 | },
139 | "spriteSourceSize": {
140 | "x": 0,
141 | "y": 0,
142 | "w": 32,
143 | "h": 41
144 | },
145 | "frame": {
146 | "x": 103,
147 | "y": 1,
148 | "w": 32,
149 | "h": 41
150 | }
151 | },
152 | "ariel-front-walk.001": {
153 | "rotated": false,
154 | "trimmed": false,
155 | "sourceSize": {
156 | "w": 32,
157 | "h": 41
158 | },
159 | "spriteSourceSize": {
160 | "x": 0,
161 | "y": 0,
162 | "w": 32,
163 | "h": 41
164 | },
165 | "frame": {
166 | "x": 137,
167 | "y": 1,
168 | "w": 32,
169 | "h": 41
170 | }
171 | },
172 | "ariel-front-walk.002": {
173 | "rotated": false,
174 | "trimmed": false,
175 | "sourceSize": {
176 | "w": 32,
177 | "h": 41
178 | },
179 | "spriteSourceSize": {
180 | "x": 0,
181 | "y": 0,
182 | "w": 32,
183 | "h": 41
184 | },
185 | "frame": {
186 | "x": 171,
187 | "y": 1,
188 | "w": 32,
189 | "h": 41
190 | }
191 | },
192 | "ariel-front-walk.003": {
193 | "rotated": false,
194 | "trimmed": false,
195 | "sourceSize": {
196 | "w": 32,
197 | "h": 41
198 | },
199 | "spriteSourceSize": {
200 | "x": 0,
201 | "y": 0,
202 | "w": 32,
203 | "h": 41
204 | },
205 | "frame": {
206 | "x": 137,
207 | "y": 1,
208 | "w": 32,
209 | "h": 41
210 | }
211 | },
212 | "ariel-left": {
213 | "rotated": false,
214 | "trimmed": false,
215 | "sourceSize": {
216 | "w": 32,
217 | "h": 41
218 | },
219 | "spriteSourceSize": {
220 | "x": 0,
221 | "y": 0,
222 | "w": 32,
223 | "h": 41
224 | },
225 | "frame": {
226 | "x": 239,
227 | "y": 1,
228 | "w": 32,
229 | "h": 41
230 | }
231 | },
232 | "ariel-left-walk.000": {
233 | "rotated": false,
234 | "trimmed": false,
235 | "sourceSize": {
236 | "w": 32,
237 | "h": 41
238 | },
239 | "spriteSourceSize": {
240 | "x": 0,
241 | "y": 0,
242 | "w": 32,
243 | "h": 41
244 | },
245 | "frame": {
246 | "x": 205,
247 | "y": 1,
248 | "w": 32,
249 | "h": 41
250 | }
251 | },
252 | "ariel-left-walk.001": {
253 | "rotated": false,
254 | "trimmed": false,
255 | "sourceSize": {
256 | "w": 32,
257 | "h": 41
258 | },
259 | "spriteSourceSize": {
260 | "x": 0,
261 | "y": 0,
262 | "w": 32,
263 | "h": 41
264 | },
265 | "frame": {
266 | "x": 239,
267 | "y": 1,
268 | "w": 32,
269 | "h": 41
270 | }
271 | },
272 | "ariel-left-walk.002": {
273 | "rotated": false,
274 | "trimmed": false,
275 | "sourceSize": {
276 | "w": 32,
277 | "h": 41
278 | },
279 | "spriteSourceSize": {
280 | "x": 0,
281 | "y": 0,
282 | "w": 32,
283 | "h": 41
284 | },
285 | "frame": {
286 | "x": 273,
287 | "y": 1,
288 | "w": 32,
289 | "h": 41
290 | }
291 | },
292 | "ariel-left-walk.003": {
293 | "rotated": false,
294 | "trimmed": false,
295 | "sourceSize": {
296 | "w": 32,
297 | "h": 41
298 | },
299 | "spriteSourceSize": {
300 | "x": 0,
301 | "y": 0,
302 | "w": 32,
303 | "h": 41
304 | },
305 | "frame": {
306 | "x": 239,
307 | "y": 1,
308 | "w": 32,
309 | "h": 41
310 | }
311 | },
312 | "ariel-right": {
313 | "rotated": false,
314 | "trimmed": false,
315 | "sourceSize": {
316 | "w": 32,
317 | "h": 41
318 | },
319 | "spriteSourceSize": {
320 | "x": 0,
321 | "y": 0,
322 | "w": 32,
323 | "h": 41
324 | },
325 | "frame": {
326 | "x": 341,
327 | "y": 1,
328 | "w": 32,
329 | "h": 41
330 | }
331 | },
332 | "ariel-right-walk.000": {
333 | "rotated": false,
334 | "trimmed": false,
335 | "sourceSize": {
336 | "w": 32,
337 | "h": 41
338 | },
339 | "spriteSourceSize": {
340 | "x": 0,
341 | "y": 0,
342 | "w": 32,
343 | "h": 41
344 | },
345 | "frame": {
346 | "x": 307,
347 | "y": 1,
348 | "w": 32,
349 | "h": 41
350 | }
351 | },
352 | "ariel-right-walk.001": {
353 | "rotated": false,
354 | "trimmed": false,
355 | "sourceSize": {
356 | "w": 32,
357 | "h": 41
358 | },
359 | "spriteSourceSize": {
360 | "x": 0,
361 | "y": 0,
362 | "w": 32,
363 | "h": 41
364 | },
365 | "frame": {
366 | "x": 341,
367 | "y": 1,
368 | "w": 32,
369 | "h": 41
370 | }
371 | },
372 | "ariel-right-walk.002": {
373 | "rotated": false,
374 | "trimmed": false,
375 | "sourceSize": {
376 | "w": 32,
377 | "h": 41
378 | },
379 | "spriteSourceSize": {
380 | "x": 0,
381 | "y": 0,
382 | "w": 32,
383 | "h": 41
384 | },
385 | "frame": {
386 | "x": 375,
387 | "y": 1,
388 | "w": 32,
389 | "h": 41
390 | }
391 | },
392 | "ariel-right-walk.003": {
393 | "rotated": false,
394 | "trimmed": false,
395 | "sourceSize": {
396 | "w": 32,
397 | "h": 41
398 | },
399 | "spriteSourceSize": {
400 | "x": 0,
401 | "y": 0,
402 | "w": 32,
403 | "h": 41
404 | },
405 | "frame": {
406 | "x": 341,
407 | "y": 1,
408 | "w": 32,
409 | "h": 41
410 | }
411 | },
412 | "ariel-wave.000": {
413 | "rotated": false,
414 | "trimmed": false,
415 | "sourceSize": {
416 | "w": 32,
417 | "h": 41
418 | },
419 | "spriteSourceSize": {
420 | "x": 0,
421 | "y": 0,
422 | "w": 32,
423 | "h": 41
424 | },
425 | "frame": {
426 | "x": 409,
427 | "y": 1,
428 | "w": 32,
429 | "h": 41
430 | }
431 | },
432 | "ariel-wave.001": {
433 | "rotated": false,
434 | "trimmed": false,
435 | "sourceSize": {
436 | "w": 32,
437 | "h": 41
438 | },
439 | "spriteSourceSize": {
440 | "x": 0,
441 | "y": 0,
442 | "w": 32,
443 | "h": 41
444 | },
445 | "frame": {
446 | "x": 443,
447 | "y": 1,
448 | "w": 32,
449 | "h": 41
450 | }
451 | },
452 | "ariel-wave.002": {
453 | "rotated": false,
454 | "trimmed": false,
455 | "sourceSize": {
456 | "w": 32,
457 | "h": 41
458 | },
459 | "spriteSourceSize": {
460 | "x": 0,
461 | "y": 0,
462 | "w": 32,
463 | "h": 41
464 | },
465 | "frame": {
466 | "x": 477,
467 | "y": 1,
468 | "w": 32,
469 | "h": 41
470 | }
471 | },
472 | "ariel-wave.003": {
473 | "rotated": false,
474 | "trimmed": false,
475 | "sourceSize": {
476 | "w": 32,
477 | "h": 41
478 | },
479 | "spriteSourceSize": {
480 | "x": 0,
481 | "y": 0,
482 | "w": 32,
483 | "h": 41
484 | },
485 | "frame": {
486 | "x": 443,
487 | "y": 1,
488 | "w": 32,
489 | "h": 41
490 | }
491 | },
492 | "ariel-wave.004": {
493 | "rotated": false,
494 | "trimmed": false,
495 | "sourceSize": {
496 | "w": 32,
497 | "h": 41
498 | },
499 | "spriteSourceSize": {
500 | "x": 0,
501 | "y": 0,
502 | "w": 32,
503 | "h": 41
504 | },
505 | "frame": {
506 | "x": 409,
507 | "y": 1,
508 | "w": 32,
509 | "h": 41
510 | }
511 | }
512 | }
513 | }
514 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | // BE CAREFUL
2 | // HERE IS THE LOGIC OF THE GAME
3 | // IF YOU READ LONGER, YOU WILL BE SPOILED.
4 |
5 | const config = {
6 | version: '0.1.1',
7 | debug: false,
8 | game: {
9 | name: 'CTFBourgPalette',
10 | quests: {
11 | ERGBHJ98: {
12 | level: 1,
13 | title: 'Quest 1',
14 | desc: 'Find Professor H and get your reward.',
15 | map: '',
16 | wifiKnow: [],
17 | orderFix: false,
18 | imsiHandler: false,
19 | goalOrder: {
20 | id3: { optional: true, break: true, dialog: [ 'Welcome to my city! Do you need some help ?', 'Oh yes! The neighbourhood is really nice and quiet. I used to walk around here and enjoy my time.', 'Only once I heard someone shout "123456789". I didn\'t understand why...', 'Well, see you later.' ] },
21 | id10: {
22 | break: true,
23 | dialog: [
24 | 'Welcome to CTFBourgPalette! Are you here to practice your hacking skills ?',
25 | 'Amazing! This is for you. I\'m curious to know if you are more black hat or white hat.',
26 | 'Your choices will define it. Enjoy!',
27 | ],
28 | },
29 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
30 | },
31 | success: 'You got a Phone! Time to hack! An automatic save is launched after each successful quest.',
32 | },
33 | OPJSBE9U: {
34 | level: 2,
35 | title: 'Quest 2',
36 | desc: 'Find a way to infiltrate ZOULOUFAMILY Network. Many techniques are available but you will discover the simplest: Predictable & Weak credentials.',
37 | map: '',
38 | wifiKnow: [],
39 | orderFix: false,
40 | imsiHandler: false,
41 | goalOrder: {
42 | id3: { optional: true, break: true, dialog: [ 'Welcome to my city! Do you need some help ?', 'Oh yes! The neighbourhood is really nice and quiet. I used to walk around here and enjoy my time.', 'Only once I heard someone shout "123456789". I didn\'t understand why...', 'Well, see you later.' ] },
43 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
44 | phone: { method: 'wifi', name: 'ZOULOUFAMILY' },
45 | },
46 | success: 'You succeed on your first infiltration.'
47 | },
48 | IOHFD93W: {
49 | level: 3,
50 | title: 'Quest 3',
51 | desc: 'Get the list of devices on your current network and find how to exploit one of them. Enter the flag you think valid in the menu "Enter a flag".',
52 | map: '',
53 | wifiKnow: [ 'ZOULOUFAMILY' ],
54 | orderFix: false,
55 | imsiHandler: false,
56 | goalOrder: {
57 | id6: { optional: true, break: true, dialog: [ 'Hey man, do you know where Sara is? I\'ve been waiting for her for so long now!'] },
58 | phone: { method: 'aim', name: 'AOKZC3O2' },
59 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
60 | },
61 | success: 'You succeed on your first exploitation.'
62 | },
63 | AOKZC3O2: { // Code needed in ComputerScreen
64 | level: 4,
65 | title: 'Quest 4',
66 | desc: 'It\'s time to play with the password. Find a computer to log in to the account whose credentials you just obtained and try to find a flag.',
67 | map: '',
68 | wifiKnow: [ 'ZOULOUFAMILY' ],
69 | orderFix: false,
70 | imsiHandler: false,
71 | goalOrder: {
72 | id8: { optional: true, break: true, dialog: [ 'Oh, you just got that password. Congrats.', 'You should try to connect with it.', 'But be careful, PhotoGram is a really good databroker.' ] },
73 | id19: { break: true, computerScreen: true, computerMode: 'photogram' },
74 | },
75 | success: 'Success. You get a credit card.',
76 | },
77 | WOXHAP89: { // Code needed in ComputerScreen
78 | level: 5,
79 | title: 'Quest 5',
80 | desc: 'Buy a IMSI-catcher and place it on a strategic point in the city. Then wait for data !',
81 | map: '',
82 | wifiKnow: [ 'ZOULOUFAMILY' ],
83 | orderFix: true,
84 | imsiHandler: false,
85 | goalOrder: {
86 | id3: { break: true, dialog: [ 'I see, you want my spy tool after all ?', 'Oh you\'ve got a credit card, ok let\'s proceed with the transaction.', 'If you want to try it, place it on a tall object like the Eiffel Tower, a construction crane or even a street lamp.' ] },
87 | id20: { break: true, dialog: [ 'You have successfully hidden your IMSI-catcher' ] },
88 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
89 | },
90 | success: 'Success',
91 | },
92 | PAPILLON: { // Code needed in ComputerScreen
93 | level: 6,
94 | title: 'Quest 6',
95 | desc: 'Look at the data you get and try to see if there is something you can use!',
96 | map: '',
97 | wifiKnow: [ 'ZOULOUFAMILY' ],
98 | orderFix: true,
99 | imsiHandler: true,
100 | goalOrder: {
101 | id20: { optional: true, break: true, computerScreen: true, computerMode: 'imsi' },
102 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
103 | },
104 | success: 'Success',
105 | },
106 | URERK896: { // Code needed in ComputerScreen
107 | level: 7,
108 | title: 'Quest 7',
109 | desc: 'Return to talk to Professor H.',
110 | map: '',
111 | wifiKnow: [ 'ZOULOUFAMILY' ],
112 | orderFix: true,
113 | imsiHandler: true,
114 | goalOrder: {
115 | id10: {
116 | break: true,
117 | dialog: [
118 | 'Here you are!',
119 | 'According to my informations you use some powerful tools to get and exploit vulnerabilities.',
120 | 'Congrats and I hope you enjoyed your time!',
121 | ],
122 | },
123 | id20: { optional: true, break: true, computerScreen: true, computerMode: 'imsi' },
124 | id19: { optional: true, computerScreen: true, computerMode: 'photogram' },
125 | },
126 | success: 'Success',
127 | },
128 | },
129 | objects: {
130 | id1: {
131 | name: '',
132 | default: '"Et puisse l\'avenir ne pas nous le reprocher par un chagrin", it looks like French literature...',
133 | },
134 | id2: {
135 | name: '',
136 | default: 'Bourg Palette is a very quiet, peaceful and relaxing place to enjoy the good weather and the spring wind...',
137 | },
138 | id3: {
139 | name: 'Roger',
140 | default: 'What\'s up ? Do you want a super spy tool ? I sell it for only 59$.',
141 | },
142 | id4: {
143 | name: '',
144 | default: 'Bourg Palette is populated by 10 wonderful people. We are happy to count you among us.',
145 | },
146 | id5: {
147 | name: '',
148 | default: 'Search House Lab, a place to learn cybersecurity.',
149 | },
150 | id6: {
151 | name: 'Bob',
152 | default: '♪ Well you give me the blues ♫',
153 | },
154 | id7: {
155 | name: 'Jest',
156 | default: 'I can\'t wait to explore the outdoors with my droids.',
157 | },
158 | id8: {
159 | name: 'Anna',
160 | default: 'My current job is to breach cryptographic security systems and gain access to the contents of encrypted messages.',
161 | },
162 | id9: {
163 | name: 'Software Engineer',
164 | default: 'Do you know what is an IP ? It\'s an numerical label that uses the Internet Protocol for communication. For example 192.168.50.1 can be the address of the router in a local network.',
165 | },
166 | id10: {
167 | name: 'Professor H',
168 | default: 'It\'s a beautiful day to hack, isn\'t it ?',
169 | },
170 | id11: {
171 | name: 'Kev',
172 | default: 'Do you know what is an IMSI-catcher ? It\'s a device used for intercepting mobile phone traffic and tracking location data of users. It\'s working like a MITM attack but for an entire zone.',
173 | },
174 | id12: { //dashboard
175 | name: '',
176 | default: '',
177 | },
178 | id13: { // server 1
179 | name: '',
180 | default: '',
181 | },
182 | id14: {// server2
183 | name: '',
184 | default: 'Look like it\'s doing some serious math',
185 | },
186 | id15: {
187 | name: '',
188 | default: 'This computer seems to be off.',
189 | },
190 | id16: {
191 | name: '',
192 | default: 'Trash is empty.',
193 | },
194 | id17: {
195 | name: 'Server',
196 | default: 'Hi, my name is Miaws',
197 | },
198 | id18: { // server 4
199 | name: '',
200 | default: '',
201 | },
202 | id19: { //softwarescene_computer2
203 | name: '',
204 | default: '',
205 | },
206 | id20: { // lampadere
207 | name: '',
208 | default: '',
209 | },
210 | id21: {
211 | name: '',
212 | default: 'It\'s closed. You can\'t walk into people\'s houses like that!',
213 | },
214 | id22: {// droid outside
215 | name: 'Droid',
216 | default: 'Civil liberty and privacy concerns are such a human concept...',
217 | },
218 | },
219 | wifi: [
220 | {
221 | actif: true,
222 | name: 'ZOULOUFAMILY',
223 | pwd: '123456789',
224 | coord: [ 941, 617 ],
225 | devices: [
226 | { name: 'Michel\'s musicPod', proba: 4, ip: '192.168.50.18', type: 'music', credentials: [ 'Michelle - The Beatles', 'Til I Fell in Love with You - Bob Dylan', 'Daft Punk - Random Access Memories' ] },
227 | { name: 'Sara\'s phone', proba: 3, ip: '192.168.50.152', type: 'navigation', actif: true, credentials: 'AOKZC3O2', probaCredential: 2 },
228 | { name: 'Computer 1', proba: 2, ip: '192.168.50.78', type: 'navigation', actif: false },
229 | { name: 'Computer 2', proba: 2, ip: '192 .168.50.129', type: 'navigation', actif: true },
230 | { name: 'Sasha\'s watch', proba: 3, ip: '192.168.50.89', type: 'watch', credentials: 'ONINHBHUVTYCR45678VC7645Q567890++°0=)0°987654SXCV}^€~^{hugugusqd~#{]~{^@&}&}}&}}&}]#^^sdfsdfjapô' },
231 | ],
232 | }, {
233 | actif: true,
234 | name: 'TP-LINK_4C50',
235 | pwd: 'IHOSDIFH8374@',
236 | coord: [ 1737, 888 ],
237 | }, {
238 | actif: true,
239 | name: 'SSID-98765432',
240 | pwd: '23456SUDQHM+',
241 | coord: [ 89, 364 ],
242 | },
243 | ],
244 | },
245 | };
246 |
247 | export default config;
248 |
--------------------------------------------------------------------------------
/src/assets/fonts/pixelop.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 |
--------------------------------------------------------------------------------
/src/components/PhoneAim.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Device } from '../store/types';
3 | import { AimOutlined, LoadingOutlined } from '@ant-design/icons';
4 | import { List, Input, Checkbox, Button } from 'antd';
5 |
6 | const styles = {
7 | tiled: {
8 | width: '100%',
9 | height: '100%',
10 | background: 'blue',
11 | display: 'flex',
12 | flexDirection: 'column',
13 | } as React.CSSProperties,
14 | tiledInactif: {
15 | width: '100%',
16 | height: '100%',
17 | background: 'grey',
18 | display: 'flex',
19 | flexDirection: 'column',
20 | } as React.CSSProperties,
21 | content: {
22 | position: 'relative',
23 | display: "flex",
24 | flexDirection: "column",
25 | height: '100%',
26 | overflowY: 'auto',
27 | justifyContent: "center",
28 | fontFamily: "Roboto, sans-serif",
29 | color: "white",
30 | } as React.CSSProperties,
31 | contentChild: {
32 | maxHeight: "calc(100% - 120px)",
33 | overflowY: 'scroll'
34 | } as React.CSSProperties,
35 | backBtn: {
36 | position: 'absolute',
37 | bottom: 0,
38 | right: 0,
39 | left: 0,
40 | background: '#373737',
41 | textAlign: 'center',
42 | padding: '5px',
43 | } as React.CSSProperties,
44 | fullWidth: {
45 | width: '100%',
46 | },
47 | };
48 |
49 | type PhoneAimType = {
50 | wifiName: string;
51 | devices: Device[];
52 | onCancel: Function;
53 | onConfirm?: Function;
54 | onDdos: Function;
55 | };
56 | type PhoneAimTiledType = {
57 | onClick: Function;
58 | actif: boolean;
59 | };
60 | type NetworkData = {
61 | dest: string;
62 | text: string;
63 | };
64 |
65 |
66 | const networkListen = {
67 | randomText: ['Transmission Control Protocol, Src Port: 46952', 'Simple Service Discovery Protocol', 'BOOTID, UDPN.ORG: 152549', 'Router Solicitation from 1.1.1.1', 'Standard query response 0x09875', 'TCP Keep-Alive', 'NOTIFIY * HTTP/1.1', 'Ping to 250.230.10.20'],
68 | randomDest: 254,
69 | };
70 |
71 | const dataTools = [
72 | { name: 'Scan devices', action: 'scan' },
73 | { name: 'Man in the middle', action: 'mim', },
74 | { name: 'DDoS', action: 'ddos' },
75 | ];
76 |
77 | function PhoneAim(props: PhoneAimType) {
78 | const [step, setStep] = useState('listAttack');
79 | const [loading, setLoading] = useState(false);
80 | const [successChoiceIP, setSuccessChoiceIP] = useState(false);
81 | const [errorChoiceIP, setErrorChoiceIP] = useState(false);
82 | const [choiceIP, setChoiceIP] = useState('');
83 | const [dataNetwork, setDataNetwork] = useState([]);
84 | const [filterNetwork, setFilterNetwork] = useState(false);
85 | const [devicesNetwork, setDevicesNetwork] = useState(props.devices.filter(elt => elt.proba <= parseInt('' + Math.random() * 10)));
86 | const [device, setDevice] = useState(null);
87 |
88 | // scan loader
89 | useEffect(() => {
90 | let timerFunc: ReturnType;
91 | if (loading) {
92 | timerFunc = setTimeout(() => {
93 | if (step === 'scan')
94 | setDevicesNetwork(props.devices.filter(elt => elt.proba <= parseInt('' + Math.random() * 10)));
95 | else if (step === 'ddos') {
96 | if (props.onDdos)
97 | props.onDdos(props.wifiName);
98 | handleReset();
99 | props.onCancel();
100 | }
101 |
102 | setLoading(false);
103 | }, 3000);
104 | }
105 | return () => clearTimeout(timerFunc);
106 | }, [loading, props.devices]);
107 |
108 | const buildRandomNavigation = () => {
109 | const buildOne = () => {
110 | const dest = [
111 | parseInt('' + Math.random() * networkListen.randomDest),
112 | parseInt('' + Math.random() * networkListen.randomDest),
113 | parseInt('' + Math.random() * networkListen.randomDest),
114 | parseInt('' + Math.random() * networkListen.randomDest),
115 | ].join('.');
116 | const text = networkListen.randomText[parseInt('' + Math.random() * networkListen.randomText.length)];
117 | return { dest, text };
118 | }
119 | if (!filterNetwork)
120 | setDataNetwork([ buildOne(), buildOne(), buildOne(), buildOne() ])
121 | else if (dataNetwork.length !== 1) {
122 | const navigation = [];
123 | const device = props.devices.filter(elt => elt.ip === choiceIP)[0];
124 | if (device && device.credentials && device.probaCredential) {
125 | const rand = Math.random() * 10;
126 | const isCredentialsTime = device.probaCredential <= rand;
127 |
128 | if (isCredentialsTime) navigation.push({
129 | dest: 'photogram.art',
130 | text: 'Logged with ' + device.credentials
131 | });
132 | }
133 | setDataNetwork(navigation);
134 | }
135 | }
136 |
137 | // listen mim
138 | useEffect(() => {
139 | let timerFunc: ReturnType;
140 | if (successChoiceIP) {
141 | timerFunc = setTimeout(buildRandomNavigation, 1000);
142 | }
143 | return () => clearTimeout(timerFunc);
144 | }, [dataNetwork]);
145 |
146 | const handleReset = () => {
147 | setStep('listAttack');
148 | setErrorChoiceIP(false);
149 | setSuccessChoiceIP(false);
150 | setFilterNetwork(false);
151 | setDevice(null);
152 | setChoiceIP('');
153 | }
154 |
155 | const handleConfirmDDOS = () => {
156 | setLoading(true);
157 | }
158 |
159 | const handleConfirmMiM = () => {
160 | console.log('confirmMiM');
161 | setErrorChoiceIP(false);
162 | setSuccessChoiceIP(false);
163 | if (props.devices.map(elt => elt.ip).indexOf(choiceIP) === -1)
164 | setErrorChoiceIP(true);
165 | else {
166 | const device = props.devices.filter(elt => elt.ip === choiceIP)[0];
167 | setDevice(device);
168 | setSuccessChoiceIP(true);
169 | setStep('mimListen_' + device.type);
170 | if (device.type === 'navigation' && device.actif)
171 | buildRandomNavigation();
172 | }
173 | }
174 |
175 | return (
176 |
177 | {step === 'listAttack' &&
(
183 |
184 | {
185 | if (item.action === 'scan') setLoading(true);
186 | setStep(item.action);
187 | }
188 | }>
189 | {item.name}
190 |
191 |
192 | )}
193 | />}
194 |
195 | {step === 'scan' &&
196 | {loading && }
197 | {!loading && Devices found on this network
}
200 | dataSource={devicesNetwork}
201 | style={{ background: 'white' }}
202 | renderItem={item => (
203 |
204 | {item.name} IP: {item.ip}
205 |
206 | )}
207 | />}
208 | { setLoading(true); }}>Refresh
209 |
}
210 |
211 | {step === 'mim' &&
212 |
Man in the middle
213 |
Choose an address to attack. Your phone will become the relay between the Internet and the device using this address. This means that each request will first go through your phone where you can choose to listen or even edit the response.
214 | {successChoiceIP &&
Success
}
215 | {errorChoiceIP &&
Fail. Wrong IP ?
}
216 |
) => setChoiceIP(e.target.value)} placeholder="192.168.0.0" prefix={'IP:'} />
217 |
Connect
218 |
}
219 |
220 | {step === 'mimListen_navigation' &&
221 |
Listen to the network live...
222 |
223 | Filter:
224 | setFilterNetwork(e.target.checked)}>Only credentials
225 |
226 |
(
232 |
233 | {choiceIP} to {item.dest}
234 | {item.text}
235 |
236 | )}
237 | />
238 |
}
239 |
240 | {step === 'mimListen_watch' &&
241 |
Listen to the network live...
242 |
It seems that the content is encrypted.
243 |
{device && device.credentials}
244 |
}
245 |
246 | {step === 'mimListen_music' &&
247 |
Listen to the network live...
248 |
It seems that the device is running {device && device.credentials && device.credentials[parseInt('' + Math.random() * device.credentials.length)]} .
249 |
}
250 |
251 | {step === 'ddos' &&
252 | {!loading && <>
253 |
DDoS attack
254 |
Your phone will connect to the SearchHouse lab network and request 10 million queries from multiple sources on your current network. This should overload the system... Are you sure you want to do this ?
255 |
DDoS
256 | >}
257 | {loading &&
}
258 |
}
259 |
260 | {
261 | if (step === 'listAttack') {
262 | props.onCancel();
263 | } else setStep('listAttack');
264 | handleReset();
265 | }
266 | }>Back
267 |
268 | )
269 | }
270 |
271 | export const PhoneAimTiled = (props: PhoneAimTiledType) => {
272 | return (
273 | props.onClick() : () => {}} style={props.actif ? styles.tiled : styles.tiledInactif}>
274 |
275 |
Tools
276 |
277 | )
278 | }
279 |
280 | export default PhoneAim;
--------------------------------------------------------------------------------
/src/components/ComputerScreen.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { UserOutlined, LockOutlined, LoadingOutlined } from '@ant-design/icons';
3 | import { Input, Button, Card, Timeline } from 'antd';
4 | import { displayDate, levelDisplay } from '../store/utils';
5 | import {
6 | Chart as ChartJS,
7 | RadialLinearScale,
8 | ArcElement,
9 | Tooltip,
10 | Legend,
11 | } from 'chart.js';
12 | import { PolarArea } from 'react-chartjs-2';
13 |
14 | ChartJS.register(RadialLinearScale, ArcElement, Tooltip, Legend);
15 |
16 | const catcherData = [
17 | {
18 | name: 'SMS',
19 | color: 'rgba(255, 99, 132, 0.5)',
20 | coef: 6,
21 | }, {
22 | name: 'Credentials',
23 | color: 'rgba(54, 162, 235, 0.5)',
24 | coef: 1,
25 | max: 1,
26 | }, {
27 | name: 'Pictures',
28 | color: 'rgba(255, 206, 86, 0.5)',
29 | coef: 3,
30 | }, {
31 | name: 'Calls',
32 | color: 'rgba(75, 192, 192, 0.5)',
33 | coef: 4,
34 | }, {
35 | name: 'Videos',
36 | color: 'rgba(153, 102, 255, 0.5)',
37 | coef: 2,
38 | }, {
39 | name: 'Others',
40 | color: 'rgba(255, 159, 64, 0.5)',
41 | coef: 5,
42 | }
43 | ];
44 |
45 | const { Meta } = Card;
46 |
47 | const styles = {
48 | screenContainer: {
49 | width: '100vw',
50 | maxWidth: '100%',
51 | height: '87vh',
52 | maxHeight: '100%',
53 | } as React.CSSProperties,
54 | AppContain: {
55 | height: '100%',
56 | } as React.CSSProperties,
57 | navBar: {
58 | minHeight: '35px',
59 | background: '#5936ff',
60 | color: 'white',
61 | textShadow: '1px 1px 1px black',
62 | borderBottom: '1px solid black',
63 | } as React.CSSProperties,
64 | logo: {
65 | position: 'relative',
66 | top: '5px',
67 | left: '5px',
68 | } as React.CSSProperties,
69 | center: {
70 | display: 'flex',
71 | justifyContent: 'center',
72 | alignItems: 'center',
73 | flexDirection: 'column',
74 | maxWidth: '500px',
75 | width: '100%',
76 | height: '100%',
77 | margin: 'auto',
78 | } as React.CSSProperties,
79 | fail: {} as React.CSSProperties,
80 | name: {} as React.CSSProperties,
81 | password: {} as React.CSSProperties,
82 | submit: {} as React.CSSProperties,
83 | profil: {
84 | float: 'right',
85 | } as React.CSSProperties,
86 | content: {
87 | display: 'flex',
88 | flexDirection: 'column',
89 | overflow: 'scroll',
90 | maxHeight: '90%',
91 | alignItems: 'center',
92 | marginTop: '15px',
93 | marginBottom: '15px',
94 |
95 | } as React.CSSProperties,
96 | card: {
97 | width: '300px',
98 | margin: '5px',
99 | } as React.CSSProperties,
100 | };
101 |
102 | type ComputerScreenType = {
103 | children?: any;
104 | mode?: string;
105 | started?: number;
106 | };
107 |
108 | function ComputerScreen(props: ComputerScreenType) {
109 | const enumStep = { login: 0, dashboard: 1, profil: 2, creditCard: 3, credentialIMSIPage: 4 };
110 | const [step, setStep] = useState(enumStep.login);
111 | const [loading, setLoading] = useState(false);
112 | const enumLogged = { success: 2, fail: 1, init: 0 };
113 | const [logged, setLogged] = useState(enumLogged.init);
114 | const [name, setName] = useState('SARA');
115 | const [password, setPassword] = useState('');
116 |
117 | useEffect(() => {
118 | let timerFunc: ReturnType;
119 | if (loading) {
120 | timerFunc = setTimeout(() => {
121 | setLoading(false);
122 | }, 750);
123 | }
124 | return () => clearTimeout(timerFunc);
125 | }, [loading]);
126 |
127 | const buildDataIMSI = () => {
128 | return {
129 | labels: catcherData.map(elt => elt.name),
130 | datasets: [
131 | {
132 | label: '# of Data Catched',
133 | data: catcherData.map(elt => levelDisplay(diffDate(), elt.coef, elt.max)),
134 | backgroundColor: catcherData.map(elt => elt.color),
135 | borderWidth: 1,
136 | },
137 | ],
138 | }
139 | }
140 |
141 | const tryLogin = () => {
142 | if (name === 'SARA' && password === 'AOKZC3O2') {
143 | setLogged(enumLogged.success);
144 | handleChgmtPage(enumStep.dashboard);
145 | }
146 | else
147 | setLogged(enumLogged.fail);
148 | }
149 |
150 | const handleChgmtPage = (page: number) => {
151 | if (page !== step) {
152 | setLoading(true);
153 | setStep(page);
154 | }
155 | }
156 |
157 | const getCredentialsFound = () => {
158 | const data = catcherData.filter(elt => elt.name === 'Credentials')[0];
159 | return data ? levelDisplay(diffDate(), data.coef, data.max) : 0;
160 | }
161 |
162 | const diffDate = () => {
163 | const d = new Date();
164 | if (props.started) {
165 | const diff = d.getTime() - props.started;
166 | const minutes = Math.floor(diff / 60000);
167 | //const seconds = ((diff % 60000) / 1000).toFixed(0);
168 | return minutes;
169 | }
170 | return 0;
171 | }
172 |
173 | return (
174 |
175 | {(!props.mode || props.mode === 'photogram') && <>
176 | {!loading && (step === enumStep.login || (step === enumStep.dashboard && logged !== enumLogged.success)) &&
177 |
178 | PhotoGram.Art
179 |
180 |
181 | {logged === enumLogged.fail &&
Wrong credentials
}
182 |
183 |
184 |
) => setName(e.target.value)} placeholder="Name" prefix={
} />
185 |
) => setPassword(e.target.value)} placeholder="Password" prefix={
} />
186 |
Connect
187 |
188 |
189 |
190 |
}
191 |
192 | {!loading && step === enumStep.dashboard && logged === enumLogged.success &&
193 |
194 | handleChgmtPage(enumStep.dashboard)} style={styles.logo}>PhotoGram.Art
195 | handleChgmtPage(enumStep.profil)} style={styles.profil} type="primary">Profil
196 |
197 |
198 |
205 | }
206 | >
207 |
211 |
212 |
213 |
220 | }
221 | >
222 |
226 |
227 |
228 |
235 | }
236 | >
237 |
241 |
242 |
243 |
250 | }
251 | >
252 |
256 |
257 |
258 |
265 | }
266 | >
267 |
271 |
272 |
273 |
}
274 |
275 | {!loading && step === enumStep.profil &&
276 |
277 | handleChgmtPage(enumStep.dashboard)} style={styles.logo}>PhotoGram.Art
278 | handleChgmtPage(enumStep.profil)} style={styles.profil} type="primary">Profil
279 |
280 |
281 |
Name: Sara
282 |
Followers: 1269
283 |
Following: 177
284 |
Birthday: 09/05/2000
285 |
Mail: sara_connor@photogram.art
286 |
Last login: 5min ago
287 |
Find here the informations built according to your usage of PhotoGram:
288 |
Gender: Woman
289 |
Time spent: 185min per day
290 |
Affinity with: Chocolate, Clothes, Cats
291 |
Language: English
292 |
Location: Bourg Palette
293 |
Education: University
294 |
Employement: False
295 |
Political views: Is socially influenced
296 |
Relashionship status: Single
297 |
Planning to have a baby: False
298 |
Number of child: 0
299 |
Have a cat: True
300 |
Loans: 0
301 |
Income: 0
302 |
Vehicles owned: 1
303 |
Properties owned: 0
304 |
Type of home: Multi-family
305 |
Insurance: No major medical insurance
306 |
Health: Diabetic
307 |
Alcohol: Interest
308 |
Tobacco: Interest
309 |
Lottery: False
310 |
Casino gaming: False
311 |
Religion: Catholic
312 |
Economic stable: True
313 |
Receptive to ads: True
314 |
Version commercial beta: True
315 |
Already bought online: True
316 |
handleChgmtPage(enumStep.creditCard)}>List of recent purcharses
317 |
318 |
}
319 |
320 | {!loading && step === enumStep.creditCard &&
321 |
322 | handleChgmtPage(enumStep.dashboard)} style={styles.logo}>PhotoGram.Art
323 | handleChgmtPage(enumStep.profil)} style={styles.profil} type="primary">Profil
324 |
325 |
326 |
327 | {displayDate(0)} - Coffee offer to @LabewCoffee
328 | {displayDate(0)} - Chocolate from Adviser #E564
329 | {displayDate(2)} - Bag from Adviser #F265
330 | {displayDate(6)} - Shoes from Adviser #CA56
331 | {displayDate(10)} - Bag from Adviser #XWAK
332 | {displayDate(15)} - Underclothes from Adviser #AA5X
333 | {displayDate(18)} - Game for Cats from Adviser #SOJA
334 | {displayDate(23)} - Tools from Adviser #WAWA
335 |
336 |
337 | 4165 9810 WOXHAP89
338 | 18/25 - 054
339 |
340 |
341 |
}
342 | >}
343 |
344 | {props.mode === 'imsi' && <>
345 |
346 |
IMSI Catcher
347 | {step === enumStep.login &&
348 |
Launched since: {diffDate()}min
349 |
Caught {getCredentialsFound()} credential
350 | {getCredentialsFound() > 0 &&
handleChgmtPage(enumStep.credentialIMSIPage)}>See result }
351 |
352 |
}
353 |
354 | {step === enumStep.credentialIMSIPage &&
355 |
358 |
365 |
366 | handleChgmtPage(enumStep.login)}>Back
367 |
}
368 |
369 | >}
370 |
371 | {loading &&
372 |
373 |
}
374 |
375 | )
376 | }
377 |
378 | export default ComputerScreen;
--------------------------------------------------------------------------------
/src/assets/maps/software_v.tmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,
12 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,
13 | 47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,
14 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,
15 | 47,1073741946,1073741947,86,87,86,87,86,3221225595,3221225594,47,46,47,46,47,46,47,46,47,1073741946,1073741947,86,87,86,87,86,3221225595,3221225594,47,46,
16 | 46,1073741907,1073741908,125,126,125,126,125,3221225556,3221225555,46,47,46,47,46,47,46,47,46,1073741907,1073741908,125,126,125,126,125,3221225556,3221225555,46,47,
17 | 47,44,45,46,47,46,47,46,5,6,47,46,47,46,47,46,47,46,47,44,45,46,47,46,47,46,5,6,47,46,
18 | 46,5,6,47,46,47,46,47,44,45,46,47,46,47,46,47,46,47,46,5,6,47,46,47,46,47,44,45,46,47,
19 | 47,44,45,46,47,46,47,46,5,6,47,46,47,46,47,46,47,46,47,44,45,46,47,46,47,46,5,6,47,46,
20 | 46,83,84,85,86,85,86,85,88,89,46,47,46,47,46,47,46,47,46,83,84,85,86,85,86,85,88,89,46,47,
21 | 47,122,123,124,125,124,125,124,127,128,47,46,47,46,47,46,47,46,47,122,123,124,125,124,125,124,127,128,47,46,
22 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,
23 | 47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,
24 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,
25 | 47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,
26 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,
27 | 47,1073741946,1073741947,86,87,86,87,86,3221225595,3221225594,47,46,47,46,47,46,47,46,47,1073741946,1073741947,86,87,86,87,86,3221225595,3221225594,47,46,
28 | 46,1073741907,1073741908,125,126,125,126,125,3221225556,3221225555,46,47,46,47,46,47,46,47,46,1073741907,1073741908,125,126,125,126,125,3221225556,3221225555,46,47,
29 | 47,44,45,46,47,46,47,46,5,6,47,46,47,46,47,46,47,46,47,44,45,46,47,46,47,46,5,6,47,46,
30 | 46,5,6,47,46,47,46,47,44,45,46,47,46,47,46,47,46,47,46,5,6,47,46,47,46,47,44,45,46,47,
31 | 47,44,45,46,47,46,47,46,5,6,47,46,47,46,47,46,47,46,47,44,45,46,47,46,47,46,5,6,47,46,
32 | 46,83,84,85,86,85,86,85,88,89,46,47,46,47,46,47,46,47,46,83,84,85,86,85,86,85,88,89,46,47,
33 | 47,122,123,124,125,124,125,124,127,128,47,46,47,46,47,46,47,46,47,122,123,124,125,124,125,124,127,128,47,46,
34 | 46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47,46,47
35 |
36 |
37 |
38 |
39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
42 | 0,0,0,0,0,0,0,0,0,0,0,0,12,13,13,13,13,14,0,0,0,0,0,0,0,0,0,0,0,0,
43 | 0,0,0,0,0,0,0,0,0,0,0,0,51,52,52,52,52,53,0,0,0,0,0,0,0,0,0,0,0,0,
44 | 0,0,0,0,0,0,0,0,0,0,0,0,51,52,52,52,52,53,0,0,0,0,0,0,0,0,0,0,0,0,
45 | 0,0,0,0,0,0,0,0,0,0,0,0,90,130,52,52,2147483778,92,0,0,0,0,0,0,0,0,0,0,0,0,
46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
47 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
48 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
51 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
52 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
53 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
54 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
55 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
56 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
59 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
60 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
61 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0,
62 | 0,0,0,0,0,0,0,0,0,0,0,0,0,131,52,52,2147483779,0,0,0,0,0,0,0,0,0,0,0,0,0
63 |
64 |
65 |
66 |
67 | 26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,
68 | 65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,
69 | 104,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,106,
70 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
71 | 140,0,0,0,226,0,0,0,0,0,0,0,0,0,0,228,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
72 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
73 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,272,273,304,0,0,142,
74 | 140,0,0,272,273,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,311,312,0,0,0,142,
75 | 140,0,0,311,312,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,350,351,0,0,0,142,
76 | 140,0,0,350,351,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
77 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
78 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
79 | 140,0,0,0,0,0,0,0,0,0,890,891,0,0,0,0,0,0,2147484539,2147484538,0,0,0,0,0,305,0,0,0,142,
80 | 140,0,0,0,0,0,0,0,0,0,929,930,0,0,0,0,0,0,2147484578,2147484577,0,0,0,0,0,0,0,0,0,142,
81 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
82 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
83 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
84 | 140,0,0,152,113,0,73,74,0,0,0,0,0,0,0,0,0,0,0,0,0,272,273,0,0,0,0,0,0,142,
85 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,311,312,0,0,0,0,0,0,142,
86 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,350,351,0,0,0,0,0,0,142,
87 | 140,0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
88 | 140,0,618,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
89 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
90 | 140,0,0,0,0,0,0,0,0,0,0,0,0,614,0,0,615,0,0,0,0,0,0,0,0,0,0,0,208,142
91 |
92 |
93 |
94 |
95 | 0,0,0,0,0,0,0,0,0,0,0,0,0,582,583,584,585,0,0,0,0,0,0,0,0,0,0,0,0,0,
96 | 0,0,0,0,770,771,0,0,0,322,0,0,0,621,622,623,624,581,0,0,0,323,0,0,0,577,577,578,580,0,
97 | 0,0,0,0,809,810,0,0,0,361,0,0,0,660,661,662,663,620,0,0,0,362,0,0,0,616,616,617,619,0,
98 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
99 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
101 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,693,0,0,0,0,
102 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103 | 0,0,0,692,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
104 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
105 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
106 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
107 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
108 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
109 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
110 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
111 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
113 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,694,0,0,0,0,0,0,0,0,
114 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
115 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
116 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
117 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
118 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
119 |
120 |
121 |
122 |
123 | 0,0,0,0,731,732,335,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,335,336,0,0,0,0,0,0,
124 | 0,0,0,0,0,0,374,375,0,0,0,0,0,0,0,0,0,0,0,0,0,0,374,375,0,0,0,0,0,0,
125 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
126 | 0,0,0,0,187,0,0,0,0,0,0,0,0,0,0,189,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
127 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,265,0,0,0,
129 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
130 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
131 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
132 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
133 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
134 | 0,0,0,0,0,0,0,0,0,0,851,0,0,0,0,0,0,0,0,2147484499,0,0,0,0,0,266,0,0,0,0,
135 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
136 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
137 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
138 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
139 | 0,0,0,0,0,0,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
140 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
141 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
142 | 0,0,0,0,0,0,345,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
143 | 0,0,579,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
144 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
145 | 0,0,0,0,0,0,0,0,0,0,0,0,0,575,0,0,576,0,0,0,0,0,0,0,0,0,0,0,169,0,
146 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
147 |
148 |
149 |
150 |
151 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
152 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
153 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
154 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
155 | 40,0,0,0,40,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
156 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
157 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,40,0,0,40,
158 | 40,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,0,0,0,40,
159 | 40,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,40,
160 | 40,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
161 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
162 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
163 | 40,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,40,40,0,0,0,0,0,40,0,0,0,40,
164 | 40,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,40,
165 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
166 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
167 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
168 | 40,0,0,40,40,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,40,
169 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,40,
170 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,40,
171 | 40,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
172 | 40,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
173 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
174 | 40,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,40,0,0,0,0,0,0,0,0,0,0,0,40,40
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 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from 'react';
2 |
3 | import config from './config';
4 | import GameContext from "./store";
5 | import { getHour, calculateDistance } from "./store/utils";
6 |
7 | import {
8 | Objects,
9 | } from "./store/types";
10 |
11 | import './App.css';
12 | import "antd/dist/antd.css";
13 | import "nes.css/css/nes.min.css";
14 |
15 | import phaserGame from './PhaserGame';
16 |
17 | import NavBar from './components/NavBar';
18 | import PixelPhone from './components/PixelPhone';
19 | import PhoneWifi, { PhoneWifiTiled } from './components/PhoneWifi';
20 | import PhoneAim, { PhoneAimTiled } from './components/PhoneAim';
21 | import { PhoneContactTiled } from './components/PhoneContact';
22 | import { PhoneCallTiled } from './components/PhoneCall';
23 | import { PhoneMailTiled } from './components/PhoneMail';
24 | import { PhoneMessageTiled } from './components/PhoneMessage';
25 | import ComputerScreen from './components/ComputerScreen';
26 |
27 | import { WifiOutlined, ThunderboltOutlined, LoadingOutlined } from '@ant-design/icons';
28 | import { Modal, Input } from "antd";
29 | const { Search } = Input;
30 |
31 | type Player = {
32 | x: number;
33 | y: number;
34 | };
35 |
36 | function App() {
37 | const store = useContext(GameContext);
38 | const objects: Objects = config.game.objects;
39 | const [progressionQuest, setProgressionQuest] = useState([]);
40 | ///////////////
41 |
42 | const [countLoader, setCountLoader] = useState(1);
43 | const [dialogSign, setDialogSign] = useState('');
44 |
45 | // screen display
46 | const [screenVisible, setScreenVisible] = useState(false);
47 | const [stepScreenComputer, setStepScreenComputer] = useState('');
48 |
49 | // phone display
50 | const [stepPhone, setStepPhone] = useState('');
51 | const [phoneConnected, setPhoneConnected] = useState([]);
52 | const [phoneVisible, setPhoneVisible] = useState(false);
53 | const [player, setPlayer] = useState(null);
54 |
55 | // menu display
56 | const [stepMenu, setStepMenu] = useState(0);
57 | const [questMenu, setQuestMenu] = useState('');
58 | const [isMenuVisible, setIsMenuVisible] = useState(false);
59 |
60 | // during quest
61 | const [signText, setSignText] = useState('');
62 | const [stepDialogQuest, setStepDialogQuest] = useState(0);
63 | const [dialogQuest, setDialogQuest] = useState('');
64 | const [successText, setSuccessText] = useState('');
65 | const [breakGame, setBreakGame] = useState(false);
66 |
67 | // Loader (for debug)
68 | useEffect(() => {
69 | if (phaserGame.scene.keys.OverWorldScene) {
70 | setCountLoader(0);
71 | }
72 | }, []);
73 |
74 |
75 | // when sign change
76 | useEffect(() => {
77 | //console.log('signText', signText);
78 | if (store.user && !stepDialogQuest && !stepScreenComputer) {
79 | if (store.quest) {
80 | const questGoal = Object.keys(store.quest.goalOrder).filter(elt => store.quest && !store.quest.goalOrder[elt].optional);
81 | const order = questGoal.indexOf(signText) === -1 ? 0 : questGoal.indexOf(signText);
82 | const orderRespected = store.quest.orderFix ? order === progressionQuest.length : true;
83 | if (store.quest.goalOrder[signText] && orderRespected && progressionQuest.indexOf(signText) === -1) {
84 | if (store.quest.goalOrder[signText].computerScreen) {
85 | setStepScreenComputer(store.quest.goalOrder[signText].computerMode);
86 | handleScreen(true);
87 | }
88 | else handleDialogQuest(signText);
89 | } else setDialogSign(signText);
90 | }
91 | else setDialogSign(signText);
92 | }
93 | }, [signText]);
94 |
95 | // Loader & events
96 | useEffect(() => {
97 | if (countLoader > 0) {
98 | setTimeout(async () => {
99 | if (countLoader > 0 && store && store.user && phaserGame.scene.keys.OverWorldScene) {
100 | setCountLoader(0);
101 |
102 | // ADD HANDLER FOR SIGN EVENT
103 | phaserGame.scene.keys.OverWorldScene.events.on('sign', (text: string) => setSignText(text));
104 | phaserGame.scene.keys.SoftwareScene.events.on('sign', (text: string) => setSignText(text));
105 | phaserGame.scene.keys.OverWorldScene.events.on('player', (player: any) => setPlayer(player));
106 |
107 | // check loading quest
108 | if (store.user.loadingLevel) {
109 | const prevQuestFinished = store.getPrevQuest();
110 | if (prevQuestFinished) setSuccessText(store.quests[prevQuestFinished].success + '\n\nFlag is: ' + store.currentQ);
111 | setIsMenuVisible(true);
112 | handleBreak();
113 | store.setNewLevelViewed();
114 | }
115 |
116 | // init player position
117 | getUserPosition();
118 | }
119 | else if (countLoader > 0) setCountLoader(countLoader + 1);
120 | }, 1000);
121 | }
122 | }, [countLoader]);
123 |
124 | const handlePhoneSuccess = async (method: string, text: string) => {
125 | if (!store.quest) return false;
126 | if (method === 'wifi') {
127 | store.addWifiKnow(text);
128 |
129 | // close phone
130 | handlePhone();
131 |
132 | const cQ = progressionQuest;
133 | cQ.push('phone');
134 | await setProgressionQuest(cQ)
135 | }
136 | await checkQuest();
137 | }
138 |
139 | const checkQuest = () => {
140 | if (!store.quest) return false;
141 |
142 | // remove optionnal
143 | const progression = progressionQuest.filter(elt => store.quest && store.quest.goalOrder[elt].optional ? false : true)
144 | const goal = Object.keys(store.quest.goalOrder).filter(elt => store.quest && store.quest.goalOrder[elt].optional ? false : true);
145 |
146 | // todo, if press enter to pass dialog = check menu not open
147 | if (progression.join(',') === goal.join(',')) {
148 | const flag = store.getNextQuest();
149 | if (flag) setSuccessText(store.quest.success + '\n\nFlag is: ' + flag);
150 | else setSuccessText(store.quest.success + '\n\nYou have completed the game.');
151 | setIsMenuVisible(true);
152 | setProgressionQuest([]);
153 | handleBreak();
154 | }
155 | }
156 |
157 | const handleDialogQuest = (text: string) => {
158 | if (!store.quest) return false;
159 |
160 | const cQ = progressionQuest;
161 | const goal = store.quest.goalOrder[text];
162 |
163 | // dialog start = break movement
164 | if (stepDialogQuest === 0 && goal.break)
165 | handleBreak();
166 | // dialog continue
167 | if (goal.dialog && goal.dialog.length > stepDialogQuest) {
168 | setDialogSign(text);
169 | setDialogQuest(goal.dialog[stepDialogQuest]);
170 | setStepDialogQuest(stepDialogQuest + 1);
171 | }
172 | // dialog done
173 | else if (goal.dialog && stepDialogQuest === goal.dialog.length) {
174 | setDialogSign('');
175 | setStepDialogQuest(0);
176 | setDialogQuest('');
177 | cQ.push(text);
178 | setProgressionQuest(cQ);
179 | handleBreak();
180 | checkQuest();
181 | }
182 | }
183 |
184 | const handleBreak = () => {
185 | setBreakGame(!breakGame);
186 | const OverWorldScene = phaserGame.scene.keys.OverWorldScene;
187 | const SoftwareScene = phaserGame.scene.keys.SoftwareScene;
188 | OverWorldScene.events.emit('break');
189 | SoftwareScene.events.emit('break');
190 | }
191 |
192 | const getUserPosition = () => {
193 | const OverWorldScene = phaserGame.scene.keys.OverWorldScene;
194 | OverWorldScene.events.emit('position');
195 | }
196 |
197 | const handlePhone = () => {
198 | if (!store.user || countLoader) return false;
199 | checkConnected();
200 | setPhoneVisible(!phoneVisible);
201 | handleBreak();
202 | }
203 |
204 | const checkConnected = async () => {
205 | await getUserPosition();
206 | if (player) {
207 | const connected = store.wifi
208 | .filter(elt => elt.actif)
209 | .filter(elt => store.user && store.user.wifiKnow.indexOf(elt.name) !== -1)
210 | .filter(elt => calculateDistance([player.x, player.y], elt.coord) >= 0)
211 | .sort((a, b) => calculateDistance([player.x, player.y], a.coord) - calculateDistance([player.x, player.y], b.coord))
212 | .map(elt => elt.name);
213 | setPhoneConnected(connected);
214 | }
215 | }
216 |
217 | const handleMenu = () => {
218 | if (!store.user || countLoader) return false;
219 | setIsMenuVisible(!isMenuVisible);
220 | setStepMenu(0);
221 | handleBreak();
222 | if (successText)
223 | setSuccessText('');
224 | }
225 |
226 | const handleScreen = (open: boolean) => {
227 | handleBreak();
228 | setScreenVisible(open);
229 | if (!open) setStepScreenComputer('');
230 | }
231 |
232 | // Gestion Menu
233 | const menuDisplay = () => {
234 | const currentLevel = store.user ? store.user.level : 1;
235 | const newLevel = store.user ? store.user.newLevel : false;
236 | const enumMenu = {
237 | init: 0,
238 | enterCode: 1,
239 | saveCode: 2,
240 | option: 3,
241 | quests: 4,
242 | descQuest: 5,
243 | credit: 6,
244 | };
245 |
246 | const initMenu = (
247 | <>
248 | V {config.version} - level {currentLevel}
249 | setStepMenu(enumMenu.enterCode)}>ENTER A FLAG
250 | setStepMenu(enumMenu.saveCode)}>SAVE
251 | setStepMenu(enumMenu.quests)}>
252 | QUESTS
253 | {newLevel && NEW }
254 |
255 | setStepMenu(enumMenu.option)}>OPTION
256 | setStepMenu(enumMenu.credit)}>CREDIT
257 | EXIT
258 | >
259 | );
260 |
261 | const enterCodeMenu = (
262 |
263 |
Enter a flag
264 |
}
268 | onSearch={(value) => store.loadAFlag(value)}
269 | />
270 |
If nothing happens: your flag is false.
271 |
setStepMenu(enumMenu.init)}>BACK
272 |
273 | );
274 |
275 | const saveCodeMenu = (
276 | <>
277 | Your current Flag is:
278 | {store.currentQ}
279 | setStepMenu(enumMenu.init)}>BACK
280 | >
281 | );
282 |
283 | const optionMenu = (
284 | <>
285 | store.resetGame()} style={{ background: 'tomato', color: 'white', padding: '5px', }}>Reset your game
286 | setStepMenu(enumMenu.init)}>BACK
287 | >
288 | )
289 |
290 | const creditMenu = (
291 | <>
292 | README
293 | setStepMenu(enumMenu.init)}>BACK
294 | >
295 | )
296 |
297 | const availableQuests: string[] = Object.keys(store.quests).filter(e => store.quests[e].level <= currentLevel);
298 | const questsMenu = (
299 | <>
300 | {availableQuests.map((e: string, index: number) =>
301 | {
302 | setQuestMenu(e);
303 | setStepMenu(enumMenu.descQuest);
304 | if (index === availableQuests.length - 1 && newLevel)
305 | store.setNewQuestViewed();
306 | }
307 | }>
308 | {store.quests && store.quests[e] && store.quests[e].title}
309 | {(index < availableQuests.length - 1) && }
310 | {(index === availableQuests.length - 1 && currentLevel > availableQuests.length) && }
311 | {(index === availableQuests.length - 1) && newLevel && NEW }
312 |
313 | )}
314 | setStepMenu(enumMenu.init)}>BACK
315 | >
316 | );
317 | const descQuestMenu = (
318 | <>
319 | {store.quests[questMenu] && store.quests[questMenu].level <= currentLevel && store.quests[questMenu].title}
320 | {store.quests[questMenu] && store.quests[questMenu].level <= currentLevel && store.quests[questMenu].desc}
321 | setStepMenu(enumMenu.quests)}>BACK
322 | >
323 | )
324 |
325 | const stepArr = [initMenu, enterCodeMenu, saveCodeMenu, optionMenu, questsMenu, descQuestMenu, creditMenu]
326 | return (
327 | {stepArr[stepMenu]}
328 |
);
329 | }
330 |
331 | return (
332 |
333 | {/* Title & Menu Btn*/}
334 |
337 |
338 | {/* Loader Screen */}
339 | {countLoader > 0 &&
340 |
341 |
Loading...
342 |
}
343 |
344 | {/* Phone Btn */}
345 | {store.user && store.user.level > 1 &&
346 |
347 | Phone
348 |
349 |
}
350 |
351 | {/* Dialog modal */}
352 | {dialogSign && (objects[dialogSign].default || dialogQuest) &&
handleDialogQuest(dialogSign) : () => {}} className="dialogSign nes-container is-rounded with-title">
353 | {objects[dialogSign].name &&
{objects[dialogSign].name}
}
354 |
{dialogQuest ? dialogQuest : objects[dialogSign].default}
355 | {dialogQuest &&
}
356 |
}
357 |
358 | {/* Modal for Menu & Success Quest */}
359 |
366 | {!successText ? menuDisplay() : successText.split("\n").map((item, idx) => (
367 |
368 | {item}
369 |
370 |
371 | )
372 | )}
373 |
374 |
375 | {/* Modal for Computer Screen */}
376 |
handleScreen(false)}>close]}
379 | closable={false}
380 | wrapClassName="computerScreen"
381 | visible={screenVisible}
382 | onCancel={() => handleScreen(false)}>
383 |
387 |
388 |
389 | {/* Modal for Phone content */}
390 |
397 |
398 |
399 | {player
400 | && phoneConnected.length > 0
401 | &&
{phoneConnected[0]}}
402 | {!phoneConnected.length &&
No network }
403 |
{getHour()}
404 |
405 | {player && stepPhone === 'wifi'
406 | && setStepPhone('')}
409 | onConfirm={(name: string) => { handlePhoneSuccess('wifi', name) }}
410 | wifiKnow={store.user ? store.user.wifiKnow : []}
411 | data={store.wifi ? store.wifi : []}
412 | />}
413 | {stepPhone === 'aim'
414 | && setStepPhone('')}
418 | onConfirm={(name: string) => { handlePhoneSuccess('aim', name) }}
419 | onDdos={(name: string) => { store.ddosWifi(name); checkConnected(); }}
420 | />}
421 | {!stepPhone &&
422 |
setStepPhone('wifi')}/>
423 | 0} onClick={() => setStepPhone('aim')} />
424 |
425 |
426 |
427 |
428 | }
429 |
430 |
431 |
432 | )
433 | }
434 |
435 | export default App
436 |
--------------------------------------------------------------------------------
/src/assets/maps/university-new.tmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
12 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
13 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
14 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
15 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
16 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
17 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
18 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
19 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
20 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
21 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
22 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
23 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
24 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
25 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
26 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
27 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
28 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
29 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
30 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
31 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
32 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
33 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
34 | 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121
35 |
36 |
37 |
38 |
39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
41 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
42 | 0,0,0,0,0,0,0,0,0,79,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43 | 0,0,0,0,0,0,0,0,0,79,79,0,0,0,0,0,0,0,0,0,0,0,0,0,355,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,206,204,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
47 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,547,0,0,550,0,0,0,0,
48 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,283,166,284,0,0,0,0,0,0,0,0,0,0,0,0,0,0,586,587,588,589,0,0,0,0,
49 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,316,0,0,0,0,
51 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,2,3,3,3,3,3,3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,61,0,0,41,42,42,42,42,42,42,42,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
53 | 22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,81,81,81,81,81,81,81,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
54 | 61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,2,3,4,0,0,0,354,0,0,
55 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,316,0,0,0,0,0,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0,
56 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0,
57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0,
58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352,0,0,0,314,0,41,42,43,0,0,0,0,0,0,
59 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0,
60 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,0,0,0,0,0,0,0,41,42,43,0,0,355,0,0,0,
61 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0,
62 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,43,0,0,0,0,0,0
63 |
64 |
65 |
66 |
67 | 23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,
68 | 62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,
69 | 101,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,103,218,219,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,103,
70 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,257,258,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
71 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,296,297,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,142,
72 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,231,0,0,0,0,0,0,0,0,232,142,
73 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,0,0,0,0,271,142,
74 | 140,0,0,0,229,0,0,0,230,0,0,0,381,0,0,0,307,0,0,142,0,0,0,0,0,0,0,0,1281,0,0,0,0,0,0,0,0,0,509,510,0,0,0,0,142,
75 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,207,0,0,0,0,306,0,0,0,0,0,0,0,0,231,0,0,0,548,549,0,0,0,232,142,
76 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,146,0,147,0,0,0,0,0,0,0,270,0,0,0,0,0,0,0,0,271,142,
77 | 140,0,0,0,0,0,308,0,0,0,382,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
78 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
79 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
80 | 179,0,0,0,380,0,0,0,0,0,0,0,383,0,0,0,386,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
81 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
82 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
83 | 141,0,0,0,0,0,148,0,0,0,385,0,0,0,384,0,0,0,0,142,0,310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
84 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,349,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
85 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,1238,1239,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,142,
86 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,1277,1278,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
87 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,310,0,0,0,0,302,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
88 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,349,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
89 | 140,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,208,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,
90 | 140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,0,0,0,0,364,0,0,365,0,0,362,0,0,361,0,0,0,0,0,0,0,0,0,0,142
91 |
92 |
93 |
94 |
95 | 0,0,0,0,0,0,0,0,1121,1122,1123,1124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
96 | 0,894,895,0,337,338,0,0,1160,1161,1162,1163,0,0,337,338,0,1125,1126,0,0,0,0,0,0,0,0,337,338,0,0,0,0,0,0,0,337,338,0,0,0,0,0,0,0,
97 | 0,933,934,0,0,0,0,0,1199,1200,1201,1202,0,0,0,0,0,1164,1165,0,102,102,0,0,1240,1241,0,0,0,0,0,0,0,0,0,0,0,0,0,1240,1241,0,1240,1241,0,
98 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,150,0,0,0,0,0,0,0,0,
99 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
101 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
102 | 0,0,0,0,75,0,0,0,75,0,0,0,75,0,0,0,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
104 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
105 | 890,891,0,0,0,0,75,0,0,0,75,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
106 | 929,930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
107 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
108 | 0,0,0,0,75,0,0,0,76,0,0,0,75,0,0,0,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,150,0,
109 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
110 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
111 | 0,0,0,0,0,0,75,0,0,0,75,0,0,0,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
113 | 890,891,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
114 | 929,930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
115 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
116 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
117 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
118 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
119 |
120 |
121 |
122 |
123 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
124 | 0,172,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
125 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
126 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,264,0,0,0,
127 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1203,0,0,0,0,0,0,0,0,430,431,432,433,0,0,0,0,
129 | 0,0,0,0,190,0,0,0,191,0,0,0,342,0,0,0,268,0,0,0,0,0,0,0,0,0,0,0,1242,0,0,0,0,0,0,0,0,469,470,471,472,0,0,0,0,
130 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,168,0,0,0,0,267,0,0,0,0,0,0,0,0,0,0,0,508,0,0,511,0,0,0,0,
131 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
132 | 851,0,0,0,0,0,269,0,0,0,343,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
133 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
134 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
135 | 0,0,0,0,341,0,0,0,0,0,0,0,344,0,0,0,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
136 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
137 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
138 | 0,0,0,0,0,0,109,0,0,0,346,0,0,0,345,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
139 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
140 | 851,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1204,0,0,
141 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
142 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,263,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
143 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
144 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,169,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
145 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,325,0,0,326,0,0,323,0,0,322,0,0,0,0,0,0,0,0,0,0,0,
146 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
147 |
148 |
149 |
150 |
151 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
152 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
153 | 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
154 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,40,
155 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,40,
156 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,40,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,40,40,
157 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,40,40,
158 | 40,0,0,0,40,0,0,0,40,0,0,0,40,0,0,0,40,0,0,40,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,40,
159 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,40,0,0,0,0,0,0,0,0,40,0,0,0,40,40,0,0,0,40,40,
160 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,40,0,40,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,40,40,
161 | 40,40,0,0,0,0,40,0,0,0,40,0,0,0,40,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
162 | 40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
163 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
164 | 40,0,0,0,40,0,0,0,40,0,0,0,40,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,40,
165 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
166 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
167 | 40,0,0,0,0,0,40,0,0,0,40,0,0,0,40,0,0,0,0,40,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
168 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
169 | 40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,40,0,40,
170 | 40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
171 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,40,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
172 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
173 | 40,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,
174 | 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,0,0,40,0,0,40,0,0,40,0,0,40,0,0,0,0,0,0,0,0,0,0,40
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | Shhhhh...
197 | Hahahahaha
198 | Shhhhh...
199 | Jajajajaja
200 |
201 |
202 |
203 |
204 |
205 | How cool
206 | is my hat?
207 | Cuán cool
208 | es mi sombrero?
209 |
210 |
211 |
212 |
213 |
214 | Caritoooo
215 | suelta tu pena
216 | Caritoooo
217 | suelta tu pena
218 |
219 |
220 |
221 |
222 |
223 | Hi teacher,
224 | when is the exam?
225 | Profesor,
226 | cuándo es el examen?
227 |
228 |
229 |
230 |
231 |
232 | Hi teacher,
233 | when is the exam?
234 | Profesor,
235 | cuándo es el examen?
236 |
237 |
238 |
239 |
240 |
241 | Hi teacher,
242 | when is the exam?
243 | Profesor,
244 | cuándo es el examen?
245 |
246 |
247 |
248 |
249 |
250 | Hi teacher,
251 | when is the exam?
252 | Profesor,
253 | cuándo es el examen?
254 |
255 |
256 |
257 |
258 |
259 | Hi teacher,
260 | when is the exam?
261 | Profesor,
262 | cuándo es el examen?
263 |
264 |
265 |
266 |
267 |
268 | Hi teacher,
269 | when is the exam?
270 | Profesor,
271 | cuándo es el examen?
272 |
273 |
274 |
275 |
276 |
277 | Hi teacher,
278 | when is the exam?
279 | Profesor,
280 | cuándo es el examen?
281 |
282 |
283 |
284 |
285 |
286 | Teacher, what will
287 | be on the exam?
288 | Profesor,
289 | qué va a tomar en el examen?
290 |
291 |
292 |
293 |
294 |
295 | Will the exam
296 | be difficult?
297 | El examen
298 | será difícil?
299 |
300 |
301 |
302 |
303 |
304 | If I fail the exam
305 | Do I get a do-over?
306 | Hay recuperatorio
307 | del examen?
308 |
309 |
310 |
311 |
312 |
313 | What course
314 | is this?
315 | Qué curso
316 | es este?
317 |
318 |
319 |
320 |
321 |
322 | Will the exam
323 | be written?
324 | El examen
325 | será escrito?
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 | I received my PhD in Philosophy
335 | from the University of Buenos
336 | Aires in 2020. I have taught
337 | more than 20 courses at the
338 | undergrad and postgrad levels,
339 | with subjects ranging from logic
340 | to philosophy of science, of
341 | biology and the methodology of
342 | science. To know more, exit through
343 | the door at the left of this room.
344 | Recibí mi doctorado en Filosofía
345 | de la Universidad de Buenos Aires
346 | en 2020. He dictado más de 20 cursos
347 | en los niveles universitario y de
348 | posgrado, sobre temas de lógica,
349 | filosofía de la ciencia, de la
350 | biología y de metodología de la
351 | ciencia. Para saber más, sal por la
352 | puerta de la izquierda.
353 |
354 |
355 |
356 |
357 |
--------------------------------------------------------------------------------
/src/assets/maps/software_v.json:
--------------------------------------------------------------------------------
1 | { "compressionlevel":-1,
2 | "height":24,
3 | "infinite":false,
4 | "layers":[
5 | {
6 | "data":[47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46,
7 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47,
8 | 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46,
9 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47,
10 | 47, 1073741946, 1073741947, 86, 87, 86, 87, 86, 3221225595, 3221225594, 47, 46, 47, 46, 47, 46, 47, 46, 47, 1073741946, 1073741947, 86, 87, 86, 87, 86, 3221225595, 3221225594, 47, 46,
11 | 46, 1073741907, 1073741908, 125, 126, 125, 126, 125, 3221225556, 3221225555, 46, 47, 46, 47, 46, 47, 46, 47, 46, 1073741907, 1073741908, 125, 126, 125, 126, 125, 3221225556, 3221225555, 46, 47,
12 | 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46,
13 | 46, 5, 6, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 44, 45, 46, 47,
14 | 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46,
15 | 46, 83, 84, 85, 86, 85, 86, 85, 88, 89, 46, 47, 46, 47, 46, 47, 46, 47, 46, 83, 84, 85, 86, 85, 86, 85, 88, 89, 46, 47,
16 | 47, 122, 123, 124, 125, 124, 125, 124, 127, 128, 47, 46, 47, 46, 47, 46, 47, 46, 47, 122, 123, 124, 125, 124, 125, 124, 127, 128, 47, 46,
17 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47,
18 | 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46,
19 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47,
20 | 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46,
21 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47,
22 | 47, 1073741946, 1073741947, 86, 87, 86, 87, 86, 3221225595, 3221225594, 47, 46, 47, 46, 47, 46, 47, 46, 47, 1073741946, 1073741947, 86, 87, 86, 87, 86, 3221225595, 3221225594, 47, 46,
23 | 46, 1073741907, 1073741908, 125, 126, 125, 126, 125, 3221225556, 3221225555, 46, 47, 46, 47, 46, 47, 46, 47, 46, 1073741907, 1073741908, 125, 126, 125, 126, 125, 3221225556, 3221225555, 46, 47,
24 | 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46,
25 | 46, 5, 6, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 44, 45, 46, 47,
26 | 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46, 47, 46, 47, 46, 47, 46, 47, 44, 45, 46, 47, 46, 47, 46, 5, 6, 47, 46,
27 | 46, 83, 84, 85, 86, 85, 86, 85, 88, 89, 46, 47, 46, 47, 46, 47, 46, 47, 46, 83, 84, 85, 86, 85, 86, 85, 88, 89, 46, 47,
28 | 47, 122, 123, 124, 125, 124, 125, 124, 127, 128, 47, 46, 47, 46, 47, 46, 47, 46, 47, 122, 123, 124, 125, 124, 125, 124, 127, 128, 47, 46,
29 | 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47, 46, 47],
30 | "height":24,
31 | "id":1,
32 | "name":"Ground1",
33 | "opacity":1,
34 | "type":"tilelayer",
35 | "visible":true,
36 | "width":30,
37 | "x":0,
38 | "y":0
39 | },
40 | {
41 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 13, 13, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 52, 52, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 52, 52, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
47 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 130, 52, 52, 2147483778, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 52, 52, 2147483779, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
65 | "height":24,
66 | "id":2,
67 | "name":"Ground2",
68 | "opacity":1,
69 | "type":"tilelayer",
70 | "visible":true,
71 | "width":30,
72 | "x":0,
73 | "y":0
74 | },
75 | {
76 | "data":[26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28,
77 | 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67,
78 | 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 106,
79 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
80 | 140, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
81 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
82 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 273, 304, 0, 0, 142,
83 | 140, 0, 0, 272, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, 0, 0, 0, 142,
84 | 140, 0, 0, 311, 312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 351, 0, 0, 0, 142,
85 | 140, 0, 0, 350, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
86 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
87 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
88 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 890, 891, 0, 0, 0, 0, 0, 0, 2147484539, 2147484538, 0, 0, 0, 0, 0, 305, 0, 0, 0, 142,
89 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 929, 930, 0, 0, 0, 0, 0, 0, 2147484578, 2147484577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
90 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
91 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
92 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
93 | 140, 0, 0, 152, 113, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 273, 0, 0, 0, 0, 0, 0, 142,
94 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 311, 312, 0, 0, 0, 0, 0, 0, 142,
95 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 351, 0, 0, 0, 0, 0, 0, 142,
96 | 140, 0, 0, 0, 0, 0, 384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
97 | 140, 0, 618, 619, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
98 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142,
99 | 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 614, 0, 0, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 142],
100 | "height":24,
101 | "id":3,
102 | "name":"Collision1",
103 | "opacity":1,
104 | "type":"tilelayer",
105 | "visible":true,
106 | "width":30,
107 | "x":0,
108 | "y":0
109 | },
110 | {
111 | "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 582, 583, 584, 585, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 | 0, 0, 0, 0, 770, 771, 0, 0, 0, 322, 0, 0, 0, 621, 622, 623, 624, 581, 0, 0, 0, 323, 0, 0, 0, 577, 577, 578, 580, 0,
113 | 0, 0, 0, 0, 809, 810, 0, 0, 0, 361, 0, 0, 0, 660, 661, 662, 663, 620, 0, 0, 0, 362, 0, 0, 0, 616, 616, 617, 619, 0,
114 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 693, 0, 0, 0, 0,
118 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 | 0, 0, 0, 692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 694, 0, 0, 0, 0, 0, 0, 0, 0,
130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
135 | "height":24,
136 | "id":4,
137 | "name":"Collision2",
138 | "opacity":1,
139 | "type":"tilelayer",
140 | "visible":true,
141 | "width":30,
142 | "x":0,
143 | "y":0
144 | },
145 | {
146 | "data":[0, 0, 0, 0, 731, 732, 335, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 335, 336, 0, 0, 0, 0, 0, 0,
147 | 0, 0, 0, 0, 0, 0, 374, 375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, 375, 0, 0, 0, 0, 0, 0,
148 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
149 | 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, 0, 0, 0,
152 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
154 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
156 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
157 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 851, 0, 0, 0, 0, 0, 0, 0, 0, 2147484499, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0,
158 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
159 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
162 | 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
163 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165 | 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166 | 0, 0, 579, 580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 575, 0, 0, 576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0,
169 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
170 | "height":24,
171 | "id":5,
172 | "name":"Above",
173 | "opacity":1,
174 | "type":"tilelayer",
175 | "visible":true,
176 | "width":30,
177 | "x":0,
178 | "y":0
179 | },
180 | {
181 | "data":[40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
182 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
183 | 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
184 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
185 | 40, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
186 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
187 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 0, 0, 40,
188 | 40, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 40,
189 | 40, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 40,
190 | 40, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
191 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
192 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
193 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 40, 0, 0, 0, 40,
194 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
195 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
196 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
197 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
198 | 40, 0, 0, 40, 40, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 40,
199 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 40,
200 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 40,
201 | 40, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
202 | 40, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
203 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,
204 | 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40],
205 | "height":24,
206 | "id":7,
207 | "name":"CollisionLayer",
208 | "opacity":1,
209 | "type":"tilelayer",
210 | "visible":true,
211 | "width":30,
212 | "x":0,
213 | "y":0
214 | },
215 | {
216 | "draworder":"topdown",
217 | "id":6,
218 | "name":"Objects",
219 | "objects":[
220 | {
221 | "height":0,
222 | "id":1,
223 | "name":"Spawn Point",
224 | "point":true,
225 | "rotation":0,
226 | "type":"",
227 | "visible":true,
228 | "width":0,
229 | "x":480,
230 | "y":704
231 | },
232 | {
233 | "gid":1,
234 | "height":9,
235 | "id":2,
236 | "name":"door",
237 | "properties":[
238 | {
239 | "name":"destination",
240 | "type":"string",
241 | "value":"OverWorldScene"
242 | },
243 | {
244 | "name":"link",
245 | "type":"bool",
246 | "value":false
247 | }],
248 | "rotation":0,
249 | "type":"door",
250 | "visible":true,
251 | "width":64,
252 | "x":448,
253 | "y":768
254 | },
255 | {
256 | "gid":1,
257 | "height":32,
258 | "id":5,
259 | "name":"sign",
260 | "properties":[
261 | {
262 | "name":"direction",
263 | "type":"string",
264 | "value":"down"
265 | },
266 | {
267 | "name":"text",
268 | "type":"string",
269 | "value":"id7"
270 | }],
271 | "rotation":0,
272 | "type":"sign",
273 | "visible":true,
274 | "width":32,
275 | "x":192,
276 | "y":672
277 | },
278 | {
279 | "gid":1,
280 | "height":32,
281 | "id":12,
282 | "name":"sign",
283 | "properties":[
284 | {
285 | "name":"direction",
286 | "type":"string",
287 | "value":"up"
288 | },
289 | {
290 | "name":"text",
291 | "type":"string",
292 | "value":"id13"
293 | }],
294 | "rotation":0,
295 | "type":"sign",
296 | "visible":true,
297 | "width":32,
298 | "x":63.9773993661834,
299 | "y":703.725100316908
300 | },
301 | {
302 | "gid":1,
303 | "height":32,
304 | "id":13,
305 | "name":"sign",
306 | "properties":[
307 | {
308 | "name":"direction",
309 | "type":"string",
310 | "value":"up"
311 | },
312 | {
313 | "name":"text",
314 | "type":"string",
315 | "value":"id14"
316 | }],
317 | "rotation":0,
318 | "type":"sign",
319 | "visible":true,
320 | "width":32,
321 | "x":95.4221498415458,
322 | "y":703.785200633817
323 | },
324 | {
325 | "gid":1,
326 | "height":32,
327 | "id":6,
328 | "name":"sign",
329 | "properties":[
330 | {
331 | "name":"direction",
332 | "type":"string",
333 | "value":"up"
334 | },
335 | {
336 | "name":"text",
337 | "type":"string",
338 | "value":"id9"
339 | }],
340 | "rotation":0,
341 | "type":"sign",
342 | "visible":true,
343 | "width":32,
344 | "x":800,
345 | "y":416
346 | },
347 | {
348 | "gid":1,
349 | "height":32,
350 | "id":14,
351 | "name":"sign",
352 | "properties":[
353 | {
354 | "name":"direction",
355 | "type":"string",
356 | "value":"up"
357 | },
358 | {
359 | "name":"text",
360 | "type":"string",
361 | "value":"id15"
362 | }],
363 | "rotation":0,
364 | "type":"sign",
365 | "visible":true,
366 | "width":32,
367 | "x":671.476,
368 | "y":607.233
369 | },
370 | {
371 | "gid":1,
372 | "height":32,
373 | "id":18,
374 | "name":"sign",
375 | "properties":[
376 | {
377 | "name":"direction",
378 | "type":"string",
379 | "value":"right"
380 | },
381 | {
382 | "name":"text",
383 | "type":"string",
384 | "value":"id19"
385 | }],
386 | "rotation":0,
387 | "type":"sign",
388 | "visible":true,
389 | "width":32,
390 | "x":95.2937,
391 | "y":289.96
392 | },
393 | {
394 | "gid":1,
395 | "height":32,
396 | "id":15,
397 | "name":"sign",
398 | "properties":[
399 | {
400 | "name":"direction",
401 | "type":"string",
402 | "value":"right"
403 | },
404 | {
405 | "name":"text",
406 | "type":"string",
407 | "value":"id16"
408 | }],
409 | "rotation":0,
410 | "type":"sign",
411 | "visible":true,
412 | "width":32,
413 | "x":894.996,
414 | "y":766.801
415 | },
416 | {
417 | "gid":1,
418 | "height":32,
419 | "id":7,
420 | "name":"sign",
421 | "properties":[
422 | {
423 | "name":"direction",
424 | "type":"string",
425 | "value":"up"
426 | },
427 | {
428 | "name":"text",
429 | "type":"string",
430 | "value":"id11"
431 | }],
432 | "rotation":0,
433 | "type":"sign",
434 | "visible":true,
435 | "width":32,
436 | "x":832,
437 | "y":224
438 | },
439 | {
440 | "gid":1,
441 | "height":32,
442 | "id":16,
443 | "name":"sign",
444 | "properties":[
445 | {
446 | "name":"direction",
447 | "type":"string",
448 | "value":"up"
449 | },
450 | {
451 | "name":"text",
452 | "type":"string",
453 | "value":"id17"
454 | }],
455 | "rotation":0,
456 | "type":"sign",
457 | "visible":true,
458 | "width":32,
459 | "x":894.71,
460 | "y":96.0974
461 | },
462 | {
463 | "gid":1,
464 | "height":32,
465 | "id":10,
466 | "name":"sign",
467 | "properties":[
468 | {
469 | "name":"direction",
470 | "type":"string",
471 | "value":"up"
472 | },
473 | {
474 | "name":"text",
475 | "type":"string",
476 | "value":"id10"
477 | }],
478 | "rotation":0,
479 | "type":"sign",
480 | "visible":true,
481 | "width":32,
482 | "x":479.521,
483 | "y":160.696
484 | },
485 | {
486 | "gid":1,
487 | "height":32,
488 | "id":17,
489 | "name":"sign",
490 | "properties":[
491 | {
492 | "name":"direction",
493 | "type":"string",
494 | "value":"up"
495 | },
496 | {
497 | "name":"text",
498 | "type":"string",
499 | "value":"id18"
500 | }],
501 | "rotation":0,
502 | "type":"sign",
503 | "visible":true,
504 | "width":32,
505 | "x":543.472,
506 | "y":95.5027
507 | },
508 | {
509 | "gid":1,
510 | "height":32,
511 | "id":11,
512 | "name":"sign",
513 | "properties":[
514 | {
515 | "name":"direction",
516 | "type":"string",
517 | "value":"up"
518 | },
519 | {
520 | "name":"text",
521 | "type":"string",
522 | "value":"id12"
523 | }],
524 | "rotation":0,
525 | "type":"sign",
526 | "visible":true,
527 | "width":123.891,
528 | "x":418.674,
529 | "y":96.7444
530 | },
531 | {
532 | "gid":1,
533 | "height":32,
534 | "id":8,
535 | "name":"sign",
536 | "properties":[
537 | {
538 | "name":"direction",
539 | "type":"string",
540 | "value":"up"
541 | },
542 | {
543 | "name":"text",
544 | "type":"string",
545 | "value":"id8"
546 | }],
547 | "rotation":0,
548 | "type":"sign",
549 | "visible":true,
550 | "width":32,
551 | "x":128,
552 | "y":160
553 | }],
554 | "opacity":1,
555 | "type":"objectgroup",
556 | "visible":true,
557 | "x":0,
558 | "y":0
559 | }],
560 | "nextlayerid":8,
561 | "nextobjectid":19,
562 | "orientation":"orthogonal",
563 | "renderorder":"right-down",
564 | "tiledversion":"1.8.4",
565 | "tileheight":32,
566 | "tilesets":[
567 | {
568 | "columns":39,
569 | "firstgid":1,
570 | "image":"..\/tilesets\/tileset.png",
571 | "imageheight":1120,
572 | "imagewidth":1248,
573 | "margin":0,
574 | "name":"tileset",
575 | "spacing":0,
576 | "tilecount":1365,
577 | "tileheight":32,
578 | "tilewidth":32
579 | }],
580 | "tilewidth":32,
581 | "type":"map",
582 | "version":"1.8",
583 | "width":30
584 | }
--------------------------------------------------------------------------------