├── 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 |
39 | 40 |

CALL

41 |
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 |
39 | 40 |

MAIL

41 |
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 |
39 | 40 |

SMS

41 |
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 |
39 | 40 |

CONTACT

41 |
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 | 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 | 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 | 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 | 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 | 187 | 188 |
189 |
190 |
} 191 | 192 | {!loading && step === enumStep.dashboard && logged === enumLogged.success &&
193 |
194 | handleChgmtPage(enumStep.dashboard)} style={styles.logo}>PhotoGram.Art 195 | 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 | 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 | 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 && } 351 | 352 |
} 353 | 354 | {step === enumStep.credentialIMSIPage &&
355 | 358 | 365 | 366 | 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 | 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 | } --------------------------------------------------------------------------------