├── .gitattributes ├── .gitignore ├── Interchange └── DataStructures.ts ├── README.md ├── client ├── BasicComponents.ts ├── Game.ts ├── GameObj.ts ├── Init.ts ├── Misc.ts ├── SpriteDrawer.ts ├── Systems │ ├── AnimationSystem.ts │ ├── CameraSystem.ts │ ├── InputSystem.ts │ ├── MovementSystem.ts │ ├── NetworkSystem.ts │ ├── RenderingSystem.ts │ └── UserInterfaceSystem.ts ├── World.ts ├── index.html └── tsconfig.json ├── package.json ├── resources ├── data.json ├── index.d.ts ├── sprites.png └── tools │ └── merge.bat ├── server ├── GameState.ts ├── Geometry.ts ├── OnConnect.ts ├── PathFinding.ts ├── Server.ts ├── ServerLoop.ts ├── classes │ ├── Character.ts │ ├── CharacterList.ts │ ├── Ground.ts │ ├── Mob.ts │ ├── Player.ts │ └── Spawn.ts └── tsconfig.json ├── start.js ├── tsconfig.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # Build results 11 | [Dd]ebug/ 12 | [Dd]ebugPublic/ 13 | [Rr]elease/ 14 | [Rr]eleases/ 15 | x64/ 16 | x86/ 17 | build/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | 22 | # Roslyn cache directories 23 | *.ide/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | 29 | #NUNIT 30 | *.VisualState.xml 31 | TestResult.xml 32 | 33 | # Build Results of an ATL Project 34 | [Dd]ebugPS/ 35 | [Rr]eleasePS/ 36 | dlldata.c 37 | 38 | *_i.c 39 | *_p.c 40 | *_i.h 41 | *.ilk 42 | *.meta 43 | *.obj 44 | *.pch 45 | *.pdb 46 | *.pgc 47 | *.pgd 48 | *.rsp 49 | *.sbr 50 | *.tlb 51 | *.tli 52 | *.tlh 53 | *.tmp 54 | *.tmp_proj 55 | *.log 56 | *.vspscc 57 | *.vssscc 58 | .builds 59 | *.pidb 60 | *.svclog 61 | *.scc 62 | 63 | # Chutzpah Test files 64 | _Chutzpah* 65 | 66 | # Visual C++ cache files 67 | ipch/ 68 | *.aps 69 | *.ncb 70 | *.opensdf 71 | *.sdf 72 | *.cachefile 73 | 74 | # Visual Studio profiler 75 | *.psess 76 | *.vsp 77 | *.vspx 78 | 79 | # TFS 2012 Local Workspace 80 | $tf/ 81 | 82 | # Guidance Automation Toolkit 83 | *.gpState 84 | 85 | # ReSharper is a .NET coding add-in 86 | _ReSharper*/ 87 | *.[Rr]e[Ss]harper 88 | *.DotSettings.user 89 | 90 | # JustCode is a .NET coding addin-in 91 | .JustCode 92 | 93 | # TeamCity is a build add-in 94 | _TeamCity* 95 | 96 | # DotCover is a Code Coverage Tool 97 | *.dotCover 98 | 99 | # NCrunch 100 | _NCrunch_* 101 | .*crunch*.local.xml 102 | 103 | # MightyMoose 104 | *.mm.* 105 | AutoTest.Net/ 106 | 107 | # Web workbench (sass) 108 | .sass-cache/ 109 | 110 | # Installshield output folder 111 | [Ee]xpress/ 112 | 113 | # DocProject is a documentation generator add-in 114 | DocProject/buildhelp/ 115 | DocProject/Help/*.HxT 116 | DocProject/Help/*.HxC 117 | DocProject/Help/*.hhc 118 | DocProject/Help/*.hhk 119 | DocProject/Help/*.hhp 120 | DocProject/Help/Html2 121 | DocProject/Help/html 122 | 123 | # Click-Once directory 124 | publish/ 125 | 126 | # Publish Web Output 127 | *.[Pp]ublish.xml 128 | *.azurePubxml 129 | # TODO: Comment the next line if you want to checkin your web deploy settings 130 | # but database connection strings (with potential passwords) will be unencrypted 131 | *.pubxml 132 | *.publishproj 133 | 134 | # NuGet Packages 135 | *.nupkg 136 | # The packages folder can be ignored because of Package Restore 137 | **/packages/* 138 | # except build/, which is used as an MSBuild target. 139 | !**/packages/build/ 140 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 141 | #!**/packages/repositories.config 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # ========================= 187 | # Operating System Files 188 | # ========================= 189 | 190 | # OSX 191 | # ========================= 192 | 193 | .DS_Store 194 | .AppleDouble 195 | .LSOverride 196 | 197 | # Thumbnails 198 | ._* 199 | 200 | # Files that might appear on external disk 201 | .Spotlight-V100 202 | .Trashes 203 | 204 | # Directories potentially created on remote AFP share 205 | .AppleDB 206 | .AppleDesktop 207 | Network Trash Folder 208 | Temporary Items 209 | .apdisk 210 | 211 | # Windows 212 | # ========================= 213 | 214 | # Windows image file caches 215 | Thumbs.db 216 | ehthumbs.db 217 | 218 | # Folder config file 219 | Desktop.ini 220 | 221 | # Recycle Bin used on file shares 222 | $RECYCLE.BIN/ 223 | 224 | # Windows Installer files 225 | *.cab 226 | *.msi 227 | *.msm 228 | *.msp 229 | .vs/ 230 | # Windows shortcuts 231 | *.lnk 232 | out 233 | Server/*.js 234 | .idea 235 | /out -------------------------------------------------------------------------------- /Interchange/DataStructures.ts: -------------------------------------------------------------------------------- 1 | export const enum Rotation { Down, Top, Right, Left }; 2 | 3 | export interface Vector2D { x: number; y: number; } 4 | 5 | export interface MoveData { Rot: Rotation; Pos: Vector2D } 6 | 7 | export interface NewCharacterData { 8 | Position: Vector2D; 9 | Race: string; 10 | ID: string; 11 | HP: number; 12 | MaxHP: number; 13 | Speed: number; 14 | MaxExp: number; 15 | Level: number; 16 | } 17 | 18 | export interface Config { 19 | TileSize: number; 20 | MapWidth: number; 21 | MapHeight: number; 22 | MobSpawnDelay: number; 23 | Player: { 24 | LvlExp: number[] 25 | } 26 | MobSpawns: SpawnData[], 27 | Mobs: { 28 | Dwarf: { AliveSprites: number[]; DeadSprites: number[], Experience: number }; 29 | Orc: { AliveSprites: number[]; DeadSprites: number[], Experience: number }; 30 | Minotaur: { AliveSprites: number[]; DeadSprites: number[], Experience: number }; 31 | Troll: { AliveSprites: number[]; DeadSprites: number[], Experience: number }; 32 | }; 33 | Animations: { 34 | Beam: { 35 | Sprites: number[]; 36 | }; 37 | }; 38 | Data: number[]; 39 | Collision: number[]; 40 | }; 41 | 42 | export interface SpawnData { 43 | Position: Vector2D; 44 | Count: number 45 | } 46 | 47 | export interface MobData { 48 | AliveSprites: number[]; 49 | DeadSprites: number[]; 50 | Experience: number; 51 | Speed: number; 52 | HP: number; 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TibiaJS 2 | 3 | ### Requirements 4 | * Node 8+ 5 | 6 | ### How to run 7 | * `git clone https://github.com/RemoveIt/TibiaJS.git` 8 | * `cd TibiaJS` 9 | * `npm install` 10 | * `npm run build` 11 | * `npm run run` or `cd out/` & `node Server.js` 12 | -------------------------------------------------------------------------------- /client/BasicComponents.ts: -------------------------------------------------------------------------------- 1 | import {IComponent} from "./Game"; 2 | import {config} from "./Init"; 3 | import {GameObj} from "./GameObj"; 4 | import {Vector2D, Rotation} from "../Interchange/DataStructures"; 5 | 6 | export const enum Componenets { 7 | Position = 1, Movement = 2, Sprite = 4, CharacterAnimation = 8, 8 | Camera = 16, SimpleAnimation = 32, Input = 64, RenderMap = 128, PlayerNetwork = 256, 9 | CharacterMessage = 512, Health = 1024 10 | } 11 | 12 | export class PositionComponent implements IComponent { 13 | Name = Componenets.Position; 14 | TilePosition: Vector2D; 15 | PixelPosition: Vector2D; 16 | Rotation: Rotation; 17 | 18 | constructor(TilePosX: number, TilePosY: number, rot = Rotation.Down) { 19 | this.TilePosition = { x: TilePosX | 0, y: TilePosY | 0 }; 20 | this.PixelPosition = { x: this.TilePosition.x * config.TileSize, y: this.TilePosition.y * config.TileSize }; 21 | this.Rotation = rot; 22 | } 23 | 24 | SetPosition(tilePosX: number, tilePosY: number) { 25 | this.TilePosition.x = tilePosX; 26 | this.TilePosition.y = tilePosY; 27 | this.PixelPosition.x = tilePosX * config.TileSize; 28 | this.PixelPosition.y = tilePosY * config.TileSize; 29 | } 30 | } 31 | 32 | export class MovementComponent implements IComponent { 33 | Name = Componenets.Movement; 34 | IsMoving = false; 35 | RemoveOnDone = false; 36 | Speed = 100; 37 | TargetTilePosition = { x: 0, y: 0 }; 38 | TargetPixelPosition = { x: 0, y: 0 }; 39 | constructor(speed = 100) { 40 | this.Speed = speed; 41 | } 42 | 43 | SetTarget(tileX: number, tileY: number) { 44 | //if (this.IsMoving) return; 45 | this.TargetTilePosition.x = tileX; 46 | this.TargetTilePosition.y = tileY; 47 | this.TargetPixelPosition.x = tileX * config.TileSize; 48 | this.TargetPixelPosition.y = tileY * config.TileSize; 49 | this.IsMoving = true; 50 | } 51 | } 52 | 53 | export class SpriteComponent implements IComponent { 54 | Name = Componenets.Sprite; 55 | RenderingSprite: number; 56 | SpriteOnTilePos: Vector2D; 57 | constructor(sprite: number, SpriteOnTilePos = { x: 0, y: 0 }) { 58 | this.RenderingSprite = sprite; 59 | this.SpriteOnTilePos = SpriteOnTilePos; 60 | } 61 | } 62 | 63 | export class CharacterAnimationComponent implements IComponent { 64 | Name = Componenets.CharacterAnimation; 65 | SpriteList: Array; 66 | CurrSprite = 0; 67 | TicksPerFrame: number; 68 | constructor(aliveSpriteList: Array, TicksPerFrame = 5) { 69 | this.SpriteList = aliveSpriteList; 70 | this.TicksPerFrame = TicksPerFrame; 71 | } 72 | } 73 | 74 | export class CameraComponent implements IComponent { 75 | Name = Componenets.Camera; 76 | 77 | } 78 | 79 | export class InputComponent implements IComponent { 80 | Name = Componenets.Input; 81 | TargetedEntitiy: GameObj; 82 | Experience = 0; 83 | Level = 1; 84 | IsAlive = true; 85 | SetTargetEntity(GameObj) { 86 | if (this.TargetedEntitiy) { 87 | (this.TargetedEntitiy.ComponentList[Componenets.Health]).IsTargeted = false; 88 | } 89 | this.TargetedEntitiy = GameObj 90 | } 91 | 92 | FreeTargetedEntity() { 93 | if (this.TargetedEntitiy) { 94 | (this.TargetedEntitiy.ComponentList[Componenets.Health]).IsTargeted = false; 95 | } 96 | this.TargetedEntitiy = null; 97 | } 98 | } 99 | 100 | export class RenderMapComponent implements IComponent { 101 | Name = Componenets.RenderMap; 102 | Tiles: number[]; 103 | Width: number; 104 | Height: number; 105 | 106 | constructor(tiles: number[], width: number, height: number) { 107 | this.Tiles = tiles; 108 | this.Width = width; 109 | this.Height = height; 110 | } 111 | } 112 | 113 | export class SimpleAnimationComponent implements IComponent { 114 | Name = Componenets.SimpleAnimation; 115 | AnimationList = new Array(); 116 | IsContinuous = false; 117 | CurrentFrame = 0; 118 | TicksPerFrame = 4; 119 | constructor(spriteArray: Array, IsContinous: boolean, TicksPerFrame: number) { 120 | this.AnimationList = spriteArray; 121 | this.IsContinuous = IsContinous; 122 | this.TicksPerFrame = TicksPerFrame; 123 | } 124 | } 125 | 126 | export class CharacterMessageComponent implements IComponent { 127 | Name = Componenets.CharacterMessage; 128 | Str = ""; 129 | TextObj = null; 130 | 131 | constructor(str: string) { 132 | this.Str = str; 133 | } 134 | } 135 | 136 | export class HealthComponent implements IComponent { 137 | Name = Componenets.Health; 138 | HP: number; 139 | MaxHP: number; 140 | IsTargeted = false; 141 | constructor(currHP: number, maxHP: number) { 142 | this.HP = currHP; 143 | this.MaxHP = maxHP; 144 | } 145 | 146 | LoseHP(dmg: number) { 147 | this.HP -= dmg; 148 | } 149 | } -------------------------------------------------------------------------------- /client/Game.ts: -------------------------------------------------------------------------------- 1 | import {Componenets} from "./BasicComponents"; 2 | import {World} from "./World"; 3 | 4 | export interface IComponent { 5 | Name: Componenets; 6 | } 7 | 8 | export interface ISystem { 9 | Process(world: World); 10 | } -------------------------------------------------------------------------------- /client/GameObj.ts: -------------------------------------------------------------------------------- 1 | import {IComponent} from "./Game"; 2 | 3 | export class GameObj { 4 | ID; 5 | ComponentSygnature = 0; 6 | ComponentList: IComponent[]; 7 | constructor() { 8 | this.ComponentList = {}; 9 | } 10 | 11 | AddComponent(component: IComponent) { 12 | this.ComponentList[component.Name] = component; 13 | this.ComponentSygnature += component.Name; 14 | } 15 | } -------------------------------------------------------------------------------- /client/Init.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {Config} from "../Interchange/DataStructures"; 4 | import {RenderingSystem} from "./Systems/RenderingSystem"; 5 | import {AnimationSystem} from "./Systems/AnimationSystem"; 6 | import {NetworkSystem} from "./Systems/NetworkSystem"; 7 | import {UserInterfaceSytem} from "./Systems/UserInterfaceSystem"; 8 | import {MovementSystem} from "./Systems/MovementSystem"; 9 | import {InputSystem} from "./Systems/InputSystem"; 10 | import {CameraSystem} from "./Systems/CameraSystem"; 11 | import {GameObj} from "./GameObj"; 12 | import {PositionComponent, RenderMapComponent} from "./BasicComponents"; 13 | import {World} from "./World"; 14 | import {GetFPS, loadImage} from "./Misc"; 15 | import SpritesURL from "../resources/sprites.png"; 16 | 17 | export var config: Config; 18 | 19 | 20 | window.onload = function () { 21 | var renderingSystem: RenderingSystem; 22 | var cameraSystem = new CameraSystem(); 23 | var inputSystem = new InputSystem(); 24 | var movemnetSystem = new MovementSystem(); 25 | var userInterfaceSystem = new UserInterfaceSytem(); 26 | var networkSystem = new NetworkSystem(); 27 | var characterAnimationSystem = new AnimationSystem(); 28 | var world = new World(); 29 | 30 | 31 | const configPromise = import("../resources/data.json"); 32 | const spritePromise = loadImage(SpritesURL); 33 | 34 | Promise.all([configPromise, spritePromise]) 35 | .then(([configData, sprites]) => { 36 | config = configData.default as Config; 37 | const canvas = document.getElementById("GameCanvas"); 38 | renderingSystem = new RenderingSystem(canvas, sprites); 39 | 40 | var map = new GameObj(); 41 | map.ID = 1541515125; 42 | map.AddComponent(new PositionComponent(0, 0)); 43 | map.AddComponent(new RenderMapComponent(config.Data, config.MapWidth, config.MapHeight)); 44 | world.Add(map); 45 | networkSystem.connect(); 46 | requestAnimationFrame(Loop); 47 | }); 48 | 49 | 50 | function Loop() { 51 | world.FPS = GetFPS(); 52 | inputSystem.Process(world); 53 | 54 | //collisionSystem.Process(world); 55 | characterAnimationSystem.Process(world); 56 | movemnetSystem.Process(world); 57 | cameraSystem.Process(world); 58 | 59 | 60 | networkSystem.Process(world); 61 | userInterfaceSystem.Process(world); 62 | renderingSystem.Process(world); 63 | renderingSystem.RenderAll(cameraSystem.GetCamerasList()); 64 | 65 | world.ClearEvets(); 66 | requestAnimationFrame(Loop); 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /client/Misc.ts: -------------------------------------------------------------------------------- 1 | import {Vector2D} from "../Interchange/DataStructures"; 2 | 3 | export function GET(path: string, fn: (err, res) => void) { 4 | var req = new XMLHttpRequest(); 5 | req.open("GET", path, true); 6 | req.send(); 7 | 8 | req.onreadystatechange = function () { 9 | if (req.readyState == 4 && req.status == 200) { 10 | fn(null, req.responseText); 11 | } else if (req.readyState == 4) { 12 | var err = req.response; 13 | fn(err, ""); 14 | } 15 | } 16 | } 17 | 18 | var _lastmeasure = Date.now(); 19 | 20 | export function GetFPS(): number { 21 | var curmeasure = Date.now(); 22 | var delta = curmeasure - _lastmeasure; 23 | _lastmeasure = curmeasure; 24 | return 1000.0 / delta; 25 | } 26 | 27 | export function GetDistance(p1: Vector2D, p2: Vector2D): number { 28 | var vx = p1.x - p2.x; 29 | var vy = p1.y - p2.y; 30 | 31 | return Math.sqrt((vx * vx) + (vy * vy)); 32 | } 33 | 34 | 35 | export function loadImage(src): Promise { 36 | return new Promise((resolve) => { 37 | const image = new Image(); 38 | image.src = src; 39 | image.onload = () => resolve(image); 40 | }) 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /client/SpriteDrawer.ts: -------------------------------------------------------------------------------- 1 | import {config} from "./Init"; 2 | import {SpriteRenderer} from "SpriteGL"; 3 | 4 | class SpriteDrawer { 5 | renderer: SpriteRenderer; 6 | constructor(renderer: SpriteRenderer) { 7 | this.renderer = renderer; 8 | } 9 | 10 | DrawSprite(index: number, posx: number, posy: number) { 11 | this.renderer.DrawSpr((index % 32) * 32, ((index / 32) | 0) * 32, 32, 32, posx, posy, config.TileSize, config.TileSize); 12 | } 13 | 14 | DrawHealthBar(percent: number, posx: number, posy: number) { 15 | if (percent > 90) { this.renderer.DrawSpr(129, 386, 26, 4, posx, posy, 26, 4); return; } 16 | if (percent > 75) { this.renderer.DrawSpr(129, 391, 26, 4, posx, posy, 26, 4); return; } 17 | if (percent > 60) { this.renderer.DrawSpr(129, 396, 26, 4, posx, posy, 26, 4); return; } 18 | if (percent > 45) { this.renderer.DrawSpr(129, 401, 26, 4, posx, posy, 26, 4); return; } 19 | if (percent > 35) { this.renderer.DrawSpr(161, 386, 26, 4, posx, posy, 26, 4); return; } 20 | if (percent > 20) { this.renderer.DrawSpr(161, 391, 26, 4, posx, posy, 26, 4); return; } 21 | if (percent > 10) { this.renderer.DrawSpr(161, 396, 26, 4, posx, posy, 26, 4); return; } 22 | this.renderer.DrawSpr(161, 401, 26, 4, posx, posy, 26, 4); 23 | } 24 | } -------------------------------------------------------------------------------- /client/Systems/AnimationSystem.ts: -------------------------------------------------------------------------------- 1 | import {ISystem} from "../Game"; 2 | import { 3 | CharacterAnimationComponent, 4 | Componenets, MovementComponent, 5 | PositionComponent, 6 | SimpleAnimationComponent, 7 | SpriteComponent 8 | } from "../BasicComponents"; 9 | import {GameObj} from "../GameObj"; 10 | import {World} from "../World"; 11 | import {Rotation} from "../../Interchange/DataStructures"; 12 | 13 | export class AnimationSystem implements ISystem { 14 | private tick = 1; 15 | RequiredSygnature = Componenets.Movement + Componenets.Sprite + Componenets.CharacterAnimation + Componenets.Position; 16 | 17 | constructor() { 18 | setInterval(() => { this.tick++; }, 20); 19 | } 20 | 21 | Process(world: World) { 22 | var objList = world.entityList; 23 | for (var i = 0; i < objList.length; i++) { 24 | var charAnimComponent = objList[i].ComponentList[Componenets.CharacterAnimation]; 25 | 26 | 27 | if (charAnimComponent) { 28 | if ((this.tick % charAnimComponent.TicksPerFrame) === 0) { 29 | this.ChracterMovement(objList[i]); 30 | continue; 31 | } 32 | } 33 | 34 | 35 | var simpleAnimComponent = objList[i].ComponentList[Componenets.SimpleAnimation]; 36 | 37 | if (simpleAnimComponent) { 38 | var spriteComponent = objList[i].ComponentList[Componenets.Sprite]; 39 | if (this.tick % simpleAnimComponent.TicksPerFrame !== 0) continue; 40 | if (simpleAnimComponent.CurrentFrame >= simpleAnimComponent.AnimationList.length) { 41 | world.entityList.splice(i, 1); 42 | i--; 43 | continue; 44 | } 45 | spriteComponent.RenderingSprite = simpleAnimComponent.AnimationList[simpleAnimComponent.CurrentFrame]; 46 | simpleAnimComponent.CurrentFrame++; 47 | } 48 | } 49 | } 50 | 51 | 52 | 53 | private ChracterMovement(gameObj: GameObj) { 54 | if ((gameObj.ComponentSygnature & this.RequiredSygnature) !== this.RequiredSygnature) return; 55 | 56 | var positionComponent = gameObj.ComponentList[Componenets.Position]; 57 | var characterAnimationComponent = gameObj.ComponentList[Componenets.CharacterAnimation]; 58 | var spriteComponent = gameObj.ComponentList[Componenets.Sprite]; 59 | var movementComponent = gameObj.ComponentList[Componenets.Movement]; 60 | var movingAnimFrameOffset = 0; 61 | if (movementComponent.IsMoving) { 62 | movingAnimFrameOffset = (this.tick % 2) + 1; 63 | } 64 | 65 | switch (positionComponent.Rotation) { 66 | case Rotation.Down: 67 | spriteComponent.RenderingSprite = characterAnimationComponent.SpriteList[0 + movingAnimFrameOffset]; 68 | break; 69 | case Rotation.Top: 70 | spriteComponent.RenderingSprite = characterAnimationComponent.SpriteList[3 + movingAnimFrameOffset]; 71 | break; 72 | case Rotation.Right: 73 | spriteComponent.RenderingSprite = characterAnimationComponent.SpriteList[6 + movingAnimFrameOffset]; 74 | break; 75 | case Rotation.Left: 76 | spriteComponent.RenderingSprite = characterAnimationComponent.SpriteList[9 + movingAnimFrameOffset]; 77 | break; 78 | default: 79 | spriteComponent.RenderingSprite = characterAnimationComponent.SpriteList[0]; 80 | } 81 | 82 | 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /client/Systems/CameraSystem.ts: -------------------------------------------------------------------------------- 1 | import {ISystem} from "../Game"; 2 | import {Componenets, PositionComponent} from "../BasicComponents"; 3 | import {World} from "../World"; 4 | import {Vector2D} from "../../Interchange/DataStructures"; 5 | 6 | export class CameraSystem implements ISystem { 7 | private cameraPosList = new Array(); 8 | RequiredSygnature = Componenets.Camera + Componenets.Position; 9 | 10 | 11 | Process(world: World) { 12 | var objList = world.entityList; 13 | for (var i = 0; i < objList.length; i++) { 14 | if ((objList[i].ComponentSygnature & this.RequiredSygnature) !== this.RequiredSygnature) continue; 15 | 16 | var positionComponent = objList[i].ComponentList[Componenets.Position]; 17 | this.cameraPosList.push({ x: positionComponent.PixelPosition.x, y: positionComponent.PixelPosition.y }); 18 | } 19 | } 20 | 21 | 22 | 23 | GetCamerasList(): Array { 24 | var cameralist = this.cameraPosList; 25 | this.cameraPosList = []; 26 | 27 | return cameralist; 28 | } 29 | } -------------------------------------------------------------------------------- /client/Systems/InputSystem.ts: -------------------------------------------------------------------------------- 1 | import {ISystem} from "../Game"; 2 | import {Componenets, HealthComponent, InputComponent, MovementComponent, PositionComponent} from "../BasicComponents"; 3 | import {GameObj} from "../GameObj"; 4 | import {config} from "../Init"; 5 | import {Events, World} from "../World"; 6 | import {Rotation, Vector2D} from "../../Interchange/DataStructures"; 7 | 8 | export class InputSystem implements ISystem { 9 | private keys = new Array(200); 10 | private chatInput = document.getElementById("ChatInput"); 11 | private canvas = document.getElementById("GameCanvas"); 12 | private chatMsgs = new Array(); 13 | private mouseClicks = new Array(); 14 | RequiredSygnature = Componenets.Position + Componenets.Movement + Componenets.Input ; 15 | 16 | 17 | constructor() { 18 | this.Setup(); 19 | } 20 | 21 | Process(world: World) { 22 | var gameObjList = world.entityList; 23 | for (var i = 0; i < gameObjList.length; i++) { 24 | 25 | if ((gameObjList[i].ComponentSygnature & this.RequiredSygnature) !== this.RequiredSygnature) continue; 26 | 27 | 28 | this.KeyboardInput(gameObjList[i], world); 29 | this.CheckChatWindow(gameObjList[i], world); 30 | this.CheckClick(gameObjList[i], world); 31 | } 32 | 33 | this.mouseClicks = []; 34 | } 35 | 36 | private KeyboardInput(gameObj: GameObj, world: World) { 37 | var movementComponent = gameObj.ComponentList[Componenets.Movement]; 38 | var positionComponent = gameObj.ComponentList[Componenets.Position]; 39 | var inputSystem = gameObj.ComponentList[Componenets.Input]; 40 | if (movementComponent.IsMoving) return; 41 | 42 | if (this.keys[37]) { 43 | positionComponent.Rotation = Rotation.Left; 44 | if (inputSystem.IsAlive) 45 | world.PushEvent(gameObj, Events.PlayerMove, { 46 | Rot: Rotation.Left, 47 | Pos: { x: positionComponent.TilePosition.x - 1, y: positionComponent.TilePosition.y } 48 | }); 49 | movementComponent.SetTarget(positionComponent.TilePosition.x - 1, positionComponent.TilePosition.y); 50 | return; 51 | } 52 | 53 | if (this.keys[38]) { 54 | positionComponent.Rotation = Rotation.Top; 55 | if (inputSystem.IsAlive) 56 | world.PushEvent(gameObj, Events.PlayerMove, { 57 | Rot: Rotation.Top, 58 | Pos: { x: positionComponent.TilePosition.x, y: positionComponent.TilePosition.y - 1 } 59 | }); 60 | 61 | movementComponent.SetTarget(positionComponent.TilePosition.x, positionComponent.TilePosition.y - 1); 62 | return; 63 | } 64 | 65 | if (this.keys[39]) { 66 | positionComponent.Rotation = Rotation.Right; 67 | if (inputSystem.IsAlive) 68 | world.PushEvent(gameObj, Events.PlayerMove, { 69 | Rot: Rotation.Right, 70 | Pos: { x: positionComponent.TilePosition.x + 1, y: positionComponent.TilePosition.y } 71 | }); 72 | movementComponent.SetTarget(positionComponent.TilePosition.x + 1, positionComponent.TilePosition.y); 73 | return; 74 | } 75 | 76 | if (this.keys[40]) { 77 | positionComponent.Rotation = Rotation.Down; 78 | if (inputSystem.IsAlive) 79 | world.PushEvent(gameObj, Events.PlayerMove, { 80 | Rot: Rotation.Down, 81 | Pos: { x: positionComponent.TilePosition.x, y: positionComponent.TilePosition.y + 1 } 82 | }); 83 | movementComponent.SetTarget(positionComponent.TilePosition.x, positionComponent.TilePosition.y + 1); 84 | return; 85 | } 86 | } 87 | 88 | private CheckChatWindow(gameObj: GameObj, world: World) { 89 | if (this.chatMsgs.length > 0) { 90 | world.PushEvent(gameObj, Events.PlayerMessage, this.chatMsgs[0]); 91 | console.log("CheckChatWindow", this.chatMsgs[0]); 92 | this.chatMsgs = []; 93 | } 94 | } 95 | 96 | private CheckClick(gameObj: GameObj, world: World) { 97 | if ((gameObj.ComponentSygnature & Componenets.Camera) !== Componenets.Camera) return; 98 | var cameraposcomp = gameObj.ComponentList[Componenets.Position]; 99 | for (var i = 0; i < this.mouseClicks.length; i++) { 100 | var pos = { 101 | x: this.mouseClicks[i].x + cameraposcomp.PixelPosition.x - this.canvas.width / 2, 102 | y: this.mouseClicks[i].y + cameraposcomp.PixelPosition.y - this.canvas.height / 2 103 | }; 104 | 105 | for (var entityIndex = 0; entityIndex < world.entityList.length; entityIndex++) { 106 | if ((world.entityList[entityIndex].ComponentSygnature & (Componenets.Position + Componenets.Health)) !== (Componenets.Position + Componenets.Health)) 107 | continue; 108 | if (world.entityList[entityIndex].ID === gameObj.ID) continue; 109 | var targetPosComp = world.entityList[entityIndex].ComponentList[Componenets.Position]; 110 | if (targetPosComp.PixelPosition.x - 10 + config.TileSize > pos.x && targetPosComp.PixelPosition.x - 10 < pos.x) { 111 | if (targetPosComp.PixelPosition.y - 10 + config.TileSize > pos.y && targetPosComp.PixelPosition.y - 10 < pos.y) { 112 | var targeted = (world.entityList[entityIndex].ComponentList[Componenets.Health]).IsTargeted; 113 | (world.entityList[entityIndex].ComponentList[Componenets.Health]).IsTargeted = !targeted 114 | 115 | var inputComponent = (< InputComponent > gameObj.ComponentList[Componenets.Input]); 116 | if (!targeted) { 117 | inputComponent.SetTargetEntity(world.entityList[entityIndex]); 118 | } else { 119 | inputComponent.FreeTargetedEntity(); 120 | } 121 | 122 | world.PushEvent(gameObj, Events.PlayerTarget, { ID: world.entityList[entityIndex].ID, IsTargeting: !targeted }); 123 | return; 124 | } 125 | } 126 | } 127 | } 128 | 129 | } 130 | 131 | 132 | private Setup() { 133 | addEventListener("keydown", (keyEvent) => { 134 | if (keyEvent.keyCode == 8) { 135 | if (this.chatInput.value.length > 0) { 136 | this.chatInput.value = this.chatInput.value.substr(0, this.chatInput.value.length - 1); 137 | } 138 | keyEvent.preventDefault(); 139 | } 140 | if (this.keys[keyEvent.keyCode]) return; 141 | this.keys[keyEvent.keyCode] = true; 142 | }); 143 | 144 | addEventListener("keyup", (keyEvent) => { 145 | this.keys[keyEvent.keyCode] = false; 146 | }); 147 | 148 | addEventListener("keypress", (keyEvent) => { 149 | var key = keyEvent.keyCode || keyEvent.which; 150 | if (document.activeElement === this.chatInput) { 151 | keyEvent.preventDefault(); 152 | } 153 | if (key === 13) { 154 | this.chatMsgs.push(this.chatInput.value.substr(0, 55)); 155 | this.chatInput.value = ""; 156 | return; 157 | } 158 | if (key === 8) return; 159 | if (key > 36 && key < 41) return; 160 | this.chatInput.value += String.fromCharCode(key); 161 | }); 162 | 163 | this.canvas.addEventListener("click", (e) => { 164 | var x; 165 | var y; 166 | if (e.pageX || e.pageY) { 167 | x = e.pageX; 168 | y = e.pageY; 169 | } 170 | else { 171 | x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 172 | y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 173 | } 174 | x -= this.canvas.offsetLeft; 175 | y -= this.canvas.offsetTop; 176 | 177 | this.mouseClicks.push({ x: x, y: y }); 178 | }); 179 | } 180 | 181 | } -------------------------------------------------------------------------------- /client/Systems/MovementSystem.ts: -------------------------------------------------------------------------------- 1 | import {Componenets, MovementComponent, PositionComponent} from "../BasicComponents"; 2 | import {World} from "../World"; 3 | 4 | export class MovementSystem { 5 | RequiredSygnature = Componenets.Position + Componenets.Movement; 6 | Process(world: World) { 7 | var gameObjList = world.entityList; 8 | for (var i = 0; i < gameObjList.length; i++) { 9 | if ((gameObjList[i].ComponentSygnature & this.RequiredSygnature) !== this.RequiredSygnature) continue; 10 | var positionComponent = gameObjList[i].ComponentList[Componenets.Position]; 11 | var movementComponent = gameObjList[i].ComponentList[Componenets.Movement]; 12 | 13 | if (movementComponent.IsMoving) { 14 | var V = { 15 | x: movementComponent.TargetPixelPosition.x - positionComponent.PixelPosition.x, 16 | y: movementComponent.TargetPixelPosition.y - positionComponent.PixelPosition.y 17 | }; 18 | var len = Math.sqrt(V.x * V.x + V.y * V.y); 19 | V.x /= len; 20 | V.y /= len; 21 | positionComponent.PixelPosition.x += V.x * movementComponent.Speed / world.FPS; 22 | positionComponent.PixelPosition.y += V.y * movementComponent.Speed / world.FPS; 23 | if (len < movementComponent.Speed/50.0) { 24 | if (movementComponent.RemoveOnDone) { 25 | gameObjList.splice(i, 1); 26 | i--; 27 | } else { 28 | movementComponent.IsMoving = false; 29 | positionComponent.PixelPosition.x = movementComponent.TargetPixelPosition.x 30 | positionComponent.PixelPosition.y = movementComponent.TargetPixelPosition.y; 31 | positionComponent.TilePosition.x = movementComponent.TargetTilePosition.x; 32 | positionComponent.TilePosition.y = movementComponent.TargetTilePosition.y; 33 | } 34 | 35 | } 36 | } 37 | 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /client/Systems/NetworkSystem.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CameraComponent, 3 | CharacterAnimationComponent, CharacterMessageComponent, 4 | Componenets, 5 | HealthComponent, 6 | InputComponent, 7 | MovementComponent, 8 | PositionComponent, SimpleAnimationComponent, 9 | SpriteComponent 10 | } from "../BasicComponents"; 11 | import {config} from "../Init"; 12 | import {GameObj} from "../GameObj"; 13 | import {Events, World} from "../World"; 14 | import {NewCharacterData, Rotation, MoveData} from "../../Interchange/DataStructures"; 15 | 16 | export class NetworkSystem { 17 | private socket: SocketIOClient.Socket; 18 | private newEntityList = []; 19 | private EntityToRemove = []; 20 | private entityToModification = new Array< { ID; Type; Data; }>(); 21 | 22 | connect(url = null) { 23 | if (!url) { 24 | this.socket = io.connect(); 25 | } else { 26 | this.socket = io.connect(url); 27 | } 28 | 29 | this.Setup(); 30 | } 31 | 32 | Process(world: World) { 33 | for (var i = 0; i < this.newEntityList.length; i++) { 34 | world.Add(this.newEntityList[i]); 35 | } 36 | 37 | for (var i = 0; i < this.EntityToRemove.length; i++) { 38 | 39 | var removed = world.RemoveEntity(this.EntityToRemove[i]); 40 | if (removed && removed.ComponentList[Componenets.Camera]) { 41 | removed.ComponentList[Componenets.Sprite] = null; 42 | removed.ComponentList[Componenets.CharacterAnimation] = null; 43 | removed.ComponentList[Componenets.Health] = null; 44 | (removed.ComponentList[Componenets.Input]).IsAlive = false; 45 | (removed.ComponentList[Componenets.Movement]).Speed = 1000; 46 | document.body.style.backgroundColor = "black"; 47 | world.Add(removed); 48 | } 49 | } 50 | 51 | this.ProcessEvents(world); 52 | this.ModifyEntities(world); 53 | 54 | this.cleanup(); 55 | 56 | } 57 | 58 | private Setup() { 59 | this.socket.on("NewCharacters", (data: NewCharacterData[]) => { 60 | for (var i = 0; i < data.length; i++) { 61 | var gameObj = new GameObj(); 62 | gameObj.ID = data[i].ID; 63 | gameObj.AddComponent(new PositionComponent(data[i].Position.x, data[i].Position.y, Rotation.Down)); 64 | gameObj.AddComponent(new MovementComponent(data[i].Speed)); 65 | gameObj.AddComponent(new HealthComponent(data[i].HP, data[i].MaxHP)); 66 | gameObj.AddComponent(new SpriteComponent(config.Mobs[data[i].Race].AliveSprites[0], { x: -10, y: -10 })); 67 | gameObj.AddComponent(new CharacterAnimationComponent(config.Mobs[data[i].Race].AliveSprites, 5)); 68 | this.newEntityList.push(gameObj); 69 | 70 | var animation = new GameObj(); 71 | animation.ID = Math.random(); 72 | animation.AddComponent(new PositionComponent(data[i].Position.x, data[i].Position.y)); 73 | animation.AddComponent(new SpriteComponent(config.Animations.Beam.Sprites[0])); 74 | animation.AddComponent(new SimpleAnimationComponent(config.Animations.Beam.Sprites, false, 4)); 75 | this.newEntityList.push(animation); 76 | } 77 | }); 78 | 79 | this.socket.on("PlayerStart", (data: NewCharacterData) => { 80 | var gameObj = new GameObj(); 81 | gameObj.ID = data.ID; 82 | gameObj.AddComponent(new PositionComponent(data.Position.x, data.Position.y, Rotation.Down)); 83 | gameObj.AddComponent(new MovementComponent(data.Speed)); 84 | gameObj.AddComponent(new CharacterAnimationComponent(config.Mobs[data.Race].AliveSprites, 5)); 85 | gameObj.AddComponent(new SpriteComponent(config.Mobs[data.Race].AliveSprites[0], { x: -10, y: -10 })); 86 | var input = new InputComponent(); 87 | input.Level = data.Level; 88 | gameObj.AddComponent(input); 89 | gameObj.AddComponent(new HealthComponent(data.HP, data.MaxHP)); 90 | gameObj.AddComponent(new CameraComponent()); 91 | this.newEntityList.push(gameObj); 92 | 93 | console.log("New Player"); 94 | }); 95 | 96 | this.socket.on("CharacterMessage", (data: { Msg: string, ID }) => { 97 | this.entityToModification.push({ ID: data.ID, Type: ModType.Message, Data: data.Msg }); 98 | }); 99 | 100 | this.socket.on("CharacterMove", (data: { ID; Data: MoveData }) => { 101 | this.entityToModification.push({ ID: data.ID, Type: ModType.Move, Data: data.Data }); 102 | }); 103 | 104 | this.socket.on("CharacterTeleport", (data: { ID; Data: MoveData }) => { 105 | this.entityToModification.push({ ID: data.ID, Type: ModType.Teleport, Data: data.Data }); 106 | }); 107 | 108 | this.socket.on("ApplyDommage", (data: { AttackType: number; AttarckerID; TargetID; HitPoints: number }) => { 109 | this.entityToModification.push({ ID: data.TargetID, Type: ModType.Hit, Data: data.HitPoints }); 110 | }); 111 | 112 | this.socket.on("ApplyExperience", (data: { ID; Exp: number }) => { 113 | this.entityToModification.push({ ID: data.ID, Type: ModType.Exp, Data: data }); 114 | }); 115 | 116 | this.socket.on("SpawnProjectile", (data) => { 117 | var gameObj = new GameObj(); 118 | gameObj.ID = Math.random(); 119 | gameObj.AddComponent(new PositionComponent(data.StartPos.x, data.StartPos.y, Rotation.Down)); 120 | var movementComponet = new MovementComponent(); 121 | movementComponet.RemoveOnDone = true; 122 | movementComponet.SetTarget(data.TargetPos.x, data.TargetPos.y); 123 | movementComponet.Speed = 1000; 124 | gameObj.AddComponent(movementComponet); 125 | gameObj.AddComponent(new SpriteComponent(44)); 126 | this.newEntityList.push(gameObj); 127 | }); 128 | 129 | this.socket.on("Animation", (data) => { 130 | var gameObj = new GameObj(); 131 | gameObj.ID = Math.random(); 132 | gameObj.AddComponent(new PositionComponent(data.Pos.x, data.Pos.y)); 133 | gameObj.AddComponent(new SimpleAnimationComponent(data.Sprites, false, data.TicksPerFrame)); 134 | gameObj.AddComponent(new SpriteComponent(data.Sprites[0])); 135 | this.newEntityList.push(gameObj); 136 | }); 137 | 138 | 139 | this.socket.on("DeleteCharacters", (data: any[]) => { 140 | 141 | for (var i = 0; i < data.length; i++) { 142 | this.EntityToRemove.push(data[i]); 143 | } 144 | }); 145 | } 146 | 147 | private ProcessEvents(world: World) { 148 | var plrMoveEventList = world.GetEventByType(Events.PlayerMove); 149 | plrMoveEventList.forEach((value) => { 150 | for (var i = 0; i < plrMoveEventList.length; i++) { 151 | this.socket.emit("PlayerMove", plrMoveEventList[i].Payload); 152 | } 153 | }); 154 | 155 | var msgEventList = world.GetEventByType(Events.PlayerMessage); 156 | for (var i = 0; i < msgEventList.length; i++) { 157 | this.socket.emit("PlayerMessage", { Msg: msgEventList[i].Payload }); 158 | } 159 | 160 | var targetEventList = world.GetEventByType(Events.PlayerTarget); 161 | for (var i = 0; i < targetEventList.length; i++) { 162 | this.socket.emit("PlayerTarget", targetEventList[i].Payload); 163 | } 164 | } 165 | 166 | private ModifyEntities(world: World) { 167 | var gameObjList = world.entityList; 168 | for (var j = 0; j < gameObjList.length; j++) { 169 | var movement = gameObjList[j].ComponentList[Componenets.Movement]; 170 | var position = gameObjList[j].ComponentList[Componenets.Position]; 171 | 172 | for (var i = 0; i < this.entityToModification.length; i++) { 173 | if (this.entityToModification[i].ID !== gameObjList[j].ID) continue; 174 | if (this.entityToModification[i].Type === ModType.Move) { 175 | if (!movement) continue; 176 | movement.SetTarget(this.entityToModification[i].Data.Pos.x, this.entityToModification[i].Data.Pos.y); 177 | position.Rotation = this.entityToModification[i].Data.Rot; 178 | } 179 | 180 | if (this.entityToModification[i].Type === ModType.Teleport) { 181 | if (!movement) continue; 182 | movement.IsMoving = false; 183 | movement.SetTarget(this.entityToModification[i].Data.Pos.x, this.entityToModification[i].Data.Pos.y); 184 | position.SetPosition(this.entityToModification[i].Data.Pos.x, this.entityToModification[i].Data.Pos.y); 185 | } 186 | 187 | if (this.entityToModification[i].Type === ModType.Message) { 188 | var chMsg = gameObjList[j].ComponentList[Componenets.CharacterMessage]; 189 | if (!chMsg) { 190 | gameObjList[j].AddComponent(new CharacterMessageComponent(this.entityToModification[i].Data)); 191 | } else { 192 | chMsg.Str = this.entityToModification[i].Data; 193 | } 194 | 195 | } 196 | 197 | if (this.entityToModification[i].Type === ModType.Hit) { 198 | var healthComponent = gameObjList[j].ComponentList[Componenets.Health]; 199 | if (healthComponent) { 200 | healthComponent.LoseHP(this.entityToModification[i].Data); 201 | world.PushEvent(gameObjList[j], Events.TxtSpawn, { Str: this.entityToModification[i].Data.toString(), Color: "Red" }); 202 | 203 | } 204 | } 205 | 206 | if (this.entityToModification[i].Type === ModType.Exp) { 207 | var inputComponent = gameObjList[j].ComponentList[Componenets.Input]; 208 | if (inputComponent) { 209 | world.PushEvent(gameObjList[j], Events.TxtSpawn, { Str: this.entityToModification[i].Data.Exp.toString(), Color: "White" }); 210 | if (this.entityToModification[i].Data.NextLvl) { 211 | inputComponent.Level = this.entityToModification[i].Data.NextLvl; 212 | inputComponent.Experience = 0; 213 | } else { 214 | inputComponent.Experience += this.entityToModification[i].Data.Exp; 215 | } 216 | } 217 | } 218 | } 219 | } 220 | } 221 | 222 | private cleanup() { 223 | this.newEntityList = []; 224 | this.entityToModification = []; 225 | this.EntityToRemove = []; 226 | } 227 | } 228 | 229 | const enum ModType { Move, Teleport, Message, Hit, Exp }; -------------------------------------------------------------------------------- /client/Systems/RenderingSystem.ts: -------------------------------------------------------------------------------- 1 | import SpriteGL, {SpriteRenderer} from "SpriteGL"; 2 | import { 3 | CharacterMessageComponent, 4 | Componenets, 5 | HealthComponent, 6 | PositionComponent, RenderMapComponent, 7 | SpriteComponent 8 | } from "../BasicComponents"; 9 | import {config} from "../Init"; 10 | import {ISystem} from "../Game"; 11 | import {Events, World} from "../World"; 12 | import {Vector2D} from "../../Interchange/DataStructures"; 13 | 14 | export class RenderingSystem implements ISystem { 15 | private renderer: SpriteRenderer; 16 | private mapsToRender = new Array<{ position: PositionComponent; map: RenderMapComponent; }>(); 17 | private dmgTxtList = new Array<{ txtObj; position: Vector2D, lifeTime: number }>(); 18 | constructor(canvas: HTMLCanvasElement, textureAtlas: HTMLImageElement) { 19 | this.renderer = SpriteGL.SpriteRenderer.fromCanvas(canvas, textureAtlas); 20 | } 21 | 22 | Process(world: World) { 23 | var gameObjList = world.entityList; 24 | for (var i = 0; i < gameObjList.length; i++) { 25 | if ((gameObjList[i].ComponentSygnature & Componenets.Position) !== Componenets.Position) continue; 26 | var positionComponent = gameObjList[i].ComponentList[Componenets.Position]; 27 | 28 | var spriteComponent = gameObjList[i].ComponentList[Componenets.Sprite]; 29 | if (spriteComponent) { 30 | var pos = { 31 | x: positionComponent.PixelPosition.x + spriteComponent.SpriteOnTilePos.x, 32 | y: positionComponent.PixelPosition.y + spriteComponent.SpriteOnTilePos.y 33 | } 34 | this.DrawSprite(spriteComponent.RenderingSprite, pos.x, pos.y); 35 | 36 | var chMsg = gameObjList[i].ComponentList[Componenets.CharacterMessage]; 37 | if (chMsg) { 38 | 39 | if (!chMsg.TextObj || chMsg.TextObj.str !== chMsg.Str) { 40 | this.renderer.DisposeTxt(chMsg.TextObj); 41 | chMsg.TextObj = this.renderer.PrepareTxt(chMsg.Str, "Yellow", 14, true); 42 | 43 | } 44 | this.renderer.DrawTxt(chMsg.TextObj, (pos.x - chMsg.TextObj.Size.Width / 2) + 10, pos.y - 23); 45 | } 46 | 47 | var healthComponent = gameObjList[i].ComponentList[Componenets.Health]; 48 | if (healthComponent) { 49 | this.renderer.SetHight(0.001); 50 | this.DrawHealthBar(healthComponent.HP / healthComponent.MaxHP, pos.x, pos.y - 6); 51 | this.renderer.SetHight(0.0); 52 | 53 | if (healthComponent.IsTargeted) { 54 | this.DrawSprite(99, positionComponent.PixelPosition.x, positionComponent.PixelPosition.y); 55 | } 56 | } 57 | 58 | continue; 59 | } 60 | 61 | var mapComponent = gameObjList[i].ComponentList[Componenets.RenderMap]; 62 | if (mapComponent) { 63 | this.mapsToRender.push({ position: positionComponent, map: mapComponent }); 64 | continue; 65 | } 66 | } 67 | 68 | var txts = world.GetEventByType(Events.TxtSpawn); 69 | 70 | for (var i = 0; i < txts.length; i++) { 71 | var posComp = txts[i].Subject.ComponentList[Componenets.Position]; 72 | 73 | var txtObj = this.renderer.PrepareTxt(txts[i].Payload.Str, txts[i].Payload.Color, 11, true); 74 | this.dmgTxtList.push({ 75 | txtObj: txtObj, position: { 76 | x: posComp.PixelPosition.x, y: posComp.PixelPosition.y - 25 77 | }, lifeTime: 0 78 | }); 79 | 80 | } 81 | 82 | this.renderer.SetHight(0.001); 83 | for (var i = 0; i < this.dmgTxtList.length; i++) { 84 | this.renderer.DrawTxt(this.dmgTxtList[i].txtObj, this.dmgTxtList[i].position.x, this.dmgTxtList[i].position.y); 85 | this.dmgTxtList[i].position.y -= 10 / world.FPS; 86 | this.dmgTxtList[i].lifeTime += 1 / world.FPS; 87 | if (this.dmgTxtList[i].lifeTime > 1) { 88 | var txtObjToDispose = this.dmgTxtList.splice(i, 1)[0].txtObj; 89 | this.renderer.DisposeTxt(txtObjToDispose); 90 | i--; 91 | } 92 | } 93 | this.renderer.SetHight(0); 94 | } 95 | 96 | RenderAll(cameraList: Array) { 97 | if (cameraList.length === 0) { 98 | cameraList.push({ x: 55 * config.TileSize, y: 55 * config.TileSize }); 99 | } 100 | 101 | if (this.mapsToRender.length !== 0) { 102 | this.DrawMap(cameraList[0], this.mapsToRender[0].position.PixelPosition, this.mapsToRender[0].map.Tiles); 103 | } 104 | this.mapsToRender = []; 105 | this.renderer.UpdateCamera(cameraList[0].x | 0, cameraList[0].y | 0); 106 | this.renderer.RenderAll(); 107 | } 108 | 109 | 110 | private DrawSprite(index: number, posx: number, posy: number) { 111 | this.renderer.DrawSpr((index % 32) * 32, ((index / 32) | 0) * 32, 32, 32, posx, posy, config.TileSize, config.TileSize); 112 | } 113 | 114 | 115 | private DrawHealthBar(fraction: number, posx: number, posy: number) { 116 | if (fraction > 0.90) { this.renderer.DrawSpr(129, 386, 26, 4, posx, posy, 26, 4); return; } 117 | if (fraction > 0.75) { this.renderer.DrawSpr(129, 391, 26, 4, posx, posy, 26, 4); return; } 118 | if (fraction > 0.60) { this.renderer.DrawSpr(129, 396, 26, 4, posx, posy, 26, 4); return; } 119 | if (fraction > 0.45) { this.renderer.DrawSpr(129, 401, 26, 4, posx, posy, 26, 4); return; } 120 | if (fraction > 0.35) { this.renderer.DrawSpr(161, 386, 26, 4, posx, posy, 26, 4); return; } 121 | if (fraction > 0.20) { this.renderer.DrawSpr(161, 391, 26, 4, posx, posy, 26, 4); return; } 122 | if (fraction > 0.10) { this.renderer.DrawSpr(161, 396, 26, 4, posx, posy, 26, 4); return; } 123 | this.renderer.DrawSpr(161, 401, 26, 4, posx, posy, 26, 4); 124 | } 125 | 126 | 127 | private DrawMap(cameraPos: Vector2D, mapPos: Vector2D, tileMap: number[]) { 128 | this.renderer.SetHight(-0.0001); 129 | for (var i = 0; i < this.mapsToRender.length; i++) { 130 | var startX = ((cameraPos.x - 400) / config.TileSize) | 0; 131 | 132 | var endX = (startX + 800 / config.TileSize) | 0; 133 | endX += 1; 134 | var startY = ((cameraPos.y - 300) / config.TileSize) | 0; 135 | 136 | var endY = (startY + 600 / config.TileSize) | 0; 137 | endY += 2; 138 | if (startX < 0) startX = 0; 139 | if (startY < 0) startY = 0; 140 | if (endX > config.MapWidth - 1) endX = config.MapWidth - 1; 141 | if (endY > config.MapHeight - 1) endY = config.MapHeight - 1; 142 | for (var i = startY; i < endY; i++) { 143 | for (var j = startX; j < endX; j++) { 144 | this.DrawSprite(config.Data[i * config.MapWidth + j] - 1, (j * config.TileSize), i * config.TileSize); 145 | } 146 | } 147 | } 148 | this.renderer.SetHight(0.0); 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /client/Systems/UserInterfaceSystem.ts: -------------------------------------------------------------------------------- 1 | import {ISystem} from "../Game"; 2 | import {Componenets, InputComponent} from "../BasicComponents"; 3 | import {config} from "../Init"; 4 | import {World} from "../World"; 5 | 6 | export class UserInterfaceSytem implements ISystem { 7 | private Level = document.getElementById("Lvl"); 8 | private Exp = document.getElementById("Exp"); 9 | private LvlProgressBar = document.getElementById("LevelProgressBar"); 10 | 11 | Process(world: World) { 12 | for (var i = 0; i < world.entityList.length; i++) { 13 | if ((world.entityList[i].ComponentSygnature & Componenets.Input) === Componenets.Input) { 14 | var inputComponent = world.entityList[i].ComponentList[Componenets.Input]; 15 | this.Level.innerHTML = inputComponent.Level.toString(); 16 | this.Exp.innerHTML = inputComponent.Experience.toString() + "/" + config.Player.LvlExp[inputComponent.Level].toString(); 17 | this.LvlProgressBar.value = inputComponent.Experience / config.Player.LvlExp[inputComponent.Level] * 100; 18 | 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /client/World.ts: -------------------------------------------------------------------------------- 1 | import {GameObj} from "./GameObj"; 2 | 3 | export class World { 4 | entityList = new Array(); 5 | eventList = new Array(); 6 | FPS = 1; 7 | 8 | Add(gameObj: GameObj) { 9 | 10 | if (!this.GetByID(gameObj.ID)) { 11 | 12 | this.entityList.push(gameObj); 13 | } else { 14 | 15 | this.RemoveEntity(gameObj.ID); 16 | this.entityList.push(gameObj); 17 | } 18 | } 19 | 20 | GetByID(ID) { 21 | for (var i = 0; i < this.entityList.length; i++) { 22 | if (this.entityList[i].ID === ID) return this.entityList[i]; 23 | } 24 | return null; 25 | } 26 | 27 | PushEvent(subject: GameObj, eventType: Events, Payload = null) { 28 | this.eventList.push(new GameEvent(subject, eventType, Payload)); 29 | } 30 | 31 | GetEventByType(type: Events): GameEvent[] { 32 | var result = []; 33 | for (var i = 0; i < this.eventList.length; i++) { 34 | if (this.eventList[i].EventType === type) 35 | result.push(this.eventList[i]); 36 | } 37 | return result; 38 | } 39 | 40 | ClearEvets() { 41 | this.eventList = []; 42 | } 43 | 44 | RemoveEntity(ID) { 45 | for (var i = 0; i < this.entityList.length; i++) { 46 | if (this.entityList[i].ID === ID) { 47 | return this.entityList.splice(i, 1)[0]; 48 | } 49 | } 50 | } 51 | 52 | } 53 | 54 | 55 | export enum Events { PlayerMove, PlayerMessage, PlayerTarget, TxtSpawn }; 56 | class GameEvent { 57 | EventType: Events; 58 | Subject: GameObj; 59 | Payload; 60 | 61 | constructor(subject: GameObj, eventType: Events, Payload = null) { 62 | this.Subject = subject; 63 | this.EventType = eventType; 64 | this.Payload = Payload; 65 | } 66 | } -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | TibiaJS client 5 | 48 | 49 | 50 |
51 | 52 | 53 |
54 | 55 |
56 |
57 | Level: 1 58 | Exp: 0 59 |
60 | 61 |
62 | Mana: 63 | 20/20 64 |
65 | 66 |
67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "target": "es2015", 6 | "lib": [ "es2015", "dom" ], 7 | "sourceMap": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TibiaJS", 3 | "version": "0.0.0", 4 | "description": "TibiaJS", 5 | "main": "app.js", 6 | "scripts": { 7 | "run": "node ./start.js", 8 | "build": "concurrently \"npm run build:client\" \"npm run build:server\"", 9 | "build:client": "parcel build client/index.html -d out/static --no-minify", 10 | "build:server": "parcel build server/Server.ts -d out --target node --no-minify" 11 | }, 12 | "author": { 13 | "name": "Pawel", 14 | "email": "" 15 | }, 16 | "dependencies": { 17 | "SpriteGL": "https://github.com/krtr/SpriteGL", 18 | "express": "4.16.3", 19 | "serve-static": "1.13.2", 20 | "socket.io": "2.1.1" 21 | }, 22 | "devDependencies": { 23 | "@types/express": "^4.16.0", 24 | "@types/node": "^10.11.6", 25 | "@types/socket.io": "^1.4.36", 26 | "@types/socket.io-client": "^1.4.32", 27 | "concurrently": "^4.0.1", 28 | "nodemon": "^1.18.10", 29 | "open": "0.0.5", 30 | "parcel-bundler": "^1.10.2", 31 | "typescript": "^3.1.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "TileSize": 32, 3 | "MapWidth": 100, 4 | "MapHeight": 100, 5 | "MobSpawnDelay": 20000, 6 | "Player": { 7 | "LvlExp": [ 75, 125, 200, 300, 450, 650, 800, 1100 ] 8 | }, 9 | "MobSpawns": [ 10 | { "Position": { "x": 80, "y": 80 }, "Count": 4 }, 11 | { "Position": { "x": 44, "y": 73 }, "Count": 3 }, 12 | { "Position": { "x": 14, "y": 73 }, "Count": 4 }, 13 | { "Position": { "x": 8, "y": 54 }, "Count": 5 }, 14 | { "Position": { "x": 31, "y": 35 }, "Count": 3 }, 15 | { "Position": { "x": 82, "y": 23 }, "Count": 7 } 16 | ], 17 | "Mobs": { 18 | "Dwarf": { 19 | "AliveSprites": [ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67 ], 20 | "DeadSprites": [ 68, 69, 70 ], 21 | "Speed": 70, 22 | "Experience": 30, 23 | "HP": 40 24 | }, 25 | "Orc": { 26 | "AliveSprites": [ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124 ], 27 | "DeadSprites": [ 125, 126, 127 ], 28 | "Speed": 100, 29 | "Experience": 25, 30 | "HP": 25 31 | }, 32 | "Minotaur": { 33 | "AliveSprites": [ 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234 ], 34 | "DeadSprites": [ 235, 236, 237 ], 35 | "Speed": 120, 36 | "Experience": 50, 37 | "HP": 35 38 | 39 | }, 40 | "Troll": { 41 | "AliveSprites": [ 244, 245, 246, 247, 248, 249, 238, 239, 240, 241, 242, 243 ], 42 | "DeadSprites": [ 250, 251, 252 ], 43 | "Speed": 90, 44 | "Experience": 20, 45 | "HP": 20 46 | } 47 | }, 48 | "Animations": { 49 | "Beam": { "Sprites": [ 48, 49, 50, 51, 52, 53, 54, 55 ] } 50 | }, 51 | "Data": [ 359, 360, 359, 356, 360, 358, 359, 361, 358, 356, 357, 360, 360, 359, 358, 361, 361, 360, 360, 356, 357, 358, 356, 356, 359, 360, 356, 361, 361, 358, 357, 357, 357, 358, 359, 360, 359, 358, 359, 357, 361, 356, 358, 358, 358, 359, 360, 356, 356, 359, 358, 356, 361, 361, 361, 360, 359, 361, 361, 357, 358, 357, 360, 356, 358, 357, 360, 358, 360, 358, 358, 357, 359, 361, 358, 361, 359, 358, 361, 357, 357, 360, 359, 359, 361, 359, 357, 356, 361, 358, 358, 359, 360, 357, 359, 357, 358, 361, 361, 356, 358, 358, 360, 358, 361, 357, 361, 358, 361, 357, 361, 357, 358, 356, 357, 361, 357, 356, 361, 360, 359, 357, 359, 358, 356, 358, 356, 360, 360, 361, 357, 358, 356, 356, 358, 360, 359, 359, 357, 359, 356, 360, 356, 357, 361, 357, 356, 360, 358, 359, 358, 361, 361, 361, 361, 359, 356, 360, 358, 359, 358, 357, 359, 359, 357, 361, 358, 361, 357, 361, 360, 356, 359, 361, 358, 358, 358, 359, 357, 360, 360, 360, 356, 358, 358, 359, 356, 359, 357, 361, 359, 356, 360, 361, 359, 359, 360, 359, 358, 360, 357, 357, 357, 361, 360, 358, 358, 358, 361, 360, 361, 360, 359, 359, 356, 360, 360, 357, 357, 361, 358, 361, 356, 356, 358, 360, 356, 358, 359, 360, 356, 358, 356, 359, 361, 361, 361, 361, 358, 357, 360, 361, 359, 358, 356, 361, 359, 361, 356, 356, 357, 356, 358, 356, 361, 356, 359, 356, 359, 359, 358, 361, 359, 361, 357, 356, 358, 356, 361, 359, 360, 359, 356, 361, 357, 356, 359, 356, 359, 358, 359, 361, 357, 357, 357, 357, 356, 361, 359, 361, 361, 360, 358, 359, 361, 357, 361, 360, 356, 358, 359, 358, 359, 359, 360, 356, 360, 360, 357, 361, 356, 356, 357, 356, 359, 359, 359, 360, 358, 359, 359, 166, 166, 359, 356, 166, 360, 361, 356, 357, 358, 359, 358, 356, 361, 360, 359, 359, 357, 357, 357, 359, 358, 358, 359, 357, 359, 356, 357, 360, 359, 359, 356, 358, 357, 358, 361, 358, 361, 361, 356, 359, 357, 357, 358, 361, 358, 361, 356, 358, 358, 356, 361, 361, 360, 356, 361, 356, 358, 357, 361, 356, 357, 359, 360, 358, 360, 360, 357, 356, 356, 356, 360, 356, 356, 359, 358, 361, 360, 359, 359, 357, 361, 357, 361, 357, 356, 358, 358, 361, 357, 360, 358, 358, 356, 361, 357, 361, 361, 360, 166, 166, 360, 356, 361, 166, 166, 361, 359, 360, 358, 361, 358, 358, 357, 360, 358, 360, 357, 359, 357, 358, 357, 356, 360, 356, 356, 361, 356, 357, 357, 357, 356, 356, 360, 361, 359, 358, 357, 358, 356, 357, 357, 361, 358, 360, 359, 358, 360, 360, 356, 357, 357, 357, 356, 360, 356, 361, 361, 361, 358, 359, 357, 356, 358, 146, 363, 150, 357, 361, 361, 359, 361, 356, 357, 357, 357, 357, 359, 357, 356, 357, 356, 359, 359, 360, 361, 360, 358, 356, 358, 359, 357, 361, 358, 358, 358, 359, 359, 359, 166, 358, 356, 356, 357, 360, 166, 358, 358, 357, 358, 356, 361, 356, 361, 358, 359, 356, 356, 357, 359, 358, 360, 360, 361, 358, 357, 356, 356, 360, 356, 359, 357, 361, 358, 360, 357, 358, 358, 359, 357, 357, 361, 361, 358, 356, 356, 357, 356, 356, 359, 361, 356, 356, 359, 359, 360, 360, 356, 360, 356, 360, 356, 146, 363, 158, 350, 373, 356, 358, 357, 356, 359, 359, 361, 357, 356, 356, 356, 358, 357, 357, 357, 359, 358, 361, 359, 359, 357, 358, 361, 359, 357, 356, 356, 356, 356, 360, 360, 359, 166, 166, 357, 357, 360, 359, 166, 166, 359, 357, 357, 357, 361, 358, 356, 357, 356, 358, 356, 361, 361, 356, 357, 357, 359, 360, 358, 360, 359, 359, 357, 356, 360, 360, 360, 357, 356, 359, 359, 356, 358, 360, 358, 356, 356, 360, 356, 359, 358, 359, 357, 357, 359, 358, 360, 361, 359, 358, 361, 361, 358, 360, 148, 158, 338, 338, 353, 159, 150, 359, 358, 359, 356, 356, 359, 357, 358, 360, 359, 356, 356, 358, 358, 358, 361, 360, 358, 358, 357, 358, 357, 361, 357, 361, 360, 359, 359, 358, 360, 356, 361, 166, 358, 359, 359, 357, 166, 166, 360, 360, 356, 358, 361, 357, 356, 361, 358, 358, 356, 360, 358, 356, 357, 360, 357, 361, 356, 361, 359, 361, 361, 358, 360, 361, 361, 359, 359, 359, 356, 360, 356, 357, 359, 358, 361, 357, 361, 361, 357, 357, 361, 361, 358, 361, 356, 360, 360, 356, 360, 359, 361, 148, 158, 345, 342, 345, 348, 339, 378, 361, 359, 361, 356, 360, 361, 361, 357, 356, 359, 361, 358, 359, 361, 357, 357, 357, 359, 356, 358, 360, 360, 360, 357, 357, 356, 357, 356, 356, 361, 360, 358, 166, 166, 166, 357, 357, 166, 360, 361, 357, 361, 357, 356, 358, 358, 356, 357, 357, 359, 356, 359, 358, 356, 359, 360, 360, 359, 360, 360, 356, 356, 356, 360, 361, 359, 359, 357, 359, 358, 356, 357, 358, 359, 361, 357, 361, 358, 360, 361, 361, 357, 360, 359, 357, 361, 358, 358, 356, 356, 361, 361, 141, 351, 355, 345, 343, 338, 337, 378, 356, 358, 359, 358, 359, 360, 359, 359, 356, 356, 356, 360, 361, 356, 358, 358, 360, 356, 361, 360, 356, 357, 356, 361, 358, 359, 357, 359, 358, 357, 357, 358, 360, 358, 166, 166, 166, 166, 359, 358, 359, 360, 357, 358, 358, 360, 357, 357, 357, 356, 359, 358, 359, 356, 360, 356, 361, 361, 356, 360, 359, 357, 358, 361, 361, 358, 356, 361, 359, 361, 360, 361, 358, 359, 357, 360, 358, 357, 361, 356, 360, 358, 359, 358, 360, 361, 361, 358, 357, 356, 361, 146, 158, 355, 351, 344, 337, 345, 349, 373, 359, 361, 358, 358, 357, 356, 357, 357, 359, 357, 357, 357, 356, 361, 357, 361, 360, 360, 358, 361, 361, 358, 360, 359, 357, 359, 357, 357, 361, 360, 357, 359, 356, 358, 357, 358, 356, 361, 357, 360, 359, 359, 361, 360, 358, 359, 360, 358, 356, 357, 356, 360, 357, 357, 360, 359, 360, 361, 358, 357, 361, 358, 358, 357, 360, 360, 361, 357, 359, 356, 356, 356, 358, 358, 356, 359, 359, 356, 358, 356, 359, 358, 360, 360, 358, 361, 361, 356, 357, 357, 358, 139, 338, 343, 342, 348, 340, 346, 352, 375, 358, 358, 359, 357, 358, 356, 359, 356, 358, 358, 361, 358, 360, 358, 361, 361, 360, 361, 361, 357, 361, 361, 358, 358, 356, 356, 358, 361, 360, 356, 358, 360, 359, 360, 359, 357, 361, 361, 360, 356, 356, 358, 356, 359, 358, 357, 356, 360, 356, 356, 361, 359, 358, 359, 359, 358, 361, 356, 357, 359, 356, 358, 359, 358, 361, 356, 361, 360, 361, 356, 356, 356, 359, 358, 357, 361, 358, 361, 356, 356, 361, 358, 360, 360, 360, 359, 358, 356, 359, 360, 357, 143, 340, 348, 353, 344, 349, 353, 340, 376, 357, 358, 360, 360, 356, 361, 356, 358, 358, 361, 358, 358, 356, 357, 357, 360, 359, 359, 359, 357, 357, 358, 357, 356, 361, 361, 358, 356, 357, 359, 361, 360, 360, 361, 356, 361, 357, 358, 360, 361, 358, 360, 360, 356, 358, 361, 361, 358, 360, 358, 361, 356, 360, 360, 356, 356, 356, 361, 358, 356, 360, 357, 358, 358, 359, 359, 358, 360, 357, 356, 359, 356, 357, 359, 359, 361, 360, 357, 361, 360, 356, 360, 360, 357, 357, 357, 359, 356, 356, 359, 356, 141, 349, 338, 342, 346, 346, 341, 337, 376, 358, 359, 359, 357, 361, 360, 359, 357, 359, 360, 361, 360, 356, 361, 361, 358, 359, 358, 358, 360, 356, 358, 356, 359, 360, 361, 360, 360, 356, 358, 358, 360, 361, 356, 357, 358, 359, 358, 356, 361, 361, 358, 358, 360, 358, 357, 360, 360, 358, 361, 360, 357, 358, 359, 356, 357, 360, 356, 357, 359, 359, 360, 361, 358, 357, 357, 356, 357, 357, 361, 357, 361, 359, 361, 359, 359, 359, 358, 356, 359, 359, 357, 356, 360, 358, 359, 360, 361, 358, 359, 361, 137, 337, 348, 349, 349, 338, 346, 342, 376, 361, 357, 360, 357, 361, 357, 360, 358, 360, 361, 359, 361, 359, 356, 358, 356, 358, 359, 361, 360, 358, 359, 360, 357, 356, 361, 361, 358, 361, 361, 356, 360, 360, 356, 359, 359, 360, 356, 359, 357, 358, 360, 357, 357, 361, 361, 360, 357, 361, 358, 357, 357, 356, 361, 361, 360, 360, 357, 357, 359, 361, 358, 361, 358, 358, 361, 358, 357, 361, 358, 358, 361, 361, 358, 358, 356, 358, 357, 359, 356, 359, 359, 357, 357, 359, 359, 356, 358, 360, 359, 146, 158, 353, 349, 347, 343, 342, 349, 341, 375, 147, 362, 368, 149, 356, 356, 359, 356, 358, 359, 361, 358, 357, 361, 361, 359, 358, 360, 360, 356, 357, 361, 357, 357, 357, 358, 358, 359, 361, 356, 359, 356, 360, 357, 360, 359, 360, 360, 356, 359, 357, 358, 358, 357, 356, 359, 357, 357, 360, 360, 361, 356, 356, 358, 356, 361, 356, 359, 356, 357, 360, 358, 356, 359, 357, 359, 356, 357, 357, 357, 358, 359, 357, 359, 361, 360, 357, 360, 358, 357, 356, 360, 358, 358, 360, 359, 359, 357, 356, 146, 158, 352, 348, 355, 347, 351, 337, 351, 340, 159, 158, 354, 346, 159, 150, 359, 356, 356, 360, 360, 358, 358, 358, 361, 358, 358, 358, 358, 356, 361, 356, 356, 357, 359, 359, 358, 360, 359, 356, 356, 359, 356, 359, 358, 361, 358, 358, 356, 356, 359, 357, 356, 361, 356, 361, 359, 360, 358, 357, 356, 356, 359, 357, 357, 359, 356, 360, 360, 359, 358, 361, 359, 361, 360, 360, 356, 359, 361, 358, 360, 360, 361, 361, 358, 358, 356, 360, 361, 360, 361, 359, 359, 358, 358, 146, 366, 370, 368, 369, 158, 348, 347, 347, 341, 355, 346, 341, 343, 354, 346, 347, 342, 344, 352, 159, 149, 360, 358, 359, 361, 361, 360, 360, 358, 359, 357, 357, 359, 356, 360, 359, 356, 360, 361, 359, 356, 359, 361, 361, 360, 358, 356, 357, 358, 359, 361, 358, 358, 360, 356, 360, 359, 356, 358, 359, 361, 358, 358, 359, 361, 356, 358, 356, 356, 358, 359, 359, 359, 358, 357, 357, 360, 358, 359, 361, 360, 359, 360, 357, 356, 360, 358, 360, 356, 359, 360, 361, 359, 356, 359, 360, 360, 358, 146, 158, 354, 338, 342, 351, 351, 339, 353, 340, 354, 344, 351, 338, 355, 354, 351, 355, 347, 348, 345, 354, 375, 359, 356, 359, 359, 357, 358, 361, 357, 360, 358, 356, 361, 359, 360, 360, 356, 358, 357, 360, 357, 360, 360, 357, 356, 359, 357, 358, 361, 360, 360, 361, 361, 357, 356, 361, 357, 357, 361, 361, 356, 359, 356, 358, 360, 358, 359, 360, 360, 361, 356, 356, 361, 358, 358, 357, 360, 361, 361, 359, 357, 358, 356, 358, 360, 356, 361, 360, 359, 356, 358, 360, 357, 357, 360, 358, 357, 148, 158, 338, 354, 338, 354, 346, 350, 341, 337, 342, 355, 339, 341, 344, 342, 346, 341, 349, 353, 347, 346, 350, 371, 358, 356, 358, 356, 358, 361, 360, 360, 361, 360, 359, 361, 356, 358, 361, 358, 361, 357, 361, 361, 360, 356, 357, 357, 357, 359, 358, 360, 357, 360, 360, 359, 358, 361, 358, 361, 357, 358, 360, 356, 360, 356, 358, 360, 360, 357, 357, 359, 356, 359, 358, 358, 360, 356, 360, 356, 359, 361, 359, 358, 357, 361, 361, 357, 356, 356, 359, 359, 358, 361, 360, 360, 358, 356, 358, 361, 145, 347, 343, 343, 342, 354, 338, 341, 347, 339, 354, 355, 352, 355, 337, 352, 337, 353, 344, 350, 345, 355, 346, 376, 357, 356, 361, 358, 356, 359, 356, 361, 356, 356, 360, 356, 357, 359, 359, 356, 359, 360, 358, 359, 359, 357, 356, 360, 359, 361, 361, 357, 359, 356, 361, 361, 361, 358, 358, 357, 357, 361, 357, 360, 359, 360, 358, 360, 360, 359, 359, 357, 359, 356, 359, 356, 358, 356, 361, 360, 358, 358, 358, 358, 360, 358, 361, 356, 356, 356, 361, 357, 359, 359, 360, 359, 357, 357, 358, 359, 142, 351, 346, 340, 341, 349, 349, 347, 344, 354, 345, 346, 341, 349, 341, 347, 355, 354, 342, 351, 351, 347, 351, 374, 360, 361, 360, 359, 356, 360, 358, 357, 360, 357, 146, 364, 362, 362, 150, 360, 358, 358, 357, 360, 360, 358, 356, 360, 361, 357, 361, 358, 356, 358, 358, 360, 357, 357, 356, 361, 360, 356, 357, 358, 360, 358, 357, 358, 359, 356, 357, 357, 356, 356, 358, 359, 357, 359, 361, 358, 359, 356, 358, 360, 358, 357, 358, 360, 359, 358, 359, 361, 359, 360, 357, 357, 361, 359, 361, 361, 138, 354, 348, 340, 351, 353, 341, 340, 345, 346, 343, 342, 348, 352, 346, 338, 348, 344, 348, 347, 341, 352, 346, 375, 358, 360, 360, 357, 356, 360, 357, 357, 357, 358, 144, 161, 160, 350, 159, 150, 359, 359, 360, 358, 360, 360, 361, 359, 359, 357, 359, 356, 359, 359, 356, 357, 360, 358, 360, 361, 361, 358, 357, 361, 358, 359, 361, 357, 358, 356, 359, 360, 356, 361, 356, 360, 356, 359, 358, 361, 359, 360, 361, 357, 361, 356, 357, 357, 357, 357, 361, 356, 357, 356, 357, 356, 356, 361, 361, 359, 142, 342, 343, 339, 350, 352, 344, 341, 338, 339, 353, 338, 343, 343, 337, 346, 342, 346, 346, 340, 340, 342, 347, 375, 360, 358, 359, 361, 358, 356, 357, 359, 357, 357, 154, 155, 145, 340, 338, 378, 358, 359, 358, 360, 358, 360, 360, 358, 358, 359, 357, 356, 359, 356, 361, 360, 361, 360, 359, 361, 358, 358, 359, 356, 358, 360, 359, 361, 358, 361, 358, 356, 358, 356, 356, 360, 360, 358, 356, 360, 360, 357, 359, 358, 361, 358, 359, 361, 361, 358, 361, 356, 358, 357, 356, 358, 357, 358, 361, 360, 154, 160, 352, 345, 342, 338, 342, 355, 345, 346, 355, 349, 351, 347, 352, 344, 343, 338, 340, 339, 338, 338, 349, 378, 360, 360, 360, 358, 356, 356, 356, 359, 358, 361, 148, 149, 142, 342, 340, 371, 357, 358, 359, 361, 359, 361, 357, 358, 360, 359, 361, 360, 360, 356, 360, 357, 357, 359, 358, 357, 359, 357, 356, 358, 361, 360, 359, 358, 356, 356, 359, 361, 357, 359, 356, 359, 357, 357, 359, 357, 356, 356, 359, 359, 357, 358, 357, 359, 358, 356, 361, 358, 356, 360, 361, 356, 360, 361, 359, 358, 357, 143, 353, 338, 337, 342, 349, 348, 345, 352, 343, 348, 338, 342, 346, 337, 353, 354, 341, 351, 344, 353, 161, 157, 357, 360, 357, 356, 356, 358, 356, 357, 361, 358, 143, 159, 158, 352, 161, 155, 358, 361, 359, 360, 360, 358, 358, 357, 358, 360, 358, 359, 357, 360, 360, 358, 356, 359, 361, 359, 357, 359, 358, 359, 360, 356, 357, 361, 361, 356, 356, 357, 361, 360, 357, 358, 356, 358, 356, 356, 360, 356, 356, 356, 357, 356, 356, 357, 361, 357, 358, 357, 356, 361, 359, 358, 357, 358, 358, 361, 358, 153, 382, 160, 352, 348, 345, 347, 343, 339, 341, 352, 339, 354, 345, 342, 348, 351, 347, 350, 347, 339, 375, 360, 358, 358, 358, 356, 356, 356, 357, 358, 359, 357, 142, 346, 337, 353, 378, 358, 359, 357, 356, 357, 357, 357, 358, 356, 357, 361, 358, 356, 357, 361, 360, 359, 356, 356, 359, 361, 357, 357, 357, 356, 361, 356, 359, 356, 359, 361, 358, 361, 357, 358, 358, 357, 357, 358, 357, 359, 357, 357, 358, 356, 360, 361, 358, 358, 357, 361, 358, 359, 361, 361, 359, 360, 361, 361, 360, 359, 356, 360, 360, 153, 160, 350, 340, 348, 337, 342, 340, 354, 344, 342, 339, 352, 344, 341, 354, 355, 340, 161, 155, 361, 359, 356, 356, 361, 356, 358, 360, 359, 359, 148, 158, 343, 343, 337, 377, 356, 356, 356, 359, 361, 360, 360, 358, 361, 361, 356, 359, 360, 360, 360, 361, 361, 357, 361, 359, 356, 359, 147, 369, 363, 369, 362, 362, 366, 151, 360, 361, 357, 361, 356, 360, 357, 356, 357, 357, 357, 361, 356, 360, 356, 357, 361, 360, 360, 358, 356, 356, 358, 359, 358, 358, 361, 357, 357, 361, 360, 361, 146, 151, 357, 140, 352, 354, 346, 352, 337, 339, 352, 339, 352, 349, 345, 338, 348, 161, 380, 384, 157, 358, 360, 359, 356, 361, 361, 358, 361, 356, 361, 361, 153, 160, 340, 161, 384, 157, 360, 360, 361, 359, 359, 358, 360, 359, 360, 361, 361, 146, 367, 367, 362, 366, 149, 361, 356, 361, 148, 368, 158, 339, 347, 344, 340, 351, 337, 375, 358, 359, 361, 360, 359, 361, 359, 357, 358, 356, 361, 358, 357, 361, 357, 361, 358, 358, 357, 357, 356, 357, 356, 359, 360, 361, 360, 359, 147, 366, 364, 367, 158, 159, 151, 153, 160, 353, 350, 353, 348, 339, 337, 349, 337, 343, 338, 350, 161, 157, 357, 361, 357, 361, 361, 359, 361, 359, 360, 356, 359, 359, 357, 359, 357, 154, 388, 157, 359, 359, 360, 358, 361, 148, 362, 367, 369, 366, 363, 363, 364, 158, 344, 355, 342, 349, 159, 367, 363, 363, 158, 346, 344, 350, 347, 345, 347, 339, 342, 159, 365, 150, 361, 357, 358, 359, 356, 360, 357, 360, 357, 360, 356, 360, 359, 356, 361, 359, 357, 359, 357, 360, 358, 358, 148, 367, 366, 367, 158, 345, 351, 346, 343, 342, 159, 366, 158, 344, 355, 351, 351, 354, 338, 347, 351, 351, 351, 353, 377, 358, 360, 358, 357, 356, 360, 357, 361, 356, 360, 360, 357, 361, 361, 357, 360, 356, 357, 358, 358, 357, 356, 148, 370, 158, 346, 352, 354, 352, 355, 345, 343, 343, 349, 343, 342, 341, 337, 337, 343, 351, 347, 342, 351, 351, 344, 344, 352, 340, 344, 355, 353, 372, 357, 359, 361, 358, 356, 361, 359, 358, 356, 359, 356, 357, 360, 357, 360, 356, 358, 359, 357, 361, 359, 148, 158, 341, 353, 346, 339, 353, 354, 345, 347, 337, 344, 339, 344, 339, 342, 339, 353, 337, 344, 355, 342, 340, 349, 161, 156, 357, 361, 358, 359, 358, 360, 359, 358, 358, 356, 361, 356, 358, 357, 359, 356, 361, 359, 357, 361, 359, 357, 137, 343, 344, 340, 355, 341, 348, 344, 347, 350, 345, 345, 355, 337, 348, 349, 354, 352, 348, 338, 337, 338, 342, 346, 346, 355, 352, 350, 348, 351, 379, 360, 357, 358, 361, 357, 361, 356, 356, 356, 361, 358, 357, 356, 360, 361, 359, 361, 358, 147, 149, 356, 141, 348, 343, 337, 347, 354, 348, 345, 341, 354, 343, 353, 355, 344, 353, 342, 352, 350, 348, 347, 344, 353, 355, 341, 378, 358, 361, 357, 359, 357, 358, 356, 357, 358, 356, 359, 359, 358, 360, 361, 356, 358, 361, 357, 357, 356, 359, 356, 137, 338, 343, 337, 343, 346, 339, 352, 337, 355, 353, 338, 345, 354, 338, 350, 349, 351, 355, 342, 351, 352, 347, 352, 349, 343, 349, 352, 346, 350, 159, 370, 151, 357, 359, 357, 359, 360, 359, 359, 356, 359, 357, 356, 358, 148, 363, 367, 366, 158, 159, 363, 158, 341, 343, 344, 340, 343, 345, 348, 347, 348, 341, 339, 343, 354, 345, 351, 343, 344, 337, 344, 354, 344, 340, 352, 372, 359, 358, 357, 361, 360, 356, 359, 358, 356, 361, 360, 357, 356, 360, 358, 359, 357, 359, 360, 357, 358, 360, 361, 154, 160, 352, 347, 354, 354, 345, 349, 345, 342, 344, 352, 355, 353, 339, 352, 351, 350, 341, 339, 352, 339, 350, 351, 346, 355, 350, 354, 342, 345, 344, 161, 155, 148, 368, 370, 368, 367, 364, 370, 368, 151, 359, 361, 148, 158, 344, 348, 341, 348, 343, 353, 342, 348, 351, 350, 341, 337, 355, 350, 345, 349, 338, 351, 345, 345, 343, 354, 339, 346, 345, 339, 339, 338, 340, 342, 373, 357, 358, 356, 356, 360, 358, 356, 358, 356, 358, 361, 361, 356, 359, 360, 356, 358, 359, 360, 360, 358, 356, 358, 356, 152, 160, 355, 161, 160, 346, 351, 350, 352, 351, 355, 342, 351, 353, 337, 344, 339, 344, 350, 355, 353, 344, 342, 355, 340, 339, 353, 355, 350, 345, 378, 356, 144, 339, 347, 349, 354, 342, 337, 346, 159, 369, 362, 158, 340, 340, 350, 352, 340, 341, 338, 339, 353, 353, 352, 341, 354, 340, 351, 346, 355, 355, 353, 341, 346, 355, 353, 338, 353, 341, 337, 338, 342, 346, 350, 159, 151, 358, 360, 359, 356, 357, 358, 359, 357, 360, 357, 357, 360, 358, 358, 358, 360, 356, 357, 359, 360, 359, 357, 360, 358, 153, 387, 155, 153, 388, 160, 340, 343, 348, 350, 351, 342, 347, 343, 340, 344, 347, 355, 337, 349, 352, 350, 344, 337, 349, 342, 343, 348, 355, 378, 147, 158, 351, 345, 354, 339, 344, 346, 341, 344, 344, 344, 344, 354, 345, 355, 352, 342, 341, 341, 352, 349, 350, 355, 338, 352, 347, 352, 349, 353, 350, 339, 344, 339, 344, 338, 353, 355, 347, 346, 348, 348, 338, 337, 349, 378, 361, 361, 361, 359, 356, 356, 360, 361, 360, 357, 360, 360, 358, 356, 361, 356, 360, 360, 357, 356, 359, 358, 358, 358, 356, 361, 358, 358, 359, 139, 348, 354, 345, 352, 346, 339, 345, 348, 344, 337, 343, 344, 351, 340, 348, 346, 342, 353, 354, 349, 347, 344, 340, 378, 154, 160, 349, 348, 345, 349, 351, 340, 339, 349, 346, 344, 343, 338, 346, 341, 338, 347, 345, 353, 353, 352, 352, 344, 351, 355, 338, 347, 355, 340, 337, 352, 345, 350, 338, 345, 350, 342, 346, 349, 353, 341, 340, 344, 346, 159, 150, 359, 360, 359, 356, 360, 359, 358, 357, 357, 356, 359, 359, 359, 356, 358, 357, 146, 364, 363, 365, 149, 360, 356, 357, 359, 356, 361, 359, 138, 348, 349, 337, 348, 339, 348, 351, 348, 345, 344, 338, 354, 355, 339, 345, 347, 343, 338, 347, 343, 348, 344, 344, 159, 369, 158, 348, 350, 340, 355, 350, 342, 352, 346, 354, 342, 349, 351, 355, 352, 343, 348, 347, 351, 345, 342, 339, 350, 353, 340, 343, 353, 346, 354, 348, 354, 348, 337, 340, 348, 340, 337, 342, 338, 341, 338, 352, 338, 348, 339, 159, 149, 359, 360, 360, 356, 358, 360, 359, 358, 358, 356, 356, 356, 357, 147, 365, 158, 340, 345, 346, 373, 360, 358, 359, 358, 356, 358, 359, 152, 384, 160, 350, 343, 343, 351, 342, 339, 338, 346, 342, 340, 347, 337, 339, 354, 352, 340, 346, 348, 350, 353, 350, 347, 350, 344, 346, 342, 354, 340, 351, 348, 353, 345, 344, 339, 339, 347, 343, 354, 348, 350, 341, 354, 350, 348, 341, 343, 347, 352, 346, 314, 315, 352, 350, 350, 354, 355, 341, 343, 340, 345, 355, 337, 350, 351, 354, 351, 348, 351, 348, 159, 367, 370, 151, 361, 359, 356, 358, 361, 361, 357, 356, 358, 356, 139, 347, 339, 355, 351, 342, 373, 356, 357, 356, 361, 361, 360, 356, 357, 358, 153, 385, 160, 346, 352, 345, 339, 350, 347, 343, 347, 355, 351, 350, 349, 345, 339, 347, 353, 352, 346, 348, 346, 341, 355, 346, 350, 350, 347, 339, 352, 342, 341, 346, 347, 355, 344, 354, 353, 350, 355, 352, 343, 355, 344, 341, 338, 348, 353, 354, 301, 313, 347, 349, 348, 349, 340, 338, 351, 352, 339, 337, 339, 344, 338, 339, 347, 348, 346, 342, 354, 338, 343, 159, 363, 149, 358, 359, 357, 360, 360, 358, 360, 360, 138, 343, 341, 337, 343, 347, 159, 150, 358, 357, 360, 356, 359, 356, 356, 356, 359, 357, 152, 160, 353, 347, 337, 347, 343, 346, 347, 347, 347, 346, 348, 345, 346, 351, 347, 343, 344, 352, 350, 338, 338, 346, 340, 344, 350, 349, 353, 349, 337, 341, 345, 347, 354, 354, 354, 347, 350, 342, 337, 353, 342, 344, 351, 350, 337, 337, 302, 313, 346, 342, 344, 350, 352, 351, 339, 339, 352, 350, 349, 350, 355, 347, 351, 339, 343, 340, 338, 343, 349, 345, 344, 377, 361, 359, 356, 358, 357, 358, 358, 361, 143, 349, 349, 350, 349, 344, 349, 159, 150, 361, 361, 356, 358, 361, 357, 360, 360, 356, 359, 153, 383, 160, 340, 340, 350, 341, 337, 348, 337, 340, 351, 337, 354, 353, 337, 353, 345, 353, 343, 353, 344, 346, 348, 346, 341, 353, 351, 343, 345, 346, 347, 346, 345, 340, 348, 339, 338, 353, 338, 346, 350, 355, 351, 351, 344, 337, 301, 319, 298, 315, 347, 338, 353, 343, 344, 348, 351, 350, 341, 343, 350, 337, 349, 355, 350, 342, 350, 337, 348, 347, 340, 378, 360, 356, 361, 359, 358, 358, 357, 146, 158, 351, 340, 350, 351, 345, 347, 338, 159, 150, 359, 357, 358, 361, 361, 359, 360, 357, 361, 360, 361, 144, 340, 343, 355, 338, 355, 345, 342, 351, 350, 339, 341, 350, 352, 343, 345, 346, 351, 339, 348, 341, 338, 352, 341, 350, 344, 348, 340, 340, 352, 338, 341, 350, 346, 351, 337, 343, 351, 354, 342, 351, 343, 339, 340, 351, 317, 299, 321, 319, 315, 343, 338, 340, 354, 343, 353, 355, 341, 352, 342, 338, 353, 347, 353, 338, 350, 347, 355, 353, 341, 378, 360, 358, 358, 358, 358, 356, 358, 142, 341, 346, 341, 353, 351, 349, 355, 344, 161, 155, 360, 357, 361, 360, 356, 360, 356, 356, 359, 360, 360, 138, 340, 340, 351, 354, 338, 351, 343, 349, 337, 341, 339, 355, 348, 339, 346, 341, 349, 348, 349, 343, 343, 347, 338, 341, 344, 350, 352, 337, 346, 348, 339, 350, 344, 348, 346, 350, 350, 354, 341, 342, 349, 345, 350, 354, 340, 345, 317, 321, 319, 298, 298, 315, 350, 354, 345, 352, 354, 348, 340, 351, 355, 353, 337, 339, 338, 351, 345, 342, 347, 159, 149, 356, 357, 361, 358, 361, 357, 138, 337, 352, 347, 350, 351, 342, 344, 161, 156, 359, 360, 357, 357, 358, 361, 361, 358, 358, 361, 358, 358, 140, 338, 349, 345, 337, 344, 349, 353, 342, 339, 349, 350, 338, 346, 345, 340, 341, 340, 348, 349, 350, 355, 352, 344, 341, 338, 352, 349, 355, 350, 340, 351, 345, 349, 354, 341, 339, 343, 355, 342, 346, 350, 350, 340, 353, 340, 352, 314, 318, 320, 300, 321, 319, 315, 354, 349, 347, 340, 350, 353, 343, 338, 343, 340, 350, 337, 352, 349, 342, 347, 348, 374, 358, 357, 361, 360, 357, 147, 158, 339, 339, 342, 344, 340, 161, 388, 156, 357, 359, 361, 360, 360, 147, 151, 358, 356, 358, 356, 357, 356, 141, 350, 341, 354, 345, 342, 351, 353, 337, 341, 352, 341, 337, 352, 346, 340, 345, 353, 339, 346, 349, 339, 341, 354, 347, 338, 347, 343, 338, 350, 349, 346, 354, 347, 353, 351, 343, 350, 338, 338, 344, 345, 339, 344, 337, 314, 298, 318, 176, 312, 314, 318, 183, 313, 337, 340, 340, 350, 341, 348, 354, 339, 342, 349, 355, 352, 341, 355, 337, 351, 161, 157, 360, 357, 356, 360, 356, 143, 348, 352, 345, 342, 340, 343, 159, 366, 366, 362, 363, 149, 359, 147, 158, 374, 361, 356, 359, 356, 359, 359, 144, 339, 345, 347, 348, 339, 347, 345, 340, 338, 341, 353, 351, 341, 346, 344, 344, 350, 344, 340, 345, 352, 353, 354, 346, 349, 351, 346, 345, 352, 339, 350, 347, 351, 341, 341, 337, 339, 347, 350, 355, 354, 351, 110, 341, 301, 320, 300, 299, 316, 301, 185, 184, 312, 348, 351, 355, 352, 355, 337, 337, 355, 350, 347, 346, 340, 342, 340, 341, 339, 372, 361, 361, 356, 361, 357, 361, 143, 355, 345, 340, 337, 337, 346, 341, 337, 348, 339, 348, 159, 149, 144, 343, 159, 366, 368, 151, 359, 357, 357, 138, 341, 344, 349, 347, 350, 348, 347, 314, 298, 298, 298, 298, 315, 338, 350, 338, 340, 345, 341, 353, 349, 339, 339, 345, 354, 355, 340, 340, 347, 349, 337, 345, 344, 354, 340, 349, 338, 349, 339, 109, 106, 107, 113, 110, 111, 319, 315, 352, 314, 318, 320, 299, 316, 341, 345, 340, 346, 347, 340, 355, 348, 354, 346, 338, 341, 342, 352, 337, 342, 379, 357, 356, 357, 361, 359, 360, 142, 353, 349, 344, 341, 340, 344, 344, 350, 354, 353, 350, 343, 159, 158, 347, 337, 353, 350, 159, 151, 148, 367, 158, 354, 341, 341, 342, 314, 298, 298, 318, 181, 320, 299, 321, 319, 298, 298, 298, 315, 314, 315, 349, 337, 339, 348, 343, 343, 352, 337, 344, 352, 347, 338, 338, 354, 355, 339, 352, 350, 340, 339, 113, 110, 111, 112, 113, 110, 185, 313, 339, 302, 175, 319, 315, 353, 340, 353, 353, 342, 354, 351, 342, 350, 351, 339, 339, 337, 342, 339, 346, 341, 372, 361, 357, 358, 356, 358, 146, 158, 353, 348, 348, 345, 344, 353, 347, 344, 348, 343, 343, 347, 340, 351, 353, 340, 355, 342, 340, 159, 158, 351, 347, 314, 298, 298, 298, 318, 181, 181, 185, 180, 312, 314, 318, 320, 321, 320, 321, 319, 318, 319, 298, 315, 343, 343, 337, 349, 349, 350, 349, 340, 346, 338, 343, 349, 341, 342, 341, 353, 354, 354, 106, 345, 348, 314, 298, 318, 182, 319, 298, 318, 175, 181, 313, 348, 346, 337, 345, 337, 349, 354, 343, 343, 345, 349, 346, 340, 354, 354, 339, 161, 155, 361, 356, 361, 357, 361, 137, 352, 350, 337, 351, 351, 343, 351, 339, 339, 347, 354, 340, 351, 345, 339, 353, 342, 345, 341, 353, 348, 338, 338, 314, 318, 320, 321, 182, 183, 179, 320, 299, 299, 316, 301, 174, 313, 301, 319, 318, 181, 174, 177, 178, 319, 315, 314, 298, 298, 315, 352, 352, 342, 355, 344, 351, 344, 348, 351, 351, 345, 344, 345, 337, 345, 314, 318, 179, 178, 185, 174, 183, 182, 180, 320, 316, 337, 351, 353, 353, 338, 345, 352, 349, 343, 349, 353, 351, 346, 353, 346, 345, 375, 359, 361, 356, 357, 358, 356, 141, 346, 354, 341, 340, 346, 355, 347, 351, 343, 344, 340, 341, 339, 353, 351, 352, 348, 314, 298, 315, 346, 346, 314, 318, 320, 316, 301, 176, 320, 300, 316, 343, 339, 341, 317, 300, 316, 317, 299, 321, 185, 320, 321, 181, 176, 319, 318, 183, 177, 319, 298, 298, 315, 344, 345, 338, 340, 343, 344, 340, 339, 352, 340, 314, 298, 318, 185, 320, 300, 321, 179, 176, 174, 180, 319, 315, 354, 341, 353, 337, 348, 339, 344, 340, 337, 348, 337, 355, 351, 339, 340, 346, 378, 358, 359, 358, 356, 360, 356, 141, 346, 353, 341, 347, 352, 340, 354, 345, 344, 343, 347, 353, 340, 355, 343, 345, 345, 302, 179, 319, 298, 298, 318, 185, 319, 315, 317, 300, 316, 341, 354, 352, 344, 345, 344, 343, 340, 341, 341, 317, 299, 316, 301, 184, 185, 320, 321, 182, 177, 183, 180, 182, 319, 298, 298, 315, 355, 353, 340, 339, 339, 353, 345, 301, 181, 320, 299, 316, 314, 318, 185, 179, 183, 320, 321, 319, 298, 315, 344, 351, 344, 348, 350, 343, 337, 350, 342, 339, 348, 340, 352, 347, 372, 357, 358, 359, 360, 358, 360, 142, 338, 348, 354, 352, 349, 349, 349, 352, 347, 339, 314, 298, 298, 298, 298, 298, 298, 318, 320, 321, 185, 320, 299, 299, 299, 316, 349, 352, 345, 338, 347, 340, 349, 355, 341, 353, 343, 337, 339, 347, 337, 337, 317, 299, 299, 316, 302, 176, 177, 177, 184, 184, 185, 176, 174, 319, 298, 298, 315, 353, 349, 352, 314, 318, 181, 313, 350, 314, 318, 180, 174, 184, 176, 312, 317, 299, 321, 319, 315, 355, 344, 354, 339, 351, 342, 344, 352, 354, 337, 342, 339, 161, 156, 357, 356, 360, 361, 360, 361, 143, 343, 348, 352, 342, 338, 346, 346, 353, 337, 348, 302, 320, 299, 299, 321, 177, 320, 299, 316, 317, 299, 316, 349, 342, 339, 340, 340, 355, 353, 161, 388, 386, 160, 341, 355, 352, 337, 354, 344, 338, 341, 338, 339, 343, 354, 351, 317, 299, 300, 321, 182, 180, 175, 175, 179, 185, 178, 185, 319, 298, 298, 298, 318, 175, 176, 319, 298, 318, 175, 183, 176, 179, 180, 312, 346, 339, 317, 321, 313, 346, 346, 348, 347, 347, 355, 348, 345, 345, 345, 342, 345, 374, 357, 359, 361, 358, 357, 360, 360, 153, 160, 347, 345, 354, 344, 351, 343, 345, 354, 340, 317, 316, 351, 353, 317, 299, 316, 351, 350, 341, 355, 347, 348, 342, 161, 388, 380, 383, 160, 159, 150, 356, 154, 386, 381, 383, 160, 355, 341, 354, 344, 347, 351, 344, 351, 348, 344, 355, 338, 317, 321, 183, 176, 183, 185, 174, 174, 184, 320, 299, 300, 321, 180, 178, 184, 175, 175, 174, 177, 174, 320, 299, 299, 316, 338, 337, 349, 301, 313, 342, 351, 339, 348, 346, 355, 349, 348, 353, 339, 350, 337, 371, 358, 359, 360, 360, 360, 356, 358, 357, 141, 348, 346, 352, 354, 340, 342, 353, 348, 344, 344, 339, 344, 340, 351, 342, 347, 354, 355, 350, 350, 343, 349, 350, 378, 356, 360, 357, 152, 382, 156, 357, 358, 359, 359, 360, 142, 351, 342, 345, 341, 338, 353, 337, 341, 341, 353, 344, 337, 355, 302, 320, 300, 321, 184, 175, 184, 184, 313, 314, 315, 317, 321, 175, 175, 180, 320, 299, 299, 300, 316, 345, 340, 350, 345, 342, 354, 301, 313, 340, 346, 355, 345, 344, 352, 344, 339, 348, 349, 352, 346, 376, 359, 359, 357, 357, 357, 359, 358, 356, 145, 345, 340, 343, 337, 339, 337, 347, 345, 345, 343, 348, 349, 344, 341, 346, 342, 351, 348, 339, 343, 349, 341, 352, 377, 359, 361, 359, 361, 356, 357, 360, 361, 358, 356, 147, 158, 340, 346, 352, 350, 342, 345, 353, 355, 352, 345, 338, 353, 352, 301, 319, 315, 301, 183, 320, 321, 175, 319, 318, 319, 298, 318, 174, 175, 320, 316, 355, 340, 337, 337, 344, 355, 351, 346, 351, 314, 318, 312, 345, 341, 341, 343, 345, 349, 344, 350, 352, 339, 337, 354, 379, 356, 357, 359, 359, 360, 360, 356, 357, 145, 341, 347, 352, 350, 342, 355, 338, 341, 349, 338, 338, 354, 344, 350, 338, 353, 342, 352, 354, 346, 344, 351, 343, 159, 362, 151, 361, 360, 357, 361, 358, 360, 356, 147, 158, 338, 348, 338, 342, 338, 355, 348, 341, 348, 343, 338, 339, 347, 353, 301, 183, 312, 317, 321, 312, 301, 179, 183, 175, 174, 174, 320, 299, 300, 316, 340, 351, 340, 351, 347, 349, 349, 340, 350, 353, 302, 174, 313, 348, 341, 351, 352, 342, 338, 354, 346, 348, 354, 340, 161, 157, 356, 361, 356, 361, 357, 361, 359, 361, 140, 339, 347, 347, 349, 350, 338, 341, 344, 348, 342, 349, 352, 347, 355, 351, 354, 355, 345, 352, 340, 345, 353, 350, 161, 380, 157, 358, 358, 361, 357, 356, 356, 147, 158, 341, 351, 342, 353, 340, 343, 338, 341, 354, 349, 354, 340, 344, 342, 339, 302, 179, 319, 298, 318, 319, 318, 179, 179, 180, 177, 183, 312, 352, 347, 348, 352, 353, 350, 353, 340, 350, 352, 337, 345, 341, 317, 321, 319, 315, 343, 344, 355, 350, 344, 337, 340, 350, 348, 351, 374, 356, 359, 359, 361, 359, 358, 356, 356, 360, 153, 160, 355, 343, 355, 347, 344, 338, 342, 352, 349, 347, 355, 350, 342, 347, 347, 348, 350, 344, 343, 351, 354, 352, 371, 148, 362, 151, 361, 361, 360, 358, 361, 152, 160, 161, 382, 160, 343, 345, 342, 354, 353, 347, 338, 342, 343, 349, 349, 340, 301, 320, 299, 321, 181, 182, 183, 184, 174, 174, 174, 174, 319, 315, 351, 350, 338, 344, 350, 347, 355, 348, 341, 348, 354, 351, 343, 317, 321, 319, 298, 315, 350, 342, 342, 346, 339, 344, 352, 351, 378, 359, 361, 357, 359, 358, 360, 358, 358, 357, 356, 145, 342, 342, 350, 344, 353, 353, 345, 345, 344, 355, 354, 350, 351, 353, 342, 344, 348, 351, 340, 355, 350, 352, 159, 158, 339, 373, 359, 358, 357, 361, 358, 361, 153, 156, 148, 158, 345, 353, 351, 353, 338, 354, 343, 344, 347, 339, 345, 355, 301, 319, 315, 301, 183, 175, 320, 299, 299, 321, 178, 176, 178, 313, 347, 353, 343, 343, 341, 349, 348, 341, 355, 341, 341, 339, 340, 353, 317, 299, 321, 312, 343, 352, 350, 355, 343, 339, 339, 348, 376, 358, 360, 356, 361, 361, 358, 360, 357, 357, 356, 144, 338, 340, 343, 337, 347, 351, 354, 346, 353, 348, 343, 344, 353, 345, 347, 347, 352, 349, 350, 355, 341, 342, 343, 342, 352, 159, 365, 151, 357, 361, 359, 360, 357, 357, 154, 160, 348, 347, 346, 348, 347, 351, 346, 349, 337, 337, 355, 345, 317, 321, 319, 318, 178, 180, 319, 298, 298, 318, 175, 183, 184, 312, 348, 354, 344, 339, 347, 344, 349, 347, 342, 346, 355, 339, 355, 340, 337, 314, 318, 313, 347, 342, 337, 342, 349, 350, 340, 342, 372, 357, 359, 357, 360, 360, 361, 360, 359, 357, 361, 137, 341, 344, 338, 346, 349, 352, 347, 347, 342, 352, 353, 352, 338, 342, 343, 348, 337, 348, 354, 354, 341, 354, 343, 337, 348, 347, 338, 159, 151, 361, 147, 367, 151, 361, 359, 153, 160, 337, 342, 346, 350, 341, 353, 350, 339, 355, 353, 343, 342, 317, 321, 176, 183, 184, 320, 299, 321, 182, 175, 182, 181, 312, 346, 353, 355, 340, 350, 339, 341, 354, 349, 339, 354, 355, 340, 314, 298, 318, 320, 316, 347, 338, 354, 352, 337, 340, 341, 353, 377, 356, 357, 359, 358, 356, 359, 358, 360, 358, 360, 139, 355, 339, 340, 347, 341, 354, 342, 354, 340, 340, 343, 337, 355, 346, 349, 352, 351, 353, 345, 354, 345, 338, 339, 349, 345, 347, 352, 353, 159, 150, 142, 353, 159, 150, 358, 360, 145, 343, 338, 337, 346, 353, 342, 348, 346, 338, 338, 343, 353, 343, 317, 300, 321, 320, 316, 337, 301, 184, 182, 178, 180, 313, 351, 355, 355, 354, 352, 350, 337, 341, 344, 353, 339, 352, 337, 317, 299, 299, 316, 337, 346, 341, 346, 345, 354, 341, 337, 340, 375, 361, 361, 360, 358, 360, 361, 357, 356, 356, 358, 142, 348, 339, 344, 354, 349, 344, 340, 340, 338, 341, 346, 345, 347, 352, 341, 344, 353, 338, 352, 354, 344, 342, 350, 341, 344, 355, 350, 348, 348, 159, 158, 346, 352, 159, 369, 367, 158, 340, 338, 350, 346, 348, 350, 352, 348, 343, 340, 355, 337, 354, 342, 353, 302, 313, 347, 351, 317, 321, 185, 175, 320, 316, 342, 338, 350, 354, 353, 338, 340, 340, 342, 349, 339, 353, 338, 344, 341, 340, 337, 344, 343, 350, 349, 352, 350, 337, 353, 346, 377, 359, 360, 358, 359, 356, 360, 360, 361, 357, 356, 144, 353, 348, 342, 348, 348, 348, 353, 341, 349, 340, 351, 341, 343, 342, 354, 348, 354, 349, 343, 347, 347, 340, 343, 347, 352, 355, 352, 337, 353, 348, 352, 347, 344, 338, 351, 350, 350, 342, 339, 351, 349, 349, 339, 339, 344, 351, 339, 349, 339, 339, 347, 353, 301, 319, 315, 354, 349, 302, 185, 185, 312, 342, 343, 338, 352, 345, 352, 355, 346, 354, 339, 346, 343, 346, 344, 350, 348, 349, 349, 347, 339, 343, 350, 344, 347, 344, 347, 355, 372, 360, 360, 360, 360, 358, 356, 360, 360, 357, 358, 140, 338, 343, 346, 353, 338, 337, 349, 349, 354, 339, 352, 340, 343, 355, 345, 340, 337, 351, 343, 353, 338, 343, 341, 343, 339, 341, 350, 339, 353, 345, 340, 342, 355, 341, 338, 351, 344, 343, 353, 353, 344, 338, 341, 351, 348, 352, 353, 344, 337, 354, 341, 350, 317, 321, 319, 298, 298, 318, 175, 320, 316, 349, 355, 342, 343, 338, 348, 349, 354, 350, 354, 339, 343, 346, 338, 337, 338, 349, 337, 347, 344, 352, 354, 348, 346, 353, 338, 345, 372, 361, 361, 357, 356, 358, 357, 357, 361, 360, 360, 138, 354, 348, 354, 339, 343, 348, 353, 348, 350, 350, 352, 343, 340, 337, 354, 344, 349, 355, 354, 354, 352, 353, 338, 355, 349, 350, 337, 341, 351, 347, 343, 337, 339, 350, 342, 340, 348, 353, 354, 347, 348, 337, 355, 351, 348, 345, 339, 352, 340, 342, 338, 340, 354, 301, 177, 179, 178, 175, 175, 313, 345, 338, 342, 348, 352, 349, 351, 345, 352, 347, 348, 355, 339, 354, 353, 347, 348, 338, 341, 343, 339, 342, 340, 353, 338, 342, 337, 344, 373, 357, 358, 358, 356, 361, 361, 356, 359, 358, 361, 142, 346, 340, 355, 350, 341, 354, 355, 340, 355, 353, 350, 340, 344, 353, 351, 344, 340, 341, 346, 348, 346, 354, 345, 344, 353, 344, 345, 355, 351, 339, 355, 342, 349, 342, 349, 355, 339, 351, 347, 345, 347, 348, 343, 338, 337, 350, 355, 340, 337, 346, 349, 340, 314, 318, 184, 184, 175, 183, 320, 316, 344, 338, 340, 352, 343, 342, 344, 341, 351, 349, 343, 339, 346, 354, 354, 344, 342, 351, 342, 352, 346, 350, 344, 350, 345, 354, 341, 353, 378, 360, 361, 357, 358, 358, 357, 357, 356, 358, 356, 138, 350, 346, 345, 354, 344, 354, 352, 340, 342, 352, 339, 351, 340, 340, 350, 344, 338, 351, 337, 348, 347, 354, 354, 344, 345, 354, 352, 349, 344, 349, 352, 345, 343, 341, 343, 347, 352, 353, 339, 346, 342, 349, 339, 352, 354, 340, 347, 347, 347, 341, 354, 314, 318, 182, 183, 175, 320, 299, 316, 351, 348, 349, 340, 343, 346, 355, 354, 347, 354, 339, 338, 354, 349, 352, 342, 345, 342, 350, 344, 340, 348, 349, 350, 340, 346, 342, 345, 344, 377, 360, 359, 361, 356, 358, 360, 361, 359, 360, 361, 142, 351, 348, 345, 343, 343, 352, 345, 353, 353, 349, 341, 348, 338, 337, 353, 344, 346, 339, 343, 352, 341, 345, 337, 340, 353, 342, 353, 348, 337, 340, 339, 354, 342, 340, 345, 341, 348, 341, 337, 340, 337, 348, 343, 338, 343, 341, 346, 354, 337, 345, 344, 302, 174, 184, 320, 300, 316, 350, 349, 348, 337, 354, 337, 348, 341, 342, 353, 338, 341, 354, 340, 353, 343, 345, 352, 344, 338, 347, 347, 337, 344, 340, 338, 339, 337, 347, 346, 161, 157, 360, 356, 357, 356, 356, 356, 356, 360, 359, 358, 139, 350, 350, 343, 339, 352, 339, 349, 346, 351, 340, 343, 343, 344, 339, 353, 339, 347, 347, 351, 353, 339, 341, 343, 348, 338, 338, 354, 339, 339, 344, 344, 338, 351, 343, 346, 352, 342, 338, 349, 344, 347, 342, 337, 353, 354, 346, 346, 347, 339, 354, 347, 302, 179, 320, 316, 339, 351, 339, 352, 348, 346, 353, 347, 343, 353, 345, 344, 350, 348, 352, 343, 345, 339, 351, 343, 337, 349, 353, 337, 349, 353, 350, 345, 355, 354, 343, 347, 376, 359, 360, 358, 358, 356, 357, 359, 358, 359, 359, 361, 140, 348, 353, 339, 351, 337, 354, 352, 338, 342, 339, 338, 338, 337, 342, 337, 347, 346, 341, 355, 341, 349, 352, 338, 355, 346, 341, 338, 338, 352, 351, 344, 338, 350, 342, 340, 338, 345, 348, 346, 345, 343, 348, 342, 344, 347, 353, 341, 351, 338, 340, 354, 317, 299, 316, 351, 354, 344, 352, 348, 343, 337, 347, 341, 344, 341, 339, 354, 337, 355, 354, 352, 352, 353, 337, 343, 348, 345, 340, 340, 340, 343, 338, 341, 345, 349, 349, 340, 378, 357, 359, 356, 358, 359, 356, 356, 356, 357, 358, 148, 158, 353, 352, 337, 346, 351, 339, 347, 339, 354, 350, 337, 343, 341, 345, 352, 340, 347, 345, 344, 340, 341, 342, 348, 353, 348, 338, 353, 351, 338, 348, 337, 345, 339, 345, 340, 343, 349, 350, 355, 346, 338, 343, 337, 347, 346, 355, 342, 342, 337, 348, 343, 337, 353, 354, 339, 348, 337, 355, 349, 355, 344, 349, 337, 345, 353, 349, 353, 354, 345, 343, 340, 347, 348, 337, 344, 346, 354, 340, 347, 351, 345, 350, 348, 339, 341, 342, 338, 159, 149, 358, 361, 357, 360, 359, 358, 361, 356, 361, 143, 340, 338, 342, 345, 350, 350, 351, 346, 341, 343, 346, 348, 344, 344, 343, 354, 343, 353, 353, 339, 347, 344, 338, 354, 337, 337, 347, 351, 345, 338, 345, 346, 354, 342, 348, 345, 346, 346, 338, 347, 347, 337, 346, 348, 338, 350, 350, 353, 346, 352, 355, 337, 337, 345, 338, 348, 344, 348, 338, 342, 343, 350, 344, 349, 342, 339, 340, 340, 339, 341, 354, 339, 339, 342, 348, 346, 350, 338, 339, 354, 338, 340, 338, 349, 337, 343, 354, 338, 339, 376, 359, 357, 361, 359, 357, 356, 356, 361, 360, 140, 355, 338, 338, 351, 338, 345, 345, 340, 348, 342, 355, 348, 350, 337, 347, 353, 351, 347, 350, 353, 344, 346, 338, 347, 349, 354, 354, 350, 352, 337, 348, 354, 343, 351, 349, 350, 354, 339, 345, 348, 354, 346, 355, 338, 354, 353, 345, 348, 344, 341, 350, 341, 339, 355, 354, 354, 337, 355, 339, 350, 351, 345, 348, 352, 343, 353, 347, 344, 338, 342, 340, 338, 346, 349, 341, 352, 344, 337, 354, 339, 344, 347, 341, 338, 342, 339, 337, 343, 161, 157, 361, 358, 361, 359, 357, 356, 356, 358, 360, 137, 355, 338, 355, 349, 338, 350, 355, 351, 345, 339, 353, 345, 341, 351, 348, 345, 353, 349, 352, 343, 351, 341, 348, 347, 355, 348, 343, 341, 349, 344, 340, 351, 349, 340, 343, 338, 339, 340, 339, 355, 345, 347, 340, 355, 351, 349, 347, 345, 343, 344, 354, 345, 339, 344, 349, 341, 352, 347, 341, 340, 354, 353, 344, 339, 344, 348, 342, 337, 354, 337, 337, 348, 347, 339, 341, 344, 353, 352, 345, 354, 345, 355, 345, 337, 349, 342, 354, 161, 156, 357, 358, 360, 360, 358, 356, 361, 361, 356, 357, 140, 338, 352, 349, 347, 354, 342, 350, 355, 344, 347, 347, 338, 343, 340, 346, 340, 354, 345, 338, 352, 352, 338, 347, 342, 344, 341, 342, 353, 355, 344, 342, 337, 339, 353, 340, 348, 354, 353, 353, 338, 352, 343, 344, 353, 353, 351, 338, 340, 345, 344, 348, 345, 352, 345, 340, 353, 341, 347, 351, 338, 351, 343, 351, 345, 352, 339, 355, 343, 347, 339, 344, 353, 338, 340, 342, 348, 346, 347, 337, 342, 344, 343, 343, 355, 346, 337, 351, 374, 357, 361, 361, 357, 361, 361, 359, 357, 357, 357, 356, 154, 160, 337, 338, 338, 339, 339, 355, 349, 341, 343, 346, 351, 337, 345, 346, 355, 345, 346, 352, 354, 339, 352, 342, 337, 346, 340, 349, 341, 345, 343, 353, 338, 353, 346, 347, 341, 340, 350, 352, 350, 352, 351, 349, 346, 341, 345, 348, 347, 339, 348, 350, 349, 346, 342, 338, 352, 343, 353, 339, 340, 346, 340, 355, 339, 337, 341, 348, 342, 351, 343, 354, 348, 353, 352, 344, 339, 351, 346, 344, 355, 345, 341, 339, 350, 340, 339, 161, 156, 360, 359, 357, 360, 360, 359, 360, 356, 358, 356, 359, 361, 145, 346, 347, 344, 348, 338, 349, 340, 340, 348, 338, 351, 354, 348, 351, 344, 349, 337, 351, 337, 348, 353, 352, 342, 349, 344, 340, 355, 354, 344, 354, 340, 346, 342, 353, 352, 345, 341, 352, 337, 337, 337, 353, 342, 345, 349, 340, 345, 350, 353, 349, 350, 351, 338, 347, 346, 348, 345, 342, 347, 341, 353, 340, 345, 355, 342, 354, 355, 338, 348, 351, 355, 354, 339, 354, 349, 355, 341, 338, 340, 341, 340, 349, 340, 342, 337, 374, 357, 358, 357, 357, 357, 356, 358, 361, 357, 358, 356, 360, 358, 137, 161, 160, 341, 353, 350, 337, 340, 347, 352, 340, 342, 354, 346, 350, 342, 354, 340, 346, 340, 338, 345, 350, 341, 347, 337, 349, 339, 352, 350, 345, 339, 346, 348, 337, 352, 346, 355, 347, 340, 337, 351, 353, 341, 353, 161, 385, 380, 386, 387, 385, 385, 384, 160, 340, 353, 343, 349, 337, 337, 343, 348, 341, 345, 355, 352, 348, 345, 339, 340, 338, 345, 337, 354, 353, 339, 346, 354, 342, 337, 353, 344, 346, 345, 341, 347, 377, 358, 358, 360, 356, 356, 361, 358, 358, 357, 360, 361, 360, 358, 137, 379, 144, 343, 344, 353, 340, 350, 343, 354, 338, 345, 348, 348, 343, 339, 355, 353, 338, 350, 338, 345, 347, 349, 349, 355, 347, 343, 344, 342, 355, 348, 345, 347, 350, 349, 344, 346, 350, 346, 347, 353, 355, 161, 388, 156, 358, 358, 357, 357, 361, 360, 360, 154, 385, 160, 350, 337, 339, 351, 343, 338, 337, 344, 340, 344, 355, 350, 351, 345, 354, 339, 344, 354, 355, 347, 349, 342, 346, 337, 342, 342, 338, 347, 354, 351, 372, 357, 356, 358, 361, 359, 356, 356, 359, 358, 357, 357, 361, 358, 154, 157, 144, 344, 350, 353, 342, 345, 341, 353, 340, 347, 348, 349, 348, 346, 348, 338, 342, 346, 345, 353, 350, 345, 353, 353, 345, 338, 343, 345, 353, 337, 348, 353, 355, 345, 346, 354, 354, 339, 340, 353, 348, 371, 360, 356, 356, 360, 360, 357, 361, 360, 357, 360, 358, 153, 160, 349, 344, 341, 347, 337, 339, 341, 352, 347, 354, 347, 349, 339, 343, 349, 350, 344, 342, 350, 349, 344, 342, 343, 341, 350, 345, 337, 346, 354, 374, 359, 356, 359, 358, 361, 358, 358, 357, 359, 360, 360, 356, 359, 361, 359, 144, 340, 350, 346, 342, 345, 352, 340, 352, 341, 353, 355, 343, 343, 345, 337, 354, 341, 348, 350, 337, 347, 355, 348, 345, 341, 346, 352, 351, 355, 352, 344, 352, 344, 354, 343, 348, 350, 354, 347, 161, 157, 357, 357, 359, 357, 356, 357, 358, 358, 359, 359, 357, 358, 153, 160, 340, 338, 339, 355, 348, 340, 347, 344, 350, 340, 353, 352, 341, 348, 343, 352, 339, 346, 337, 350, 350, 342, 347, 349, 339, 355, 343, 339, 374, 357, 359, 358, 357, 361, 357, 359, 356, 358, 358, 358, 358, 359, 357, 148, 158, 350, 342, 351, 339, 350, 340, 341, 355, 350, 340, 342, 347, 347, 347, 348, 355, 352, 338, 349, 339, 353, 340, 342, 338, 346, 338, 344, 355, 346, 344, 349, 340, 348, 351, 347, 344, 355, 347, 161, 155, 360, 360, 357, 359, 359, 360, 359, 359, 359, 361, 359, 360, 360, 357, 152, 160, 350, 347, 349, 337, 346, 351, 338, 352, 337, 339, 344, 355, 352, 342, 349, 339, 344, 346, 354, 355, 348, 345, 352, 342, 341, 343, 339, 378, 356, 361, 359, 359, 360, 361, 358, 356, 360, 358, 359, 356, 361, 357, 152, 380, 382, 386, 160, 339, 354, 348, 348, 338, 349, 342, 353, 348, 352, 351, 339, 355, 355, 354, 341, 338, 353, 355, 348, 337, 351, 353, 354, 340, 350, 343, 349, 354, 341, 346, 354, 352, 355, 161, 155, 361, 356, 356, 361, 360, 360, 358, 361, 357, 361, 359, 358, 358, 357, 356, 359, 137, 343, 342, 345, 343, 345, 337, 346, 351, 350, 350, 351, 352, 342, 349, 348, 347, 346, 345, 354, 344, 353, 353, 355, 352, 352, 354, 338, 377, 358, 360, 359, 359, 358, 360, 357, 360, 360, 358, 358, 358, 357, 357, 360, 356, 361, 146, 158, 340, 347, 347, 349, 351, 337, 344, 352, 339, 340, 340, 342, 345, 339, 343, 342, 339, 350, 341, 337, 346, 349, 347, 354, 353, 352, 352, 342, 345, 353, 344, 355, 348, 350, 377, 356, 359, 359, 358, 358, 356, 361, 357, 361, 361, 357, 357, 358, 360, 361, 359, 357, 152, 160, 347, 349, 343, 353, 344, 354, 351, 355, 348, 348, 352, 349, 346, 351, 348, 341, 354, 346, 337, 343, 342, 337, 352, 340, 349, 351, 373, 357, 356, 357, 357, 356, 358, 357, 357, 359, 358, 357, 360, 359, 361, 356, 361, 359, 140, 354, 351, 339, 339, 338, 351, 352, 348, 346, 348, 338, 340, 354, 344, 352, 341, 354, 341, 337, 339, 342, 343, 352, 340, 348, 346, 341, 344, 346, 338, 353, 337, 347, 346, 161, 157, 357, 360, 361, 360, 358, 357, 361, 356, 361, 358, 358, 358, 361, 358, 360, 356, 356, 356, 144, 347, 351, 338, 340, 343, 350, 355, 347, 347, 338, 353, 349, 349, 343, 161, 385, 384, 381, 380, 160, 352, 344, 340, 353, 343, 355, 376, 360, 357, 360, 360, 358, 359, 359, 360, 357, 358, 359, 359, 360, 356, 359, 361, 359, 137, 347, 349, 353, 345, 353, 338, 348, 340, 338, 342, 352, 345, 351, 340, 351, 339, 351, 349, 351, 346, 344, 341, 355, 341, 338, 349, 352, 348, 343, 344, 352, 347, 342, 161, 157, 358, 358, 356, 357, 361, 358, 356, 358, 357, 357, 356, 356, 358, 358, 358, 358, 357, 357, 356, 153, 160, 354, 341, 351, 353, 350, 341, 342, 338, 343, 351, 353, 346, 161, 157, 356, 358, 359, 356, 153, 385, 387, 380, 160, 355, 161, 156, 357, 358, 358, 357, 356, 356, 359, 356, 361, 357, 358, 358, 356, 359, 357, 356, 357, 152, 388, 160, 353, 351, 348, 337, 349, 349, 338, 345, 351, 341, 351, 352, 347, 337, 340, 349, 337, 348, 343, 352, 344, 344, 350, 355, 355, 337, 345, 343, 349, 346, 161, 157, 358, 359, 358, 359, 358, 356, 360, 358, 361, 359, 359, 356, 356, 361, 361, 358, 356, 357, 359, 360, 359, 143, 348, 351, 341, 355, 340, 349, 341, 348, 344, 355, 161, 382, 156, 356, 357, 357, 359, 361, 356, 359, 360, 361, 145, 353, 376, 356, 356, 360, 359, 356, 358, 361, 358, 356, 358, 360, 358, 357, 359, 356, 356, 360, 358, 359, 359, 152, 385, 388, 382, 382, 383, 160, 353, 343, 348, 346, 345, 337, 346, 354, 339, 352, 352, 339, 352, 347, 337, 338, 349, 342, 340, 354, 353, 355, 345, 341, 371, 357, 361, 358, 359, 356, 360, 357, 356, 359, 357, 357, 359, 360, 358, 357, 360, 360, 359, 357, 359, 360, 360, 143, 340, 338, 346, 338, 346, 340, 354, 351, 161, 384, 157, 360, 358, 356, 359, 359, 358, 356, 358, 358, 359, 358, 152, 380, 157, 357, 361, 361, 360, 356, 357, 358, 360, 357, 357, 361, 359, 358, 356, 361, 361, 360, 359, 361, 356, 360, 359, 358, 359, 356, 356, 152, 380, 160, 342, 353, 354, 345, 337, 341, 350, 341, 348, 346, 350, 352, 161, 160, 354, 348, 353, 352, 342, 349, 349, 345, 378, 357, 358, 359, 356, 360, 361, 359, 357, 359, 360, 360, 361, 360, 359, 356, 358, 359, 357, 360, 360, 357, 359, 139, 354, 337, 351, 343, 343, 161, 388, 385, 156, 357, 359, 361, 357, 358, 357, 359, 359, 359, 358, 358, 358, 359, 359, 357, 357, 360, 357, 360, 358, 359, 360, 357, 356, 359, 361, 357, 356, 357, 358, 357, 360, 360, 358, 360, 358, 360, 357, 361, 359, 359, 358, 361, 359, 154, 388, 382, 381, 383, 381, 387, 385, 384, 383, 384, 383, 388, 155, 153, 380, 383, 380, 386, 381, 383, 384, 384, 156, 357, 361, 356, 356, 360, 358, 360, 357, 359, 356, 360, 361, 357, 361, 361, 358, 356, 360, 360, 356, 359, 361, 152, 381, 383, 387, 386, 381, 156, 360, 358, 357, 361, 356, 361, 358, 359, 357, 361, 361, 360, 356, 360, 359, 359, 358, 357, 357, 360, 361, 359, 358, 359, 359, 358, 361, 360, 358, 359, 356, 359, 356, 360, 357, 356, 358, 357, 358, 358, 358, 356, 361, 357, 356, 358, 360, 359, 358, 358, 361, 361, 357, 359, 361, 361, 361, 356, 361, 360, 361, 359, 360, 356, 357, 358, 356, 359, 356, 359, 359, 356, 358, 360, 359, 359, 360, 356, 358, 358, 361, 360, 357, 360, 358, 361, 359, 360, 356, 357, 361, 358, 357, 356, 359, 360, 357, 361, 357, 361, 361, 359, 357, 360, 357, 358, 357, 360, 358, 360, 359, 359, 357, 358, 357, 358, 356, 360, 359, 356, 359, 356, 356, 357, 361, 361, 356, 356, 359, 361, 360, 359, 356, 361, 358, 358, 361, 361, 360, 359, 356, 360, 356, 356, 357, 361, 356, 357, 360, 358, 359, 356, 360, 360, 358, 359, 357, 358, 358, 359, 356, 358, 358, 358, 361, 358, 359, 360, 359, 359, 359, 356, 359, 359, 360, 356, 359, 357, 357, 357, 359, 358, 360, 360, 356, 357, 361, 356, 361, 356, 360, 359, 356, 356, 360, 357, 359, 360, 360, 359, 358, 360, 360, 359, 359, 360, 360, 361, 356, 356, 361, 361, 356, 359, 358, 361, 357, 361, 360, 360, 358, 359, 359, 358, 359, 358, 361, 360, 359, 357, 358, 356, 360, 356, 361, 359, 360, 360, 359, 360, 361, 356, 356, 356, 361, 359, 359, 356, 360, 358, 358, 360, 360, 356, 359, 358, 360, 358, 360, 359, 359, 357, 359, 360, 359, 360, 360, 356, 359, 359, 357, 361, 361, 358, 360, 357, 356, 360, 358, 356, 356, 361, 356, 359, 356, 356, 360, 356, 360, 359, 356, 357, 360, 360, 358, 361, 357, 360, 361, 361, 361, 360, 357, 357, 360, 357, 359, 359, 360, 361, 359, 357, 361, 360, 356, 356, 356, 361, 360, 356, 361, 359, 356, 359, 356, 358, 357, 358, 357, 358, 358, 360, 361, 359, 357, 360, 357, 361, 357, 356, 359, 357, 359, 359, 360, 359, 358, 358, 359, 361, 357, 357, 361, 358, 360, 359, 361, 360, 360, 356, 360, 357, 358, 359, 361, 359, 359, 356, 359, 361, 361, 356, 356, 360, 357, 356, 359, 361, 361, 359, 356, 356, 357, 360, 360, 360, 356, 361, 359, 358, 358, 357, 356, 359, 360, 360, 358, 356, 360, 357, 356, 360, 359, 361, 359, 358, 358, 360, 356, 359, 357, 358, 360, 357, 358, 356, 361, 361, 361, 360, 356, 361, 357, 358, 360, 356, 359, 361, 359, 356, 359, 361, 358, 357, 360, 356, 360, 356, 360, 356, 359, 356, 357, 357, 360, 356, 358, 358, 358, 357, 358, 358, 360, 359, 360, 359, 358, 359, 361, 361, 360, 359, 357, 358, 360, 357, 356, 359, 357, 356, 360, 356, 359, 359, 356, 357, 360, 359, 358, 357, 358, 359, 359, 358, 361, 361, 357, 357, 357, 361, 357, 361, 361, 358, 359, 357, 357, 359, 356, 356, 356, 360, 359, 360, 358, 358, 357, 356, 361, 360, 360, 356, 358, 359, 360, 361, 361, 361, 358, 356, 357, 356, 359, 361, 356, 359, 359, 360, 360, 357, 359, 356, 358, 359, 356, 360, 356, 356, 361, 359, 358, 361, 358, 360, 361, 357, 357, 359, 360, 356, 358, 356, 357, 358, 356, 361, 357, 356, 361, 358, 359, 360, 357, 360, 357, 357, 359, 360, 361, 361, 360, 359, 358, 357, 359, 356, 360, 358, 358, 358, 358, 360, 358, 359, 360, 360, 358, 361, 361, 359, 357, 358, 356, 357, 361, 357, 360, 361, 361, 359, 358, 359, 361, 360, 359, 358, 356, 360, 357, 357, 358, 357, 359, 360, 358, 360, 359, 361, 361, 361, 357, 357, 357, 359, 357, 357, 357, 360, 359, 357 ], 52 | "Collision": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] 53 | } 54 | -------------------------------------------------------------------------------- /resources/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.png" { 2 | const image: string; 3 | export default image; 4 | } 5 | 6 | declare module "*.json" { 7 | const resources: any; 8 | export default resources; 9 | } 10 | -------------------------------------------------------------------------------- /resources/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krtr/TibiaJS/79c82813930cf89a9a65b0d2a216789554c4add0/resources/sprites.png -------------------------------------------------------------------------------- /resources/tools/merge.bat: -------------------------------------------------------------------------------- 1 | montage -mode concatenate -tile 32x -background #ff00ff *.png out.png 2 | convert out.png -gravity north -extent 512x512 out.png 3 | convert out.png -transparent #ff00ff out.png 4 | -------------------------------------------------------------------------------- /server/GameState.ts: -------------------------------------------------------------------------------- 1 | import {CharacterList} from "./classes/CharacterList"; 2 | import {Ground} from "./classes/Ground"; 3 | import data from "../resources/data.json"; 4 | import {Config} from "../Interchange/DataStructures"; 5 | 6 | export const config: Config = data; 7 | export const characterList = new CharacterList(); 8 | export const ground = new Ground(); 9 | -------------------------------------------------------------------------------- /server/Geometry.ts: -------------------------------------------------------------------------------- 1 | import {Vector2D, Rotation} from "../Interchange/DataStructures"; 2 | 3 | export function GetDistance(p1: Vector2D, p2: Vector2D): number { 4 | var vx = p1.x - p2.x; 5 | var vy = p1.y - p2.y; 6 | 7 | return Math.sqrt((vx * vx) + (vy * vy)); 8 | } 9 | 10 | export function GetRotationFromV(v: Vector2D) { 11 | var radians = Math.atan2(v.y, v.x); 12 | var angle = (radians > 0 ? radians : (2 * Math.PI + radians)) * 360 / (2 * Math.PI); 13 | if (angle >= 315 || angle <= 45) { return Rotation.Left }; 14 | if (angle > 45 && angle < 135) { return Rotation.Top }; 15 | if (angle >= 135 && angle <= 225) { return Rotation.Right }; 16 | if (angle > 225 && angle < 315) { return Rotation.Down; } 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /server/OnConnect.ts: -------------------------------------------------------------------------------- 1 | import {Player} from "./classes/Player"; 2 | import {characterList} from "./GameState"; 3 | import {socketServer} from "./Server"; 4 | import {MoveData} from "../Interchange/DataStructures"; 5 | 6 | 7 | 8 | export function OnConnection(socket: SocketIO.Socket) { 9 | var plr = new Player(socket); 10 | plr.Sync(); 11 | socket.emit("NewCharacters", characterList.GetAllSyncData()); 12 | plr.SelfAnnouce(); 13 | 14 | socket.on("PlayerMove", function (data: MoveData) { 15 | plr.Move(data); 16 | }); 17 | 18 | socket.on("PlayerMessage", function (data: { Msg: string }) { 19 | console.log(data.Msg); 20 | socketServer.sockets.emit("CharacterMessage", { Msg: data.Msg, ID: socket.id }); 21 | }); 22 | 23 | socket.on("PlayerTarget", function (data: { ID; IsTargeting: boolean }) { 24 | var plr = characterList.GetByID(socket.id); 25 | 26 | if (plr) { 27 | if (data.IsTargeting) { 28 | var targetChar = characterList.GetByID(data.ID); 29 | if (!targetChar) return; 30 | plr.Target(targetChar); 31 | } else { 32 | plr.Untarget(); 33 | } 34 | 35 | } 36 | }); 37 | 38 | socket.on("disconnect", () => { 39 | var char = characterList.RemoveByID(socket.id); 40 | if (char) { 41 | char.Dispose(); 42 | console.log("DISPOSED", socket.id); 43 | } 44 | }); 45 | 46 | characterList.AddNewPlayer(plr); 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /server/PathFinding.ts: -------------------------------------------------------------------------------- 1 | import {ground} from "./GameState"; 2 | import {Vector2D} from "../Interchange/DataStructures"; 3 | 4 | 5 | export function AStar(start: Vector2D, goal: Vector2D) { 6 | function GetNeighbours(pos: Vector2D) { 7 | var result = []; 8 | if (!ground.GetCollision(pos.x - 1, pos.y)) result.push(visitedArray[pos.x - 1][pos.y]); 9 | if (!ground.GetCollision(pos.x + 1, pos.y)) result.push(visitedArray[pos.x + 1][pos.y]); 10 | if (!ground.GetCollision(pos.x, pos.y - 1)) result.push(visitedArray[pos.x][pos.y - 1]); 11 | if (!ground.GetCollision(pos.x, pos.y + 1)) result.push(visitedArray[pos.x][pos.y + 1]); 12 | 13 | return result; 14 | } 15 | 16 | function Heurestic(pos0, pos1) { 17 | var d1 = Math.abs(pos1.x - pos0.x); 18 | var d2 = Math.abs(pos1.y - pos0.y); 19 | return d1 + d2; 20 | } 21 | 22 | var visitedArray = new Array>(100); 23 | for (var i = 0; i < 100; i++) { 24 | visitedArray[i] = new Array<{ parent: any; visited: boolean; h: number; f: number; g: number; pos: Vector2D; }>(100); 25 | for (var j = 0; j < 100; j++) { 26 | visitedArray[i][j] = { parent: null, visited: false, f: 0, h: 0, g: 0, pos: { x: i, y: j } } 27 | } 28 | } 29 | 30 | var closedSet = new Array< { parent: any; visited: boolean; g: number; pos: Vector2D; }>(); 31 | visitedArray[start.x][start.y].h = Heurestic(start, goal); 32 | visitedArray[start.x][start.y].f = visitedArray[start.x][start.y].h; 33 | var openSet = [visitedArray[start.x][start.y]]; 34 | 35 | 36 | while (openSet.length !== 0) { 37 | 38 | var lowInd = 0; 39 | for (var i = 0; i < openSet.length; i++) { 40 | if (openSet[i].f < openSet[lowInd].f) { lowInd = i; } 41 | } 42 | 43 | 44 | var current = openSet[lowInd] 45 | 46 | 47 | if (current.h === 1) { 48 | var parent = current; 49 | var result = []; 50 | while (parent) { 51 | result.push(parent.pos); 52 | console.log(parent.pos); 53 | parent = parent.parent; 54 | } 55 | 56 | return result.reverse(); 57 | 58 | } 59 | 60 | openSet.splice(lowInd, 1); 61 | closedSet.push(current); 62 | 63 | var Neighbours = GetNeighbours(current.pos); 64 | 65 | for (var i = 0; i < Neighbours.length; i++) { 66 | 67 | if (!Neighbours[i].visited || current.g + 1 < Neighbours[i].g) { 68 | Neighbours[i].parent = current; 69 | Neighbours[i].g = current.g + 1; 70 | Neighbours[i].h = Heurestic(Neighbours[i].pos, goal); 71 | Neighbours[i].f = Neighbours[i].g + Neighbours[i].h; 72 | 73 | if (!Neighbours[i].visited) { 74 | openSet.push(Neighbours[i]); 75 | Neighbours[i].visited = true; 76 | 77 | } 78 | 79 | } 80 | 81 | 82 | 83 | } 84 | 85 | } 86 | 87 | 88 | return ["not found"]; 89 | } 90 | -------------------------------------------------------------------------------- /server/Server.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {OnConnection} from "./OnConnect"; 4 | import express from "express"; 5 | import socketio from "socket.io"; 6 | import serveStatic from "serve-static"; 7 | import * as ServerLoop from "./ServerLoop"; 8 | 9 | var app = express(); 10 | var server = app.listen(2137); 11 | 12 | 13 | export var socketServer = socketio(server); 14 | 15 | 16 | ServerLoop.Start(); 17 | app.use(serveStatic("./static", { index: ["index.html"] })); 18 | socketServer.on('connection', OnConnection); -------------------------------------------------------------------------------- /server/ServerLoop.ts: -------------------------------------------------------------------------------- 1 | import * as GameState from "./GameState"; 2 | import {Spawn} from "./classes/Spawn"; 3 | import {characterList} from "./GameState"; 4 | 5 | var intervalHandle: NodeJS.Timer; 6 | 7 | var spawnList = new Array(); 8 | 9 | export function Start() { 10 | intervalHandle = setInterval(NewLoop, 50); 11 | for (var i = 0; i < GameState.config.MobSpawns.length; i++) { 12 | spawnList.push(new Spawn(GameState.config.MobSpawns[i].Position.x, GameState.config.MobSpawns[i].Position.y)); 13 | spawnList[i].MaintainMobCount(GameState.config.MobSpawns[i].Count); 14 | } 15 | } 16 | 17 | export function Stop() { 18 | if (intervalHandle) clearInterval(intervalHandle); 19 | } 20 | 21 | function NewLoop() { 22 | characterList.ForEachPlayer((plr) => { 23 | plr.AttackTarget(); 24 | if (plr.IsDead()) { 25 | characterList.RemoveByID(plr.GetID()); 26 | } 27 | }); 28 | 29 | for (var i = 0; i < spawnList.length; i++) { 30 | spawnList[i].Process(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/classes/Character.ts: -------------------------------------------------------------------------------- 1 | import {config} from "../GameState"; 2 | import {MoveData, Rotation} from "../../Interchange/DataStructures"; 3 | 4 | export interface Character { 5 | Move(data: MoveData); 6 | MoveDir(rot: Rotation); 7 | GetJSON(); 8 | GetID(): string; 9 | Dispose(); 10 | SelfAnnouce(); 11 | Target(char: Character); 12 | Untarget(); 13 | GetHP(): number; 14 | Hit(dmg: number): { Exp: number }; 15 | Kill(); 16 | IsDead(): boolean 17 | CanMove(): boolean 18 | CanAttack(): boolean 19 | AttackTarget(); 20 | 21 | } 22 | 23 | 24 | 25 | export class CharacterDataToSync { 26 | Position = { x: 60, y: 50 }; 27 | Race: string; 28 | ID: string; 29 | HP: number; 30 | MaxHP: number; 31 | Speed: number; 32 | MaxExp: number; 33 | Level = 1; 34 | CurrentExp = 0; 35 | ExpAtDead = 0; 36 | 37 | toJSON() { 38 | return { 39 | Position: this.Position, Speed: this.Speed, HP: this.HP, MaxHP: this.MaxHP, 40 | Race: this.Race, ID: this.ID, MaxExp: this.MaxExp, Level: this.Level 41 | }; 42 | } 43 | 44 | constructor(race : string) { 45 | this.ID = CharacterDataToSync.lastID.toString(); 46 | this.Race = race; 47 | this.MaxExp = config.Player.LvlExp[this.Level]; 48 | this.Speed = config.Mobs[this.Race].Speed; 49 | this.ExpAtDead = config.Mobs[this.Race].Experience; 50 | CharacterDataToSync.lastID++; 51 | this.MaxHP = config.Mobs[this.Race].HP; 52 | this.HP = config.Mobs[this.Race].HP; 53 | } 54 | 55 | private static lastID = 0; 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /server/classes/CharacterList.ts: -------------------------------------------------------------------------------- 1 | import {Mob} from "./Mob"; 2 | import {Player} from "./Player"; 3 | import {Character, CharacterDataToSync} from "./Character"; 4 | 5 | export class CharacterList { 6 | private moblist = new Array(); 7 | private plrlist = new Array(); 8 | 9 | AddNewPlayer(plr: Player) { 10 | this.plrlist.push(plr); 11 | } 12 | 13 | AddNewMob(mob: Mob) { 14 | this.moblist.push(mob); 15 | } 16 | 17 | GetAllSyncData(): Array { 18 | var result = []; 19 | this.moblist.forEach((val) => { 20 | result.push(val.GetJSON()); 21 | }); 22 | 23 | this.plrlist.forEach((val) => { 24 | result.push(val.GetJSON()); 25 | }); 26 | return result; 27 | } 28 | 29 | ForEach(callback: (plr: Character) => void) { 30 | this.ForEachMob(callback); 31 | this.ForEachPlayer(callback); 32 | } 33 | 34 | ForEachMob(callback: (plr: Mob) => void) { 35 | for (var i = 0; i < this.moblist.length; i++) { 36 | callback(this.moblist[i]) 37 | } 38 | } 39 | 40 | ForEachPlayer(callback: (plr: Player) => void) { 41 | 42 | for (var i = 0; i < this.plrlist.length; i++) { 43 | callback(this.plrlist[i]) 44 | } 45 | } 46 | 47 | GetByID(ID: string): Character { 48 | for (var i = 0; i < this.moblist.length; i++) { 49 | if (this.moblist[i].GetID() === ID) { 50 | return this.moblist[i]; 51 | } 52 | } 53 | 54 | for (var i = 0; i < this.plrlist.length; i++) { 55 | if (this.plrlist[i].GetID() === ID) { 56 | return this.plrlist[i]; 57 | } 58 | } 59 | 60 | return null; 61 | } 62 | 63 | RemoveByID(ID: string): Character { 64 | var tmpChar; 65 | for (var i = 0; i < this.moblist.length; i++) { 66 | if (this.moblist[i].GetID() === ID) { 67 | tmpChar = this.moblist[i]; 68 | this.moblist.splice(i, 1); 69 | return tmpChar; 70 | } 71 | } 72 | 73 | for (var i = 0; i < this.plrlist.length; i++) { 74 | if (this.plrlist[i].GetID() === ID) { 75 | tmpChar = this.plrlist[i]; 76 | this.plrlist.splice(i, 1); 77 | return tmpChar; 78 | } 79 | } 80 | 81 | return null; 82 | } 83 | 84 | GetMobCount() { 85 | return this.moblist.length; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /server/classes/Ground.ts: -------------------------------------------------------------------------------- 1 | import * as GameState from "../GameState"; 2 | 3 | export class Ground { 4 | private width: number; 5 | private height: number; 6 | 7 | constructor() { 8 | this.width = GameState.config.MapWidth; 9 | this.height = GameState.config.MapHeight; 10 | } 11 | 12 | GetCollision(x: number, y: number) { 13 | if (x > this.width) return 1; 14 | if (x < 0) return 1; 15 | if (y > this.height) return 1; 16 | if (y < 0) return 1; 17 | return GameState.config.Collision[y * this.width + x]; 18 | } 19 | 20 | SetCollision(x: number, y: number) { 21 | GameState.config.Collision[y * this.width + x] = 1; 22 | } 23 | 24 | FreeCollision(x: number, y: number) { 25 | GameState.config.Collision[y * this.width + x] = 0; 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /server/classes/Mob.ts: -------------------------------------------------------------------------------- 1 | import "../../Interchange/DataStructures"; 2 | import {Character, CharacterDataToSync} from "./Character"; 3 | import {config, ground} from "../GameState"; 4 | import {socketServer} from "../Server"; 5 | import {GetDistance} from "../Geometry"; 6 | import {Vector2D, MoveData, Rotation} from "../../Interchange/DataStructures"; 7 | 8 | var startSprites = ["Orc", "Minotaur", "Troll", "Dwarf"]; 9 | 10 | 11 | 12 | 13 | export class Mob implements Character { 14 | private syncData = new CharacterDataToSync(startSprites[(Math.random() * 4) | 0]); 15 | private lastMoveTime = 0; 16 | private moveDelay = 35000 / this.syncData.Speed; 17 | private LastAttackTime = 0; 18 | private AttackDelay = 850; 19 | private targetChar: Character; 20 | // private IsDead = false; 21 | 22 | constructor(pos: Vector2D) { 23 | this.syncData.Position = pos; 24 | } 25 | 26 | Move(data: MoveData) { 27 | if (!this.CanMove()) return; 28 | ground.FreeCollision(this.syncData.Position.x, this.syncData.Position.y); 29 | this.syncData.Position.x = data.Pos.x; 30 | this.syncData.Position.y = data.Pos.y; 31 | ground.SetCollision(this.syncData.Position.x, this.syncData.Position.y); 32 | socketServer.emit("CharacterMove", { ID: this.syncData.ID, Data: data }); 33 | this.lastMoveTime = Date.now(); 34 | } 35 | 36 | MoveDir(rot: Rotation) { 37 | var tmpPos = { x: this.syncData.Position.x, y: this.syncData.Position.y }; 38 | if (rot === Rotation.Left) { 39 | tmpPos.x--; 40 | } 41 | if (rot === Rotation.Top) { 42 | tmpPos.y--; 43 | } 44 | if (rot === Rotation.Right) { 45 | tmpPos.x++; 46 | } 47 | if (rot === Rotation.Down) { 48 | tmpPos.y++; 49 | } 50 | 51 | var data = { Rot: rot, Pos: tmpPos }; 52 | this.Move(data); 53 | } 54 | 55 | GetJSON() { 56 | return this.syncData.toJSON(); 57 | } 58 | 59 | GetID(): string { 60 | return this.syncData.ID; 61 | } 62 | 63 | Dispose() { 64 | socketServer.emit("DeleteCharacters", [this.syncData.ID]); 65 | ground.FreeCollision(this.syncData.Position.x, this.syncData.Position.y); 66 | } 67 | 68 | SelfAnnouce() { 69 | socketServer.emit("NewCharacters", [this.GetJSON()]); 70 | ground.SetCollision(this.syncData.Position.x, this.syncData.Position.y); 71 | } 72 | 73 | Target(char: Character) { 74 | this.targetChar = char; 75 | } 76 | 77 | Untarget() { 78 | this.targetChar = null; 79 | } 80 | 81 | GetHP(): number { 82 | return this.syncData.HP; 83 | } 84 | 85 | AttackTarget() { 86 | if (!this.targetChar) return; 87 | if (this.targetChar.GetHP() < 0) { 88 | this.Untarget(); 89 | return; 90 | } 91 | if (!this.CanAttack()) return; 92 | var dist = GetDistance(this.syncData.Position, this.targetChar.GetJSON().Position); 93 | if (dist > 1.5) return; 94 | var dmg = Math.random() * 5 | 0 + 1; 95 | this.targetChar.Hit(dmg); 96 | 97 | this.LastAttackTime = Date.now(); 98 | } 99 | 100 | 101 | Hit(dmg: number): { Exp: number } { 102 | socketServer.sockets.emit("ApplyDommage", { AttackType: 0, TargetID: this.syncData.ID, HitPoints: dmg }); 103 | this.syncData.HP -= dmg; 104 | if (this.syncData.HP < 0) { 105 | this.Kill(); 106 | return { Exp: this.syncData.ExpAtDead }; 107 | } 108 | 109 | 110 | } 111 | 112 | Kill() { 113 | this.Dispose(); 114 | socketServer.sockets.emit("Animation", { Sprites: config.Mobs[this.GetJSON().Race].DeadSprites, Pos: this.syncData.Position, TicksPerFrame: 100 }); 115 | } 116 | 117 | IsDead() { 118 | return this.syncData.HP < 0; 119 | } 120 | 121 | MoveByVector(desiredMoveV: Vector2D) { 122 | if (!this.CanMove()) return; 123 | var dataArr = new Array(4); 124 | var radians = Math.atan2(desiredMoveV.y, desiredMoveV.x); 125 | dataArr[Rotation.Left] = ({ 126 | can: ground.GetCollision(this.syncData.Position.x - 1, this.syncData.Position.y), 127 | desire: Math.cos(radians) 128 | }); 129 | dataArr[Rotation.Down] = ({ 130 | can: ground.GetCollision(this.syncData.Position.x, this.syncData.Position.y + 1), 131 | desire: Math.cos(radians + (Math.PI / 2)) 132 | }); 133 | dataArr[Rotation.Right] = ({ 134 | can: ground.GetCollision(this.syncData.Position.x + 1, this.syncData.Position.y), 135 | desire: Math.cos(radians + Math.PI) 136 | }); 137 | dataArr[Rotation.Top] = ({ 138 | can: ground.GetCollision(this.syncData.Position.x, this.syncData.Position.y - 1), 139 | desire: Math.cos(radians + (Math.PI / 2 * 3)) 140 | }); 141 | 142 | var mostdesire = -1; 143 | var result = -1; 144 | for (var i = 0; i < 4; i++) { 145 | if (!dataArr[i].can && dataArr[i].desire > -0.1) { 146 | if (dataArr[i].desire > mostdesire) { 147 | result = i; 148 | mostdesire = dataArr[i].desire; 149 | } 150 | } 151 | } 152 | 153 | if (result !== -1) { 154 | this.MoveDir(result); 155 | } 156 | } 157 | 158 | IdleMoving() { 159 | if (!this.CanMove()) return; 160 | if (Math.random() > 0.95) { 161 | this.MoveByVector({ x: Math.sin(Math.random() * Math.PI * 2), y: Math.sin(Math.random() * Math.PI * 2) }); 162 | } 163 | } 164 | 165 | CanMove() { 166 | return ((Date.now() - this.lastMoveTime) > this.moveDelay) && !this.IsDead(); 167 | } 168 | 169 | CanAttack() { 170 | return ((Date.now() - this.LastAttackTime) > this.AttackDelay) && !this.IsDead(); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /server/classes/Player.ts: -------------------------------------------------------------------------------- 1 | import * as Character from "./Character"; 2 | import * as GameState from "../GameState"; 3 | import * as Geometry from "../Geometry"; 4 | import {ground} from "../GameState"; 5 | import {socketServer} from "../Server"; 6 | import {Rotation, MoveData} from "../../Interchange/DataStructures"; 7 | 8 | var startSprites = ["Orc", "Minotaur", "Troll", "Dwarf"]; 9 | 10 | export class Player implements Character.Character { 11 | private socket: SocketIO.Socket; 12 | private syncData = new Character.CharacterDataToSync(startSprites[(Math.random() * 4) | 0]); 13 | private targetChar: Character.Character; 14 | private AttackDelay = 850; 15 | private LastAttackTime = 0; 16 | 17 | constructor(socket: SocketIO.Socket) { 18 | this.syncData.Position = { x: 60, y: 50 }; 19 | this.syncData.ID = socket.id; 20 | this.socket = socket; 21 | } 22 | 23 | Move(data: MoveData) { 24 | if (ground.GetCollision(data.Pos.x, data.Pos.y)) { 25 | this.socket.emit("CharacterTeleport", { ID: this.syncData.ID, Data: { Rot: 0, Pos: this.syncData.Position } }); 26 | return; 27 | } 28 | ground.FreeCollision(this.syncData.Position.x, this.syncData.Position.y); 29 | this.syncData.Position.x = data.Pos.x; 30 | this.syncData.Position.y = data.Pos.y; 31 | ground.SetCollision(this.syncData.Position.x, this.syncData.Position.y); 32 | this.socket.broadcast.emit("CharacterMove", { ID: this.syncData.ID, Data: data }); 33 | } 34 | 35 | MoveDir(rot: Rotation) { 36 | var tmpPos = { x: this.syncData.Position.x, y: this.syncData.Position.y }; 37 | if (rot === Rotation.Left) { 38 | tmpPos.x--; 39 | } 40 | if (rot === Rotation.Top) { 41 | tmpPos.y--; 42 | } 43 | if (rot === Rotation.Right) { 44 | tmpPos.x++; 45 | } 46 | if (rot === Rotation.Down) { 47 | tmpPos.y++; 48 | } 49 | 50 | var data = { Rot: rot, Pos: tmpPos }; 51 | this.Move(data); 52 | } 53 | 54 | Sync() { 55 | this.socket.emit("PlayerStart", this.GetJSON()); 56 | } 57 | 58 | 59 | GetJSON() { 60 | return this.syncData.toJSON(); 61 | } 62 | 63 | GetID(): string { 64 | return this.syncData.ID; 65 | } 66 | 67 | Dispose() { 68 | socketServer.emit("DeleteCharacters", [this.syncData.ID]); 69 | ground.FreeCollision(this.syncData.Position.x, this.syncData.Position.y); 70 | // this.socket.disconnect(); 71 | 72 | } 73 | 74 | SelfAnnouce() { 75 | this.socket.broadcast.emit("NewCharacters", [this.GetJSON()]); 76 | ground.SetCollision(this.syncData.Position.x, this.syncData.Position.y); 77 | } 78 | 79 | Target(char: Character.Character) { 80 | 81 | this.targetChar = char; 82 | } 83 | 84 | Untarget() { 85 | 86 | this.targetChar = null; 87 | } 88 | 89 | AttackTarget() { 90 | 91 | if (!this.targetChar) return; 92 | if (this.targetChar.GetHP() < 0) { 93 | this.targetChar = null; return 94 | } 95 | if (!(Date.now() - this.LastAttackTime > this.AttackDelay)) return; 96 | var dist = Geometry.GetDistance(this.syncData.Position, this.targetChar.GetJSON().Position); 97 | if (dist > 6) return; 98 | 99 | socketServer.sockets.emit("SpawnProjectile", { Type: 0, StartPos: this.GetJSON().Position, TargetPos: this.targetChar.GetJSON().Position }); 100 | var dmg = Math.random() * this.syncData.Level * 6 | 0 + this.syncData.Level*2; 101 | var deadInfo = this.targetChar.Hit(dmg); 102 | if (deadInfo) { 103 | this.AddExp(deadInfo.Exp); 104 | } 105 | 106 | this.LastAttackTime = Date.now(); 107 | } 108 | 109 | GetHP(): number { 110 | return this.syncData.HP; 111 | } 112 | 113 | Hit(dmg: number): { Exp: number } { 114 | socketServer.sockets.emit("ApplyDommage", { AttackType: 0, TargetID: this.syncData.ID, HitPoints: dmg }); 115 | this.syncData.HP -= dmg; 116 | if (this.syncData.HP < 0) { 117 | this.Kill(); 118 | return { Exp: this.syncData.ExpAtDead * this.syncData.Level }; 119 | } 120 | } 121 | 122 | Kill() { 123 | this.syncData.HP = -1; 124 | this.Dispose(); 125 | socketServer.sockets.emit("Animation", { Sprites: GameState.config.Mobs[this.GetJSON().Race].DeadSprites, Pos: this.syncData.Position, TicksPerFrame: 500 }); 126 | } 127 | 128 | IsDead(): boolean { 129 | return this.syncData.HP < 0; 130 | } 131 | 132 | CanMove() { 133 | return true; 134 | } 135 | 136 | CanAttack() { 137 | return (Date.now() - this.LastAttackTime) > this.AttackDelay; 138 | } 139 | 140 | AddExp(exp: number) { 141 | this.syncData.CurrentExp += exp; 142 | if (this.syncData.CurrentExp > GameState.config.Player.LvlExp[this.syncData.Level]) { 143 | this.syncData.Level++; 144 | this.syncData.CurrentExp = 0; 145 | socketServer.sockets.emit("ApplyExperience", { ID: this.socket.id, Exp: exp, NextLvl: this.syncData.Level }); 146 | this.syncData.MaxHP += 35; 147 | this.syncData.HP = this.syncData.MaxHP; 148 | this.syncData.Speed += 20; 149 | this.Sync(); 150 | } 151 | else { 152 | socketServer.sockets.emit("ApplyExperience", { ID: this.socket.id, Exp: exp }); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /server/classes/Spawn.ts: -------------------------------------------------------------------------------- 1 | import {Mob} from "./Mob"; 2 | import {characterList, config} from "../GameState"; 3 | import {Player} from "./Player"; 4 | import {GetDistance} from "../Geometry"; 5 | import {Vector2D} from "../../Interchange/DataStructures"; 6 | 7 | 8 | export class Spawn { 9 | private mobList = new Array(); 10 | private pos: Vector2D; 11 | private desiredMobCount = 0; 12 | private newList = new Array(); 13 | 14 | constructor(posX: number, posY: number) { 15 | this.pos = {x: posX, y: posY}; 16 | } 17 | 18 | MaintainMobCount(count: number) { 19 | this.desiredMobCount = count; 20 | } 21 | 22 | Process() { 23 | if (this.mobList.length + this.newList.length < this.desiredMobCount) { 24 | this.newList.push(Date.now()); 25 | } 26 | 27 | if (this.newList.length > 0) { 28 | if ((this.newList[0] + config.MobSpawnDelay) < Date.now()) { 29 | this.addNew(); 30 | this.newList.splice(0, 1); 31 | } 32 | } 33 | 34 | for (var i = 0; i < this.mobList.length; i++) { 35 | if (this.mobList[i].IsDead()) { 36 | characterList.RemoveByID(this.mobList[i].GetID()); 37 | this.mobList.splice(i, 1); 38 | i--; 39 | continue; 40 | } 41 | 42 | var nearestPlr = this.getNearestPlayer(this.mobList[i]); 43 | if (!nearestPlr) return; 44 | var plrPos = nearestPlr.GetJSON().Position; 45 | var mobPos = this.mobList[i].GetJSON().Position; 46 | var dist = GetDistance(mobPos, plrPos); 47 | 48 | this.mobList[i].Target(nearestPlr); 49 | this.mobList[i].AttackTarget(); 50 | 51 | if (dist < 7 && dist > 1.5) { 52 | this.mobList[i].MoveByVector({x: mobPos.x - plrPos.x, y: mobPos.y - plrPos.y}); 53 | } 54 | if (dist >= 7) { 55 | this.mobList[i].IdleMoving(); 56 | } 57 | } 58 | } 59 | 60 | private addNew() { 61 | var char = new Mob({ 62 | x: ((Math.random() - 0.5) * 4 + this.pos.x) | 0, 63 | y: ((Math.random() - 0.5) * 4 + this.pos.y) | 0 64 | }); 65 | char.SelfAnnouce(); 66 | characterList.AddNewMob(char); 67 | this.mobList.push(char); 68 | } 69 | 70 | private getNearestPlayer(mob: Mob) { 71 | 72 | var lastDist = 1000000; 73 | var selectedPlayer: Player; 74 | characterList.ForEachPlayer((plr) => { 75 | var tmpDist = GetDistance(plr.GetJSON().Position, mob.GetJSON().Position) 76 | if (tmpDist < lastDist) { 77 | lastDist = tmpDist; 78 | selectedPlayer = plr; 79 | } 80 | }); 81 | 82 | return selectedPlayer; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ "**/*.ts" ], 4 | "compilerOptions": { 5 | "target": "es2015", 6 | "sourceMap": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /start.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const open = require("open"); 4 | const nodemon = require("nodemon"); 5 | 6 | nodemon({ 7 | cwd: "./out", 8 | ext: ".js, .css, .html", 9 | script: "Server.js", 10 | }).on("restart", () => console.log("Restarted")); 11 | 12 | open("http://localhost:2137"); 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ "es2015" ], 4 | 5 | // Module configuration. 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true, 8 | "module": "esnext", 9 | "moduleResolution": "node" 10 | } 11 | } 12 | --------------------------------------------------------------------------------