[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: egordorichev\ncustom: https://paypal.me/egordorichev\n"
  },
  {
    "path": ".github/workflows/deploy-steam.yml",
    "content": "name: Build BurningKnight\non:\n  push:\n    branches:\n      - release\n      - dev\njobs:\n  build:\n    name: Build BurningKnight\n    runs-on: windows-2019\n    steps:\n      - name: Download MonoGame\n        shell: powershell\n        run: |\n          dotnet --info\n          dotnet tool install -g dotnet-mgcb\n      #    wget -O MonoGameSetup.exe https://github.com/MonoGame/MonoGame/releases/download/v3.7/MonoGameSetup.exe\n      #- name: Install MonoGame\n      #  shell: cmd\n      #  run: |\n      #    MonoGameSetup.exe /S\n      - name: Checkout\n        uses: actions/checkout@v1\n      - name: Install NuGet\n        shell: powershell\n        run: |\n          wget -O nuget.exe  https://dist.nuget.org/win-x86-commandline/latest/nuget.exe\n      - name: Install NuGet packages\n        shell: bash\n        run: |\n          ls -l\n          mkdir packages\n          cd packages\n          ../nuget.exe install ../Lens/packages.config\n          ../nuget.exe install ../Aseprite/packages.config\n          ../nuget.exe install ../BurningKnight/packages.config\n          ../nuget.exe install ../Desktop/packages.config\n          ../nuget.exe install ../MonoGamePico8/packages.config\n          ../nuget.exe install ../Pico8Emulator/packages.config\n          ls -l\n          cd ..\n          echo $GITHUB_WORKSPACE\n          ./nuget.exe restore ./VelcroPhysics/packages.config -SolutionDirectory $GITHUB_WORKSPACE\n          dotnet restore\n      - name: Building Aseprite Extention\n        shell: bash\n        run: |\n          cd $GITHUB_WORKSPACE\n          ls -l\n          \"C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/MSBuild.exe\" ./Aseprite/Aseprite.csproj\n          ls -l\n      - name: Building Resources\n        shell: bash\n        run: |\n          cd $GITHUB_WORKSPACE/BurningKnight/Content/\n          mgcb \"Content.mgcb\" /platform:DesktopGL\n          ls -l\n      - name: Building Solution\n        shell: bash\n        run: |\n          cd $GITHUB_WORKSPACE\n          \"C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/MSBuild.exe\" ./Lens.sln /property:Configuration=Release\n          cd $GITHUB_WORKSPACE/Desktop/bin/Release\n          git init\n          git config --local user.email \"action@github.com\"\n          git config --local user.name \"GitHub Action\"\n          git add *\n          git commit -m \"Added changes\"\n          cd $GITHUB_WORKSPACE\n      - name: Push Build to egordorichev/bk_builds\n        uses: ad-m/github-push-action@master\n        with:\n          github_token: ${{ secrets.GITHUB_KEY }}\n          force: true\n          repository: \"egordorichev/bk_builds\"\n          directory: \"./Desktop/bin/Release/\" \n          branch: \"master\" \n#      - name: Upload Windows Version to Itch\n#        shell: powershell\n#        env:\n#          BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }}\n#        run: |\n#          ./butler.exe push ./Windows/ egordorichev/bkt:windows\n#      - name: Prepare Linux Version\n#        shell: bash\n#        run: |\n#          mkdir ./Linux\n#          cp -rf ./Windows/* ./Linux/\n#          git clone https://github.com/egordorichev/bk_linux_kick\n#          cp -rf ./bk_linux_kick/* ./Linux/\n#          cd ./Linux\n#          ls\n#          cd ..\n#          \n#      - name: Upload Linux Version to Itch\n#        shell: powershell\n#        env:\n#          BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }}\n#        run: |\n#          ./butler.exe push ./Linux/ egordorichev/bkt:linux\n#          \n#      - name: Upload windows build to linux\n#        uses: actions/upload-artifact@v1\n#        with:\n#          name: Windows\n#          path: Windows\n#          \n#      - name: Upload linux build to linux\n#        uses: actions/upload-artifact@v1\n#        with:\n#          name: Linux\n#          path: Linux\n#        \n#  upload:\n#    needs: build\n#    name: Push BurningKnight to Steam\n#    runs-on: ubuntu-18.04\n#    steps:\n#      - name: Download windows\n#        uses: actions/download-artifact@v1\n#        with:\n#          name: Windows\n#      - name: Download linux\n#        uses: actions/download-artifact@v1\n#        with:\n#          name: Linux\n#      - name: Upload depots to steam\n#        shell: bash\n#        run: |\n#           git clone \"https://${{ secrets.GITHUB_KEY }}@github.com/egordorichev/steam_builder.git\"\n#           mkdir ~/.steam/steam/ -p\n#           cp ./steam_builder/ssfn2631791037380626867 ~/.steam/steam/\n#           ls -l ~/.steam/steam\n#           mkdir -p ./steam_builder/tools/ContentBuilder/builder/public/\n#           cp ./steam_builder/steambootstrapper_english.txt ./steam_builder/tools/ContentBuilder/builder/public/\n#           ls -l ./steam_builder/tools/ContentBuilder/builder/public/\n#           cd steam_builder/tools/ContentBuilder\n#           mkdir ./content/Windows\n#           cp ../../../Windows/* ./content/Windows/ -r\n#           ls -l ./content/Windows/\n#           mkdir ./content/Linux\n#           cp ../../../Linux/* ./content/Linux/ -r\n#           ls -l ./content/Linux/\n#           chmod a+x builder_linux/steamcmd.sh\n#           chmod a+x builder_linux/linux32/steamcmd\n#           builder_linux/steamcmd.sh +login \"${{ secrets.STEAM_USERNAME }}\" \"${{ secrets.STEAM_PASSWORD }}\" +run_app_build ../scripts/app_build_851150.vdf +quit\n"
  },
  {
    "path": ".gitignore",
    "content": "*.idea/*\n.git\n*/bin/*\n*/obj/*\nBurningKnight/Content/bin/Sfx\nBurningKnight/Content/bin/Music\nBurningKnight/Content/obj*\nBurningKnight/Content/obj/**\npackages/*\nBurningKnight/achievement_sprites*\n*.exe\n*.pdb\n*.dll\n*SharpDx.*\n*mgfxc.*\nSharpDX.xml\nSharpDX.D3DCompiler.xml\n"
  },
  {
    "path": "Aseprite/Aseprite.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x64</Platform>\n    <ProjectGuid>{13C6F252-0B3C-4A22-A9DB-270C76657FAB}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Aseprite</RootNamespace>\n    <AssemblyName>Aseprite</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <RuntimeIdentifier>win-x64</RuntimeIdentifier>\n    <FileAlignment>512</FileAlignment>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"MonoGame.Framework, Version=3.7.1.189, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.Portable.3.7.1.189\\lib\\portable-net45+win8+wpa81\\MonoGame.Framework.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework.Content.Pipeline, Version=3.7.1.189, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.Content.Pipeline.Portable.3.7.1.189\\lib\\portable-net45+win8+wpa81\\MonoGame.Framework.Content.Pipeline.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\" />\n    <Reference Include=\"NVorbis, Version=0.8.6.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\NVorbis.0.8.6\\lib\\net35\\NVorbis.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"NVorbis.OpenTKSupport, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\NVorbis.OpenTKSupport.1.2.0\\lib\\net35\\NVorbis.OpenTKSupport.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"OpenTK, Version=3.0.1.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4\">\n      <HintPath>..\\packages\\OpenTK.3.0.1\\lib\\net20\\OpenTK.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"AsepriteAnimation.cs\" />\n    <Compile Include=\"AsepriteFile.cs\" />\n    <Compile Include=\"AsepriteImporter.cs\" />\n    <Compile Include=\"AsepriteProcessor.cs\" />\n    <Compile Include=\"AsepriteReader.cs\" />\n    <Compile Include=\"AsepriteWriter.cs\" />\n    <Compile Include=\"AudioFile.cs\" />\n    <Compile Include=\"AudioImporter.cs\" />\n    <Compile Include=\"AudioProcessor.cs\" />\n    <Compile Include=\"AudioReader.cs\" />\n    <Compile Include=\"AudioWriter.cs\" />\n    <Compile Include=\"Calc.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"README.md\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n         Other similar extension points exist, see Microsoft.Common.targets.\n    <Target Name=\"BeforeBuild\">\n    </Target>\n    <Target Name=\"AfterBuild\">\n    </Target>\n    -->\n</Project>\n"
  },
  {
    "path": "Aseprite/AsepriteAnimation.cs",
    "content": "﻿namespace Aseprite {\n\tpublic class AsepriteAnimation {\n\t\tpublic int FirstFrame;\n\t\tpublic int LastFrame;\n\t\tpublic string Name;\n\t\tpublic AsepriteTag.LoopDirections Directions;\n\t}\n}"
  },
  {
    "path": "Aseprite/AsepriteFile.cs",
    "content": "﻿using System.Collections.Generic;\nusing System;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Text;\nusing System.Linq;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Content.Pipeline;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Aseprite {\n\tpublic enum Modes {\n\t\tIndexed = 1,\n\t\tGrayscale = 2,\n\t\tRGBA = 4\n\t}\n\n\tpublic class AsepriteFile {\n\t\tpublic Modes Mode;\n\t\tpublic int Width;\n\t\tpublic int Height;\n\n\t\tpublic List<AsepriteFrame> Frames = new List<AsepriteFrame>();\n\t\tpublic List<AsepriteLayer> Layers = new List<AsepriteLayer>();\n\t\tpublic List<AsepriteTag> Tags = new List<AsepriteTag>();\n\t\tpublic List<AsepriteSlice> Slices = new List<AsepriteSlice>();\n\t\tpublic Dictionary<string, AsepriteAnimation> Animations = new Dictionary<string, AsepriteAnimation>();\n\n\t\tpublic Texture2D Texture;\n\n\t\tprivate enum Chunks {\n\t\t\tOldPaletteA = 0x0004,\n\t\t\tOldPaletteB = 0x0011,\n\t\t\tLayer = 0x2004,\n\t\t\tCel = 0x2005,\n\t\t\tCelExtra = 0x2006,\n\t\t\tMask = 0x2016,\n\t\t\tPath = 0x2017,\n\t\t\tFrameTags = 0x2018,\n\t\t\tPalette = 0x2019,\n\t\t\tUserData = 0x2020,\n\t\t\tSlice = 0x2022\n\t\t}\n\n\t\tprivate enum CelTypes {\n\t\t\tRawCel = 0,\n\t\t\tLinkedCel = 1,\n\t\t\tCompressedImage = 2\n\t\t}\n\n\t\tpublic AsepriteFile() {\n\t\t\t\n\t\t}\n\n\t\tpublic AsepriteFile(string filename) : this(filename, null) {\n\t\t\tint framesCount = Frames.Count;\n\t\t\tint layersCount = Layers.Count;\n\t\t\t\t\n\t\t\tint textureWidth = framesCount * Width;\n\t\t\tint textureHeight = layersCount * Height;\n\t\t\tint width = Width;\n\t\t\tint height = Height;\n\t\t\tint size = textureWidth * (textureHeight + 1);\n\n\t\t\tvar pixelData = new Color[size];\n\t\t\t\n\t\t\tfor (int f = 0; f < framesCount; f++) {\n\t\t\t\tvar frame = Frames[f];\n\n\t\t\t\tfor (int i = 0; i < frame.Cels.Count; i++) {\n\t\t\t\t\tvar cel = frame.Cels[i];\n\n\t\t\t\t\tvar celWidth = cel.Width;\n\t\t\t\t\tvar celHeight = cel.Height;\n\t\t\t\t\tvar addX = cel.X;\n\t\t\t\t\tvar addY = cel.Y;\n\t\t\t\t\t\n\t\t\t\t\tfor (int celY = 0; celY < celHeight; celY++) {\n\t\t\t\t\t\tfor (int celX = 0; celX < celWidth; celX++) {\n\t\t\t\t\t\t\tint ind = celX + celY * cel.Width;\n\t\t\t\t\t\t\tvar pixel = cel.Pixels[ind];\n\n\t\t\t\t\t\t\tpixelData[(f * width) + celX + addX + ((i * height) + celY + addY) * textureWidth] = pixel;\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tTexture = new Texture2D(AsepriteReader.GraphicsDevice, textureWidth, textureHeight + 1);\n\t\t\tTexture.SetData(pixelData);\n\t\t}\n\n\t\tpublic AsepriteFile(string filename, ContentBuildLogger logger) {\t\t\t\n\t\t\tusing (var stream = File.OpenRead(filename)) {\n\t\t\t\tvar reader = new BinaryReader(stream);\n\n\t\t\t\t#region File helpers\n\n\t\t\t\t// Helpers for translating the Aseprite file format reference\n\t\t\t\t// See: https://github.com/aseprite/aseprite/blob/master/docs/ase-file-specs.md\n\t\t\t\tbyte BYTE() {\n\t\t\t\t\treturn reader.ReadByte();\n\t\t\t\t}\n\n\t\t\t\tushort WORD() {\n\t\t\t\t\treturn reader.ReadUInt16();\n\t\t\t\t}\n\n\t\t\t\tshort SHORT() {\n\t\t\t\t\treturn reader.ReadInt16();\n\t\t\t\t}\n\n\t\t\t\tuint DWORD() {\n\t\t\t\t\treturn reader.ReadUInt32();\n\t\t\t\t}\n\n\t\t\t\tlong LONG() {\n\t\t\t\t\treturn reader.ReadInt32();\n\t\t\t\t}\n\n\t\t\t\tstring STRING() {\n\t\t\t\t\treturn Encoding.UTF8.GetString(BYTES(WORD()));\n\t\t\t\t}\n\n\t\t\t\tbyte[] BYTES(int number) {\n\t\t\t\t\treturn reader.ReadBytes(number);\n\t\t\t\t}\n\n\t\t\t\tvoid SEEK(int number) {\n\t\t\t\t\treader.BaseStream.Position += number;\n\t\t\t\t}\n\n\t\t\t\t#endregion\n\n\t\t\t\t#region Consume header\n\n\t\t\t\tint frameCount;\n\n\t\t\t\t{\n\t\t\t\t\tDWORD();\n\n\t\t\t\t\t// Magic number\n\t\t\t\t\tvar magic = WORD();\n\n\t\t\t\t\tif (magic != 0xA5e0) {\n\t\t\t\t\t\tthrow new Exception(\"File doesn't appear to be from Aseprite.\");\n\t\t\t\t\t}\n\n\t\t\t\t\t// Basic info\n\t\t\t\t\tframeCount = WORD();\n\n\t\t\t\t\tWidth = WORD();\n\t\t\t\t\tHeight = WORD();\n\n\t\t\t\t\tMode = (Modes) (WORD() / 8);\n\n\t\t\t\t\tlogger?.LogMessage($\"Cels are {Width}x{Height}, mode is {Mode}\");\n\n\t\t\t\t\t// Ignore a bunch of stuff\n\t\t\t\t\tDWORD(); // Flags\n\t\t\t\t\tWORD(); // Speed (deprecated)\n\t\t\t\t\tDWORD(); // 0\n\t\t\t\t\tDWORD(); // 0\n\t\t\t\t\tBYTE(); // Palette entry \n\t\t\t\t\tSEEK(3); // Ignore these bytes\n\t\t\t\t\tWORD(); // Number of colors (0 means 256 for old sprites)\n\t\t\t\t\tBYTE(); // Pixel width\n\t\t\t\t\tBYTE(); // Pixel height\n\t\t\t\t\tSEEK(92); // For Future\n\t\t\t\t}\n\n\t\t\t\t#endregion\n\n\t\t\t\t#region Actual data\n\n\t\t\t\t// Some temporary holders\n\t\t\t\tvar colorBuffer = new byte[Width * Height * (int) Mode];\n\t\t\t\tvar palette = new Color[256];\n\n\t\t\t\tIUserData lastUserData = null;\n\n\t\t\t\tfor (int i = 0; i < frameCount; i++) {\n\t\t\t\t\tvar frame = new AsepriteFrame();\n\t\t\t\t\tFrames.Add(frame);\n\n\t\t\t\t\tlong frameStart;\n\t\t\t\t\tlong frameEnd;\n\t\t\t\t\tint chunkCount;\n\n\t\t\t\t\t// Frame header\n\t\t\t\t\t{\n\t\t\t\t\t\tframeStart = reader.BaseStream.Position;\n\t\t\t\t\t\tframeEnd = frameStart + DWORD();\n\t\t\t\t\t\tWORD(); // Magic number (always 0xF1FA)\n\n\t\t\t\t\t\tchunkCount = WORD();\n\t\t\t\t\t\tframe.Duration = WORD() / 1000f;\n\t\t\t\t\t\tSEEK(6); // For future (set to zero)\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (int j = 0; j < chunkCount; j++) {\n\t\t\t\t\t\tlong chunkStart;\n\t\t\t\t\t\tlong chunkEnd;\n\t\t\t\t\t\tChunks chunkType;\n\n\t\t\t\t\t\t// Chunk header\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchunkStart = reader.BaseStream.Position;\n\t\t\t\t\t\t\tchunkEnd = chunkStart + DWORD();\n\t\t\t\t\t\t\tchunkType = (Chunks) WORD();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Layer\n\t\t\t\t\t\tif (chunkType == Chunks.Layer) {\n\t\t\t\t\t\t\tvar layer = new AsepriteLayer();\n\t\t\t\t\t\t\tlayer.Flag = (AsepriteLayer.Flags) WORD();\n\t\t\t\t\t\t\tlayer.Type = (AsepriteLayer.Types) WORD();\n\t\t\t\t\t\t\tlayer.ChildLevel = WORD();\n\n\t\t\t\t\t\t\tWORD(); // width\n\t\t\t\t\t\t\tWORD(); // height\n\n\t\t\t\t\t\t\tlayer.BlendMode = (AsepriteLayer.BlendModes) WORD();\n\t\t\t\t\t\t\tlayer.Opacity = BYTE() / 255f;\n\t\t\t\t\t\t\tSEEK(3);\n\t\t\t\t\t\t\tlayer.Name = STRING();\n\n\t\t\t\t\t\t\tlastUserData = layer;\n\t\t\t\t\t\t\tLayers.Add(layer);\n\t\t\t\t\t\t}\telse if (chunkType == Chunks.Cel) {\n\t\t\t\t\t\t\t// Cell\n\t\t\t\t\t\t\tvar cel = new AsepriteCel();\n\n\t\t\t\t\t\t\tvar layerIndex = WORD();\n\t\t\t\t\t\t\tcel.Layer = Layers[layerIndex]; // Layer is row (Frame is column)\n\t\t\t\t\t\t\tcel.X = SHORT();\n\t\t\t\t\t\t\tcel.Y = SHORT();\n\t\t\t\t\t\t\tcel.Opacity = BYTE() / 255f;\n\n\t\t\t\t\t\t\tvar celType = (CelTypes) WORD();\n\t\t\t\t\t\t\tSEEK(7);\n\n\t\t\t\t\t\t\tif (celType == CelTypes.RawCel || celType == CelTypes.CompressedImage) {\n\t\t\t\t\t\t\t\tcel.Width = WORD();\n\t\t\t\t\t\t\t\tcel.Height = WORD();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tvar byteCount = cel.Width * cel.Height * (int) Mode;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (celType == CelTypes.RawCel) {\n\t\t\t\t\t\t\t\t\treader.Read(colorBuffer, 0, byteCount);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tSEEK(2);\n\t\t\t\t\t\t\t\t\tvar deflate = new DeflateStream(reader.BaseStream, CompressionMode.Decompress);\n\n\t\t\t\t\t\t\t\t\t\tdeflate.Read(colorBuffer, 0, byteCount);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcel.Pixels = new Color[cel.Width * cel.Height];\n\t\t\t\t\t\t\t\tConvertBytesToPixels(colorBuffer, cel.Pixels, palette);\n\t\t\t\t\t\t\t} else if (celType == CelTypes.LinkedCel) {\n\t\t\t\t\t\t\t\tvar targetFrame = WORD(); // Frame position to link with\n\n\t\t\t\t\t\t\t\t// Grab the cel from a previous frame\n\t\t\t\t\t\t\t\tvar targetCel = Frames[targetFrame].Cels.Where(c => c.Layer == Layers[layerIndex]).First();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcel.Width = targetCel.Width;\n\t\t\t\t\t\t\t\tcel.Height = targetCel.Height;\n\t\t\t\t\t\t\t\tcel.Pixels = targetCel.Pixels;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlastUserData = cel;\n\t\t\t\t\t\t\tframe.Cels.Add(cel);\n\t\t\t\t\t\t} else if (chunkType == Chunks.Palette) {\n\t\t\t\t\t\t\t// Palette\n\n\t\t\t\t\t\t\tvar size = DWORD();\n\t\t\t\t\t\t\tvar start = DWORD();\n\t\t\t\t\t\t\tvar end = DWORD();\n\t\t\t\t\t\t\tSEEK(8);\n\n\t\t\t\t\t\t\tfor (int c = 0; c < (end - start) + 1; c++) {\n\t\t\t\t\t\t\t\tvar hasName = Calc.IsBitSet(WORD(), 0);\n\t\t\t\t\t\t\t\tpalette[start + c] = new Color(BYTE(), BYTE(), BYTE(), BYTE());\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (hasName) {\n\t\t\t\t\t\t\t\t\tSTRING(); // Color name\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (chunkType == Chunks.UserData) {\n\t\t\t\t\t\t\t// User data\n\n\t\t\t\t\t\t\tif (lastUserData != null) {\n\t\t\t\t\t\t\t\tvar flags = DWORD();\n\n\t\t\t\t\t\t\t\tif (Calc.IsBitSet(flags, 0)) {\n\t\t\t\t\t\t\t\t\tlastUserData.UserDataText = STRING();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (Calc.IsBitSet(flags, 1)) {\n\t\t\t\t\t\t\t\t\tlastUserData.UserDataColor = new Color(BYTE(), BYTE(), BYTE(), BYTE());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (chunkType == Chunks.FrameTags) {\n\t\t\t\t\t\t\t// Tag (animation reference)\n\n\t\t\t\t\t\t\tvar tagsCount = WORD();\n\t\t\t\t\t\t\tSEEK(8);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int t = 0; t < tagsCount; t++) {\n\t\t\t\t\t\t\t\tvar tag = new AsepriteTag();\n\n\t\t\t\t\t\t\t\ttag.From = WORD();\n\t\t\t\t\t\t\t\ttag.To = WORD();\n\t\t\t\t\t\t\t\ttag.LoopDirection = (AsepriteTag.LoopDirections) BYTE();\n\t\t\t\t\t\t\t\tSEEK(8);\n\t\t\t\t\t\t\t\ttag.Color = new Color(BYTE(), BYTE(), BYTE(), (byte) 255);\n\t\t\t\t\t\t\t\tSEEK(1);\n\t\t\t\t\t\t\t\ttag.Name = STRING();\n\n\t\t\t\t\t\t\t\tTags.Add(tag);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (chunkType == Chunks.Slice) {\n\t\t\t\t\t\t\t// Slice\n\n\t\t\t\t\t\t\tvar slicesCount = DWORD();\n\t\t\t\t\t\t\tvar flags = DWORD();\n\t\t\t\t\t\t\tDWORD();\n\t\t\t\t\t\t\tvar name = STRING();\n\n\t\t\t\t\t\t\tfor (int s = 0; s < slicesCount; s++) {\n\t\t\t\t\t\t\t\tvar slice = new AsepriteSlice();\n\t\t\t\t\t\t\t\tslice.Name = name;\n\t\t\t\t\t\t\t\tslice.Frame = (int) DWORD();\n\t\t\t\t\t\t\t\tslice.OriginX = (int) LONG();\n\t\t\t\t\t\t\t\tslice.OriginY = (int) LONG();\n\t\t\t\t\t\t\t\tslice.Width = (int) DWORD();\n\t\t\t\t\t\t\t\tslice.Height = (int) DWORD();\n\n\t\t\t\t\t\t\t\t// 9 slice\n\t\t\t\t\t\t\t\tif (Calc.IsBitSet(flags, 0)) {\n\t\t\t\t\t\t\t\t\tLONG(); // Center X position (relative to slice bounds)\n\t\t\t\t\t\t\t\t\tLONG(); // Center Y position\n\t\t\t\t\t\t\t\t\tDWORD(); // Center width\n\t\t\t\t\t\t\t\t\tDWORD(); // Center height\n\t\t\t\t\t\t\t\t}\telse if (Calc.IsBitSet(flags, 1)) {\n\t\t\t\t\t\t\t\t\t// Pivot\n\n\t\t\t\t\t\t\t\t\tslice.Pivot = new Point((int) DWORD(), (int) DWORD());\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tlastUserData = slice;\n\t\t\t\t\t\t\t\tSlices.Add(slice);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treader.BaseStream.Position = chunkEnd;\n\t\t\t\t\t}\n\n\t\t\t\t\treader.BaseStream.Position = frameEnd;\n\t\t\t\t}\n\n\t\t\t\t#endregion\n\t\t\t}\n\n\t\t\tif (logger == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t// Log out what we found\n\t\t\tlogger.LogMessage(\"Layers:\");\n\t\t\t\n\t\t\tforeach (var layer in Layers) {\n\t\t\t\tlogger.LogMessage($\"\\t{layer.Name}\");\n\t\t\t}\n\n\t\t\tlogger.LogMessage(\"Animations:\");\n\t\t\t\n\t\t\tforeach (var animation in Tags) {\n\t\t\t\tif (animation.To == animation.From) {\n\t\t\t\t\tlogger.LogMessage($\"\\t{animation.Name} => {animation.From + 1}\");\n\t\t\t\t} else {\n\t\t\t\t\tlogger.LogMessage($\"\\t{animation.Name} => {animation.From + 1} - {animation.To + 1}\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void ConvertBytesToPixels(byte[] bytes, Color[] pixels, Color[] palette) {\n\t\t\tint length = pixels.Length;\n\n\t\t\tif (Mode == Modes.RGBA) {\n\t\t\t\tfor (int pixel = 0, b = 0; pixel < length; pixel++, b += 4) {\n\t\t\t\t\tpixels[pixel].R = (byte) (bytes[b + 0] * bytes[b + 3] / 255);\n\t\t\t\t\tpixels[pixel].G = (byte) (bytes[b + 1] * bytes[b + 3] / 255);\n\t\t\t\t\tpixels[pixel].B = (byte) (bytes[b + 2] * bytes[b + 3] / 255);\n\t\t\t\t\tpixels[pixel].A = bytes[b + 3];\n\t\t\t\t}\n\t\t\t} else if (Mode == Modes.Grayscale) {\n\t\t\t\tfor (int pixel = 0, b = 0; pixel < length; pixel++, b += 2) {\n\t\t\t\t\tpixels[pixel].R = pixels[pixel].G = pixels[pixel].B = (byte) (bytes[b + 0] * bytes[b + 1] / 255);\n\t\t\t\t\tpixels[pixel].A = bytes[b + 1];\n\t\t\t\t}\n\t\t\t} else if (Mode == Modes.Indexed) {\n\t\t\t\tfor (int pixel = 0; pixel < length; pixel++) {\n\t\t\t\t\tint index = bytes[pixel];\n\n\t\t\t\t\tif (index > 0) {\n\t\t\t\t\t\tpixels[pixel] = palette[index];\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// UserData are extended chunks that get attached\n\t// to other chunks\n\tpublic interface IUserData {\n\t\tstring UserDataText { get; set; }\n\t\tColor UserDataColor { get; set; }\n\t}\n\n\t// A layer stores just the meta info for a row of cels\n\tpublic class AsepriteLayer : IUserData {\n\t\t[Flags]\n\t\tpublic enum Flags {\n\t\t\tVisible = 1,\n\t\t\tEditable = 2,\n\t\t\tLockMovement = 4,\n\t\t\tBackground = 8,\n\t\t\tPreferLinkedCels = 16,\n\t\t\tCollapsed = 32,\n\t\t\tReference = 64\n\t\t}\n\n\t\tpublic enum Types {\n\t\t\tNormal = 0,\n\t\t\tGroup = 1\n\t\t}\n\n\t\tpublic enum BlendModes {\n\t\t\tNormal = 0,\n\t\t\tMultiply = 1,\n\t\t\tScreen = 2,\n\t\t\tOverlay = 3,\n\t\t\tDarken = 4,\n\t\t\tLighten = 5,\n\t\t\tColorDodge = 6,\n\t\t\tColorBurn = 7,\n\t\t\tHardLight = 8,\n\t\t\tSoftLight = 9,\n\t\t\tDifference = 10,\n\t\t\tExclusion = 11,\n\t\t\tHue = 12,\n\t\t\tSaturation = 13,\n\t\t\tColor = 14,\n\t\t\tLuminosity = 15,\n\t\t\tAddition = 16,\n\t\t\tSubtract = 17,\n\t\t\tDivide = 18\n\t\t}\n\n\t\tpublic Flags Flag;\n\t\tpublic Types Type;\n\n\t\tpublic bool Visible;\n\t\tpublic string Name;\n\t\tpublic float Opacity;\n\t\tpublic BlendModes BlendMode;\n\t\tpublic int ChildLevel;\n\n\t\tstring IUserData.UserDataText { get; set; }\n\t\tColor IUserData.UserDataColor { get; set; }\n\t}\n\n\t// A frame is a column of cels\n\tpublic class AsepriteFrame {\n\t\tpublic float Duration;\n\t\tpublic List<AsepriteCel> Cels;\n\n\n\t\tpublic AsepriteFrame() {\n\t\t\tCels = new List<AsepriteCel>();\n\t\t}\n\t}\n\n\t// Tags are animation references\n\tpublic class AsepriteTag {\n\t\tpublic enum LoopDirections {\n\t\t\tForward = 0,\n\t\t\tReverse = 1,\n\t\t\tPingPong = 2\n\t\t}\n\n\t\tpublic string Name;\n\t\tpublic LoopDirections LoopDirection;\n\t\tpublic int From;\n\t\tpublic int To;\n\t\tpublic Color Color;\n\t}\n\n\tpublic struct AsepriteSlice : IUserData {\n\t\tpublic int Frame;\n\t\tpublic string Name;\n\t\tpublic int OriginX;\n\t\tpublic int OriginY;\n\t\tpublic int Width;\n\t\tpublic int Height;\n\t\tpublic Point? Pivot;\n\n\t\tstring IUserData.UserDataText { get; set; }\n\t\tColor IUserData.UserDataColor { get; set; }\n\t}\n\n\t// Cels are just pixel grids\n\tpublic class AsepriteCel : IUserData {\n\t\tpublic AsepriteLayer Layer;\n\n\t\tpublic Color[] Pixels;\n\n\t\tpublic int X;\n\t\tpublic int Y;\n\t\tpublic int Width;\n\t\tpublic int Height;\n\t\tpublic float Opacity;\n\n\t\tpublic string UserDataText { get; set; }\n\t\tpublic Color UserDataColor { get; set; }\n\t}\n}"
  },
  {
    "path": "Aseprite/AsepriteImporter.cs",
    "content": "﻿using Microsoft.Xna.Framework.Content.Pipeline;\n\n\nnamespace Aseprite {\n\t[ContentImporter(\".aseprite\", \".ase\", DefaultProcessor = \"AsepriteProcessor\", DisplayName = \"Aseprite Importer\")]\n\tpublic class AsepriteImporter : ContentImporter<AsepriteFile> {\n\t\tpublic override AsepriteFile Import(string filename, ContentImporterContext context) {\n\t\t\treturn new AsepriteFile(filename, context.Logger);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AsepriteProcessor.cs",
    "content": "﻿using Microsoft.Xna.Framework.Content.Pipeline;\n\nnamespace Aseprite {\n\t[ContentProcessor(DisplayName = \"Aseprite Processor\")]\n\tpublic class AsepriteProcessor : ContentProcessor<AsepriteFile, ProcessedAseprite> {\n\t\tpublic override ProcessedAseprite Process(AsepriteFile input, ContentProcessorContext context) {\n\t\t\treturn new ProcessedAseprite {\n\t\t\t\tAseprite = input,\n\t\t\t\tLog = context.Logger\n\t\t\t};\n\t\t}\n\t}\n\n\tpublic class ProcessedAseprite {\n\t\tpublic AsepriteFile Aseprite;\n\t\tpublic ContentBuildLogger Log;\n\t}\n}"
  },
  {
    "path": "Aseprite/AsepriteReader.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Content;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework.Graphics;\n\n\nnamespace Aseprite {\n\tpublic class AsepriteReader : ContentTypeReader<AsepriteFile> {\n\t\tpublic static GraphicsDevice GraphicsDevice;\n\n\t\tprotected override AsepriteFile Read(ContentReader input, AsepriteFile existingInstance) {\n\t\t\tif (existingInstance != null) {\n\t\t\t\treturn existingInstance;\n\t\t\t}\n\n\t\t\tint width = input.ReadInt32();\n\t\t\tint height = input.ReadInt32();\n\n\t\t\tAsepriteFile aseprite = new AsepriteFile {\n\t\t\t\tWidth = width,\n\t\t\t\tHeight = height\n\t\t\t};\n\n\t\t\t// Layers\n\t\t\tint layersCount = input.ReadInt32();\n\t\t\tAsepriteLayer layer;\n\t\t\tList<AsepriteLayer> layersByIndex = new List<AsepriteLayer>();\n\n\t\t\tfor (int i = 0; i < layersCount; i++) {\n\t\t\t\tlayer = new AsepriteLayer {\n\t\t\t\t\tName = input.ReadString(),\n\t\t\t\t\tOpacity = input.ReadSingle(),\n\t\t\t\t\tBlendMode = (AsepriteLayer.BlendModes) input.ReadInt32(),\n\t\t\t\t\tVisible = input.ReadBoolean()\n\t\t\t\t};\n\n\t\t\t\taseprite.Layers.Add(layer);\n\t\t\t\t// Use this for referencing cels down further\n\t\t\t\tlayersByIndex.Add(layer);\n\t\t\t}\n\n\t\t\t// Frames\n\t\t\tAsepriteFrame frame;\n\t\t\tAsepriteCel cel;\n\n\t\t\tint framesCount = input.ReadInt32();\n\t\t\tint celsCount;\n\t\t\tint celOriginX;\n\t\t\tint celOriginY;\n\t\t\tint celWidth;\n\t\t\tint celHeight;\n\t\t\tint textureWidth = framesCount * width;\n\t\t\tint textureHeight = layersCount * height;\n\n\t\t\tColor[] pixelData = new Color[textureWidth * textureHeight];\n\n\t\t\tfor (int f = 0; f < framesCount; f++) {\n\t\t\t\tframe = new AsepriteFrame {\n\t\t\t\t\tDuration = input.ReadSingle()\n\t\t\t\t};\n\n\t\t\t\t// Cels\n\t\t\t\tcelsCount = input.ReadInt32();\n\n\t\t\t\tfor (int i = 0; i < celsCount; i++) {\n\t\t\t\t\tint layerIndex = input.ReadInt32();\n\t\t\t\t\t\n\t\t\t\t\tcel = new AsepriteCel {\n\t\t\t\t\t\tLayer = layersByIndex[layerIndex]\n\t\t\t\t\t\t// ClipRect = new Rectangle(f * width, layerIndex * height, width, height)\n\t\t\t\t\t};\n\n\t\t\t\t\tframe.Cels.Add(cel);\n\n\t\t\t\t\t// Get info for the texture\n\t\t\t\t\tcelOriginX = input.ReadInt32();\n\t\t\t\t\tcelOriginY = input.ReadInt32();\n\t\t\t\t\tcelWidth = input.ReadInt32();\n\t\t\t\t\tcelHeight = input.ReadInt32();\n\t\t\t\t\t\n\t\t\t\t\tvar addX = cel.X;\n\t\t\t\t\tvar addY = cel.Y;\n\t\t\t\t\t\n\t\t\t\t\tfor (int celY = celOriginY; celY < celOriginY + celHeight; celY++) {\n\t\t\t\t\t\tfor (int celX = celOriginX; celX < celOriginX + celWidth; celX++) {\n\t\t\t\t\t\t\tvar pixel = input.ReadColor();\n\t\t\t\t\t\t\tvar ind = (f * width) + celX + addX + ((i * height) + celY + addY) * textureWidth;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// fixme: debug if check, figure out why texture loads wrong\n\t\t\t\t\t\t\tif (ind > -1 && ind < pixelData.Length) {\n\t\t\t\t\t\t\t\tpixelData[ind] = pixel;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\taseprite.Frames.Add(frame);\n\t\t\t}\n\n\t\t\t// Dump our pixels into the texture\n\t\t\taseprite.Texture = new Texture2D(GraphicsDevice, textureWidth, textureHeight);\n\t\t\taseprite.Texture.SetData(pixelData);\n\n\t\t\t// Animations\n\t\t\t\n\t\t\tint animationsCount = input.ReadInt32();\n\t\t\tAsepriteAnimation animation;\n\t\t\t\n\t\t\tfor (int i = 0; i < animationsCount; i++) {\n\t\t\t\tanimation = new AsepriteAnimation {\n\t\t\t\t\tName = input.ReadString(),\n\t\t\t\t\tFirstFrame = input.ReadInt32(),\n\t\t\t\t\tLastFrame = input.ReadInt32(),\n\t\t\t\t\tDirections = (AsepriteTag.LoopDirections) input.ReadByte()\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\taseprite.Animations.Add(animation.Name, animation);\n\t\t\t}\n\n\t\t\t// If no animations were added then just add one \n\t\t\t// that covers all frames\n\t\t\tif (aseprite.Animations.Count == 0) {\n\t\t\t\tanimation = new AsepriteAnimation {\n\t\t\t\t\tName = \"Idle\",\n\t\t\t\t\tFirstFrame = 0,\n\t\t\t\t\tLastFrame = aseprite.Frames.Count - 1\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\taseprite.Animations.Add(animation.Name, animation);\n\t\t\t}\n\n\t\t\treturn aseprite;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AsepriteWriter.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework.Content.Pipeline;\nusing Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;\n\nnamespace Aseprite {\n\t[ContentTypeWriter]\n\tclass AsepriteWriter : ContentTypeWriter<ProcessedAseprite> {\n\t\tprotected override void Write(ContentWriter output, ProcessedAseprite value) {\t\t\t\n\t\t\tAsepriteFile aseprite = value.Aseprite;\n\n\t\t\toutput.Write(aseprite.Width);\n\t\t\toutput.Write(aseprite.Height);\n\n\t\t\t// Layers\n\t\t\toutput.Write(aseprite.Layers.Count);\n\t\t\t\n\t\t\tforeach (var layer in aseprite.Layers) {\n\t\t\t\toutput.Write(layer.Name);\n\t\t\t\toutput.Write(layer.Opacity);\n\t\t\t\toutput.Write((int) layer.BlendMode);\n\t\t\t\toutput.Write(layer.Flag.HasFlag(AsepriteLayer.Flags.Visible));\n\t\t\t}\n\n\t\t\t// Frames\n\t\t\toutput.Write(aseprite.Frames.Count);\n\t\t\tvar f = 0;\n\t\t\t\n\t\t\tforeach (var frame in aseprite.Frames) {\n\t\t\t\toutput.Write(frame.Duration);\n\t\t\t\toutput.Write(frame.Cels.Count);\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < frame.Cels.Count; i++) {\n\t\t\t\t\tvar cel = frame.Cels[i];\n\t\t\t\t\toutput.Write(aseprite.Layers.IndexOf(cel.Layer));\n\t\t\t\t\toutput.Write(cel.X);\n\t\t\t\t\toutput.Write(cel.Y);\n\t\t\t\t\toutput.Write(cel.Width);\n\t\t\t\t\toutput.Write(cel.Height);\n\n\t\t\t\t\tfor (int celY = 0; celY < cel.Height; celY++) {\n\t\t\t\t\t\tfor (int celX = 0; celX < cel.Width; celX++) {\n\t\t\t\t\t\t\tint ind = celX + celY * cel.Width;\n\t\t\t\t\t\t\toutput.Write(cel.Pixels[ind]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tf++;\n\t\t\t}\n\n\t\t\t// Animations\n\t\t\toutput.Write(aseprite.Tags.Count);\n\t\t\t\n\t\t\tforeach (var animation in aseprite.Tags) {\n\t\t\t\toutput.Write(animation.Name);\n\t\t\t\toutput.Write(animation.From);\n\t\t\t\toutput.Write(animation.To);\n\t\t\t\toutput.Write((byte) animation.LoopDirection);\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetRuntimeType(TargetPlatform targetPlatform) {\n\t\t\tType type = typeof(AsepriteReader);\n\t\t\treturn type.Namespace + \".AsepriteReader, \" + type.AssemblyQualifiedName;\n\t\t}\n\n\t\tpublic override string GetRuntimeReader(TargetPlatform targetPlatform) {\n\t\t\tType type = typeof(AsepriteReader);\n\t\t\treturn type.Namespace + \".AsepriteReader, \" + type.Assembly.FullName;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AudioFile.cs",
    "content": "namespace Aseprite {\n\tpublic class AudioFile {\n\t\tpublic int SampleRate;\n\t\tpublic bool Stereo;\n\n\t\tpublic float[] Buffer;\n\t}\n}"
  },
  {
    "path": "Aseprite/AudioImporter.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework.Content.Pipeline;\n\nnamespace Aseprite {\n\t[ContentImporter(\".ogg\", DefaultProcessor = \"AudioProcessor\", DisplayName = \"Audio Importer\")]\n\tpublic class AudioImporter : ContentImporter<AudioFile> {\n\t\tpublic static AudioFile Load(string filename) {\n\t\t\tusing (var vorbis = new NVorbis.VorbisReader(filename)) {\n\t\t\t\tvar channels = vorbis.Channels;\n\t\t\t\tvar sampleRate = vorbis.SampleRate;\n\t\t\t\tvar channelSize = sampleRate * vorbis.TotalTime.TotalSeconds;\n\t\t\t\tvar bufferSize = (int) Math.Ceiling(channels * channelSize);\n\t\t\t\tvar readBuffer = new float[bufferSize];\n\n\t\t\t\tvorbis.ReadSamples(readBuffer, 0, bufferSize);\n\n\t\t\t\treturn new AudioFile {\n\t\t\t\t\t\tSampleRate = sampleRate,\n\t\t\t\t\t\tStereo = channels == 2,\n\t\t\t\t\t\tBuffer = readBuffer\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override AudioFile Import(string filename, ContentImporterContext context) {\n\t\t\treturn Load(filename);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AudioProcessor.cs",
    "content": "using Microsoft.Xna.Framework.Content.Pipeline;\n\nnamespace Aseprite {\n\t[ContentProcessor(DisplayName = \"Audio Processor\")]\n\tpublic class AudioProcessor : ContentProcessor<AudioFile, AudioFile> {\n\t\tpublic override AudioFile Process(AudioFile input, ContentProcessorContext context) {\n\t\t\treturn input;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AudioReader.cs",
    "content": "using Microsoft.Xna.Framework.Content;\n\nnamespace Aseprite {\n\tpublic class AudioReader : ContentTypeReader<AudioFile> {\n\t\tprotected override AudioFile Read(ContentReader input, AudioFile existingInstance) {\n\t\t\tif (existingInstance != null) {\n\t\t\t\treturn existingInstance;\n\t\t\t}\n\t\t\t\n\t\t\tvar stereo = input.ReadBoolean();\n\t\t\tvar sampleRate = input.ReadInt32();\n\t\t\tvar length = input.ReadInt32();\n\t\t\tvar buffer = new float[length];\n\n\t\t\tfor (var i = 0; i < buffer.Length; i++) {\n\t\t\t\tbuffer[i] = input.ReadSingle();\n\t\t\t}\n\n\t\t\treturn new AudioFile {\n\t\t\t\tStereo = stereo,\n\t\t\t\tSampleRate = sampleRate,\n\t\t\t\tBuffer = buffer\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/AudioWriter.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework.Content.Pipeline;\nusing Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;\n\nnamespace Aseprite {\n\t[ContentTypeWriter]\n\tpublic class AudioWriter : ContentTypeWriter<AudioFile> {\n\t\tpublic override string GetRuntimeType(TargetPlatform targetPlatform) {\n\t\t\tType type = typeof(AsepriteReader);\n\t\t\treturn type.Namespace + \".AudioReader, \" + type.AssemblyQualifiedName;\n\t\t}\n\n\t\tpublic override string GetRuntimeReader(TargetPlatform targetPlatform) {\n\t\t\tType type = typeof(AsepriteReader);\n\t\t\treturn type.Namespace + \".AudioReader, \" + type.Assembly.FullName;\n\t\t}\n\n\t\tprotected override void Write(ContentWriter output, AudioFile value) {\n\t\t\toutput.Write(value.Stereo);\n\t\t\toutput.Write(value.SampleRate);\n\t\t\toutput.Write(value.Buffer.Length);\n\n\t\t\tfor (var i = 0; i < value.Buffer.Length; i++) {\n\t\t\t\toutput.Write(value.Buffer[i]);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/Calc.cs",
    "content": "﻿namespace Aseprite {\n\tpublic static class Calc {\n\t\tpublic static bool IsBitSet(uint b, int pos) {\n\t\t\treturn (b & (1 << pos)) != 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Aseprite/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Aseprite\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"Aseprite\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"13C6F252-0B3C-4A22-A9DB-270C76657FAB\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]"
  },
  {
    "path": "Aseprite/README.md",
    "content": "# Aseprite loading helper\n\n**This is mostly not my code (not written by @egordorichev)**\nFull credit goes to the author [of this gist](https://gist.github.com/nathanhoad/bf9ddac2e13a5aaa922182005f3da6e5).\n\nThe task of this package is to allow me to use `.ase` files (Aseprite files) without having to export them."
  },
  {
    "path": "Aseprite/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"MonoGame.Extended.Content.Pipeline\" version=\"1.1.0\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Framework.Content.Pipeline.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Framework.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n  <package id=\"NVorbis\" version=\"0.8.6\" targetFramework=\"net471\" />\n  <package id=\"NVorbis.OpenTKSupport\" version=\"1.2.0\" targetFramework=\"net471\" />\n  <package id=\"OpenTK\" version=\"3.0.1\" targetFramework=\"net471\" />\n  <package id=\"System.Collections\" version=\"4.3.0\" targetFramework=\"net471\" />\n</packages>"
  },
  {
    "path": "BurningKnight/BK.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.mod;\nusing BurningKnight.assets.prefabs;\nusing BurningKnight.level;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing Version = Lens.Version;\n\nnamespace BurningKnight {\n\tpublic class BK : Engine {\n\t\tpublic const bool StandMode = false;\n\t\tpublic const bool Demo = false;\n\t\t\n\t\tpublic static Version Version = new Version(\"Bad rock update\", 50, 1, 3, 1, 4, Debug);\n\t\t\n\t\tpublic BK(int width, int height, bool fullscreen) : base(Version, \n\t\t\t#if DEBUG\n\t\t\t\tnew DevAssetLoadState(),\n\t\t\t#else\n\t\t\t\tnew AssetLoadState(),\n\t\t\t#endif\n\t\t\t Rnd.Chance(60) ? \"Burning Knight\" : $\"Burning Knight{(Demo ? \" Demo\" : \"\")}: {Titles.Generate()}\", width, height, fullscreen) {\n\t\t}\n\n\t\tprotected override void Initialize() {\n\t\t\tbase.Initialize();\n\n\t\t\tSaveManager.Init();\n\t\t\tControls.Load();\n\t\t\tFont.Load();\n\n\t\t\ttry {\n\t\t\t\tImGuiHelper.Init();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t\t\n\t\t\tWeather.Init();\n\t\t}\n\n\t\tprivate static void RunBash(string args) {\n\t\t\tvar process = new Process {\n\t\t\t\tStartInfo = new ProcessStartInfo {\n\t\t\t\t\tFileName = \"/bin/bash\",\n\t\t\t\t\tArguments = $\"-c \\\"{args}\\\"\",\n\t\t\t\t\tRedirectStandardOutput = true,\n\t\t\t\t\tUseShellExecute = false,\n\t\t\t\t\tCreateNoWindow = true,\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\tprocess.Start();\n\t\t\tvar result = process.StandardOutput.ReadToEnd();\n\t\t\tprocess.WaitForExit();\n\n\t\t\tConsole.WriteLine(result);\n\t\t}\n\n\t\tprotected override void UnloadContent() {\n\t\t\tMods.Destroy();\n\t\t\tItems.Destroy();\n\t\t\tPrefabs.Destroy();\n\t\t\tLights.DestroySurface();\n\t\t\t\n\t\t\tbase.UnloadContent();\n\t\t}\n\n\t\tprotected override void Update(GameTime gameTime) {\n\t\t\tbase.Update(gameTime);\n\t\t\tMods.Update((float) gameTime.ElapsedGameTime.TotalSeconds);\n\t\t}\n\n\t\tpublic override void RenderUi() {\n\t\t\tbase.RenderUi();\n\t\t\tMods.Render();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/BurningKnight.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x64</Platform>\n    <ProjectGuid>{D31D0D40-105E-47D5-A5D0-F6E30328BF86}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>BurningKnight</RootNamespace>\n    <AssemblyName>BurningKnight</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <LangVersion>7.2</LangVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Facepunch.Steamworks.Win64, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\Facepunch.Steamworks.2.3.3\\lib\\net46\\Facepunch.Steamworks.Win64.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"ImGui.NET, Version=1.70.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\ImGui.NET.1.70.0\\lib\\netstandard2.0\\ImGui.NET.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Extensions.DependencyInjection, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">\n      <HintPath>..\\packages\\Microsoft.Extensions.DependencyInjection.1.1.1\\lib\\netstandard1.1\\Microsoft.Extensions.DependencyInjection.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">\n      <HintPath>..\\packages\\Microsoft.Extensions.DependencyInjection.Abstractions.1.1.1\\lib\\netstandard1.0\\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\Microsoft.Win32.Primitives.4.3.0\\lib\\net46\\Microsoft.Win32.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended.Graphics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.Graphics.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.Graphics.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended.Tiled, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.Tiled.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.Tiled.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework, Version=3.8.0.13, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\lib\\net452\\MonoGame.Framework.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework.Content.Pipeline, Version=3.7.0.1708, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.Content.Pipeline.Portable.3.7.0.1708\\lib\\portable-net45+win8+wpa81\\MonoGame.Framework.Content.Pipeline.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"mscorlib\" />\n    <Reference Include=\"netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\" />\n    <Reference Include=\"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed\">\n      <HintPath>..\\packages\\Newtonsoft.Json.12.0.3\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.4.0.1\\lib\\net45\\SharpDX.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.Direct2D1, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.Direct2D1.4.0.1\\lib\\net45\\SharpDX.Direct2D1.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.Direct3D11, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.Direct3D11.4.0.1\\lib\\net45\\SharpDX.Direct3D11.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.Direct3D9, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.Direct3D9.4.0.1\\lib\\net45\\SharpDX.Direct3D9.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.DXGI, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.DXGI.4.0.1\\lib\\net45\\SharpDX.DXGI.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.Mathematics, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.Mathematics.4.0.1\\lib\\net45\\SharpDX.Mathematics.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.MediaFoundation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.MediaFoundation.4.0.1\\lib\\net45\\SharpDX.MediaFoundation.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.XAudio2, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.XAudio2.4.0.1\\lib\\net45\\SharpDX.XAudio2.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpDX.XInput, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1\">\n      <HintPath>..\\packages\\SharpDX.XInput.4.0.1\\lib\\net45\\SharpDX.XInput.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.AppContext.4.3.0\\lib\\net463\\System.AppContext.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Buffers.4.4.0\\lib\\netstandard2.0\\System.Buffers.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Collections, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\System.Collections.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Collections.Immutable.1.3.1\\lib\\portable-net45+win8+wp8+wpa81\\System.Collections.Immutable.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.ComponentModel.Composition\" />\n    <Reference Include=\"System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Console.4.3.0\\lib\\net46\\System.Console.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Diagnostics.DiagnosticSource.4.3.0\\lib\\net46\\System.Diagnostics.DiagnosticSource.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Diagnostics.Tracing.4.3.0\\lib\\net462\\System.Diagnostics.Tracing.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Globalization.Calendars.4.3.0\\lib\\net46\\System.Globalization.Calendars.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Interactive.Async, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263\">\n      <HintPath>..\\packages\\System.Interactive.Async.3.1.1\\lib\\net46\\System.Interactive.Async.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.4.3.0\\lib\\net462\\System.IO.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.4.3.0\\lib\\net46\\System.IO.Compression.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.ZipFile.4.3.0\\lib\\net46\\System.IO.Compression.ZipFile.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.4.3.0\\lib\\net46\\System.IO.FileSystem.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.Primitives.4.3.0\\lib\\net46\\System.IO.FileSystem.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.4.3.0\\lib\\net463\\System.Linq.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.Expressions.4.3.0\\lib\\net463\\System.Linq.Expressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Http.4.3.0\\lib\\net46\\System.Net.Http.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Sockets.4.3.0\\lib\\net46\\System.Net.Sockets.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Numerics\" />\n    <Reference Include=\"System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\System.Numerics.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Numerics.Vectors.4.4.0\\lib\\net46\\System.Numerics.Vectors.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Reflection.4.3.0\\lib\\net462\\System.Reflection.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.4.3.0\\lib\\net462\\System.Runtime.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.CompilerServices.Unsafe.4.5.0-preview2-26406-04\\lib\\netstandard2.0\\System.Runtime.CompilerServices.Unsafe.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.Extensions.4.3.0\\lib\\net462\\System.Runtime.Extensions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.InteropServices.4.3.0\\lib\\net463\\System.Runtime.InteropServices.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.InteropServices.RuntimeInformation.4.3.0\\lib\\net45\\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Algorithms.4.3.0\\lib\\net463\\System.Security.Cryptography.Algorithms.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Encoding.4.3.0\\lib\\net46\\System.Security.Cryptography.Encoding.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Primitives.4.3.0\\lib\\net46\\System.Security.Cryptography.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.X509Certificates.4.3.0\\lib\\net461\\System.Security.Cryptography.X509Certificates.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Text.RegularExpressions.4.3.0\\lib\\net463\\System.Text.RegularExpressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Threading, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\System.Threading.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Xml.ReaderWriter.4.3.0\\lib\\net46\\System.Xml.ReaderWriter.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"TextCopy, Version=1.7.1.0, Culture=neutral, PublicKeyToken=1ca091877d12ca03\">\n      <HintPath>..\\packages\\TextCopy.1.7.1\\lib\\net461\\TextCopy.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"assets\\achievements\\Achievement.cs\" />\n    <Compile Include=\"assets\\achievements\\Achievements.cs\" />\n    <Compile Include=\"assets\\CommonAse.cs\" />\n    <Compile Include=\"assets\\Dialogs.cs\" />\n    <Compile Include=\"assets\\Font.cs\" />\n    <Compile Include=\"assets\\ImGuiHelper.cs\" />\n    <Compile Include=\"assets\\input\\Control.cs\" />\n    <Compile Include=\"assets\\input\\Controls.cs\" />\n    <Compile Include=\"assets\\items\\ItemData.cs\" />\n    <Compile Include=\"assets\\items\\Items.cs\" />\n    <Compile Include=\"assets\\lighting\\EntityLight.cs\" />\n    <Compile Include=\"assets\\lighting\\Light.cs\" />\n    <Compile Include=\"assets\\lighting\\LightComponent.cs\" />\n    <Compile Include=\"assets\\lighting\\Lights.cs\" />\n    <Compile Include=\"assets\\lighting\\PositionedLight.cs\" />\n    <Compile Include=\"assets\\loot\\Drops.cs\" />\n    <Compile Include=\"assets\\loot\\LootTables.cs\" />\n    <Compile Include=\"assets\\mod\\Mod.cs\" />\n    <Compile Include=\"assets\\mod\\Mods.cs\" />\n    <Compile Include=\"assets\\Palette.cs\" />\n    <Compile Include=\"assets\\particle\\AnimatedParticle.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\AnimatedParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\AshController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\BkDeathParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\BloodParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\Controllers.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\LavaController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\RainParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\ScourgeController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\DestroyParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\FloatParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\HealthParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\ParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\SimpleParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\controller\\SparkParticleController.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\BuffParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\ConfettiParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\ConsumableParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\EpicSpawn.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\FadingParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\FireEmitter.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\FireParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\ProjectileParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\RainParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\SnowParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\TextParticle.cs\" />\n    <Compile Include=\"assets\\particle\\custom\\TileParticle.cs\" />\n    <Compile Include=\"assets\\particle\\Particle.cs\" />\n    <Compile Include=\"assets\\particle\\ParticleEmitter.cs\" />\n    <Compile Include=\"assets\\particle\\ParticleEntity.cs\" />\n    <Compile Include=\"assets\\particle\\Particles.cs\" />\n    <Compile Include=\"assets\\particle\\ParticleSystem.cs\" />\n    <Compile Include=\"assets\\particle\\renderer\\AnimatedParticleRenderer.cs\" />\n    <Compile Include=\"assets\\particle\\renderer\\HealthParticleRenderer.cs\" />\n    <Compile Include=\"assets\\particle\\renderer\\ParticleRenderer.cs\" />\n    <Compile Include=\"assets\\particle\\renderer\\RandomFrameRenderer.cs\" />\n    <Compile Include=\"assets\\particle\\renderer\\TexturedParticleRenderer.cs\" />\n    <Compile Include=\"assets\\prefabs\\Prefab.cs\" />\n    <Compile Include=\"assets\\prefabs\\Prefabs.cs\" />\n    <Compile Include=\"assets\\Shaders.cs\" />\n    <Compile Include=\"BK.cs\" />\n    <Compile Include=\"debug\\BiomeCommand.cs\" />\n    <Compile Include=\"debug\\BuffCommand.cs\" />\n    <Compile Include=\"debug\\CheatWindow.cs\" />\n    <Compile Include=\"debug\\Console.cs\" />\n    <Compile Include=\"debug\\ConsoleCommand.cs\" />\n    <Compile Include=\"debug\\DebugCommand.cs\" />\n    <Compile Include=\"debug\\DieCommand.cs\" />\n    <Compile Include=\"debug\\EntityCommand.cs\" />\n    <Compile Include=\"debug\\ExploreCommand.cs\" />\n    <Compile Include=\"debug\\GiveCommand.cs\" />\n    <Compile Include=\"debug\\GodModeCommand.cs\" />\n    <Compile Include=\"debug\\HappeningCommand.cs\" />\n    <Compile Include=\"debug\\HealCommand.cs\" />\n    <Compile Include=\"debug\\HurtCommand.cs\" />\n    <Compile Include=\"debug\\LevelCommand.cs\" />\n    <Compile Include=\"debug\\LevelLayerDebug.cs\" />\n    <Compile Include=\"debug\\LootTableEditor.cs\" />\n    <Compile Include=\"debug\\PassableCommand.cs\" />\n    <Compile Include=\"debug\\PoolEditor.cs\" />\n    <Compile Include=\"debug\\SaveCommand.cs\" />\n    <Compile Include=\"debug\\SpawnCommand.cs\" />\n    <Compile Include=\"debug\\TileCommand.cs\" />\n    <Compile Include=\"debug\\ZoomCommand.cs\" />\n    <Compile Include=\"entity\\BlankMaker.cs\" />\n    <Compile Include=\"entity\\bomb\\Bomb.cs\" />\n    <Compile Include=\"entity\\bomb\\controller\\TargetBombController.cs\" />\n    <Compile Include=\"entity\\buff\\ArmoredBuff.cs\" />\n    <Compile Include=\"entity\\buff\\BleedingBuff.cs\" />\n    <Compile Include=\"entity\\buff\\BrokenArmorBuff.cs\" />\n    <Compile Include=\"entity\\buff\\Buff.cs\" />\n    <Compile Include=\"entity\\buff\\BuffCheckEvent.cs\" />\n    <Compile Include=\"entity\\buff\\BuffedBuff.cs\" />\n    <Compile Include=\"entity\\buff\\BuffInfo.cs\" />\n    <Compile Include=\"entity\\buff\\BuffRegistry.cs\" />\n    <Compile Include=\"entity\\buff\\BurningBuff.cs\" />\n    <Compile Include=\"entity\\buff\\CharmedBuff.cs\" />\n    <Compile Include=\"entity\\buff\\ConfusedBuff.cs\" />\n    <Compile Include=\"entity\\buff\\FrozenBuff.cs\" />\n    <Compile Include=\"entity\\buff\\InvincibleBuff.cs\" />\n    <Compile Include=\"entity\\buff\\InvisibleBuff.cs\" />\n    <Compile Include=\"entity\\buff\\PoisonBuff.cs\" />\n    <Compile Include=\"entity\\buff\\ProjectileShaderHelper.cs\" />\n    <Compile Include=\"entity\\buff\\RageBuff.cs\" />\n    <Compile Include=\"entity\\buff\\SlowBuff.cs\" />\n    <Compile Include=\"entity\\component\\AimComponent.cs\" />\n    <Compile Include=\"entity\\component\\AnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\AudioEmitterComponent.cs\" />\n    <Compile Include=\"entity\\component\\BodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\BombGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\component\\BuffsComponent.cs\" />\n    <Compile Include=\"entity\\component\\CircleBodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\CloseDialogComponent.cs\" />\n    <Compile Include=\"entity\\component\\CollisionFilterComponent.cs\" />\n    <Compile Include=\"entity\\component\\CursorComponent.cs\" />\n    <Compile Include=\"entity\\component\\DoorBodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\DropModifier.cs\" />\n    <Compile Include=\"entity\\component\\DropsComponent.cs\" />\n    <Compile Include=\"entity\\component\\ExplodableComponent.cs\" />\n    <Compile Include=\"entity\\component\\ExplodeComponent.cs\" />\n    <Compile Include=\"entity\\component\\FollowerComponent.cs\" />\n    <Compile Include=\"entity\\component\\GamepadComponent.cs\" />\n    <Compile Include=\"entity\\component\\HatComponent.cs\" />\n    <Compile Include=\"entity\\component\\HealthComponent.cs\" />\n    <Compile Include=\"entity\\component\\InteractableComponent.cs\" />\n    <Compile Include=\"entity\\component\\InteractableSliceComponent.cs\" />\n    <Compile Include=\"entity\\component\\InteractDialogComponent.cs\" />\n    <Compile Include=\"entity\\component\\InventoryComponent.cs\" />\n    <Compile Include=\"entity\\component\\ItemComponent.cs\" />\n    <Compile Include=\"entity\\component\\LockComponent.cs\" />\n    <Compile Include=\"entity\\component\\ManaComponent.cs\" />\n    <Compile Include=\"entity\\component\\MobAnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\NoCornerBodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\ExtraAnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\OrbitalComponent.cs\" />\n    <Compile Include=\"entity\\component\\OrbitGiverComponent.cs\" />\n    <Compile Include=\"entity\\component\\OwnerComponent.cs\" />\n    <Compile Include=\"entity\\component\\PoolDropsComponent.cs\" />\n    <Compile Include=\"entity\\component\\QuackInteractionComponent.cs\" />\n    <Compile Include=\"entity\\component\\RandomFrameComponent.cs\" />\n    <Compile Include=\"entity\\component\\RectBodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\RoomComponent.cs\" />\n    <Compile Include=\"entity\\component\\ScalableSliceComponent.cs\" />\n    <Compile Include=\"entity\\component\\SensorBodyComponent.cs\" />\n    <Compile Include=\"entity\\component\\ShadowComponent.cs\" />\n    <Compile Include=\"entity\\component\\SimpleZAnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\SliceComponent.cs\" />\n    <Compile Include=\"entity\\component\\SparkEmitterComponent.cs\" />\n    <Compile Include=\"entity\\component\\StatsComponent.cs\" />\n    <Compile Include=\"entity\\component\\SupportableComponent.cs\" />\n    <Compile Include=\"entity\\component\\TextGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\component\\TileInteractionComponent.cs\" />\n    <Compile Include=\"entity\\component\\WallAnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\ZAnimationComponent.cs\" />\n    <Compile Include=\"entity\\component\\ZComponent.cs\" />\n    <Compile Include=\"entity\\component\\ZSliceComponent.cs\" />\n    <Compile Include=\"entity\\creature\\bk\\BkGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\creature\\bk\\BkOrbital.cs\" />\n    <Compile Include=\"entity\\creature\\bk\\BurningKnight.cs\" />\n    <Compile Include=\"entity\\creature\\bk\\SpawnTrigger.cs\" />\n    <Compile Include=\"entity\\creature\\Creature.cs\" />\n    <Compile Include=\"entity\\creature\\Decoy.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\AnyDrop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\Drop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\DropInfo.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\DropRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\EmptyDrop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\OneOfDrop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\PoolDrop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\SimpleDrop.cs\" />\n    <Compile Include=\"entity\\creature\\drop\\SingleDrop.cs\" />\n    <Compile Include=\"entity\\creature\\Gore.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\BkHead.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\BossInfo.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\BossRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\DM.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\IceQueen.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\OldKing.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\Pharaoh.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\QueenBee.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmBulletDodgeRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmEndRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmEnemyRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmMazeRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmPadsRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmPlatformRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmRoomRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\rooms\\DmSpikeRoom.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\BigSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\BlueBulletSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Caster.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Crab.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Rat.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\cave\\Broco.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\cave\\EmeraldGunner.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\cave\\Thief.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Cactus.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\DesertBulletSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Fly.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\DesertSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Maggot.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\MegaSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Mummy.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Spelunker.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\desert\\Worm.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\BigSnowball.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\CupGuy.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\Dino.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\IceCrawler.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\Snowball.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\Snowflake.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\Snowman.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\SnowmanBody.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\ice\\Sponge.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\Bee.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\BeeHive.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\BigBee.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\BuffedFlower.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\Explobee.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\Flower.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\Sniper.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\jungle\\Wombat.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\LoopChance.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\library\\Book.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\library\\Buffer.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\library\\Skeleton.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\library\\TeleportingMage.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\Mimic.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\MobSpawnInfo.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\DeathShotPrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\ExplosivePrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\EmeraldPrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\FragilePrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\GoldPrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\HealthyPrefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\Prefix.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\PrefixRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefix\\RegenerativePrefix.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\AccessoryTrader.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\ActiveTrader.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Bird.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Brastin.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Builder.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\DarkMage.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Discord.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Duck.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Boxy.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\DungeonDuck.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\DungeonElon.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\DungeonShopNpc.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Gobetta.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Nurse.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Roger.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Snek.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\TrashGoblin.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\dungeon\\Vampire.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Elon.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\EmeraldGolem.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Granny.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\HatTrader.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Isaac.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Maanex.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Maanex2.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\MaPuzzle.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Mike.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Milt.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\NullPtr.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\ShopNpc.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\WeaponTrader.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\AnimatedFollowerPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Backpack.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Bubblo.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Crystal.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\DiagonalPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\FollowerPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\GeneratorPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\LampPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\RoomBasedPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\ShieldBuddy.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Shooty.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\SnekPet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\SpikedCookie.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Strawberry.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\TheEye.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Wallet.cs\" />\n    <Compile Include=\"entity\\creature\\player\\LampComponent.cs\" />\n    <Compile Include=\"entity\\creature\\SmartState.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\Boss.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\boss\\BossAttack.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\BabySlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Bandit.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\BulletSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Clown.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Ghost.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Gunner.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\King.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\Knight.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\MotherSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\SimpleSlime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\castle\\WallCrawler.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\Dummy.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\Mob.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\MobInfo.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\MobPair.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\MobRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefabs\\Slime.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\prefabs\\WallWalker.cs\" />\n    <Compile Include=\"entity\\creature\\mob\\SpawnChance.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Beet.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Npc.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\OldMan.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\Ord.cs\" />\n    <Compile Include=\"entity\\creature\\npc\\ShopKeeper.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\BooGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\LilBoo.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\Pet.cs\" />\n    <Compile Include=\"entity\\creature\\pet\\PetRegistry.cs\" />\n    <Compile Include=\"entity\\creature\\player\\ActiveItemComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\ActiveWeaponComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\ConsumablesComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\HeartsComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\InteractorComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\LocalPlayer.cs\" />\n    <Compile Include=\"entity\\creature\\player\\Player.cs\" />\n    <Compile Include=\"entity\\creature\\player\\PlayerClass.cs\" />\n    <Compile Include=\"entity\\creature\\player\\PlayerGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\PlayerInputComponent.cs\" />\n    <Compile Include=\"entity\\creature\\player\\WeaponComponent.cs\" />\n    <Compile Include=\"entity\\Cursor.cs\" />\n    <Compile Include=\"entity\\cutscene\\controller\\CutsceneController.cs\" />\n    <Compile Include=\"entity\\cutscene\\controller\\GobboCutsceneController.cs\" />\n    <Compile Include=\"entity\\cutscene\\entity\\BabyGobbo.cs\" />\n    <Compile Include=\"entity\\cutscene\\entity\\CutsceneEntity.cs\" />\n    <Compile Include=\"entity\\cutscene\\entity\\Gobbo.cs\" />\n    <Compile Include=\"entity\\cutscene\\entity\\Heinur.cs\" />\n    <Compile Include=\"entity\\cutscene\\entity\\OldGobbo.cs\" />\n    <Compile Include=\"entity\\DamageType.cs\" />\n    <Compile Include=\"entity\\door\\BossDoor.cs\" />\n    <Compile Include=\"entity\\door\\BossLock.cs\" />\n    <Compile Include=\"entity\\door\\CageDoor.cs\" />\n    <Compile Include=\"entity\\door\\CageLock.cs\" />\n    <Compile Include=\"entity\\door\\ChallengeDoor.cs\" />\n    <Compile Include=\"entity\\door\\ConditionDoor.cs\" />\n    <Compile Include=\"entity\\door\\ConditionLock.cs\" />\n    <Compile Include=\"entity\\door\\CustomDoor.cs\" />\n    <Compile Include=\"entity\\door\\Door.cs\" />\n    <Compile Include=\"entity\\door\\GoldLock.cs\" />\n    <Compile Include=\"entity\\door\\HallDoor.cs\" />\n    <Compile Include=\"entity\\door\\HallLock.cs\" />\n    <Compile Include=\"entity\\door\\HeadDoor.cs\" />\n    <Compile Include=\"entity\\door\\IronLock.cs\" />\n    <Compile Include=\"entity\\door\\ItemDoor.cs\" />\n    <Compile Include=\"entity\\door\\ItemLock.cs\" />\n    <Compile Include=\"entity\\door\\LevelDoor.cs\" />\n    <Compile Include=\"entity\\door\\LevelLock.cs\" />\n    <Compile Include=\"entity\\door\\Lock.cs\" />\n    <Compile Include=\"entity\\door\\LockableDoor.cs\" />\n    <Compile Include=\"entity\\door\\LockedDoor.cs\" />\n    <Compile Include=\"entity\\door\\PayedDoor.cs\" />\n    <Compile Include=\"entity\\door\\RedDoor.cs\" />\n    <Compile Include=\"entity\\door\\RedLock.cs\" />\n    <Compile Include=\"entity\\door\\ScourgedDoor.cs\" />\n    <Compile Include=\"entity\\door\\ShopDoor.cs\" />\n    <Compile Include=\"entity\\door\\SpecialDoor.cs\" />\n    <Compile Include=\"entity\\door\\SpikedDoor.cs\" />\n    <Compile Include=\"entity\\door\\TeleportTrigger.cs\" />\n    <Compile Include=\"entity\\door\\TreasureDoor.cs\" />\n    <Compile Include=\"entity\\door\\VerticalConditionDoor.cs\" />\n    <Compile Include=\"entity\\door\\VerticalDoor.cs\" />\n    <Compile Include=\"entity\\door\\VerticalHallDoor.cs\" />\n    <Compile Include=\"entity\\door\\VerticalShopDoor.cs\" />\n    <Compile Include=\"entity\\events\\BombPlacedEvent.cs\" />\n    <Compile Include=\"entity\\events\\BuffAddedEvent.cs\" />\n    <Compile Include=\"entity\\events\\BuffRemovedEvent.cs\" />\n    <Compile Include=\"entity\\events\\BurningKnightDefeatedEvent.cs\" />\n    <Compile Include=\"entity\\events\\CollisionEndedEvent.cs\" />\n    <Compile Include=\"entity\\events\\CollisionStartedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ConsumableAddedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ConsumableRemovedEvent.cs\" />\n    <Compile Include=\"entity\\events\\DealChanceCalculateEvent.cs\" />\n    <Compile Include=\"entity\\events\\DiedEvent.cs\" />\n    <Compile Include=\"entity\\events\\DoorClosedEvent.cs\" />\n    <Compile Include=\"entity\\events\\DoorOpenedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ExplodedEvent.cs\" />\n    <Compile Include=\"entity\\events\\FlagCollisionEndEvent.cs\" />\n    <Compile Include=\"entity\\events\\FlagCollisionStartEvent.cs\" />\n    <Compile Include=\"entity\\events\\GramophoneBrokenEvent.cs\" />\n    <Compile Include=\"entity\\events\\HealthModifiedEvent.cs\" />\n    <Compile Include=\"entity\\events\\InteractedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemAddedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemBoughtEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemCheckEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemPlacedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemPriceCalculationEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemRemovedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemTakenEvent.cs\" />\n    <Compile Include=\"entity\\events\\ItemUsedEvent.cs\" />\n    <Compile Include=\"entity\\events\\KilledEvent.cs\" />\n    <Compile Include=\"entity\\events\\LockClosedEvent.cs\" />\n    <Compile Include=\"entity\\events\\LockOpenedEvent.cs\" />\n    <Compile Include=\"entity\\events\\LostSupportEvent.cs\" />\n    <Compile Include=\"entity\\events\\MaxHealthModifiedEvent.cs\" />\n    <Compile Include=\"entity\\events\\MobTargetChange.cs\" />\n    <Compile Include=\"entity\\events\\NewFloorEvent.cs\" />\n    <Compile Include=\"entity\\events\\NewLevelStartedEvent.cs\" />\n    <Compile Include=\"entity\\events\\PlayerHurtEvent.cs\" />\n    <Compile Include=\"entity\\events\\PlayerRolledEvent.cs\" />\n    <Compile Include=\"entity\\events\\PlayerShootEvent.cs\" />\n    <Compile Include=\"entity\\events\\PostHealthModifiedEvent.cs\" />\n    <Compile Include=\"entity\\events\\ProjectileCreatedEvent.cs\" />\n    <Compile Include=\"entity\\events\\QuackEvent.cs\" />\n    <Compile Include=\"entity\\events\\RemoveFromPoolUse.cs\" />\n    <Compile Include=\"entity\\events\\RevivedEvent.cs\" />\n    <Compile Include=\"entity\\events\\RoomChangedEvent.cs\" />\n    <Compile Include=\"entity\\events\\RoomClearedEvent.cs\" />\n    <Compile Include=\"entity\\events\\SaveEndedEvent.cs\" />\n    <Compile Include=\"entity\\events\\SaveStartedEvent.cs\" />\n    <Compile Include=\"entity\\events\\SecretRoomFoundEvent.cs\" />\n    <Compile Include=\"entity\\events\\TileCollisionEndEvent.cs\" />\n    <Compile Include=\"entity\\events\\TileCollisionStartEvent.cs\" />\n    <Compile Include=\"entity\\events\\WeaponSwappedEvent.cs\" />\n    <Compile Include=\"entity\\ExplosionMaker.cs\" />\n    <Compile Include=\"entity\\fx\\SplashFx.cs\" />\n    <Compile Include=\"entity\\fx\\ChasmFx.cs\" />\n    <Compile Include=\"entity\\fx\\ExplosionLeftOver.cs\" />\n    <Compile Include=\"entity\\fx\\Firefly.cs\" />\n    <Compile Include=\"entity\\fx\\InteractFx.cs\" />\n    <Compile Include=\"entity\\fx\\SplashParticle.cs\" />\n    <Compile Include=\"entity\\fx\\TileFx.cs\" />\n    <Compile Include=\"entity\\fx\\WaterfallFx.cs\" />\n    <Compile Include=\"entity\\fx\\WindFx.cs\" />\n    <Compile Include=\"entity\\HealthType.cs\" />\n    <Compile Include=\"entity\\item\\AnimatedItemGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\item\\BossStand.cs\" />\n    <Compile Include=\"entity\\item\\Chance.cs\" />\n    <Compile Include=\"entity\\item\\ItemQuality.cs\" />\n    <Compile Include=\"entity\\item\\RandomItem.cs\" />\n    <Compile Include=\"entity\\item\\RoundItem.cs\" />\n    <Compile Include=\"entity\\item\\Scourge.cs\" />\n    <Compile Include=\"entity\\item\\EmeraldStand.cs\" />\n    <Compile Include=\"entity\\item\\Item.cs\" />\n    <Compile Include=\"entity\\item\\ItemGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\item\\ItemInfo.cs\" />\n    <Compile Include=\"entity\\item\\ItemPair.cs\" />\n    <Compile Include=\"entity\\item\\ItemPickupFx.cs\" />\n    <Compile Include=\"entity\\item\\ItemPool.cs\" />\n    <Compile Include=\"entity\\item\\ItemType.cs\" />\n    <Compile Include=\"entity\\item\\PriceCalculator.cs\" />\n    <Compile Include=\"entity\\item\\renderer\\AngledRenderer.cs\" />\n    <Compile Include=\"entity\\item\\renderer\\ItemRenderer.cs\" />\n    <Compile Include=\"entity\\item\\renderer\\MovingAngledRenderer.cs\" />\n    <Compile Include=\"entity\\item\\renderer\\RendererRegistry.cs\" />\n    <Compile Include=\"entity\\item\\renderer\\StickRenderer.cs\" />\n    <Compile Include=\"entity\\item\\Reroller.cs\" />\n    <Compile Include=\"entity\\item\\SingleChoiceStand.cs\" />\n    <Compile Include=\"entity\\item\\SpawnMobsUse.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ActiveStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ArtifactStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\BkStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\BoxyStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\CustomStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\DarkMageStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\GarderobeStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\GobettaStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\GrannyStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\HatStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\HealChoiceStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\HealthStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ItemStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\LampStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\LampUnlockStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\PermanentStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\RogerStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ScourgedStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ShieldChoiceStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\ShopStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\SnekStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\TrashGoblinStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\VampireStand.cs\" />\n    <Compile Include=\"entity\\item\\stand\\WeaponStand.cs\" />\n    <Compile Include=\"entity\\item\\useCheck\\ItemUseCheck.cs\" />\n    <Compile Include=\"entity\\item\\useCheck\\ItemUseChecks.cs\" />\n    <Compile Include=\"entity\\item\\use\\AddHitboxUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\AddTorchUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\AffectDealChanceUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\BlankUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\BlindFoldUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\BlockDamageUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\BreakPiggyBankUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\BucketUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ChanceToUseWeaponUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DetonateBombsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DiscoverSideRoomsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoOnNewFloorUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoOnTimerUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoUsesIfUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ExplodeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\FireInAllDirsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GivePhaseUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveRandomPickupUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveScourgeImmunityUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\InvokeItemsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\LeaveLegoUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeBombsBlankUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeBombsExplodeOnTouchUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeBombsHomeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeItemsAttactUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectileExpandUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectileReshootUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesBlankOnDeathUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectileShrinkUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesHurtOnMissUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesKillWithBuffUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesSplitUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeRollKickProjectilesUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModEachAttackUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyArcUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyConsumableWeightsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyGenUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyManaMaxUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyManaUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyProjectileTextureUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyShootUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\PlaceDecoyUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\PokemonUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\PoofUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RegenUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ReplaceHeartsWithShieldsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ScourgeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoOnEnemyCollisionUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoWithUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DuplicateItemsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DuplicateMobsAndHealUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DuplicateMobsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\EnableScourgeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveBuffImmunityUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveBuffUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DoOnHurtUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveFlightUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveLaserAimUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GoThonkUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\KillMobUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesBoomerangUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyBombsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyLuckUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyStatsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\parent\\DoUsesUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\parent\\DoWithTagUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ConsumeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DigUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\DiscoverSecretRoomsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveBombUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveEmeraldsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveGoldUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveHeartContainersUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveItemUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveKeyUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\GiveWeaponUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ItemUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeLayerPassableUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesBounceUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesHomeInUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesShatternOnDeathUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesSlowDown.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeProjectilesSplitOnDeathUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MakeShopRestockUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\MeleeArcUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyActiveChargeUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyGameSaveValueUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyHpUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyShieldHeartsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyMaxHpUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyProjectilesUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ModifyStatUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\PreventDamageUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RandomActiveUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RandomUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RerollAndHideUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RerollItemsOnPlayerUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RerollItemsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\RevealMapUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SaleItemsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SetKnockbackModifierUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SetMaxHpUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SetMusicSpeed.cs\" />\n    <Compile Include=\"entity\\item\\use\\ShootLaserUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ShootQueueUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\ShootUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SimpleShootUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnBombUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnDropUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnItemsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnOrbitalUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnPetUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpawnProjectilesUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SpeedUpOrbitalsUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\SuperHotUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\TeleportToCursorUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\TeleportToPrevRoomUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\TeleportToShopUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\TeleportUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\TriggerHurtEventUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\UseOnEventUse.cs\" />\n    <Compile Include=\"entity\\item\\use\\UseRegistry.cs\" />\n    <Compile Include=\"entity\\item\\util\\MeleeArc.cs\" />\n    <Compile Include=\"entity\\item\\Weapon.cs\" />\n    <Compile Include=\"entity\\item\\WeaponType.cs\" />\n    <Compile Include=\"entity\\item\\WeaponTypeHelper.cs\" />\n    <Compile Include=\"entity\\Layers.cs\" />\n    <Compile Include=\"entity\\Lego.cs\" />\n    <Compile Include=\"entity\\orbital\\AnimatedOrbital.cs\" />\n    <Compile Include=\"entity\\orbital\\Marshmallow.cs\" />\n    <Compile Include=\"entity\\orbital\\Orbital.cs\" />\n    <Compile Include=\"entity\\orbital\\OrbitalRegistry.cs\" />\n    <Compile Include=\"entity\\orbital\\Prism.cs\" />\n    <Compile Include=\"entity\\pc\\Controller.cs\" />\n    <Compile Include=\"entity\\pc\\Pico.cs\" />\n    <Compile Include=\"entity\\pool\\Pool.cs\" />\n    <Compile Include=\"entity\\projectile\\BasicProjectileGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\BoomerangProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\ExpandProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\HsvProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\ShrinkProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\ReturnProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\SlowdownProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\SmokeProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\TargetProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\TimedProjectileController.cs\" />\n    <Compile Include=\"entity\\projectile\\controller\\WhatController.cs\" />\n    <Compile Include=\"entity\\projectile\\Laser.cs\" />\n    <Compile Include=\"entity\\projectile\\LaserGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\projectile\\LetterTemplateData.cs\" />\n    <Compile Include=\"entity\\projectile\\Missile.cs\" />\n    <Compile Include=\"entity\\projectile\\pattern\\CircleProjectilePattern.cs\" />\n    <Compile Include=\"entity\\projectile\\pattern\\CircleWithCenterProjectilePattern.cs\" />\n    <Compile Include=\"entity\\projectile\\pattern\\ExpandingCirclePattern.cs\" />\n    <Compile Include=\"entity\\projectile\\pattern\\KeepShapePattern.cs\" />\n    <Compile Include=\"entity\\projectile\\OldProjectile.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileBuilder.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileCallbacks.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileColor.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileFlags.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileGraphicsComponent.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileGraphicsEffect.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectilePattern.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileRegistry.cs\" />\n    <Compile Include=\"entity\\projectile\\ProjectileTemplate.cs\" />\n    <Compile Include=\"entity\\projectile\\Projectile.cs\" />\n    <Compile Include=\"entity\\RenderTrigger.cs\" />\n    <Compile Include=\"entity\\RenderTriggerManager.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\AlwaysOnSpikes.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\FireTrap.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\Piston.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\platform\\MovingPlatform.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\platform\\Platform.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\platform\\PlatformBorder.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\platform\\PlatformController.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\platform\\SteppingPlatform.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\RollingSpike.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\RoomControllable.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\spikes\\SensingSpikes.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\spikes\\Spikes.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\Support.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\turret\\QuadRotatingTurret.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\turret\\QuadTurret.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\turret\\RotatingTurret.cs\" />\n    <Compile Include=\"entity\\room\\controllable\\turret\\Turret.cs\" />\n    <Compile Include=\"entity\\room\\controller\\BossRoomController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\ChallengeRoomController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\FollowingSpikeBallController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\PistonActivatorController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\RoomController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\RoomControllerRegistery.cs\" />\n    <Compile Include=\"entity\\room\\controller\\SpikeFieldController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\TimedPistonSwitchController.cs\" />\n    <Compile Include=\"entity\\room\\controller\\TrapRoomController.cs\" />\n    <Compile Include=\"entity\\room\\input\\Button.cs\" />\n    <Compile Include=\"entity\\room\\input\\Lever.cs\" />\n    <Compile Include=\"entity\\room\\input\\PreasurePlate.cs\" />\n    <Compile Include=\"entity\\room\\input\\RoomInput.cs\" />\n    <Compile Include=\"entity\\room\\Room.cs\" />\n    <Compile Include=\"entity\\SpawnPoint.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\BkRageHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\BombHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\BombingHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\BuffHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\ChestHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\DarknessHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\FloorResetHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\GiveShieldHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\Happening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\HappeningRegistry.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\HealHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\HurtHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\ItemGiveHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\MakeItemsDamageUse.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\ModifyCoinsHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\ModifyMaxHpHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\RandomItemHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\RandomTypedItemHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\RerollHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\ScourgeHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\SlideHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\StealWeaponHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\happening\\TeleportHappening.cs\" />\n    <Compile Include=\"entity\\twitch\\LoginSign.cs\" />\n    <Compile Include=\"entity\\twitch\\TwitchBridge.cs\" />\n    <Compile Include=\"entity\\twitch\\TwitchExit.cs\" />\n    <Compile Include=\"entity\\twitch\\TwitchNpc.cs\" />\n    <Compile Include=\"entity\\twitch\\TwitchPet.cs\" />\n    <Compile Include=\"Events.cs\" />\n    <Compile Include=\"level\\biome\\Biome.cs\" />\n    <Compile Include=\"level\\biome\\BiomeAssets.cs\" />\n    <Compile Include=\"level\\biome\\BiomeInfo.cs\" />\n    <Compile Include=\"level\\biome\\BiomeRegistry.cs\" />\n    <Compile Include=\"level\\biome\\CastleBiome.cs\" />\n    <Compile Include=\"level\\biome\\CaveBiome.cs\" />\n    <Compile Include=\"level\\biome\\DesertBiome.cs\" />\n    <Compile Include=\"level\\biome\\JungleBiome.cs\" />\n    <Compile Include=\"level\\biome\\HubBiome.cs\" />\n    <Compile Include=\"level\\biome\\IceBiome.cs\" />\n    <Compile Include=\"level\\biome\\LibraryBiome.cs\" />\n    <Compile Include=\"level\\biome\\TechBiome.cs\" />\n    <Compile Include=\"level\\builders\\Builder.cs\" />\n    <Compile Include=\"level\\builders\\CastleBuilder.cs\" />\n    <Compile Include=\"level\\builders\\InfinityBuilder.cs\" />\n    <Compile Include=\"level\\builders\\LineBuilder.cs\" />\n    <Compile Include=\"level\\builders\\LoopBuilder.cs\" />\n    <Compile Include=\"level\\builders\\RegularBuilder.cs\" />\n    <Compile Include=\"level\\builders\\SingleRoomBuilder.cs\" />\n    <Compile Include=\"level\\challenge\\BombOnlyChallenge.cs\" />\n    <Compile Include=\"level\\challenge\\Challenge.cs\" />\n    <Compile Include=\"level\\challenge\\ChallengeRegistry.cs\" />\n    <Compile Include=\"level\\Chasm.cs\" />\n    <Compile Include=\"level\\ChasmBodyComponent.cs\" />\n    <Compile Include=\"level\\cutscene\\CutsceneLevel.cs\" />\n    <Compile Include=\"level\\cutscene\\CutsceneRoom.cs\" />\n    <Compile Include=\"level\\DoorPlaceholder.cs\" />\n    <Compile Include=\"level\\entities\\AchievementStatue.cs\" />\n    <Compile Include=\"level\\entities\\Belt.cs\" />\n    <Compile Include=\"level\\entities\\BreakableProp.cs\" />\n    <Compile Include=\"level\\entities\\building\\Thing.cs\" />\n    <Compile Include=\"level\\entities\\building\\House.cs\" />\n    <Compile Include=\"level\\entities\\Campfire.cs\" />\n    <Compile Include=\"level\\entities\\chest\\AnimatedChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\Chest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\ChestRegistry.cs\" />\n    <Compile Include=\"level\\entities\\chest\\DuckChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\GlassChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\ProtoChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\ScourgedChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\DoubleChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\GoldChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\RedChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\StoneChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\TreasureChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\TripleChest.cs\" />\n    <Compile Include=\"level\\entities\\chest\\WoodenChest.cs\" />\n    <Compile Include=\"level\\entities\\Claw.cs\" />\n    <Compile Include=\"level\\entities\\ClawControll.cs\" />\n    <Compile Include=\"level\\entities\\ContinueRun.cs\" />\n    <Compile Include=\"level\\entities\\Crystal.cs\" />\n    <Compile Include=\"level\\entities\\DailySign.cs\" />\n    <Compile Include=\"level\\entities\\decor\\BurningStatue.cs\" />\n    <Compile Include=\"level\\entities\\decor\\GrannyDecor.cs\" />\n    <Compile Include=\"level\\entities\\decor\\Lamp.cs\" />\n    <Compile Include=\"level\\entities\\decor\\Torch.cs\" />\n    <Compile Include=\"level\\entities\\decor\\Tree.cs\" />\n    <Compile Include=\"level\\entities\\decor\\WallTorch.cs\" />\n    <Compile Include=\"level\\entities\\DownBelt.cs\" />\n    <Compile Include=\"level\\entities\\Entrance.cs\" />\n    <Compile Include=\"level\\entities\\Exit.cs\" />\n    <Compile Include=\"level\\entities\\exit\\BossRushExit.cs\" />\n    <Compile Include=\"level\\entities\\exit\\ChallengeExit.cs\" />\n    <Compile Include=\"level\\entities\\exit\\DailyRunExit.cs\" />\n    <Compile Include=\"level\\entities\\exit\\ShortcutExit.cs\" />\n    <Compile Include=\"level\\entities\\exit\\TutorialExit.cs\" />\n    <Compile Include=\"level\\entities\\ExplodingBarrel.cs\" />\n    <Compile Include=\"level\\entities\\Gramophone.cs\" />\n    <Compile Include=\"level\\entities\\HiddenEntrance.cs\" />\n    <Compile Include=\"level\\entities\\HiddenExit.cs\" />\n    <Compile Include=\"level\\entities\\machine\\Charger.cs\" />\n    <Compile Include=\"level\\entities\\machine\\RerollMachine.cs\" />\n    <Compile Include=\"level\\entities\\machine\\VendingMachine.cs\" />\n    <Compile Include=\"level\\entities\\plant\\Plant.cs\" />\n    <Compile Include=\"level\\entities\\plant\\PlantGraphicsComponent.cs\" />\n    <Compile Include=\"level\\entities\\Portal.cs\" />\n    <Compile Include=\"level\\entities\\Prop.cs\" />\n    <Compile Include=\"level\\entities\\RightBelt.cs\" />\n    <Compile Include=\"level\\entities\\Safe.cs\" />\n    <Compile Include=\"level\\entities\\ShadowedProp.cs\" />\n    <Compile Include=\"level\\entities\\Sign.cs\" />\n    <Compile Include=\"level\\entities\\SlicedProp.cs\" />\n    <Compile Include=\"level\\entities\\SolidProp.cs\" />\n    <Compile Include=\"level\\entities\\Stand.cs\" />\n    <Compile Include=\"level\\entities\\StatDisplay.cs\" />\n    <Compile Include=\"level\\entities\\statue\\ChestStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\DiceStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\Fountain.cs\" />\n    <Compile Include=\"level\\entities\\statue\\GamepadStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\ScourgeStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\Statue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\StoneStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\SwordStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\WarriorStatue.cs\" />\n    <Compile Include=\"level\\entities\\statue\\Well.cs\" />\n    <Compile Include=\"level\\entities\\Teleporter.cs\" />\n    <Compile Include=\"level\\entities\\Tombstone.cs\" />\n    <Compile Include=\"level\\entities\\UpBelt.cs\" />\n    <Compile Include=\"level\\Flag.cs\" />\n    <Compile Include=\"level\\floors\\BathFloor.cs\" />\n    <Compile Include=\"level\\floors\\ChessFloor.cs\" />\n    <Compile Include=\"level\\floors\\DiagonalFloor.cs\" />\n    <Compile Include=\"level\\floors\\FancyFloor.cs\" />\n    <Compile Include=\"level\\floors\\FloorPainter.cs\" />\n    <Compile Include=\"level\\floors\\FloorRegistry.cs\" />\n    <Compile Include=\"level\\floors\\GeometryFloor.cs\" />\n    <Compile Include=\"level\\floors\\HoneycombFloor.cs\" />\n    <Compile Include=\"level\\floors\\LineFloor.cs\" />\n    <Compile Include=\"level\\floors\\MazeFloor.cs\" />\n    <Compile Include=\"level\\floors\\PatchFloor.cs\" />\n    <Compile Include=\"level\\floors\\TrippleFloor.cs\" />\n    <Compile Include=\"level\\HalfProjectileBodyComponent.cs\" />\n    <Compile Include=\"level\\HalfProjectileLevel.cs\" />\n    <Compile Include=\"level\\HalfWall.cs\" />\n    <Compile Include=\"level\\HalfWallBodyComponent.cs\" />\n    <Compile Include=\"level\\hall\\HallBuilder.cs\" />\n    <Compile Include=\"level\\hall\\HallLevel.cs\" />\n    <Compile Include=\"level\\hall\\HallRoom.cs\" />\n    <Compile Include=\"level\\Level.cs\" />\n    <Compile Include=\"level\\LevelBodyComponent.cs\" />\n    <Compile Include=\"level\\LevelTiler.cs\" />\n    <Compile Include=\"level\\Painter.cs\" />\n    <Compile Include=\"level\\paintings\\AnimatedPainting.cs\" />\n    <Compile Include=\"level\\paintings\\Painting.cs\" />\n    <Compile Include=\"level\\paintings\\PaintingRegistry.cs\" />\n    <Compile Include=\"level\\Patch.cs\" />\n    <Compile Include=\"level\\ProjectileBodyComponent.cs\" />\n    <Compile Include=\"level\\ProjectileLevelBody.cs\" />\n    <Compile Include=\"level\\RegularLevel.cs\" />\n    <Compile Include=\"level\\rooms\\boss\\BossRoom.cs\" />\n    <Compile Include=\"level\\rooms\\boss\\ChasmBossRoom.cs\" />\n    <Compile Include=\"level\\rooms\\boss\\CollumnsBossRoom.cs\" />\n    <Compile Include=\"level\\rooms\\boss\\FireTrapBossRoom.cs\" />\n    <Compile Include=\"level\\rooms\\challenge\\ChallengeRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\CabbadgeConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\ComplexTunnelRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\ConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\HoleConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\IceConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\IntersectionConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\LibraryConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\MazeConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\RingConnectionRoom.cs\" />\n    <Compile Include=\"level\\rooms\\connection\\TunnelRoom.cs\" />\n    <Compile Include=\"level\\rooms\\darkmarket\\DarkMarketRoom.cs\" />\n    <Compile Include=\"level\\rooms\\entrance\\EntranceRoom.cs\" />\n    <Compile Include=\"level\\rooms\\entrance\\EntranceWallPool.cs\" />\n    <Compile Include=\"level\\rooms\\entrance\\ExitRoom.cs\" />\n    <Compile Include=\"level\\rooms\\entrance\\PortalEntranceRoom.cs\" />\n    <Compile Include=\"level\\rooms\\granny\\GrannyRoom.cs\" />\n    <Compile Include=\"level\\rooms\\oldman\\OldManRoom.cs\" />\n    <Compile Include=\"level\\rooms\\payed\\PayedRoom.cs\" />\n    <Compile Include=\"level\\rooms\\preboss\\PrebossRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\EmptyRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\HiveRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\ItemTrollRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\JungleRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\PlatformChaosRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\PlatformLineRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\PlatformRingRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\RegularRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\TwoSidesRoom.cs\" />\n    <Compile Include=\"level\\rooms\\regular\\VerticalRegularRoom.cs\" />\n    <Compile Include=\"level\\rooms\\RoomDef.cs\" />\n    <Compile Include=\"level\\rooms\\RoomInfo.cs\" />\n    <Compile Include=\"level\\rooms\\RoomRegistry.cs\" />\n    <Compile Include=\"level\\rooms\\RoomType.cs\" />\n    <Compile Include=\"level\\rooms\\RoomTypeHelper.cs\" />\n    <Compile Include=\"level\\rooms\\scourged\\ScourgedRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\BirdSecretRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\GrannySecretRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretChasmRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretChestRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretDarkMarketEntranceRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretEmeraldGolemRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretItemRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretKeyRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretMachineRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretRoom.cs\" />\n    <Compile Include=\"level\\rooms\\secret\\SecretScourgeRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\ShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\sub\\ProtoShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\sub\\SnekShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\sub\\StorageRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\sub\\SubShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\shop\\sub\\VampireShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\ChargerRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\DarkMarketEntranceRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\DesertWellRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\HeartRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\IdolTrapRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\LockedRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\minigame\\ChestMinigameRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\minigame\\ClawMinigameRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\NpcKeyRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\NpcSaveRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\npc\\DuckRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\npc\\ElonRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\npc\\NurseRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\npc\\VampireRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\ProtoChestRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\SafeRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\BoxyShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\GobettaShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\NpcShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\RogerShopRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\SnekRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\shop\\TrashGoblinRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\SpecialRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\ChestStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\DiceStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\FountainRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\ScourgeStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\StatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\StoneStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\SwordStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\WarriorStatueRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\statue\\WellRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\TombRoom.cs\" />\n    <Compile Include=\"level\\rooms\\special\\VendingRoom.cs\" />\n    <Compile Include=\"level\\rooms\\spiked\\SpikedRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\CrossTurretPassageRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\DangerousPadsRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\FollowingSpikeBallRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\RollingSpikesRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\SpikeMazeRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\SpikePassageRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\TrapRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\TurretPassageRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\TurretTrapRoom.cs\" />\n    <Compile Include=\"level\\rooms\\trap\\VerticalTurretPassageRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\AcrossTreasureRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\HoleTreasureRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\PadTreasureRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\PlatformTreasureRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\TreasureRoom.cs\" />\n    <Compile Include=\"level\\rooms\\treasure\\TwoDiagonalTreasureRoom.cs\" />\n    <Compile Include=\"level\\tile\\Tile.cs\" />\n    <Compile Include=\"level\\tile\\TileFlags.cs\" />\n    <Compile Include=\"level\\tile\\Tiles.cs\" />\n    <Compile Include=\"level\\tile\\Tileset.cs\" />\n    <Compile Include=\"level\\tile\\Tilesets.cs\" />\n    <Compile Include=\"level\\tutorial\\TutorialLevel.cs\" />\n    <Compile Include=\"level\\tutorial\\TutorialRoom.cs\" />\n    <Compile Include=\"level\\tutorial\\TutorialStand.cs\" />\n    <Compile Include=\"level\\variant\\ChasmLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\FloodedLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\ForestLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\GoldLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\LevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\RaveCaveVariant.cs\" />\n    <Compile Include=\"level\\variant\\RegularLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\SandLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\SnowLevelVariant.cs\" />\n    <Compile Include=\"level\\variant\\VariantInfo.cs\" />\n    <Compile Include=\"level\\variant\\VariantRegistry.cs\" />\n    <Compile Include=\"level\\variant\\WebbedLevelVariant.cs\" />\n    <Compile Include=\"level\\walls\\CollumnWall.cs\" />\n    <Compile Include=\"level\\walls\\CollumsWall.cs\" />\n    <Compile Include=\"level\\walls\\CorneredTurretWall.cs\" />\n    <Compile Include=\"level\\walls\\CornerWall.cs\" />\n    <Compile Include=\"level\\walls\\EllipseWalls.cs\" />\n    <Compile Include=\"level\\walls\\library\\LibraryWallPainter.cs\" />\n    <Compile Include=\"level\\walls\\library\\TeleportSplitWall.cs\" />\n    <Compile Include=\"level\\walls\\MazeWall.cs\" />\n    <Compile Include=\"level\\walls\\PatchWall.cs\" />\n    <Compile Include=\"level\\walls\\PlatformWall.cs\" />\n    <Compile Include=\"level\\walls\\RuinsWall.cs\" />\n    <Compile Include=\"level\\walls\\SegmentedWall.cs\" />\n    <Compile Include=\"level\\walls\\SplitWall.cs\" />\n    <Compile Include=\"level\\walls\\TempleWalls.cs\" />\n    <Compile Include=\"level\\walls\\TurretWall.cs\" />\n    <Compile Include=\"level\\walls\\WallPainter.cs\" />\n    <Compile Include=\"level\\walls\\WallRegistry.cs\" />\n    <Compile Include=\"level\\Weather.cs\" />\n    <Compile Include=\"physics\\CollisionFilterEntity.cs\" />\n    <Compile Include=\"physics\\CollisionResult.cs\" />\n    <Compile Include=\"physics\\Physics.cs\" />\n    <Compile Include=\"physics\\PhysicsDebugRenderer.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"save\\cloud\\CloudFileReader.cs\" />\n    <Compile Include=\"save\\cloud\\CloudFileWriter.cs\" />\n    <Compile Include=\"save\\EntitySaver.cs\" />\n    <Compile Include=\"save\\GameSave.cs\" />\n    <Compile Include=\"save\\GlobalSave.cs\" />\n    <Compile Include=\"save\\LevelSave.cs\" />\n    <Compile Include=\"save\\PlayerSave.cs\" />\n    <Compile Include=\"save\\PrefabData.cs\" />\n    <Compile Include=\"save\\PrefabSaver.cs\" />\n    <Compile Include=\"save\\SaveDebug.cs\" />\n    <Compile Include=\"save\\SaveLock.cs\" />\n    <Compile Include=\"save\\Saver.cs\" />\n    <Compile Include=\"save\\SaveType.cs\" />\n    <Compile Include=\"save\\SaveableEntity.cs\" />\n    <Compile Include=\"save\\SaveManager.cs\" />\n    <Compile Include=\"save\\SecretSave.cs\" />\n    <Compile Include=\"save\\StatisticsSaver.cs\" />\n    <Compile Include=\"save\\statistics\\RunStatistics.cs\" />\n    <Compile Include=\"Settings.cs\" />\n    <Compile Include=\"state\\AreaDebug.cs\" />\n    <Compile Include=\"state\\AssetLoadState.cs\" />\n    <Compile Include=\"state\\Credits.cs\" />\n    <Compile Include=\"state\\CutsceneState.cs\" />\n    <Compile Include=\"state\\DevAssetLoadState.cs\" />\n    <Compile Include=\"state\\DialogEditorState.cs\" />\n    <Compile Include=\"state\\Editor.cs\" />\n    <Compile Include=\"state\\EditorState.cs\" />\n    <Compile Include=\"state\\InGameAudio.cs\" />\n    <Compile Include=\"state\\InGameState.cs\" />\n    <Compile Include=\"state\\ItemEditor.cs\" />\n    <Compile Include=\"state\\LoadState.cs\" />\n    <Compile Include=\"state\\LogoRenderer.cs\" />\n    <Compile Include=\"state\\PhotoCard.cs\" />\n    <Compile Include=\"state\\PicoState.cs\" />\n    <Compile Include=\"state\\RoomEditorState.cs\" />\n    <Compile Include=\"state\\Run.cs\" />\n    <Compile Include=\"state\\RunType.cs\" />\n    <Compile Include=\"state\\save\\EntityData.cs\" />\n    <Compile Include=\"state\\save\\EntityInspector.cs\" />\n    <Compile Include=\"state\\save\\GameInspector.cs\" />\n    <Compile Include=\"state\\save\\GlobalInspector.cs\" />\n    <Compile Include=\"state\\save\\SaveData.cs\" />\n    <Compile Include=\"state\\save\\SaveExplorerState.cs\" />\n    <Compile Include=\"state\\save\\SaveGroup.cs\" />\n    <Compile Include=\"state\\save\\SaveInspector.cs\" />\n    <Compile Include=\"state\\save\\SaveNode.cs\" />\n    <Compile Include=\"Tags.cs\" />\n    <Compile Include=\"ui\\AchievementBanner.cs\" />\n    <Compile Include=\"ui\\ButtonType.cs\" />\n    <Compile Include=\"ui\\dialog\\AnswerDialog.cs\" />\n    <Compile Include=\"ui\\dialog\\AnswerType.cs\" />\n    <Compile Include=\"ui\\dialog\\ChoiceDialog.cs\" />\n    <Compile Include=\"ui\\dialog\\CombineDialog.cs\" />\n    <Compile Include=\"ui\\dialog\\Dialog.cs\" />\n    <Compile Include=\"ui\\dialog\\DialogComponent.cs\" />\n    <Compile Include=\"ui\\dialog\\DialogNode.cs\" />\n    <Compile Include=\"ui\\dialog\\EventDialog.cs\" />\n    <Compile Include=\"ui\\dialog\\UiDialog.cs\" />\n    <Compile Include=\"ui\\editor\\command\\Command.cs\" />\n    <Compile Include=\"ui\\editor\\command\\CommandQueue.cs\" />\n    <Compile Include=\"ui\\editor\\command\\FillCommand.cs\" />\n    <Compile Include=\"ui\\editor\\command\\SetCommand.cs\" />\n    <Compile Include=\"ui\\editor\\CursorMode.cs\" />\n    <Compile Include=\"ui\\editor\\EntityEditor.cs\" />\n    <Compile Include=\"ui\\editor\\PlaceableEntity.cs\" />\n    <Compile Include=\"ui\\editor\\EditorWindow.cs\" />\n    <Compile Include=\"ui\\editor\\TileEditor.cs\" />\n    <Compile Include=\"ui\\editor\\TileInfo.cs\" />\n    <Compile Include=\"ui\\editor\\TypeInfo.cs\" />\n    <Compile Include=\"ui\\FrameRenderer.cs\" />\n    <Compile Include=\"ui\\HealthBar.cs\" />\n    <Compile Include=\"ui\\imgui\\DebugWindow.cs\" />\n    <Compile Include=\"ui\\imgui\\DialogEditor.cs\" />\n    <Compile Include=\"ui\\imgui\\DrawVertDeclaration.cs\" />\n    <Compile Include=\"ui\\imgui\\ImConnection.cs\" />\n    <Compile Include=\"ui\\imgui\\ImGuiRenderer.cs\" />\n    <Compile Include=\"ui\\imgui\\ImNodes.cs\" />\n    <Compile Include=\"ui\\imgui\\LocaleEditor.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImAnswerNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImChoiceNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImDialogNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImOrdNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImNodeRegistry.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImTextInputNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImTextNode.cs\" />\n    <Compile Include=\"ui\\imgui\\node\\ImTextOutputNode.cs\" />\n    <Compile Include=\"ui\\imgui\\WindowManager.cs\" />\n    <Compile Include=\"ui\\inventory\\UiActiveItemSlot.cs\" />\n    <Compile Include=\"ui\\inventory\\UiWeaponSlot.cs\" />\n    <Compile Include=\"ui\\inventory\\UiInventory.cs\" />\n    <Compile Include=\"ui\\inventory\\UiItem.cs\" />\n    <Compile Include=\"ui\\SaveIndicator.cs\" />\n    <Compile Include=\"ui\\str\\effect\\BlinkEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\BoldEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\ColorEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\FlipEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\GlyphEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\ItalicEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\RainbowEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\RandomEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\ShakeEffect.cs\" />\n    <Compile Include=\"ui\\str\\effect\\WaveEffect.cs\" />\n    <Compile Include=\"ui\\str\\event\\DelayEvent.cs\" />\n    <Compile Include=\"ui\\str\\event\\GlyphEvent.cs\" />\n    <Compile Include=\"ui\\str\\event\\SkipEvent.cs\" />\n    <Compile Include=\"ui\\str\\event\\SpeedEvent.cs\" />\n    <Compile Include=\"ui\\str\\event\\UserEvent.cs\" />\n    <Compile Include=\"ui\\str\\Glyph.cs\" />\n    <Compile Include=\"ui\\str\\IconRenderer.cs\" />\n    <Compile Include=\"ui\\str\\StrRenderer.cs\" />\n    <Compile Include=\"ui\\str\\UiString.cs\" />\n    <Compile Include=\"ui\\UiAchievement.cs\" />\n    <Compile Include=\"ui\\UiAnimation.cs\" />\n    <Compile Include=\"ui\\UiBanner.cs\" />\n    <Compile Include=\"ui\\UiButton.cs\" />\n    <Compile Include=\"ui\\UiChat.cs\" />\n    <Compile Include=\"ui\\UiCheckbox.cs\" />\n    <Compile Include=\"ui\\UiChoice.cs\" />\n    <Compile Include=\"ui\\UiControl.cs\" />\n    <Compile Include=\"ui\\UiDescriptionBanner.cs\" />\n    <Compile Include=\"ui\\UiEntity.cs\" />\n    <Compile Include=\"ui\\UiError.cs\" />\n    <Compile Include=\"ui\\UiImageButton.cs\" />\n    <Compile Include=\"ui\\UiLabel.cs\" />\n    <Compile Include=\"ui\\UiMap.cs\" />\n    <Compile Include=\"ui\\UiPane.cs\" />\n    <Compile Include=\"ui\\UiSlider.cs\" />\n    <Compile Include=\"ui\\UiTable.cs\" />\n    <Compile Include=\"ui\\UiTableEntry.cs\" />\n    <Compile Include=\"util\\AnimationUtil.cs\" />\n    <Compile Include=\"util\\ArrayUtils.cs\" />\n    <Compile Include=\"util\\BArray.cs\" />\n    <Compile Include=\"util\\BiomeTitles.cs\" />\n    <Compile Include=\"util\\Birthday.cs\" />\n    <Compile Include=\"util\\BitHelper.cs\" />\n    <Compile Include=\"util\\CollisionHelper.cs\" />\n    <Compile Include=\"util\\Direction.cs\" />\n    <Compile Include=\"util\\Directions.cs\" />\n    <Compile Include=\"util\\FollowingDriver.cs\" />\n    <Compile Include=\"util\\geometry\\Dot.cs\" />\n    <Compile Include=\"util\\geometry\\Rect.cs\" />\n    <Compile Include=\"util\\ImJson.cs\" />\n    <Compile Include=\"util\\JsonCounter.cs\" />\n    <Compile Include=\"util\\Line.cs\" />\n    <Compile Include=\"util\\LoadScreenJokes.cs\" />\n    <Compile Include=\"util\\LoadScreenTips.cs\" />\n    <Compile Include=\"util\\Maze.cs\" />\n    <Compile Include=\"util\\PathFinder.cs\" />\n    <Compile Include=\"util\\Titles.cs\" />\n    <Compile Include=\"util\\Vec2.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Aseprite\\Aseprite.csproj\">\n      <Project>{13c6f252-0b3c-4a22-a9db-270c76657fab}</Project>\n      <Name>Aseprite</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\Lens\\Lens.csproj\">\n      <Project>{3b26aa2e-0ba2-42dc-ad62-e6c8617f9e4d}</Project>\n      <Name>Lens</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\MonoGamePico8\\MonoGamePico8.csproj\">\n      <Project>{ba524303-7074-4c9e-8650-59e2c1293a56}</Project>\n      <Name>MonoGamePico8</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\Pico8Emulator\\Pico8Emulator.csproj\">\n      <Project>{ec0602b1-5a17-4cdc-bbb7-f2c5401ff899}</Project>\n      <Name>Pico8Emulator</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\VelcroPhysics\\VelcroPhysics.MonoGame.csproj\">\n      <Project>{4650bd15-4b03-4a7e-98d4-9f8697ed2eb4}</Project>\n      <Name>VelcroPhysics.MonoGame</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"./Content/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Dialogs/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/bin/**\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/obj/**\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Music/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/items.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Loot/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Locales/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Fonts/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Prefabs/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Animations/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Textures/*\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/Mods/**\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/bin/**\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"./Content/obj/**\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"Content\\Shaders\\bk.fx\" />\n    <Content Include=\"Content\\Shaders\\chasm.fx\" />\n    <Content Include=\"Content\\Shaders\\entity.fx\" />\n    <Content Include=\"Content\\Shaders\\fog.fx\" />\n    <Content Include=\"Content\\Shaders\\item.fx\" />\n    <Content Include=\"Content\\Shaders\\screen.fx\" />\n    <Content Include=\"Content\\Shaders\\terrain.fx\" />\n    <Content Include=\"Content\\Shaders\\ui.fx\" />\n    <Content Include=\"CppNet.dll\" />\n    <Content Include=\"libmojoshader_64.dll\" />\n    <Content Include=\"mgfxc.deps.json\" />\n    <Content Include=\"mgfxc.dll\" />\n    <Content Include=\"mgfxc.exe\" />\n    <Content Include=\"mgfxc.pdb\" />\n    <Content Include=\"mgfxc.runtimeconfig.dev.json\" />\n    <Content Include=\"mgfxc.runtimeconfig.json\" />\n    <Content Include=\"README.md\" />\n    <Content Include=\"SharpDX.D3DCompiler.dll\" />\n    <Content Include=\"SharpDX.D3DCompiler.xml\" />\n    <Content Include=\"SharpDX.dll\" />\n    <Content Include=\"SharpDX.xml\" />\n    <Content Include=\"steam_api64.dll\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <Import Project=\"..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets\" Condition=\"Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" />\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets'))\" />\n  </Target>\n  <Import Project=\"..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets\" Condition=\"Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n         Other similar extension points exist, see Microsoft.Common.targets.\n    <Target Name=\"BeforeBuild\">\n    </Target>\n    <Target Name=\"AfterBuild\">\n    </Target>\n    -->\n</Project>\n"
  },
  {
    "path": "BurningKnight/Content/Content.mgcb",
    "content": "\n#----------------------------- Global Properties ----------------------------#\n\n/outputDir:bin\n/intermediateDir:obj\n/platform:DesktopGL\n/config:\n/profile:Reach\n/compress:False\n\n#-------------------------------- References --------------------------------#\n\n/reference:..\\..\\Aseprite\\bin\\Debug\\Aseprite.dll\n/reference:..\\..\\packages\\MonoGame.Framework.Content.Pipeline.Portable.3.7.0.1708\\lib\\portable-net45+win8+wpa81\\MonoGame.Framework.Content.Pipeline.dll\n/reference:..\\..\\packages\\MonoGame.Extended.Content.Pipeline.1.1.0\\tools\\MonoGame.Extended.Content.Pipeline.dll\n\n#---------------------------------- Content ---------------------------------#\n\n#begin Fonts/fnt.spritefont\n/importer:FontDescriptionImporter\n/processor:FontDescriptionProcessor\n/processorParam:PremultiplyAlpha=False\n/processorParam:TextureFormat=Compressed\n/build:Fonts/fnt.spritefont\n\n#begin Fonts/large.png\n/importer:TextureImporter\n/processor:TextureProcessor\n/processorParam:ColorKeyColor=255,0,255,255\n/processorParam:ColorKeyEnabled=True\n/processorParam:GenerateMipmaps=False\n/processorParam:PremultiplyAlpha=True\n/processorParam:ResizeToPowerOfTwo=False\n/processorParam:MakeSquare=False\n/processorParam:TextureFormat=Color\n/build:Fonts/large.png\n\n#begin Fonts/small.png\n/importer:TextureImporter\n/processor:TextureProcessor\n/processorParam:ColorKeyColor=255,0,255,255\n/processorParam:ColorKeyEnabled=True\n/processorParam:GenerateMipmaps=False\n/processorParam:PremultiplyAlpha=True\n/processorParam:ResizeToPowerOfTwo=False\n/processorParam:MakeSquare=False\n/processorParam:TextureFormat=Color\n/build:Fonts/small.png\n\n#begin Music/Believer.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Believer.ogg\n\n#begin Music/BK.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/BK.ogg\n\n#begin Music/Born to do rogueries.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Born to do rogueries.ogg\n\n#begin Music/Botanical Expedition.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Botanical Expedition.ogg\n\n#begin Music/chip.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/chip.ogg\n\n#begin Music/Cursed legend.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Cursed legend.ogg\n\n#begin Music/Fatiga.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Fatiga.ogg\n\n#begin Music/Frozen to the bones.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Frozen to the bones.ogg\n\n#begin Music/Gobbeon.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Gobbeon.ogg\n\n#begin Music/Hidden knowledge.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Hidden knowledge.ogg\n\n#begin Music/Hub.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Hub.ogg\n\n#begin Music/Last chance.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Last chance.ogg\n\n#begin Music/Ma Precious.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Ma Precious.ogg\n\n#begin Music/Menu.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Menu.ogg\n\n#begin Music/My precious.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/My precious.ogg\n\n#begin Music/Nostalgia.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Nostalgia.ogg\n\n#begin Music/Outsider.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Outsider.ogg\n\n#begin Music/piano.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/piano.ogg\n\n#begin Music/Pirate Bay.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Pirate Bay.ogg\n\n#begin Music/Reckless.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Reckless.ogg\n\n#begin Music/Serendipity.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Serendipity.ogg\n\n#begin Music/Shopkeeper.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Shopkeeper.ogg\n\n#begin Music/Void.ogg\n/importer:OggImporter\n/processor:SongProcessor\n/processorParam:Quality=Best\n/build:Music/Void.ogg\n\n#begin Sfx/airhorn.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/airhorn.wav\n\n#begin Sfx/bomb_placed.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/bomb_placed.wav\n\n#begin Sfx/clap.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/clap.wav\n\n#begin Sfx/dead1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/dead1.wav\n\n#begin Sfx/dead2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/dead2.wav\n\n#begin Sfx/dead3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/dead3.wav\n\n#begin Sfx/enemy_alert.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/enemy_alert.wav\n\n#begin Sfx/explosion.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/explosion.wav\n\n#begin Sfx/fireball_cast.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/fireball_cast.wav\n\n#begin Sfx/fireball_death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/fireball_death.wav\n\n#begin Sfx/gunner_charge.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/gunner_charge.wav\n\n#begin Sfx/health_up.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/health_up.wav\n\n#begin Sfx/hi.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/hi.wav\n\n#begin Sfx/hurt1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/hurt1.wav\n\n#begin Sfx/hurt2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/hurt2.wav\n\n#begin Sfx/item/active.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/active.wav\n\n#begin Sfx/item/active_charged.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/active_charged.wav\n\n#begin Sfx/item/axe/catch.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/axe/catch.wav\n\n#begin Sfx/item/axe/throw.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/axe/throw.wav\n\n#begin Sfx/item/bag.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/bag.wav\n\n#begin Sfx/item/bomb.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/bomb.wav\n\n#begin Sfx/item/bow/attack.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/bow/attack.wav\n\n#begin Sfx/item/cage_key_used.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/cage_key_used.wav\n\n#begin Sfx/item/charge.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/charge.wav\n\n#begin Sfx/item/coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/coin.wav\n\n#begin Sfx/item/dice/bad.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/dice/bad.wav\n\n#begin Sfx/item/dice/break.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/dice/break.wav\n\n#begin Sfx/item/dice/good.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/dice/good.wav\n\n#begin Sfx/item/discord.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/discord.wav\n\n#begin Sfx/item/emerald.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/emerald.wav\n\n#begin Sfx/item/gold_coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gold_coin.wav\n\n#begin Sfx/item/gun/burst.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/burst.wav\n\n#begin Sfx/item/gun/fire/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/fire/1.wav\n\n#begin Sfx/item/gun/fire/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/fire/2.wav\n\n#begin Sfx/item/gun/machine.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/machine.wav\n\n#begin Sfx/item/gun/pickup.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/pickup.wav\n\n#begin Sfx/item/gun/switch.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/gun/switch.wav\n\n#begin Sfx/item/heart.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/heart.wav\n\n#begin Sfx/item/key.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/key.wav\n\n#begin Sfx/item/key_pickup.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/key_pickup.wav\n\n#begin Sfx/item/laser/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/laser/1.wav\n\n#begin Sfx/item/laser/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/laser/2.wav\n\n#begin Sfx/item/laser/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/laser/3.wav\n\n#begin Sfx/item/laser/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/laser/4.wav\n\n#begin Sfx/item/laser/player.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/laser/player.wav\n\n#begin Sfx/item/magic/lava/lava_appear.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/lava/lava_appear.wav\n\n#begin Sfx/item/magic/lava/lava_cast.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/lava/lava_cast.wav\n\n#begin Sfx/item/magic/pickup.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/pickup.wav\n\n#begin Sfx/item/magic/switch.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/switch.wav\n\n#begin Sfx/item/magic/web/appear.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/web/appear.wav\n\n#begin Sfx/item/magic/web/cast.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/magic/web/cast.wav\n\n#begin Sfx/item/mana.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/mana.wav\n\n#begin Sfx/item/map.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/map.wav\n\n#begin Sfx/item/meatguy/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/meatguy/1.wav\n\n#begin Sfx/item/meatguy/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/meatguy/2.wav\n\n#begin Sfx/item/meatguy/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/meatguy/3.wav\n\n#begin Sfx/item/meatguy/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/meatguy/4.wav\n\n#begin Sfx/item/nocash.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/nocash.wav\n\n#begin Sfx/item/orbitals.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/orbitals.wav\n\n#begin Sfx/item/pickup.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/pickup.wav\n\n#begin Sfx/item/platinum_coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/platinum_coin.wav\n\n#begin Sfx/item/purchase.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/purchase.wav\n\n#begin Sfx/item/reroll.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/reroll.wav\n\n#begin Sfx/item/shield.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/shield.wav\n\n#begin Sfx/item/shotgun/fire/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/shotgun/fire/1.wav\n\n#begin Sfx/item/shotgun/fire/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/shotgun/fire/2.wav\n\n#begin Sfx/item/shotgun/reload/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/shotgun/reload/1.wav\n\n#begin Sfx/item/shotgun/reload/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/shotgun/reload/2.wav\n\n#begin Sfx/item/silver_coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/silver_coin.wav\n\n#begin Sfx/item/sword/attack/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/attack/1.wav\n\n#begin Sfx/item/sword/attack/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/attack/2.wav\n\n#begin Sfx/item/sword/attack/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/attack/3.wav\n\n#begin Sfx/item/sword/attack/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/attack/4.wav\n\n#begin Sfx/item/sword/cooldown.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/cooldown.wav\n\n#begin Sfx/item/sword/hit/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/hit/1.wav\n\n#begin Sfx/item/sword/hit/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/hit/2.wav\n\n#begin Sfx/item/sword/hit/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/hit/3.wav\n\n#begin Sfx/item/sword/hit/wall.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/hit/wall.wav\n\n#begin Sfx/item/sword/pickup.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/pickup.wav\n\n#begin Sfx/item/sword/switch.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/sword/switch.wav\n\n#begin Sfx/item/ukulele/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/ukulele/1.wav\n\n#begin Sfx/item/ukulele/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/ukulele/2.wav\n\n#begin Sfx/item/ukulele/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/ukulele/3.wav\n\n#begin Sfx/item/ukulele/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/ukulele/4.wav\n\n#begin Sfx/item/ukulele/5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/ukulele/5.wav\n\n#begin Sfx/item/wand/fire.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/wand/fire.wav\n\n#begin Sfx/item/wand/general.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/item/wand/general.wav\n\n#begin Sfx/level/chair/break/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/chair/break/1.wav\n\n#begin Sfx/level/chair/break/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/chair/break/2.wav\n\n#begin Sfx/level/chest_open.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/chest_open.wav\n\n#begin Sfx/level/claw/close.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/close.wav\n\n#begin Sfx/level/claw/move.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/move.wav\n\n#begin Sfx/level/claw/open.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/open.wav\n\n#begin Sfx/level/claw/pc.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/pc.wav\n\n#begin Sfx/level/claw/start.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/start.wav\n\n#begin Sfx/level/claw/stop.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/claw/stop.wav\n\n#begin Sfx/level/cleared.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/cleared.wav\n\n#begin Sfx/level/cup/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/cup/1.wav\n\n#begin Sfx/level/cup/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/cup/2.wav\n\n#begin Sfx/level/door/bell.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/bell.wav\n\n#begin Sfx/level/door/close/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/close/1.wav\n\n#begin Sfx/level/door/close/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/close/2.wav\n\n#begin Sfx/level/door/head/fail.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/head/fail.wav\n\n#begin Sfx/level/door/head/success.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/head/success.wav\n\n#begin Sfx/level/door/open/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/open/1.wav\n\n#begin Sfx/level/door/open/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/open/2.wav\n\n#begin Sfx/level/door/open/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/open/3.wav\n\n#begin Sfx/level/door/open/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/open/4.wav\n\n#begin Sfx/level/door/open/5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/open/5.wav\n\n#begin Sfx/level/door/shut.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/door/shut.wav\n\n#begin Sfx/level/explosion/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/explosion/1.wav\n\n#begin Sfx/level/explosion/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/explosion/2.wav\n\n#begin Sfx/level/explosion/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/explosion/3.wav\n\n#begin Sfx/level/lever.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/lever.wav\n\n#begin Sfx/level/rain/jungle.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/rain/jungle.wav\n\n#begin Sfx/level/rain/regular.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/rain/regular.wav\n\n#begin Sfx/level/rain/snow.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/rain/snow.wav\n\n#begin Sfx/level/rock/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/rock/1.wav\n\n#begin Sfx/level/rock/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/rock/2.wav\n\n#begin Sfx/level/room_cleared.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/room_cleared.wav\n\n#begin Sfx/level/scourge_statue.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/scourge_statue.wav\n\n#begin Sfx/level/snow_break/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/snow_break/1.wav\n\n#begin Sfx/level/snow_break/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/snow_break/2.wav\n\n#begin Sfx/level/snow_break/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/snow_break/3.wav\n\n#begin Sfx/level/spike.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/spike.wav\n\n#begin Sfx/level/spike_peaking.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/spike_peaking.wav\n\n#begin Sfx/level/statue_break.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/statue_break.wav\n\n#begin Sfx/level/stone_statue_break.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/stone_statue_break.wav\n\n#begin Sfx/level/summon_chest.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/summon_chest.wav\n\n#begin Sfx/level/teleport/arrive.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/teleport/arrive.wav\n\n#begin Sfx/level/teleport/send.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/teleport/send.wav\n\n#begin Sfx/level/tnt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/tnt.wav\n\n#begin Sfx/level/turret/fire.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/turret/fire.wav\n\n#begin Sfx/level/turret/rotating.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/turret/rotating.wav\n\n#begin Sfx/level/vending_machine.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/vending_machine.wav\n\n#begin Sfx/level/vending_machine_coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/vending_machine_coin.wav\n\n#begin Sfx/level/well.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/well.wav\n\n#begin Sfx/level/well_coin.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/level/well_coin.wav\n\n#begin Sfx/mob/archeolog/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/archeolog/death.wav\n\n#begin Sfx/mob/archeolog/explosion.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/archeolog/explosion.wav\n\n#begin Sfx/mob/archeolog/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/archeolog/hurt.wav\n\n#begin Sfx/mob/bandit/damage.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bandit/damage.wav\n\n#begin Sfx/mob/bandit/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bandit/death.wav\n\n#begin Sfx/mob/bee/damage.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bee/damage.wav\n\n#begin Sfx/mob/bee/shot.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bee/shot.wav\n\n#begin Sfx/mob/bee/swirly_shot.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bee/swirly_shot.wav\n\n#begin Sfx/mob/bk/capture.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/capture.wav\n\n#begin Sfx/mob/bk/fight_loop.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/fight_loop.wav\n\n#begin Sfx/mob/bk/fire.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/fire.wav\n\n#begin Sfx/mob/bk/flame_loop.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/flame_loop.wav\n\n#begin Sfx/mob/bk/hovering_loop.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hovering_loop.wav\n\n#begin Sfx/mob/bk/hurt/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hurt/1.wav\n\n#begin Sfx/mob/bk/hurt/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hurt/2.wav\n\n#begin Sfx/mob/bk/hurt/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hurt/3.wav\n\n#begin Sfx/mob/bk/hurt/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hurt/4.wav\n\n#begin Sfx/mob/bk/hurt/5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/hurt/5.wav\n\n#begin Sfx/mob/bk/roar/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/roar/1.wav\n\n#begin Sfx/mob/bk/roar/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/roar/2.wav\n\n#begin Sfx/mob/bk/roar/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/roar/3.wav\n\n#begin Sfx/mob/bk/roar/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/roar/4.wav\n\n#begin Sfx/mob/bk/syllable/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/syllable/1.wav\n\n#begin Sfx/mob/bk/syllable/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/syllable/2.wav\n\n#begin Sfx/mob/bk/syllable/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/syllable/3.wav\n\n#begin Sfx/mob/bk/syllable/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/syllable/4.wav\n\n#begin Sfx/mob/bk/syllable/5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/syllable/5.wav\n\n#begin Sfx/mob/bk/voice.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/voice.wav\n\n#begin Sfx/mob/bk/wave.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/wave.wav\n\n#begin Sfx/mob/bk/word/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/word/1.wav\n\n#begin Sfx/mob/bk/word/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/word/2.wav\n\n#begin Sfx/mob/bk/word/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/bk/word/3.wav\n\n#begin Sfx/mob/clown/bomb/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/clown/bomb/1.wav\n\n#begin Sfx/mob/clown/bomb/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/clown/bomb/2.wav\n\n#begin Sfx/mob/clown/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/clown/death.wav\n\n#begin Sfx/mob/clown/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/clown/hurt.wav\n\n#begin Sfx/mob/dino/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/dino/death.wav\n\n#begin Sfx/mob/dino/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/dino/hurt.wav\n\n#begin Sfx/mob/dummy.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/dummy.wav\n\n#begin Sfx/mob/fire.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/fire.wav\n\n#begin Sfx/mob/fire_static.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/fire_static.wav\n\n#begin Sfx/mob/fire_wall.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/fire_wall.wav\n\n#begin Sfx/mob/flower/charging.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/flower/charging.wav\n\n#begin Sfx/mob/flower/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/flower/death.wav\n\n#begin Sfx/mob/flower/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/flower/hurt.wav\n\n#begin Sfx/mob/fly_death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/fly_death.wav\n\n#begin Sfx/mob/ghost/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/ghost/death.wav\n\n#begin Sfx/mob/ghost/hurt_1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/ghost/hurt_1.wav\n\n#begin Sfx/mob/ghost/hurt_2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/ghost/hurt_2.wav\n\n#begin Sfx/mob/gunner/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/gunner/death.wav\n\n#begin Sfx/mob/gunner/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/gunner/hurt.wav\n\n#begin Sfx/mob/hive/breaking.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hive/breaking.wav\n\n#begin Sfx/mob/hive/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hive/hurt.wav\n\n#begin Sfx/mob/hive/pop.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hive/pop.wav\n\n#begin Sfx/mob/hive/release.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hive/release.wav\n\n#begin Sfx/mob/hive/static.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hive/static.wav\n\n#begin Sfx/mob/hugger_death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/hugger_death.wav\n\n#begin Sfx/mob/mummy/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/mummy/death.wav\n\n#begin Sfx/mob/mummy/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/mummy/hurt.wav\n\n#begin Sfx/mob/oldking/explode.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/oldking/explode.wav\n\n#begin Sfx/mob/oldking/jump.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/oldking/jump.wav\n\n#begin Sfx/mob/oldking/land.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/oldking/land.wav\n\n#begin Sfx/mob/oldking/shoot.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/oldking/shoot.wav\n\n#begin Sfx/mob/pharaoh/adidos.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/pharaoh/adidos.wav\n\n#begin Sfx/mob/pharaoh/appear.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/pharaoh/appear.wav\n\n#begin Sfx/mob/pharaoh/shot.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/pharaoh/shot.wav\n\n#begin Sfx/mob/pharaoh/shot_wave.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/pharaoh/shot_wave.wav\n\n#begin Sfx/mob/pharaoh/summon.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/pharaoh/summon.wav\n\n#begin Sfx/mob/skeleton/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/skeleton/death.wav\n\n#begin Sfx/mob/skeleton/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/skeleton/hurt.wav\n\n#begin Sfx/mob/slime/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/slime/death.wav\n\n#begin Sfx/mob/slime/jump_1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/slime/jump_1.wav\n\n#begin Sfx/mob/slime/jump_2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/slime/jump_2.wav\n\n#begin Sfx/mob/slime/land_1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/slime/land_1.wav\n\n#begin Sfx/mob/slime/land_2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/slime/land_2.wav\n\n#begin Sfx/mob/sniper/focus.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/sniper/focus.wav\n\n#begin Sfx/mob/snowball/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/snowball/death.wav\n\n#begin Sfx/mob/snowball/hut.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/snowball/hut.wav\n\n#begin Sfx/mob/snowman/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/snowman/death.wav\n\n#begin Sfx/mob/snowman/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/snowman/hurt.wav\n\n#begin Sfx/mob/spelunker/beep.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/spelunker/beep.wav\n\n#begin Sfx/mob/wizard/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/wizard/death.wav\n\n#begin Sfx/mob/wizard/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/wizard/hurt.wav\n\n#begin Sfx/mob/wombat/fly.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/wombat/fly.wav\n\n#begin Sfx/mob/worm_death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/mob/worm_death.wav\n\n#begin Sfx/npc/beet/hide.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/beet/hide.wav\n\n#begin Sfx/npc/beet/show.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/beet/show.wav\n\n#begin Sfx/npc/voice/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/1.wav\n\n#begin Sfx/npc/voice/10.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/10.wav\n\n#begin Sfx/npc/voice/11.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/11.wav\n\n#begin Sfx/npc/voice/12.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/12.wav\n\n#begin Sfx/npc/voice/13.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/13.wav\n\n#begin Sfx/npc/voice/14.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/14.wav\n\n#begin Sfx/npc/voice/15.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/15.wav\n\n#begin Sfx/npc/voice/16.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/16.wav\n\n#begin Sfx/npc/voice/17.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/17.wav\n\n#begin Sfx/npc/voice/18.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/18.wav\n\n#begin Sfx/npc/voice/19.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/19.wav\n\n#begin Sfx/npc/voice/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/2.wav\n\n#begin Sfx/npc/voice/20.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/20.wav\n\n#begin Sfx/npc/voice/21.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/21.wav\n\n#begin Sfx/npc/voice/22.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/22.wav\n\n#begin Sfx/npc/voice/23.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/23.wav\n\n#begin Sfx/npc/voice/24.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/24.wav\n\n#begin Sfx/npc/voice/25.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/25.wav\n\n#begin Sfx/npc/voice/26.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/26.wav\n\n#begin Sfx/npc/voice/27.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/27.wav\n\n#begin Sfx/npc/voice/28.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/28.wav\n\n#begin Sfx/npc/voice/29.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/29.wav\n\n#begin Sfx/npc/voice/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/3.wav\n\n#begin Sfx/npc/voice/30.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/30.wav\n\n#begin Sfx/npc/voice/4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/4.wav\n\n#begin Sfx/npc/voice/5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/5.wav\n\n#begin Sfx/npc/voice/6.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/6.wav\n\n#begin Sfx/npc/voice/7.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/7.wav\n\n#begin Sfx/npc/voice/8.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/8.wav\n\n#begin Sfx/npc/voice/9.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/npc/voice/9.wav\n\n#begin Sfx/player/cursed.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/cursed.wav\n\n#begin Sfx/player/death.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/death.wav\n\n#begin Sfx/player/descending.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/descending.wav\n\n#begin Sfx/player/hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/hurt.wav\n\n#begin Sfx/player/low_hp_hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/low_hp_hurt.wav\n\n#begin Sfx/player/roll.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/roll.wav\n\n#begin Sfx/player/shield_hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/shield_hurt.wav\n\n#begin Sfx/player/step/default/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/default/1.wav\n\n#begin Sfx/player/step/gold/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/gold/1.wav\n\n#begin Sfx/player/step/gold/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/gold/2.wav\n\n#begin Sfx/player/step/gold/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/gold/3.wav\n\n#begin Sfx/player/step/grass/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/grass/1.wav\n\n#begin Sfx/player/step/grass/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/grass/2.wav\n\n#begin Sfx/player/step/grass/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/grass/3.wav\n\n#begin Sfx/player/step/ice/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/ice/1.wav\n\n#begin Sfx/player/step/ice/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/ice/2.wav\n\n#begin Sfx/player/step/ice/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/ice/3.wav\n\n#begin Sfx/player/step/sand/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/sand/1.wav\n\n#begin Sfx/player/step/sand/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/sand/2.wav\n\n#begin Sfx/player/step/sand/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/sand/3.wav\n\n#begin Sfx/player/step/snow/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/snow/1.wav\n\n#begin Sfx/player/step/snow/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/snow/2.wav\n\n#begin Sfx/player/step/snow/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/snow/3.wav\n\n#begin Sfx/player/step/stone/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/stone/1.wav\n\n#begin Sfx/player/step/stone/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/stone/2.wav\n\n#begin Sfx/player/step/stone/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/stone/3.wav\n\n#begin Sfx/player/step/water/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/water/1.wav\n\n#begin Sfx/player/step/water/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/water/2.wav\n\n#begin Sfx/player/step/water/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/water/3.wav\n\n#begin Sfx/player/step/wood/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/wood/1.wav\n\n#begin Sfx/player/step/wood/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/wood/2.wav\n\n#begin Sfx/player/step/wood/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/player/step/wood/3.wav\n\n#begin Sfx/projectile/reflected/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/reflected/1.wav\n\n#begin Sfx/projectile/reflected/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/reflected/2.wav\n\n#begin Sfx/projectile/shell/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/shell/1.wav\n\n#begin Sfx/projectile/shell/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/shell/2.wav\n\n#begin Sfx/projectile/shell/3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/shell/3.wav\n\n#begin Sfx/projectile/wall/1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/wall/1.wav\n\n#begin Sfx/projectile/wall/2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/wall/2.wav\n\n#begin Sfx/projectile/wall/enemy.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/projectile/wall/enemy.wav\n\n#begin Sfx/quck.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/quck.wav\n\n#begin Sfx/sand.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/sand.wav\n\n#begin Sfx/scroll.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/scroll.wav\n\n#begin Sfx/secret.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/secret.wav\n\n#begin Sfx/slime_hurt.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/slime_hurt.wav\n\n#begin Sfx/swap.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/swap.wav\n\n#begin Sfx/take.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/take.wav\n\n#begin Sfx/ui/achievement.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/achievement.wav\n\n#begin Sfx/ui/change_parameter.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/change_parameter.wav\n\n#begin Sfx/ui/exit.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/exit.wav\n\n#begin Sfx/ui/goback.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/goback.wav\n\n#begin Sfx/ui/moving.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/moving.wav\n\n#begin Sfx/ui/select.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/select.wav\n\n#begin Sfx/ui/start.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/ui/start.wav\n\n#begin Sfx/unlock.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/unlock.wav\n\n#begin Sfx/villager1.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager1.wav\n\n#begin Sfx/villager2.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager2.wav\n\n#begin Sfx/villager3.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager3.wav\n\n#begin Sfx/villager4.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager4.wav\n\n#begin Sfx/villager5.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager5.wav\n\n#begin Sfx/villager6.wav\n/importer:WavImporter\n/processor:SoundEffectProcessor\n/processorParam:Quality=Best\n/build:Sfx/villager6.wav\n\n#begin Shaders/bk.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/bk.fx\n\n#begin Shaders/chasm.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/chasm.fx\n\n#begin Shaders/entity.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/entity.fx\n\n#begin Shaders/fog.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/fog.fx\n\n#begin Shaders/item.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/item.fx\n\n#begin Shaders/screen.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/screen.fx\n\n#begin Shaders/terrain.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/terrain.fx\n\n#begin Shaders/ui.fx\n/importer:EffectImporter\n/processor:EffectProcessor\n/processorParam:DebugMode=Auto\n/build:Shaders/ui.fx\n\n#begin Textures/light.png\n/importer:TextureImporter\n/processor:TextureProcessor\n/processorParam:ColorKeyColor=255,0,255,255\n/processorParam:ColorKeyEnabled=True\n/processorParam:GenerateMipmaps=False\n/processorParam:PremultiplyAlpha=True\n/processorParam:ResizeToPowerOfTwo=False\n/processorParam:MakeSquare=False\n/processorParam:TextureFormat=Color\n/build:Textures/light.png\n\n#begin Textures/noise.png\n/importer:TextureImporter\n/processor:TextureProcessor\n/processorParam:ColorKeyColor=255,0,255,255\n/processorParam:ColorKeyEnabled=True\n/processorParam:GenerateMipmaps=False\n/processorParam:PremultiplyAlpha=True\n/processorParam:ResizeToPowerOfTwo=False\n/processorParam:MakeSquare=False\n/processorParam:TextureFormat=Color\n/build:Textures/noise.png\n\n#begin Textures/rexcellent_logo_pixel.png\n/importer:TextureImporter\n/processor:TextureProcessor\n/processorParam:ColorKeyColor=255,0,255,255\n/processorParam:ColorKeyEnabled=True\n/processorParam:GenerateMipmaps=False\n/processorParam:PremultiplyAlpha=True\n/processorParam:ResizeToPowerOfTwo=False\n/processorParam:MakeSquare=False\n/processorParam:TextureFormat=Color\n/build:Textures/rexcellent_logo_pixel.png\n\n"
  },
  {
    "path": "BurningKnight/Content/Dialogs/accessorytrader.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":415,\"y\":257},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":414,\"y\":298},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":416,\"y\":343}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/activetrader.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":335,\"y\":190},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":335,\"y\":242},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":336,\"y\":291}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/beet.json",
    "content": "[{\"id\":0,\"outputs\":[[[1,0]]],\"type\":\"Text output\",\"x\":-176,\"y\":64},{\"id\":1,\"outputs\":[[[2,0]],[[5,0]]],\"type\":\"Choice\",\"x\":110,\"y\":68,\"cc\":2},{\"id\":2,\"outputs\":[[[3,0]]],\"type\":\"Answer\",\"x\":490,\"y\":78,\"atype\":1},{\"id\":3,\"outputs\":[],\"type\":\"Text input\",\"x\":800,\"y\":124},{\"id\":4,\"outputs\":[[[2,0]],[[5,0]],[[6,0]]],\"type\":\"Choice\",\"x\":267,\"y\":223,\"cc\":3},{\"id\":5,\"outputs\":[],\"type\":\"Text input\",\"x\":619,\"y\":281},{\"id\":6,\"outputs\":[],\"type\":\"Text input\",\"x\":566,\"y\":411}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/bk.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":422,\"y\":276},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":416,\"y\":332},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":419,\"y\":379},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":410,\"y\":424},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":406,\"y\":465},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":392,\"y\":504},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":395,\"y\":541},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":401,\"y\":601},{\"id\":8,\"outputs\":[],\"type\":\"Text\",\"x\":392,\"y\":652},{\"id\":9,\"outputs\":[],\"type\":\"Text\",\"x\":696,\"y\":348},{\"id\":10,\"outputs\":[],\"type\":\"Text\",\"x\":685,\"y\":441},{\"id\":11,\"outputs\":[],\"type\":\"Text\",\"x\":669,\"y\":502}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/bk_sign.json",
    "content": "[{\"id\":0,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":327,\"y\":126},{\"id\":1,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":412,\"y\":249}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/boxy.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":287,\"y\":244},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":285,\"y\":304},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":286,\"y\":357},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":540,\"y\":255},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":537,\"y\":311},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":534,\"y\":365},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":781,\"y\":264},{\"id\":8,\"outputs\":[],\"type\":\"Text\",\"x\":779,\"y\":320},{\"id\":9,\"outputs\":[],\"type\":\"Text\",\"x\":1020,\"y\":268}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/brastin.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":443,\"y\":95}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/builder.json",
    "content": "[{\"id\":0,\"outputs\":[[[2,0]],[[4,0]]],\"type\":\"Choice\",\"x\":348,\"y\":111,\"cc\":2},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":687,\"y\":19},{\"id\":2,\"outputs\":[],\"type\":\"Text input\",\"x\":742,\"y\":305},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":745,\"y\":354},{\"id\":4,\"outputs\":[],\"type\":\"Text input\",\"x\":677,\"y\":157}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/charger.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":365,\"y\":217},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":375,\"y\":273},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":376,\"y\":321},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":381,\"y\":373},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":385,\"y\":424},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":378,\"y\":465}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/control.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":343,\"y\":157},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":343,\"y\":204},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":344,\"y\":251},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":335,\"y\":299},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":332,\"y\":353},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":337,\"y\":402},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":331,\"y\":459}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/dialogs.json",
    "content": "[]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/discord.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":733,\"y\":220}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/dm.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":468,\"y\":357},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":466,\"y\":427},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":453,\"y\":491},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":458,\"y\":555},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":456,\"y\":598}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/duck.json",
    "content": "[{\"id\":2,\"outputs\":[[[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[17,0],[18,0]]],\"type\":\"Text output\",\"x\":120,\"y\":702},{\"id\":7,\"outputs\":[[[5,0],[4,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":535,\"y\":296,\"cc\":2},{\"id\":4,\"outputs\":[],\"type\":\"Text input\",\"x\":1143,\"y\":793},{\"id\":5,\"outputs\":[],\"type\":\"Text input\",\"x\":1156,\"y\":560},{\"id\":6,\"outputs\":[[[5,0],[4,0]],[[5,0],[4,0]]],\"type\":\"Choice\",\"x\":534,\"y\":182,\"cc\":2},{\"id\":8,\"outputs\":[[[5,0],[4,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":531,\"y\":404,\"cc\":2},{\"id\":9,\"outputs\":[[[5,0],[4,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":531,\"y\":504,\"cc\":2},{\"id\":10,\"outputs\":[[[5,0],[4,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":529,\"y\":609,\"cc\":2},{\"id\":11,\"outputs\":[[[5,0],[4,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":529,\"y\":709,\"cc\":2},{\"id\":12,\"outputs\":[[[5,0],[4,0]],[[5,0],[4,0]]],\"type\":\"Choice\",\"x\":534,\"y\":820,\"cc\":2},{\"id\":13,\"outputs\":[[[4,0],[5,0]],[[4,0],[5,0]],[[4,0],[5,0]],[[14,0]]],\"type\":\"Choice\",\"x\":480,\"y\":957,\"cc\":4},{\"id\":14,\"outputs\":[[[5,0],[4,0]]],\"type\":\"Dialog\",\"x\":776,\"y\":1056},{\"id\":17,\"outputs\":[[[4,0],[5,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":477,\"y\":1125,\"cc\":2},{\"id\":18,\"outputs\":[[[4,0],[5,0]],[[4,0],[5,0]]],\"type\":\"Choice\",\"x\":484,\"y\":1230,\"cc\":2},{\"id\":19,\"outputs\":[],\"type\":\"Text\",\"x\":261,\"y\":69},{\"id\":20,\"outputs\":[],\"type\":\"Text\",\"x\":246,\"y\":93}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/eg.json",
    "content": "[{\"id\":0,\"outputs\":[[[]],[[]]],\"type\":\"Choice\",\"x\":336,\"y\":234,\"cc\":2}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/elon.json",
    "content": "[{\"id\":4,\"outputs\":[],\"type\":\"Text input\",\"x\":626,\"y\":153},{\"id\":2,\"outputs\":[[[4,0]],[[5,0]]],\"type\":\"Choice\",\"x\":338,\"y\":142,\"cc\":2},{\"id\":3,\"outputs\":[[[2,0]]],\"type\":\"Text output\",\"x\":98,\"y\":114},{\"id\":5,\"outputs\":[],\"type\":\"Text input\",\"x\":628,\"y\":207},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":470,\"y\":268}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/fountain.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":558,\"y\":135},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":556,\"y\":171},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":561,\"y\":211},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":558,\"y\":255}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/gobetta.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":515,\"y\":315},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":511,\"y\":362},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":516,\"y\":409},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":751,\"y\":317},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":763,\"y\":383},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":781,\"y\":437}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/granny.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":545,\"y\":294},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":548,\"y\":344},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":546,\"y\":390},{\"id\":3,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":540,\"y\":455},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":529,\"y\":521},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":556,\"y\":600}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/hattrader.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":444,\"y\":264},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":424,\"y\":322},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":419,\"y\":372}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/isaac.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":492,\"y\":200},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":492,\"y\":236},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":494,\"y\":275}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/maanex.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":236,\"y\":114},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":236,\"y\":64},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":243,\"y\":171},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":234,\"y\":224},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":249,\"y\":284},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":627,\"y\":178},{\"id\":6,\"outputs\":[[[]],[[]]],\"type\":\"Choice\",\"x\":519,\"y\":234,\"cc\":2},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":860,\"y\":184},{\"id\":8,\"outputs\":[],\"type\":\"Text input\",\"x\":827,\"y\":262},{\"id\":9,\"outputs\":[],\"type\":\"Text\",\"x\":612,\"y\":344},{\"id\":10,\"outputs\":[],\"type\":\"Text\",\"x\":864,\"y\":345},{\"id\":11,\"outputs\":[],\"type\":\"Text\",\"x\":845,\"y\":405},{\"id\":12,\"outputs\":[],\"type\":\"Text\",\"x\":889,\"y\":556}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/maanex2.json",
    "content": "[{\"id\":0,\"outputs\":[[[]],[[]]],\"type\":\"Choice\",\"x\":445,\"y\":250,\"cc\":2}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/machine.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":607,\"y\":218}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/mapuzzle.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":409,\"y\":238}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/milt.json",
    "content": "[{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":303,\"y\":162}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/mob.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":344,\"y\":244}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/npc.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":349,\"y\":355},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":357,\"y\":415},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":359,\"y\":472},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":351,\"y\":527}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/npc_hurt.json",
    "content": "[{\"id\":0,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":116,\"y\":74},{\"id\":1,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":105,\"y\":134},{\"id\":2,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":95,\"y\":199}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/nullptr.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":487,\"y\":312}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/nurse.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":292,\"y\":286},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":293,\"y\":336},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":296,\"y\":390}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/old_man.json",
    "content": "[{\"id\":0,\"outputs\":[[[1,0]]],\"type\":\"Text output\",\"x\":107,\"y\":127},{\"id\":1,\"outputs\":[[[2,0]]],\"type\":\"Dialog\",\"x\":398,\"y\":129},{\"id\":2,\"outputs\":[[[3,0]]],\"type\":\"Dialog\",\"x\":676,\"y\":164},{\"id\":3,\"outputs\":[[[]],[[]]],\"type\":\"Choice\",\"x\":907,\"y\":182,\"cc\":2},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":324,\"y\":250},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":313,\"y\":333},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":610,\"y\":415}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/player.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":441,\"y\":164}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/roger.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":342,\"y\":266},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":344,\"y\":315},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":347,\"y\":369},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":581,\"y\":261},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":585,\"y\":326},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":573,\"y\":369}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/shopkeeper.json",
    "content": "[{\"id\":0,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":320,\"y\":175},{\"id\":1,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":314,\"y\":113},{\"id\":2,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":310,\"y\":75},{\"id\":3,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":632,\"y\":180},{\"id\":4,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":559,\"y\":224},{\"id\":5,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":561,\"y\":261},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":822,\"y\":178},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":819,\"y\":226},{\"id\":8,\"outputs\":[],\"type\":\"Text\",\"x\":822,\"y\":269},{\"id\":9,\"outputs\":[],\"type\":\"Text\",\"x\":1082,\"y\":174},{\"id\":10,\"outputs\":[],\"type\":\"Text\",\"x\":1089,\"y\":227},{\"id\":11,\"outputs\":[],\"type\":\"Text\",\"x\":1065,\"y\":282},{\"id\":12,\"outputs\":[],\"type\":\"Text\",\"x\":1326,\"y\":174},{\"id\":13,\"outputs\":[],\"type\":\"Text\",\"x\":1325,\"y\":226},{\"id\":14,\"outputs\":[],\"type\":\"Text\",\"x\":1325,\"y\":277},{\"id\":15,\"outputs\":[],\"type\":\"Text\",\"x\":1597,\"y\":174},{\"id\":16,\"outputs\":[],\"type\":\"Text\",\"x\":1597,\"y\":229},{\"id\":17,\"outputs\":[],\"type\":\"Text\",\"x\":1595,\"y\":278},{\"id\":18,\"outputs\":[],\"type\":\"Text\",\"x\":1843,\"y\":175}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/snek.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":352,\"y\":154},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":355,\"y\":200},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":351,\"y\":254},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":357,\"y\":328},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":357,\"y\":372},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":352,\"y\":412},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":622,\"y\":183},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":620,\"y\":229}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/tomb.json",
    "content": "[{\"id\":0,\"outputs\":[[[]]],\"type\":\"Text output\",\"x\":536,\"y\":249}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/trash_goblin.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":329,\"y\":227},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":327,\"y\":287},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":322,\"y\":341}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/twitch.json",
    "content": "[{\"id\":0,\"outputs\":[[[1,0]]],\"type\":\"Text output\",\"x\":7,\"y\":16},{\"id\":1,\"outputs\":[[[2,0]],[[4,0]]],\"type\":\"Choice\",\"x\":267,\"y\":2,\"cc\":2},{\"id\":2,\"outputs\":[[[3,0]]],\"type\":\"Answer\",\"x\":614,\"y\":-1,\"atype\":0},{\"id\":3,\"outputs\":[],\"type\":\"Text input\",\"x\":988,\"y\":10},{\"id\":4,\"outputs\":[],\"type\":\"Text input\",\"x\":871,\"y\":154},{\"id\":5,\"outputs\":[[[2,0]],[[4,0]]],\"type\":\"Choice\",\"x\":284,\"y\":142,\"cc\":2}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/vampire.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":316,\"y\":218},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":320,\"y\":259},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":322,\"y\":304},{\"id\":3,\"outputs\":[],\"type\":\"Text\",\"x\":318,\"y\":379},{\"id\":4,\"outputs\":[],\"type\":\"Text\",\"x\":580,\"y\":282},{\"id\":5,\"outputs\":[],\"type\":\"Text\",\"x\":574,\"y\":328},{\"id\":6,\"outputs\":[],\"type\":\"Text\",\"x\":585,\"y\":372},{\"id\":7,\"outputs\":[],\"type\":\"Text\",\"x\":822,\"y\":305},{\"id\":8,\"outputs\":[],\"type\":\"Text\",\"x\":824,\"y\":359},{\"id\":9,\"outputs\":[],\"type\":\"Text\",\"x\":824,\"y\":403}]"
  },
  {
    "path": "BurningKnight/Content/Dialogs/weapontrader.json",
    "content": "[{\"id\":0,\"outputs\":[],\"type\":\"Text\",\"x\":326,\"y\":160},{\"id\":1,\"outputs\":[],\"type\":\"Text\",\"x\":325,\"y\":223},{\"id\":2,\"outputs\":[],\"type\":\"Text\",\"x\":327,\"y\":276}]"
  },
  {
    "path": "BurningKnight/Content/Fonts/fnt.spritefont",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nThis file contains an xml description of a font, and will be read by the XNA\nFramework Content Pipeline. Follow the comments to customize the appearance\nof the font in your game, and to change the characters which are available to draw\nwith.\n-->\n<XnaContent xmlns:Graphics=\"Microsoft.Xna.Framework.Content.Pipeline.Graphics\">\n  <Asset Type=\"Graphics:FontDescription\">\n\n    <!--\n    Modify this string to change the font that will be imported.\n    -->\n    <FontName>fnt.ttf</FontName>\n\n    <!--\n    Size is a float value, measured in points. Modify this value to change\n    the size of the font.\n    -->\n    <Size>9</Size>\n\n    <!--\n    Spacing is a float value, measured in pixels. Modify this value to change\n    the amount of spacing in between characters.\n    -->\n    <Spacing>0</Spacing>\n\n    <!--\n    UseKerning controls the layout of the font. If this value is true, kerning information\n    will be used when placing characters.\n    -->\n    <UseKerning>true</UseKerning>\n\n    <!--\n    Style controls the style of the font. Valid entries are \"Regular\", \"Bold\", \"Italic\",\n    and \"Bold, Italic\", and are case sensitive.\n    -->\n    <Style>Regular</Style>\n\n    <!--\n    If you uncomment this line, the default character will be substituted if you draw\n    or measure text that contains characters which were not included in the font.\n    -->\n    <!-- <DefaultCharacter>*</DefaultCharacter> -->\n\n    <!--\n    CharacterRegions control what letters are available in the font. Every\n    character from Start to End will be built and made available for drawing. The\n    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin\n    character set. The characters are ordered according to the Unicode standard.\n    See the documentation for more information.\n    -->\n    <CharacterRegions>\n      <CharacterRegion>\n        <Start>&#32;</Start>\n        <End>&#126;</End>\n      </CharacterRegion>\n      <CharacterRegion>\n        <Start>&#20300;</Start>\n        <End>&#20340;</End>\n      </CharacterRegion>\n    </CharacterRegions>\n  </Asset>\n</XnaContent>\n"
  },
  {
    "path": "BurningKnight/Content/Fonts/large_font.fnt",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<font>\n  <info face=\"CompassGold\" size=\"16\" bold=\"0\" italic=\"0\" charset=\"\" unicode=\"0\" stretchH=\"100\" smooth=\"1\" aa=\"1\" padding=\"1,1,1,1\" spacing=\"-2,-2\" outline=\"0\" />\n  <common lineHeight=\"17\" base=\"13\" scaleW=\"512\" scaleH=\"512\" pages=\"1\" packed=\"0\" alphaChnl=\"3\" redChnl=\"0\" greenChnl=\"1\" blueChnl=\"2\" />\n  <pages>\n    <page id=\"0\" file=\"large.png\" />\n  </pages>\n  <chars count=\"234\">\n    <char id=\"0\" x=\"299\" y=\"36\" width=\"7\" height=\"13\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"32\" x=\"0\" y=\"0\" width=\"0\" height=\"0\" xoffset=\"-1\" yoffset=\"11\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"33\" x=\"249\" y=\"0\" width=\"4\" height=\"13\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"34\" x=\"241\" y=\"36\" width=\"7\" height=\"6\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"35\" x=\"0\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"36\" x=\"289\" y=\"0\" width=\"9\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"37\" x=\"389\" y=\"25\" width=\"9\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"38\" x=\"324\" y=\"25\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"39\" x=\"506\" y=\"25\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"40\" x=\"253\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"41\" x=\"259\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"42\" x=\"274\" y=\"36\" width=\"6\" height=\"6\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"43\" x=\"262\" y=\"36\" width=\"6\" height=\"6\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"44\" x=\"506\" y=\"25\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"10\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"45\" x=\"289\" y=\"36\" width=\"6\" height=\"4\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"46\" x=\"295\" y=\"36\" width=\"4\" height=\"3\" xoffset=\"-1\" yoffset=\"10\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"47\" x=\"297\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"48\" x=\"213\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"49\" x=\"221\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"50\" x=\"229\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"51\" x=\"237\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"52\" x=\"245\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"53\" x=\"253\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"54\" x=\"261\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"55\" x=\"269\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"56\" x=\"277\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"57\" x=\"285\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"58\" x=\"280\" y=\"36\" width=\"4\" height=\"5\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"59\" x=\"506\" y=\"14\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"8\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"60\" x=\"9\" y=\"36\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"61\" x=\"268\" y=\"36\" width=\"6\" height=\"6\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"62\" x=\"15\" y=\"36\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"63\" x=\"242\" y=\"0\" width=\"7\" height=\"13\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"64\" x=\"309\" y=\"14\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"65\" x=\"410\" y=\"0\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"66\" x=\"420\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"67\" x=\"429\" y=\"0\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"68\" x=\"437\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"69\" x=\"446\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"70\" x=\"455\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"71\" x=\"464\" y=\"0\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"72\" x=\"472\" y=\"0\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"73\" x=\"482\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"74\" x=\"488\" y=\"0\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"75\" x=\"496\" y=\"0\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"76\" x=\"0\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"77\" x=\"9\" y=\"14\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"78\" x=\"20\" y=\"14\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"79\" x=\"31\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"80\" x=\"40\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"81\" x=\"233\" y=\"0\" width=\"9\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"82\" x=\"49\" y=\"14\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"83\" x=\"59\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"84\" x=\"67\" y=\"14\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"85\" x=\"77\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"86\" x=\"86\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"87\" x=\"94\" y=\"14\" width=\"12\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"88\" x=\"106\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"89\" x=\"114\" y=\"14\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"90\" x=\"124\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"91\" x=\"265\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"92\" x=\"303\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"93\" x=\"271\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"94\" x=\"248\" y=\"36\" width=\"7\" height=\"6\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"95\" x=\"289\" y=\"36\" width=\"6\" height=\"4\" xoffset=\"-1\" yoffset=\"10\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"96\" x=\"284\" y=\"36\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"97\" x=\"398\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"98\" x=\"132\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"99\" x=\"406\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"100\" x=\"141\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"101\" x=\"414\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"102\" x=\"150\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"103\" x=\"156\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"104\" x=\"164\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"105\" x=\"310\" y=\"25\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"106\" x=\"173\" y=\"14\" width=\"7\" height=\"11\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"107\" x=\"180\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"108\" x=\"506\" y=\"0\" width=\"5\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"109\" x=\"422\" y=\"25\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"110\" x=\"431\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"111\" x=\"439\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"112\" x=\"189\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"113\" x=\"198\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"114\" x=\"447\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"115\" x=\"455\" y=\"25\" width=\"7\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"116\" x=\"207\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"117\" x=\"462\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"118\" x=\"470\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"119\" x=\"478\" y=\"25\" width=\"12\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"120\" x=\"490\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"121\" x=\"316\" y=\"25\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"122\" x=\"498\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"123\" x=\"277\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"124\" x=\"293\" y=\"14\" width=\"4\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"125\" x=\"283\" y=\"0\" width=\"6\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"126\" x=\"232\" y=\"36\" width=\"9\" height=\"6\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"161\" x=\"346\" y=\"0\" width=\"4\" height=\"13\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"162\" x=\"340\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"163\" x=\"331\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"169\" x=\"348\" y=\"14\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"174\" x=\"361\" y=\"14\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"176\" x=\"255\" y=\"36\" width=\"7\" height=\"6\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"191\" x=\"339\" y=\"0\" width=\"7\" height=\"13\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"192\" x=\"0\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"193\" x=\"10\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"194\" x=\"20\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"195\" x=\"30\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"196\" x=\"40\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"197\" x=\"50\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"198\" x=\"374\" y=\"14\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"199\" x=\"298\" y=\"0\" width=\"8\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"200\" x=\"60\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"201\" x=\"69\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"202\" x=\"78\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"203\" x=\"87\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"204\" x=\"96\" y=\"0\" width=\"6\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"205\" x=\"102\" y=\"0\" width=\"6\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"206\" x=\"108\" y=\"0\" width=\"6\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"207\" x=\"114\" y=\"0\" width=\"6\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"208\" x=\"387\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"209\" x=\"120\" y=\"0\" width=\"11\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"210\" x=\"131\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"211\" x=\"140\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"212\" x=\"149\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"213\" x=\"158\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"214\" x=\"167\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"216\" x=\"306\" y=\"0\" width=\"9\" height=\"13\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"217\" x=\"176\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"218\" x=\"185\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"219\" x=\"194\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"220\" x=\"203\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"221\" x=\"212\" y=\"0\" width=\"10\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"222\" x=\"408\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"223\" x=\"86\" y=\"25\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"224\" x=\"416\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"225\" x=\"424\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"226\" x=\"432\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"227\" x=\"440\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"228\" x=\"448\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"229\" x=\"384\" y=\"0\" width=\"8\" height=\"12\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"230\" x=\"21\" y=\"36\" width=\"12\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"231\" x=\"332\" y=\"25\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"232\" x=\"456\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"233\" x=\"464\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"234\" x=\"472\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"235\" x=\"480\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"236\" x=\"488\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"237\" x=\"494\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"238\" x=\"500\" y=\"14\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"239\" x=\"0\" y=\"25\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"240\" x=\"392\" y=\"0\" width=\"8\" height=\"12\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"241\" x=\"6\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"242\" x=\"14\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"243\" x=\"22\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"244\" x=\"30\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"245\" x=\"38\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"246\" x=\"46\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"248\" x=\"340\" y=\"25\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"249\" x=\"54\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"250\" x=\"62\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"251\" x=\"70\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"252\" x=\"78\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"253\" x=\"315\" y=\"0\" width=\"8\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"254\" x=\"323\" y=\"0\" width=\"8\" height=\"13\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"255\" x=\"331\" y=\"0\" width=\"8\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"338\" x=\"396\" y=\"14\" width=\"12\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"339\" x=\"33\" y=\"36\" width=\"12\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"1025\" x=\"87\" y=\"0\" width=\"9\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1040\" x=\"95\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1041\" x=\"105\" y=\"25\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1042\" x=\"420\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1043\" x=\"114\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1044\" x=\"350\" y=\"0\" width=\"10\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1045\" x=\"446\" y=\"0\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1046\" x=\"122\" y=\"25\" width=\"12\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"1047\" x=\"134\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1048\" x=\"142\" y=\"25\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1049\" x=\"222\" y=\"0\" width=\"11\" height=\"14\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1050\" x=\"496\" y=\"0\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1051\" x=\"153\" y=\"25\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1052\" x=\"164\" y=\"25\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1053\" x=\"472\" y=\"0\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1054\" x=\"31\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1055\" x=\"175\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1056\" x=\"40\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1057\" x=\"429\" y=\"0\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1058\" x=\"67\" y=\"14\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1059\" x=\"185\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1060\" x=\"195\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1061\" x=\"106\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1062\" x=\"360\" y=\"0\" width=\"10\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1063\" x=\"205\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1064\" x=\"215\" y=\"25\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"1065\" x=\"370\" y=\"0\" width=\"14\" height=\"13\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"13\" page=\"0\" chnl=\"0\" />\n    <char id=\"1066\" x=\"228\" y=\"25\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1067\" x=\"239\" y=\"25\" width=\"13\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"1068\" x=\"252\" y=\"25\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1069\" x=\"261\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1070\" x=\"269\" y=\"25\" width=\"12\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"1071\" x=\"281\" y=\"25\" width=\"10\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1072\" x=\"398\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1073\" x=\"291\" y=\"25\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1074\" x=\"45\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1075\" x=\"54\" y=\"36\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1076\" x=\"348\" y=\"25\" width=\"10\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1077\" x=\"414\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1078\" x=\"62\" y=\"36\" width=\"12\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"1079\" x=\"74\" y=\"36\" width=\"7\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1080\" x=\"81\" y=\"36\" width=\"11\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1081\" x=\"299\" y=\"25\" width=\"11\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1082\" x=\"92\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1083\" x=\"101\" y=\"36\" width=\"11\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1084\" x=\"112\" y=\"36\" width=\"11\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1085\" x=\"123\" y=\"36\" width=\"10\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1086\" x=\"439\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1087\" x=\"133\" y=\"36\" width=\"10\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1088\" x=\"189\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1089\" x=\"406\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1090\" x=\"143\" y=\"36\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1091\" x=\"358\" y=\"25\" width=\"9\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1092\" x=\"400\" y=\"0\" width=\"10\" height=\"12\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1093\" x=\"490\" y=\"25\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1094\" x=\"367\" y=\"25\" width=\"9\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1095\" x=\"151\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1096\" x=\"160\" y=\"36\" width=\"12\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"11\" page=\"0\" chnl=\"0\" />\n    <char id=\"1097\" x=\"376\" y=\"25\" width=\"13\" height=\"10\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"1098\" x=\"172\" y=\"36\" width=\"10\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"1099\" x=\"182\" y=\"36\" width=\"13\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"12\" page=\"0\" chnl=\"0\" />\n    <char id=\"1100\" x=\"195\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1101\" x=\"204\" y=\"36\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1102\" x=\"212\" y=\"36\" width=\"11\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"10\" page=\"0\" chnl=\"0\" />\n    <char id=\"1103\" x=\"223\" y=\"36\" width=\"9\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1105\" x=\"480\" y=\"14\" width=\"8\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"8364\" x=\"322\" y=\"14\" width=\"9\" height=\"11\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n  </chars>\n</font>"
  },
  {
    "path": "BurningKnight/Content/Fonts/small_font.fnt",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<font>\n  <info face=\"SinsGold\" size=\"16\" bold=\"0\" italic=\"0\" charset=\"\" unicode=\"0\" stretchH=\"100\" smooth=\"1\" aa=\"1\" padding=\"1,1,1,1\" spacing=\"-2,-2\" outline=\"0\" />\n  <common lineHeight=\"15\" base=\"12\" scaleW=\"512\" scaleH=\"512\" pages=\"1\" packed=\"0\" alphaChnl=\"3\" redChnl=\"0\" greenChnl=\"1\" blueChnl=\"2\" />\n  <pages>\n    <page id=\"0\" file=\"small.png\" />\n  </pages>\n  <chars count=\"234\">\n    <char id=\"0\" x=\"276\" y=\"21\" width=\"7\" height=\"13\" xoffset=\"-1\" yoffset=\"-1\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"32\" x=\"0\" y=\"0\" width=\"0\" height=\"0\" xoffset=\"-1\" yoffset=\"10\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"33\" x=\"508\" y=\"0\" width=\"3\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"34\" x=\"226\" y=\"21\" width=\"6\" height=\"5\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"35\" x=\"47\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"36\" x=\"55\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"37\" x=\"417\" y=\"12\" width=\"5\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"38\" x=\"37\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"39\" x=\"256\" y=\"21\" width=\"3\" height=\"4\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"40\" x=\"159\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"41\" x=\"163\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"42\" x=\"247\" y=\"21\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"43\" x=\"237\" y=\"21\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"44\" x=\"252\" y=\"21\" width=\"4\" height=\"4\" xoffset=\"-1\" yoffset=\"8\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"45\" x=\"271\" y=\"21\" width=\"5\" height=\"3\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"46\" x=\"268\" y=\"21\" width=\"3\" height=\"3\" xoffset=\"-1\" yoffset=\"9\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"47\" x=\"407\" y=\"12\" width=\"5\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"48\" x=\"348\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"49\" x=\"354\" y=\"12\" width=\"5\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"50\" x=\"359\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"51\" x=\"365\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"52\" x=\"371\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"53\" x=\"377\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"54\" x=\"383\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"55\" x=\"389\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"56\" x=\"395\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"57\" x=\"401\" y=\"12\" width=\"6\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"58\" x=\"215\" y=\"21\" width=\"3\" height=\"5\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"59\" x=\"507\" y=\"12\" width=\"4\" height=\"6\" xoffset=\"-1\" yoffset=\"6\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"60\" x=\"54\" y=\"21\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"61\" x=\"242\" y=\"21\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"62\" x=\"59\" y=\"21\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"63\" x=\"31\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"64\" x=\"183\" y=\"0\" width=\"10\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"9\" page=\"0\" chnl=\"0\" />\n    <char id=\"65\" x=\"333\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"66\" x=\"339\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"67\" x=\"345\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"68\" x=\"351\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"69\" x=\"357\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"70\" x=\"363\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"71\" x=\"369\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"72\" x=\"375\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"73\" x=\"381\" y=\"0\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"74\" x=\"386\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"75\" x=\"392\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"76\" x=\"398\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"77\" x=\"404\" y=\"0\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"78\" x=\"411\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"79\" x=\"417\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"80\" x=\"423\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"81\" x=\"429\" y=\"0\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"82\" x=\"436\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"83\" x=\"442\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"84\" x=\"448\" y=\"0\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"85\" x=\"453\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"86\" x=\"459\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"87\" x=\"465\" y=\"0\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"88\" x=\"472\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"89\" x=\"478\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"90\" x=\"484\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"91\" x=\"167\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"92\" x=\"412\" y=\"12\" width=\"5\" height=\"8\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"93\" x=\"171\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"94\" x=\"259\" y=\"21\" width=\"5\" height=\"4\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"95\" x=\"271\" y=\"21\" width=\"5\" height=\"3\" xoffset=\"-1\" yoffset=\"9\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"96\" x=\"264\" y=\"21\" width=\"4\" height=\"4\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"97\" x=\"452\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"98\" x=\"490\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"99\" x=\"458\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"100\" x=\"496\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"101\" x=\"464\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"102\" x=\"502\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"103\" x=\"470\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"104\" x=\"0\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"105\" x=\"6\" y=\"12\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"106\" x=\"11\" y=\"12\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"107\" x=\"16\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"108\" x=\"22\" y=\"12\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"109\" x=\"476\" y=\"12\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"110\" x=\"483\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"111\" x=\"489\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"112\" x=\"495\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"113\" x=\"501\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"114\" x=\"0\" y=\"21\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"115\" x=\"5\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"116\" x=\"27\" y=\"12\" width=\"4\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"117\" x=\"11\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"118\" x=\"17\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"119\" x=\"23\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"120\" x=\"30\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"121\" x=\"36\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"122\" x=\"42\" y=\"21\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"123\" x=\"175\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"124\" x=\"44\" y=\"12\" width=\"3\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"125\" x=\"179\" y=\"0\" width=\"4\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"3\" page=\"0\" chnl=\"0\" />\n    <char id=\"126\" x=\"218\" y=\"21\" width=\"8\" height=\"5\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"161\" x=\"195\" y=\"12\" width=\"3\" height=\"9\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"2\" page=\"0\" chnl=\"0\" />\n    <char id=\"162\" x=\"69\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"163\" x=\"62\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"169\" x=\"75\" y=\"12\" width=\"9\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"174\" x=\"84\" y=\"12\" width=\"9\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"176\" x=\"232\" y=\"21\" width=\"5\" height=\"5\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"191\" x=\"189\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"192\" x=\"0\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"193\" x=\"6\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"194\" x=\"12\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"195\" x=\"18\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"196\" x=\"117\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"197\" x=\"24\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"198\" x=\"93\" y=\"12\" width=\"8\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"199\" x=\"123\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"200\" x=\"30\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"201\" x=\"36\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"202\" x=\"42\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"203\" x=\"129\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"204\" x=\"48\" y=\"0\" width=\"5\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"205\" x=\"53\" y=\"0\" width=\"5\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"206\" x=\"58\" y=\"0\" width=\"5\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"207\" x=\"135\" y=\"0\" width=\"5\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"208\" x=\"101\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"209\" x=\"63\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"210\" x=\"69\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"211\" x=\"75\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"212\" x=\"81\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"213\" x=\"87\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"214\" x=\"140\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"216\" x=\"108\" y=\"12\" width=\"8\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"217\" x=\"93\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"218\" x=\"99\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"219\" x=\"105\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"220\" x=\"146\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"221\" x=\"111\" y=\"0\" width=\"6\" height=\"12\" xoffset=\"-1\" yoffset=\"0\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"222\" x=\"124\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"223\" x=\"177\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"224\" x=\"193\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"225\" x=\"199\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"226\" x=\"205\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"227\" x=\"211\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"228\" x=\"130\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"229\" x=\"217\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"230\" x=\"64\" y=\"21\" width=\"9\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"231\" x=\"136\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"232\" x=\"223\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"233\" x=\"229\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"234\" x=\"235\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"235\" x=\"142\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"236\" x=\"241\" y=\"0\" width=\"5\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"237\" x=\"246\" y=\"0\" width=\"5\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"238\" x=\"251\" y=\"0\" width=\"5\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"239\" x=\"148\" y=\"12\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"240\" x=\"153\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"241\" x=\"256\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"242\" x=\"262\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"243\" x=\"268\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"244\" x=\"274\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"245\" x=\"280\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"246\" x=\"159\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"248\" x=\"73\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"249\" x=\"286\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"250\" x=\"292\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"251\" x=\"298\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"252\" x=\"165\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"253\" x=\"304\" y=\"0\" width=\"6\" height=\"10\" xoffset=\"-1\" yoffset=\"2\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"254\" x=\"171\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"4\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"255\" x=\"183\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"338\" x=\"116\" y=\"12\" width=\"8\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"339\" x=\"79\" y=\"21\" width=\"9\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"8\" page=\"0\" chnl=\"0\" />\n    <char id=\"1025\" x=\"129\" y=\"0\" width=\"6\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1040\" x=\"198\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1041\" x=\"205\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1042\" x=\"339\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1043\" x=\"211\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1044\" x=\"310\" y=\"0\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1045\" x=\"357\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1046\" x=\"217\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1047\" x=\"224\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1048\" x=\"230\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1049\" x=\"152\" y=\"0\" width=\"7\" height=\"11\" xoffset=\"-1\" yoffset=\"1\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1050\" x=\"237\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1051\" x=\"243\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1052\" x=\"250\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1053\" x=\"375\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1054\" x=\"417\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1055\" x=\"257\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1056\" x=\"423\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1057\" x=\"345\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1058\" x=\"448\" y=\"0\" width=\"5\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"1059\" x=\"263\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1060\" x=\"269\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1061\" x=\"472\" y=\"0\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1062\" x=\"318\" y=\"0\" width=\"7\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1063\" x=\"276\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1064\" x=\"282\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1065\" x=\"325\" y=\"0\" width=\"8\" height=\"10\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1066\" x=\"289\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1067\" x=\"296\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1068\" x=\"303\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1069\" x=\"309\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1070\" x=\"316\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1071\" x=\"323\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1072\" x=\"452\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1073\" x=\"329\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1074\" x=\"88\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1075\" x=\"94\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1076\" x=\"422\" y=\"12\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1077\" x=\"464\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1078\" x=\"100\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1079\" x=\"107\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1080\" x=\"113\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1081\" x=\"341\" y=\"12\" width=\"7\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1082\" x=\"120\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1083\" x=\"126\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1084\" x=\"133\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1085\" x=\"140\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1086\" x=\"489\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1087\" x=\"146\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1088\" x=\"495\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1089\" x=\"458\" y=\"12\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1090\" x=\"152\" y=\"21\" width=\"5\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"4\" page=\"0\" chnl=\"0\" />\n    <char id=\"1091\" x=\"157\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1092\" x=\"430\" y=\"12\" width=\"7\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1093\" x=\"30\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1094\" x=\"437\" y=\"12\" width=\"7\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1095\" x=\"163\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1096\" x=\"169\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1097\" x=\"444\" y=\"12\" width=\"8\" height=\"8\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n    <char id=\"1098\" x=\"176\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1099\" x=\"183\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1100\" x=\"190\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1101\" x=\"196\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1102\" x=\"202\" y=\"21\" width=\"7\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"6\" page=\"0\" chnl=\"0\" />\n    <char id=\"1103\" x=\"209\" y=\"21\" width=\"6\" height=\"7\" xoffset=\"-1\" yoffset=\"5\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"1105\" x=\"335\" y=\"12\" width=\"6\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"5\" page=\"0\" chnl=\"0\" />\n    <char id=\"8364\" x=\"47\" y=\"12\" width=\"8\" height=\"9\" xoffset=\"-1\" yoffset=\"3\" xadvance=\"7\" page=\"0\" chnl=\"0\" />\n  </chars>\n</font>"
  },
  {
    "path": "BurningKnight/Content/Locales/by.json",
    "content": "{\n\t\"bk:halo\": \"Нiмб\",\n\t\"bk:halo_desc\": \"Павелiчэнне HP\",\n\t\"bk:revolver\": \"Рэвальвер\",\n\t\"bk:sword\": \"Драýляны Меч\",\n\t\"bk:sword_desc\": \"Ня проста палка\",\n\t\"bk:heart\": \"Сэрца\",\n\t\"resume\": \"Працягнуць\",\n\t\"settings\": \"Наладкi\",\n\t\"restart\": \"Пачаць Нанова\",\n\t\"death_message\": \"Ты Памёр\",\n\t\"descend\": \"Спусцiцца\",\n\t\"ascend\": \"Падняцца\",\n\t\"exit\": \"Выхад\",\n\t\"painting_rexcellent\": \"Экселлент\",\n\t\"painting_grannylisa\": \"Граннiлiза\",\n\t\"painting_maanex\": \"Думацель\",\n\t\"painting_bk\": \"Падгарэлы Рыцар\",\n\t\"painting_failpositive\": \"Дыджэй\",\n\t\"painting_old_man\": \"Ну вееельмi стары стары\",\n\t\"painting_arthouse\": \"Арт Хаус\",\n\t\"painting_black\": \"Сусвет\",\n\t\"painting_milt\": \"Чувак ý снезе\",\n\t\"painting_skyscraper\": \"Адынокi хмарачос\",\n\t\"painting_egor\": \"Падпалены дыназавр\",\n\t\"painting_null\": \"НУЛЬ\",\n\t\"painting_badosz\": \"Згубiýшiся пацан\",\n\t\"painting_banana\": \"Бананчык\",\n\t\"painting_tv\": \"Скрыня на нябёсах\",\n\t\"painting_company\": \"Балдёжная кампанiя\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Сабака ля Трасевол\",\n\t\"painting_lamp\": \"Да вазьмi ты яе\",\n\t\"painting_scream\": \"Марозiва\",\n\t\"painting_stars\": \"Стремная ноч\",\n\t\"painting_fog\": \"На морах\",\n\t\"painting_nufflee\": \"Вуф\",\n\t\"by\": \"Аýтар\",\n\t\"old_man_0\": \"Там небяспечна!\",\n\t\"continue_run\": \"Працягнуть Забег\",\n\t\"new_run\": \"Новы Забег\",\n\t\"was_unlocked\": \"Быý Адкрыты!\",\n\t\"bk:revolver_desc\": \"Рукi ýгору, @everyone!\",\n\t\"bk:shovel\": \"Сiняя Лапата\",\n\t\"bk:shovel_desc\": \"А че яна сiняя-то?\",\n\t\"beet_0\": \"Прiвкi!\",\n\t\"beet_2\": \"Як назваць?\",\n\t\"npc_hurt_0\": \"Ой.\",\n\t\"npc_hurt_1\": \"Блiн, балюча.\",\n\t\"npc_hurt_2\": \"О нет.\",\n\t\"beet_3\": \"Пасiбкi <3\",\n\t\"beet_1\": \"А ты не хочаш пасадзiць ^^насенне^^?\",\n\t\"beet_1_0\": \"Да!\",\n\t\"beet_1_1\": \"Не.\",\n\t\"beet_4\": \"Насенне зараз [vr seed]. Хочаш яе памяняць?\",\n\t\"beet_4_0\": \"Да!\",\n\t\"beet_4_1\": \"Не.\",\n\t\"beet_5\": \"Ну добра.\",\n\t\"beet_4_2\": \"Хай будзе выпадковым.\",\n\t\"beet_6\": \"Ок. Насенне зараз [vr seed]!\",\n\t\"bk:idol\": \"Iдал\",\n\t\"bk:idol_desc\": \"Схаваная пастка шчоýкнула!\",\n\t\"bk:key\": \"Залаты Ключык\",\n\t\"bk:infinite_bomb\": \"Бясконцая Бомба\",\n\t\"bk:infinite_bomb_desc\": \"Ну амаль\",\n\t\"throw_coin\": \"Кiнуць Манетку\",\n\t\"bk:potatoo\": \"Буульба\",\n\t\"bk:potatoo_desc\": \"Дзелiць Кулi\",\n\t\"bk:spectacles\": \"Акуляры\",\n\t\"bk:spectacles_desc\": \"Паказвае Сакрэткi\",\n\t\"bk:cross\": \"Крыж\",\n\t\"bk:cross_desc\": \"Павялiчвае час непаражальнасцi\",\n\t\"bk:slime\": \"Слiзь\",\n\t\"bk:slime_desc\": \"Прыгучыя кулi\",\n\t\"bk:missile\": \"Ракета\",\n\t\"bk:missile_desc\": \"Саманаводка\",\n\t\"bk:rod_of_discord\": \"Посах Дiскорда\",\n\t\"bk:rod_of_discord_desc\": \"Тэлепортатор для @everyone\",\n\t\"bk:goo\": \"Гу\",\n\t\"bk:goo_desc\": \"Круцельны Сябар\",\n\t\"bk:jelly\": \"Жэлешка\",\n\t\"bk:jelly_desc\": \"^^Прыгучая^^\",\n\t\"bk:broken_stone\": \"Зламаны Камень\",\n\t\"bk:broken_stone_desc\": \"Моцны Арбiталь\",\n\t\"bk:nano_orb\": \"Нана Шар\",\n\t\"bk:nano_orb_desc\": \"Мiкра Сябар\",\n\t\"bk:saturn\": \"Планета\",\n\t\"bk:saturn_desc\": \"Зразумела мы яе яшчэ кахаем\",\n\t\"bk:soap\": \"Мыла\",\n\t\"bk:soap_desc\": \"Замаруджвае кулi\",\n\t\"bk:d6\": \"Д6\",\n\t\"bk:d6_desc\": \"^^Рэролл^^ прадметаý!\",\n\t\"bk:my_heart\": \"Маё Сэрца\",\n\t\"bk:my_heart_desc\": \"Павелiчвае HP\",\n\t\"bk:broken_heart\": \"Разбiтае Сэрца\",\n\t\"bk:broken_heart_desc\": \"Павелiчвае HP\",\n\t\"bk:parcel\": \"Пасылка\",\n\t\"bk:parcel_desc\": \"Аднаýляе здароýе\",\n\t\"bk:glass\": \"Шкляшка\",\n\t\"bk:glass_desc\": \"##Крохкiя## кулi\",\n\t\"bk:glass_bullet\": \"Шкляныя Кулi\",\n\t\"bk:glass_bullet_desc\": \"Страляй над камянямi\",\n\t\"bk:broken_guitar\": \"Зламаная Гiтара\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Аýтамат\",\n\t\"bk:machine_gun_desc\": \"Аýтаматычны\",\n\t\"bk:grenade_launcher\": \"Базука\",\n\t\"bk:grenade_launcher_desc\": \"Бум!\",\n\t\"bk:shotgun\": \"Драбаш\",\n\t\"bk:shotgun_desc\": \"Соль у твар!\",\n\t\"bk:missile_launcher\": \"Ракетнiца\",\n\t\"bk:missile_launcher_desc\": \"Мэта выяýлена\",\n\t\"bk:burst_gun\": \"Пушка-Фiгулька\",\n\t\"bk:burst_gun_desc\": \"Фiгня найпоýная\",\n\t\"bk:flak_cannon\": \"Пушка-Ватрушка\",\n\t\"bk:flak_cannon_desc\": \"Вечарынка\",\n\t\"bk:disk_gun\": \"Дыскастрэл\",\n\t\"bk:disk_gun_desc\": \"Вельмi востры\",\n\t\"bk:duck_gun\": \"Крякалка\",\n\t\"bk:duck_gun_desc\": \"Кряк!\",\n\t\"bk:follower\": \"Паслядоýнiк\",\n\t\"bk:follower_desc\": \"За мной!\",\n\t\"bk:portal_gun\": \"Портал Ган\",\n\t\"bk:portal_gun_desc\": \"Торцiк гэта хлусня\",\n\t\"bk:snowflake\": \"Сняжынка\",\n\t\"bk:snowflake_desc\": \"Марозiць усiх\",\n\t\"bk:restock\": \"Пастаýка\",\n\t\"bk:restock_desc\": \"Тавар у краме не сканчаецца\",\n\t\"bk:charisma_ring_desc\": \"Царскiя знiжкi\",\n\t\"bk:charisma_ring\": \"Харызматычнае Кальцо\",\n\t\"bk:battery\": \"Батарэйка\",\n\t\"tomb_0\": \"Тут пахаваны Вялiкi [cl green]Гоблiн[cl]\",\n\t\"bk:homemade_dice\": \"Самадзельны Кубiк Dice\",\n\t\"bk:homemade_dice_desc\": \"^^Рэролл^^ прадметаý! (DIY)\",\n\t\"shopkeeper_0\": \"##Я КАЗАÝ ПЕРАСТАНЬ!##\",\n\t\"shopkeeper_1\": \"Спынiся!\",\n\t\"shopkeeper_2\": \"Ня трэба.\",\n\t\"shopkeeper_3\": \"[cl red]##РЫХТУЙСЯ ДА СМЕРЦI!##\",\n\t\"shopkeeper_4\": \"[cl red]ВОР!\",\n\t\"shopkeeper_5\": \"[cl red]ЛАВI ЯГО!\",\n\t\"desert\": \"Пустынны Замак\",\n\t\"jungle\": \"Старажытныя Джунглi\",\n\t\"ice\": \"Ледзяныя Развалiны\",\n\t\"bk:iron_boots\": \"Стальныя Чаравiкi\",\n\t\"bk:iron_boots_desc\": \"Шыпы - не перашкода\",\n\t\"bk:mimic_totem\": \"Татэм мiмiкаý\",\n\t\"bk:mimic_totem_desc\": \"##Смерць мiмiкам!##\",\n\t\"back_to_town\": \"Вяртацца ý Горад\",\n\t\"bk:glass_gun\": \"Шкляная Пукалка\",\n\t\"bk:glass_gun_desc\": \"##Крохкая##\",\n\t\"bk:glass_shard\": \"Асколак Шкла\",\n\t\"bk:glass_shard_desc\": \"Астаткi цэлага\",\n\t\"bk:disk_10\": \"Дыск №10\",\n\t\"bk:disk_10_desc\": \"Торгаш\",\n\t\"bk:disk_1\": \"Дыск 1\",\n\t\"bk:disk_1_desc\": \"Хата\",\n\t\"bk:disk_2\": \"Дыск 2\",\n\t\"bk:disk_2_desc\": \"Лес\",\n\t\"bk:disk_3\": \"Дыск 3\",\n\t\"bk:disk_3_desc\": \"Джунглi\",\n\t\"bk:disk_4\": \"Дыск 4\",\n\t\"bk:disk_4_desc\": \"Лед\",\n\t\"bk:disk_5\": \"Дыск 5\",\n\t\"bk:disk_5_desc\": \"Замак\",\n\t\"bk:disk_6\": \"Дыск 6\",\n\t\"bk:disk_6_desc\": \"Пекла\",\n\t\"bk:disk_7\": \"Дыск 7\",\n\t\"bk:disk_7_desc\": \"???\",\n\t\"bk:disk_8\": \"Дыск 8\",\n\t\"bk:disk_8_desc\": \"Пустата\",\n\t\"bk:disk_9\": \"Дыск 9\",\n\t\"bk:disk_9_desc\": \"Cut\",\n\t\"bk:dagger\": \"Кiнжал\",\n\t\"bk:dagger_desc\": \"Настальгiя...\",\n\t\"bk:spear\": \"Кап'ё\",\n\t\"bk:spear_desc\": \"Доýгiя лапкi\",\n\t\"shopkeeper_6\": \"Дратуце :)\",\n\t\"shopkeeper_7\": \"[cl yellow]Чаю[cl] не хочаш?\",\n\t\"shopkeeper_8\": \"Як жыцце?\",\n\t\"back\": \"Назад\",\n\t\"master_volume\": \"Агульная Гучнасць\",\n\t\"music\": \"Музыка\",\n\t\"sfx\": \"Гукi\",\n\t\"graphics\": \"Графон\",\n\t\"audio\": \"Аýдыё\",\n\t\"ui_sfx\": \"Гукi Кнопачак\",\n\t\"on\": \"УКЛ\",\n\t\"off\": \"ВЫКЛ\",\n\t\"fullscreen\": \"Поýны Экран\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Лiчыльнiк FPS\",\n\t\"speedrun_timer\": \"Таймер\",\n\t\"screenshake\": \"Трасянiна Экрана\",\n\t\"freeze_frames\": \"Кадры Замарозкi\",\n\t\"flash_frames\": \"Кадры Ýспышкi\",\n\t\"reset_progress\": \"Скiнуць Прагрэс\",\n\t\"blood_n_gore\": \"Кроý i Астанкi\",\n\t\"vegan_mode\": \"Агароднiнны Рэжым\",\n\t\"reset_settings\": \"Скiнуць Наладкi\",\n\t\"are_you_sure\": \"Ты ýпэýнены?\",\n\t\"yes\": \"Угу\",\n\t\"reset_progress_dis\": \"Гэта сатрэ ýвесь твой прагрэс!\",\n\t\"reset_settings_dis\": \"Гэта верне ýсе наладкi да iх дэфолту!\",\n\t\"autosave\": \"Аýта Захаванне\",\n\t\"autopause\": \"Аýта Паýза\",\n\t\"input\": \"Кiраванне\",\n\t\"use\": \"Выкарыстоýваць\",\n\t\"active\": \"Актыýка\",\n\t\"bomb\": \"Бомба\",\n\t\"interact\": \"Узаемадзеянне\",\n\t\"swap\": \"Змена Зброi\",\n\t\"roll\": \"Перакат\",\n\t\"duck\": \"Крак\",\n\t\"pause\": \"Паýза\",\n\t\"none\": \"Ничего\",\n\t\"keyboard_controls\": \"Клавя\",\n\t\"gamepad_controls\": \"Джойсцiк\",\n\t\"keyboard\": \"Клавя\",\n\t\"gamepad\": \"Джойсцiк\",\n\t\"game\": \"Геймплэй\",\n\t\"select\": \"Выбраць\",\n\t\"cursor\": \"Курсок\",\n\t\"ach_bk:rip_desc\": \"Памры\",\n\t\"ach_bk:overshake\": \"Перетрасянiна\",\n\t\"ach_bk:overshake_desc\": \"1000% трасянiна экрану\",\n\t\"ach_bk:rip\": \"Самая Папулярная Ачiýка\",\n\t\"bk:emerald\": \"Смарагд\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Дзякуй!^^\",\n\t\"shopkeeper_11\": \"Якая %%прапанова%%!\",\n\t\"shopkeeper_12\": \"Не хочаш купiць [cl red]buy[cl] ^^што небудзь^^?\",\n\t\"shopkeeper_13\": \"Толькi сёння, толькi для [cl green]вас[cl]!\",\n\t\"shopkeeper_14\": \"Якая [cl yellow]прапанова[cl]!\",\n\t\"bk:magnifier\": \"Павелiчальная Шкляшка\",\n\t\"bk:magnifier_desc\": \"Вялiкiя кулi\",\n\t\"bk:mushroom_hat\": \"Грыбная Шапка\",\n\t\"bk:mushroom_hat_desc\": \"Смачная?\",\n\t\"bk:stone_hat\": \"Закамянелая Шапка\",\n\t\"bk:stone_hat_desc\": \"Цяжкая\",\n\t\"bk:knight_hat\": \"Шлем Рыцара\",\n\t\"bk:knight_hat_desc\": \"Старыя добрыя ворагi...\",\n\t\"bk:cowboy_hat\": \"Капялюш Каýбоя\",\n\t\"bk:cowboy_hat_desc\": \"Дзiкi Захад!\",\n\t\"bk:soup_hat\": \"Супны Капялюш\",\n\t\"bk:soup_hat_desc\": \"^^Смачны.^^\",\n\t\"bk:gold_hat\": \"Залаты Капялюш\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Багач!\",\n\t\"bk:viking_hat\": \"Шлем Вiкiнга\",\n\t\"bk:viking_hat_desc\": \"Амерыка!\",\n\t\"bk:dunce_hat\": \"Капялюш Балбеса\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Кацялок\",\n\t\"bk:top_hat_desc\": \"Мода гэта я!\",\n\t\"bk:ushanka\": \"Ушанка\",\n\t\"bk:ushanka_desc\": \"Дзе мая ##балалайка##?\",\n\t\"bk:valkyrie_hat\": \"Шапка Валькiрыi\",\n\t\"bk:valkyrie_hat_desc\": \"Я веру што ^^я магу лётаць^^!\",\n\t\"bk:skull_hat\": \"Чэрапушка\",\n\t\"bk:skull_hat_desc\": \"Кашалёк або жыццё!\",\n\t\"bk:grandma_head\": \"Галава Бабули\",\n\t\"bk:grandma_head_desc\": \"Чаёк?\",\n\t\"bk:diamond_helmet\": \"Алмазны Шлем\",\n\t\"bk:diamond_helmet_desc\": \"Иди копай!\",\n\t\"bk:villager_head\": \"Галава Жыхара\",\n\t\"bk:villager_head_desc\": \"Хмм?\",\n\t\"bk:fez\": \"Феска\",\n\t\"bk:fez_desc\": \"Кубит\",\n\t\"bk:no_hat\": \"Зняць Капялюш\",\n\t\"bk:no_hat_desc\": \"Няма капялюша - няма праблем!\",\n\t\"bk:null_hat\": \"НУЛЬ\",\n\t\"bk:null_hat_desc\": \"Спроба выклiкаць значэнне null\",\n\t\"accessorytrader_0\": \"##ЗМАТВАЙСЯ АДСЮЛЬ!## [dl]Або купi гэтыя ^^цудоýныя^^ прадметы за ^^%%99 крышталяý кожны%%^^!\",\n\t\"accessorytrader_1\": \"Здароý!\",\n\t\"accessorytrader_2\": \"Прывiтанне!\",\n\t\"weapontrader_0\": \"Заходзь!\",\n\t\"weapontrader_1\": \"Як надворье?\",\n\t\"weapontrader_2\": \"Купи што-небудзь, я хачу паабедаць!\",\n\t\"activetrader_0\": \"Лепшыя прапановы на рынку!\",\n\t\"activetrader_1\": \"Заплацi за два i атрымай два!\",\n\t\"activetrader_2\": \"Купi мне пончыкаý, [dl]калi ласка!!\",\n\t\"hattrader_0\": \"Хочаш быць такiм жа ^^страшэнным^^ як я? [dl]Купi капялюш\",\n\t\"hattrader_1\": \"Хочаш быць такiм жа стромкiм, як я? [dl]Я таксама.\",\n\t\"hattrader_2\": \"^^Ха ха hats!^^\",\n\t\"granny_0\": \"Ня хочаш чайку?\",\n\t\"granny_1\": \"Зрабi паýзу, выпей чайку!\",\n\t\"granny_2\": \"Чайку?\",\n\t\"bk:xmas_hat\": \"Шапка Санты\",\n\t\"bk:xmas_hat_desc\": \"З Калядамi!\",\n\t\"bk:pumpkin_hat\": \"Гарбузища\",\n\t\"bk:pumpkin_hat_desc\": \"^^Стремный стремный шкiлетос^^\",\n\t\"bk:cage_key\": \"Ключ ад Турмы\",\n\t\"bk:cage_key_desc\": \"Выратуй ^^чувака^^!\",\n\t\"npc_0\": \"Дапамажы мне! Знайдзi ключ!\",\n\t\"npc_1\": \"Дзякуй за выратаванне!\",\n\t\"npc_2\": \"Хутчэй, адкрывай дзверы!\",\n\t\"npc_3\": \"Калi ласка, выратуй  мяне!\",\n\t\"control_0\": \"Жмякнi [ic 0][ic 1] каб паставiць бомбу\",\n\t\"control_1\": \"Перакочвацца ты можаш! Тыкнi [ic 0][ic 1] каб здабыць сiлу!\",\n\t\"control_2\": \"Нацiснi [ic 0][ic 1] каб стаць небяспечным\",\n\t\"control_3\": \"Дацягнiся да [ic 0][ic 1] каб ýзаемадзейнiчаць\",\n\t\"control_4\": \"Крак? [ic 0][ic 1]!\",\n\t\"control_5\": \"Выкарыстоýвай [ic 0][ic 1] каб змяняць зброю\",\n\t\"shopkeeper_15\": \"Я не даваý табе знiжак!\",\n\t\"shopkeeper_16\": \"Прынясi пабольш грошай!\",\n\t\"shopkeeper_17\": \"Ты забыýся заплацiць!\",\n\t\"bk:frog\": \"Тэлегушка\",\n\t\"bk:frog_desc\": \"Хуткае перасоýванне?\",\n\t\"bk:sword_orbital\": \"Меч Правасуддзя\",\n\t\"bk:sword_orbital_desc\": \"Ён круцiцца\",\n\t\"robbed\": \"Абрабаваны\",\n\t\"bk:gift_desc\": \"Што ж там унутры?\",\n\t\"bk:spike_ring\": \"калючае Кальцо\",\n\t\"bk:spike_ring_desc\": \"Страты з дотыку\",\n\t\"bk:fire_ring\": \"Падпаленае Кальцо\",\n\t\"bk:fire_ring_desc\" : \"падпальваючы з дотыку\",\n\t\"bk:ice_ring\" : \"Ледзяное Кальцо\",\n\t\"bk:ice_ring_desc\" : \"Замарозка з дотыку\",\n\t\"bk:duck_ring\" : \" Крякцо\",\n\t\"bk:duck_ring_desc\" : \"тэлепартацыя з страт\",\n\t\"bk:dull_blade\" : \"затупiць Брытва\",\n\t\"bk:dull_blade_desc\" : \"Трiгеррыт прадметы на атрыманне страт\",\n\t\"bk:sharp_blade\" : \"Брытва\",\t\t\n\t\"bk:sharp_blade_desc\" : \"Балюча \",\n\t\"bk:obsidian_shield\": \"Обсидиановый Шчыт\",\n\t\"bk:obsidian_shield_desc\": \"Iмунiтэт да отбасыванию\",\n\t\"bk:bill\": \"Валюта\",\n\t\"bk:bill_desc\": \"99 Баксiка\",\n\t\"control_6\": \"Выкарыстоýвай активку з дапамогай [ic 0] [ic 1]\",\n\t\"bk:clover\" : \"Чатырехлiстнiк\",\n\t\"bk:clover_desc\" : \"Шчаслiвы!\",\n\t\"bk:d4\" : \"д4\",\n\t\"bk:d4_desc\" : \"^^ Рэролл %% тваiх артыфактаý %%! ^^\",\n\t\"brastin_0\" : \"знайдзi карцiну [cl purple] з катом [cl]!\",\n\t\"elon_1\" : \"Трымай!\",\n\t\"bk:maanex_head\" : \"Галава Маанекса\",\n\t\"bk:maanex_head_desc\" : \"хмммммм\",\n\t\"bk:maanex\" : \"Маанекс\",\n\t\"bk:maanex_desc\": \"Прымушае ворагаý задумацца\",\n\t\"mob_0\": \"Хмммм\",\n\t\"bk:map_greenprints\": \"Чарцяжы Замка\",\n\t\"bk:map_greenprints_desc\": \"Адкрывае Карту\",\n\t\"bk:map\" : \"Карта\",\n\t\"bk:map_desc\" : \"Адкрывае Карту назаýсёды\",\n\t\"milt_1\" : \"Я хачу падаруначак\",\n\t\"mapuzzle_0\" : \"Гравiтацыя.\",\n\t\"nullptr_0\" : \"ПАМЫЛКА сегментацыi.\",\n\t\"copied_to_clipboard\"  : \"скапiяваць!\",\n\t\"isaac_0\": \"У жыццi няма сэнсу ...\",\n\t\"isaac_1\": \"Чаму\",\n\t\"isaac_2\":\" : sob:\",\n\t\"discord_0\": \"Скажы прывiтанне discord.gg\\/rexcellent\",\n\t\"old_man_5\" : \"Кацiся, дурань!\",\n\t\"tutorial\" : \"Туторыал\",\n\t\"bk:crying_bomb\" : \"Бомба-Плакса\",\n\t\"bk:crying_bomb_desc\" : \"Бомбы страляюць\",\n\t\"bk:matches\"  : \"Запалкi\",\n\t\"bk:matches_desc\": \"Памяншае затрымку перад выбухам у бомбаý\",\n\t\"bk:bomb_pack\": \"Пачак бомба\",\n\t\"bk:bomb_pack_desc\": \"Мы кладзем бомбы ý вашыя бомбы!\",\n\t\"bk:tnt\" : \"Дынамiт\",\n\t\"bk:tnt_desc\" : \"99 узрывалак\",\n\t\"bk:weird_mushroom_desc\" : \"падвойвае ýсё\",\n\t\"bk:weird_mushroom\" : \"стремно Грыб\",\n\t\"bk:bomb_shower\" : \"Бомбический Душ \" ,\n\t\"bk:bomb_shower_desc\": \"Хай пойдзе дождж з бомбаý!\",\n\t\"bk:black_belt\": \"Чорны Пояс\",\n\t\"bk:black_belt_desc\": \"Больш не падрываць\",\n\t\"bk:ninjia_bomb\": \"Бомба Нiндзя\",\n\t\"bk:ninjia_bomb_desc\": \"Заклiкае падмогу пры атрыманнi страт\",\n\t\"start_new_run\": \"Твой заб яг будзе сцёрты!\",\n\t\"bk:laser_pointer\" : \"Лазерная ýказка\",\n\t\"bk:laser_pointer_desc\" : \"Паказаць\",\n\t\"ach_bk:marauder\" : \"Марадер\",\n\t\"ach_bk:marauder_desc\" : \"Убей гандляра\",\n\t\"ach_bk : treasure_hunter\" : \"Паляýнiчы за скарбамi\",\n\t\"ach_bk:treasure_hunter_desc\" : \"Знайдзi сакрэткi\",\n\t\"ach_bk:dodge_master\" : \"Майстар Додж\",\n\t\"ach_bk:dodge_master_desc\" : \"завал босяру без атрымання страху\",\n\t\"ach_bk:dodge_overlord\" : \"Уладар Додж\",\n\t\"ach_bk:dodge_overlord_desc\" : \"Прайдзi паверх без атрымання страт\",\n\t\"ach_bk:quackers\" : \"Квакерz\",\n\t\"ach_bk:quackers_desc\" : \"Пераквакай\",\n\t\"ach_bk:tea_party\" : \"Паýдзённы Чай\",\n\t\"ach_bk:tea_party_desc\" : \"Выпi кубачак гарбаты з бабусi\",\n\t\"ach_bk:not_a_thief\" : \"Больш не Злодзей\",\n\t\"ach_bk:not_a_thief_desc\" : \"завяршыýся забег не ýзяýшы ня еди ого прадмета\",\n\t\"ach_bk:npc_party2\" : \"туса\",\n\t\"ach_bk:npc_party2_desc\" : \"Выратуй усiх NPC\",\n\t\"bk:gold_coin\" : \"Залатая Манета\",\n\t\"bk:iron_coin\" : \"Жалезная Манета\",\n\t\"bk : copper_coin\" : \"Медная Манета\",\n\t\"bk:platinum_coin\" : \"Плацiнавая Манета\",\n\t\"bk:voodoo_doll\" : \"Лялька Вуду\",\n\t\"bk:voodoo_doll_desc\" : \"Забiвае ýсiх ворагаý у пакоi\",\n\t\"hub\" : \"Горад Доджа\",\n\t\"castle\" : \"Графскi Развалiны\",\n\t\"charger_0\" : \"АКТИВКА НЕ вЫЯУЛЕНА\",\n\t\"charger_1\" : \"АКТИВКА УЖО ЗАРАДЖАНА\",\n\t\"charger_2\" : \"ДЗЕ МАЕ ГРОШЫ, мяшок з мясам?\",\n\t\"charger_3\" : \"## Я КАЗА ДАЙ МНЕ ГРОШЫ! ##\",\n\t\"charger_4\" : \"## Я захоплены УВЕСЬ СВЕТ! ##\",\n\t\"charger_5\" : \"## МУХАХАХАХАХАХА ##\",\n\t\"maanex_6_0\" : \"Вядома, давай!\",\n\t\"maanex_6_1\" : \"Найн.\",\n\t\"maanex_6\" : \"Окей, дай мне [cl yellow] [vr cost] манет [cl] i я дам табе адкрыць адзiн куфар, iдзе?\",\n\t\"maanex_5\" : \"Гэй ты, не хочаш ^^ выпрабаваць поспех ^^?\",\n\t\"maanex_7\" : \"Гэта было весела!\",\n\t\"maanex_8\" : \"Удачы!\",\n\t\"maanex_9\": \"Ну, пашанцуе ý наступны раз :(\",\n\t\"maanex_10\": \"%%^^ВАУ^^%%\",\n\t\"maanex_11\": \"Але ý цябе няма столькi грошай!\",\n\t\"maanex_12\": \"##СЫН?!##\",\n\t\"bk:amurs_arrow\": \"Страла Амура\",\n\t\"bk:amurs_arrow_desc\": \"ýлюбляюцца кулi\",\n\t\"bk:amurs_bow\": \"Цыбуля Амура\",\n\t\"bk:amurs_bow_desc\" : \"Я бачу каханне\",\n\t\"bk:poison_flask\" : \"склянкi з атрутай\",\n\t\"bk:poison_flask_desc\" : \"Атручаныя Кулi\",\n\t\"bk:snowball\" : \"Сняжок\",\n\t\"bk:snowball_desc\" : \"Страшэнна непрыемныя кулi\",\n\t\"bk:peper\" : \"Востры Перчык\",\n\t\"bk:peper_desc\" : \"Гарачыя кулi\",\t\n\t\"bk:sale_coupon\" : \"Купон на Знiжкон\",\n\t\"bk:sale_coupon_desc\" : \"-50%! \",\n\t\"bk:pet_box\": \"Кот у Скрынцы\",\n\t\"bk:pet_box_desc\" : \"А хто ж ýнутры?\",\n\t\"bk:crate\" : \"Скрынка з арбiталей\",\n\t\"bk:crate_desc\" : \"А хто ж ýнутры?\",\n\t\"bk:strawberry\" : \"Клубнiчка\",\n\t\"bk:strawberry_desc\" : \"Салодкiя ýспамiны\",\n\t\"bk:wings\" : \"Крылы\",\n\t\"bk:wings_desc\" : \"я не веру, што я магу лятаць\",\n\t\"bk:coin_pouch\" : \"Мешочек з манетамi\",\n\t\"bk:coin_pouch_desc\" : \"Цi дае манеты\",\n\t\"bk:key_pouch\" : \"Мешочек з Ключамi\",\n\t\"bk:key_pouch_desc\" : \"Цi дае ключы\",\n\t\"bk:bomb_pouch\" : \"Бомбический Мешочек\",\n\t\"bk : bomb_pouch_desc\" : \"Цi дае бомбы\",\n\t\"bk:pouch_pouch\" : \"Мешочек з мяшочка\",\n\t\"bk:pouch_pouch_desc\" : \"Ён дакладна не дае мяшэчкi\",\n\t\"bk:lightsaber\" : \"Светсейбер\",\n\t\"bk:lightsaber_desc\"  : \"Ты быý абраным!\",\n\t\"bk:snail\": \"Слiмак\",\n\t\"bk:snail_desc\": \"Запавольвае ворагаý\",\n\t\"bk:spike\": \"Калючка\",\n\t\"bk:spike_desc\" : \"+1 да страт\",\n\t\"bk:mushroom\" : \"Грыб\",\n\t\"bk:mushroom_desc\" : \"буст хуткасць\",\n\t\"bk:candy\" : \"Цукерка\",\n\t\"bk:candy_desc\" : \"^^ павышае бадзёрасць ^^, павялiчвае хуткасць стрэльбы\",\n\t\"bk:glasses\" : \"Ачкi\",\n\t\"bk:glasses_desc\" : \"Падвышаная дакладнасць\",\n\t\"bk:ruler\" : \"Лiнейка\",\n\t\"bk:ruler_desc\" : \"+1 да далёкасцi атакi\",\n\t\"bk:stopwatch\" : \"Секундамер\",\n\t\"bk:stopwatch_desc\" : \"Атрыманне страт запавольвае час\",\n\t\"bk_0\" : \"## НЯ СМЕЙ ЧАПАЦЬ ГЭТА! ## \",\n\t\"bk_1\": \"## Я СКАЗАЛ НЕ ЧАПАЦЬ !! ##\",\n\t\"bk_2\": \"## ТЫ НЕ МОЖАШ ПЕРАМАГЧЫ МЯНЕ, [cl red] ПАДПАЛЕНАГА РЫЦАРА [cl], ДУРАНЬ! ##\",\n\t\"bk_3\": \"## ПРЫГАТАВАЦЬ СУСТРЭЧУ! ##\",\n\t\"bk_4\": \"^^ КАКАЯ ШУТКА ^^\",\n\t\"shopkeeper_18\": \"[cl red] ^^ Гарачая распродажа! [cl]\",\n\t\"dm_0\": \"@ @  Да нас запрашаем @@\",\n\t\"ach_bk:deal\" : \"Выбiтны Ход\",\n\t\"ach_bk:deal_desc\" : \"Зрабi здзелку з Цёмным Чараýнiком\",\n\t\"ach_bk:grannys_gift\" : \"Падарунак Бабулi\",\n\t\"ach_bk:grannys_gift_desc\" : \"Атрымай падарунак ад бабусi\",\n\t\"ach_bk:shopper\" : \"Пакупкi да упаду\",\n\t\"ach_bk:shopper_desc\" : \"Купi прадмет у магазе\",\n\t\"bk_5\" : \"Я Б НЕ ЗВЯРТАÝ УВАГУ НА ГЭТУ ПСКЛЮ\",\n\t\"bk_6\" : \"## ЗАБI ЯГО, [cl lime] ЭДВАРД [cl]! ##\",\n\t\"bk_7\" : \"[cl lime] ЭДВАРД [cl], ## НЕЕЕЕЕЕТ !!!! ##\",\n\t\"bk_8\" : \"ПЕРАСТАНЬ ПАДРЫВАЦЬ МОЙ ЗАМАК!\",\n\t\"bk_9\" : \"[cl pink] БАБУЛЬКА [cl], [dl] ТЫ МОЖАШ УЖЕ ЗГIНУЦЬ, КАЛI ЛАСКА ##?!? ##\",\n\t\"bk_10\" : \"МАЙСТАР, [dl] Я ПРЫВЁÝ [cl green] ГОБЛIНА [cl]\",\n\t\"dm_1\" : \"Вельмi добра [dl], дзякуй [dl], [cl red] Лимпор [cl]\",\n\t\"dm_2\" : \"## Так, так, мне трэба больш [cl orange] моцы [cl]! ##\",\n\t\"dm_3\" : \"## БОЛЬШ [cl orange] моцы [cl]!\",\n\t\"dm_4\" : \"Я чуствую [cl orange] моц [cl] пульсавалую ýва мне !\",\n\t\"granny_3\" : \"Ты будзеш першым, [cl red] Лимпор [cl]!\",\n\t\"granny_4\" : \"Сардэчна запрашаем, [cl green] Гоббо [vr id][cl]!\",\n\t\"granny_5\" : \"Удачы ý тваiм сумным квэсце!\",\n\t\"bk:meat_guy\" : \"Мясны Таварыш\",\n\t\"bk:meat_guy_desc\" : \"Магутны!\",\n\t\"bk:bullet_stone\" : \"Каменны Стралок\",\n\t\"bk:bullet_stone_desc\" : \"Ён аттакует i абараняе!\",\n\t\"bk:batman\" : \"Батарейкман\",\n\t\"bk:batman_desc\" : \"Не дапамагае, але затое дае батарэйкi\",\n\t\"vibration\" : \"Вiбрацыя\",\n\t\"bk:sharp_arrow\" : \"Вострая Страла\",\n\t\"bk:sharp_arrow_desc\" : \"Скразныя кулi\",\n\t\"machine_0\" : \"Устаýце [cl yellow] манету\",\n\t\"bk:boomerang\" : \"Бумеранг\",\n\t\"bk:boomerang_desc\" : \"кулi вернуцца\",\n\t\"bk:backpack\" : \"Заплечнiк\",\n\t\"bk:backpack_desc\" : \"Больш месца\",\n\t\"place_an_item\" : \"Пакласцi Зброя\",\n\t\"bk:crystal\" : \"Крышталь\",\n\t\"bk:crystal_desc\" : \"Сiла Вясёлкi \",\n\t\"bk:prism\": \"Прызма\",\n\t\"bk:prism_desc\": \"Кулi -> Вясёлка\",\n\t\"scourged\": \"Пракляты\",\n\t\"bk:bomb\": \"Бомба\",\n\t\"bk:scourge_of_egg\": \"Праклён Яйкi\",\n\t\"bk:scourge_of_egg_desc\" : \"пераблыталi назвы\",\n\t\"bk:scourge_of_unknown\" : \"Праклён невядома\",\n\t\"bk:scourge_of_unknown_desc\" : \"Схаваныя прадметы\",\n\t\"bk:scourge_of_blood\" : \"Праклён Крывi\",\n\t\"bk:scourge_of_blood_desc\" : \"Больш ворагаý\",\n\t\"bk:scourge_of_risk\" : \"Праклён Рызыкi\",\n\t\"bk:scourge_of_risk_desc\" : \"Схаванае здароýе\",\n\t\"bk:scourge_of_keys\" : \"Праклён Ключоý\",\n\t\"bk:scourge_of_keys_desc\" : \"Схаваныя пiкапы \" ,\n\t\"bk:scourge_of_lost\": \"Праклён Страчанага\",\n\t\"bk:scourge_of_lost_desc\" : \"Амнезiя\",\n\t\"bk:scourge_of_scourged\" : \"Праклён праклён\",\n\t\"bk:scourge_of_scourged_desc\" : \"Праклёны Усюды\",\n\t\"bk:scourge_of_illness\" : \"Праклён Хворага\",\n\t\"bk:scourge_of_illness_desc\" : \"Сэрца лечаць менш\",\n\t\"bk:scourge_of_death\" : \"Праклён Смерцi\",\n\t\"bk:scourge_of_death_desc\" : \"Хардмод\",\n\t\"bk:ancient_revolver\" : \"Старажытны Рэвальвер\",\n\t\"bk:ancient_revolver_desc\" : \"Выглядае Классно \" ,\n\t\"bk:assault_rifle\": \"Штурмавая Вiнтоýка\",\n\t\"bk:assault_rifle_desc\": \"Пiу Пiу\",\n\t\"fountain_0\": \"Прынясi пяць манет i я благославлю цябе\",\n\t\"fountain_1\": \"Ты быý часткова ачышчаны\",\n\t\"fountain_2\" : \"Ты быý цалкам ачышчаны\",\n\t\"fountain_3\" : \"Ты ýжо ачышчаны\",\n\t\"buffed\" : \"Бафнут\",\n\t\"nerfed\" : \"Панерфлен\",\n\t\"restored\" : \"узражден\",\n\t\"damaged\" : \"калецтваý\",\n\t\"cleansed\" : \"ачышчаны\",\n\t\"gifted\" : \"адарыý\",\n\t\"lucky\" : \"Шчаслiýчык\",\n\t\"unlucky\" : \"Няýдачнiк\",\n\t\"max_hp\" : \"Максiмальнае HP\",\n\t\"touch\" : \"пакратаць\",\n\t\"break\" : \"Зламаць\",\n\t\"no_coins\" : \"Няма Манет\",\n\t\"old_man_6\" : \"Небяспечна iсцi аднаму, вазьмi гэта!\",\n\t\"roger_0\" : \"Бум! \",\n\t\"roger_1\": \"## * бУМ * ##\",\n\t\"roger_2\": \"бум бум шакалака!\",\n\t\"bk:shield\": \"Шчыт\",\n\t\"bk:gift\": \"Падарунак\",\n\t\"bk:shield_pouch\" : \"Мешочек з Шчытамi\",\n\t\"bk:shield_pouch_desc\": \"Цi дае шчыты\",\n\t\"bk:shield_buddy\": \"Щитовик\",\n\t\"bk:shield_buddy_desc\": \"Абаронца\",\n\t\"bk:skeleton_key\": \"Ключ Шкiлета\",\n\t\"bk:skeleton_key_desc\" : \"99 ключыкаý\",\n\t\"bk:jar\" : \"склянкамi са Здароýем\",\n\t\"bk:jar_desc\" : \"Джэм\",\n\t\"bk:star\" : \"Зорка\",\n\t\"bk:star_desc\" : \"Абарона\",\n\t\"bk:car_bomb\" : \"Бомбы на колах\",\n\t\"bk:car_bomb_desc\" : \"сiстэму ма дастаýкi бомбаý да ворагаý\",\n\t\"bk:grenade\" : \"Граната\",\n\t\"bk:grenade_desc\" : \"Бомбы выбухаюць пры дотыку\",\n\t\"trash_goblin_0\" : \"Выратуй мяне ад майго [cl purple] праклёны [cl]! Калi ласка!\",\n\t\"Trash_goblin_1\" : \"Я свабодны! [Dl] Дзякуй табе велiзарнае!\",\n\t\"Boxy_0\" : \"Балдеж\",\n\t\"boxy_1\" : \"Якая ýпакоýка!\",\n\t\"Boxy_2\" : \"Табе патрэбна абгортачная папера? \" ,\n\t\"trash_goblin_2\": \"^^ Туман над ракой ^^\",\n\t\"bk:vampire_bat\": \"Мыш Вампiр\",\n\t\"bk:vampire_bat_desc\": \"Реген\",\n\t\"shields\": \"Шчыты\",\n\t\"bk:mustache\": \"Вусы\",\n\t\"bk:mustache_desc\": \"ВIП\",\n\t\"bk:bloody_chest\": \"Крывавы Сундук\",\n\t\"bk:bloody_chest_desc\": \"Куфры лечят\",\n\t\"bk:bloody_shield\": \"Крывавы Шчыт\",\n\t\"bk:bloody_shield_desc\" : \"Шчыты назаýсёды\",\n\t\"bk:cutsaw\" : \"Пiла\",\n\t\"bk:cutsaw_desc\" : \"Ворагi заплацяць\",\n\t\"vampire_0\" : \"Нам!\",\n\t\"vampire_1\" : \"Балдеж\",\n\t\"vampire_2\" : \"Мммм\",\n\t\"vampire_3\": \"Мы ведаем правiлы, [cl red] ^^ цi не так [cl]?\",\n\t\"vampire_4\": \"^^ Мммммм ^^\",\n\t\"vampire_5\": \"Якi ý цябе тып крывi ?\",\n\t\"vampire_6\"  : \"Смаката\",\n\t\"duck_2\": \"Адкажаш на пару пытанняý?\",\n\t\"Duck_7_0\": \"Давай\",\n\t\"duck_7_1\": \"Не\",\n\t\"duck_7\": \"Ты атрымаеш гэты куфар?\",\n\t\"Duck_4\": \" прыгажунчык, трымай куфар!\",\n\t\"duck_5\" : \"Я не магу з табой пагадзiцца ...\",\n\t\"duck_6_0\" : \"Сусвет\",\n\t\"duck_6_1\" : \"^^ кваркаý ^^\",\n\t\"duck_6\" : \"Пра што я думаю?\",\n\t\"duck_8_0\" : \"[cl red] Чырвоны [cl]\",\n\t\"duck_8_1\" : \"[cl blue] Сiнi [cl]\",\n\t\"duck_8\" : \"Якi мой любiмы ^^ %% колер %% ^^?\",\n\t\"duck_9_0\" : \"Кошка\",\n\t\"duck_9_1\" : \"Ты\",\n\t\"duck_9\" : \"Хто сказаý \\\"мяу\\\"?\",\n\t\"duck_10_0\" : \"0\",\n\t\"duck_10_1\" : \"1\",\n\t\"duck_10\" : \"Што лепш?\",\n\t\"duck_11_0\" : \"Што, ты яйка?\",\n\t\"duck_11_1\" : \"\\\\[_ Ён ударыý его._]\",\n\t\"duck_11\" : \"ты соус\",\n\t\"duck_12_0\" : \"Курыца\",\n\t\"duck_12_1\" : \"Яйка\",\n\t\"duck_12\" : \"Што было першым?\",\n\t\"duck_13_0\" : \"Нiчога.\",\n\t\"duck_13_1\" : \"Снэк.\",\n\t\"duck_13_2\" : \"Яйка.\",\n\t\"duck_13_3\" : \"Смажаная курыца.\",\n\t\"duck_13\" : \"Што я еý сёння?\",\n\t\"duck_14\" : \"Ой.\",\n\t\"duck_17_0\" : \"Вядома\",\n\t\"duck_17_1\"  : \"## Нанi ##\",\n\t\"duck_17\": \"Як наконт ананасаý на тваёй пiцы?\",\n\t\"duck_18_0\": \"Белага!\",\n\t\"duck_18_1\": \"[cl yellow] Жоýтага [cl]!\",\n\t\"duck_18\" : \"Якога колеру сыр?\",\n\t\"nurse_0\" : \"Ты выглядаеш выдатна, дарагi!\",\n\t\"nurse_1\" : \"Я магу цябе падлячыць, але мне трэба [cl yellow] [vr price] манет [cl]\",\n\t\"nurse_2\" : \"Я спадзяюся гэта было не балiць\",\n\t\"elon_4\" : \"Трымай, поспеху\",\n\t\"elon_2_0\" : \"Паехалi\",\n\t\"elon_2_1\" : \"надвор'е\",\n\t\"elon_2\" : \"Хочаш выпрабаваць маю магiю? \",\n\t\"elon_3\": \"Я магу трансмутировать тваё зброю\",\n\t\"elon_5\": \"Ну добра\",\n\t\"elon_7\": \"Бро, дзе тваё зброю ???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\":\" : 3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"* blush *\",\n\t\"gobetta_4\": \"Гэта ... ты?\",\n\t\"Gobetta_5\": \"Столькi гадоý мiнула ...\",\n\t\"ach_bk:desert\": \"Суха ды Жарко\",\n\t\"ach_bk:desert_desc\": \"дойдзем да пустыннага Замка\",\n\t\"ach_bk:jungle\": \"Жужала Пчолкi\",\n\t\"ach_bk:jungle_desc\": \"Дабярыся да Старажытных Джунглей\",\n\t\"rooms_explored\" : \"Пакояý даследавана\",\n\t\"bk:shadow_cloak_desc\" : \"No U\",\n\t\"bk:shadow_cloak\" : \"Мантыя Неведимка\",\n\t\"bk:dynamite_stick\" : \"Палка дынамiту\",\n\t\"bk:dynamite_stick_desc\" : \"Хочаш бомбануть?\",\n\t\"bk:chalice_of_blood\" : \"Кубак з Крывёю\",\n\t\"bk:chalice_of_blood_desc\" : \"Боль выклiкае злосць, злосць выклiкае страты\",\n\t\"bk:detonator\" : \"Дэтанатар\",\n\t\"bk:detonator_desc\" : \"выклiкае выбухi\",\n\t\"invincibility_time\" : \"Час непаражальным\",\n\t\"accuracy\" : \"Дакладнасць\",\n\t\"range\" : \"Так льность\",\n\t\"fire_rate\" : \"Хуткасць Аттаки\",\n\t\"speed\" : \"Хуткасць\",\n\t\"bk:talisman_of_foresight\" : \"Талiсман прадбачання\",\n\t\"bk:talisman_of_foresight_desc\" : \"Адкрый вочы i ýбачыýшы суседнiя пакоi!\",\n\t\"bk:scourge_ring\" : \"Праклятае Кальцо\",\n\t\"bk:scourge_ring_desc\" : \"Iмунiтэт да праклёнам\",\n\t\"snek_0\" : \"Найс.\",\n\t\"snek_1\" : \"Дддддзякуй\",\n\t\"snek_2\" : \"Класшшш\",\n\t\"snek_3\" : \"прывiтанне\",\n\t\"snek_4\" : \"Добрага часу шшуток\",\n\t\"snek_5\" : \"Купi шшшто-небудзь?\",\n\t\"snek_6\" : \"Мне трэба удоволетворить пакупнiка ...\",\n\t\"snek_7\" : \"я ссссделаю то, шшшто я павiнен!\",\n\t\"bk:snek\" : \"смей\",\n\t\"bk:snek_desc\" : \"Снэк?\",\n\t\"boxy_3\" : \"^^: wave: ^^\",\n\t\"boxy_4\" : \"Цi знойдзецца лiшнi ключ? \",\n\t\"boxy_5\": \"Дай пару ключоý?\",\n\t\"bk:blank\": \"Пустышка\",\n\t\"bk:blank_desc\": \"_Пусты Тэкст_\",\n\t\"bk:blank_bombs\" : \"Пустыя Бомбы\",\n\t\"bk:blank_bombs_desc\" : \"_Пустота_\",\n\t\"bk:explosive_bullets\" : \"Бомбические Кулi\",\n\t\"bk:explosive_bullets_desc\" : \"Выбухаюць\",\n\t\"bk:random_bullets\"  : \"Выпадковыя Кулi\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Чашка\",\n\t\"bk:cup_desc\": \"Бабуля не зможа не прыйсцi\",\n\t\"bk:cartridge\": \"Катрыджа\",\n\t\"bk:cartridge_desc\": \"Цёмны Чараýнiк абяцаý зайсцi пагуляць\",\n\t\"bk:marriage_ring\": \"Заручальнае Кальцо\",\n\t\"bk:marriage_ring_desc\": \"Цёмны Чараýнiк & Бабуля назаýсёды!\",\n\t\"boxy_7\": \"Я хачу ключоý\",\n\t\"boxy_8\": \"у цябе не дастаткова ключоý :(\",\n\t\"boxy_9\": \"Цяпер у мяне хапае ключоý каб ^^ адкрыцца ^^!\",\n\t\"roger_3\": \"Я не супраць калi ты заплацiш\",\n\t\"roger_4\": \"Сёння няма знiжак\",\n\t\"roger_5\": \"Бомбы ýтаропiý адз\",\n\t\"vampire_7\" : \"Ты не здаровы\",\n\t\"vampire_8\" : \"Я не даю скiдак\",\n\t\"vampire_9\" : \"Ты памрэш\",\n\t\"ach_bk:scourged\" : \"Пракляты\",\n\t\"ach_bk:scourged_desc\" : \"атрымай токен праклёны\",\n\t\"ach_bk:scourged_weapon\" : \"праклятае зброя\",\n\t\"ach_bk:scourged_weapon_desc\" : \"атрымай праклятае зброю\",\n\t\"rerolled\" : \"Зарэролена\",\n\t\"ach_bk:open_up\" : \"Адкрывашка\",\n\t\"ach_bk:open_up_desc\" : \"Купi усё ý краме бокс\",\n\t\"ach_bk:snek\" : \"змяя ý ботах\",\n\t\"ach_bk:snek_desc\" : \"займець гандляра змея ý якасцi гадаванца\",\n\t\"bk:scourge_of_greed\" : \"Праклён прагнасць\",\n\t\"bk : scourge_of_greed_desc\" : \"Высокiя цэны\",\n\t\"killed_by\" : \"Забойца\",\n\t\"kills\" : \"Забiта iстот\",\n\t\"time\" : \"Час\",\n\t\"depth\" : \"Узровень\",\n\t\"bk:blank_bullets\" : \"Пустыя кулi\",\n\t\"bk:blank_bullets_desc\" : \"Пуста\",\n\t\"bk:lego\"  : \"Канструктар\",\n\t\"bk:lego_desc\": \"На яго так балюча наступаць ...\",\n\t\"bk:iron_armor\": \"Стальная Броня\",\n\t\"bk:iron_armor_desc\": \"Цi дае Шчыты\",\n\t\"bk:round_shield\": \"Круглы Шчыт\",\n\t\"bk:round_shield_desc\": \"Iмунiтэт да кантактнага страт\",\n\t\"bk:arkhalis\": \"Аркалис\",\n\t\"bk:arkhalis_desc\": \"Легендарны меч\",\n\t\"bk:inverted_arkhalis\": \"Антычны Аркалис\",\n\t\"bk:inverted_arkhalis_desc\": \"Падмога пры 1 hp\",\n\t\"bk:gun_sword\": \"Пушкамеч\",\n\t\"bk:gun_sword_desc\": \"Мутант\",\n\t\"ach_bk:scourge_king_desc\": \"Атрымай 10 праклёнаý\",\n\t\"ach_bk:scourge_king\" : \"Пракляты Кароль\",\n\t\"ach_bk:sting_operation\": \"Жальная Аперацыя\",\n\t\"ach_bk:sting_operation_desc\": \"Перамажы Каралеву Пчалу\",\n\t\"ach_bk:mummified\": \"забальзамаваную\",\n\t\"ach_bk:mummified_desc\": \"Перамажы фараона\",\n\t\"ach_bk:democracy\": \"Дэмакратыя\",\n\t\"ach_bk:democracy_desc\": \"Перамажы Караля\",\n\t\"pharaoh_scream\": \"## Прыгатаваць СТАЦЬ мумiяй! ##\",\n\t\"queen_bee_scream\": \"## ЗА [cl yellow] HONEY LORD [cl]! ##\",\n\t\"bk : half_heart\" : \"Пол Сэрца\",\n\t\"right\" : \"Направа\",\n\t\"down\" : \"Унiз\",\n\t\"left\" : \"Налева\",\n\t\"up\" : \"Уверх\",\n\t\"painting_cat\" : \"Кот\",\n\t\"bk:axe\" : \"Сякера\",\n\t\"bk:axe_desc\" : \"Ён паляцеý, але абяцаý вярнуцца\",\n\t\"bk:guitar\" : \"Гiтара\",\n\t\"bk:guitar_desc\" : \"Яна вельмi растроена\",\n\t\"bk:glass_sword\" : \"Шкляны Меч\",\n\t\"bk:glass_sword_desc\" : \"Зброя майстроý\",\n\t\"bk:chicken\" : \"Крыльца\",\n\t\"bk:chicken_desc\" : \"Ай, пальчыкi апёк\",\n\t\"bk:pickaxe\" : \"Кiрха \" ,\n\t\"bk:pickaxe_desc\": \"Капай давай\",\n\t\"bk:mana\": \"Мана\",\n\t\"bk:half_mana\": \"Пол маны\",\n\t\"bk:lava_wand\": \"Посах Лавы\",\n\t\"bk:lava_wand_desc\": \"Гарачы\",\n\t\"bk:web_wand\": \"Павуковы Посах\",\n\t\"bk:web_wand_desc\": \"правайдер web сэрвiсаý\",\n\t\"bk:slap_stick\" : \"Палка Надавалка\",\n\t\"bk:slap_stick_desc\" : \"шлёп\",\n\t\"sensivity\" : \"Адчувальнасць\",\n\t\"no\" : \"Не\",\n\t\"scale\" : \"Наблiжэнне \",\n\t\"ach_bk:ice\": \"Леднiковы Перыяд\",\n\t\"ach_bk:ice_desc\": \"Дабярыся да Ледзяных развалiны\",\n\t\"ach_bk:library\": \"Знiклыя Тэксты\",\n\t\"ach_bk:library_desc\": \"Дабярыся да Сакрэтнай Бибилотеки\",\n\t\"bk : ice_skates\" : \"Канькi\",\n\t\"bk:ice_skates_desc\" : \"Iмунiтэт да лёду\",\n\t\"bk:campfire_in_bottle\" : \"Вогнiшча ý бутэльку\",\n\t\"bk:campfire_in_bottle_desc\" : \"Iмунiтэт да замарозцы\",\n\t\"library\" : \"Сакрэтная бiблiятэка\",\n\t\"ach_bk:cat_without_a_hat\" : \"Кот без шапкi\",\n\t\"ach_bk:cat_without_a_hat_desc\" : \"Знайдзi карцiну з Катом\",\n\t\"ach_bk:rich\" : \"Туалетная Папера\",\n\t\"ach_bk:rich_desc\" : \"Збяры 99 манет \" ,\n\t\"ach_bk:rescue_operation\" : \"Выратавальная Аперацыя\",\n\t\"ach_bk:rescue_operation_desc\" : \"Выратуй NPC\",\n\t\"ach_bk:tutorial\" : \"Былы\",\n\t\"ach_bk:tutorial_desc\" : \"Закончы туторыал\",\n\t\"ach_bk:fancy_hat\" : \"Клевы  Капялюш\" ,\n\t\"ach_bk:fancy_hat_desc\": \"Купi Капялюш\",\n\t\"ach_bk:unlock\": \"Адкрывальнiк\",\n\t\"ach_bk:unlock_desc\": \"разблакуюцца прадмет\",\n\t\"floor_brightness\": \"Якрость Пола\",\n\t\"ach_bk:shielded\": \"Падняць шчыты\",\n\t\"ach_bk:shielded_desc\" : \"займець сэрца-шчыт\",\n\t\"run_type\" : \"Тып забегу\",\n\t\"run_regular\" : \"Звычайны\",\n\t\"run_challenge\" : \"Выпрабаванне\",\n\t\"damage_taken\" : \"Страты атрыманы \",\n\t\"km\": \"км\",\n\t\"distance_traveled\": \"Дыстанцыя\",\n\t\"seed\": \"Сiд\",\n\t\"score\": \"Рахунак\",\n\t\"new_high_score\": \"Новы рэкорд!\",\n\t\"items_collected\": \"Рэчаý сабрана\" ,\n\t\"boss_rush\": \"Бос Раш\",\n\t\"run_bossrush\": \"Бос Раш\",\n\t\"bk:blindfold\": \"Павязка\",\n\t\"Daily_run\" : \"Дэйлик\",\n\t\"builder_0_0\" : \"Так\",\n\t\"builder_0_1\" : \"Мне самому патрэбныя грошы\",\n\t\"builder_0\" : \"Я планую пабудаваць тунэль сюды, але мне трэба яшчэ [vr need] [ic 0]. Можаш дапамагчы?\",\n\t\"Builder_1\" : \"Але ý цябе наогул няма грошай!\",\n\t\"Builder_2\" : \"Дзякуй за iнвестыцыю!\",\n\t\"Builder_3\" : \"У мяне нарэшце дастаткова грошай для заканчэння гэтага праекта! Дзякуй велiзарнае!\",\n\t\"Builder_4\" : \"Ок, прабач!\",\n\t\"Shortcut_is_broken\" : \"Тунэль Зламаны\",\n\t\"ach_bk:boss_rush\" : \"заваёýнiк босаý\",\n\t\"ach_bk:boss_rush_desc\" : \"Перамажы ýсiх босаý ý Бос Раше \" ,\n\t\"ach_bk:daily\": \"Дзённая Слава\",\n\t\"ach_bk:daily_desc\": \"выйграла Дейлик\",\n\t\"ach_bk:desert_shortcut\": \"Пустынны Тунэль\",\n\t\"ach_bk:desert_shortcut_desc\": \"пачын тунель, якi вядзе ý Пустынны Палац\",\n\t\"ach_bk:jungle_shortcut\": \"Старажытны Тунэль\",\n\t\"ach_bk:jungle_shortcut_desc\": \"пачын тунель, якi вядзе ý Старажытныя Джунглi\",\n\t\"ach_bk:ice_shortcut\": \"Ледзяны Тунэль\",\n\t\"ach_bk:ice_shortcut_desc\": \"пачын тунель, якi вядзе ý ледзяныя Развалiны\",\n\t\"ach_bk:library_shortcut\" : \"Сакрэтны Тунэль\",\n\t\"ach_bk:library_shortcut_desc\" : \"пачын тунель, якi вядзе ý Сакрэтную Бiблiятэку\",\n\t\"ach_bk:fashion_matters2\" : \"Мода Важная\",\n\t\"ach_bk:fashion_matters2_desc\" : \"Купi усё капялюшы\",\n\t\"ach_bk:10_challenges\" : \"Challenger\",\n\t\"ach_bk:10_challenges_desc\" : \"Скончы 10  выпрабавання\" ,\n\t\"ach_bk:20_challenges\": \"Challenger 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Скончы 20 выпрабаваннi\",\n\t\"ach_bk:30_challenges\": \"Challenger 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Скончы 30 выпрабаваннi\",\n\t\"ach_bk:bk_no_more\" : \"BK no more\",\n\t\"ach_bk:bk_no_more_desc\" : \"Пераможыць Падпаленага Рыцара\",\n\t\"ach_bk:dm_no_more\" : \"DM no more\",\n\t\"ach_bk:dm_no_more_desc\" : \"Пераможыць Цемнага Калдуна\",\n\t\"ach_bk : egor_no_more\" : \"Egor no more\",\n\t\"ach_bk:egor_no_more_desc\" : \"???\",\n\t\"ach_bk:loop\" : \"Ah, here we go again\",\n\t\"ach_bk:loop_desc\" : \"Enter the loop\",\n\t\"coins_collected\" : \"Манет собранно\",\n\t\"bk:cup_head\" : \"Галавачашка\",\n\t\"bk:cup_head_desc\" : \"Выпi чайку\",\n\t\"bk:mustache_hat\" : \"Вусы\",\n\t\"bk:mustache_hat_desc\" : \"AFK\",\n\t\"bk:propeller_hat\" : \"Шапка з маторчыкам\",\n\t\"bk:propeller_hat_desc\": \"Ён круцiцца\",\n\t\"bk:sunglasses\": \"Сонечныя Ачкi\",\n\t\"bk:sunglasses_desc\": \"Гэтак жа працуюць з Месяцам!\",\n\t\"bk:cap\": \" кепка\",\n\t\"bk:cap_desc\" : \"Круты @ - @\",\n\t\"bk:eyes\" : \"Вочы\",\n\t\"bk:eyes_desc\" : \"@ @\",\n\t\"bk:eye\" : \"Вока\",\n\t\"bk:eye_desc\" : \"@\",\n\t\"bk:hair\" : \"Валасы\",\n\t\"bk:hair_desc\" : \"Ну нарэшце\",\n\t\"won\" : \"Перамог\",\n\t\"won_message\" : \"Ты перамог!\",\n\t\"garderobe_sign\" : \"Гардэроб\",\n\t\"darkmarket_tip\": \"~~ [cl purple] Праклён [cl] або [cl yellow] 30 манет [cl] @@\",\n\t\"mike_0\": \"Заплацi мне [cl green] 3 смарагду\",\n\t\"mike_1\" : \"Паспрабуй Бос Раш ýсяго за [cl green] 3 смарагду [cl]!\",\n\t\"bk:weird_potion\" : \"стремно Зелле\",\n\t\"bk:weird_potion_desc\" : \"Дзiýныя Кулi\",\n\t\"bk:megaphone\" : \"Мегафон\",\n\t\"bk:megaphone_desc\" : \"павялiчэнню Куль\",\n\t\"scourge\" : \"Праклёны\" ,\n\t\"Scourge_stats\": \"Праклёны\",\n\t\"run_daily\": \"Дэйлик\",\n\t\"completed_on\": \"Дасягнута\",\n\t\"complete\": \"дасягнута\",\n\t\"next_daily_in\": \"[cl gray]Наступны пачынаецца праз[cl]\",\n\t\"hours\": \"гадзiн\",\n\t\"minutes\": \"хвiлiн\",\n\t\"seconds\": \"секунд\",\n\t\"ach_bk:star\": \"Зорка Шоу\",\n\t\"ach_bk:star_desc\": \"Збяры 3 арбiталь\",\n\t\"ach_bk:family\" : \"Шчаслiвая Сям'я\",\n\t\"ach_bk:family_desc\" : \"Збяры 3 гадаванца\",\n\t\"ach_bk:return_to_sender\" : \"No U\",\n\t\"ach_bk:return_to_sender_desc\" : \"Убей ворага яго ж куляй\",\n\t\"ach_bk:van_no_gogh\"  : \"Ван Але Гог\",\n\t\"ach_bk:van_no_gogh_desc\": \"Зламай 100 карцiн\",\n\t\"ach_bk:boom\": \"Ланцуговая Рэакцыя\",\n\t\"ach_bk:boom_desc\": \"Падарву ланцуг з 3 дынамiтаý\",\n\t\"ach_bk:dark_market\": \"Крымiнальная нычку\",\n\t\"ach_bk:dark_market_desc\": \"Спусцiся ý Цёмны Маркет\",\n\t\"ach_bk:spikes\": \"Шыпамi Замак не сапсавалi\",\n\t\"ach_bk:spikes_desc\" : \"Актывiруйце 100 шыпоý за 1 забег\",\n\t\"ach_bk:white_flag\" : \"Бяззбройны\",\n\t\"ach_bk:white_flag_desc\" : \"зачысцiць пакой не выкарыстоýваючы зброi\",\n\t\"quack\" : \"[cl yellow] Крак! [cl]\",\n\t\"pixel_perfect\" : \"Pixel Perfect\",\n\t\"bk_11\" : \"Я дарую табе жыццу. АЛЕ ## НЕ РАБI ## ГЭТА IЗНОÝ!\",\n\t\"Leaderboard\" : \"Дошка Лiдэраý\",\n\t\"display\" : \"Фiльтр\",\n\t\"around_you\" : \"Вакол Цябе\",\n\t\"friends\" : \"Сябры\",\n\t\"global\" : \"Усе\",\n\t\"loading\": \"Загружаем\",\n\t\"generating\": \"Генерим\",\n\t\"cursor_radius\": \"Радыус Курсора\",\n\t\"no_scores_yet\": \"Яшчэ няма рахункаý\",\n\t\"no_score_yet\": \"Яшчэ няма рахунку\",\n\t\"run\" : \"Забег\",\n\t\"top\" : \"Топ\",\n\t\"quick_restart\" : \"Хуткi Рэстарт\",\n\t\"painting_dungeon\" : \"Замак\",\n\t\"painting_goose\" : \"Мiнi Гусь\",\n\t\"painting_chess\" : \"Лятучы Слон \",\n\t\"painting_peach\": \"Персiкавае Дрэва\",\n\t\"bk:no_lamp\": \"Не\",\n\t\"bk:explosive_lamp\": \"Выбухная Лямпа\",\n\t\"bk:explosive_lamp_desc\": \"Калi ты занадта любiш ýсе падрываць\",\n\t\"bk:shielded_lamp\" : \"Шчытавая Лямпа\",\n\t\"bk:shielded_lamp_desc\": \"Падняць Шчыты!\",\n\t\"lamp\": \"Лямпа\",\n\t\"bk:brain\": \"Мега Мозг\",\n\t\"bk:brain_desc\" : \"Памер мозгу: Мега\",\n\t\"bk:heart_amulet\" : \"Сардэчны Амулет\",\n\t\"bk:heart_amulet_desc\" : \"+1 да памеру сэрца\",\n\t\"bk:star_amulet_desc\" : \"+1 да маны \",\n\t\"bk:star_amulet\": \"Зорны Амулет\",\n\t\"bk:coin_amulet\": \"Амулет на Грошы\",\n\t\"bk:coin_amulet_desc\": \"Грошы даюць больш\",\n\t\"bk:key_amulet\": \"Амулет на Ключы\",\n\t\"bk:key_amulet_desc\": \"Ключы даюць больш\",\n\t\"bk:bomb_amulet\": \"Бомбический Амулет\",\n\t\"bk:bomb_amulet_desc\": \"Бомбы даюць больш\",\n\t\"bk:eye_amulet\": \"Вочны Амулет\",\n\t\"bk:eye_amulet_desc\" : \"Як жа балюча быць недакладным\",\n\t\"bk:eye_patch\" : \"Оклюдер\",\n\t\"bk:eye_patch_desc\" : \"Вы гатовыя, дзецi?\",\n\t\"bk:toilet_paper\" : \"Туалетная Папера\",\n\t\"bk:toilet_paper_desc\"  : \"Заýсёды заканчиватся\",\n\t\"bk:decoy\": \"Прынада\",\n\t\"bk:decoy_desc\": \"Яна взрываетс я\",\n\t\"bk:wallet\": \"Кашэлечак\",\n\t\"bk:wallet_desc\": \"Захоýвае грошы\",\n\t\"bk:skele_buddy\" : \"Дэманюга\",\"bk:skele_buddy_desc\" : \"стремно\",\n\t\"bk:mega_bomb\" : \"Мега Бомба\",\n\t\"bk:mega_bomb_desc\" : \"Памер бомбы: Мега\",\n\t\"bk:condensed_milk\" : \"Згушчонка\",\n\t\"bk:condensed_milk_desc\" : \"Шустрыя пiкселi - Павольныя Працiýнiкi\",\n\t\"bk:marshma llow\" : \"Маршмеллоу\",\n\t\"bk:marshmallow_desc\" : \"Лiпкая штука\",\n\t\"bk:orbital_multiplier\" : \"Множнiк арбiталей\",\n\t\"bk:orbital_multiplier_desc\" : \"Больш арбiталей ýладару арбiталей!\",\n\t\"bk:pet_multiplier\" : \"множнiк гадаванца\",\n\t\"bk:pet_multiplier_desc\" : \"Больш гадаванцаý!\",\n\t\"bk:ghost_bullets\" : \"Кулi Прывiды\",\n\t\"bk:ghost_bullets_desc\" : \"Сцены не перашкода\",\n\t\"bk:weight\" : \"Гiра\",\n\t\"bk:weight_desc\" : \"Узмацняе гравiтацыю\",\n\t\"bk:d2\" : \"Д2\",\n\t\"bk:d2_desc\" : \"Вазьмi або пакiнь\",\n\t\"bk:ethernal_d6\" : \"Нябесны Д6\",\n\t\"bk:ethernal_d6_desc\" : \"Рэролiт i \\/ або знiшчае\",\n\t\"bk:billiard\" : \"Бiльярд\",\n\t\"bk:billiard_desc\" : \"Кулi адскокваюць ад куль\",\n\t\"bk:enraged_bullets\" : \"раззлаваны Кулi\",\n\t\"bk:enraged_bullets_desc\" : \"Кулi ламаюць кулi\",\n\t\"bk:rewind_button\" : \"Кноп ка перамоткi\",\n\t\"bk:rewind_button_desc\" : \"Пастой\",\n\t\"bk:piggy_bank\" : \"Свiнка Скарбонка\",\n\t\"bk:piggy_bank_desc\" : \"Мае зберажэннi\",\n\t\"coins\" : \"Манеты\",\n\t\"bk:death_star\" : \"Зорка Смерцi\",\n\t\"bk:death_star_desc\": \"RIP Альдэран\",\n\t\"bk:soldering_iron\": \"Паяльнiк\",\n\t\"bk:soldering_iron_desc\": \"Гарачы\",\n\t\"bk:can\": \"Банка\",\n\t\"bk:can_desc\" : \"Падваенне Куль\",\n\t\"bk:swimming_mask\" : \"Плавальны Маска\",\n\t\"bk:swimming_mask_desc\" : \"Сакрэтная Зброя\",\n\t\"bk:bullet_chair\" : \"Рэактывны Стул\",\n\t\"bk:bullet_chair_desc\" : \"4 ногi 4 пухи\",\n\t\"bk:cell\" : \"Клетка\",\n\t\"bk:cell_desc\" : \"Кулi нараджаюцца\",\n\t\"bk:brick\" : \"iКiрпыч\",\n\t\"bk:brick_desc\" : \"Вялiкiя ýзроýнi\",\n\t\"bk:ring_of_pain\" : \"Кола Болi\",\n\t\"bk:ring_of_pain_desc\" : \"Атрыманне страт б'е ýсiх\",\n\t\"bk:schrodingers_cat\" : \"Кот Schrödingerа\",\n\t\"bk:schrodingers_cat_ desc\" : \"Быць цi не быць (50% шанец)\",\n\t\"bk:smoke_bomb\" : \"Дымавуха\",\n\t\"bk:smoke_bomb_desc\" : \"Уцёкi ý стылi нiндзя\",\n\t\"bk:chest_ring\" : \"Кола куфар\",\n\t\"bk:chest_ring_desc\" : \"Вялiкi куфар!\",\n\t\"bk:empty_shell\" : \"Пустая Гiльза\",\n\t\"bk:empty_shell_desc\" : \"Шанец знiшчыць кулi працiýнiкаý\",\n\t\"bk:parachute\" : \"Парашут\",\n\t\"bk:parachute_desc\"  : \"Iмунiтэт да дзiркi\",\n\t\"bk:spiked_cookie\": \"шыпастым Печенька\",\n\t\"bk:spiked_cookie_desc\": \"Хворы аб б'е\",\n\t\"bk:shooty\": \"Стреляка\",\n\t\"bk:shooty_desc\": \"Ён страляе\" ,\n\t\"bk:rabbit_bullets\": \"Зайчёна Кулi\",\n\t\"bk:rabbit_bullets_desc\": \"Яны размножваюцца\",\n\t\"bk:pandoras_box\": \"Скрынка Пандоры\",\n\t\"bk:pandoras_box_desc\": \"Захавай зло\",\n\t\"bk:bubbles\" : \"Мыльныя Бурбалкi\",\n\t\"bk:bubbles_desc\": \"Сябар\",\n\t\"bk:match\": \"Запалка\",\n\t\"bk:match_desc\" : \"Агонь для ýсiх\",\n\t\"bk:hammer\": \"Молат\",\n\t\"bk:hammer_desc\": \"Я тваю бронь ламаць\",\n\t\"bk:helmet\": \"Сталёвы Шлем\",\n\t\"bk:helmet_desc\": \"Шанец ня атрымаць страты\",\n\t\"bk:beer\" : \"Пiýка\",\n\t\"bk:beer_desc\" : \"страты выклiкае злосць\",\n\t\"bk:the_eye\" : \"Глазик\",\n\t\"bk:the_eye_desc\" : \"Ён глядзiць\",\n\t\"bk:mimics_tooth\" : \"Зуб мiмiка\",\n\t\"bk:mimics_tooth_desc\" : \"Прыцягвае мiмiка\",\n\t\"ach_bk:mimic\" : \"Скрымер\",\n\t\"ach_bk:mimic_desc\" : \"Знайдзi мiмiка\",\n\t\"bk:paper_airplane\" : \"Папяровы Самалёцiк \" ,\n\t\"bk:paper_airplane_desc\": \"Саманавадяшиеся кулi\",\n\t\"ach_bk:ice_boss\": \"Дай ёй Сысцi\",\n\t\"ach_bk:ice_boss_desc\": \"Убей Ледзяную Каралеву\",\n\t\"ice_queen_scream\": \"^^ [cl cyan] Ахем\",\n\t\"painting_agency\": \"Сардэчна запрашаем у агенства\",\n\t\"language\": \"Мова\",\n\t\"bk:pouch\": \"Мешочек\",\n\t\"bk:alien_glasses\": \"Iнапланетныя Акуляры\",\n\t\"bk:alien_glasses_desc\" : \"Я бачу больш\",\n\t\"inventory\": \"Iнвентар\",\n\t\"bk:led\": \"Святлодыёд\",\n\t\"bk:led_desc\": \"Дакладная Лямпачка\",\n\t\"bk:fragile_lamp\": \"Крохкая Лямпачка\",\n\t\"bk:fragile_lamp_desc\": \"Адын удар K.O.\",\n\t\"painting_guitar\" : \"Больш гучнасцi!\"\n}"
  },
  {
    "path": "BurningKnight/Content/Locales/de.json",
    "content": "{\n\t\"bk:halo\": \"Heiligenschein\",\n\t\"bk:halo_desc\": \"Mehr Leben\",\n\t\"bk:revolver\": \"Revolver\",\n\t\"bk:sword\": \"Holzschwert\",\n\t\"bk:sword_desc\": \"Ein Stock mit scharfen Kanten\",\n\t\"bk:heart\": \"Herz\",\n\t\"resume\": \"Fortfahren\",\n\t\"settings\": \"Einstellungen\",\n\t\"restart\": \"Neustarten\",\n\t\"death_message\": \"Du bist gestorben!\",\n\t\"descend\": \"Hinabsteigen\",\n\t\"ascend\": \"Hochklettern\",\n\t\"exit\": \"Verlassen\",\n\t\"painting_rexcellent\": \"Excellent\",\n\t\"painting_grannylisa\": \"Grannylisa\",\n\t\"painting_maanex\": \"Der Denker\",\n\t\"painting_bk\": \"Der geröstete Ritter\",\n\t\"painting_failpositive\": \"Party Macher\",\n\t\"painting_old_man\": \"Sehr alter Mann\",\n\t\"painting_arthouse\": \"Kunst Haus\",\n\t\"painting_black\": \"Universum\",\n\t\"painting_milt\": \"Junge im Schnee\",\n\t\"painting_skyscraper\": \"Einsamer Wolkenkratzer\",\n\t\"painting_egor\": \"Brennender Rex\",\n\t\"painting_null\": \"NULL\",\n\t\"painting_badosz\": \"Verwirrter Junge im Wald\",\n\t\"painting_banana\": \"BANANE\",\n\t\"painting_tv\": \"Fernseher im Himmel\",\n\t\"painting_company\": \"In guter Gesellschaft\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Dog du Trasevol\",\n\t\"painting_lamp\": \"Schnapp sie dir!\",\n\t\"painting_scream\": \"Eis!\",\n\t\"painting_stars\": \"Gruselige Nacht\",\n\t\"painting_fog\": \"In den Gewässern...\",\n\t\"painting_nufflee\": \"WUFF\",\n\t\"by\": \"von\",\n\t\"old_man_0\": \"Es ist gefährlich!\",\n\t\"continue_run\": \"Run fortsetzen\",\n\t\"new_run\": \"Neuer Run\",\n\t\"was_unlocked\": \"wurde freigeschaltet!\",\n\t\"bk:revolver_desc\": \"HÄNDE HOCH @everyone!\",\n\t\"bk:shovel\": \"Blaue Schaufel\",\n\t\"bk:shovel_desc\": \"Aber warum ist sie blau???\",\n\t\"beet_0\": \"Hi!\",\n\t\"beet_2\": \"Wie soll er heißen?\",\n\t\"npc_hurt_0\": \"Aua.\",\n\t\"npc_hurt_1\": \"Das tut weh.\",\n\t\"npc_hurt_2\": \"Oh nein.\",\n\t\"beet_3\": \"Danke <3\",\n\t\"beet_1\": \"Möchtest du einen ^^Seed^^ einsetzen?\",\n\t\"beet_1_0\": \"Klar!\",\n\t\"beet_1_1\": \"Nein\",\n\t\"beet_4\": \"Der momentane Seed ist [vr seed]. Willst du ihn verändern?\",\n\t\"beet_4_0\": \"Ja bitte!\",\n\t\"beet_4_1\": \"Ne, passt so.\",\n\t\"beet_5\": \"Wie auch immer...\",\n\t\"beet_4_2\": \"Zufalls-Seed bitte!\",\n\t\"beet_6\": \"Alles klar. Der Seed lautet nun: [vr seed]\",\n\t\"bk:idol\": \"Idol\",\n\t\"bk:idol_desc\": \"Eine geheime Falle aktiviert sich!\",\n\t\"bk:key\": \"Goldener Schlüssel\",\n\t\"bk:infinite_bomb\": \"Unendlichkeits-Bombe\",\n\t\"bk:infinite_bomb_desc\": \"Eine wiederverwendbare Bombe\",\n\t\"throw_coin\": \"Wirf eine Münze\",\n\t\"bk:potatoo\": \"Kartoffel\",\n\t\"bk:potatoo_desc\": \"Spaltet projektile\",\n\t\"bk:spectacles\": \"Sehhilfe\",\n\t\"bk:spectacles_desc\": \"Deckt Geheimnisse auf\",\n\t\"bk:cross\": \"Kreuz\",\n\t\"bk:cross_desc\": \"Erhöht die Dauer der Unsterblichkeit\",\n\t\"bk:slime\": \"Slime\",\n\t\"bk:slime_desc\": \"Lässt deine Schüsse abprallen!\",\n\t\"bk:missile\": \"Rakete\",\n\t\"bk:missile_desc\": \"Zielsuchende Schüsse\",\n\t\"bk:rod_of_discord\": \"Discord Zauberstab\",\n\t\"bk:rod_of_discord_desc\": \"Teleportation für Jedermann\",\n\t\"bk:goo\": \"Glibber\",\n\t\"bk:goo_desc\": \"Begleiter-Freund\",\n\t\"bk:jelly\": \"Gelee!\",\n\t\"bk:jelly_desc\": \"^^Wackelig^^\",\n\t\"bk:broken_stone\": \"Gebrochener Stein\",\n\t\"bk:broken_stone_desc\": \"Gut gebautes Orbital\",\n\t\"bk:nano_orb\": \"Mini Orb\",\n\t\"bk:nano_orb_desc\": \"Micro freund\",\n\t\"bk:saturn\": \"Planet\",\n\t\"bk:saturn_desc\": \"Natürlich haben wir ihn auch lieb\",\n\t\"bk:soap\": \"Seife\",\n\t\"bk:soap_desc\": \"Nicht fallen lassen! (Langamere Projektile)\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"Gegenstände ^^durchmischen^^!\",\n\t\"bk:my_heart\": \"Mein Herz\",\n\t\"bk:my_heart_desc\": \"Mehr Leben\",\n\t\"bk:broken_heart\": \"Gebrochenes Herz\",\n\t\"bk:broken_heart_desc\": \"Mehr Leben\",\n\t\"bk:parcel\": \"Paketchen\",\n\t\"bk:parcel_desc\": \"Wiederverwendbare Heilung\",\n\t\"bk:glass\": \"Glas\",\n\t\"bk:glass_desc\": \"##Zerbrechliche## Projektile\",\n\t\"bk:glass_bullet\": \"Glass Patrone\",\n\t\"bk:glass_bullet_desc\": \"Schieße über Steine\",\n\t\"bk:broken_guitar\": \"Demolierte Gitarre\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Maschinengewehr\",\n\t\"bk:machine_gun_desc\": \"Vollautomatisch\",\n\t\"bk:grenade_launcher\": \"Granatenwerfer\",\n\t\"bk:grenade_launcher_desc\": \"Kaboom!\",\n\t\"bk:shotgun\": \"Shotgun\",\n\t\"bk:shotgun_desc\": \"Bitte Sicherheitsabstand einhalten!\",\n\t\"bk:missile_launcher\": \"Portable Raketenabschussrampe\",\n\t\"bk:missile_launcher_desc\": \"Verrückte Technologie...\",\n\t\"bk:burst_gun\": \"Feuerstoßgewähr\",\n\t\"bk:burst_gun_desc\": \"Mit Lichtgeschwindigkeit!\",\n\t\"bk:flak_cannon\": \"Flakkanone\",\n\t\"bk:flak_cannon_desc\": \"Zeit für Party!\",\n\t\"bk:disk_gun\": \"Scheiben-Pistole\",\n\t\"bk:disk_gun_desc\": \"Scharfe Angelegenheit\",\n\t\"bk:duck_gun\": \"Enten-Pistole\",\n\t\"bk:duck_gun_desc\": \"Jetzt ist Ente im Gelände\",\n\t\"bk:follower\": \"Follower\",\n\t\"bk:follower_desc\": \"\\\"Und lasst nen like da!\\\"\",\n\t\"bk:portal_gun\": \"Portal Gun\",\n\t\"bk:portal_gun_desc\": \"Der Kuchen war eine Lüge!\",\n\t\"bk:snowflake\": \"Schneeflocke\",\n\t\"bk:snowflake_desc\": \"Frier sie alle ein!\",\n\t\"bk:restock\": \"Auffüllen\",\n\t\"bk:restock_desc\": \"Unbegrenzte Angebote in Shops\",\n\t\"bk:charisma_ring_desc\": \"Königliche Angebote\",\n\t\"bk:charisma_ring\": \"Charisma Ring\",\n\t\"bk:battery\": \"Batterie\",\n\t\"tomb_0\": \"Hier liegt [cl green]Gobbo[cl] der Große\",\n\t\"bk:homemade_dice\": \"Hausgemachter Würfel\",\n\t\"bk:homemade_dice_desc\": \"Gegenstände ^^durchmischen^^! (DIY)\",\n\t\"shopkeeper_0\": \"##ICH SAGTE DU SOLLST DAS LASSEN!##\",\n\t\"shopkeeper_1\": \"Bitte, aufhören!\",\n\t\"shopkeeper_2\": \"Mach das nicht.\",\n\t\"shopkeeper_3\": \"[cl red]##MACH DICH BEREIT ZUM STERBEN!##\",\n\t\"shopkeeper_4\": \"[cl red]DIEB!\",\n\t\"shopkeeper_5\": \"[cl red]SCHNAPP IHN DIR!\",\n\t\"desert\": \"Wüstentempel\",\n\t\"jungle\": \"Uralter Dschungel\",\n\t\"ice\": \"Eis-Ruinen\",\n\t\"bk:iron_boots\": \"Eisenstiefel\",\n\t\"bk:iron_boots_desc\": \"Stacheln tun nicht mehr weh\",\n\t\"bk:mimic_totem\": \"Nachahm-Totem\",\n\t\"bk:mimic_totem_desc\": \"##KEINE NACHAHMUNGEN MEHR##\",\n\t\"back_to_town\": \"Zurück ins Dorf\",\n\t\"bk:glass_gun\": \"Glas-Pistole\",\n\t\"bk:glass_gun_desc\": \"##Zerbrechlich##\",\n\t\"bk:glass_shard\": \"Glassplitter\",\n\t\"bk:glass_shard_desc\": \"Nur ein kleiner Teil des Ganzen\",\n\t\"bk:disk_10\": \"Platte №10\",\n\t\"bk:disk_10_desc\": \"Ladenbesitzer\",\n\t\"bk:disk_1\": \"Platte 1\",\n\t\"bk:disk_1_desc\": \"Zuhause\",\n\t\"bk:disk_2\": \"Platte 2\",\n\t\"bk:disk_2_desc\": \"Wald\",\n\t\"bk:disk_3\": \"Platte 3\",\n\t\"bk:disk_3_desc\": \"Dschungel\",\n\t\"bk:disk_4\": \"Platte 4\",\n\t\"bk:disk_4_desc\": \"Eis\",\n\t\"bk:disk_5\": \"Platte 5\",\n\t\"bk:disk_5_desc\": \"Kerker\",\n\t\"bk:disk_6\": \"Platte 6\",\n\t\"bk:disk_6_desc\": \"Hölle\",\n\t\"bk:disk_7\": \"Platte 7\",\n\t\"bk:disk_7_desc\": \"???\",\n\t\"bk:disk_8\": \"Platte 8\",\n\t\"bk:disk_8_desc\": \"Leere\",\n\t\"bk:disk_9\": \"Platte 9\",\n\t\"bk:disk_9_desc\": \"Schnitt\",\n\t\"bk:dagger\": \"Messer\",\n\t\"bk:dagger_desc\": \"Nostalgie...\",\n\t\"bk:spear\": \"Speer\",\n\t\"bk:spear_desc\": \"Längere arme?\",\n\t\"shopkeeper_6\": \"Willkommen :)\",\n\t\"shopkeeper_7\": \"Wie gehts,[dl] darf ich dir etwas [cl yellow]Tee[cl] anbieten?\",\n\t\"shopkeeper_8\": \"Wie gehts wie stehts?\",\n\t\"back\": \"Zurück\",\n\t\"master_volume\": \"Allgemeine Lautstärke\",\n\t\"music\": \"Musik\",\n\t\"sfx\": \"Soundeffekte\",\n\t\"graphics\": \"Grafik\",\n\t\"audio\": \"Audio\",\n\t\"ui_sfx\": \"Menü-Soundeffekte\",\n\t\"on\": \"An\",\n\t\"off\": \"Aus\",\n\t\"fullscreen\": \"Vollbild\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"FPS Anzeige\",\n\t\"speedrun_timer\": \"Speedrun Modus\",\n\t\"screenshake\": \"Bilschirmwackeln\",\n\t\"freeze_frames\": \"Freeze Frames\",\n\t\"flash_frames\": \"Flash Frames\",\n\t\"reset_progress\": \"Fortschritt zurücksetzen\",\n\t\"blood_n_gore\": \"Blut und Innereien\",\n\t\"vegan_mode\": \"Vegan-Modus\",\n\t\"reset_settings\": \"Einstellungen zurücksetzen\",\n\t\"are_you_sure\": \"Bist du dir sicher?\",\n\t\"yes\": \"Yes\",\n\t\"reset_progress_dis\": \"Das wird deinen GESAMTEN FORTSCHRITT löschen!\",\n\t\"reset_settings_dis\": \"Das wird ALLE Einstellungen zurücksetzen!\",\n\t\"autosave\": \"Automatisch Speichern\",\n\t\"autopause\": \"Automatisch Pausieren\",\n\t\"input\": \"Eingabe\",\n\t\"use\": \"Benutzen\",\n\t\"active\": \"Aktiv\",\n\t\"bomb\": \"Bombe\",\n\t\"interact\": \"Interagieren\",\n\t\"swap\": \"Waffen tauschen\",\n\t\"roll\": \"Rollen\",\n\t\"duck\": \"Ducken\",\n\t\"pause\": \"Pause\",\n\t\"none\": \"Nichts\",\n\t\"keyboard_controls\": \"Tastatursteuerung\",\n\t\"gamepad_controls\": \"Gamepadsteuerung\",\n\t\"keyboard\": \"Tastatur\",\n\t\"gamepad\": \"Gamepad\",\n\t\"game\": \"Spiel\",\n\t\"select\": \"Auswählen\",\n\t\"cursor\": \"Zeiger\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"Stirb\",\n\t\"ach_bk:overshake\": \"Überschüttelung\",\n\t\"ach_bk:overshake_desc\": \"1000% screen shake\",\n\t\"ach_bk:rip\": \"Beliebteste Errungenschaft\",\n\t\"bk:emerald\": \"Smaragd\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Danke!^^\",\n\t\"shopkeeper_11\": \"Was für ein %%Deal%%!\",\n\t\"shopkeeper_12\": \"Willst du ^^Etwas^^ [cl red]kaufen[cl]?\",\n\t\"shopkeeper_13\": \"Exclusiv nur für [cl green]dich[cl] und nur heute!\",\n\t\"shopkeeper_14\": \"So viele [cl yellow]unglaublich gute[cl] Angebote!\",\n\t\"bk:magnifier\": \"Lupe\",\n\t\"bk:magnifier_desc\": \"Größere Projektile\",\n\t\"bk:mushroom_hat\": \"Pilzhut\",\n\t\"bk:mushroom_hat_desc\": \"Schmeckts?\",\n\t\"bk:stone_hat\": \"Steinhut\",\n\t\"bk:stone_hat_desc\": \"Leider recht schwer\",\n\t\"bk:knight_hat\": \"Ritterhelm\",\n\t\"bk:knight_hat_desc\": \"Hile, ich seh nichts mehr!\",\n\t\"bk:cowboy_hat\": \"Cowboyhut\",\n\t\"bk:cowboy_hat_desc\": \"YEEHAW\",\n\t\"bk:soup_hat\": \"Suppenhut\",\n\t\"bk:soup_hat_desc\": \"^^Lecker!^^\",\n\t\"bk:gold_hat\": \"Goldener Hut\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Reichtum!\",\n\t\"bk:viking_hat\": \"Wikingerhelm\",\n\t\"bk:viking_hat_desc\": \"Nur für die starken Männer!\",\n\t\"bk:dunce_hat\": \"Dummkopf Hut\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Zylinder\",\n\t\"bk:top_hat_desc\": \"Modisch!\",\n\t\"bk:ushanka\": \"Ushanka\",\n\t\"bk:ushanka_desc\": \"Wo ist meine ##balalaika?##\",\n\t\"bk:valkyrie_hat\": \"Walküren Hut\",\n\t\"bk:valkyrie_hat_desc\": \"^^I belive I can fly!^^\",\n\t\"bk:skull_hat\": \"Schädelhut\",\n\t\"bk:skull_hat_desc\": \"Moralisch gesehen eher fragwürdig.\",\n\t\"bk:grandma_head\": \"Omi's Kopf\",\n\t\"bk:grandma_head_desc\": \"\\\"Und du bist auch wirklich satt?\\\"\",\n\t\"bk:diamond_helmet\": \"Diamanthelm\",\n\t\"bk:diamond_helmet_desc\": \"Grab niemals gerade nach unten!\",\n\t\"bk:villager_head\": \"Dorfbewohnerkopf\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fes\",\n\t\"bk:fez_desc\": \"Schick!\",\n\t\"bk:no_hat\": \"Hut entfernen\",\n\t\"bk:no_hat_desc\": \"Kein Hut - kein Stress!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"ERROR! NullPointerException at NullItem:43\",\n\t\"accessorytrader_0\": \"##RAUS HIER!## [dl]Oder natürlich du kaufst ein paar dieser ^^wunderbaren^^ Gegenstände für nur ^^%%99 Diamanten pro Stück%%^^!\",\n\t\"accessorytrader_1\": \"Hi\",\n\t\"accessorytrader_2\": \"Na?\",\n\t\"weapontrader_0\": \"Kommen'se rein!\",\n\t\"weapontrader_1\": \"Nen' guten Tag, der Herr!\",\n\t\"weapontrader_2\": \"Willst was kaufen? Scho' oder?\",\n\t\"activetrader_0\": \"Die besten Angebote auf dem Markt!\",\n\t\"activetrader_1\": \"Zahl für Zwei und bekomme auch Zwei!\",\n\t\"activetrader_2\": \"Gebt mir Donuts, [dl]bitte!!\",\n\t\"hattrader_0\": \"Möchten Sie so cool sein wie ich? [dl]Legen Sie sich einen neuen Hut zu!\",\n\t\"hattrader_1\": \"Wollen Sie auch so unglaublich gut ausschauen wie ich? [dl]Treten Sie näher!\",\n\t\"hattrader_2\": \"^^Wunderbare neue Hüte, exklusiv für Sie ausgesucht!^^\",\n\t\"granny_0\": \"Willst du etwas Tee?\",\n\t\"granny_1\": \"Setz dich![dl]Mach kurz 'ne Pause!\",\n\t\"granny_2\": \"Du bist so Groß geworden!\",\n\t\"bk:xmas_hat\": \"Weihnachtsmütze\",\n\t\"bk:xmas_hat_desc\": \"Frohe Weihnachten!\",\n\t\"bk:pumpkin_hat\": \"Ausgeschnitzter Kürbis\",\n\t\"bk:pumpkin_hat_desc\": \"^^spooky scary skeletons^^\",\n\t\"bk:cage_key\": \"Gefängnisschlüssel\",\n\t\"bk:cage_key_desc\": \"Rette ^^den Kerl^^!\",\n\t\"npc_0\": \"Hilf mir! Such den Schlüssel!\",\n\t\"npc_1\": \"Vielen Dank, dass du mich gerettet hast!\",\n\t\"npc_2\": \"Schneller! Sperr die Tür auf!\",\n\t\"npc_3\": \"Bitte! Hilf mir!\",\n\t\"control_0\": \"Drücke [ic 0][ic 1] um eine Bombe zu werfen!\",\n\t\"control_1\": \"Rollen, du kannst! [ic 0][ic 1] drücken, du musst!\",\n\t\"control_2\": \"Drücke [ic 0][ic 1] um anzugreifen\",\n\t\"control_3\": \"Drücke [ic 0][ic 1] um zu interagieren\",\n\t\"control_4\": \"Quak? [ic 0][ic 1]!\",\n\t\"control_5\": \"Drücke [ic 0][ic 1] um Waffen zu wechseln\",\n\t\"shopkeeper_15\": \"Kein Angebot für dich!\",\n\t\"shopkeeper_16\": \"Schnapp dir ein bisschen mehr Geld und dann komm wieder!\",\n\t\"shopkeeper_17\": \"Du musst schon erst bezahlen!\",\n\t\"bk:frog\": \"Tele-Frosch\",\n\t\"bk:frog_desc\": \"Wuschhh\",\n\t\"bk:sword_orbital\": \"Schwert-Orbital\",\n\t\"bk:sword_orbital_desc\": \"Gerechtigkeit!\",\n\t\"robbed\": \"Beklaut\",\n\t\"bk:gift_desc\": \"Was da wohl drinnen ist?\",\n\t\"bk:spike_ring\": \"Stachelring\",\n\t\"bk:spike_ring_desc\": \"Deine Feinde müssen ##bestraft## werden!\",\n\t\"bk:fire_ring\": \"Freuerring\",\n\t\"bk:fire_ring_desc\": \"Lass sie BRENNEN\",\n\t\"bk:ice_ring\": \"Eisring\",\n\t\"bk:ice_ring_desc\": \"Stoppe deine Gegner\",\n\t\"bk:duck_ring\": \"Entenring\",\n\t\"bk:duck_ring_desc\": \"Teleportiert dich beim Schaden nehmen\",\n\t\"bk:dull_blade\": \"Stumpfe Klinge\",\n\t\"bk:dull_blade_desc\": \"Löst Schadenseffekt aus\",\n\t\"bk:sharp_blade\": \"Scharfe Klinge\",\n\t\"bk:sharp_blade_desc\": \"Echt scharf, lieber aufpassen!\",\n\t\"bk:obsidian_shield\": \"Obsidianschild\",\n\t\"bk:obsidian_shield_desc\": \"Rückstoß = 0\",\n\t\"bk:bill\": \"Rechnung\",\n\t\"bk:bill_desc\": \"99 Euro\",\n\t\"control_6\": \"Setzte dein aktives Item mit [ic 0][ic 1] ein!\",\n\t\"bk:clover\": \"Vierblättriges Kleeblatt\",\n\t\"bk:clover_desc\": \"Glückspilz!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^%%Neue Artifakte!%%^^\",\n\t\"brastin_0\": \"Finde das [cl purple]Katzen-Gemälde[cl]!\",\n\t\"elon_0\": \"Ich kann deine Waffe in eine Andere verwandeln\",\n\t\"elon_1\": \"Hier, bitteschön. Viel Spaß damit!\",\n\t\"bk:maanex_head\": \"Maanex Kopf\",\n\t\"bk:maanex_head_desc\": \"Hmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Lässt alle Gegner für einen Moment nachdenken\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Karten Grünpause\",\n\t\"bk:map_greenprints_desc\": \"Deckt alle Räume auf\",\n\t\"bk:map\": \"Karte\",\n\t\"bk:map_desc\": \"Deckt die gesamte Ebene permanent auf\",\n\t\"milt_1\": \"Ich will Geschenk.\",\n\t\"mapuzzle_0\": \"Schweeerkraaaft.\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Kopiert!\",\n\t\"isaac_0\": \"Leben hat keinen Sinn...\",\n\t\"isaac_1\": \"Waruuuuuummmmm????\",\n\t\"isaac_2\": \":sob:\",\n\t\"discord_0\": \"Sag Hi! discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"Rollen, Dummkopf!\",\n\t\"tutorial\": \"Tutorial\",\n\t\"bk:the_key\": \"Der Schlüssel\",\n\t\"bk:the_key_desc\": \"Öffnet den Ausgang\",\n\t\"bk:crying_bomb\": \"Heulende Bombe\",\n\t\"bk:crying_bomb_desc\": \"Bomben weinen jetzt!\",\n\t\"bk:matches\": \"Streichhölzer\",\n\t\"bk:matches_desc\": \"Explosionen explodieren schneller\",\n\t\"bk:bomb_pack\": \"Bombenpack\",\n\t\"bk:bomb_pack_desc\": \"Wir packen Bomben in deine Bomben!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 Bomben\",\n\t\"bk:weird_mushroom_desc\": \"Verdoppelt alles!\",\n\t\"bk:weird_mushroom\": \"Komischer Pilz\",\n\t\"bk:bomb_shower\": \"Bomben-Dusche\",\n\t\"bk:bomb_shower_desc\": \"Lass es Bomben regnen!\",\n\t\"bk:black_belt\": \"Schwarzer Gürtel\",\n\t\"bk:black_belt_desc\": \"\\\"Explosionen machen mir nichts mehr aus!\\\"\",\n\t\"bk:ninjia_bomb\": \"Ninjia-Bombe\",\n\t\"bk:ninjia_bomb_desc\": \"Erschafft Bomben, wenn du verletzt wirst!\",\n\t\"start_new_run\": \"Dein momentaner Run wird verloren gehen!\",\n\t\"bk:laser_pointer\": \"Laser Pointer\",\n\t\"bk:laser_pointer_desc\": \"Ziel ist im Visier!\",\n\t\"ach_bk:marauder\": \"Plünderer\",\n\t\"ach_bk:marauder_desc\": \"Töte den Ladenbesitzer\",\n\t\"ach_bk:treasure_hunter\": \"Schatzjäger\",\n\t\"ach_bk:treasure_hunter_desc\": \"Finde einen geheimen Raum\",\n\t\"ach_bk:dodge_master\": \"Meister des Ausweichens\",\n\t\"ach_bk:dodge_master_desc\": \"Töte einen Boss-Gegner ohne Schaden zu nehmen\",\n\t\"ach_bk:dodge_overlord\": \"Jetzt übertreib mal nicht!\",\n\t\"ach_bk:dodge_overlord_desc\": \"Schaff es durch eine Ebene, ohne Schaden zu nehmen\",\n\t\"ach_bk:quackers\": \"Quak Quak Quak\",\n\t\"ach_bk:quackers_desc\": \"Quak Quak Quak Quak Quak Quak\",\n\t\"ach_bk:tea_party\": \"Zeit für einen Tee\",\n\t\"ach_bk:tea_party_desc\": \"Lass dir von der Großmutter einen Tee servieren\",\n\t\"ach_bk:not_a_thief\": \"Alles andere als ein Dieb\",\n\t\"ach_bk:not_a_thief_desc\": \"Beende einen Run ohne auch nur einen einzigen Gegenstand mitgehen zu lassen\",\n\t\"ach_bk:npc_party2\": \"NPC Party\",\n\t\"ach_bk:npc_party2_desc\": \"Rette alle NPCs\",\n\t\"bk:gold_coin\": \"Goldmünze\",\n\t\"bk:iron_coin\": \"Silbermünze\",\n\t\"bk:copper_coin\": \"Kupfermünze\",\n\t\"bk:platinum_coin\": \"Platinmünze\",\n\t\"bk:voodoo_doll\": \"Voodoo Puppe\",\n\t\"bk:voodoo_doll_desc\": \"Tötet alle Gegner im Raum\",\n\t\"hub\": \"Rollingen\",\n\t\"castle\": \"Burgruinen\",\n\t\"charger_0\": \"KEIN AKTIVER GEGENSTAND GEFUNDEN\",\n\t\"charger_1\": \"AKTIVER GEGENSTAND IST BEREITS VOLLKOMMEND AUFGELADEN\",\n\t\"charger_2\": \"WO IST MEIN GELD, DU FLEISCHSACK?\",\n\t\"charger_3\": \"##ICH SAGTE GIB MIR MEIN GELD!##\",\n\t\"charger_4\": \"##ICH WERDE DIE WELTHERRSCHAFT AN MICH REIßEN!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Na klar, gerne!\",\n\t\"maanex_6_1\": \"Ne, lass mal lieber.\",\n\t\"maanex_6\": \"Sehr schön.[dl] Dann gib mir [cl yellow][vr cost] Münzen[cl] und ich lass dich eine von den Kisten hier aufmachen, okay?\",\n\t\"maanex_5\": \"Hallöchen, lust auf ein kleines ^^Glücksspiel^^?\",\n\t\"maanex_7\": \"Das war super!\",\n\t\"maanex_8\": \"Viel Glück!\",\n\t\"maanex_9\": \"Ahhh, das tut mir leid. Vielleicht nächstes Mal!\",\n\t\"maanex_10\": \"%%^^WOAH^^%%\",\n\t\"maanex_11\": \"Aber... [dl]ähh... [dl] du hast nicht genug Geld!\",\n\t\"maanex_12\": \"##SOHN?![dl] BIST DUS?!##\",\n\t\"bk:amurs_arrow\": \"Amors Pfeil\",\n\t\"bk:amurs_arrow_desc\": \"Bezaubernde Projektile\",\n\t\"bk:amurs_bow\": \"Amors Bogen\",\n\t\"bk:amurs_bow_desc\": \"Herzschmerz vorprogrammiert\",\n\t\"bk:poison_flask\": \"Gift-Flasche\",\n\t\"bk:poison_flask_desc\": \"Vergiftete Projektile\",\n\t\"bk:snowball\": \"Schneeball\",\n\t\"bk:snowball_desc\": \"Eiskalte Projektile\",\n\t\"bk:peper_desc\": \"Richtig Heiße Projektile\",\n\t\"bk:peper\": \"Chilischote\",\n\t\"bk:sale_coupon\": \"Rabatt Gutschein\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Haustier in einer Box\",\n\t\"bk:pet_box_desc\": \"Was da wohl drinnen ist?\",\n\t\"bk:crate\": \"Orbital-Box\",\n\t\"bk:crate_desc\": \"Hallo? Ist da jemand drinnen?\",\n\t\"bk:strawberry\": \"Erdbeere\",\n\t\"bk:strawberry_desc\": \"Süße Erinnerungen\",\n\t\"bk:wings\": \"Flügel\",\n\t\"bk:wings_desc\": \"\\\"I belive I can fly\\\"\",\n\t\"bk:coin_pouch\": \"Münzbeutel\",\n\t\"bk:coin_pouch_desc\": \"Gibt dir ein paar Münzen\",\n\t\"bk:key_pouch\": \"Schlüssel-Säckchen\",\n\t\"bk:key_pouch_desc\": \"Gibt dir eine handvoll Schlüssel\",\n\t\"bk:bomb_pouch\": \"Bombenbeutel\",\n\t\"bk:bomb_pouch_desc\": \"Gibt dir Bomben\",\n\t\"bk:pouch_pouch\": \"Beutel-Beutel\",\n\t\"bk:pouch_pouch_desc\": \"Gibt dir noch mehr Beutel\",\n\t\"bk:lightsaber\": \"Lichtschwert\",\n\t\"bk:lightsaber_desc\": \"Ich hab da ein ganz mieses Gefühl...\",\n\t\"bk:snail\": \"Schnecke\",\n\t\"bk:snail_desc\": \"Liiichtgeeschwwindigkeeiit. *gähn*\",\n\t\"bk:spike\": \"Stachel\",\n\t\"bk:spike_desc\": \"MEHR SCHADEN!\",\n\t\"bk:mushroom\": \"Pilz\",\n\t\"bk:mushroom_desc\": \"Schneller, SCHNELLER!\",\n\t\"bk:candy\": \"Bonbon\",\n\t\"bk:candy_desc\": \"^^Zuckerrausch^^, schieß jetzt noch schneller!\",\n\t\"bk:glasses\": \"Brille\",\n\t\"bk:glasses_desc\": \"Bessere Zielgenauigkeit\",\n\t\"bk:ruler\": \"Lineal\",\n\t\"bk:ruler_desc\": \"Erhöhte Reichweite\",\n\t\"bk:stopwatch\": \"Stoppuhr\",\n\t\"bk:stopwatch_desc\": \"Um kurz anzuhalten, wenn du getroffen wirst\",\n\t\"bk_0\": \"##WAG ES JA NICHT DAS ANZUFASSEN!##\",\n\t\"bk_1\": \"##HÖRST DU SCHLECHT? [dl]ICH SAGTE NICHT ANFASSEN!##\",\n\t\"bk_2\": \"##DU KANNST DEN [cl red]BURNING KNIGHT[cl] NICHT BESIEGEN!##[dl] Dummkopf...\",\n\t\"bk_3\": \"##DU HAST ES SCHEINBAR SO GEWOLLT!##\",\n\t\"bk_4\": \"^^SO EINE WITZFIGUR^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Heiße Angebote![cl]\",\n\t\"dm_0\": \"@@Willkommen@@\",\n\t\"ach_bk:deal\": \"Überragender Schachzug\",\n\t\"ach_bk:deal_desc\": \"Lass dich auf einen Deal mit dem dunklen Magier ein\",\n\t\"ach_bk:grannys_gift\": \"Geschenk von Oma\",\n\t\"ach_bk:grannys_gift_desc\": \"Wenn da mal keine Socken drinnen sind...\",\n\t\"ach_bk:shopper\": \"Wirtschaft ankurbeln\",\n\t\"ach_bk:shopper_desc\": \"Kauf dir Etwas in einem Laden\",\n\t\"bk_5\": \"AN DEINER STELLE WÜRDE ICH MIR NICHT EINMAL DIE MÜHE MACHEN, MIT IHM ZU REDEN\",\n\t\"bk_6\": \"##TÖTE IHN, [cl lime]BERND[cl]!##\",\n\t\"bk_7\": \"[cl lime]BERND[cl], ##NEEEEEEEEIN!!!!##\",\n\t\"bk_8\": \"ACH KOMM SCHON, HÖR AUF HIER ALLES IN DIE LUFT ZU JAGEN!\",\n\t\"bk_9\": \"Oh, [cl pink]guten Tag[cl], die Dame. [dl]Ich hoffe mein ^^Gast^^ hier stört Sie nicht.\",\n\t\"bk_10\": \"MEIN MEISTER,[dl] ICH HABE DEN [cl green]GOBLIN[cl] MITGEBRACHT, WIE VEREINBART.\",\n\t\"dm_1\": \"Sehr gut[dl], vielen dank[dl], [cl red]Limpor[cl]\",\n\t\"dm_2\": \"Ja,[dl] oh ja,[dl] ICH BRAUCHE MEHR [cl orange]##ENERGIE##[cl]!\",\n\t\"dm_3\": \"##MEHR [cl orange]ENERGIEEEEE[cl]!##\",\n\t\"dm_4\": \"Ich kann [cl orange]die Energie[cl] schon förmlich Spüren!\",\n\t\"granny_3\": \"Er macht nen netteren Eindruck als du, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Willkommen, [cl green]Gobbo [vr id][cl]!\",\n\t\"granny_5\": \"Viel Glück und Erfolg! [dl]Pass auf dich auf!\",\n\t\"bk:meat_guy\": \"Fleisch Typ\",\n\t\"bk:meat_guy_desc\": \"Joa...\",\n\t\"bk:bullet_stone\": \"Patronen Patron\",\n\t\"bk:bullet_stone_desc\": \"Ein kleiner Schutzengel\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"Hilft nicht, aber gibt dir Batterien\",\n\t\"vibration\": \"Vibration\",\n\t\"bk:sharp_arrow\": \"Spitzer Pfeil\",\n\t\"bk:sharp_arrow_desc\": \"Erhöhte Projektil Penetration\",\n\t\"machine_0\": \"[cl yellow]Münze [cl]einwerfen\",\n\t\"player_0\": \"Papa?? ##Was haben die mit dir gemacht?!?##\",\n\t\"bk:boomerang\": \"Boomerang\",\n\t\"bk:boomerang_desc\": \"Boomerang Projektile\",\n\t\"bk:backpack\": \"Rucksack\",\n\t\"bk:backpack_desc\": \"Das wandern ist des Müllers lust\",\n\t\"place_an_item\": \"Gegenstand hineinlegen\",\n\t\"bk:crystal\": \"Kristall\",\n\t\"bk:crystal_desc\": \"Mit der Kraft des %%Regenbogen%%\",\n\t\"bk:prism\": \"Prisma\",\n\t\"bk:prism_desc\": \"Projektile -> %%Regenbogen%%\",\n\t\"scourged\": \"Verflucht\",\n\t\"bk:bomb\": \"Bombe\",\n\t\"bk:scourge_of_egg\": \"Fluch des Eies\",\n\t\"bk:scourge_of_egg_desc\": \"Vertauschte Gegenstandsnamen\",\n\t\"bk:scourge_of_unknown\": \"Fluch des Unbekannten\",\n\t\"bk:scourge_of_unknown_desc\": \"Gegenstände versteckt\",\n\t\"bk:scourge_of_blood\": \"Fluch des Blutes\",\n\t\"bk:scourge_of_blood_desc\": \"Gegner verdoppelt\",\n\t\"bk:scourge_of_risk\": \"Fluch des Risikos\",\n\t\"bk:scourge_of_risk_desc\": \"Versteckte Lebensanzeige\",\n\t\"bk:scourge_of_keys\": \"Fluch der Schlüssel\",\n\t\"bk:scourge_of_keys_desc\": \"Münzen, Bomben und Schlüssel versteckt\",\n\t\"bk:scourge_of_lost\": \"Fluch der Orientierungslosigkeit\",\n\t\"bk:scourge_of_lost_desc\": \"Amnesie\",\n\t\"bk:scourge_of_scourged\": \"Fluch der Flüche\",\n\t\"bk:scourge_of_scourged_desc\": \"Flüche überall!\",\n\t\"bk:scourge_of_illness\": \"Fluch der Krankheit\",\n\t\"bk:scourge_of_illness_desc\": \"Heilung weniger effektiv\",\n\t\"bk:scourge_of_death\": \"Fluch des Todes\",\n\t\"bk:scourge_of_death_desc\": \"Leben am Limit\",\n\t\"bk:ancient_revolver\": \"Uralter Revolver\",\n\t\"bk:ancient_revolver_desc\": \"Schaut cool aus\",\n\t\"bk:assault_rifle\": \"Sturmgewehr\",\n\t\"bk:assault_rifle_desc\": \"Ratatatatatata\",\n\t\"fountain_0\": \"Bringe 5 Münzen und du seist gesegnet\",\n\t\"fountain_1\": \"Du wurdest teilweise gereinigt\",\n\t\"fountain_2\": \"Du wurdest vollkommend gereinigt\",\n\t\"fountain_3\": \"Du bist bereits gereinigt\",\n\t\"buffed\": \"Verbessert\",\n\t\"nerfed\": \"Verschlechtert\",\n\t\"restored\": \"Wiederhergestellt\",\n\t\"damaged\": \"Verletzt\",\n\t\"cleansed\": \"Gereinigt\",\n\t\"gifted\": \"Beschenkt\",\n\t\"lucky\": \"Glück gehabt!\",\n\t\"unlucky\": \"Pech gehabt!\",\n\t\"max_hp\": \"Maximale HP\",\n\t\"touch\": \"Anfassen\",\n\t\"break\": \"Zerstören\",\n\t\"no_coins\": \"Keine Münzen\",\n\t\"old_man_6\": \"Es ist gefährlich alleine zu gehen, nimm das!\",\n\t\"roger_0\": \"Kaboom!\",\n\t\"roger_1\": \"##*BOOM*##\",\n\t\"roger_2\": \"Boom boom shakalaka!\",\n\t\"bk:shield\": \"Schild\",\n\t\"bk:gift\": \"Geschenk\",\n\t\"bk:shield_pouch\": \"Schildsäckchen\",\n\t\"bk:shield_pouch_desc\": \"Gibt dir Schilde\",\n\t\"bk:shield_buddy\": \"Schild Kumpel\",\n\t\"bk:shield_buddy_desc\": \"Beschützt dich!\",\n\t\"bk:skeleton_key\": \"Skelettschlüssel\",\n\t\"bk:skeleton_key_desc\": \"99 Schlüssel\",\n\t\"bk:jar\": \"Lebenstrank\",\n\t\"bk:jar_desc\": \"Aber nicht alles aufeinmal!\",\n\t\"bk:star\": \"Stern\",\n\t\"bk:star_desc\": \"%%^^Weeeeeee^^%%\",\n\t\"bk:car_bomb\": \"Autobombe\",\n\t\"bk:car_bomb_desc\": \"Bomben-Lieferservice\",\n\t\"bk:grenade\": \"Granate\",\n\t\"bk:grenade_desc\": \"Explodiert bei Berührung\",\n\t\"trash_goblin_0\": \"Befrei mich von meinem [cl purple]Fluch[cl]![dl] Bitte!\",\n\t\"trash_goblin_1\": \"ICH BIN FREI![dl] Vielen, vielen Dank!\",\n\t\"boxy_0\": \"Schlüsselhaft...\",\n\t\"boxy_1\": \"Was für eine schöne Box!\",\n\t\"boxy_2\": \"Brauchst du noch Geschenkpapier?\",\n\t\"trash_goblin_2\": \"[ic 0] ^^Atemlos... [dl]durch die Naaaacht...^^ [ic 1][dl] ##BIS EIN NEUER TAG ERWAAAACHT[ic 0]##\",\n\t\"bk:vampire_bat\": \"Vampir Fledermaus\",\n\t\"bk:vampire_bat_desc\": \"Regeneration\",\n\t\"shields\": \"Schilder\",\n\t\"bk:mustache\": \"Schnurrbart\",\n\t\"bk:mustache_desc\": \"Premium\",\n\t\"bk:bloody_chest\": \"Blutige Kiste\",\n\t\"bk:bloody_chest_desc\": \"Kisten heilen dich\",\n\t\"bk:bloody_shield\": \"Blutiges Schild\",\n\t\"bk:bloody_shield_desc\": \"Schilder bis zum Lebensende\",\n\t\"bk:cutsaw\": \"Kreissäge\",\n\t\"bk:cutsaw_desc\": \"Sie werden bezahlen, MUHAHAHAHA\",\n\t\"vampire_0\": \"Mhhh!\",\n\t\"vampire_1\": \"Einfach nur Herzerwärmend!\",\n\t\"vampire_2\": \"So süß!\",\n\t\"vampire_3\": \"We know the rules, [cl red]^^right[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"Welche Blutgruppe hast du?\",\n\t\"vampire_6\": \"So lecker!\",\n\t\"duck_2\": \"Entschuldigung,[dl] hätten Sie kurz Zeit für eine kleine Umfrage?\",\n\t\"duck_7_0\": \"Klar\",\n\t\"duck_7_1\": \"Nö\",\n\t\"duck_7\": \"Willst du die Kiste?\",\n\t\"duck_4\": \"Sehr gut! Dann darfst du die Kiste haben!\",\n\t\"duck_5\": \"Dem kann ich leider nicht zustimmen!\",\n\t\"duck_6_0\": \"Pizza\",\n\t\"duck_6_1\": \"Steuern\",\n\t\"duck_6\": \"Über was denke ich gerade nach?\",\n\t\"duck_8_0\": \"[cl red]Rot[cl]\",\n\t\"duck_8_1\": \"[cl blue]Blau[cl]\",\n\t\"duck_8\": \"Welche ist meine ^^%%Lieblingsfarbe%%^^?\",\n\t\"duck_9_0\": \"Eine Katze\",\n\t\"duck_9_1\": \"Du, gerade im Moment\",\n\t\"duck_9\": \"Wer sagt \\\"Miau\\\"?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"Was ist besser?\",\n\t\"duck_11_0\": \"What, you egg?\",\n\t\"duck_11_1\": \"\\\\[_He stabs him._]\",\n\t\"duck_11\": \"\\\"You are a saucy boy\\\"\",\n\t\"duck_12_0\": \"Henne\",\n\t\"duck_12_1\": \"Ei\",\n\t\"duck_12\": \"Was kam zuerst?\",\n\t\"duck_13_0\": \"Müsli, Milch, Löffel\",\n\t\"duck_13_1\": \"Milch, Müsli, Löffel\",\n\t\"duck_13_2\": \"Löffel, Milch, Müsli\",\n\t\"duck_13_3\": \"Müsli, Käse, Salat, Gabel\",\n\t\"duck_13\": \"Welche ist die richtige Reihenfolge?\",\n\t\"duck_14\": \"Autsch.\",\n\t\"duck_17_0\": \"Na klar!\",\n\t\"duck_17_1\": \"##EKELHAFT##\",\n\t\"duck_17\": \"Ananas auf Pizza?\",\n\t\"duck_18_0\": \"Weiss!\",\n\t\"duck_18_1\": \"[cl yellow]Gelb![cl]\",\n\t\"duck_18\": \"Welche Farbe hat Käse?\",\n\t\"nurse_0\": \"Du schaust super aus, Liebling!\",\n\t\"nurse_1\": \"Ich könnte dich etwas Ärztlich versorgen.[dl] Nicht versichert? Dann macht das [cl yellow][vr price] Münzen[cl]!\",\n\t\"nurse_2\": \"Ich hoffe das hat jetzt nicht wehgetan!\",\n\t\"elon_4\": \"Hier, Bitteschön, viel Spaß!\",\n\t\"elon_2_0\": \"Losgehts\",\n\t\"elon_2_1\": \"HALT STOP\",\n\t\"elon_2\": \"Willst du ein bisschen Magie ausprobieren?\",\n\t\"elon_3\": \"Ich kann deine Waffe in eine Andere verwandeln!\",\n\t\"elon_5\": \"Okay...\",\n\t\"elon_7\": \"Junge, wo ist dein Waffe?\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*peinlich berührter Gesichtsausdruck*\",\n\t\"gobetta_4\": \"Bist du's?\",\n\t\"gobetta_5\": \"Es ist so lange her..\",\n\t\"ach_bk:desert\": \"Trocken und Heiß\",\n\t\"ach_bk:desert_desc\": \"Erreiche den Wüstenpalast\",\n\t\"ach_bk:jungle\": \"Sum sum sum\",\n\t\"ach_bk:jungle_desc\": \"Erreiche den verlorenen Tempel\",\n\t\"rooms_explored\": \"Räume erkundet\",\n\t\"bk:shadow_cloak_desc\": \"Nein, du!\",\n\t\"bk:shadow_cloak\": \"Schattenumhang\",\n\t\"bk:dynamite_stick\": \"Dynamitstange\",\n\t\"bk:dynamite_stick_desc\": \"Willst du explodieren?\",\n\t\"bk:chalice_of_blood\": \"Kelch des Blutes\",\n\t\"bk:chalice_of_blood_desc\": \"Furcht führt zu Wut, Wut führt zu Hass, Hass führt zu unsäglichem Leid\",\n\t\"bk:detonator\": \"Zündvorrichtung\",\n\t\"bk:detonator_desc\": \"Jagt Sprengkörper in die Luft\",\n\t\"invincibility_time\": \"Unbesiegbarkeitszeit\",\n\t\"accuracy\": \"Zielgenauigkeit\",\n\t\"range\": \"Reichweite\",\n\t\"fire_rate\": \"Feuerrate\",\n\t\"speed\": \"Geschwindigkeit\",\n\t\"bk:talisman_of_foresight\": \"Talisman der Voraussicht\",\n\t\"bk:talisman_of_foresight_desc\": \"Öffne deine Augen und sieh in angrenzende Räume!\",\n\t\"bk:scourge_ring\": \"Fluchring\",\n\t\"bk:scourge_ring_desc\": \"Schnipp Schnapp, Fluch hau ab.\",\n\t\"snek_0\": \"Cool.\",\n\t\"snek_1\": \"Sssehr nett, man\",\n\t\"snek_2\": \"Vvvverrückt!\",\n\t\"snek_3\": \"Wie gehtssss?\",\n\t\"snek_4\": \"Guten Tag, Ssssir\",\n\t\"snek_5\": \"Wollen Ssssie was kaufen?\",\n\t\"snek_6\": \"Kunde isssst König\",\n\t\"snek_7\": \"Ich werde tun, wassss ich musssss\",\n\t\"bk:snek\": \"Snek\",\n\t\"bk:snek_desc\": \"Snack?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Hey, hast nen Schlüssel übrig?\",\n\t\"boxy_5\": \"Was dagegen ein paar Schlüssel zu spenden?\",\n\t\"bk:blank\": \"Leer\",\n\t\"bk:blank_desc\": \"_Leerer Text_\",\n\t\"bk:blank_bombs\": \"Leere Bomben\",\n\t\"bk:blank_bombs_desc\": \"Schusssicheres Schild\",\n\t\"bk:explosive_bullets\": \"Explosive Schüsse\",\n\t\"bk:explosive_bullets_desc\": \"bumm bumm\",\n\t\"bk:random_bullets\": \"Zufällige Projektile\",\n\t\"bk:random_bullets_desc\": \"Alle Angaben ohne Gewehr\",\n\t\"bk:cup\": \"Tasse\",\n\t\"bk:cup_desc\": \"*Schlürf*\",\n\t\"bk:cartridge\": \"Druckerpatrone\",\n\t\"bk:cartridge_desc\": \"Da kann selbst der dunkle Magier nicht wiederstehen!\",\n\t\"bk:marriage_ring\": \"Hochzeitsring\",\n\t\"bk:marriage_ring_desc\": \"DM & Omi <3\",\n\t\"boxy_7\": \"Ich will Schlüssel\",\n\t\"boxy_8\": \"Du scheinst nicht genug Schlüssel zu haben :(\",\n\t\"boxy_9\": \"Ayyy, super![dl] Jetzt hab ich genug Schlüssel, danke!\",\n\t\"roger_3\": \"Lust zu spielen?\",\n\t\"roger_4\": \"Keine Rabatte heute, sorry\",\n\t\"roger_5\": \"Bombastisch!\",\n\t\"vampire_7\": \"Du hast nicht genug Blut!\",\n\t\"vampire_8\": \"Ich geb hier keine Preisnachlässe...\",\n\t\"vampire_9\": \"Deine HP scheinen zu niedrig zu sein...\",\n\t\"ach_bk:scourged\": \"Verflucht\",\n\t\"ach_bk:scourged_desc\": \"Hebe eine Fluch-Rune auf\",\n\t\"ach_bk:scourged_weapon\": \"Verfluchte Waffe\",\n\t\"ach_bk:scourged_weapon_desc\": \"Hebe eine verfluchte Waffe auf\",\n\t\"rerolled\": \"Gegenstände durchgemischt!\",\n\t\"ach_bk:open_up\": \"Open Up\",\n\t\"ach_bk:open_up_desc\": \"Kaufe alles was Boxy anbietet.\",\n\t\"ach_bk:snek\": \"Snek\",\n\t\"ach_bk:snek_desc\": \"Bekomme Snek dazu dein Haustier zu sein.\",\n\t\"bk:scourge_of_greed\": \"Fluch der Gier\",\n\t\"bk:scourge_of_greed_desc\": \"Hohe Preise\",\n\t\"killed_by\": \"Getötet durch\",\n\t\"kills\": \"Tötungen\",\n\t\"time\": \"Zeit\",\n\t\"depth\": \"Ebene\",\n\t\"bk:blank_bullets\": \"Leere Kugeln\",\n\t\"bk:blank_bullets_desc\": \"Leer\",\n\t\"bk:lego\": \"Baustein\",\n\t\"bk:lego_desc\": \"Aus rechtlichen Gründen können wir hier leider nicht den allseits bekannten Namen verwenden.\",\n\t\"bk:iron_armor\": \"Eisenrüstung\",\n\t\"bk:iron_armor_desc\": \"Gibt Schilde\",\n\t\"bk:round_shield\": \"Rundes Schild\",\n\t\"bk:round_shield_desc\": \"Verhindert Schaden durch direkten Kontakt\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"Wie in der Legende\",\n\t\"bk:inverted_arkhalis\": \"Invertiertes Arkhalis\",\n\t\"bk:inverted_arkhalis_desc\": \"Hilfe kommt kurz vorm Tod\",\n\t\"bk:gun_sword\": \"Pistolen-Schwert\",\n\t\"bk:gun_sword_desc\": \"Jetzt gibt es Ärger!\",\n\t\"ach_bk:scourge_king_desc\": \"Bekomme 10 Fluch-Punkte\",\n\t\"ach_bk:scourge_king\": \"König der Flüche\",\n\t\"ach_bk:sting_operation\": \"Stachlige Angelegenheit\",\n\t\"ach_bk:sting_operation_desc\": \"Besiege die Bienenkönigin\",\n\t\"ach_bk:mummified\": \"Mumifiziert\",\n\t\"ach_bk:mummified_desc\": \"Besiege den Pharao\",\n\t\"ach_bk:democracy\": \"Demokratie\",\n\t\"ach_bk:democracy_desc\": \"Besiege den alten König\",\n\t\"pharaoh_scream\": \"##MACH DICH BEREIT FÜR DEN SARG!##\",\n\t\"queen_bee_scream\": \"##FÜR DEN [cl yellow]HONIG LORD[cl]!##\",\n\t\"duck_19\": \"Meine Schwester wurde in den Kerker gesperrt...[dl] bis [cl red]er[cl] herausgefunden hat, dass sie mit ihrem Mund Kugeln schießen konnte...[dl] Ich frag mich, ob sie noch da unten ist...\",\n\t\"duck_20\": \"quack. \",\n\t\"bk:half_heart\": \"Halbes Herz\",\n\t\"right\": \"Rechts\",\n\t\"down\": \"Runter\",\n\t\"left\": \"Links\",\n\t\"up\": \"Hoch\",\n\t\"painting_cat\": \"Katzen-Gemälde\",\n\t\"bk:axe\": \"Axt\",\n\t\"bk:axe_desc\": \"Hat versprochen wiederzukommen\",\n\t\"bk:guitar\": \"Gitarre\",\n\t\"bk:guitar_desc\": \"Ist leider verstimmt\",\n\t\"bk:glass_sword\": \"Glas-Schwert\",\n\t\"bk:glass_sword_desc\": \"Man sieht die Klinge nicht kommen...\",\n\t\"bk:chicken\": \"Hähnchenflügel\",\n\t\"bk:chicken_desc\": \"Scharf wie sonst noch was...\",\n\t\"bk:pickaxe\": \"Spitzhacke\",\n\t\"bk:pickaxe_desc\": \"Grab schneller, du fauler Sack!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"Halbe Mana\",\n\t\"bk:lava_wand\": \"Lava-Zauberstab\",\n\t\"bk:lava_wand_desc\": \"Hitzige Sache\",\n\t\"bk:web_wand\": \"Spinnen-Zauberstab\",\n\t\"bk:web_wand_desc\": \"World-Wide-Web Anbieter\",\n\t\"bk:slap_stick\": \"Fernklatscher\",\n\t\"bk:slap_stick_desc\": \"Klatsch!\",\n\t\"sensivity\": \"Empfindlichkeit\",\n\t\"no\": \"Nein\",\n\t\"scale\": \"Zoom-Faktor\",\n\t\"ach_bk:ice\": \"Eiszeit\",\n\t\"ach_bk:ice_desc\": \"Erreiche die Eis-Ruinen\",\n\t\"ach_bk:library\": \"Die heiligen Texte!\",\n\t\"ach_bk:library_desc\": \"Erreiche die geheime Bibliothek\",\n\t\"bk:ice_skates\": \"Schlittschuhe\",\n\t\"bk:ice_skates_desc\": \"Für mehr Körperkontrolle auf dem Eis\",\n\t\"bk:campfire_in_bottle\": \"Lagerfeuer in der Flasche\",\n\t\"bk:campfire_in_bottle_desc\": \"Immunität gegen Einfrieren\",\n\t\"library\": \"Geheime Bibliothek\",\n\t\"ach_bk:cat_without_a_hat\": \"Katze ohne Hut\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Finde das Katzen-Gemälde\",\n\t\"ach_bk:rich\": \"Toilettenpapier\",\n\t\"ach_bk:rich_desc\": \"Besitze 99 Münzen\",\n\t\"ach_bk:rescue_operation\": \"Rettungsaktion\",\n\t\"ach_bk:rescue_operation_desc\": \"Rette einen NPC\",\n\t\"ach_bk:tutorial\": \"Guru\",\n\t\"ach_bk:tutorial_desc\": \"Beende das Tutorial\",\n\t\"ach_bk:fancy_hat\": \"Schicker Hut!\",\n\t\"ach_bk:fancy_hat_desc\": \"Kauf dir einen Hut\",\n\t\"ach_bk:unlock\": \"Sammler\",\n\t\"ach_bk:unlock_desc\": \"Schalte einen Gegenstand frei\",\n\t\"floor_brightness\": \"Boden-Helligkeit\",\n\t\"ach_bk:shielded\": \"Schilde Hoch!\",\n\t\"ach_bk:shielded_desc\": \"Sammle ein Schild-Herz\",\n\t\"run_type\": \"Run Typ\",\n\t\"run_regular\": \"Normal\",\n\t\"run_challenge\": \"Herausforderung\",\n\t\"damage_taken\": \"Schaden erlitten\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Distanz gelaufen\",\n\t\"seed\": \"Seed\",\n\t\"score\": \"Punktzahl\",\n\t\"new_high_score\": \"Neuer Rekord!\",\n\t\"items_collected\": \"Gegenstände gesammelt\",\n\t\"boss_rush\": \"Boss Rush\",\n\t\"run_bossrush\": \"Boss Rush\",\n\t\"bk:blindfold_desc\": \"RIP meine Waffen\",\n\t\"bk:blindfold\": \"Augenbinde\",\n\t\"daily_run\": \"Täglicher Run\",\n\t\"builder_0_0\": \"Ja klar!\",\n\t\"builder_0_1\": \"Ich brauch das Geld selber!\",\n\t\"builder_0\": \"Ich plane eine Abkürzung hierher zu bauen, dafür bräuchte ich aber noch [vr need] [ic 0] weitere coins. Kannst du mir da helfen?\",\n\t\"builder_1\": \"Aber du hast garkein Geld! :(\",\n\t\"builder_2\": \"Danke für deine Investition!\",\n\t\"builder_3\": \"Ich hab endlich genug Geld um das Projekt hier abzuschließen. Vielen Dank!\",\n\t\"builder_4\": \"Okay, 'tschuldigung!\",\n\t\"shortcut_is_broken\": \"Abkürzung ist kaputt\",\n\t\"ach_bk:boss_rush\": \"Boss Herausforderer\",\n\t\"ach_bk:boss_rush_desc\": \"Besiege alle Bosse in \\\"Boss Rush\\\"\",\n\t\"ach_bk:daily\": \"Täglicher Ruhm\",\n\t\"ach_bk:daily_desc\": \"Beende eine der täglichen Herausforderungen\",\n\t\"ach_bk:desert_shortcut\": \"Wüstenpalast Abkürzung\",\n\t\"ach_bk:desert_shortcut_desc\": \"Repariere die Abkürzung zum Wüstenpalast\",\n\t\"ach_bk:jungle_shortcut\": \"Uralter Dschungel Abkürzung\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Repariere die Abkürzung zum Uralten Dschungel\",\n\t\"ach_bk:ice_shortcut\": \"Eis-Ruinen Abkürzung\",\n\t\"ach_bk:ice_shortcut_desc\": \"Repariere die Abkürzung zu den Eis-Ruinen\",\n\t\"ach_bk:library_shortcut\": \"Geheime Bibliothek Abkürzung\",\n\t\"ach_bk:library_shortcut_desc\": \"Repariere die Abkürzung zur Geheime Bibliothek\",\n\t\"ach_bk:fashion_matters2\": \"Mode ist wichtig\",\n\t\"ach_bk:fashion_matters2_desc\": \"Kaufe jeden einzelnen Hut\",\n\t\"ach_bk:10_challenges\": \"Herausforderer\",\n\t\"ach_bk:10_challenges_desc\": \"Schließe 10 Herausforderungen ab\",\n\t\"ach_bk:20_challenges\": \"Herausforderer 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Schließe 20 Herausforderungen ab\",\n\t\"ach_bk:30_challenges\": \"Herausforderer 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Schließe 30 Herausforderungen ab\",\n\t\"ach_bk:bk_no_more\": \"Tschüss, Burning Knight!\",\n\t\"ach_bk:bk_no_more_desc\": \"Besiege den Burning Knight\",\n\t\"ach_bk:dm_no_more\": \"Ende im Gelände\",\n\t\"ach_bk:dm_no_more_desc\": \"Besiege den dunklen Magier\",\n\t\"ach_bk:egor_no_more\": \"Egor's Untergang\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Auf ein Neues!\",\n\t\"ach_bk:loop_desc\": \"Betrete die Schleife\",\n\t\"coins_collected\": \"Münzen gesammelt\",\n\t\"bk:cup_head\": \"Tassenhut\",\n\t\"bk:cup_head_desc\": \"Hoffentlich ohne Inhalt\",\n\t\"bk:mustache_hat\": \"Schnurrbart\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Propeller Hut\",\n\t\"bk:propeller_hat_desc\": \"Er dreht sich\",\n\t\"bk:sunglasses\": \"Sonnenbrille\",\n\t\"bk:sunglasses_desc\": \"Der coolere Daniel\",\n\t\"bk:cap\": \"Cap\",\n\t\"bk:cap_desc\": \"Cool @-@\",\n\t\"bk:eyes\": \"Augen\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Auge\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Haare\",\n\t\"bk:hair_desc\": \"Schick!\",\n\t\"won\": \"Gewonnen\",\n\t\"won_message\": \"Du haben Gewonnen! Großer Glückwunsch!\",\n\t\"you_won_demo\": \"Das ist das Ende der Demo-Version :)\",\n\t\"garderobe_sign\": \"Ankleideraum\",\n\t\"darkmarket_tip\": \"~~[cl purple]Fluch[cl] oder [cl yellow]30 Münzen[cl]@@\",\n\t\"mike_0\": \"Du musst mir [cl green]3 Smaragde[cl] zahlen!\",\n\t\"mike_1\": \"Probiere Boss Rush für nur [cl green]3 Smaragde[cl]!\",\n\t\"bk:weird_potion\": \"Seltsamer Trank\",\n\t\"bk:weird_potion_desc\": \"Seltsame Projektile\",\n\t\"bk:megaphone\": \"Megaphon\",\n\t\"bk:megaphone_desc\": \"SEHR LAUTE UND VORALLEM GROßE PROJEKTILE\",\n\t\"scourge\": \"Fluch\",\n\t\"scourge_stats\": \"Flüche\",\n\t\"run_daily\": \"Täglicher Run\",\n\t\"full_version\": \"Diese Tür kannst du nur in der Vollversion öffnen!\",\n\t\"completed_on\": \"Abgeschlossen am\",\n\t\"complete\": \"Abgeschlossen\",\n\t\"wishlist_pls\": \"Macht dir die Demo spaß? Füge die Vollversion zu deiner Wunschlite hinzu! [cl red]burningknight.net\\/steam\",\n\t\"next_daily_in\": \"[cl gray]Nächster Run startet in[cl]\",\n\t\"hours\": \"Stunden\",\n\t\"minutes\": \"Minuten\",\n\t\"seconds\": \"Sekunden\",\n\t\"ach_bk:star\": \"Der Star der Show\",\n\t\"ach_bk:star_desc\": \"Habe drei Orbitale gleichzeitig\",\n\t\"ach_bk:family\": \"Familienvater\",\n\t\"ach_bk:family_desc\": \"Besitze drei Haustiere gleichzeitig\",\n\t\"ach_bk:return_to_sender\": \"no u\",\n\t\"ach_bk:return_to_sender_desc\": \"Töte einen Gegner mit seinem eigenen Projektil\",\n\t\"ach_bk:van_no_gogh\": \"Van-Ganzundgarnicht-Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Zerstöre 100 Gemälde\",\n\t\"ach_bk:boom\": \"Kettenreaktion\",\n\t\"ach_bk:boom_desc\": \"Lasse eine Kette von drei TNT explodieren\",\n\t\"ach_bk:dark_market\": \"Verbrecherversteck\",\n\t\"ach_bk:dark_market_desc\": \"Begieb dich zum Schwarzmarkt\",\n\t\"ach_bk:spikes\": \"Brensliche Angelegenheit\",\n\t\"ach_bk:spikes_desc\": \"Aktiviere 100 Fallen in einem Run\",\n\t\"ach_bk:white_flag\": \"Ich komme in Frieden\",\n\t\"ach_bk:white_flag_desc\": \"Leere einen Raum ohne Waffen zu verwenden\",\n\t\"quack\": \"[cl yellow]Quak![cl]\",\n\t\"pixel_perfect\": \"Pixel-Perfect\",\n\t\"bk_11\": \"ICH VERGEBE DIR DIESES EINE MAL... ##ABER MACH DAS BLOß NICHT NOCHMAL!##\",\n\t\"leaderboard\": \"Bestenliste\",\n\t\"display\": \"Zeige an\",\n\t\"around_you\": \"Dein Umfeld\",\n\t\"friends\": \"Freunde\",\n\t\"global\": \"Global\",\n\t\"loading\": \"Läd...\",\n\t\"generating\": \"Generiert...\",\n\t\"cursor_radius\": \"Cursor Radius\",\n\t\"no_scores_yet\": \"Keine Punkzahlen bisher\",\n\t\"no_score_yet\": \"Keine Punkzahl bisher\",\n\t\"run\": \"Run\",\n\t\"top\": \"Top\",\n\t\"quick_restart\": \"Schnellstart\",\n\t\"painting_dungeon\": \"Kerker\",\n\t\"painting_goose\": \"Mini Gans\",\n\t\"painting_chess\": \"Fliegender Elefant\",\n\t\"painting_peach\": \"Ein Pfirsichbaum\",\n\t\"bk:no_lamp\": \"Keine Lampe\",\n\t\"bk:explosive_lamp\": \"Explosive Lampe\",\n\t\"bk:explosive_lamp_desc\": \"Wenn ein Bumm nicht einfach nur ein Bumm ist...\",\n\t\"bk:shielded_lamp\": \"Gepanzerte Lampe\",\n\t\"bk:shielded_lamp_desc\": \"KAMERADSCHAFT, SCHILE HOCH!\",\n\t\"lamp\": \"Lampe\",\n\t\"bk:brain\": \"Mega Gehirn\",\n\t\"bk:brain_desc\": \"Gehin Größe: Mega\",\n\t\"bk:heart_amulet\": \"Herzamulett\",\n\t\"bk:heart_amulet_desc\": \"+1 Herzgröße\",\n\t\"bk:star_amulet_desc\": \"Mehr Mana\",\n\t\"bk:star_amulet\": \"Sternenamulett\",\n\t\"bk:coin_amulet\": \"Münzamulett\",\n\t\"bk:coin_amulet_desc\": \"Münzen sind mehr Wert\",\n\t\"bk:key_amulet\": \"Schlüsselamulett\",\n\t\"bk:key_amulet_desc\": \"Schlüssel sind mehr Wert\",\n\t\"bk:bomb_amulet\": \"Bombenamulett\",\n\t\"bk:bomb_amulet_desc\": \"Bomben sind mehr Wert\",\n\t\"bk:eye_amulet\": \"Augamulett\",\n\t\"bk:eye_amulet_desc\": \"Es schmerzt so Unpräzise zu sein\",\n\t\"bk:eye_patch\": \"Augenklappe\",\n\t\"bk:eye_patch_desc\": \"Arr arr!\",\n\t\"bk:toilet_paper\": \"Klopapier\",\n\t\"bk:toilet_paper_desc\": \"Kann man nie genug davon haben!\",\n\t\"bk:decoy\": \"Lockvogel\",\n\t\"bk:decoy_desc\": \"...mit Sprengstatz\",\n\t\"bk:wallet\": \"Geldbeutel-Kumpel\",\n\t\"bk:wallet_desc\": \"Passt auf deine Münzen auf\",\n\t\"bk:skele_buddy\": \"Skelett-Kumpel\",\n\t\"bk:skele_buddy_desc\": \"Gruselig\",\n\t\"bk:mega_bomb\": \"Mega Bombe\",\n\t\"bk:mega_bomb_desc\": \"Bomben Größe: Mega\",\n\t\"bk:condensed_milk\": \"Kondensmilch\",\n\t\"bk:condensed_milk_desc\": \"Jetzt mit 0.5% weniger Fett!\",\n\t\"bk:marshmallow\": \"Marshmallow\",\n\t\"bk:marshmallow_desc\": \"Klebrig\",\n\t\"bk:orbital_multiplier\": \"Orbitalmultiplikator\",\n\t\"bk:orbital_multiplier_desc\": \"Mehr Orbitale!\",\n\t\"bk:pet_multiplier\": \"Haustiermultiplikator\",\n\t\"bk:pet_multiplier_desc\": \"Mehr Haustiere!\",\n\t\"bk:ghost_bullets\": \"Geisterkugeln\",\n\t\"bk:ghost_bullets_desc\": \"Wände halten dich nicht mehr auf!\",\n\t\"bk:weight\": \"Schweres Gewicht\",\n\t\"bk:weight_desc\": \"e = m * v^2\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"\\\"Take it or leave it\\\"\",\n\t\"bk:ethernal_d6\": \"Zeitloser D6\",\n\t\"bk:ethernal_d6_desc\": \"Würfelt und\\/oder Zerstört\",\n\t\"bk:billiard\": \"Billard\",\n\t\"bk:billiard_desc\": \"Kugeln prallen ab\",\n\t\"bk:enraged_bullets\": \"Wütende Kugeln\",\n\t\"bk:enraged_bullets_desc\": \"Kugeln zerstören Kugeln\",\n\t\"bk:rewind_button\": \"Rewind Knopf\",\n\t\"bk:rewind_button_desc\": \"Das kann ja nur schief gehen!\",\n\t\"bk:piggy_bank\": \"Sparschwein\",\n\t\"bk:piggy_bank_desc\": \"Für schlechte Zeiten\",\n\t\"coins\": \"Münzen\",\n\t\"bk:death_star\": \"Todesstern\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Lötkolben\",\n\t\"bk:soldering_iron_desc\": \"heiß heiß heiß\",\n\t\"bk:can\": \"Dose\",\n\t\"bk:can_desc\": \"Doppelte Projektile\",\n\t\"bk:swimming_mask\": \"Taucherbrille\",\n\t\"bk:swimming_mask_desc\": \"(Ist eine geheime Waffe)\",\n\t\"bk:bullet_chair\": \"Offensivstuhl\",\n\t\"bk:bullet_chair_desc\": \"4 Beine, 4 Kanonen\",\n\t\"bk:cell\": \"Zelle\",\n\t\"bk:cell_desc\": \"Zelltelilung für Projektile\",\n\t\"bk:brick\": \"iZiegel\",\n\t\"bk:brick_desc\": \"Größere Level\",\n\t\"bk:ring_of_pain\": \"Ring des Schmerzes\",\n\t\"bk:ring_of_pain_desc\": \"Verlezt werden tut allen Weh\",\n\t\"bk:schrodingers_cat\": \"Schrödingers Katze\",\n\t\"bk:schrodingers_cat_desc\": \"Sein oder nicht sein, das hat eine 50% Wahrscheinlichkeit. Oder so.\",\n\t\"bk:smoke_bomb\": \"Rauchbombe\",\n\t\"bk:smoke_bomb_desc\": \"Bitte nicht im Gebäude rauchen!\",\n\t\"bk:chest_ring\": \"Kistenring\",\n\t\"bk:chest_ring_desc\": \"Wer auch immer sich das ausgedacht hat, sollte gefeuert werden. (Mehr Kisten)\",\n\t\"bk:empty_shell\": \"Leerer Panzer\",\n\t\"bk:empty_shell_desc\": \"Eine Chance gegnerische Kugeln zu zerstören\",\n\t\"bk:parachute\": \"Fallschirm\",\n\t\"bk:parachute_desc\": \"Runterfallen nicht mehr mögich\",\n\t\"bk:spiked_cookie\": \"Stachelkeks\",\n\t\"bk:spiked_cookie_desc\": \"Joa, was soll man dazu noch sagen...\",\n\t\"bk:shooty\": \"Shooty\",\n\t\"bk:shooty_desc\": \"Schießt schneller als sein Schatten\",\n\t\"bk:rabbit_bullets\": \"Kaninchenkugeln\",\n\t\"bk:rabbit_bullets_desc\": \"Sie vermehren sich wie die Karnickel\",\n\t\"bk:pandoras_box\": \"Pandora's Büchse\",\n\t\"bk:pandoras_box_desc\": \"Öffne sie lieber nicht\",\n\t\"bk:bubbles\": \"Blasen\",\n\t\"bk:bubbles_desc\": \"Blubberfreund\",\n\t\"bk:match\": \"Streichholz\",\n\t\"bk:match_desc\": \"Mit feuer spielt man nicht!\",\n\t\"bk:hammer\": \"Hammer\",\n\t\"bk:hammer_desc\": \"Rüstungsbrecher\",\n\t\"bk:helmet\": \"Eisenhelm\",\n\t\"bk:helmet_desc\": \"Mit etwas Glück hält er Schaden ab\",\n\t\"bk:beer\": \"Bier\",\n\t\"bk:beer_desc\": \"Betrunken + Aggressiv = Schlechte Kombination\",\n\t\"bk:the_eye\": \"Das Auge\",\n\t\"bk:the_eye_desc\": \"Es beobachtet dich!\",\n\t\"bk:mimics_tooth\": \"Mimic's Zähne\",\n\t\"bk:mimics_tooth_desc\": \"Zieht Mimics an\",\n\t\"ach_bk:mimic\": \"Jump Scare\",\n\t\"ach_bk:mimic_desc\": \"Finde einen Mimic\",\n\t\"bk:paper_airplane\": \"Papierflugzeug\",\n\t\"bk:paper_airplane_desc\": \"Kugeln mit Autopilot\",\n\t\"ach_bk:ice_boss\": \"Let It Go\",\n\t\"ach_bk:ice_boss_desc\": \"Töte die Eiskönigin\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Ahem\",\n\t\"painting_agency\": \"Willkommen in der Agentur\",\n\t\"inventory\" : \"Inventar\",\n\t\"bk:pouch\": \"Beutel\",\n\t\"bk:alien_glasses\": \"Alien Brille\",\n\t\"bk:alien_glasses_desc\": \"Ich sehe mehr!\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Es werde Licht!\",\n\t\"bk:fragile_lamp\": \"Zerbrechliche Lampe\",\n\t\"bk:fragile_lamp_desc\": \"Schachmatt in einem Zug\",\n\t\"painting_guitar\": \"LAUTER!\",\n\t\"ach_bk:maanex\": \"Et tu, Brut?\",\n\t\"ach_bk:maanex_desc\": \"Töte Maanex während du seinen Kopf aufhast.\",\n\t\"dad_0\": \"Hey Sohn![dl] Ich muss gehen um [cl red]die Lampe[cl] zu finden. Du hast jetzt hier das Komando!\",\n\t\"dad_1\": \"Ach, fast vergessen...[dl]Wenn ich nicht zurück komme, such auch nicht nach mir. Tschüssi!\",\n\t\"son_0\": \"##NEEEEEEEIN##\",\n\t\"gobbo_0\": \"Sohn, [cl green]mein Vater[cl] hat mich vor 20 Jahren verlassen. Ich muss ihn finden.\",\n\t\"gobbo_1\": \"Du, äh... du hast jetzt hier das Sagen! Man sieht sich!\",\n\t\"dm_5\": \"Eine neue und vorallem ^^bessere^^ [cl red]Puppe[cl]![dl] ##MUHAHAHA##\",\n\t\"dm_6\": \"Hast du mich gehört, [cl red]Limpor?\",\n\t\"heinur_0\": \"##OCH NEEE[dl], NICH SCHON WIEDER!##\",\n\t\"nbk_0\": \"##JA, MEIN MEISTER##\",\n\t\"bk_12\": \"##ICH HAB KEINE KÖNIGE MEHR ÜBRIG! ALSO KÄMPF GEGEN MICH, DU SCHWÄCHLING!##\",\n\t\"bk:headshot_gun\": \"Gebogene Shotgun\",\n\t\"bk:headshot_gun_desc\": \"Sehr fragwürdiges Patent\",\n\t\"bk:laser_cannon\": \"Laserpistole\",\n\t\"bk:laser_cannon_desc\": \"Haha, laser macht pew pew\",\n\t\"credits\": \"Mitwirkende\",\n\t\"head_0\": \"Trottel\",\n\t\"tech\": \"Techno\",\n\t\"ach_bk:collector\": \"Sammler\",\n\t\"ach_bk:collector_desc\": \"Sammel alle Gegenstände\",\n\t\"bk:treasure_key\": \"Roter Schlüssel\",\n\t\"bk:treasure_key_desc\": \"Öffnet die %%Schleife%%\",\n\t\"bk:pass\": \"Pass\",\n\t\"bk:pass_desc\": \"Führerschein und Fahrzeugpapiere bitte!\",\n\t\"bk:bucket\": \"Eimer\",\n\t\"bk:bucket_desc\": \"So leer macht der wenig Sinn.\",\n\t\"bk:water_bucket\": \"Wassereimer\",\n\t\"bk:water_bucket_desc\": \"Beruhigt [cl red]das Feuer[cl]\",\n\t\"bk:snow_bucket\": \"Schneeeimer\",\n\t\"bk:snow_bucket_desc\": \"Vielleicht... könnte es... schmelzen?\",\n\t\"m2_0\": \"Ich glaub ich muss Insolvenz anmelden...\",\n\t\"m2_1\": \"Nicht schlecht!\",\n\t\"m2_2\": \"Hey du, willst du mal die Maschine hier ausprobieren?\",\n\t\"m2_3\": \"Kassenzettel?[dl] Wie auch immer, benutze ^^%%den Computer%%^^ hier um den Greifarm zu steuern!\",\n\t\"maanex2_0_0\": \"Nimm mein Geld!\",\n\t\"maanex2_0_1\": \"Das ist doch eh nur Abzocke.\",\n\t\"maanex2_0\": \"Okay, das macht dann [cl yellow][vr cost] Münzen[cl], bitte!\",\n\t\"dm_7\": \"Lasst uns ein kleines Spiel spielen!\",\n\t\"bkw_0\": \"EIN WEITERER [cl red]EINDRINGLING[cl]!\",\n\t\"bkw_1\": \"##RAUS HIER, SOFORT!##[dl] Oder ich äh, muss dich zwingen...\",\n\t\"bkw_2\": \"Ich suche nach [cl green]meinem Vater\",\n\t\"bkw_3\": \"ICH HABE DICH GEWARNT\",\n\t\"spanish_inquisition\": \"[cl red]Spanische Inquisition\",\n\t\"lp_0\": \"Nicht schlecht, [cl purple]Ritta[cl][dl], ich starte [cl green]die Simulation[cl] dann mal neu, ja?\",\n\t\"bk:broken_bucket\": \"Eimer mit Loch\",\n\t\"bk:broken_bucket_desc\": \"Also quasi Müll...\",\n\t\"bk:ankh\": \"Ankh\",\n\t\"bk:ankh_desc\": \"Leben nach dem Tod!\",\n\t\"bk:broken_ankh\": \"Kaputtes Ankh\",\n\t\"bk:broken_ankh_desc\": \"Leben nach dem Tod?\",\n\t\"bk:what\": \"Was?\",\n\t\"bk:what_desc\": \"Nein ernsthaft, WAS?\",\n\t\"bk:gold_minigun\": \"Goldene Minigun\",\n\t\"bk:gold_minigun_desc\": \"Teurer Spaß...\",\n\t\"bk:gold_dagger\": \"Goldenes Messer\",\n\t\"bk:gold_dagger_desc\": \"Factory New\",\n\t\"bk:gold_revolver\": \"Goldener Revolver\",\n\t\"bk:gold_revolver_desc\": \"Überschütte mich mit Gold!\",\n\t\"bk:gold_axe\": \"Goldene Axt\",\n\t\"bk:gold_axe_desc\": \"Ja halt ne Axt, nix besonderes...\",\n\t\"painting_code\": \"Code\",\n\t\"bk:katana\": \"Katana\",\n\t\"bk:katana_desc\": \"Wem gehört das eigentlich?\",\n\t\"bk:smart_gun\": \"Schlaue Pistole\",\n\t\"bk:smart_gun_desc\": \"Sie weiß bescheid!\",\n\t\"bk:pop_gun\": \"Pop Gun\",\n\t\"bk:pop_gun_desc\": \"Sehr populär!\",\n\t\"bk:the_button\": \"Der Knopf\",\n\t\"bk:the_button_desc\": \"Schaut gefährlich aus...\",\n\t\"bk:gold_sword\": \"Goldenes Schwert\",\n\t\"bk:gold_sword_desc\": \"Wenn du sonst nichts mehr findest wofür du Geld ausgeben kannst...\",\n\t\"bk:donut\": \"Donut\",\n\t\"bk:donut_desc\": \"Lieber nicht auf die Kalorienwerte schauen!\",\n\t\"bk:sudoku\": \"Sudoku\",\n\t\"bk:sudoku_desc\": \"Die Hälfte des Raumes ist weg, reduziert auf Atome\",\n\t\"bk:gps_ring\": \"GPS Ring\",\n\t\"bk:gps_ring_desc\": \"Kleine Wahrscheinlichkeit die Karte aufzudecken\",\n\t\"bk:shield_potion\": \"Schildtrank\",\n\t\"bk:shield_potion_desc\": \"Einen großen Schluck nehmen!\",\n\t\"bk:trash_generator\": \"Müll Generator\",\n\t\"bk:trash_generator_desc\": \"Ja.\",\n\t\"bk:crabs_claw\": \"Krabbenklaue\",\n\t\"bk:crabs_claw_desc\": \"Zerstört jegliche Rüstung\",\n\t\"eg_3\": \"Guten Zeitpunkt, der Herr\",\n\t\"eg_0_0\": \"Nimm ^^[cl lime]die Smaragde[cl]^^\",\n\t\"eg_0_1\": \"Lass sie liegen\",\n\t\"eg_0\": \"Nimm [cl lime]meine Smaragde[cl], ich bitteschön!\",\n\t\"eg_1\": \"Ich bin raus hier\",\n\t\"bk:reverse_card\": \"Richtungswechsel\",\n\t\"bk:reverse_card_desc\": \"Durch Projektile rollen, reflektiert diese\",\n\t\"bk:magnet\": \"Magnet\",\n\t\"bk:magnet_desc\": \"Anziehung und Zuneigung\",\n\t\"bk:glowing_mushroom\": \"Leuchtender Pilz\",\n\t\"bk:glowing_mushroom_desc\": \"Er ist am viben\",\n\t\"bk:tinfoil_hat\": \"Aluhut\",\n\t\"bk:tinfoil_hat_desc\": \"Sicher vor außerirdischen Strahlungen\",\n\t\"bk:rear_window\": \"Heckscheibe\",\n\t\"bk:rear_window_desc\": \"Hält dir den Rücken frei!\",\n\t\"bk:refractor\": \"Refraktor\",\n\t\"bk:refractor_desc\": \"Mit ein bisschen Glück greifst du in alle Richtungen gleichzeitig an!\",\n\t\"bk:fork\": \"Gabel\",\n\t\"bk:fork_desc\": \"Es tut weh\",\n\t\"bk:rock\": \"Felsen\",\n\t\"bk:rock_desc\": \"Schaden zu einem Preis\",\n\t\"bk:coffee_grinder\": \"Kaffeemühle\",\n\t\"bk:coffee_grinder_desc\": \"Kleine aber schnelle Projektile\",\n\t\"integrations\": \"Integrationen\",\n\t\"twitch\": \"Twitch\",\n\t\"streamer_username\": \"Twitch Benutzername\",\n\t\"bk:shawarma\": \"Schawarma\",\n\t\"bk:shawarma_desc\": \"Manchmal sind deine Projektile größer, aber nicht immer!\",\n\t\"bk:cats_ear\": \"Katzenohr\",\n\t\"bk:cats_ear_desc\": \"Kranke Ausweichmanöver!\",\n\t\"luck\": \"Glück\",\n\t\"bk:gamepad\": \"Gamepad\",\n\t\"bk:gamepad_desc\": \"Stabile FPS\",\n\t\"bk:hotdog\": \"Hotdog\",\n\t\"bk:hotdog_desc\": \"Du wurdest gesegnet. Mehr Glück und mehr Leben auf all deinen Wegen!\",\n\t\"bk:bomb_shell\": \"Bombenpanzer\",\n\t\"bk:bomb_shell_desc\": \"Interessantes Konzept\",\n\t\"painting_no_idea\": \"Kein Plan\",\n\t\"painting_tinkerer\": \"Bastler\",\n\t\"painting_in_loving_memory_of_ali\": \"In liebevoller Erinnerung an Ali\",\n\t\"painting_happy_accident\": \"Glück im Unglück\",\n\t\"painting_observing_cheese\": \"Käseinspektion\",\n\t\"painting_chicken_enemy_unknown\": \"Huhn Gegner Unbekannt\",\n\t\"painting_know_stuff\": \"Er weiß bescheid\",\n\t\"painting_whoops\": \"Upsi\",\n\t\"painting_too_lake\": \"Schweinerei\",\n\t\"painting_step_through\": \"Zu viel des Guten\",\n\t\"painting_thats_a_moon\": \"Der Mond ist echt!\",\n\t\"painting_totem\": \"Magischer Kreis\",\n\t\"painting_too_late\": \"Zu spät!\",\n\t\"painting_whipped_cream\": \"Schlagsahne\",\n\t\"painting_beet_boys\": \"Rübenkumpel\",\n\t\"painting_moonshine\": \"Mondschein\",\n\t\"painting_void\": \"Die Leere\",\n\t\"painting_peasants\": \"Der einfache Mann\",\n\t\"bk:gold_lamp\": \"Gold Lampe\",\n\t\"bk:gold_lamp_desc\": \"GELD GELD GELD\",\n\t\"bk:sharp_lamp\": \"Scharfe Lampe\",\n\t\"bk:sharp_lamp_desc\": \"Für Nahkampf-Enthusiasten\",\n\t\"bk:ancient_sword\": \"Uraltes Schwert\",\n\t\"bk:ancient_sword_desc\": \"Das war schon zu Zeiten meines Opas alt!\",\n\t\"ach_bk:unstoppable\": \"Unaufhaltbar\",\n\t\"ach_bk:unstoppable_desc\": \"Spiele das Spiel mit einer Lampe durch!\",\n\t\"no_emeralds\": \"Keine Smaragde\",\n\t\"bk:emerald_gun\": \"Smaragdpistole\",\n\t\"bk:emerald_gun_desc\": \"Die teuerste Pistole auf dem Mark!\"\n}\n"
  },
  {
    "path": "BurningKnight/Content/Locales/en.json",
    "content": "{\n\t\"bk:halo\": \"Halo\",\n\t\"bk:halo_desc\": \"Health up\",\n\t\"bk:revolver\": \"Revolver\",\n\t\"bk:sword\": \"Wooden Sword\",\n\t\"bk:sword_desc\": \"Not just a stick\",\n\t\"bk:heart\": \"Heart\",\n\t\"resume\": \"Resume\",\n\t\"settings\": \"Settings\",\n\t\"restart\": \"Restart\",\n\t\"death_message\": \"You Died\",\n\t\"descend\": \"Descend\",\n\t\"ascend\": \"Ascend\",\n\t\"exit\": \"Exit\",\n\t\"painting_rexcellent\": \"Excellent\",\n\t\"painting_grannylisa\": \"Grannylisa\",\n\t\"painting_maanex\": \"Thinker\",\n\t\"painting_bk\": \"Roasted Knight\",\n\t\"painting_bgang\": \"The Gang\",\n\t\"painting_failpositive\": \"Party Maker\",\n\t\"painting_old_man\": \"Really Old Man\",\n\t\"painting_arthouse\": \"Art House\",\n\t\"painting_black\": \"Universe\",\n\t\"painting_milt\": \"Boy in the snow\",\n\t\"painting_skyscraper\": \"Lonely skyscraper\",\n\t\"painting_egor\": \"Burning Rex\",\n\t\"painting_null\": \"NULL\",\n\t\"painting_badosz\": \"Lost Boy in the Woods\",\n\t\"painting_banana\": \"BANANA\",\n\t\"painting_tv\": \"TV in the sky\",\n\t\"painting_company\": \"Good Company\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Dog du Trasevol\",\n\t\"painting_lamp\": \"Take it\",\n\t\"painting_scream\": \"Icecream\",\n\t\"painting_stars\": \"Scarry night\",\n\t\"painting_fog\": \"In the Seas\",\n\t\"painting_nufflee\": \"Bark\",\n\t\"by\": \"by\",\n\t\"old_man_0\": \"It's dangerous!\",\n\t\"continue_run\": \"Continue Run\",\n\t\"new_run\": \"New Run\",\n\t\"was_unlocked\": \"Was unlocked!\",\n\t\"bk:revolver_desc\": \"Hands up, @everyone!\",\n\t\"bk:shovel\": \"Blue Shovel\",\n\t\"bk:shovel_desc\": \"But why is it blue???\",\n\t\"beet_0\": \"Hi!\",\n\t\"beet_2\": \"Tell me its name!\",\n\t\"npc_hurt_0\": \"Ouch.\",\n\t\"npc_hurt_1\": \"That hurts.\",\n\t\"npc_hurt_2\": \"Oh no.\",\n\t\"beet_3\": \"Thanks <3\",\n\t\"beet_1\": \"Do you want to plant a ^^seed^^?\",\n\t\"beet_1_0\": \"Yes\",\n\t\"beet_1_1\": \"No\",\n\t\"beet_4\": \"The seed is [vr seed]. Do you want to change it?\",\n\t\"beet_4_0\": \"Yes\",\n\t\"beet_4_1\": \"No\",\n\t\"beet_5\": \"Whatever.\",\n\t\"beet_4_2\": \"Let it be random!\",\n\t\"beet_6\": \"Ok. Seed is now [vr seed]!\",\n\t\"bk:idol\": \"Idol\",\n\t\"bk:idol_desc\": \"A hidden trap activates!\",\n\t\"bk:key\": \"Golden Key\",\n\t\"bk:infinite_bomb\": \"Infinite Bomb\",\n\t\"bk:infinite_bomb_desc\": \"Reusable bomb\",\n\t\"throw_coin\": \"Throw a Coin\",\n\t\"bk:potatoo\": \"Potatoo\",\n\t\"bk:potatoo_desc\": \"Splits projectiles\",\n\t\"bk:spectacles\": \"Spectacles\",\n\t\"bk:spectacles_desc\": \"Reveals secrets\",\n\t\"bk:cross\": \"Cross\",\n\t\"bk:cross_desc\": \"Increases invincibility time\",\n\t\"bk:slime\": \"Slime\",\n\t\"bk:slime_desc\": \"Bouncy shots\",\n\t\"bk:missile\": \"Missile\",\n\t\"bk:missile_desc\": \"Homing shots\",\n\t\"bk:rod_of_discord\": \"Rod of Discord\",\n\t\"bk:rod_of_discord_desc\": \"Teleporter for @everyone\",\n\t\"bk:goo\": \"Goo\",\n\t\"bk:goo_desc\": \"Orbiting friend\",\n\t\"bk:jelly\": \"Jelly!\",\n\t\"bk:jelly_desc\": \"^^Bouncy^^\",\n\t\"bk:broken_stone\": \"Broken Stone\",\n\t\"bk:broken_stone_desc\": \"Well-built orbital\",\n\t\"bk:nano_orb\": \"Nano Orb\",\n\t\"bk:nano_orb_desc\": \"Micro friend\",\n\t\"bk:saturn\": \"Planet\",\n\t\"bk:saturn_desc\": \"Of course we still love it\",\n\t\"bk:soap\": \"Soap\",\n\t\"bk:soap_desc\": \"Slows down your projectiles\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"^^Reroll^^ items!\",\n\t\"bk:my_heart\": \"My Heart\",\n\t\"bk:my_heart_desc\": \"Health up\",\n\t\"bk:broken_heart\": \"Broken Heart\",\n\t\"bk:broken_heart_desc\": \"Health up\",\n\t\"bk:parcel\": \"Parcel\",\n\t\"bk:parcel_desc\": \"Reusable healer\",\n\t\"bk:glass\": \"Glass\",\n\t\"bk:glass_desc\": \"##Fragile## projectiles\",\n\t\"bk:glass_bullet\": \"Glass Bullet\",\n\t\"bk:glass_bullet_desc\": \"Shoot over stones\",\n\t\"bk:broken_guitar\": \"Broken Guitar\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Machine Gun\",\n\t\"bk:machine_gun_desc\": \"Automatic\",\n\t\"bk:grenade_launcher\": \"Grenade Launcher\",\n\t\"bk:grenade_launcher_desc\": \"Kaboom!\",\n\t\"bk:shotgun\": \"Shotgun\",\n\t\"bk:shotgun_desc\": \"Salt into the face!\",\n\t\"bk:missile_launcher\": \"Missile Launcher\",\n\t\"bk:missile_launcher_desc\": \"Target detected!\",\n\t\"bk:burst_gun\": \"Burst Gun\",\n\t\"bk:burst_gun_desc\": \"Speed of light\",\n\t\"bk:flak_cannon\": \"Flak Cannon\",\n\t\"bk:flak_cannon_desc\": \"It's party time!\",\n\t\"bk:disk_gun\": \"Disk Gun\",\n\t\"bk:disk_gun_desc\": \"Sharp matter\",\n\t\"bk:duck_gun\": \"Duck Gun\",\n\t\"bk:duck_gun_desc\": \"Quakers!\",\n\t\"bk:follower\": \"Follower\",\n\t\"bk:follower_desc\": \"Follow me!\",\n\t\"bk:portal_gun\": \"Portal Gun\",\n\t\"bk:portal_gun_desc\": \"Cake is a lie\",\n\t\"bk:snowflake\": \"Snowflake\",\n\t\"bk:snowflake_desc\": \"Freeze everyone!\",\n\t\"bk:restock\": \"Restock\",\n\t\"bk:restock_desc\": \"Infinite shop supply\",\n\t\"bk:charisma_ring_desc\": \"Royal Sales\",\n\t\"bk:charisma_ring\": \"Charisma Ring\",\n\t\"bk:battery\": \"Battery\",\n\t\"tomb_0\": \"Here lies [cl green]Gobbo[cl] the Great\",\n\t\"bk:homemade_dice\": \"Homemade Dice\",\n\t\"bk:homemade_dice_desc\": \"^^Reroll^^ items! (DIY)\",\n\t\"shopkeeper_0\": \"##I SAID DON'T DO IT!##\",\n\t\"shopkeeper_1\": \"Please, stop!\",\n\t\"shopkeeper_2\": \"Don't do that.\",\n\t\"shopkeeper_3\": \"[cl red]##PREPARE TO DIE!##\",\n\t\"shopkeeper_4\": \"[cl red]BURGLAR!\",\n\t\"shopkeeper_5\": \"[cl red]GET HIM!\",\n\t\"desert\": \"Desert Palace\",\n\t\"jungle\": \"Ancient Jungle\",\n\t\"ice\": \"Ice Ruins\",\n\t\"bk:iron_boots\": \"Iron Boots\",\n\t\"bk:iron_boots_desc\": \"Spikes hurt no more\",\n\t\"bk:mimic_totem\": \"Mimic Totem\",\n\t\"bk:mimic_totem_desc\": \"##NO MORE MIMICS##\",\n\t\"back_to_town\": \"Back to Town\",\n\t\"bk:glass_gun\": \"Glass Gun\",\n\t\"bk:glass_gun_desc\": \"##Fragile##\",\n\t\"bk:glass_shard\": \"Glass Shard\",\n\t\"bk:glass_shard_desc\": \"Just a piece of the whole\",\n\t\"bk:dagger\": \"Dagger\",\n\t\"bk:dagger_desc\": \"Nostalgia...\",\n\t\"bk:spear\": \"Spear\",\n\t\"bk:spear_desc\": \"Longer arms?\",\n\t\"shopkeeper_6\": \"Welcome :)\",\n\t\"shopkeeper_7\": \"Sup, wanna some [cl yellow]tea[cl]?\",\n\t\"shopkeeper_8\": \"How's going?\",\n\t\"back\": \"Back\",\n\t\"master_volume\": \"Master Volume\",\n\t\"music\": \"Music\",\n\t\"sfx\": \"Sound Effects\",\n\t\"graphics\": \"Graphics\",\n\t\"audio\": \"Audio\",\n\t\"ui_sfx\": \"Ui Sound Effects\",\n\t\"on\": \"On\",\n\t\"off\": \"Off\",\n\t\"fullscreen\": \"Fullscreen\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"FPS Counter\",\n\t\"flashes\": \"Flashes\",\n\t\"speedrun_timer\": \"Speedrun Timer\",\n\t\"screenshake\": \"Screen Shake\",\n\t\"reset_progress\": \"Reset Progress\",\n\t\"blood_n_gore\": \"Blood'n'Gore\",\n\t\"vegan_mode\": \"Vegan Mode\",\n\t\"reset_settings\": \"Reset Settings\",\n\t\"are_you_sure\": \"Are you sure?\",\n\t\"yes\": \"Yes\",\n\t\"reset_progress_dis\": \"This will delete ALL your progress!\",\n\t\"reset_settings_dis\": \"This will reset ALL settings to their default values!\",\n\t\"autosave\": \"Auto Save\",\n\t\"autopause\": \"Auto Pause\",\n\t\"input\": \"Input\",\n\t\"use\": \"Use\",\n\t\"active\": \"Active\",\n\t\"bomb\": \"Bomb\",\n\t\"interact\": \"Interact\",\n\t\"swap\": \"Swap Weapons\",\n\t\"roll\": \"Roll\",\n\t\"duck\": \"Duck\",\n\t\"pause\": \"Pause\",\n\t\"none\": \"None\",\n\t\"keyboard_controls\": \"Keyboard Controls\",\n\t\"gamepad_controls\": \"Gamepad Controls\",\n\t\"keyboard\": \"Keyboard\",\n\t\"gamepad\": \"Gamepad\",\n\t\"game\": \"Game\",\n\t\"select\": \"Select\",\n\t\"cursor\": \"Cursor\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"Die\",\n\t\"ach_bk:overshake\": \"Overshake\",\n\t\"ach_bk:overshake_desc\": \"1000% screen shake\",\n\t\"ach_bk:rip\": \"Most Popular Achievement\",\n\t\"bk:emerald\": \"Emerald\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Thanks!^^\",\n\t\"shopkeeper_11\": \"What a %%deal%%!\",\n\t\"shopkeeper_12\": \"Wanna [cl red]buy[cl] ^^smth^^?\",\n\t\"shopkeeper_13\": \"Only for [cl green]you[cl], only today!\",\n\t\"shopkeeper_14\": \"What an [cl yellow]offer[cl]!\",\n\t\"bk:magnifier\": \"Magnifier\",\n\t\"bk:magnifier_desc\": \"Bigger Projectiles\",\n\t\"bk:mushroom_hat\": \"Mushroom Hat\",\n\t\"bk:mushroom_hat_desc\": \"Tasty?\",\n\t\"bk:stone_hat\": \"Stone Hat\",\n\t\"bk:stone_hat_desc\": \"Heavy\",\n\t\"bk:knight_hat\": \"Knight Hat\",\n\t\"bk:knight_hat_desc\": \"Good old enemies...\",\n\t\"bk:cowboy_hat\": \"Cowboy Hat\",\n\t\"bk:cowboy_hat_desc\": \"Wild west!\",\n\t\"bk:soup_hat\": \"Soup Hat\",\n\t\"bk:soup_hat_desc\": \"^^Yummy^^\",\n\t\"bk:gold_hat\": \"Gold Hat\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Rich!\",\n\t\"bk:viking_hat\": \"Viking Hat\",\n\t\"bk:viking_hat_desc\": \"America!\",\n\t\"bk:dunce_hat\": \"Dunce Hat\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Top Hat\",\n\t\"bk:top_hat_desc\": \"Fashion!\",\n\t\"bk:ushanka\": \"Ushanka\",\n\t\"bk:ushanka_desc\": \"Where is my ##balalaika?##\",\n\t\"bk:valkyrie_hat\": \"Valkyrie Hat\",\n\t\"bk:valkyrie_hat_desc\": \"I believe ^^I can fly!^^\",\n\t\"bk:skull_hat\": \"Skull Hat\",\n\t\"bk:skull_hat_desc\": \"Money or life!\",\n\t\"bk:grandma_head\": \"Grandma Head\",\n\t\"bk:grandma_head_desc\": \"Tea?\",\n\t\"bk:diamond_helmet\": \"Diamond Helmet\",\n\t\"bk:diamond_helmet_desc\": \"Shut up and dig!\",\n\t\"bk:villager_head\": \"Villager Head\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fez\",\n\t\"bk:fez_desc\": \"Cubit\",\n\t\"bk:no_hat\": \"Remove Hat\",\n\t\"bk:no_hat_desc\": \"Not hat - no trouble!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"Attempt to call a null value\",\n\t\"accessorytrader_0\": \"##GET OUT OF HERE!## [dl]Or buy these ^^delicious^^ items at only ^^%%99 diamonds each%%^^!\",\n\t\"accessorytrader_1\": \"Hi\",\n\t\"accessorytrader_2\": \"Sup!\",\n\t\"weapontrader_0\": \"Come in!\",\n\t\"weapontrader_1\": \"Good day, sir!\",\n\t\"weapontrader_2\": \"Buy somethin', will ya?\",\n\t\"activetrader_0\": \"Best offers on the market!\",\n\t\"activetrader_1\": \"Pay for two and get two!\",\n\t\"activetrader_2\": \"Give me donuts, [dl]please!!\",\n\t\"hattrader_0\": \"Wanna be as cool as I am? [dl]Buy some hats!\",\n\t\"hattrader_1\": \"Wanna be as cool as I am? [dl]Me too, boy.\",\n\t\"hattrader_2\": \"^^Ha ha hats!^^\",\n\t\"granny_0\": \"Wanna some tea?\",\n\t\"granny_1\": \"Have a tea pause!\",\n\t\"granny_2\": \"Tea?\",\n\t\"bk:xmas_hat\": \"Santa Hat\",\n\t\"bk:xmas_hat_desc\": \"Merry Christmas!\",\n\t\"bk:pumpkin_hat\": \"Carved Pumpkin\",\n\t\"bk:pumpkin_hat_desc\": \"^^Spooky spooky skeleton^^\",\n\t\"bk:cage_key\": \"Cage Key\",\n\t\"bk:cage_key_desc\": \"Save ^^the dude^^!\",\n\t\"npc_0\": \"Help me! Find the key!\",\n\t\"npc_1\": \"Thanks for saving me!\",\n\t\"npc_2\": \"Faster! Unlock the door!\",\n\t\"npc_3\": \"Please! Help me!\",\n\t\"control_0\": \"Press [ic 0][ic 1] to place a bomb\",\n\t\"control_1\": \"Roll you can! Press [ic 0][ic 1] to obtain the power!\",\n\t\"control_2\": \"Press [ic 0][ic 1] to attack\",\n\t\"control_3\": \"Press [ic 0][ic 1] to interact\",\n\t\"control_4\": \"Quack? [ic 0][ic 1]!\",\n\t\"control_5\": \"Press [ic 0][ic 1] to swap weapons\",\n\t\"shopkeeper_15\": \"No discount for you!\",\n\t\"shopkeeper_16\": \"Grab more money and come back!\",\n\t\"shopkeeper_17\": \"Gotta pay first!\",\n\t\"bk:frog\": \"Tele Frog\",\n\t\"bk:frog_desc\": \"Fast travel?\",\n\t\"bk:sword_orbital\": \"Sword Orbital\",\n\t\"bk:sword_orbital_desc\": \"Justice\",\n\t\"robbed\": \"Robbed\",\n\t\"bk:gift_desc\": \"What's inside?\",\n\t\"bk:spike_ring\": \"Spike Ring\",\n\t\"bk:spike_ring_desc\": \"Your enemies must be ##punished##!\",\n\t\"bk:fire_ring\": \"Fire Ring\",\n\t\"bk:fire_ring_desc\": \"Let your enemies burn\",\n\t\"bk:ice_ring\": \"Ice Ring\",\n\t\"bk:ice_ring_desc\": \"Stop your enemies\",\n\t\"bk:duck_ring\": \"Duck Ring\",\n\t\"bk:duck_ring_desc\": \"Teleport after getting hit\",\n\t\"bk:dull_blade\": \"Dull Blade\",\n\t\"bk:dull_blade_desc\": \"Triggers hurt effect\",\n\t\"bk:sharp_blade\": \"Sharp Blade\",\n\t\"bk:sharp_blade_desc\": \"Self damage\",\n\t\"bk:obsidian_shield\": \"Obsidian Shield\",\n\t\"bk:obsidian_shield_desc\": \"Knockback = 0\",\n\t\"bk:bill\": \"Bill\",\n\t\"bk:bill_desc\": \"99 dollars\",\n\t\"control_6\": \"Use active item with [ic 0][ic 1]\",\n\t\"bk:clover\": \"4 Leaf Clover\",\n\t\"bk:clover_desc\": \"Lucky!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^Reroll %%your artifacts%%!^^\",\n\t\"brastin_0\": \"Find the [cl purple]cat[cl] painting!\",\n\t\"elon_1\": \"Here you go, have fun\",\n\t\"bk:maanex_head\": \"Maanex Head\",\n\t\"bk:maanex_head_desc\": \"Hmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Makes enemies think for a bit\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Map Greenprints\",\n\t\"bk:map_greenprints_desc\": \"Reveals the map\",\n\t\"bk:map\": \"Map\",\n\t\"bk:map_desc\": \"Reveals the map permanently\",\n\t\"milt_1\": \"I want gift\",\n\t\"mapuzzle_0\": \"Gravity.\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Copied!\",\n\t\"isaac_0\": \"Life has no meaning...\",\n\t\"isaac_1\": \"Whyyyyyyyy\",\n\t\"isaac_2\": \":sob:\",\n\t\"discord_0\": \"Say hi! discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"Roll, fool!\",\n\t\"tutorial\": \"Tutorial\",\n\t\"bk:crying_bomb\": \"Crying Bomb\",\n\t\"bk:crying_bomb_desc\": \"Bombs now cry!\",\n\t\"bk:matches\": \"Matches\",\n\t\"bk:matches_desc\": \"Shorter explosion timer\",\n\t\"bk:bomb_pack\": \"Bomb Pack\",\n\t\"bk:bomb_pack_desc\": \"We put bombs in your bombs!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 bombs\",\n\t\"bk:weird_mushroom_desc\": \"Doubles Everything\",\n\t\"bk:weird_mushroom\": \"Weird Mushroom\",\n\t\"bk:bomb_shower\": \"Bomb Shower\",\n\t\"bk:bomb_shower_desc\": \"Let it rain bombs\",\n\t\"bk:black_belt\": \"Black Belt\",\n\t\"bk:black_belt_desc\": \"Explode no more\",\n\t\"bk:ninjia_bomb\": \"Ninja Bomb\",\n\t\"bk:ninjia_bomb_desc\": \"Getting hurt spawns bombs\",\n\t\"start_new_run\": \"Your current run will be lost!\",\n\t\"bk:laser_pointer\": \"Laser Pointer\",\n\t\"bk:laser_pointer_desc\": \"Aim is clear!\",\n\t\"ach_bk:marauder\": \"Marauder\",\n\t\"ach_bk:marauder_desc\": \"Kill the shopkeeper\",\n\t\"ach_bk:treasure_hunter\": \"Treasure Hunter\",\n\t\"ach_bk:treasure_hunter_desc\": \"Find a secret room\",\n\t\"ach_bk:dodge_master\": \"Dodge Master\",\n\t\"ach_bk:dodge_master_desc\": \"Kill a boss without getting hit\",\n\t\"ach_bk:dodge_overlord\": \"Dodge Overlord\",\n\t\"ach_bk:dodge_overlord_desc\": \"Finish a floor without getting hit once\",\n\t\"ach_bk:quackers\": \"Quackers\",\n\t\"ach_bk:quackers_desc\": \"Overquack\",\n\t\"ach_bk:tea_party\": \"Tea Party\",\n\t\"ach_bk:tea_party_desc\": \"Join Granny in her tea party\",\n\t\"ach_bk:not_a_thief\": \"Not a thief\",\n\t\"ach_bk:not_a_thief_desc\": \"Finish a run without stealing any items\",\n\t\"ach_bk:npc_party2\": \"NPC Party\",\n\t\"ach_bk:npc_party2_desc\": \"Save all NPCs\",\n\t\"bk:gold_coin\": \"Gold Coin\",\n\t\"bk:iron_coin\": \"Iron Coin\",\n\t\"bk:copper_coin\": \"Copper Coin\",\n\t\"bk:platinum_coin\": \"Platinum Coin\",\n\t\"bk:voodoo_doll\": \"Voodoo Doll\",\n\t\"bk:voodoo_doll_desc\": \"Kills all enemies in the room\",\n\t\"hub\": \"Dodge Town\",\n\t\"castle\": \"Castle Ruins\",\n\t\"cave\": \"Emerald Caves\",\n\t\"charger_0\": \"NO ACTIVE ITEM DETECTED\",\n\t\"charger_1\": \"ACTIVE ITEM IS ALREADY CHARGED\",\n\t\"charger_2\": \"WHERE IS MY MONEY, YOU, MEAT BAG!\",\n\t\"charger_3\": \"##I SAID GIVE ME MY MONEY!##\",\n\t\"charger_4\": \"##I WILL TAKE OVER THE WORLD!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Sure, let's do this!\",\n\t\"maanex_6_1\": \"Nah.\",\n\t\"maanex_6\": \"Okay, give me [cl yellow][vr cost] coins[cl] and I will let you open one of these chests. Ok?\",\n\t\"maanex_5\": \"Hey man, wanna ^^try out^^ your luck?\",\n\t\"maanex_7\": \"That was fun!\",\n\t\"maanex_8\": \"Good luck!\",\n\t\"maanex_9\": \"Well, not this time :(\",\n\t\"maanex_10\": \"%%^^WOAH^^%%\",\n\t\"maanex_11\": \"But you don't have enough money!\",\n\t\"maanex_12\": \"##SON?!##\",\n\t\"bk:amurs_arrow\": \"Amur's Arrow\",\n\t\"bk:amurs_arrow_desc\": \"Charming Projectiles\",\n\t\"bk:amurs_bow\": \"Amur's Bow\",\n\t\"bk:amurs_bow_desc\": \"I see love\",\n\t\"bk:poison_flask\": \"Poison Flask\",\n\t\"bk:poison_flask_desc\": \"Poisoned Projectiles\",\n\t\"bk:snowball\": \"Snowball\",\n\t\"bk:snowball_desc\": \"Ice Cold Projectiles\",\n\t\"bk:peper_desc\": \"Hot Projectiles\",\n\t\"bk:peper\": \"Hot Pepper\",\n\t\"bk:sale_coupon\": \"Sale Coupon\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Pet in a Box\",\n\t\"bk:pet_box_desc\": \"Who's inside?\",\n\t\"bk:crate\": \"Orbital Crate\",\n\t\"bk:crate_desc\": \"Who's inside?\",\n\t\"bk:strawberry\": \"Strawberry\",\n\t\"bk:strawberry_desc\": \"Sweet Memories\",\n\t\"bk:wings\": \"Wings\",\n\t\"bk:wings_desc\": \"I belive I can fly\",\n\t\"bk:coin_pouch\": \"Coin Pouch\",\n\t\"bk:coin_pouch_desc\": \"Gives Coins\",\n\t\"bk:key_pouch\": \"Key Pouch\",\n\t\"bk:key_pouch_desc\": \"Gives Keys\",\n\t\"bk:bomb_pouch\": \"Bomb Pouch\",\n\t\"bk:bomb_pouch_desc\": \"Gives Bombs\",\n\t\"bk:pouch_pouch\": \"Pouch Pouch\",\n\t\"bk:pouch_pouch_desc\": \"Gives Pouches\",\n\t\"bk:lightsaber\": \"Svetsaber\",\n\t\"bk:lightsaber_desc\": \"You were the chosen one!\",\n\t\"bk:snail\": \"Snail\",\n\t\"bk:snail_desc\": \"Mass Slower\",\n\t\"bk:spike\": \"Spike\",\n\t\"bk:spike_desc\": \"Damage Up\",\n\t\"bk:mushroom\": \"Mushroom\",\n\t\"bk:mushroom_desc\": \"Speed up\",\n\t\"bk:candy\": \"Candy\",\n\t\"bk:candy_desc\": \"^^Sugar rush^^, fire rate up\",\n\t\"bk:glasses\": \"Glasses\",\n\t\"bk:glasses_desc\": \"Better Accuracy\",\n\t\"bk:ruler\": \"Ruler\",\n\t\"bk:ruler_desc\": \"Longer Range\",\n\t\"bk:stopwatch\": \"Stopwatch\",\n\t\"bk:stopwatch_desc\": \"Getting Hurt Controls the Time\",\n\t\"bk_0\": \"##DON'T YOU DARE TOUCH THAT!##\",\n\t\"bk_1\": \"##I SAID DON'T TOUCH THAT!##\",\n\t\"bk_2\": \"##YOU CAN'T DEFEAT [cl red]THE BURNING KNIGHT[cl], FOOL!##\",\n\t\"bk_3\": \"##PREPARE TO DIE!##\",\n\t\"bk_4\": \"^^WHAT A JOKE^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Hot sale![cl]\",\n\t\"dm_0\": \"@@Welcome@@\",\n\t\"ach_bk:deal\": \"Outstanding Move\",\n\t\"ach_bk:deal_desc\": \"Make a deal with the Dark Mage\",\n\t\"ach_bk:grannys_gift\": \"Granny's Gift\",\n\t\"ach_bk:grannys_gift_desc\": \"Take a gift from Granny\",\n\t\"ach_bk:shopper\": \"Shop till ya Drop\",\n\t\"ach_bk:shopper_desc\": \"Buy an item in any shop\",\n\t\"bk_5\": \"I WOUDLN'T EVEN BOTHER TALKING TO HIM\",\n\t\"bk_6\": \"##KILL HIM, [cl lime]EDWARD[cl]!##\",\n\t\"bk_7\": \"[cl lime]EDWARD[cl], ##NOOOOOO!!!!##\",\n\t\"bk_8\": \"OH COMON, STOP EXPLODING MY CASTLE!\",\n\t\"bk_9\": \"[cl pink]GRANNY[cl],[dl] CAN YOU JUST DIE, PLEASE##?!?##\",\n\t\"bk_10\": \"MY MASTER,[dl] I BROUGHT [cl green]GOBLIN[cl]\",\n\t\"dm_1\": \"Very well[dl], thank you[dl], [cl red]Limpor[cl]\",\n\t\"dm_2\": \"##Yes, yes, I need more [cl orange]power[cl]!##\",\n\t\"dm_3\": \"##MORE [cl orange]POWER[cl]!\",\n\t\"dm_4\": \"I can feel [cl orange]the power[cl] pulsing inside of me!\",\n\t\"granny_3\": \"You will be first, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Welcome, [cl green]Gobbo [vr id][cl]!\",\n\t\"granny_5\": \"Good luck on your sad quest!\",\n\t\"bk:meat_guy\": \"Meat Guy\",\n\t\"bk:meat_guy_desc\": \"Nuts!\",\n\t\"bk:bullet_stone\": \"Bullet Stone\",\n\t\"bk:bullet_stone_desc\": \"He attac, he protec, but most importantly, he cute as hecc\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"Doesn't help, but gives batteries\",\n\t\"vibration\": \"Vibration\",\n\t\"bk:sharp_arrow\": \"Sharp Arrow\",\n\t\"bk:sharp_arrow_desc\": \"Projectile Penetration\",\n\t\"machine_0\": \"Insert a [cl yellow]coin\",\n\t\"player_0\": \"Daddy?? ##What did they do with you?!?##\",\n\t\"bk:boomerang\": \"Boomerang\",\n\t\"bk:boomerang_desc\": \"Boomerang Projectiles\",\n\t\"bk:backpack\": \"Backpack\",\n\t\"bk:backpack_desc\": \"Ma Bear Friend\",\n\t\"place_an_item\": \"Place an Item\",\n\t\"bk:crystal\": \"Crystal\",\n\t\"bk:crystal_desc\": \"The Power of the Rainbow\",\n\t\"bk:prism\": \"Prism\",\n\t\"bk:prism_desc\": \"Projectiles -> Rainbow\",\n\t\"scourged\": \"Scourged\",\n\t\"bk:bomb\": \"Bomb\",\n\t\"bk:scourge_of_egg\": \"Scourge of Egg\",\n\t\"bk:scourge_of_egg_desc\": \"Shuffeled Item Names\",\n\t\"bk:scourge_of_unknown\": \"Scourge of Unknown\",\n\t\"bk:scourge_of_unknown_desc\": \"Hidden Items\",\n\t\"bk:scourge_of_blood\": \"Scourge of Blood\",\n\t\"bk:scourge_of_blood_desc\": \"Double Trouble (and Enemies)\",\n\t\"bk:scourge_of_risk\": \"Scourge of Risk\",\n\t\"bk:scourge_of_risk_desc\": \"Hidden Health\",\n\t\"bk:scourge_of_keys\": \"Scourge of Keys\",\n\t\"bk:scourge_of_keys_desc\": \"Hidden Consumables\",\n\t\"bk:scourge_of_lost\": \"Scourge of Lost\",\n\t\"bk:scourge_of_lost_desc\": \"Amnesia\",\n\t\"bk:scourge_of_scourged\": \"Scourge of Scourged\",\n\t\"bk:scourge_of_scourged_desc\": \"Scourge Everywhere\",\n\t\"bk:scourge_of_illness\": \"Scourge of Illness\",\n\t\"bk:scourge_of_illness_desc\": \"Healing is Nerfed\",\n\t\"bk:scourge_of_death\": \"Scourge of Death\",\n\t\"bk:scourge_of_death_desc\": \"Hardmode\",\n\t\"bk:ancient_revolver\": \"Ancient Revolver\",\n\t\"bk:ancient_revolver_desc\": \"Looks Cool\",\n\t\"bk:assault_rifle\": \"Assault Rifle\",\n\t\"bk:assault_rifle_desc\": \"Bursts\",\n\t\"fountain_0\": \"Bring 5 coins and you will be blessed\",\n\t\"fountain_1\": \"You've been partly cleansed\",\n\t\"fountain_2\": \"You've been fully cleansed\",\n\t\"fountain_3\": \"You are already cleansed\",\n\t\"buffed\": \"Buffed\",\n\t\"nerfed\": \"Nerfed\",\n\t\"restored\": \"Restored\",\n\t\"damaged\": \"Damaged\",\n\t\"cleansed\": \"Cleansed\",\n\t\"gifted\": \"Gifted\",\n\t\"lucky\": \"Lucky\",\n\t\"unlucky\": \"Unlucky\",\n\t\"max_hp\": \"Max HP\",\n\t\"touch\": \"Touch\",\n\t\"break\": \"Break\",\n\t\"no_coins\": \"No Coins\",\n\t\"old_man_6\": \"It's dangerous to go alone, take this!\",\n\t\"roger_0\": \"Kaboom!\",\n\t\"roger_1\": \"##*BOOM*##\",\n\t\"roger_2\": \"Boom boom shakataka!\",\n\t\"bk:shield\": \"Shield\",\n\t\"bk:gift\": \"Gift\",\n\t\"bk:shield_pouch\": \"Shield Pouch\",\n\t\"bk:shield_pouch_desc\": \"Gives Shields\",\n\t\"bk:shield_buddy\": \"Shield Buddy\",\n\t\"bk:shield_buddy_desc\": \"He protec\",\n\t\"bk:skeleton_key\": \"Skeleton Key\",\n\t\"bk:skeleton_key_desc\": \"99 keys\",\n\t\"bk:jar\": \"Health Jar\",\n\t\"bk:jar_desc\": \"Jar Jar Clinks\",\n\t\"bk:star\": \"Star\",\n\t\"bk:star_desc\": \"It protec\",\n\t\"bk:car_bomb\": \"Car Bomb\",\n\t\"bk:car_bomb_desc\": \"Bomb Delivery Service\",\n\t\"bk:grenade\": \"Grenade\",\n\t\"bk:grenade_desc\": \"Detonates Bomb on Touch\",\n\t\"trash_goblin_0\": \"Free me from my [cl purple]scourge[cl]! Please!\",\n\t\"trash_goblin_1\": \"I'm free![dl] Thank you so much!\",\n\t\"boxy_0\": \"Keysellent!\",\n\t\"boxy_1\": \"What a neat box!\",\n\t\"boxy_2\": \"You need wrapping paper?\",\n\t\"trash_goblin_2\": \"^^Smoke on the water [ic 0] [ic 1]^^\",\n\t\"bk:vampire_bat\": \"Vampire Bat\",\n\t\"bk:vampire_bat_desc\": \"Regen\",\n\t\"shields\": \"Shields\",\n\t\"bk:mustache\": \"Mustache\",\n\t\"bk:mustache_desc\": \"VIP\",\n\t\"bk:bloody_chest\": \"Bloody Chest\",\n\t\"bk:bloody_chest_desc\": \"Chests Heal\",\n\t\"bk:bloody_shield\": \"Bloody Shield\",\n\t\"bk:bloody_shield_desc\": \"Shields Forever\",\n\t\"bk:cutsaw\": \"Cutsaw\",\n\t\"bk:cutsaw_desc\": \"Enemies Will Pay\",\n\t\"vampire_0\": \"Yum!\",\n\t\"vampire_1\": \"Bloody awesome!\",\n\t\"vampire_2\": \"So sweet!\",\n\t\"vampire_3\": \"We know the rules, [cl red]^^right[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"What's your blood type?\",\n\t\"vampire_6\": \"So tasty\",\n\t\"duck_2\": \"Mind particapating in a survey?\",\n\t\"duck_7_0\": \"Yes\",\n\t\"duck_7_1\": \"No\",\n\t\"duck_7\": \"Will you get this chest?\",\n\t\"duck_4\": \"Good job, have this chest!\",\n\t\"duck_5\": \"I can't agree with you...\",\n\t\"duck_6_0\": \"The universe\",\n\t\"duck_6_1\": \"^^Quarks^^\",\n\t\"duck_6\": \"What I'm thinking about?\",\n\t\"duck_8_0\": \"[cl red]Red[cl]\",\n\t\"duck_8_1\": \"[cl blue]Blue[cl]\",\n\t\"duck_8\": \"What's my favorite ^^%%color%%^^?\",\n\t\"duck_9_0\": \"A cat\",\n\t\"duck_9_1\": \"You just said it\",\n\t\"duck_9\": \"Who said meow?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"What's better?\",\n\t\"duck_11_0\": \"What, you egg?\",\n\t\"duck_11_1\": \"\\\\[_He stabs him._]\",\n\t\"duck_11\": \"You are a saucy boy\",\n\t\"duck_12_0\": \"Chicken\",\n\t\"duck_12_1\": \"Egg\",\n\t\"duck_12\": \"Who came first?\",\n\t\"duck_13_0\": \"Nothing.\",\n\t\"duck_13_1\": \"A snack.\",\n\t\"duck_13_2\": \"An egg.\",\n\t\"duck_13_3\": \"Fried chicken.\",\n\t\"duck_13\": \"What did you eat today?\",\n\t\"duck_14\": \"Ouch.\",\n\t\"duck_17_0\": \"Sure lad\",\n\t\"duck_17_1\": \"##NAAAAAH##\",\n\t\"duck_17\": \"Ya like some pineapple on your pizza?\",\n\t\"duck_18_0\": \"White!\",\n\t\"duck_18_1\": \"[cl yellow]Yellow[cl]!\",\n\t\"duck_18\": \"What color is cheese?\",\n\t\"nurse_0\": \"You are looking really good, honey!\",\n\t\"nurse_1\": \"I could heal you a bit, but I need [cl yellow][vr price] coins[cl]\",\n\t\"nurse_2\": \"I hope that didn't hurt\",\n\t\"elon_4\": \"Here you go, have fun\",\n\t\"elon_2_0\": \"Letsego\",\n\t\"elon_2_1\": \"Hold up\",\n\t\"elon_2\": \"Wanna try out my magic?\",\n\t\"elon_3\": \"I can transform your weapon into another one\",\n\t\"elon_5\": \"Whatever\",\n\t\"elon_7\": \"Bro, where is your weapon???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*blush*\",\n\t\"gobetta_4\": \"Is it... you?\",\n\t\"gobetta_5\": \"It's been so long...\",\n\t\"ach_bk:desert\": \"Dry'n'Hot\",\n\t\"ach_bk:desert_desc\": \"Reach the Desert Palace\",\n\t\"ach_bk:jungle\": \"Buzzing Bees\",\n\t\"ach_bk:jungle_desc\": \"Reach the Ancient Jungle\",\n\t\"rooms_explored\": \"Rooms explored\",\n\t\"bk:shadow_cloak_desc\": \"No U\",\n\t\"bk:shadow_cloak\": \"Shadow Cloak\",\n\t\"bk:dynamite_stick\": \"Dynamite Stick\",\n\t\"bk:dynamite_stick_desc\": \"Do you want to explode?\",\n\t\"bk:chalice_of_blood\": \"Chalice of Blood\",\n\t\"bk:chalice_of_blood_desc\": \"Pain invokes rage, rage invokes damage\",\n\t\"bk:detonator\": \"Detonator\",\n\t\"bk:detonator_desc\": \"Detonates Explosives\",\n\t\"invincibility_time\": \"Invincibility Time\",\n\t\"accuracy\": \"Accuracy\",\n\t\"range\": \"Range\",\n\t\"fire_rate\": \"Fire Rate\",\n\t\"speed\": \"Speed\",\n\t\"bk:talisman_of_foresight\": \"Talisman of Foresight\",\n\t\"bk:talisman_of_foresight_desc\": \"Open your eyes and see the rooms nearby!\",\n\t\"bk:scourge_ring\": \"Scourge Ring\",\n\t\"bk:scourge_ring_desc\": \"Scourge No More\",\n\t\"snek_0\": \"Nice.\",\n\t\"snek_1\": \"Thhankss man\",\n\t\"snek_2\": \"Awesssome\",\n\t\"snek_3\": \"Ssssup\",\n\t\"snek_4\": \"Good day, ssssir\",\n\t\"snek_5\": \"Thou sssshal buy smth?\",\n\t\"snek_6\": \"I need to sssatisfy the customer...\",\n\t\"snek_7\": \"I will do, what I mussst!\",\n\t\"bk:snek\": \"Snek\",\n\t\"bk:snek_desc\": \"Snack?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Got a spare key?\",\n\t\"boxy_5\": \"Mind donating a few keys?\",\n\t\"bk:blank\": \"Blank\",\n\t\"bk:blank_desc\": \"_Blank Text_\",\n\t\"bk:blank_bombs\": \"Blank Bombs\",\n\t\"bk:blank_bombs_desc\": \"Bullet Shield\",\n\t\"bk:explosive_bullets\": \"Explosive Bullets\",\n\t\"bk:explosive_bullets_desc\": \"Explosive\",\n\t\"bk:random_bullets\": \"Random Bullets\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Cup\",\n\t\"bk:cup_desc\": \"Granny can't resist showing up\",\n\t\"bk:cartridge\": \"Cartridge\",\n\t\"bk:cartridge_desc\": \"Dark Mage can't resist showing up\",\n\t\"bk:marriage_ring\": \"Marriage Ring\",\n\t\"bk:marriage_ring_desc\": \"DM & Granny Forever!\",\n\t\"boxy_7\": \"I want keys\",\n\t\"boxy_8\": \"You don't seem to have enough keys :(\",\n\t\"boxy_9\": \"Now I finally have enough keys to ^^open up^^!\",\n\t\"roger_3\": \"Mind paying?\",\n\t\"roger_4\": \"No discounts today\",\n\t\"roger_5\": \"Bombs first\",\n\t\"vampire_7\": \"You are not healthy enough\",\n\t\"vampire_8\": \"I don't give discounts\",\n\t\"vampire_9\": \"Your health seems to be low\",\n\t\"ach_bk:scourged\": \"Scourged\",\n\t\"ach_bk:scourged_desc\": \"Pickup a Scourge Token\",\n\t\"ach_bk:scourged_weapon\": \"Scourged Weapon\",\n\t\"ach_bk:scourged_weapon_desc\": \"Pickup a Scourged Weapon\",\n\t\"rerolled\": \"Rerolled\",\n\t\"ach_bk:open_up\": \"Open Up\",\n\t\"ach_bk:open_up_desc\": \"Buy everything from Boxy\",\n\t\"ach_bk:snek\": \"Snek Pet\",\n\t\"ach_bk:snek_desc\": \"Get the Snek to be your pet\",\n\t\"bk:scourge_of_greed\": \"Scourge of Greed\",\n\t\"bk:scourge_of_greed_desc\": \"High Prices\",\n\t\"killed_by\": \"Killed by\",\n\t\"kills\": \"Kills\",\n\t\"time\": \"Time\",\n\t\"depth\": \"Depth\",\n\t\"bk:blank_bullets\": \"Blank Bullets\",\n\t\"bk:blank_bullets_desc\": \"Blank\",\n\t\"bk:lego\": \"Constructor\",\n\t\"bk:lego_desc\": \"It hurts so much stepping on these...\",\n\t\"bk:iron_armor\": \"Iron Armor\",\n\t\"bk:iron_armor_desc\": \"Gives Shields\",\n\t\"bk:round_shield\": \"Round Shield\",\n\t\"bk:round_shield_desc\": \"Prevents Contact Damage\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"The Legend Himself\",\n\t\"bk:inverted_arkhalis\": \"Inverted Arkhalis\",\n\t\"bk:inverted_arkhalis_desc\": \"Help will come when low on health\",\n\t\"bk:gun_sword\": \"Gun Sword\",\n\t\"bk:gun_sword_desc\": \"Prepare for trouble and make it double!\",\n\t\"ach_bk:scourge_king_desc\": \"Get 10 Scourge points\",\n\t\"ach_bk:scourge_king\": \"Scourge King\",\n\t\"ach_bk:sting_operation\": \"Sting Operation\",\n\t\"ach_bk:sting_operation_desc\": \"Defeat the Queen Bee\",\n\t\"ach_bk:mummified\": \"Mummified\",\n\t\"ach_bk:mummified_desc\": \"Defeat the Pharaoh\",\n\t\"ach_bk:democracy\": \"Democracy\",\n\t\"ach_bk:democracy_desc\": \"Defeat the Old King\",\n\t\"pharaoh_scream\": \"##PREPARE TO GET MUMMIFIED!##\",\n\t\"queen_bee_scream\": \"##FOR THE [cl yellow]HONEY LORD[cl]!##\",\n\t\"bk:half_heart\": \"Half Heart\",\n\t\"right\": \"Right\",\n\t\"down\": \"Down\",\n\t\"left\": \"Left\",\n\t\"up\": \"Up\",\n\t\"painting_cat\": \"Cat Painting\",\n\t\"bk:axe\": \"Axe\",\n\t\"bk:axe_desc\": \"He promised to return\",\n\t\"bk:guitar\": \"Guitar\",\n\t\"bk:guitar_desc\": \"It's detuned\",\n\t\"bk:glass_sword\": \"Glass Sword\",\n\t\"bk:glass_sword_desc\": \"The weapon of masters\",\n\t\"bk:chicken\": \"Chicken Wing\",\n\t\"bk:chicken_desc\": \"It's Hot\",\n\t\"bk:pickaxe\": \"Pickaxe\",\n\t\"bk:pickaxe_desc\": \"Dig, peasant!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"Half Mana\",\n\t\"bk:lava_wand\": \"Lava Wand\",\n\t\"bk:lava_wand_desc\": \"Hot Matter\",\n\t\"bk:web_wand\": \"Spider Wand\",\n\t\"bk:web_wand_desc\": \"World-wide web provider\",\n\t\"bk:slap_stick\": \"Slap Stick\",\n\t\"bk:slap_stick_desc\": \"Slap\",\n\t\"sensivity\": \"Sensivity\",\n\t\"no\": \"No\",\n\t\"scale\": \"Scale\",\n\t\"ach_bk:ice\": \"Ice Age\",\n\t\"ach_bk:ice_desc\": \"Reach the Frozen Ruins\",\n\t\"ach_bk:library\": \"Sacred Texts\",\n\t\"ach_bk:library_desc\": \"Reach the Secret Library\",\n\t\"bk:ice_skates\": \"Ice Skates\",\n\t\"bk:ice_skates_desc\": \"Ice Immunity\",\n\t\"bk:campfire_in_bottle\": \"Campfire in a Bottle\",\n\t\"bk:campfire_in_bottle_desc\": \"Frost Immunity\",\n\t\"library\": \"Secret Library\",\n\t\"ach_bk:cat_without_a_hat\": \"Cat without a hat\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Find the cat painting\",\n\t\"ach_bk:rich\": \"Toilet Paper\",\n\t\"ach_bk:rich_desc\": \"Obtain 99 coins\",\n\t\"ach_bk:rescue_operation\": \"Rescue Operation\",\n\t\"ach_bk:rescue_operation_desc\": \"Save a NPC\",\n\t\"ach_bk:tutorial\": \"Guru\",\n\t\"ach_bk:tutorial_desc\": \"Finish the tutorial\",\n\t\"ach_bk:fancy_hat\": \"Fancy Hat\",\n\t\"ach_bk:fancy_hat_desc\": \"Buy a hat\",\n\t\"ach_bk:unlock\": \"Unlocker\",\n\t\"ach_bk:unlock_desc\": \"Unlock an item\",\n\t\"floor_brightness\": \"Floor Brightness\",\n\t\"ach_bk:shielded\": \"Shields Up\",\n\t\"ach_bk:shielded_desc\": \"Obtain a shield heart\",\n\t\"run_type\": \"Run type\",\n\t\"run_regular\": \"Regular\",\n\t\"run_challenge\": \"Challenge\",\n\t\"damage_taken\": \"Damage taken\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Distance traveled\",\n\t\"seed\": \"Seed\",\n\t\"score\": \"Score\",\n\t\"new_high_score\": \"New high!\",\n\t\"items_collected\": \"Items collected\",\n\t\"boss_rush\": \"Boss Rush\",\n\t\"run_bossrush\": \"Boss rush\",\n\t\"bk:blindfold_desc\": \"RIP my weapons\",\n\t\"bk:blindfold\": \"Blindfold\",\n\t\"daily_run\": \"Daily Run\",\n\t\"builder_0_0\": \"Yeah\",\n\t\"builder_0_1\": \"I need my money for myself\",\n\t\"builder_0\": \"I'm planning on building a shortcut here, but I need [vr need] [ic 0] more coins. Can you help me?\",\n\t\"builder_1\": \"But you have no money! :(\",\n\t\"builder_2\": \"Thanks for your investment!\",\n\t\"builder_3\": \"I finally have enough money to finish the project! Thanks so much!\",\n\t\"builder_4\": \"Okay, sorry!\",\n\t\"shortcut_is_broken\": \"Shortcut is broken\",\n\t\"ach_bk:boss_rush\": \"Boss Challenger\",\n\t\"ach_bk:boss_rush_desc\": \"Defeat all bosses in the Boss Rush\",\n\t\"ach_bk:daily\": \"Daily Glory\",\n\t\"ach_bk:daily_desc\": \"Complete the Daily Challenge\",\n\t\"ach_bk:desert_shortcut\": \"Desert Palace Shortcut\",\n\t\"ach_bk:desert_shortcut_desc\": \"Fix the shortcut to the Desert Palace\",\n\t\"ach_bk:jungle_shortcut\": \"Ancient Jungle Shortcut\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Fix the shortcut to the Ancient Jungle\",\n\t\"ach_bk:ice_shortcut\": \"Frozen Ruins Shortcut\",\n\t\"ach_bk:ice_shortcut_desc\": \"Fix the shortcut to the Frozen Ruins\",\n\t\"ach_bk:library_shortcut\": \"Secret Library Shortcut\",\n\t\"ach_bk:library_shortcut_desc\": \"Fix the shortcut to the Secret Library\",\n\t\"ach_bk:fashion_matters2\": \"Fashion Matters\",\n\t\"ach_bk:fashion_matters2_desc\": \"Buy every single hat\",\n\t\"ach_bk:10_challenges\": \"Challenger\",\n\t\"ach_bk:10_challenges_desc\": \"Complete 10 challenges\",\n\t\"ach_bk:20_challenges\": \"Challenger 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Complete 20 challenges\",\n\t\"ach_bk:30_challenges\": \"Challenger 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Complete 30 challenges\",\n\t\"ach_bk:bk_no_more\": \"Burning no more\",\n\t\"ach_bk:bk_no_more_desc\": \"Defeat the Burning Knight himself\",\n\t\"ach_bk:dm_no_more\": \"DM no more\",\n\t\"ach_bk:dm_no_more_desc\": \"Defeat the Dark Mage\",\n\t\"ach_bk:egor_no_more\": \"Egor no more\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Ah, here we go again\",\n\t\"ach_bk:loop_desc\": \"Enter the loop\",\n\t\"coins_collected\": \"Coins collected\",\n\t\"bk:cup_head\": \"Cup Head\",\n\t\"bk:cup_head_desc\": \"Have a cup of tea\",\n\t\"bk:mustache_hat\": \"Mustache\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Propeller Hat\",\n\t\"bk:propeller_hat_desc\": \"It spins\",\n\t\"bk:sunglasses\": \"Sunglasses\",\n\t\"bk:sunglasses_desc\": \"Work with moon too!\",\n\t\"bk:cap\": \"Cap\",\n\t\"bk:cap_desc\": \"Cool @-@\",\n\t\"bk:eyes\": \"Eyes\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Eye\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Hair\",\n\t\"bk:hair_desc\": \"Fancy\",\n\t\"won\": \"Won\",\n\t\"won_message\": \"You Won!\",\n\t\"garderobe_sign\": \"Dressing Room\",\n\t\"darkmarket_tip\": \"~~[cl purple]Scourge[cl] or [cl yellow]30 coins[cl]@@\",\n\t\"mike_0\": \"Gotta pay me [cl green]3 emeralds\",\n\t\"mike_1\": \"Try boss rush just for [cl green]3 emeralds[cl]!\",\n\t\"bk:weird_potion\": \"Weird Potion\",\n\t\"bk:weird_potion_desc\": \"Weird Projectiles\",\n\t\"bk:megaphone\": \"Megaphone\",\n\t\"bk:megaphone_desc\": \"Expanding Projectiles\",\n\t\"scourge\": \"Scourge\",\n\t\"scourge_stats\": \"Scourge\",\n\t\"run_daily\": \"Daily\",\n\t\"completed_on\": \"Completed on\",\n\t\"complete\": \"complete\",\n\t\"next_daily_in\": \"[cl gray]Next starts in[cl]\",\n\t\"hours\": \"hours\",\n\t\"minutes\": \"minutes\",\n\t\"seconds\": \"seconds\",\n\t\"ach_bk:star\": \"The Star of the Show\",\n\t\"ach_bk:star_desc\": \"Obtain 3 orbitals\",\n\t\"ach_bk:family\": \"Happy Lil Family\",\n\t\"ach_bk:family_desc\": \"Obtain 3 pets\",\n\t\"ach_bk:return_to_sender\": \"No U\",\n\t\"ach_bk:return_to_sender_desc\": \"Kill an enemy with its own projectile\",\n\t\"ach_bk:van_no_gogh\": \"Van No Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Destroy 100 paintings\",\n\t\"ach_bk:dark_market\": \"Crime Hideout\",\n\t\"ach_bk:dark_market_desc\": \"Descend into the Dark Market\",\n\t\"ach_bk:spikes\": \"Sharp Matter\",\n\t\"ach_bk:spikes_desc\": \"Active 100 spikes in a single run\",\n\t\"ach_bk:white_flag\": \"Weapon Free\",\n\t\"ach_bk:white_flag_desc\": \"Defeat a room without using a weapon once\",\n\t\"quack\": \"[cl yellow]Quack![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfect\",\n\t\"bk_11\": \"I FORGIVE YOU THIS TIME... BUT ##DO NOT## DO IT AGAIN!\",\n\t\"leaderboard\": \"Leaderboard\",\n\t\"display\": \"Display\",\n\t\"around_you\": \"Around You\",\n\t\"friends\": \"Friends\",\n\t\"global\": \"Global\",\n\t\"loading\": \"Loading\",\n\t\"generating\": \"Generating\",\n\t\"cursor_radius\": \"Cursor Radius\",\n\t\"no_scores_yet\": \"No scores yet\",\n\t\"no_score_yet\": \"No score yet\",\n\t\"run\": \"Run\",\n\t\"top\": \"Top\",\n\t\"quick_restart\": \"Quack Restart\",\n\t\"painting_dungeon\": \"Dungeon\",\n\t\"painting_goose\": \"Mini Goose\",\n\t\"painting_chess\": \"Flying Elephant\",\n\t\"painting_peach\": \"A peach tree\",\n\t\"bk:no_lamp\": \"No Lamp\",\n\t\"bk:explosive_lamp\": \"Explosive Lamp\",\n\t\"bk:explosive_lamp_desc\": \"When boom means more\",\n\t\"bk:shielded_lamp\": \"Shielded Lamp\",\n\t\"bk:shielded_lamp_desc\": \"Shields Up!\",\n\t\"lamp\": \"Lamp\",\n\t\"bk:brain\": \"Mega Brain\",\n\t\"bk:brain_desc\": \"What if we use 0% of our brain\",\n\t\"bk:heart_amulet\": \"Heart Amulet\",\n\t\"bk:heart_amulet_desc\": \"+1 to Heart Size\",\n\t\"bk:star_amulet_desc\": \"Mana Up\",\n\t\"bk:star_amulet\": \"Star Amulet\",\n\t\"bk:coin_amulet\": \"Coin Amulet\",\n\t\"bk:coin_amulet_desc\": \"Coins Are Worth More\",\n\t\"bk:key_amulet\": \"Key Amulet\",\n\t\"bk:key_amulet_desc\": \"Keys Are Worth More\",\n\t\"bk:bomb_amulet\": \"Bomb Amulet\",\n\t\"bk:bomb_amulet_desc\": \"Bombs Are Worth More\",\n\t\"bk:eye_amulet\": \"Eye Amulet\",\n\t\"bk:eye_amulet_desc\": \"It Hurts To Be Inaccurate\",\n\t\"bk:eye_patch\": \"Eye Patch\",\n\t\"bk:eye_patch_desc\": \"Are You Ready, Kids?\",\n\t\"bk:toilet_paper\": \"Toilet Paper\",\n\t\"bk:toilet_paper_desc\": \"Its Always Ending\",\n\t\"bk:decoy\": \"Decoy\",\n\t\"bk:decoy_desc\": \"It Explodes\",\n\t\"bk:wallet\": \"Wallet Buddy\",\n\t\"bk:wallet_desc\": \"Stores Your Coins\",\n\t\"bk:skele_buddy\": \"Skele Buddy\",\n\t\"bk:skele_buddy_desc\": \"Spooky\",\n\t\"bk:mega_bomb\": \"Mega Bomb\",\n\t\"bk:mega_bomb_desc\": \"Bomb Size: Mega\",\n\t\"bk:condensed_milk\": \"Condensed Milk\",\n\t\"bk:condensed_milk_desc\": \"Fast Pixels - Slow Enemies\",\n\t\"bk:marshmallow\": \"Marshmallow X_X\",\n\t\"bk:marshmallow_desc\": \"Sticky\",\n\t\"bk:orbital_multiplier\": \"Orbital Multiplier\",\n\t\"bk:orbital_multiplier_desc\": \"More Orbitals!\",\n\t\"bk:pet_multiplier\": \"Pet Multiplier\",\n\t\"bk:pet_multiplier_desc\": \"More Pets!\",\n\t\"bk:ghost_bullets\": \"Ghost Bullets\",\n\t\"bk:ghost_bullets_desc\": \"Walls Wont Stop\",\n\t\"bk:weight\": \"Heavy Weight\",\n\t\"bk:weight_desc\": \"Gravity Booster\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"Take it or leave it\",\n\t\"bk:ethernal_d6\": \"Ethernal D6\",\n\t\"bk:ethernal_d6_desc\": \"Rerolls And\\/Or Destroys\",\n\t\"bk:billiard\": \"Billiard\",\n\t\"bk:billiard_desc\": \"Bullets Bounce\",\n\t\"bk:enraged_bullets\": \"Enraged Bullets\",\n\t\"bk:enraged_bullets_desc\": \"Bullets Break Bullets\",\n\t\"bk:rewind_button\": \"Rewind Button\",\n\t\"bk:rewind_button_desc\": \"Hold Up\",\n\t\"bk:piggy_bank\": \"Piggy Bank\",\n\t\"bk:piggy_bank_desc\": \"My Life Savings\",\n\t\"coins\": \"Coins\",\n\t\"bk:death_star\": \"Death Star\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Soldering Iron\",\n\t\"bk:soldering_iron_desc\": \"It's Hot\",\n\t\"bk:can\": \"Can\",\n\t\"bk:can_desc\": \"Double Projectiles\",\n\t\"bk:swimming_mask\": \"Swimming Mask\",\n\t\"bk:swimming_mask_desc\": \"It's a Secret Weapon\",\n\t\"bk:bullet_chair\": \"Bullet Chair\",\n\t\"bk:bullet_chair_desc\": \"4 Legs 4 Guns\",\n\t\"bk:cell\": \"Cell\",\n\t\"bk:cell_desc\": \"Projectiles Multiply\",\n\t\"bk:brick\": \"iBrick\",\n\t\"bk:brick_desc\": \"Bigger Levels\",\n\t\"bk:ring_of_pain\": \"Ring Of Pain\",\n\t\"bk:ring_of_pain_desc\": \"Getting Hurt Hurts Everyone\",\n\t\"bk:schrodingers_cat\": \"Schrödingers Cat\",\n\t\"bk:schrodingers_cat_desc\": \"To Be Or Not To Be (50% chance)\",\n\t\"bk:smoke_bomb\": \"Smoke Bomb\",\n\t\"bk:smoke_bomb_desc\": \"Ninjia-inspired Escape\",\n\t\"bk:chest_ring\": \"Chest Ring\",\n\t\"bk:chest_ring_desc\": \"More Chests!\",\n\t\"bk:empty_shell\": \"Empty Shell\",\n\t\"bk:empty_shell_desc\": \"A Chance To Destroy Enemy Bullets\",\n\t\"bk:parachute\": \"Parachute\",\n\t\"bk:parachute_desc\": \"Pit Immunity\",\n\t\"bk:spiked_cookie\": \"Spiked Cookie\",\n\t\"bk:spiked_cookie_desc\": \"Spiky Boi\",\n\t\"bk:shooty\": \"Shooty\",\n\t\"bk:shooty_desc\": \"He Be Shooting\",\n\t\"bk:rabbit_bullets\": \"Rabbit Bullets\",\n\t\"bk:rabbit_bullets_desc\": \"They Multiply\",\n\t\"bk:pandoras_box\": \"Pandora's Box\",\n\t\"bk:pandoras_box_desc\": \"You had to fight evel!\",\n\t\"bk:bubbles\": \"Bubbles\",\n\t\"bk:bubbles_desc\": \"Bubble Frend\",\n\t\"bk:match\": \"Match\",\n\t\"bk:match_desc\": \"Fire For Everyone\",\n\t\"bk:hammer\": \"Hammer\",\n\t\"bk:hammer_desc\": \"Armor Breaker\",\n\t\"bk:helmet\": \"Iron Helmet\",\n\t\"bk:helmet_desc\": \"A Chance To Ignore Damage\",\n\t\"bk:beer\": \"Beer\",\n\t\"bk:beer_desc\": \"Damage Enrages\",\n\t\"bk:the_eye\": \"The Eye\",\n\t\"bk:the_eye_desc\": \"He Be Watching\",\n\t\"bk:mimics_tooth\": \"Mimic's Tooth\",\n\t\"bk:mimics_tooth_desc\": \"Attracks Mimics\",\n\t\"ach_bk:mimic\": \"Jump Scare\",\n\t\"ach_bk:mimic_desc\": \"Find A Mimic\",\n\t\"bk:paper_airplane\": \"Paper Airplane\",\n\t\"bk:paper_airplane_desc\": \"Homing Projectiles\",\n\t\"ach_bk:ice_boss\": \"Let It Go\",\n\t\"ach_bk:ice_boss_desc\": \"Kill The Ice Queen\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Ahem\",\n\t\"painting_agency\": \"Welcome to the agency\",\n\t\"painting_nat\": \"Nat\",\n\t\"painting_totemori\": \"Totemori\",\n\t\"painting_horatio\": \"Horatio\",\n\t\"painting_coce\": \"Coce\",\n\t\"painting_totemori_redux\": \"Totemori Redux\",\n\t\"painting_raj\": \"Raj\",\n\t\"painting_plank\": \"Plank\",\n\t\"painting_qrilin\": \"Qrilin\",\n\t\"painting_kobra_throne\": \"Kobra Can\",\n\t\"painting_mori\": \"Mori\",\n\t\"painting_balbo\": \"Balbo\",\n\t\"painting_olpi\": \"Olpi\",\n\t\"painting_one_knight_stand\": \"One Knight Stand\",\n\t\"painting_ne_furdje_le\": \"Ne furdje le!\",\n\t\"painting_sushi_sushi\": \"Sushi! Sushi!\",\n\t\"painting_hoop_gang\": \"Hoop Gang\",\n\t\"painting_riveting_view\": \"Riveting View\",\n\t\"painting_gang\": \"Goop Gang\",\n\t\"painting_zweihandler\": \"Zweihandler\",\n\t\"painting_cauliflower\": \"Cauliflower\",\n\t\"painting_raise_volcano\": \"Raise Volcano\",\n\t\"painting_mahula\": \"Mahula\",\n\t\"painting_tofulama\": \"Tofulama\",\n\t\"painting_esty\": \"Misfit\",\n\t\"language\": \"Language\",\n\t\"bk:pouch\": \"Pouch\",\n\t\"bk:alien_glasses\": \"Alien Glasses\",\n\t\"bk:alien_glasses_desc\": \"I see more\",\n\t\"inventory\": \"Inventory\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Accurate Lamp\",\n\t\"bk:fragile_lamp\": \"Fragile Lamp\",\n\t\"bk:fragile_lamp_desc\": \"1 hit K.O.\",\n\t\"painting_guitar\": \"More volume!\",\n\t\"ach_bk:maanex\": \"Et tu, Brute?\",\n\t\"ach_bk:maanex_desc\": \"Kill Maanex while wearing his head\",\n\t\"dad_0\": \"Hey son![dl] I need to go and find [cl red]the Lamp[cl]. I leave you to rule.\",\n\t\"dad_1\": \"If I don't return, don't search for me. Bye!\",\n\t\"son_0\": \"##NOOOOOOO##\",\n\t\"gobbo_0\": \"Son, [cl green]my father[cl] left me 20 years ago. I need to find him.\",\n\t\"gobbo_1\": \"I leave you as the ruler. Bye!\",\n\t\"dm_5\": \"A new and ^^better^^ [cl red]puppet[cl]![dl] ##MUHAHAHA##\",\n\t\"dm_6\": \"Do you hear me, [cl red]Limpor?\",\n\t\"heinur_0\": \"##NO[dl], NOT AGAIN!##\",\n\t\"nbk_0\": \"##YES, MY MASTER##\",\n\t\"bk_12\": \"##I'M OUT OF KINGS, SO FIGHT ME, FOOL!##\",\n\t\"bk:headshot_gun\": \"Bent Gun\",\n\t\"bk:headshot_gun_desc\": \"Headshot\",\n\t\"bk:laser_cannon\": \"Laser Cannon\",\n\t\"bk:laser_cannon_desc\": \"Haha, laser go pew pew\",\n\t\"credits\": \"Credits\",\n\t\"head_0\": \"Fool\",\n\t\"tech\": \"Techno\",\n\t\"ach_bk:collector\": \"Collector\",\n\t\"ach_bk:collector_desc\": \"Unlock all items\",\n\t\"bk:treasure_key\": \"Red Key\",\n\t\"bk:treasure_key_desc\": \"Opens loopholes\",\n\t\"bk:pass\": \"Pass\",\n\t\"bk:pass_desc\": \"Identify yourself!\",\n\t\"bk:bucket\": \"Bucket\",\n\t\"bk:bucket_desc\": \"Useless without the contents\",\n\t\"bk:water_bucket\": \"Water Bucket\",\n\t\"bk:water_bucket_desc\": \"Calms [cl red]the Fire[cl]\",\n\t\"bk:snow_bucket\": \"Snow Bucket\",\n\t\"bk:snow_bucket_desc\": \"Prehaps, it could melt\",\n\t\"m2_0\": \"I'm never going to financially recover from this\",\n\t\"m2_1\": \"Good job!\",\n\t\"m2_2\": \"Hey man, wanna ^^try out^^ your %%skill%%?\",\n\t\"m2_3\": \"Use ^^%%the Computer%%^^ to control the claw!\",\n\t\"maanex2_0_0\": \"Take my money!\",\n\t\"maanex2_0_1\": \"Not this time, tnx.\",\n\t\"maanex2_0\": \"Okay, gimme [cl yellow][vr cost] coins[cl] and you can give the claw a try!\",\n\t\"dm_7\": \"Let's play a game\",\n\t\"bkw_0\": \"ANOTHER [cl red]INTRUDER[cl]!\",\n\t\"bkw_1\": \"##GET OUT OF HERE##[dl], OR I WILL FORCE YOU!\",\n\t\"bkw_2\": \"I'm looking for [cl green]my father\",\n\t\"bkw_3\": \"I GAVE YOU _A WARNING_\",\n\t\"spanish_inquisition\": \"[cl red]Spanish Inquisition\",\n\t\"lp_0\": \"Good job, [cl purple]Ritta[cl][dl], restarting [cl green]the simulation[cl][dl].[dl].[dl].\",\n\t\"bk:broken_bucket\": \"Broken Bucket\",\n\t\"bk:broken_bucket_desc\": \"Protecc\",\n\t\"bk:ankh\": \"Ankh\",\n\t\"bk:ankh_desc\": \"Eternal Life\",\n\t\"bk:broken_ankh\": \"Broken Ankh\",\n\t\"bk:broken_ankh_desc\": \"Eternal Life?\",\n\t\"bk:what\": \"What\",\n\t\"bk:what_desc\": \"Seriusly, WHAT?\",\n\t\"bk:gold_minigun\": \"Golden Minigun\",\n\t\"bk:gold_minigun_desc\": \"Haha budget go brrr\",\n\t\"bk:gold_dagger\": \"Golden Dagger\",\n\t\"bk:gold_dagger_desc\": \"Old but gold\",\n\t\"bk:gold_revolver\": \"Golden Revolver\",\n\t\"bk:gold_revolver_desc\": \"Cover me in gold\",\n\t\"bk:gold_axe\": \"Golden Axe\",\n\t\"bk:gold_axe_desc\": \"Just an axe\",\n\t\"painting_code\": \"Code\",\n\t\"bk:katana\": \"Katana\",\n\t\"bk:katana_desc\": \"Who's [cl orange]the owner[cl]?\",\n\t\"bk:smart_gun\": \"Smart Gun\",\n\t\"bk:smart_gun_desc\": \"He knows\",\n\t\"bk:pop_gun\": \"Pop Gun\",\n\t\"bk:pop_gun_desc\": \"Really popular\",\n\t\"bk:the_button\": \"The Button\",\n\t\"bk:the_button_desc\": \"8-dir attack\",\n\t\"bk:gold_sword\": \"Golden Sword\",\n\t\"bk:gold_sword_desc\": \"When you don't have anything to spend money on\",\n\t\"bk:donut\": \"Donut\",\n\t\"bk:donut_desc\": \"Do not hesitate\",\n\t\"bk:sudoku\": \"Sudoku\",\n\t\"bk:sudoku_desc\": \"Half of the room just gone, reduced to atoms\",\n\t\"bk:gps_ring\": \"GPS Ring\",\n\t\"bk:gps_ring_desc\": \"A chance to reveal the map\",\n\t\"bk:shield_potion\": \"Shield Potion\",\n\t\"bk:shield_potion_desc\": \"Shield juice big sip\",\n\t\"bk:trash_generator\": \"Trash Generator\",\n\t\"bk:trash_generator_desc\": \"Yes.\",\n\t\"bk:crabs_claw\": \"Crab's Claw\",\n\t\"bk:crabs_claw_desc\": \"Breaks any armor\",\n\t\"eg_3\": \"Good time of day, sir\",\n\t\"eg_0_0\": \"Take ^^[cl lime]the emeralds[cl]^^\",\n\t\"eg_0_1\": \"Leave them\",\n\t\"eg_0\": \"Take [cl lime]my emeralds[cl], I beg you!\",\n\t\"eg_1\": \"Ima head out\",\n\t\"bk:reverse_card\": \"Reverse Card\",\n\t\"bk:reverse_card_desc\": \"Rolling through projectiles reflects them\",\n\t\"bk:magnet\": \"Magnet\",\n\t\"bk:magnet_desc\": \"Attraction & Affection\",\n\t\"bk:glowing_mushroom\": \"Glowing Mushroom\",\n\t\"bk:glowing_mushroom_desc\": \"He be vibing\",\n\t\"bk:tinfoil_hat\": \"Tinfoil Hat\",\n\t\"bk:tinfoil_hat_desc\": \"Feels safe\",\n\t\"bk:rear_window\": \"Rear Window\",\n\t\"bk:rear_window_desc\": \"Watches your back\",\n\t\"bk:refractor\": \"Refractor\",\n\t\"bk:refractor_desc\": \"A chance to attack in all directions\",\n\t\"bk:fork\": \"Fork\",\n\t\"bk:fork_desc\": \"It hurts\",\n\t\"bk:rock\": \"Rock\",\n\t\"bk:rock_desc\": \"Damage at a cost\",\n\t\"bk:coffee_grinder\": \"Coffee Grinder\",\n\t\"bk:coffee_grinder_desc\": \"Small & fast projectiles\",\n\t\"integrations\": \"Integrations\",\n\t\"twitch\": \"Twitch\",\n\t\"twitch_mode\": \"Twitch Mode\",\n\t\"streamer_username\": \"Streamer Username\",\n\t\"bk:shawarma\": \"Shawarma\",\n\t\"bk:shawarma_desc\": \"Sometimes projectiles are bigger\",\n\t\"bk:cats_ear\": \"Cat's Ear\",\n\t\"bk:cats_ear_desc\": \"Sick dodge\",\n\t\"luck\": \"Luck\",\n\t\"bk:gamepad\": \"Gamepad\",\n\t\"bk:gamepad_desc\": \"Stable FPS\",\n\t\"bk:hotdog\": \"Hotdog\",\n\t\"bk:bomb_shell\": \"Bomb Shell\",\n\t\"bk:bomb_shell_desc\": \"Weird Health\",\n\t\"painting_no_idea\": \"No Idea\",\n\t\"painting_tinkerer\": \"Tinkerer\",\n\t\"painting_in_loving_memory_of_ali\": \"In loving memory of Ali\",\n\t\"painting_happy_accident\": \"Happy Accident\",\n\t\"painting_observing_cheese\": \"Observing Cheese\",\n\t\"painting_chicken_enemy_unknown\": \"Chicken Enemy Unknown\",\n\t\"painting_know_stuff\": \"Know Stuff\",\n\t\"painting_whoops\": \"Whoops\",\n\t\"painting_too_lake\": \"Too Lake\",\n\t\"painting_step_through\": \"Threshold\",\n\t\"painting_thats_a_moon\": \"That's a moon\",\n\t\"painting_totem\": \"Magic Circle\",\n\t\"painting_too_late\": \"Too Late\",\n\t\"painting_whipped_cream\": \"Whipped Cream\",\n\t\"painting_beet_boys\": \"Beet Bois\",\n\t\"painting_moonshine\": \"Moonshine\",\n\t\"painting_void\": \"The Void\",\n\t\"painting_peasants\": \"Peasants\",\n\t\"bk:hotdog_desc\": \"Luck & Health Up\",\n\t\"logged_in_as\": \"Logged in as\",\n\t\"not_logged_in\": \"Not logged in\",\n\t\"failed_to_login\": \"Failed to log in as\",\n\t\"logging_in\": \"Logging in[dl].[dl].[dl].\",\n\t\"twitch_0\": \"Pog!\",\n\t\"twitch_1_0\": \"Yes\",\n\t\"twitch_1_1\": \"No\",\n\t\"twitch_1\": \"Do you want to play with Twitch mode on?\",\n\t\"twitch_2\": \"Tell me your Twitch username!\",\n\t\"twitch_3\": \"Welcome to the chat, [cl purple]@[vr username][cl]!\",\n\t\"twitch_4\": \"Mkay.\",\n\t\"twitch_5_0\": \"Yes\",\n\t\"twitch_5_1\": \"No\",\n\t\"twitch_5\": \"Your Twitch username is [cl purple]@[vr username][cl]. Wanna change it?\",\n\t\"run_twitch\": \"Twitch\",\n\t\"happening_bk:hurt\": \"Hurt\",\n\t\"happening_bk:big_hurt\": \"Big Hurt\",\n\t\"happening_bk:omega_hurt\": \"Omega Hurt\",\n\t\"happening_bk:confused\": \"Confusion\",\n\t\"happening_bk:snail\": \"Snail\",\n\t\"happening_bk:broken\": \"Broken Armor\",\n\t\"happening_bk:darkness\": \"Lights Out\",\n\t\"happening_bk:scourge_token\": \"Bad Token\",\n\t\"happening_bk:risk\": \"Hidden Health\",\n\t\"happening_bk:double_trouble\": \"Double Trouble\",\n\t\"happening_bk:rage\": \"Rage\",\n\t\"happening_bk:regular_tp\": \"Teleport\",\n\t\"happening_bk:reset\": \"Level Reset\",\n\t\"happening_bk:sudoku\": \"Sudoku\",\n\t\"happening_bk:items_hurt\": \"Items Hurt\",\n\t\"happening_bk:scourged\": \"Scourged\",\n\t\"happening_bk:reroll_items\": \"Rerolled\",\n\t\"happening_bk:reroll_weapon\": \"New Weapons\",\n\t\"happening_bk:nerf\": \"Nerfed\",\n\t\"happening_bk:rob\": \"Robbed\",\n\t\"happening_bk:steal\": \"Weapon Stolen\",\n\t\"happening_bk:give_artifact\": \"Random Artifact\",\n\t\"happening_bk:give_weapon\": \"Random Weapon\",\n\t\"happening_bk:give_random_item\": \"Random Item\",\n\t\"happening_bk:give_random_consumable\": \"Random Consumable\",\n\t\"happening_bk:invincible\": \"Invincibility\",\n\t\"happening_bk:treasure_tp\": \"Treasure Locator\",\n\t\"happening_bk:small_heal\": \"Tiny Heal\",\n\t\"happening_bk:heal\": \"Heal\",\n\t\"happening_bk:omega_heal\": \"OEMGA HEAL\",\n\t\"happening_bk:shielded\": \"Shielded\",\n\t\"happening_bk:cleanse\": \"Cleansed\",\n\t\"happening_bk:chest\": \"Chest Attack\",\n\t\"happening_bk:buffed\": \"Buffed\",\n\t\"happening_bk:gift\": \"Gifted\",\n\t\"happening_bk:entrance_tp\": \"Here we start again\",\n\t\"happening_bk:exit_tp\": \"Get out\",\n\t\"twitch_next\": \"What shall happen next?\",\n\t\"total_votes\": \"votes\",\n\t\"bk:gold_lamp\": \"Gold Lamp\",\n\t\"bk:gold_lamp_desc\": \"Money money money\",\n\t\"bk:sharp_lamp\": \"Sharp Lamp\",\n\t\"bk:sharp_lamp_desc\": \"For melee lowers\",\n\t\"bk:ancient_sword\": \"Ancient Sword\",\n\t\"bk:ancient_sword_desc\": \"Really old stick\",\n\t\"ach_bk:unstoppable\": \"Unstoppable\",\n\t\"ach_bk:unstoppable_desc\": \"Beat the game with any lamp\",\n\t\"no_emeralds\": \"No Emeralds\",\n\t\"bk:emerald_gun\": \"Emerald Gun\",\n\t\"bk:emerald_gun_desc\": \"Most expensive gun on the market\",\n\t\"minimap\": \"Minimap\",\n\t\"quality\": \"Quality\",\n\t\"normal\": \"Normal\",\n\t\"potato\": \"Potato\",\n\t\"happening_bk:bomb\": \"Bomb Attack\",\n\t\"happening_bk:slide\": \"Slide to the left\",\n\t\"20_years_later\": \"20 years later\",\n\t\"painting_ducktective\": \"Ducktective\",\n\t\"painting_eye\": \"Space Eye\",\n\t\"boss_oldking\": \"Old King\",\n\t\"boss_pharaoh\": \"Pharaoh\",\n\t\"boss_queenbee\": \"Queen Bee\",\n\t\"boss_icequeen\": \"Ice Queen\",\n\t\"boss_burningknight\": \"Burning Knight\",\n\t\"boss_dm\": \"Dark Mage\",\n\t\"painting_bug\": \"This isn't a bug, that's a feature!\",\n\t\"damage\": \"Damage\",\n\t\"painting_new\": \"Gnobfather\",\n\t\"revive\": \"Revive\",\n\t\"coop_sign\": \"Press any button on a gamepad to add another player\",\n\t\"bk:party_hat\": \"Party Hat\",\n\t\"bk:party_hat_desc\": \"Why do I feel so sad\",\n\t\"bk:police_hat\": \"Police Hat\",\n\t\"bk:police_hat_desc\": \"Better stay away from portals\",\n\t\"bk:spike_hat\": \"Spike Hat\",\n\t\"bk:spike_hat_desc\": \"Poke\",\n\t\"bk:hood\": \"Hood\",\n\t\"bk:hood_desc\": \"Find the ring\",\n\t\"bk:bullet_hat\": \"Bullet Hat\",\n\t\"bk:bullet_hat_desc\": \"Bang\",\n\t\"remove_player\": \"Hold [ic 0] to remove player\",\n\t\"bk:spook\": \"Spook\",\n\t\"bk:spook_desc\": \"Boo\",\n\t\"bk:mask\": \"Mask\",\n\t\"bk:mask_desc\": \"Stay at 127.0.0.1\",\n\t\"bk:sword_polish\": \"Sword Polish\",\n\t\"bk:sword_polish_desc\": \"Bigger Melee Attacks\",\n\t\"bk:pumpkin_juice\": \"Pumpkin Juice\",\n\t\"bk:pumpkin_juice_desc\": \"Exciting\",\n\t\"bk:bouncy_glove\": \"Bouncy Glove\",\n\t\"bk:bouncy_glove_desc\": \"Bonk\",\n\t\"seeded\": \"(seeded)\"\n}"
  },
  {
    "path": "BurningKnight/Content/Locales/fr.json",
    "content": "﻿{\n\t\"bk:halo\": \"Halo\",\n\t\"bk:halo_desc\": \"Vie augmentée\",\n\t\"bk:revolver\": \"Revolver\",\n\t\"bk:sword\": \"Épée en bois\",\n\t\"bk:sword_desc\": \"Pas juste un bâton\",\n\t\"bk:heart\": \"Coeur\",\n\t\"resume\": \"Reprendre\",\n\t\"settings\": \"Options\",\n\t\"restart\": \"Recommencer\",\n\t\"death_message\": \"Vous êtes mort\",\n\t\"descend\": \"Descendre\",\n\t\"ascend\": \"Monter\",\n\t\"exit\": \"Sortir\",\n\t\"painting_rexcellent\": \"Excellent\",\n\t\"painting_grannylisa\": \"Mamielisa\",\n\t\"painting_maanex\": \"Le Penseur\",\n\t\"painting_bk\": \"Burning Knight\",\n\t\"painting_failpositive\": \"Le fêtard\",\n\t\"painting_old_man\": \"Un homme vraiment vieux\",\n\t\"painting_arthouse\": \"Maison Artistique\",\n\t\"painting_black\": \"L'Univers\",\n\t\"painting_milt\": \"Une boite dans la neige\",\n\t\"painting_skyscraper\": \"Un gratte-ciel solitaire\",\n\t\"painting_egor\": \"Burning Rex\",\n\t\"painting_null\": \"NULL\",\n\t\"painting_badosz\": \"Garçon perdu dans les bois\",\n\t\"painting_banana\": \"BANANE\",\n\t\"painting_tv\": \"Télé dans le ciel\",\n\t\"painting_company\": \"Une bonne entreprise\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Chien du Trasevol\",\n\t\"painting_lamp\": \"Prend le\",\n\t\"painting_scream\": \"Une glace\",\n\t\"painting_stars\": \"Nuit blanche\",\n\t\"painting_fog\": \"Dans les mers\",\n\t\"painting_nufflee\": \"Écorce\",\n\t\"by\": \"par\",\n\t\"old_man_0\": \"C'est dangeureux!\",\n\t\"continue_run\": \"Continuer la partie\",\n\t\"new_run\": \"Nouvelle partie\",\n\t\"was_unlocked\": \"A été déverrouillé!\",\n\t\"bk:revolver_desc\": \"Mains en l'air, @everyone!\",\n\t\"bk:shovel\": \"Une pelle bleue\",\n\t\"bk:shovel_desc\": \"Mais pourquoi est-elle bleue???\",\n\t\"beet_0\": \"Salut!\",\n\t\"beet_2\": \"Dites-moi son nom!\",\n\t\"npc_hurt_0\": \"Ouch.\",\n\t\"npc_hurt_1\": \"Ça fait mal.\",\n\t\"npc_hurt_2\": \"Oh non.\",\n\t\"beet_3\": \"Merci <3\",\n\t\"beet_1\": \"Veux tu planter une ^^graine^^?\",\n\t\"beet_1_0\": \"Oui!\",\n\t\"beet_1_1\": \"Non.\",\n\t\"beet_4\": \"La graine est [vr seed]. Voulez-vous la changer?\",\n\t\"beet_4_0\": \"Oui!\",\n\t\"beet_4_1\": \"Non.\",\n\t\"beet_5\": \"Peu importe.\",\n\t\"beet_4_2\": \"Faites que ce soit aléatoire!\",\n\t\"beet_6\": \"Ok. La graine est désormais [vr seed]!\",\n\t\"bk:idol\": \"Idole\",\n\t\"bk:idol_desc\": \"Un piège caché s'active!\",\n\t\"bk:key\": \"Clé en Or\",\n\t\"bk:infinite_bomb\": \"Bombe infinie\",\n\t\"bk:infinite_bomb_desc\": \"Bombe réutilisable\",\n\t\"throw_coin\": \"Jeter une pièce\",\n\t\"bk:potatoo\": \"Potatoo\",\n\t\"bk:potatoo_desc\": \"Projectiles à fragmentation\",\n\t\"bk:spectacles\": \"Lunettes\",\n\t\"bk:spectacles_desc\": \"Révèle les secrets\",\n\t\"bk:cross\": \"Croix\",\n\t\"bk:cross_desc\": \"Augmente le temps d'invincibilité\",\n\t\"bk:slime\": \"Slime\",\n\t\"bk:slime_desc\": \"Renvoi les tirs\",\n\t\"bk:missile\": \"Missile\",\n\t\"bk:missile_desc\": \"Tirs à tête chercheuse\",\n\t\"bk:rod_of_discord\": \"Baguette de Discord\",\n\t\"bk:rod_of_discord_desc\": \"Téléporte @everyone\",\n\t\"bk:goo\": \"Goo\",\n\t\"bk:goo_desc\": \"Un ami en orbite\",\n\t\"bk:jelly\": \"Jelly!\",\n\t\"bk:jelly_desc\": \"^^Rebondis^^\",\n\t\"bk:broken_stone\": \"Pierre brisée\",\n\t\"bk:broken_stone_desc\": \"Une orbite bien construite\",\n\t\"bk:nano_orb\": \"Nano Orbe\",\n\t\"bk:nano_orb_desc\": \"Un ami microscopique\",\n\t\"bk:saturn\": \"Planète\",\n\t\"bk:saturn_desc\": \"Bien sûr, nous l'aimons toujours\",\n\t\"bk:soap\": \"Savon\",\n\t\"bk:soap_desc\": \"Ralenti vos projectiles\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"^^Reroll^^ les objets!\",\n\t\"bk:my_heart\": \"Mon Coeur\",\n\t\"bk:my_heart_desc\": \"Augmente la vie\",\n\t\"bk:broken_heart\": \"Coeur Brisé\",\n\t\"bk:broken_heart_desc\": \"Augmente la vie\",\n\t\"bk:parcel\": \"Colis\",\n\t\"bk:parcel_desc\": \"Médecin réutilisable\",\n\t\"bk:glass\": \"Verre\",\n\t\"bk:glass_desc\": \"Projectiles ##Fragile##\",\n\t\"bk:glass_bullet\": \"Balle de Verre\",\n\t\"bk:glass_bullet_desc\": \"Tire à travers la pierre\",\n\t\"bk:broken_guitar\": \"Guitare Cassée\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Mitrailleuse\",\n\t\"bk:machine_gun_desc\": \"Automatique\",\n\t\"bk:grenade_launcher\": \"Lance-Grenades\",\n\t\"bk:grenade_launcher_desc\": \"Kaboom!\",\n\t\"bk:shotgun\": \"Fusil à Pompe\",\n\t\"bk:shotgun_desc\": \"Du gros sel dans la face!\",\n\t\"bk:missile_launcher\": \"Lance-Missiles\",\n\t\"bk:missile_launcher_desc\": \"Cible détectée!\",\n\t\"bk:burst_gun\": \"Pistolet Automatique\",\n\t\"bk:burst_gun_desc\": \"Tir à la vitesse de la lumière\",\n\t\"bk:flak_cannon\": \"Cannon Anti-Aérien\",\n\t\"bk:flak_cannon_desc\": \"C'est la fête !\",\n\t\"bk:disk_gun\": \"Pistolet à Disque\",\n\t\"bk:disk_gun_desc\": \"Il faut que ça coupe\",\n\t\"bk:duck_gun\": \"Pistolet Canard\",\n\t\"bk:duck_gun_desc\": \"Coin-Coin!\",\n\t\"bk:follower\": \"Follower\",\n\t\"bk:follower_desc\": \"Follow me!\",\n\t\"bk:portal_gun\": \"Pistolet à portail\",\n\t\"bk:portal_gun_desc\": \"The cake is a lie\",\n\t\"bk:snowflake\": \"Flocon\",\n\t\"bk:snowflake_desc\": \"Gèle tout le monde!\",\n\t\"bk:restock\": \"Réapprovisionnement\",\n\t\"bk:restock_desc\": \"Offre de magasin infinie\",\n\t\"bk:charisma_ring_desc\": \"Ventes royales\",\n\t\"bk:charisma_ring\": \"Anneau de Charisme\",\n\t\"bk:battery\": \"Batterie\",\n\t\"tomb_0\": \"Ci-gît [cl green]Gobbo[cl] le Grand\",\n\t\"bk:homemade_dice\": \"Dé fait maison\",\n\t\"bk:homemade_dice_desc\": \"^^Reroll^^ les objets! (DIY)\",\n\t\"shopkeeper_0\": \"##JE VOUS AI DIT DE NE PAS LE FAIRE !##\",\n\t\"shopkeeper_1\": \"S'il te plaît, arrête!\",\n\t\"shopkeeper_2\": \"Ne fais pas ça.\",\n\t\"shopkeeper_3\": \"[cl red]##PREPARE TOI À MOURIR!##\",\n\t\"shopkeeper_4\": \"[cl red]VOLEUR!\",\n\t\"shopkeeper_5\": \"[cl red]ATTRAPEZ LE!\",\n\t\"desert\": \"Palais du Désert\",\n\t\"jungle\": \"Jungle Ancienne\",\n\t\"ice\": \"Ruines de Glace\",\n\t\"bk:iron_boots\": \"Bottes de Métal\",\n\t\"bk:iron_boots_desc\": \"Les piques ne font plus mal\",\n\t\"bk:mimic_totem\": \"Totem Imitateur\",\n\t\"bk:mimic_totem_desc\": \"##PAS D'AUTRES IMITATIONS##\",\n\t\"back_to_town\": \"Retour à la ville\",\n\t\"bk:glass_gun\": \"Pistolet de Verre\",\n\t\"bk:glass_gun_desc\": \"##Fragile##\",\n\t\"bk:glass_shard\": \"Éclats de verre\",\n\t\"bk:glass_shard_desc\": \"Juste une partie de l'ensemble\",\n\t\"bk:dagger\": \"Dague\",\n\t\"bk:dagger_desc\": \"Nostalgie...\",\n\t\"bk:spear\": \"Lance\",\n\t\"bk:spear_desc\": \"Des bras plus longs?\",\n\t\"shopkeeper_6\": \"Bienvenue :)\",\n\t\"shopkeeper_7\": \"Yo, tu veux du [cl yellow]thé[cl]?\",\n\t\"shopkeeper_8\": \"Comment ca se passe?\",\n\t\"back\": \"Retour\",\n\t\"master_volume\": \"Volume Général\",\n\t\"music\": \"Musique\",\n\t\"sfx\": \"Effets sonores\",\n\t\"graphics\": \"Graphismes\",\n\t\"audio\": \"Audio\",\n\t\"ui_sfx\": \"Ui Effets sonores\",\n\t\"on\": \"On\",\n\t\"off\": \"Off\",\n\t\"fullscreen\": \"Plein Écran\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Compteur de FPS\",\n\t\"speedrun_timer\": \"Chronomètre Speedrun\",\n\t\"screenshake\": \"Tremblement de l'écran\",\n\t\"reset_progress\": \"Réinitialiser la progression\",\n\t\"blood_n_gore\": \"Sang et Effets gores\",\n\t\"vegan_mode\": \"Mode Végan\",\n\t\"reset_settings\": \"Réinitialiser les Options\",\n\t\"are_you_sure\": \"Êtes vous sûrs?\",\n\t\"yes\": \"Oui\",\n\t\"reset_progress_dis\": \"Cela supprimera TOUTE votre progression!\",\n\t\"reset_settings_dis\": \"Ceci réinitialisera TOUS les paramètres à leurs valeurs par défaut!\",\n\t\"autosave\": \"Sauvegarde Automatique\",\n\t\"autopause\": \"Pause Automatique\",\n\t\"input\": \"Saisie\",\n\t\"use\": \"Utiliser\",\n\t\"active\": \"Actif\",\n\t\"bomb\": \"Bombe\",\n\t\"interact\": \"Interagir\",\n\t\"swap\": \"Changer d'Armes\",\n\t\"roll\": \"Esquiver\",\n\t\"duck\": \"S'accroupir\",\n\t\"pause\": \"Pause\",\n\t\"none\": \"None\",\n\t\"keyboard_controls\": \"Contrôles du clavier\",\n\t\"gamepad_controls\": \"Contrôles de la manette de jeu\",\n\t\"keyboard\": \"Clavier\",\n\t\"gamepad\": \"Manette\",\n\t\"game\": \"Jeu\",\n\t\"select\": \"Selectionner\",\n\t\"cursor\": \"Curseur\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"Meurt\",\n\t\"ach_bk:overshake\": \"Mode Tremblement Infernal\",\n\t\"ach_bk:overshake_desc\": \"1000% de tremblement d'écran\",\n\t\"ach_bk:rip\": \"Succès le plus populaire\",\n\t\"bk:emerald\": \"Emeraude\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Merci!^^\",\n\t\"shopkeeper_11\": \"Quelle %%affaire%%!\",\n\t\"shopkeeper_12\": \"Tu veux [cl red]acheter[cl] ^^quelque chose^^?\",\n\t\"shopkeeper_13\": \"Seulement pour [cl green]toi[cl], seulement aujourd'hui!\",\n\t\"shopkeeper_14\": \"Quelle [cl yellow]offre[cl]!\",\n\t\"bk:magnifier\": \"Loupe\",\n\t\"bk:magnifier_desc\": \"Projectiles plus gros\",\n\t\"bk:mushroom_hat\": \"Chapeau champignons\",\n\t\"bk:mushroom_hat_desc\": \"C'est bon ?\",\n\t\"bk:stone_hat\": \"Chapeau de pierre\",\n\t\"bk:stone_hat_desc\": \"C'est lourd\",\n\t\"bk:knight_hat\": \"Casque de chevalier\",\n\t\"bk:knight_hat_desc\": \"De bons vieux ennemis...\",\n\t\"bk:cowboy_hat\": \"Chapeau de Cowboy\",\n\t\"bk:cowboy_hat_desc\": \"L'Ouest Sauvage!\",\n\t\"bk:soup_hat\": \"Chapeau de soupe\",\n\t\"bk:soup_hat_desc\": \"^^Délicieux^^\",\n\t\"bk:gold_hat\": \"Chapeau doré\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Riche!\",\n\t\"bk:viking_hat\": \"Casque Viking\",\n\t\"bk:viking_hat_desc\": \"Amerique!\",\n\t\"bk:dunce_hat\": \"Chapeau d'âne\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Haut-de-Forme\",\n\t\"bk:top_hat_desc\": \"À la mode!\",\n\t\"bk:ushanka\": \"Chapka\",\n\t\"bk:ushanka_desc\": \"Où est ma ##balalaïka?##\",\n\t\"bk:valkyrie_hat\": \"Casque de Valkyrie\",\n\t\"bk:valkyrie_hat_desc\": \"I believe ^^I can fly!^^\",\n\t\"bk:skull_hat\": \"Masque de squelette\",\n\t\"bk:skull_hat_desc\": \"L'argent ou la vie!\",\n\t\"bk:grandma_head\": \"Tête de Grand-mère\",\n\t\"bk:grandma_head_desc\": \"Du thé?\",\n\t\"bk:diamond_helmet\": \"Casque de Diamant\",\n\t\"bk:diamond_helmet_desc\": \"Tais toi et creuse!\",\n\t\"bk:villager_head\": \"Tête de villageois\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fez\",\n\t\"bk:fez_desc\": \"Cubit\",\n\t\"bk:no_hat\": \"Enlever son chapeau\",\n\t\"bk:no_hat_desc\": \"Pas de chapeau - pas de problèmes!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"Tentative d'appeler une valeur null\",\n\t\"accessorytrader_0\": \"##SORS DE LÀ!## [dl]Ou achète ces ^^delicieux^^ objets à seulement ^^%%99 diamants chacun%%^^!\",\n\t\"accessorytrader_1\": \"Salut\",\n\t\"accessorytrader_2\": \"Ca va!\",\n\t\"weapontrader_0\": \"Entre!\",\n\t\"weapontrader_1\": \"Bonne journée, monsieur!\",\n\t\"weapontrader_2\": \"Achète quelque chose, non?\",\n\t\"activetrader_0\": \"Les meilleures offres sur le marché!\",\n\t\"activetrader_1\": \"Payez pour deux et obtenez-en deux!\",\n\t\"activetrader_2\": \"Donne moi des donuts, [dl]s'il te plait!!\",\n\t\"hattrader_0\": \"Tu veux être aussi cool que moi? [dl]Achète des chapeaux!\",\n\t\"hattrader_1\": \"Tu veux être aussi cool que moi? [dl]Moi aussi, gamin.\",\n\t\"hattrader_2\": \"^^Ha ha des chapeaux!^^\",\n\t\"granny_0\": \"Tu veux du thé?\",\n\t\"granny_1\": \"Fais une pause thé!\",\n\t\"granny_2\": \"Thé?\",\n\t\"bk:xmas_hat\": \"Chapeau de Noël\",\n\t\"bk:xmas_hat_desc\": \"Joyeux Noël!\",\n\t\"bk:pumpkin_hat\": \"Citrouille sculptée\",\n\t\"bk:pumpkin_hat_desc\": \"^^Squelette effrayant^^\",\n\t\"bk:cage_key\": \"Clé de la cage\",\n\t\"bk:cage_key_desc\": \"Sauve ^^le mec^^!\",\n\t\"npc_0\": \"Aide moi! Touve la clé!\",\n\t\"npc_1\": \"Merci de m'avoir sauvé!\",\n\t\"npc_2\": \"Plus vite! Déverrouille la porte!\",\n\t\"npc_3\": \"S'il te plait! Aide moi!\",\n\t\"control_0\": \"Appuie sur [ic 0][ic 1] pour poser une bombe\",\n\t\"control_1\": \"Esquive! Appuie sur [ic 0][ic 1] pour obtenir le pouvoir!\",\n\t\"control_2\": \"Appuie sur [ic 0][ic 1] pour attaquer\",\n\t\"control_3\": \"Appuie sur [ic 0][ic 1] pour interagir\",\n\t\"control_4\": \"Coin? [ic 0][ic 1]!\",\n\t\"control_5\": \"Appuie sur [ic 0][ic 1] pour changer d'arme\",\n\t\"shopkeeper_15\": \"Pas de réduction pour toi!\",\n\t\"shopkeeper_16\": \"Obtenez plus d'argent et revenez!\",\n\t\"shopkeeper_17\": \"Il faut d'abord payer!\",\n\t\"bk:frog\": \"Télé-grenouille\",\n\t\"bk:frog_desc\": \"Voyage rapide?\",\n\t\"bk:sword_orbital\": \"Épée Orbitale\",\n\t\"bk:sword_orbital_desc\": \"Justice\",\n\t\"robbed\": \"Volé\",\n\t\"bk:gift_desc\": \"Qu'est ce qu'il y a à l'intérieur?\",\n\t\"bk:spike_ring\": \"Bague à pointes\",\n\t\"bk:spike_ring_desc\": \"Vos ennemies doivent être ##punis##!\",\n\t\"bk:fire_ring\": \"Anneau de Feu\",\n\t\"bk:fire_ring_desc\": \"Laissez vos ennemis brûler\",\n\t\"bk:ice_ring\": \"Anneau de Glace\",\n\t\"bk:ice_ring_desc\": \"Arrêtez vos ennemis\",\n\t\"bk:duck_ring\": \"Anneau du Canard\",\n\t\"bk:duck_ring_desc\": \"Vous téléporte après avoir été touché\",\n\t\"bk:dull_blade\": \"Lame émoussée\",\n\t\"bk:dull_blade_desc\": \"Déclenche un effet négatif\",\n\t\"bk:sharp_blade\": \"Lame aiguisée\",\n\t\"bk:sharp_blade_desc\": \"Vous blesse\",\n\t\"bk:obsidian_shield\": \"Bouclier d'Obsidienne\",\n\t\"bk:obsidian_shield_desc\": \"Recul = 0\",\n\t\"bk:bill\": \"Facture\",\n\t\"bk:bill_desc\": \"99 dollars\",\n\t\"control_6\": \"Utilisez les objets actifs avec [ic 0][ic 1]\",\n\t\"bk:clover\": \"Trèfle à 4 feuilles\",\n\t\"bk:clover_desc\": \"Chanceux!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^Reroll %%vos artéfacts%%!^^\",\n\t\"brastin_0\": \"Trouvez le tableau du [cl purple]chat[cl]!\",\n\t\"elon_1\": \"Voilà, amusez-vous bien\",\n\t\"bk:maanex_head\": \"Tête de Maanex\",\n\t\"bk:maanex_head_desc\": \"Hmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Fait réfléchir un peu les ennemis\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Carte des empreintes vertes\",\n\t\"bk:map_greenprints_desc\": \"Révèle la carte\",\n\t\"bk:map\": \"Carte\",\n\t\"bk:map_desc\": \"Révèle la carte définitivement \",\n\t\"milt_1\": \"Je veux un cadeau\",\n\t\"mapuzzle_0\": \"Gravité.\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Copié!\",\n\t\"isaac_0\": \"La vie n'a pas de sens...\",\n\t\"isaac_1\": \"Pourquoiiiiiii\",\n\t\"isaac_2\": \":sob:\",\n\t\"discord_0\": \"Dites bonjour! discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"Esquive, idiot!\",\n\t\"tutorial\": \"Tutoriel\",\n\t\"bk:crying_bomb\": \"Bombe pleureuse\",\n\t\"bk:crying_bomb_desc\": \"Les bombes pleurent maintenant!\",\n\t\"bk:matches\": \"Allumettes\",\n\t\"bk:matches_desc\": \"Réduis le délai de l'explosion\",\n\t\"bk:bomb_pack\": \"Pack de bombes\",\n\t\"bk:bomb_pack_desc\": \"On met des bombes dans vos bombes!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 bombes\",\n\t\"bk:weird_mushroom_desc\": \"Double tout\",\n\t\"bk:weird_mushroom\": \"Champignon bizarre\",\n\t\"bk:bomb_shower\": \"Pluie de bombe\",\n\t\"bk:bomb_shower_desc\": \"Faites pleuvoir les bombes\",\n\t\"bk:black_belt\": \"Ceinture noire\",\n\t\"bk:black_belt_desc\": \"N'explosez plus\",\n\t\"bk:ninjia_bomb\": \"Bombe Ninjia\",\n\t\"bk:ninjia_bomb_desc\": \"Les blessures font apparaitre des bombes\",\n\t\"start_new_run\": \"Votre partie actuelle sera perdue!\",\n\t\"bk:laser_pointer\": \"Pointeur laser\",\n\t\"bk:laser_pointer_desc\": \"L'objectif est clair!\",\n\t\"ach_bk:marauder\": \"Maraudeur\",\n\t\"ach_bk:marauder_desc\": \"Tuez le marchand\",\n\t\"ach_bk:treasure_hunter\": \"Chasseur de trésor\",\n\t\"ach_bk:treasure_hunter_desc\": \"Trouver une pièce secrète\",\n\t\"ach_bk:dodge_master\": \"Maître de l'esquive\",\n\t\"ach_bk:dodge_master_desc\": \"Tuer un boss sans se faire toucher\",\n\t\"ach_bk:dodge_overlord\": \"Maître de l'Esquive Suprême\",\n\t\"ach_bk:dodge_overlord_desc\": \"Terminer un étage sans se faire toucher une seule fois\",\n\t\"ach_bk:quackers\": \"Coin-Coin\",\n\t\"ach_bk:quackers_desc\": \"Super Coin-Coin\",\n\t\"ach_bk:tea_party\": \"Après-midi thé\",\n\t\"ach_bk:tea_party_desc\": \"Rejoignez Mamie dans son après-midi thé\",\n\t\"ach_bk:not_a_thief\": \"Pas un voleur\",\n\t\"ach_bk:not_a_thief_desc\": \"Terminer une partie sans prendre d'objets\",\n\t\"ach_bk:npc_party2\": \"Fête de PNJ\",\n\t\"ach_bk:npc_party2_desc\": \"Sauvez tous les PNJ\",\n\t\"bk:gold_coin\": \"Pièce d'Or\",\n\t\"bk:iron_coin\": \"Pièce d'Argent\",\n\t\"bk:copper_coin\": \"Pièce de Cuivre\",\n\t\"bk:platinum_coin\": \"Pièce de Platine\",\n\t\"bk:voodoo_doll\": \"Poupée Vaudou\",\n\t\"bk:voodoo_doll_desc\": \"Tuez tous les ennemis présents dans la pièce\",\n\t\"hub\": \"Ville de l'esquive\",\n\t\"castle\": \"Ruines du château\",\n\t\"charger_0\": \"AUCUN OBJET ACTIF DÉTECTÉ\",\n\t\"charger_1\": \"L'OBJET ACTIF EST DÉJÀ CHARGÉ\",\n\t\"charger_2\": \"OÙ EST MON ARGENT, TOI, SAC À VIANDE!\",\n\t\"charger_3\": \"##J'AI DIT DONNE-MOI MON ARGENT!##\",\n\t\"charger_4\": \"##JE VAIS CONQUÉRIR LE MONDE!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Bien sûr, allons-y!\",\n\t\"maanex_6_1\": \"Non.\",\n\t\"maanex_6\": \"Okay, donne moi [cl yellow][vr cost] pièces[cl] et je te laisserai ouvrir un de ces coffres. D'accord?\",\n\t\"maanex_5\": \"Hey toi, tu veux ^^tenter^^ ta chance?\",\n\t\"maanex_7\": \"C'était amusant!\",\n\t\"maanex_8\": \"Bonne Chance!\",\n\t\"maanex_9\": \"Eh bien, pas cette fois :(\",\n\t\"maanex_10\": \"%%^^WOAH^^%%\",\n\t\"maanex_11\": \"Mais tu n'as pas assez d'argent!\",\n\t\"maanex_12\": \"##FILS?!##\",\n\t\"bk:amurs_arrow\": \"Flèche d'Amour\",\n\t\"bk:amurs_arrow_desc\": \"Projectiles de charme\",\n\t\"bk:amurs_bow\": \"Arc d'Amour'\",\n\t\"bk:amurs_bow_desc\": \"Je vois l'amour\",\n\t\"bk:poison_flask\": \"Flacon de Poison\",\n\t\"bk:poison_flask_desc\": \"Projectiles empoisonnés\",\n\t\"bk:snowball\": \"Boule de neige\",\n\t\"bk:snowball_desc\": \"Projectiles glacés\",\n\t\"bk:peper_desc\": \"Projectiles brûlants\",\n\t\"bk:peper\": \"Piment Fort\",\n\t\"bk:sale_coupon\": \"Coupon de vente\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Animal en boîte\",\n\t\"bk:pet_box_desc\": \"Qui est là?\",\n\t\"bk:crate\": \"Caisse Orbitale\",\n\t\"bk:crate_desc\": \"Qui est à l'intérieur?\",\n\t\"bk:strawberry\": \"Fraise\",\n\t\"bk:strawberry_desc\": \"Doux souvenirs\",\n\t\"bk:wings\": \"Ailes\",\n\t\"bk:wings_desc\": \"I belive I can fly\",\n\t\"bk:coin_pouch\": \"Sac de pièces\",\n\t\"bk:coin_pouch_desc\": \"Donne des pièces\",\n\t\"bk:key_pouch\": \"Sac de Clés\",\n\t\"bk:key_pouch_desc\": \"Donne des Clés\",\n\t\"bk:bomb_pouch\": \"Sac de Bombes\",\n\t\"bk:bomb_pouch_desc\": \"Donne des Bombes\",\n\t\"bk:pouch_pouch\": \"Sac de Sacs\",\n\t\"bk:pouch_pouch_desc\": \"Donne des Sacs\",\n\t\"bk:lightsaber\": \"Svetsaber\",\n\t\"bk:lightsaber_desc\": \"Vous étiez l'élu!\",\n\t\"bk:snail\": \"Escargot\",\n\t\"bk:snail_desc\": \"Ralentissement de la masse\",\n\t\"bk:spike\": \"Piques\",\n\t\"bk:spike_desc\": \"Augmente les Dégâts\",\n\t\"bk:mushroom\": \"Champignon\",\n\t\"bk:mushroom_desc\": \"Augmente la Vitesse\",\n\t\"bk:candy\": \"Bonbon\",\n\t\"bk:candy_desc\": \"^^Sugar rush^^, Cadence de Tir augmentée\",\n\t\"bk:glasses\": \"Lunettes\",\n\t\"bk:glasses_desc\": \"Augmente la Précision\",\n\t\"bk:ruler\": \"Règle\",\n\t\"bk:ruler_desc\": \"Augmente la Portée\",\n\t\"bk:stopwatch\": \"Chronomètre\",\n\t\"bk:stopwatch_desc\": \"Se faire toucher permet de contrôler le temps\",\n\t\"bk_0\": \"##N'OSE PAS TOUCHER À ÇA!##\",\n\t\"bk_1\": \"##J'AI DIT NE TOUCHE À ÇA!##\",\n\t\"bk_2\": \"##TU NE PEUX PAS VAINCRE [cl red]BURNING KNIGHT[cl], IDIOT!##\",\n\t\"bk_3\": \"##PREPARE TOI A MOURIR!##\",\n\t\"bk_4\": \"^^QUELLE BLAGUE^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Grosses Soldes![cl]\",\n\t\"dm_0\": \"@@Bienvenue@@\",\n\t\"ach_bk:deal\": \"Événement Exceptionnel\",\n\t\"ach_bk:deal_desc\": \"Conclure un accord avec le Mage Noir\",\n\t\"ach_bk:grannys_gift\": \"Cadeau de mamie\",\n\t\"ach_bk:grannys_gift_desc\": \"Prenez un cadeau de Mamie\",\n\t\"ach_bk:shopper\": \"Acheter jusqu'à ne plus pouvoir\",\n\t\"ach_bk:shopper_desc\": \"Acheter un article dans n'importe quel magasin\",\n\t\"bk_5\": \"JE N'AURAIS MÊME PAS BESOIN DE LUI PARLER\",\n\t\"bk_6\": \"##TUE-LE, [cl lime]EDWARD[cl]!##\",\n\t\"bk_7\": \"[cl lime]EDWARD[cl], ##NOOOOOON!!!!##\",\n\t\"bk_8\": \"OH ÇA VA, ARRÊTE DE FAIRE EXPLOSER MON CHÂTEAU!\",\n\t\"bk_9\": \"[cl pink]?Q?IE[cl],[dl] TU PEUX MOURIR, S'IL TE PLAÎT##?!?##\",\n\t\"bk_10\": \"MON MAÎTRE,[dl] J'AI APPORTÉ LE [cl green]GOBLIN[cl]\",\n\t\"dm_1\": \"Très bien[dl], merci[dl], [cl red]Limpor[cl]\",\n\t\"dm_2\": \"##Oui, oui, j'ai besoin de plus de [cl orange]puissance[cl]!##\",\n\t\"dm_3\": \"##PLUS DE [cl orange]PUISSANCE[cl]!\",\n\t\"dm_4\": \"Je peux sentir [cl orange]cette force[cl] palpiter en moi!\",\n\t\"granny_3\": \"Tu sera le premier, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Bienvenue, [cl green]Gobbo [vr id][cl]!\",\n\t\"granny_5\": \"Bonne chance dans votre triste quête!\",\n\t\"bk:meat_guy\": \"Homme Viande\",\n\t\"bk:meat_guy_desc\": \"Les boules!\",\n\t\"bk:bullet_stone\": \"Balles de pierre\",\n\t\"bk:bullet_stone_desc\": \"Il attaque, il protège, mais surtout, il est mignon comme tout\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"N'aide pas, mais donne des piles\",\n\t\"vibration\": \"Vibration\",\n\t\"bk:sharp_arrow\": \"Flèche acérée\",\n\t\"bk:sharp_arrow_desc\": \"Augmente la pénétration des projectiles\",\n\t\"machine_0\": \"Insérer une [cl yellow]pièce\",\n\t\"player_0\": \"Papa?? ##Qu'est-ce qu'ils t'ont fait?!?##\",\n\t\"bk:boomerang\": \"Boomerang\",\n\t\"bk:boomerang_desc\": \"Projectiles Boomerang\",\n\t\"bk:backpack\": \"Sac à Dos\",\n\t\"bk:backpack_desc\": \"Mon meilleur ami\",\n\t\"place_an_item\": \"Placer un objet\",\n\t\"bk:crystal\": \"Crystal\",\n\t\"bk:crystal_desc\": \"La puissance de l'arc-en-ciel\",\n\t\"bk:prism\": \"Prisme\",\n\t\"bk:prism_desc\": \"Projectiles -> Arc-en-ciel\",\n\t\"scourged\": \"Malédiction\",\n\t\"bk:bomb\": \"Bombe\",\n\t\"bk:scourge_of_egg\": \"La Malédiction de l'Oeuf\",\n\t\"bk:scourge_of_egg_desc\": \"Mélange les noms d'objets\",\n\t\"bk:scourge_of_unknown\": \"La Malédiction de l'inconnu\",\n\t\"bk:scourge_of_unknown_desc\": \"Objets cachés\",\n\t\"bk:scourge_of_blood\": \"La Malédiction du sang\",\n\t\"bk:scourge_of_blood_desc\": \"Double problème (et ennemis)\",\n\t\"bk:scourge_of_risk\": \"La Malédiction du risque\",\n\t\"bk:scourge_of_risk_desc\": \"Santé cachée\",\n\t\"bk:scourge_of_keys\": \"La Malédiction des Clés\",\n\t\"bk:scourge_of_keys_desc\": \"Consommables cachés\",\n\t\"bk:scourge_of_lost\": \"La Malédiction du Vide\",\n\t\"bk:scourge_of_lost_desc\": \"Amnésie\",\n\t\"bk:scourge_of_scourged\": \"La Malédiction des Malédictions\",\n\t\"bk:scourge_of_scourged_desc\": \"Des Malédictions partout\",\n\t\"bk:scourge_of_illness\": \"La Malédiction de Vie\",\n\t\"bk:scourge_of_illness_desc\": \"Les soins sont amoindries\",\n\t\"bk:scourge_of_death\": \"La Malédiction Mortelle\",\n\t\"bk:scourge_of_death_desc\": \"Mode Difficile\",\n\t\"bk:ancient_revolver\": \"Revolver Ancient\",\n\t\"bk:ancient_revolver_desc\": \"L'aspect est cool\",\n\t\"bk:assault_rifle\": \"Fusil d'Assaut\",\n\t\"bk:assault_rifle_desc\": \"Mitraille\",\n\t\"fountain_0\": \"Apporte 5 pièces et tu sera bénis\",\n\t\"fountain_1\": \"Vous avez été partiellement purifié\",\n\t\"fountain_2\": \"Vous avez été entièrement purifié\",\n\t\"fountain_3\": \"Vous êtes déjà purifié\",\n\t\"buffed\": \"Amélioré\",\n\t\"nerfed\": \"Nerfé\",\n\t\"restored\": \"Restoré\",\n\t\"damaged\": \"Endommagé\",\n\t\"cleansed\": \"Purifié\",\n\t\"gifted\": \"Doué\",\n\t\"lucky\": \"Chanceux\",\n\t\"unlucky\": \"Malchanceux\",\n\t\"max_hp\": \"PV Max\",\n\t\"touch\": \"Contact\",\n\t\"break\": \"Pause\",\n\t\"no_coins\": \"Pas de pièces\",\n\t\"old_man_6\": \"C'est dangereux d'y aller seul, prends ça!\",\n\t\"roger_0\": \"Kaboom!\",\n\t\"roger_1\": \"##*BOOM*##\",\n\t\"roger_2\": \"Boom boom shakataka!\",\n\t\"bk:shield\": \"Bouclier\",\n\t\"bk:gift\": \"Cadeau\",\n\t\"bk:shield_pouch\": \"Sac de Boucliers\",\n\t\"bk:shield_pouch_desc\": \"Donne des Boucliers\",\n\t\"bk:shield_buddy\": \"Compagnon bouclier\",\n\t\"bk:shield_buddy_desc\": \"Il protège\",\n\t\"bk:skeleton_key\": \"Passe-partout\",\n\t\"bk:skeleton_key_desc\": \"99 clés\",\n\t\"bk:jar\": \"Jar de Vie\",\n\t\"bk:jar_desc\": \"Jar Jar Clinks\",\n\t\"bk:star\": \"Étoile\",\n\t\"bk:star_desc\": \"Elle protège\",\n\t\"bk:car_bomb\": \"Voiture piégée\",\n\t\"bk:car_bomb_desc\": \"Service de livraison de bombes\",\n\t\"bk:grenade\": \"Grenade\",\n\t\"bk:grenade_desc\": \"Explose au touché\",\n\t\"trash_goblin_0\": \"Libérez-moi de ma [cl purple]malédiction[cl]! S'il vous plait!\",\n\t\"trash_goblin_1\": \"Je suis libre![dl] Merci beaucoup!\",\n\t\"boxy_0\": \"Cléxellent!\",\n\t\"boxy_1\": \"Quelle belle boîte!\",\n\t\"boxy_2\": \"Tu veux du papier cadeau?\",\n\t\"trash_goblin_2\": \"^^Fumée sur l'eau [ic 0] [ic 1]^^\",\n\t\"bk:vampire_bat\": \"Chauve-souris vampire\",\n\t\"bk:vampire_bat_desc\": \"Régen\",\n\t\"shields\": \"Boucliers\",\n\t\"bk:mustache\": \"Moustache\",\n\t\"bk:mustache_desc\": \"VIP\",\n\t\"bk:bloody_chest\": \"Coffre sanglant\",\n\t\"bk:bloody_chest_desc\": \"Les coffres vous soignent\",\n\t\"bk:bloody_shield\": \"Bouclier sanglant\",\n\t\"bk:bloody_shield_desc\": \"Boucliers pour toujour\",\n\t\"bk:cutsaw\": \"Scie\",\n\t\"bk:cutsaw_desc\": \"Les ennemis paieront\",\n\t\"vampire_0\": \"Yum!\",\n\t\"vampire_1\": \"Exsanglant!\",\n\t\"vampire_2\": \"Si doux!\",\n\t\"vampire_3\": \"Nous connaissons les règles, [cl red]^^pas vrai[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"Quel est ton groupe sanguin?\",\n\t\"vampire_6\": \"Si savoureux\",\n\t\"duck_2\": \"Ça te dirais de participer a une enquête?\",\n\t\"duck_7_0\": \"Oui\",\n\t\"duck_7_1\": \"Non\",\n\t\"duck_7\": \"Voulez-vous obtenir ce coffre?\",\n\t\"duck_4\": \"Bien joué, prenez ce coffre!\",\n\t\"duck_5\": \"Je ne suis pas d'accord avec toi...\",\n\t\"duck_6_0\": \"L'Univers\",\n\t\"duck_6_1\": \"^^Coin^^\",\n\t\"duck_6\": \"A quoi est ce que je pense?\",\n\t\"duck_8_0\": \"[cl red]Rouge[cl]\",\n\t\"duck_8_1\": \"[cl blue]Bleu[cl]\",\n\t\"duck_8\": \"Quel est ma ^^%%couleur%%^^ préférée?\",\n\t\"duck_9_0\": \"Un chat\",\n\t\"duck_9_1\": \"Tu viens de le dire\",\n\t\"duck_9\": \"Qui a dit meow?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"Qu'est-ce qui est mieux?\",\n\t\"duck_11_0\": \"Quoi, ton oeuf?\",\n\t\"duck_11_1\": \"\\\\[_Il le poignarde._]\",\n\t\"duck_11\": \"Tu es un insolent\",\n\t\"duck_12_0\": \"Poulet\",\n\t\"duck_12_1\": \"Oeuf\",\n\t\"duck_12\": \"Qui est arrivé en premier?\",\n\t\"duck_13_0\": \"Rien.\",\n\t\"duck_13_1\": \"Une collation.\",\n\t\"duck_13_2\": \"un oeuf.\",\n\t\"duck_13_3\": \"Poulet frit.\",\n\t\"duck_13\": \"Tu as mangé quoi aujourd'hui?\",\n\t\"duck_14\": \"Ouch.\",\n\t\"duck_17_0\": \"Bien sûr, mon gars\",\n\t\"duck_17_1\": \"##NAAAAAH##\",\n\t\"duck_17\": \"Tu aimes l'ananas sur ta pizza?\",\n\t\"duck_18_0\": \"Blanc!\",\n\t\"duck_18_1\": \"[cl yellow]Jaune[cl]!\",\n\t\"duck_18\": \"Quelle est la couleur du fromage ??\",\n\t\"nurse_0\": \"Tu es magnifique, chérie!\",\n\t\"nurse_1\": \"Je pourrais te guérir un peu, mais j'ai besoin [cl yellow][vr price] pièces[cl]\",\n\t\"nurse_2\": \"J'espère que çq n'a pas fait mal\",\n\t\"elon_4\": \"Voilà, amusez-vous bien\",\n\t\"elon_2_0\": \"Allons-y\",\n\t\"elon_2_1\": \"Attends\",\n\t\"elon_2\": \"Tu veux essayer ma magie?\",\n\t\"elon_3\": \"Je peux transformer ton arme en une autre\",\n\t\"elon_5\": \"Peu importe\",\n\t\"elon_7\": \"Bro, où est ton arme???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*blush*\",\n\t\"gobetta_4\": \"C'est... toi?\",\n\t\"gobetta_5\": \"Ça fait si longtemps...\",\n\t\"ach_bk:desert\": \"Sec et Chaud\",\n\t\"ach_bk:desert_desc\": \"Atteindre le Palais du Désert\",\n\t\"ach_bk:jungle\": \"Abeilles bourdonnantes\",\n\t\"ach_bk:jungle_desc\": \"Atteindre l'ancienne jungle\",\n\t\"rooms_explored\": \"Salles explorées\",\n\t\"bk:shadow_cloak_desc\": \"Non Toi\",\n\t\"bk:shadow_cloak\": \"Cape de l'ombre\",\n\t\"bk:dynamite_stick\": \"Bâton de Dynamite\",\n\t\"bk:dynamite_stick_desc\": \"Tu veux exploser?\",\n\t\"bk:chalice_of_blood\": \"Calice de sang\",\n\t\"bk:chalice_of_blood_desc\": \"La douleur invoque la rage, la rage invoque les dégâts\",\n\t\"bk:detonator\": \"Detonateur\",\n\t\"bk:detonator_desc\": \"Déclenche les explosifs\",\n\t\"invincibility_time\": \"Temps d'invincibilité\",\n\t\"accuracy\": \"Précision\",\n\t\"range\": \"Portée\",\n\t\"fire_rate\": \"Cadence de Tir\",\n\t\"speed\": \"Vitesse\",\n\t\"bk:talisman_of_foresight\": \"Talisman de prévoyance\",\n\t\"bk:talisman_of_foresight_desc\": \"Ouvrez les yeux et voyez les salles à proximité!\",\n\t\"bk:scourge_ring\": \"Anneau de Malédiction\",\n\t\"bk:scourge_ring_desc\": \"Vous ne pouvez plus être maudis\",\n\t\"snek_0\": \"Nice.\",\n\t\"snek_1\": \"Mersssi mec\",\n\t\"snek_2\": \"Impressionnant\",\n\t\"snek_3\": \"Ssssa va\",\n\t\"snek_4\": \"Bonne journée, monssssieur\",\n\t\"snek_5\": \"Tu dois assseter quelque chossse?\",\n\t\"snek_6\": \"Je dois sssatissssfaire le client...\",\n\t\"snek_7\": \"Je vais faire ssse que je dois faire !\",\n\t\"bk:snek\": \"Snek\",\n\t\"bk:snek_desc\": \"Snack?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Tu as un double de la clé?\",\n\t\"boxy_5\": \"Faites don de quelques clés?\",\n\t\"bk:blank\": \"Vide\",\n\t\"bk:blank_desc\": \"_Texte Vide_\",\n\t\"bk:blank_bombs\": \"Bombes à blanc\",\n\t\"bk:blank_bombs_desc\": \"Bouclier de balles\",\n\t\"bk:explosive_bullets\": \"Balles explosives\",\n\t\"bk:explosive_bullets_desc\": \"Explosif\",\n\t\"bk:random_bullets\": \"Balles aléatoires\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Coupe\",\n\t\"bk:cup_desc\": \"Mamie ne peut pas résister à l'envie de se montrer\",\n\t\"bk:cartridge\": \"Cartouche\",\n\t\"bk:cartridge_desc\": \"Le Mage Noir ne résiste pas à l'envie de se montrer\",\n\t\"bk:marriage_ring\": \"Alliance de mariage\",\n\t\"bk:marriage_ring_desc\": \"MN & Mamie pour toujours!\",\n\t\"boxy_7\": \"Je veux des clés\",\n\t\"boxy_8\": \"Tu n'as pas assez de clés :(\",\n\t\"boxy_9\": \"Maintenant, j'ai enfin assez de clés ^^m'ouvrir^^!\",\n\t\"roger_3\": \"Vous voulez bien payer ?\",\n\t\"roger_4\": \"Pas de réductions aujourd'hui\",\n\t\"roger_5\": \"Les bombes d'abord\",\n\t\"vampire_7\": \"Vous n'êtes pas en assez bonne santé\",\n\t\"vampire_8\": \"Je n'accorde pas de remises\",\n\t\"vampire_9\": \"Votre santé semble faible\",\n\t\"ach_bk:scourged\": \"Maudis\",\n\t\"ach_bk:scourged_desc\": \"Prenez un jeton maudis\",\n\t\"ach_bk:scourged_weapon\": \"Arme Maudite\",\n\t\"ach_bk:scourged_weapon_desc\": \"Ramassez une arme maudite\",\n\t\"rerolled\": \"Rerolled\",\n\t\"ach_bk:open_up\": \"Ouvrir\",\n\t\"ach_bk:open_up_desc\": \"Tout acheter à Boxy\",\n\t\"ach_bk:snek\": \"Animal de compagnie Snek\",\n\t\"ach_bk:snek_desc\": \"Faites du Snek votre animal de compagnie\",\n\t\"bk:scourge_of_greed\": \"La Malédiction de l'Avidité\",\n\t\"bk:scourge_of_greed_desc\": \"Prix élevés\",\n\t\"killed_by\": \"Tué par\",\n\t\"kills\": \"Kills\",\n\t\"time\": \"Temps\",\n\t\"depth\": \"Profondeur\",\n\t\"bk:blank_bullets\": \"Balles à Blanc\",\n\t\"bk:blank_bullets_desc\": \"Vide\",\n\t\"bk:lego\": \"Constructeur\",\n\t\"bk:lego_desc\": \"Cela fait tellement mal de marcher sur ces...\",\n\t\"bk:iron_armor\": \"Armure de Fer\",\n\t\"bk:iron_armor_desc\": \"Donne des boucliers\",\n\t\"bk:round_shield\": \"Bouclier Rond\",\n\t\"bk:round_shield_desc\": \"Empêche les dégâts de mêlée\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"La légende elle-même\",\n\t\"bk:inverted_arkhalis\": \"Arkhalis Inversé\",\n\t\"bk:inverted_arkhalis_desc\": \"L'aide viendra quand la santé sera au plus bas\",\n\t\"bk:gun_sword\": \"Épée fusil\",\n\t\"bk:gun_sword_desc\": \"Préparez-vous aux ennuis et faites en deux fois plus!\",\n\t\"ach_bk:scourge_king_desc\": \"Obtenew 10 points de Malédiction\",\n\t\"ach_bk:scourge_king\": \"Roi Maudis\",\n\t\"ach_bk:sting_operation\": \"Opération Pointilleuse\",\n\t\"ach_bk:sting_operation_desc\": \"Vaincre la Reine des Abeilles\",\n\t\"ach_bk:mummified\": \"Momifié\",\n\t\"ach_bk:mummified_desc\": \"Vaincre le Pharaon\",\n\t\"ach_bk:democracy\": \"Démocratie\",\n\t\"ach_bk:democracy_desc\": \"Vaincre le Vieux Roi\",\n\t\"pharaoh_scream\": \"##PRÉPARE TOI À ÊTRE MOMIFIÉ!##\",\n\t\"queen_bee_scream\": \"##POUR LE [cl yellow]SEIGNEUR DU MIEL[cl]!##\",\n\t\"bk:half_heart\": \"Demi-Coeur\",\n\t\"right\": \"Droite\",\n\t\"down\": \"Bas\",\n\t\"left\": \"Gauche\",\n\t\"up\": \"Haut\",\n\t\"painting_cat\": \"Peinture de Chat\",\n\t\"bk:axe\": \"Hache\",\n\t\"bk:axe_desc\": \"Il a promis de revenir\",\n\t\"bk:guitar\": \"Guitare\",\n\t\"bk:guitar_desc\": \"Elle est désaccordée\",\n\t\"bk:glass_sword\": \"Épée de verre\",\n\t\"bk:glass_sword_desc\": \"L'arme des maîtres\",\n\t\"bk:chicken\": \"Aile de Poulet\",\n\t\"bk:chicken_desc\": \"C'est chaud\",\n\t\"bk:pickaxe\": \"Pioche\",\n\t\"bk:pickaxe_desc\": \"Creuse, paysan!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"Demi Mana\",\n\t\"bk:lava_wand\": \"Baguette de lave\",\n\t\"bk:lava_wand_desc\": \"Matière chaude\",\n\t\"bk:web_wand\": \"Baguette de l'Araignée\",\n\t\"bk:web_wand_desc\": \"Fournisseur d'accès au web\",\n\t\"bk:slap_stick\": \"Bâton à claques\",\n\t\"bk:slap_stick_desc\": \"Slap\",\n\t\"sensivity\": \"Sensibilité\",\n\t\"no\": \"Non\",\n\t\"scale\": \"Taille\",\n\t\"ach_bk:ice\": \"L'ère glaciaire\",\n\t\"ach_bk:ice_desc\": \"Atteindre les Ruines Gelées\",\n\t\"ach_bk:library\": \"Les Textes Sacrés\",\n\t\"ach_bk:library_desc\": \"Accéder à la bibliothèque secrète\",\n\t\"bk:ice_skates\": \"Patins à glace\",\n\t\"bk:ice_skates_desc\": \"L'immunité à la glace\",\n\t\"bk:campfire_in_bottle\": \"Feu de camp en bouteille\",\n\t\"bk:campfire_in_bottle_desc\": \"Immunité au gel\",\n\t\"library\": \"Bibliothèque secrète\",\n\t\"ach_bk:cat_without_a_hat\": \"Un chat sans chapeau\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Trouver le tableau du chat\",\n\t\"ach_bk:rich\": \"Papier Toilette\",\n\t\"ach_bk:rich_desc\": \"Obtiens 99 pièces\",\n\t\"ach_bk:rescue_operation\": \"Opération de sauvetage\",\n\t\"ach_bk:rescue_operation_desc\": \"Sauver un PNJ\",\n\t\"ach_bk:tutorial\": \"Gourou\",\n\t\"ach_bk:tutorial_desc\": \"Terminer le tutoriel\",\n\t\"ach_bk:fancy_hat\": \"Chapeau fantaisie\",\n\t\"ach_bk:fancy_hat_desc\": \"Acheter un chapeau\",\n\t\"ach_bk:unlock\": \"Débloqueur\",\n\t\"ach_bk:unlock_desc\": \"Débloquer un objet\",\n\t\"floor_brightness\": \"Luminosité de la salle\",\n\t\"ach_bk:shielded\": \"Boucliers levés\",\n\t\"ach_bk:shielded_desc\": \"Obtenir un coeur-bouclier\",\n\t\"run_type\": \"Type de partie\",\n\t\"run_regular\": \"Normal\",\n\t\"run_challenge\": \"Challenge\",\n\t\"damage_taken\": \"Dégats subis\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Distance parcourue\",\n\t\"seed\": \"Seed\",\n\t\"score\": \"Score\",\n\t\"new_high_score\": \"Nouveau record!\",\n\t\"items_collected\": \"Objets collectés\",\n\t\"boss_rush\": \"Boss Rush\",\n\t\"run_bossrush\": \"Boss rush\",\n\t\"bk:blindfold_desc\": \"RIP mes armes\",\n\t\"bk:blindfold\": \"Les yeux bandés\",\n\t\"daily_run\": \"Le prochain commence dans\",\n\t\"builder_0_0\": \"Yeah\",\n\t\"builder_0_1\": \"J'ai besoin de mon argent pour moi\",\n\t\"builder_0\": \"Je prévois de construire un raccourci ici, mais j'ai encore besoin de [vr need] [ic 0] pièces. Tu peux m'aider?\",\n\t\"builder_1\": \"Mais tu n'as pas d'argent! :(\",\n\t\"builder_2\": \"Merci de votre investissement!\",\n\t\"builder_3\": \"J'ai enfin assez d'argent pour terminer le projet ! Merci beaucoup.!\",\n\t\"builder_4\": \"Okay, pardon!\",\n\t\"shortcut_is_broken\": \"Le raccourci est cassé\",\n\t\"ach_bk:boss_rush\": \"Boss Challenger\",\n\t\"ach_bk:boss_rush_desc\": \"Vaincre tous les bosses dans le mode Boss Rush\",\n\t\"ach_bk:daily\": \"Gloire Quotidienne\",\n\t\"ach_bk:daily_desc\": \"Relevez le défi quotidien\",\n\t\"ach_bk:desert_shortcut\": \"Raccourci vers le Palais du Désert\",\n\t\"ach_bk:desert_shortcut_desc\": \"Réparer le raccourci vers le Palais du Désert\",\n\t\"ach_bk:jungle_shortcut\": \"Raccourci vers la Jungle Ancienne\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Réparer le raccourci vers la Jungle Ancienne\",\n\t\"ach_bk:ice_shortcut\": \"Raccourci vers les Ruines Gelées\",\n\t\"ach_bk:ice_shortcut_desc\": \"Réparer le raccourci vers les Ruines Gelées\",\n\t\"ach_bk:library_shortcut\": \"Raccourci vers la Bibliothèque Secrète\",\n\t\"ach_bk:library_shortcut_desc\": \"Réparer le raccourci vers la Bibliothèque Secrète\",\n\t\"ach_bk:fashion_matters2\": \"La mode a son importance\",\n\t\"ach_bk:fashion_matters2_desc\": \"Acheter tous les chapeaux\",\n\t\"ach_bk:10_challenges\": \"Challenger\",\n\t\"ach_bk:10_challenges_desc\": \"Compléter 10 challenges\",\n\t\"ach_bk:20_challenges\": \"Challenger 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Compléter 20 challenges\",\n\t\"ach_bk:30_challenges\": \"Challenger 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Compléter 30 challenges\",\n\t\"ach_bk:bk_no_more\": \"Plus de BK\",\n\t\"ach_bk:bk_no_more_desc\": \"Vaincre le Burning Knight en personne\",\n\t\"ach_bk:dm_no_more\": \"Plus de MN\",\n\t\"ach_bk:dm_no_more_desc\": \"Vaincre le Mage Noir\",\n\t\"ach_bk:egor_no_more\": \"Plus de Egor\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Ah, et c'est reparti\",\n\t\"ach_bk:loop_desc\": \"Entrez dans la boucle\",\n\t\"coins_collected\": \"Pièces collectées\",\n\t\"bk:cup_head\": \"Cup Head\",\n\t\"bk:cup_head_desc\": \"Prendre une tasse de thé\",\n\t\"bk:mustache_hat\": \"Moustache\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Chapeau à hélices\",\n\t\"bk:propeller_hat_desc\": \"Ça tourne\",\n\t\"bk:sunglasses\": \"Lunettes de soleil\",\n\t\"bk:sunglasses_desc\": \"Marche avec la lune aussi!\",\n\t\"bk:cap\": \"Casquette\",\n\t\"bk:cap_desc\": \"Cool @-@\",\n\t\"bk:eyes\": \"Yeux\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Oeil\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Cheveux\",\n\t\"bk:hair_desc\": \"Fantaisie\",\n\t\"won\": \"Gagné\",\n\t\"won_message\": \"Tu as gagné!\",\n\t\"garderobe_sign\": \"Vestiaire\",\n\t\"darkmarket_tip\": \"~~[cl purple]Une Malédiction[cl] ou [cl yellow]30 pièces[cl]@@\",\n\t\"mike_0\": \"Il faut me payer [cl green]3 émeraudes\",\n\t\"mike_1\": \"Essaye boss rush contre [cl green]3 émeraudes[cl]!\",\n\t\"bk:weird_potion\": \"Potion Bizarre\",\n\t\"bk:weird_potion_desc\": \"Projectiles bizarres\",\n\t\"bk:megaphone\": \"Megaphone\",\n\t\"bk:megaphone_desc\": \"Projectiles à expansion\",\n\t\"scourge\": \"Malédiction\",\n\t\"scourge_stats\": \"Malédiction\",\n\t\"run_daily\": \"Quotidien\",\n\t\"completed_on\": \"Complété le\",\n\t\"complete\": \"Terminé\",\n\t\"next_daily_in\": \"[cl gray]La prochaine commence dans[cl]\",\n\t\"hours\": \"heures\",\n\t\"minutes\": \"minutes\",\n\t\"seconds\": \"secondes\",\n\t\"ach_bk:star\": \"La Vedette du Spectacle\",\n\t\"ach_bk:star_desc\": \"Obtiens 3 orbites\",\n\t\"ach_bk:family\": \"Petite famille heureuse\",\n\t\"ach_bk:family_desc\": \"Obtenir 3 animaux de compagnie\",\n\t\"ach_bk:return_to_sender\": \"Non Toi\",\n\t\"ach_bk:return_to_sender_desc\": \"Tuer un ennemi avec son propre projectile\",\n\t\"ach_bk:van_no_gogh\": \"Van No Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Détruire 100 peintures\",\n\t\"ach_bk:dark_market\": \"Cachette pour les criminels\",\n\t\"ach_bk:dark_market_desc\": \"Descendre dans le marché noir\",\n\t\"ach_bk:spikes\": \"Une question épineuse\",\n\t\"ach_bk:spikes_desc\": \"Active 100 piques en une seule partie\",\n\t\"ach_bk:white_flag\": \"Sans arme\",\n\t\"ach_bk:white_flag_desc\": \"Vaincre une salle sans utiliser une arme une seule fois\",\n\t\"quack\": \"[cl yellow]Coin![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfect\",\n\t\"bk_11\": \"JE TE PARDONNE POUR CETTE FOIS... MAIS ##N'ESSAYEZ PAS## DE RECOMMENCER!\",\n\t\"leaderboard\": \"Leaderboard\",\n\t\"display\": \"Affichage\",\n\t\"around_you\": \"Autour de vous\",\n\t\"friends\": \"Amis\",\n\t\"global\": \"Global\",\n\t\"loading\": \"Chargement\",\n\t\"generating\": \"Génération\",\n\t\"cursor_radius\": \"Rayon du curseur\",\n\t\"no_scores_yet\": \"Aucun résultat pour l'instant\",\n\t\"no_score_yet\": \"Aucun résultat pour l'instant\",\n\t\"run\": \"Partie\",\n\t\"top\": \"Top\",\n\t\"quick_restart\": \"Redémarrage Rapide\",\n\t\"painting_dungeon\": \"Donjon\",\n\t\"painting_goose\": \"Mini-Oie\",\n\t\"painting_chess\": \"Eléphant volant\",\n\t\"painting_peach\": \"Un arbre à pêche\",\n\t\"bk:no_lamp\": \"Pas de lampe\",\n\t\"bk:explosive_lamp\": \"Lampe explosive\",\n\t\"bk:explosive_lamp_desc\": \"Quand boom veut dire plus\",\n\t\"bk:shielded_lamp\": \"Lampe blindée\",\n\t\"bk:shielded_lamp_desc\": \"Boucliers levés!\",\n\t\"lamp\": \"Lampe\",\n\t\"bk:brain\": \"Méga Cerveau\",\n\t\"bk:brain_desc\": \"Taille de l'Esprit: Méga\",\n\t\"bk:heart_amulet\": \"Amulet en Coeur\",\n\t\"bk:heart_amulet_desc\": \"+1 à vos Coeurs\",\n\t\"bk:star_amulet_desc\": \"Mana Augmenté\",\n\t\"bk:star_amulet\": \"Amulette Étoilée\",\n\t\"bk:coin_amulet\": \"Amulette Pièces de monnaie\",\n\t\"bk:coin_amulet_desc\": \"Les pièces ont plus de valeur\",\n\t\"bk:key_amulet\": \"Amulette Clé\",\n\t\"bk:key_amulet_desc\": \"Les clés ont plus de valeur\",\n\t\"bk:bomb_amulet\": \"Amulet Explosive\",\n\t\"bk:bomb_amulet_desc\": \"Les bombes ont plus de valeur\",\n\t\"bk:eye_amulet\": \"Amulette Oculaire\",\n\t\"bk:eye_amulet_desc\": \"Ça fait mal de ne pas être précis\",\n\t\"bk:eye_patch\": \"Cache-Oeil\",\n\t\"bk:eye_patch_desc\": \"Vous-êtes prêts, les enfants ??\",\n\t\"bk:toilet_paper\": \"Papier Toilette\",\n\t\"bk:toilet_paper_desc\": \"Ça se termine toujours\",\n\t\"bk:decoy\": \"Leurre\",\n\t\"bk:decoy_desc\": \"Ça explose\",\n\t\"bk:wallet\": \"Banque de Compagnie\",\n\t\"bk:wallet_desc\": \"Stock vos pièces\",\n\t\"bk:skele_buddy\": \"Copain Squelette\",\n\t\"bk:skele_buddy_desc\": \"Effrayant \",\n\t\"bk:mega_bomb\": \"Mega Bombe\",\n\t\"bk:mega_bomb_desc\": \"Taille de la Bombe : Mega\",\n\t\"bk:condensed_milk\": \"Lait Condensé\",\n\t\"bk:condensed_milk_desc\": \"Pixels rapides - Ennemis lents\",\n\t\"bk:marshmallow\": \"Marshmallow\",\n\t\"bk:marshmallow_desc\": \"Collant\",\n\t\"bk:orbital_multiplier\": \"Multiplicateur Orbital\",\n\t\"bk:orbital_multiplier_desc\": \"Plus d'Orbites!\",\n\t\"bk:pet_multiplier\": \"Multiplicateur d'animaux de compagnie\",\n\t\"bk:pet_multiplier_desc\": \"Plus d'animaux!\",\n\t\"bk:ghost_bullets\": \"Balles Fantômes\",\n\t\"bk:ghost_bullets_desc\": \"Les murs ne les arrêteront pas\",\n\t\"bk:weight\": \"Poids Lourd\",\n\t\"bk:weight_desc\": \"Booster de gravité\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"À prendre ou à laisser\",\n\t\"bk:ethernal_d6\": \"Ethernel D6\",\n\t\"bk:ethernal_d6_desc\": \"Rerolls et\\/Ou Détruit\",\n\t\"bk:billiard\": \"Billard\",\n\t\"bk:billiard_desc\": \"Les balles rebondissent\",\n\t\"bk:enraged_bullets\": \"Balles Enragées\",\n\t\"bk:enraged_bullets_desc\": \"Les balles cassent les balles\",\n\t\"bk:rewind_button\": \"Bouton de Rembobinage\",\n\t\"bk:rewind_button_desc\": \"Attends\",\n\t\"bk:piggy_bank\": \"Tirelire\",\n\t\"bk:piggy_bank_desc\": \"Mes économies\",\n\t\"coins\": \"Pièces\",\n\t\"bk:death_star\": \"L'étoile de la mort\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Fer à souder\",\n\t\"bk:soldering_iron_desc\": \"C'est chaud\",\n\t\"bk:can\": \"Conserve\",\n\t\"bk:can_desc\": \"Projectiles doubles\",\n\t\"bk:swimming_mask\": \"Masque de Plongé\",\n\t\"bk:swimming_mask_desc\": \"C'est une arme secrète\",\n\t\"bk:bullet_chair\": \"Balle Chaise\",\n\t\"bk:bullet_chair_desc\": \"4 Pieds 4 Armes\",\n\t\"bk:cell\": \"Cellule\",\n\t\"bk:cell_desc\": \"Les projectiles se multiplient\",\n\t\"bk:brick\": \"iBrick\",\n\t\"bk:brick_desc\": \"Des niveaux plus grands\",\n\t\"bk:ring_of_pain\": \"Anneau de Douleur\",\n\t\"bk:ring_of_pain_desc\": \"Les dégâts sont infligés à tout le monde\",\n\t\"bk:schrodingers_cat\": \"Le Chat de Schrödingers\",\n\t\"bk:schrodingers_cat_desc\": \"Être ou ne pas être (50% de chance)\",\n\t\"bk:smoke_bomb\": \"Bombe Ninja\",\n\t\"bk:smoke_bomb_desc\": \"Une évasion inspirée par les Ninjia\",\n\t\"bk:chest_ring\": \"Bague du Coffre\",\n\t\"bk:chest_ring_desc\": \"Plus de Coffres!\",\n\t\"bk:empty_shell\": \"Coquille vide\",\n\t\"bk:empty_shell_desc\": \"Une chance de détruire les balles ennemies\",\n\t\"bk:parachute\": \"Parachute\",\n\t\"bk:parachute_desc\": \"Empêche les dégâts de chute\",\n\t\"bk:spiked_cookie\": \"Cookie Épiqués\",\n\t\"bk:spiked_cookie_desc\": \"Ca pique\",\n\t\"bk:shooty\": \"Shooty\",\n\t\"bk:shooty_desc\": \"Il tire\",\n\t\"bk:rabbit_bullets\": \"Balles Lapin\",\n\t\"bk:rabbit_bullets_desc\": \"Elles se multiplient\",\n\t\"bk:pandoras_box\": \"La Boîte de Pandore\",\n\t\"bk:pandoras_box_desc\": \"Conserve le Mal\",\n\t\"bk:bubbles\": \"Bulles\",\n\t\"bk:bubbles_desc\": \"L'ami des bulles\",\n\t\"bk:match\": \"Match\",\n\t\"bk:match_desc\": \"Tire pour tous les monde\",\n\t\"bk:hammer\": \"Marteau\",\n\t\"bk:hammer_desc\": \"Briseur d'armure\",\n\t\"bk:helmet\": \"Casque de fer\",\n\t\"bk:helmet_desc\": \"Une chance d'ignorer les dommages\",\n\t\"bk:beer\": \"Bière\",\n\t\"bk:beer_desc\": \"Enragés par les dégâts\",\n\t\"bk:the_eye\": \"L'Oeil\",\n\t\"bk:the_eye_desc\": \"Il regarde\",\n\t\"bk:mimics_tooth\": \"Dent de l'Imitateur\",\n\t\"bk:mimics_tooth_desc\": \"Attire les mimiques\",\n\t\"ach_bk:mimic\": \"Jump Scare\",\n\t\"ach_bk:mimic_desc\": \"Révèle une mimique\",\n\t\"bk:paper_airplane\": \"Avion en papier\",\n\t\"bk:paper_airplane_desc\": \"Missile à Tête Chercheuse\",\n\t\"ach_bk:ice_boss\": \"Laissez-le aller\",\n\t\"ach_bk:ice_boss_desc\": \"Tuez la Reine de Glace\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Ahem\",\n\t\"painting_agency\": \"Bienvenue à l'Qgence\",\n\t\"language\": \"Langue\",\n\t\"bk:pouch\": \"Poche\",\n\t\"bk:alien_glasses\": \"Lunettes Alien\",\n\t\"bk:alien_glasses_desc\": \"Je vois mieux\",\n\t\"inventory\": \"Inventaire\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Lampe précise\",\n\t\"bk:fragile_lamp\": \"Lampe fragile\",\n\t\"bk:fragile_lamp_desc\": \"K.O.en un coup\",\n\t\"painting_guitar\": \"Plus de volume!\",\n\t\"ach_bk:maanex\": \"Et tu, Brut ?\",\n\t\"ach_bk:maanex_desc\": \"Tue Maanex tout en portant son chapeau\",\n\t\"dad_0\": \"Hey fiston![dl] Je dois aller trouver [cl red]la Lampe [cl]. Je te laisse régner.\",\n\t\"dad_1\": \"Si je ne reviens pas, ne viens pas me chercher. Salut!\",\n\t\"son_0\": \"##NOOOOOOON##\",\n\t\"gobbo_0\": \"Fiston, [cl green]mon père[cl] est parti il y a 20 ans. Je dois le retrouver.\",\n\t\"gobbo_1\": \"Je te laisse régner. Salut!\",\n\t\"dm_5\": \"Une nouvelle et ^^meilleure^^ [cl red]marionette[cl]![dl] ##MUHAHAHA##\",\n\t\"dm_6\": \"M'entends-tu, [cl red]Limpor?\",\n\t\"heinur_0\": \"##NON[dl], PAS ENCORE!##\",\n\t\"nbk_0\": \"##OUI, MON MAÎTRE##\",\n\t\"bk_12\": \"##JE N'AI PLUS DE ROI EN STOCK, AFFRONTE-MOI DONC, IDIOT!##\",\n\t\"bk:headshot_gun\": \"Pistolet courbé\",\n\t\"bk:headshot_gun_desc\": \"Headshot\",\n\t\"bk:laser_cannon\": \"Canon laser\",\n\t\"bk:laser_cannon_desc\": \"Haha, laser go pew pew\",\n\t\"credits\": \"Crédits\",\n\t\"head_0\": \"Idiot\",\n\t\"tech\": \"Techno\",\n\t\"ach_bk:collector\": \"Collectionneur\",\n\t\"ach_bk:collector_desc\": \"Débloque tous les items\",\n\t\"bk:treasure_key\": \"Clé rouge\",\n\t\"bk:treasure_key_desc\": \"Ouvre des échappatoires\",\n\t\"bk:pass\": \"Laisser-Passer\",\n\t\"bk:pass_desc\": \"Identifiez-vous!\",\n\t\"bk:bucket\": \"Seau\",\n\t\"bk:bucket_desc\": \"Inutile sans le contenu\",\n\t\"bk:water_bucket\": \"Seau d'eau\",\n\t\"bk:water_bucket_desc\": \"Calme [cl red]le Feu[cl]\",\n\t\"bk:snow_bucket\": \"Seau de neige\",\n\t\"bk:snow_bucket_desc\": \"Peut-être, que ça peut fondre\",\n\t\"m2_0\": \"Je ne vais jamais pouvoir récupérer financièrement de cette perte\",\n\t\"m2_1\": \"Bien joué!\",\n\t\"m2_2\": \"Hey mec, ça te dirait de mettre tes %%skills%% ^^à l'epreuve^^?\",\n\t\"m2_3\": \"Utilise ^^%%l'Ordinateur%%^^ pour controler le grappin!\",\n\t\"maanex2_0_0\": \"Prends mon argent!\",\n\t\"maanex2_0_1\": \"Pas cette fois, merci.\",\n\t\"maanex2_0\": \"Okay, Donne-moi [cl yellow][vr cost] pièces [cl] et tu peux essayer le grappin!\",\n\t\"dm_7\": \"Jouons un jeu\",\n\t\"bkw_0\": \"UN AUTRE [cl red]INTRUS[cl]!\",\n\t\"bkw_1\": \"##VAS-T'EN##[dl], OU JE M'EN CHARGE!\",\n\t\"bkw_2\": \"Je suis à la recherche de [cl green]mon père\",\n\t\"bkw_3\": \"JE T'AURAIS _PRÉVENU_\",\n\t\"spanish_inquisition\": \"[cl red]L'Inquisition Espagnole\",\n\t\"lp_0\": \"Bien joué, [cl purple]Ritta[cl][dl], réinitialisation de [cl green]la simulation[cl][dl].[dl].[dl].\",\n\t\"bk:broken_bucket\": \"Seau cassé\",\n\t\"bk:broken_bucket_desc\": \"Protecc\",\n\t\"bk:ankh\": \"Ankh\",\n\t\"bk:ankh_desc\": \"Vie éternelle\",\n\t\"bk:broken_ankh\": \"Ankh cassé\",\n\t\"bk:broken_ankh_desc\": \"Vie éternelle?\",\n\t\"bk:what\": \"Quoi\",\n\t\"bk:what_desc\": \"sérieusement, QUOI?\",\n\t\"bk:gold_minigun\": \"Minigun doré\",\n\t\"bk:gold_minigun_desc\": \"Haha budget go brrr\",\n\t\"bk:gold_dagger\": \"Dague dorée\",\n\t\"bk:gold_dagger_desc\": \"Vieille mais dorée\",\n\t\"bk:gold_revolver\": \"Revolver doré\",\n\t\"bk:gold_revolver_desc\": \"Couvrez-moi d'or\",\n\t\"bk:gold_axe\": \"Hache dorée\",\n\t\"bk:gold_axe_desc\": \"Juste une hache\",\n\t\"painting_code\": \"Code\",\n\t\"bk:katana\": \"Katana\",\n\t\"bk:katana_desc\": \"Qui est [cl orange]le propriétaire[cl]?\",\n\t\"bk:smart_gun\": \"Pistolet intelligent\",\n\t\"bk:smart_gun_desc\": \"Il sait\",\n\t\"bk:pop_gun\": \"Pop Gun\",\n\t\"bk:pop_gun_desc\": \"Très populaire\",\n\t\"bk:the_button\": \"Le Bouton\",\n\t\"bk:the_button_desc\": \"Attaque dans 8 directions\",\n\t\"bk:gold_sword\": \"Epée dorée\",\n\t\"bk:gold_sword_desc\": \"Quand tu ne sais plus comment dépenser ton argent\",\n\t\"bk:donut\": \"Donut\",\n\t\"bk:donut_desc\": \"N'hésite-pas\",\n\t\"bk:sudoku\": \"Sudoku\",\n\t\"bk:sudoku_desc\": \"La moitié de la salle a disparu, réduite en atomes\",\n\t\"bk:gps_ring\": \"Anneau GPS\",\n\t\"bk:gps_ring_desc\": \"Une chance de révéler l'étage\",\n\t\"bk:shield_potion\": \"Potion Bouclier\",\n\t\"bk:shield_potion_desc\": \"Grosse gorgée de Jus de bouclier \",\n\t\"bk:trash_generator\": \"Générateur d'ordures\",\n\t\"bk:trash_generator_desc\": \"Oui.\",\n\t\"bk:crabs_claw\": \"Pince de crabe\",\n\t\"bk:crabs_claw_desc\": \"Détruit toutes les armures\",\n\t\"eg_3\": \"Belle journée, Monsieur\",\n\t\"eg_0_0\": \"Prendre ^^[cl lime]ces émeraudes[cl]^^\",\n\t\"eg_0_1\": \"Les laisser\",\n\t\"eg_0\": \"Prends [cl lime]mes émeraudes[cl], je t'en supplie!\",\n\t\"eg_1\": \"Je m'en vais\",\n\t\"bk:reverse_card\": \"Carte Inversion\",\n\t\"bk:reverse_card_desc\": \"Rouler à travers les projectiles les dévie\",\n\t\"bk:magnet\": \"Aimant\",\n\t\"bk:magnet_desc\": \"Attraction & Affection\",\n\t\"bk:glowing_mushroom\": \"Champignon brillant\",\n\t\"bk:glowing_mushroom_desc\": \"Il est vibrant\",\n\t\"bk:tinfoil_hat\": \"Chapeau en papier d'aluminium\",\n\t\"bk:tinfoil_hat_desc\": \"Tu te sens en sécurité\",\n\t\"bk:rear_window\": \"Vitre arrière\",\n\t\"bk:rear_window_desc\": \"Regarde derrière toi\",\n\t\"bk:refractor\": \"Réfracteur\",\n\t\"bk:refractor_desc\": \"Une chance d'attaquer dans toutes les directions\",\n\t\"bk:fork\": \"Fourchette\",\n\t\"bk:fork_desc\": \"Ça fait mal\",\n\t\"bk:rock\": \"Rocher\",\n\t\"bk:rock_desc\": \"Les dégâts ont un coût\",\n\t\"bk:coffee_grinder\": \"Moulin à café\",\n\t\"bk:coffee_grinder_desc\": \"Projectiles petits & rapides \",\n\t\"integrations\": \"Integrations\",\n\t\"twitch\": \"Twitch\",\n\t\"streamer_username\": \"Pseudo du Twitcher\",\n\t\"bk:shawarma\": \"Shwarma\",\n\t\"bk:shawarma_desc\": \"Parfois les projectiles sont plus gros\",\n\t\"bk:cats_ear\": \"Oreille de chat\",\n\t\"bk:cats_ear_desc\": \"Esquive de malade\",\n\t\"luck\": \"Chance\",\n\t\"bk:gamepad\": \"Gamepad\",\n\t\"bk:gamepad_desc\": \"FPS stable\",\n\t\"bk:hotdog\": \"Hotdog\",\n\t\"bk:bomb_shell\": \"Obus\",\n\t\"bk:bomb_shell_desc\": \"Santé étrange\",\n\t\"painting_no_idea\": \"No Idea\",\n\t\"painting_tinkerer\": \"Tinkerer\",\n\t\"painting_in_loving_memory_of_ali\": \"In loving memory of Ali\",\n\t\"painting_happy_accident\": \"Happy Accident\",\n\t\"painting_observing_cheese\": \"Observing Cheese\",\n\t\"painting_chicken_enemy_unknown\": \"Chicken Enemy Unknown\",\n\t\"painting_know_stuff\": \"Know Stuff\",\n\t\"painting_whoops\": \"Whoops\",\n\t\"painting_too_lake\": \"Too Lake\",\n\t\"painting_step_through\": \"Threshold\",\n\t\"painting_thats_a_moon\": \"That's a moon\",\n\t\"painting_totem\": \"Magic Circle\",\n\t\"painting_too_late\": \"Too Late\",\n\t\"painting_whipped_cream\": \"Whipped Cream\",\n\t\"painting_beet_boys\": \"Beet Bois\",\n\t\"painting_moonshine\": \"Moonshine\",\n\t\"painting_void\": \"The Void\",\n\t\"painting_peasants\": \"Peasants\",\n\t\"quality\" : \"Qualité\",\n\t\"20_years_later\" : \"20 ans plus tard\"\n}\n"
  },
  {
    "path": "BurningKnight/Content/Locales/it.json",
    "content": "{\n\t\"bk:halo\": \"aureola\",\n\t\"bk:halo_desc\": \"Vita su\",\n\t\"bk:revolver\": \"Revolver\",\n\t\"bk:sword\": \"Spada di legno\",\n\t\"bk:sword_desc\": \"Non solamente un bastone\",\n\t\"bk:heart\": \"Cuore\",\n\t\"resume\": \"Continua\",\n\t\"settings\": \"Opzioni\",\n\t\"restart\": \"Ricomincia\",\n\t\"death_message\": \"Sei morto\",\n\t\"descend\": \"Scendi\",\n\t\"ascend\": \"Sali\",\n\t\"exit\": \"esci\",\n\t\"painting_rexcellent\": \"rexcellent\",\n\t\"painting_grannylisa\": \"Nonnalisa\",\n\t\"painting_maanex\": \"maanex il Pensatore\",\n\t\"painting_bk\": \"Cavaliere arrostito\",\n\t\"painting_failpositive\": \"Festeggiatore Seriale\",\n\t\"painting_old_man\": \"Un Uomo Molto Vecchio\",\n\t\"painting_arthouse\": \"Casa dell'Arte\",\n\t\"painting_black\": \"Universo\",\n\t\"painting_milt\": \"Ragazzo nella neve\",\n\t\"painting_skyscraper\": \"Grattacielo solitario\",\n\t\"painting_egor\": \"Rex infuocato\",\n\t\"painting_null\": \"NULL\",\n\t\"painting_badosz\": \"Ragazzo perso nel bosco\",\n\t\"painting_banana\": \"BANANA\",\n\t\"painting_tv\": \"TV nel cielo\",\n\t\"painting_company\": \"Buona compagnia\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"cane du Trasevol\",\n\t\"painting_lamp\": \"Prendila\",\n\t\"painting_scream\": \"Gelato\",\n\t\"painting_stars\": \"Notte stellata\",\n\t\"painting_fog\": \"Nei mari\",\n\t\"painting_nufflee\": \"Bau\",\n\t\"by\": \"da\",\n\t\"old_man_0\": \"E' pericoloso!\",\n\t\"continue_run\": \"Continua la Partita\",\n\t\"new_run\": \"Nuova Partita\",\n\t\"was_unlocked\": \"E' stata sbloccata!\",\n\t\"bk:revolver_desc\": \"Mani in alto, @everyone!\",\n\t\"bk:shovel\": \"Pala blu\",\n\t\"bk:shovel_desc\": \"Ma perche' e blu???\",\n\t\"beet_0\": \"Ciao!\",\n\t\"beet_2\": \"seed:\",\n\t\"npc_hurt_0\": \"Ouch.\",\n\t\"npc_hurt_1\": \"Hei fa male.\",\n\t\"npc_hurt_2\": \"Oh no.\",\n\t\"beet_3\": \"Grazie <3\",\n\t\"beet_1\": \"Vuoi piantare un seme ^^seme^^?\",\n\t\"beet_1_0\": \"Si!\",\n\t\"beet_1_1\": \"No.\",\n\t\"beet_4\": \"il seme e' [vr seed]. Lo vuoi cambiare?\",\n\t\"beet_4_0\": \"Si!\",\n\t\"beet_4_1\": \"No.\",\n\t\"beet_5\": \"Vabbe.\",\n\t\"beet_4_2\": \"Mettilo a caso!\",\n\t\"beet_6\": \"Ok. il seme e' [vr seed]!\",\n\t\"bk:idol\": \"Idol\",\n\t\"bk:idol_desc\": \"Una trappola nascosta si e' attivata!\",\n\t\"bk:key\": \"Chiave d'oro\",\n\t\"bk:infinite_bomb\": \"Bombe infinite\",\n\t\"bk:infinite_bomb_desc\": \"Bombe riusabili\",\n\t\"throw_coin\": \"Lancia una moneta\",\n\t\"bk:potatoo\": \"Patata\",\n\t\"bk:potatoo_desc\": \"Proiettili che si dividonooo\",\n\t\"bk:spectacles\": \"occhiali magici\",\n\t\"bk:spectacles_desc\": \"Rivela segreti\",\n\t\"bk:cross\": \"Croce\",\n\t\"bk:cross_desc\": \"aumenta periodo di invincibilita\",\n\t\"bk:slime\": \"Slime\",\n\t\"bk:slime_desc\": \"Proiettili rimbalzanti\",\n\t\"bk:missile\": \"Missile\",\n\t\"bk:missile_desc\": \"teleguidati\",\n\t\"bk:rod_of_discord\": \"bacchetta della Discordia\",\n\t\"bk:rod_of_discord_desc\": \"Teletrasportatore per @everyone\",\n\t\"bk:goo\": \"Goo\",\n\t\"bk:goo_desc\": \"Amico orbitante\",\n\t\"bk:jelly\": \"Gelatina!\",\n\t\"bk:jelly_desc\": \"^^Rimbalzoso^^\",\n\t\"bk:broken_stone\": \"Pietra rotta\",\n\t\"bk:broken_stone_desc\": \"Orbitale ben fatto\",\n\t\"bk:nano_orb\": \"Orb nano\",\n\t\"bk:nano_orb_desc\": \"Micro amici\",\n\t\"bk:saturn\": \"Pianeta\",\n\t\"bk:saturn_desc\": \"Of course we still love it\",\n\t\"bk:soap\": \"Sapone\",\n\t\"bk:soap_desc\": \"Rallenta i tuoi proiettili\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"^^Ripesca^^ oggetti!\",\n\t\"bk:my_heart\": \"Il mio cuore\",\n\t\"bk:my_heart_desc\": \"Salute su\",\n\t\"bk:broken_heart\": \"Cuore spezzato\",\n\t\"bk:broken_heart_desc\": \"salute su\",\n\t\"bk:parcel\": \"Pacco\",\n\t\"bk:parcel_desc\": \"Cura riusabile\",\n\t\"bk:glass\": \"Vetro\",\n\t\"bk:glass_desc\": \"Proiettili ##Fragili##\",\n\t\"bk:glass_bullet\": \"Proiettili di vetro\",\n\t\"bk:glass_bullet_desc\": \"Spaccavetri\",\n\t\"bk:broken_guitar\": \"Chitarra rotta\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Mitragloatrice\",\n\t\"bk:machine_gun_desc\": \"Automatica\",\n\t\"bk:grenade_launcher\": \"Lanciagranate\",\n\t\"bk:grenade_launcher_desc\": \"Kaboom!\",\n\t\"bk:shotgun\": \"fucile\",\n\t\"bk:shotgun_desc\": \"Sale in faccia!\",\n\t\"bk:missile_launcher\": \"Lancia missili\",\n\t\"bk:missile_launcher_desc\": \"Obbiettivo agganciato!\",\n\t\"bk:burst_gun\": \"Burst Gun\",\n\t\"bk:burst_gun_desc\": \"Velocita' della luce\",\n\t\"bk:flak_cannon\": \"Cannone antiaereo\",\n\t\"bk:flak_cannon_desc\": \"e' tempo di festa!\",\n\t\"bk:disk_gun\": \"Pistola lanciadisco\",\n\t\"bk:disk_gun_desc\": \"Roba affilata\",\n\t\"bk:duck_gun\": \"Pistola papera\",\n\t\"bk:duck_gun_desc\": \"quack!\",\n\t\"bk:follower\": \"Seguace\",\n\t\"bk:follower_desc\": \"Seguimi!\",\n\t\"bk:portal_gun\": \"Portal Gun\",\n\t\"bk:portal_gun_desc\": \"Cake is a lie\",\n\t\"bk:snowflake\": \"Fiocco di neve\",\n\t\"bk:snowflake_desc\": \"Fermi tutti!\",\n\t\"bk:restock\": \"Rifornimenti\",\n\t\"bk:restock_desc\": \"scorte infinite al negozio\",\n\t\"bk:charisma_ring_desc\": \"Sconti regali\",\n\t\"bk:charisma_ring\": \"Anello del carisma\",\n\t\"bk:battery\": \"Batteria\",\n\t\"tomb_0\": \"Qui giace [cl green]Gobbo[cl] il grande\",\n\t\"bk:homemade_dice\": \"Dado fatto in casa\",\n\t\"bk:homemade_dice_desc\": \"^^R^^ items! (DIY)\",\n\t\"shopkeeper_0\": \"##TI AVEVO DETTO DI NON FARLO!##\",\n\t\"shopkeeper_1\": \"Per favore fermati!\",\n\t\"shopkeeper_2\": \"Non lo fare.\",\n\t\"shopkeeper_3\": \"[cl red]##PREPARATI A MORIRE!##\",\n\t\"shopkeeper_4\": \"[cl red]LADRO!\",\n\t\"shopkeeper_5\": \"[cl red]PRENDETELO!\",\n\t\"desert\": \"Palazzo del deserto\",\n\t\"jungle\": \"Giungla antica\",\n\t\"ice\": \"Rovine Ghiacciate\",\n\t\"bk:iron_boots\": \"Stivali di ferro\",\n\t\"bk:iron_boots_desc\": \"Le trappole non mi faranno piu paura\",\n\t\"bk:mimic_totem\": \"Totem dei mimic\",\n\t\"bk:mimic_totem_desc\": \"##NIENTE PIU' MIMIC##\",\n\t\"back_to_town\": \"Torna al villaggio'\",\n\t\"bk:glass_gun\": \"pistola di vetro\",\n\t\"bk:glass_gun_desc\": \"##Fragile##\",\n\t\"bk:glass_shard\": \"frammenti do vetro\",\n\t\"bk:glass_shard_desc\": \"solo un pezzo dell totale\",\n\t\"bk:dagger\": \"Pugnale\",\n\t\"bk:dagger_desc\": \"Nostalgia...\",\n\t\"bk:spear\": \"Lancia\",\n\t\"bk:spear_desc\": \"Braccia piu lunghe?\",\n\t\"shopkeeper_6\": \"Benvenuto :)\",\n\t\"shopkeeper_7\": \"Hei, vuoi un po di [cl yellow]te'[cl]?\",\n\t\"shopkeeper_8\": \"come va?\",\n\t\"back\": \"indietro\",\n\t\"master_volume\": \"Principale\",\n\t\"music\": \"Musica\",\n\t\"sfx\": \"Effetti audio\",\n\t\"graphics\": \"Grafica\",\n\t\"audio\": \"Audio\",\n\t\"ui_sfx\": \"Suoni interfaccia\",\n\t\"on\": \"On\",\n\t\"off\": \"Off\",\n\t\"fullscreen\": \"Schermo intero\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Contatore FPS\",\n\t\"speedrun_timer\": \"Speedrun Timer\",\n\t\"screenshake\": \"Screen Shake\",\n\t\"reset_progress\": \"Reset dei Progressi\",\n\t\"blood_n_gore\": \"Sangue\",\n\t\"vegan_mode\": \"Modalita' vegana\",\n\t\"reset_settings\": \"Reset delle opzioni\",\n\t\"are_you_sure\": \"Sicuro?\",\n\t\"yes\": \"Si\",\n\t\"reset_progress_dis\": \"Cancellerai tutti i tuoi progressi!\",\n\t\"reset_settings_dis\": \"Fara' il reset di TUTTE le impostazioni!\",\n\t\"autosave\": \"Salvataggio automatico\",\n\t\"autopause\": \"Pausa automatica\",\n\t\"input\": \"Input\",\n\t\"use\": \"Usa\",\n\t\"active\": \"Attiva\",\n\t\"bomb\": \"Bomba\",\n\t\"interact\": \"Interagisci\",\n\t\"swap\": \"Cambia arma\",\n\t\"roll\": \"Rotola\",\n\t\"duck\": \"Accucciati\",\n\t\"pause\": \"Pausa\",\n\t\"none\": \"Nessuno\",\n\t\"keyboard_controls\": \"Controlli tastiera\",\n\t\"gamepad_controls\": \"Controlli gamepad\",\n\t\"keyboard\": \"Tastieta\",\n\t\"gamepad\": \"Gamepad\",\n\t\"game\": \"Gioco\",\n\t\"select\": \"Seleziona\",\n\t\"cursor\": \"Cursore\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"muori\",\n\t\"ach_bk:overshake\": \"Overshake\",\n\t\"ach_bk:overshake_desc\": \"1000% screen shake\",\n\t\"ach_bk:rip\": \"Obbiettivo piu' poplare\",\n\t\"bk:emerald\": \"Smeraldo\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Grazie!^^\",\n\t\"shopkeeper_11\": \"che %%affare%%!\",\n\t\"shopkeeper_12\": \"Vuoi [cl red]comprare[cl] ^^qualcosa^^?\",\n\t\"shopkeeper_13\": \"solo per [cl green]te[cl], solo oggi!\",\n\t\"shopkeeper_14\": \"Che [cl yellow]offerte[cl]!\",\n\t\"bk:magnifier\": \"Lente d'ingrandimento\",\n\t\"bk:magnifier_desc\": \"Proietti piu' grandi\",\n\t\"bk:mushroom_hat\": \"Cappello fungo\",\n\t\"bk:mushroom_hat_desc\": \"Gustoso?\",\n\t\"bk:stone_hat\": \"cappello di pietra\",\n\t\"bk:stone_hat_desc\": \"Pesante\",\n\t\"bk:knight_hat\": \"elmo del cavaliere\",\n\t\"bk:knight_hat_desc\": \"Buoni vecchi nemici ...\",\n\t\"bk:cowboy_hat\": \"Cappello del cowboy\",\n\t\"bk:cowboy_hat_desc\": \"Wild west!\",\n\t\"bk:soup_hat\": \"Cappello zuppa\",\n\t\"bk:soup_hat_desc\": \"^^Yummy^^\",\n\t\"bk:gold_hat\": \"Cappello d'oro\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Ricco!\",\n\t\"bk:viking_hat\": \"Cappello del vichingo\",\n\t\"bk:viking_hat_desc\": \"America!\",\n\t\"bk:dunce_hat\": \"Cappello dell'asino\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Cilindro\",\n\t\"bk:top_hat_desc\": \"Fashion!\",\n\t\"bk:ushanka\": \"Ushanka\",\n\t\"bk:ushanka_desc\": \"Dov' e' la mia ##balalaika?##\",\n\t\"bk:valkyrie_hat\": \"Cappello della valchiria\",\n\t\"bk:valkyrie_hat_desc\": \"I belive ^^I can fly!^^\",\n\t\"bk:skull_hat\": \"Cappello teschio\",\n\t\"bk:skull_hat_desc\": \"I soldi o la vita!\",\n\t\"bk:grandma_head\": \"Cappello della nonna\",\n\t\"bk:grandma_head_desc\": \"Te'?\",\n\t\"bk:diamond_helmet\": \"Elmo di Diamante\",\n\t\"bk:diamond_helmet_desc\": \"Zitto e scava!\",\n\t\"bk:villager_head\": \"Testa del villico\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fez\",\n\t\"bk:fez_desc\": \"Cubit\",\n\t\"bk:no_hat\": \"Togli il cappello\",\n\t\"bk:no_hat_desc\": \"Nessun cappello - nessun problema!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"Attempt to call a null value\",\n\t\"accessorytrader_0\": \"##VIA DI QUI!## [dl]O compra questi ^^deliziosi^^ oggetti a soli ^^%%99 diamanti l'uno%%^^!\",\n\t\"accessorytrader_1\": \"Ciao\",\n\t\"accessorytrader_2\": \"Hei!\",\n\t\"weapontrader_0\": \"Vieni dentro!\",\n\t\"weapontrader_1\": \"Buona giornata, signore!\",\n\t\"weapontrader_2\": \"Hai voglia di comprare qualcosa?\",\n\t\"activetrader_0\": \"Migliori offerte sul mercato!\",\n\t\"activetrader_1\": \"Paghi due e prendi due!\",\n\t\"activetrader_2\": \"voglio ciambelle, [dl]perpiacere perfavore!!\",\n\t\"hattrader_0\": \"vuoi essere figo quanto me? [dl]Compra dei cappelli!\",\n\t\"hattrader_1\": \"vuoi essere figo quanto me? [dl]anch'io bimbo.\",\n\t\"hattrader_2\": \"^^Ha ha cappelli!^^\",\n\t\"granny_0\": \"Wuoi del te'?\",\t\n\t\"granny_1\": \"Fai una pausa te'!\",\n\t\"granny_2\": \"Te'?\",\n\t\"bk:xmas_hat\": \"Cappello di Babbo natale\",\n\t\"bk:xmas_hat_desc\": \"Buon natale!\",\n\t\"bk:pumpkin_hat\": \"Zucca intagliata\",\n\t\"bk:pumpkin_hat_desc\": \"^^Spooky spooky skeleton^^\",\n\t\"bk:cage_key\": \"Chiave della prigione\",\n\t\"bk:cage_key_desc\": \"Salva ^^il tipo^^!\",\n\t\"npc_0\": \"Aiuto! Trova la chiave!\",\n\t\"npc_1\": \"Grazie per avermi salvato!\",\n\t\"npc_2\": \"Veloce! Apri la porta!\",\n\t\"npc_3\": \"Ti prego! aiuto!\",\n\t\"control_0\": \"Premi [ic 0][ic 1] per posizionare una bomba\",\n\t\"control_1\": \"Rotola! Premi [ic 0][ic 1] per rotolare!\",\n\t\"control_2\": \"Premi [ic 0][ic 1] per attaccare\",\n\t\"control_3\": \"Premi [ic 0][ic 1] per interagire\",\n\t\"control_4\": \"Qua? [ic 0][ic 1]!\",\n\t\"control_5\": \"Premi [ic 0][ic 1] per cambiare arma\",\n\t\"shopkeeper_15\": \"Niente sconto per te!\",\n\t\"shopkeeper_16\": \"Trova altri soldi e torna qui!\",\n\t\"shopkeeper_17\": \"Prima devi pagare!\",\n\t\"bk:frog\": \"Tele Rana\",\n\t\"bk:frog_desc\": \"Viaggio rapido?\",\n\t\"bk:sword_orbital\": \"Spada Orbitante\",\n\t\"bk:sword_orbital_desc\": \"Giustizia\",\n\t\"robbed\": \"Derubato\",\n\t\"bk:gift_desc\": \"Cosa c'e' dentro?\",\n\t\"bk:spike_ring\": \"Anello acuminato\",\n\t\"bk:spike_ring_desc\": \"I tuoi nemici devono essere ##puniti##!\",\n\t\"bk:fire_ring\": \"Anello di fuoco\",\n\t\"bk:fire_ring_desc\": \"Lascia che i tuoi nemici brucino\",\n\t\"bk:ice_ring\": \"Anello di ghiaccio\",\n\t\"bk:ice_ring_desc\": \"Ghiaccia i tuoi nemici\",\n\t\"bk:duck_ring\": \"Anello papera\",\n\t\"bk:duck_ring_desc\": \"Ti teletrasporta se ti fanno male\",\n\t\"bk:dull_blade\": \"Lama dalla punta arrotondata\",\n\t\"bk:dull_blade_desc\": \"Finto autolesionista\",\n\t\"bk:sharp_blade\": \"Lama affilata\",\n\t\"bk:sharp_blade_desc\": \"Attento che taglia\",\n\t\"bk:obsidian_shield\": \"Scudo di ossidiana\",\n\t\"bk:obsidian_shield_desc\": \"Contraccolpo = 0\",\n\t\"bk:bill\": \"Banconota\",\n\t\"bk:bill_desc\": \"99 dollari\",\n\t\"control_6\": \"Usa un oggetto attivo con [ic 0][ic 1]\",\n\t\"bk:clover\": \"Quadrifoglio\",\n\t\"bk:clover_desc\": \"Fortunato!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^Ripesca %%i tuoi artefatti%%!^^\",\n\t\"brastin_0\": \"trova il quadro del [cl purple]gatto[cl]!\",\n\t\"elon_1\": \"Ecco qua, divertiti\",\n\t\"bk:maanex_head\": \"Testa di Maanex\",\n\t\"bk:maanex_head_desc\": \"Hmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Fa pensare i nemici\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Map Greenprints\",\n\t\"bk:map_greenprints_desc\": \"Rivela la mappa\",\n\t\"bk:map\": \"Mappa\",\n\t\"bk:map_desc\": \"Rivela la mappa per sempre\",\n\t\"milt_1\": \"Voglio un regalo\",\n\t\"mapuzzle_0\": \"Gravita'.\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Copiato!\",\n\t\"isaac_0\": \"La vita non ha sensooo...\",\n\t\"isaac_1\": \"Percheeeeeeee\",\n\t\"isaac_2\": \":sob:\",\n\t\"discord_0\": \"Vieni a salutarci! discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"rotola, stolto!\",\n\t\"tutorial\": \"Tutorial\",\n\t\"bk:crying_bomb\": \"Bomba Piangente\",\n\t\"bk:crying_bomb_desc\": \"Adesso anche le bombe piangono!\",\n\t\"bk:matches\": \"Fiammiferi\",\n\t\"bk:matches_desc\": \"Tempo di esplosione piu breve\",\n\t\"bk:bomb_pack\": \"Pacco di bombe\",\n\t\"bk:bomb_pack_desc\": \"Abbiamo messo bombe nelle nostre bombe!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 bombe\",\n\t\"bk:weird_mushroom_desc\": \"Raddoppia tutto\",\n\t\"bk:weird_mushroom\": \"Che strano fungo\",\n\t\"bk:bomb_shower\": \"Pioggia di bombe\",\n\t\"bk:bomb_shower_desc\": \"Piovono bombee\",\n\t\"bk:black_belt\": \"Cintura nera\",\n\t\"bk:black_belt_desc\": \"Non esplodere piu'\",\n\t\"bk:ninjia_bomb\": \"Bombe Ninjia\",\n\t\"bk:ninjia_bomb_desc\": \"Essere colpiti fa apparire bombe\",\n\t\"start_new_run\": \"La partita corrente andra' persa!\",\n\t\"bk:laser_pointer\": \"Puntatore laser\",\n\t\"bk:laser_pointer_desc\": \"La mira e' piu chiara!\",\n\t\"ach_bk:marauder\": \"Assassino\",\n\t\"ach_bk:marauder_desc\": \"Uccidi il negoziante!\",\n\t\"ach_bk:treasure_hunter\": \"Cacciatore di tesori!\",\n\t\"ach_bk:treasure_hunter_desc\": \"Trova la stanza segreta\",\n\t\"ach_bk:dodge_master\": \"Maestro dello schivo\",\n\t\"ach_bk:dodge_master_desc\": \"Uccidi un boss senza essere colpito\",\n\t\"ach_bk:dodge_overlord\": \"Padrone supremo dello schivo\",\n\t\"ach_bk:dodge_overlord_desc\": \"Finisci un livello senza mai colpito\",\n\t\"ach_bk:quackers\": \"Quackers\",\n\t\"ach_bk:quackers_desc\": \"Overquack\",\n\t\"ach_bk:tea_party\": \"Tea Party\",\n\t\"ach_bk:tea_party_desc\": \"Fai merenda con la nonna\",\n\t\"ach_bk:not_a_thief\": \"Non un ladro\",\n\t\"ach_bk:not_a_thief_desc\": \"Finisci una partita senza prendere nessun oggetto\",\n\t\"ach_bk:npc_party2\": \"NPC Party\",\n\t\"ach_bk:npc_party2_desc\": \"salva tutti gli NPCs\",\n\t\"bk:gold_coin\": \"Moneta d'oro\",\n\t\"bk:iron_coin\": \"Moneta d'argento\",\n\t\"bk:copper_coin\": \"Moneta di rame\",\n\t\"bk:platinum_coin\": \"Moneta di platino\",\n\t\"bk:voodoo_doll\": \"Bambola voodoo\",\n\t\"bk:voodoo_doll_desc\": \"Uccide tutti i nemici nella stanza\",\n\t\"hub\": \"Citta della schivata\",\n\t\"castle\": \"Le rovine del castello\",\n\t\"charger_0\": \"NESSUN OGGETTO ATTIVO RILEVATO\",\n\t\"charger_1\": \"L'OGGETTO ATTIVO E' GIA CARICO\",\n\t\"charger_2\": \"DOVE SONO I MIEI SOLDI?!\",\n\t\"charger_3\": \"##HO DETTO DAMMI I MIEI SOLDI!##\",\n\t\"charger_4\": \"##CONQUISTERO' IL MONDO!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Certo, facciamolo!\",\n\t\"maanex_6_1\": \"Nah.\",\n\t\"maanex_6\": \"Ok, dammi [cl yellow][vr cost] monete[cl] e ti lasciero' aprire uno di questi scrigni. Ok?\",\n\t\"maanex_5\": \"Hey amico, vuoi ^^tentare^^ la fortuna?\",\n\t\"maanex_7\": \"E' stato divertente!\",\n\t\"maanex_8\": \"Buona fortuna\",\n\t\"maanex_9\": \"be, questa volta non e' andata:(\",\n\t\"maanex_10\": \"%%^^WOAH^^%%\",\n\t\"maanex_11\": \"Ma non hai abbastanza soldi!\",\n\t\"maanex_12\": \"##FIGLIOLO?!##\",\n\t\"bk:amurs_arrow\": \"La freccia di cupido\",\n\t\"bk:amurs_arrow_desc\": \"Proiettili amorosi\",\n\t\"bk:amurs_bow\": \"Arco di cupido\",\n\t\"bk:amurs_bow_desc\": \"Vedo l'amore\",\n\t\"bk:poison_flask\": \"Fiaschetta del veleno\",\n\t\"bk:poison_flask_desc\": \"Proiettili velenosi\",\n\t\"bk:snowball\": \"Palladineve\",\n\t\"bk:snowball_desc\": \"Proiettili gelati\",\n\t\"bk:peper_desc\": \"Proiettili piccanti\",\n\t\"bk:peper\": \"Peperoncino\",\n\t\"bk:sale_coupon\": \"Buono spesa\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Amico in scatola\",\n\t\"bk:pet_box_desc\": \"C'e' qualcuno?\",\n\t\"bk:crate\": \"Cratere Orbitante\",\n\t\"bk:crate_desc\": \"C'e' nessuno?\",\n\t\"bk:strawberry\": \"Fragola\",\n\t\"bk:strawberry_desc\": \"Dolci Memorie\",\n\t\"bk:wings\": \"Ali\",\n\t\"bk:wings_desc\": \"I belive I can fly\",\n\t\"bk:coin_pouch\": \"Sacca delle monete\",\n\t\"bk:coin_pouch_desc\": \"Ti da' monete\",\n\t\"bk:key_pouch\": \"Sacca delle chiavi\",\n\t\"bk:key_pouch_desc\": \"Ti da' chiavi\",\n\t\"bk:bomb_pouch\": \"Sacca delle bombe\",\n\t\"bk:bomb_pouch_desc\": \"Ti da' Bombs\",\n\t\"bk:pouch_pouch\": \"Sacca delle sacche\",\n\t\"bk:pouch_pouch_desc\": \"Ti da' sacche\",\n\t\"bk:lightsaber\": \"Svetsaber\",\n\t\"bk:lightsaber_desc\": \"Eri il prescielto!\",\n\t\"bk:snail\": \"Lumachina\",\n\t\"bk:snail_desc\": \"Rallentatore di massa\",\n\t\"bk:spike\": \"Trappola\",\n\t\"bk:spike_desc\": \"Danno maggiore\",\n\t\"bk:mushroom\": \"Funghetto\",\n\t\"bk:mushroom_desc\": \"Velocita' maggiore\",\n\t\"bk:candy\": \"Caramella\",\n\t\"bk:candy_desc\": \"^^Pieno di zuccheri^^, velocita' di fuoco maggiore\",\n\t\"bk:glasses\": \"Occhiali\",\n\t\"bk:glasses_desc\": \"precisione maggiore\",\n\t\"bk:ruler\": \"Righello\",\n\t\"bk:ruler_desc\": \"portata piu lunga\",\n\t\"bk:stopwatch\": \"Cronometro\",\n\t\"bk:stopwatch_desc\": \"Venir colpito ti fa controllare il tempo\",\n\t\"bk_0\": \"##NON TI AZZARDARE A TOCCARLO!##\",\n\t\"bk_1\": \"##TI HO DETTO NON TOCCARE!##\",\n\t\"bk_2\": \"##NON POTRAI MAI SCONFIGGERE [cl red]IL BURNING KNIGHT[cl], SCIOCCO!##\",\n\t\"bk_3\": \"##PREPARATI A MORIRE!##\",\n\t\"bk_4\": \"^^CHE ASSURDITA'^^\",\n\t\"shopkeeper_18\": \"[cl red]^^OFFERTONE![cl]\",\n\t\"dm_0\": \"@@Benvenuto@@\",\n\t\"ach_bk:deal\": \"Fantastica decisione\",\n\t\"ach_bk:deal_desc\": \"Fai un affare con il mago oscuro\",\n\t\"ach_bk:grannys_gift\": \"Regalo di nonna\",\n\t\"ach_bk:grannys_gift_desc\": \"prendi un regalino dalla nonna\",\n\t\"ach_bk:shopper\": \"Compra a piu' non posso\",\n\t\"ach_bk:shopper_desc\": \"Compra ogni oggetto nel negozio\",\n\t\"bk_5\": \"NON CI PROVEREI NEANCHE A PARLARE CON LUI\",\n\t\"bk_6\": \"##UCCIDILO, [cl lime]EDWARD[cl]!##\",\n\t\"bk_7\": \"[cl lime]EDWARD[cl], ##NOOOOOO!!!!##\",\n\t\"bk_8\": \"OH ANDIAMO, SMETTILA DI ESPLODERMI IL CASTELLO!\",\n\t\"bk_9\": \"[cl pink]NONNA[cl],[dl] POTRESTI MORIRE, PERFAVORE##?!?##\",\n\t\"bk_10\": \"MAESTRO,[dl] LE HO PORTATO [cl green]GOBLIN[cl]\",\n\t\"dm_1\": \"Molto bene[dl], grazie[dl], [cl red]Limpor[cl]\",\n\t\"dm_2\": \"##SII, si, ho bisogno di piu' [cl orange]potere[cl]!##\",\n\t\"dm_3\": \"##PIU' [cl orange]POTERE[cl]!\",\n\t\"dm_4\": \"Posso sentire il [cl orange]potere[cl] scorrermi nelle vene!\",\n\t\"granny_3\": \"Tu sarai il primo, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Benvenuto, [cl green]Gobbo[cl]!\",\n\t\"granny_5\": \"Buona fortuna nella tua triste avventura!\",\n\t\"bk:meat_guy\": \"Meat Guy\",\n\t\"bk:meat_guy_desc\": \"Figo!\",\n\t\"bk:bullet_stone\": \"Protettili di pietra\",\n\t\"bk:bullet_stone_desc\": \"He attac, he protec, but most importantly, he cute as hecc\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"non aiuta, ma ti rifornisce di BATterie\",\n\t\"vibration\": \"Vibrazione\",\n\t\"bk:sharp_arrow\": \"Freccia affilata\",\n\t\"bk:sharp_arrow_desc\": \"proiettili penetranti\",\n\t\"machine_0\": \"Inserisci una [cl yellow]moneta\",\n\t\"player_0\": \"Papa'?? ##Che cosa ti han fatto?!?##\",\n\t\"bk:boomerang\": \"Boomerang\",\n\t\"bk:boomerang_desc\": \"Proiettili boomerang\",\n\t\"bk:backpack\": \"Zaino\",\n\t\"bk:backpack_desc\": \"il mio amico orso\",\n\t\"place_an_item\": \"metti un oggetto\",\n\t\"bk:crystal\": \"Cristallo\",\n\t\"bk:crystal_desc\": \"Il potere dell'arcobaleno\",\n\t\"bk:prism\": \"Prisma\",\n\t\"bk:prism_desc\": \"Proiettili -> arcobaleno\",\n\t\"scourged\": \"Maledetto\",\n\t\"bk:bomb\": \"Bomba\",\n\t\"bk:scourge_of_egg\": \"Maledizione delle uova\",\n\t\"bk:scourge_of_egg_desc\": \"mischia i nomi degli oggetti\",\n\t\"bk:scourge_of_unknown\": \"Maledizione dell'ignoto\",\n\t\"bk:scourge_of_unknown_desc\": \"Oggetti nascosti\",\n\t\"bk:scourge_of_blood\": \"Maledizione del sangue\",\n\t\"bk:scourge_of_blood_desc\": \"Difficolta' doppia (e nemici)\",\n\t\"bk:scourge_of_risk\": \"Maledizione del rischio\",\n\t\"bk:scourge_of_risk_desc\": \"Vita nascosta\",\n\t\"bk:scourge_of_keys\": \"Maledizione delle chiavi\",\n\t\"bk:scourge_of_keys_desc\": \"consumabili nascosti\",\n\t\"bk:scourge_of_lost\": \"Maledizione dei perduti\",\n\t\"bk:scourge_of_lost_desc\": \"Amnesia\",\n\t\"bk:scourge_of_scourged\": \"Maledizione delle Maledizioni\",\n\t\"bk:scourge_of_scourged_desc\": \"Maledizioni ovunque\",\n\t\"bk:scourge_of_illness\": \"Maledizione della malattia\",\n\t\"bk:scourge_of_illness_desc\": \"raccogliere cuori cura molto meno\",\n\t\"bk:scourge_of_death\": \"Maledizione della morte\",\n\t\"bk:scourge_of_death_desc\": \"Modalita' difficile\",\n\t\"bk:ancient_revolver\": \"Revolver antico\",\n\t\"bk:ancient_revolver_desc\": \"Sembra figo\",\n\t\"bk:assault_rifle\": \"Fucile d'assalto\",\n\t\"bk:assault_rifle_desc\": \"Raffiche\",\n\t\"fountain_0\": \"Porta 5 monete e sarai benedetto\",\n\t\"fountain_1\": \"Sei stato parzialmente purificato\",\n\t\"fountain_2\": \"Sei stato pienamente purificato\",\n\t\"fountain_3\": \"Sei gia stato purificato\",\n\t\"buffed\": \"Buffed\",\n\t\"nerfed\": \"Nerfed\",\n\t\"restored\": \"Restaurata\",\n\t\"damaged\": \"Danneggiato\",\n\t\"cleansed\": \"Purificato\",\n\t\"gifted\": \"Migliorato\",\n\t\"lucky\": \"Fortunato\",\n\t\"unlucky\": \"Sfortunato\",\n\t\"max_hp\": \"Vita massima\",\n\t\"touch\": \"tocca\",\n\t\"break\": \"rompi\",\n\t\"no_coins\": \"Nessuna moneta\",\n\t\"old_man_6\": \"It's dangerous to go alone, take this!\",\n\t\"roger_0\": \"Kaboom!\",\n\t\"roger_1\": \"##*BOOM*##\",\n\t\"roger_2\": \"Boom boom shakataka!\",\n\t\"bk:shield\": \"Scudo\",\n\t\"bk:gift\": \"Regalo\",\n\t\"bk:shield_pouch\": \"Sacca degli scudi\",\n\t\"bk:shield_pouch_desc\": \"Ti da' scudi\",\n\t\"bk:shield_buddy\": \"Amico scudo\",\n\t\"bk:shield_buddy_desc\": \"Protegge\",\n\t\"bk:skeleton_key\": \"Chiave scheletro\",\n\t\"bk:skeleton_key_desc\": \"99 chiavi\",\n\t\"bk:jar\": \"Vasetto della vita\",\n\t\"bk:jar_desc\": \"clinck!\",\n\t\"bk:star\": \"Stella\",\n\t\"bk:star_desc\": \"protegge\",\n\t\"bk:car_bomb\": \"Automobile bomba\",\n\t\"bk:car_bomb_desc\": \"Servizio di consegna delle bombe\",\n\t\"bk:grenade\": \"Granata\",\n\t\"bk:grenade_desc\": \"Fa' detonare le bombe in un sol colpo \",\n\t\"trash_goblin_0\": \"Liberami dalla mia [cl purple]maledizione[cl]! Perfavore!\",\n\t\"trash_goblin_1\": \"Sono libero![dl] Grazie infinite!\",\n\t\"boxy_0\": \"chiaveccellente!\",\n\t\"boxy_1\": \"Che scatola fantastica!\",\n\t\"boxy_2\": \"Hai bisogno di carta regalo?\",\n\t\"trash_goblin_2\": \"^^Smoke on the water [ic 0] [ic 1]^^\",\n\t\"bk:vampire_bat\": \"Ammazzavampiri\",\n\t\"bk:vampire_bat_desc\": \"Rigenera\",\n\t\"shields\": \"Scudi\",\n\t\"bk:mustache\": \"Baffi\",\n\t\"bk:mustache_desc\": \"VIP\",\n\t\"bk:bloody_chest\": \"Scrigno insanguinato\",\n\t\"bk:bloody_chest_desc\": \"Scrigno che cura\",\n\t\"bk:bloody_shield\": \"Scudo insanguinato\",\n\t\"bk:bloody_shield_desc\": \"Scudi per sempre!\",\n\t\"bk:cutsaw\": \"sega\",\n\t\"bk:cutsaw_desc\": \"i nemici pagheranno\",\n\t\"vampire_0\": \"Yum!\",\n\t\"vampire_1\": \"fantastico!\",\n\t\"vampire_2\": \"Cosi dolce!\",\n\t\"vampire_3\": \"Conosciamo le regole, [cl red]^^vero[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"Di che gruppo sanguineo sei?\",\n\t\"vampire_6\": \"Gustosissimo\",\n\t\"duck_2\": \"Ti piacerebbe partecipare in un sondaggio?\",\n\t\"duck_7_0\": \"Si\",\n\t\"duck_7_1\": \"No\",\n\t\"duck_7\": \"Prenderai questo baule?\",\n\t\"duck_4\": \"Ottimo lavoro! Tieni questo baule\",\n\t\"duck_5\": \"Non sono daccordo...\",\n\t\"duck_6_0\": \"L'universo\",\n\t\"duck_6_1\": \"^^Quark^^\",\n\t\"duck_6\": \"A cosa sto pensando?\",\n\t\"duck_8_0\": \"[cl red]Rosso[cl]\",\n\t\"duck_8_1\": \"[cl blue]Blu[cl]\",\n\t\"duck_8\": \"Qual'e' il mio ^^%%colore%%^^ preferito?\",\n\t\"duck_9_0\": \"Un gatto\",\n\t\"duck_9_1\": \"L'hai appena detto\",\n\t\"duck_9\": \"Chi ha detto miao?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"Cos'e' meglio?\",\n\t\"duck_11_0\": \"Cosa, uovo?\",\n\t\"duck_11_1\": \"\\\\[_Lo accoltella_]\",\n\t\"duck_11\": \"Tu sei un tipo da salsa\",\n\t\"duck_12_0\": \"Pulcino\",\n\t\"duck_12_1\": \"Uovo\",\n\t\"duck_12\": \"Cos'e venuto prima?\",\n\t\"duck_13_0\": \"Niente.\",\n\t\"duck_13_1\": \"Uno snack.\",\n\t\"duck_13_2\": \"Un uovo.\",\n\t\"duck_13_3\": \"Pollo fritto.\",\n\t\"duck_13\": \"Cos'hai mangiato oggi?\",\n\t\"duck_14\": \"Ouch.\",\n\t\"duck_17_0\": \"Certo\",\n\t\"duck_17_1\": \"##NAAAAAH##\",\n\t\"duck_17\": \"Vuoi della ananas sulla tua pizza?\",\n\t\"duck_18_0\": \"Bianco!\",\n\t\"duck_18_1\": \"[cl yellow]Giallo[cl]!\",\n\t\"duck_18\": \"Di che colore e' il formaggio?\",\n\t\"nurse_0\": \"Sei uno splendore, dolcezza!\",\n\t\"nurse_1\": \"Potrei curarti un po, ma ho bisogno di [cl yellow][vr price] soldi[cl]\",\n\t\"nurse_2\": \"Spero non abbia fatto male\",\n\t\"elon_4\": \"Tutto fatto, divertiti\",\n\t\"elon_2_0\": \"andiamo\",\n\t\"elon_2_1\": \"Spetta\",\n\t\"elon_2\": \"Vuoi provare la mia magia?\",\n\t\"elon_3\": \"Posso trasformare la tua arma in un altra\",\n\t\"elon_5\": \"Vabbe'\",\n\t\"elon_7\": \"hei, che arma hai???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*blush*\",\n\t\"gobetta_4\": \"Sei.. tu?\",\n\t\"gobetta_5\": \"E' passato cosi' tanto tempo...\",\n\t\"ach_bk:desert\": \"arido e asciutto\",\n\t\"ach_bk:desert_desc\": \"Raggiungi il Palazzo del Deserto\",\n\t\"ach_bk:jungle\": \"Api\",\n\t\"ach_bk:jungle_desc\": \"Raggiungi la Giungla Antica\",\n\t\"rooms_explored\": \"Stanze esplorate\",\n\t\"bk:shadow_cloak_desc\": \"No tu\",\n\t\"bk:shadow_cloak\": \"Mantello d'Ombra\",\n\t\"bk:dynamite_stick\": \"Candela di dinamite\",\n\t\"bk:dynamite_stick_desc\": \"Vuoi esplodere?\",\n\t\"bk:chalice_of_blood\": \"Calice di sangue\",\n\t\"bk:chalice_of_blood_desc\": \"Il dolore invoca rabbia, rabbia invoca danno\",\n\t\"bk:detonator\": \"Detonatore\",\n\t\"bk:detonator_desc\": \"Detonatore esplosivo\",\n\t\"invincibility_time\": \"Tempo di invincibilita'\",\n\t\"accuracy\": \"Precisione\",\n\t\"range\": \"Range\",\n\t\"fire_rate\": \"velocita' di fuoco\",\n\t\"speed\": \"velocita'\",\n\t\"bk:talisman_of_foresight\": \"Talismano della premunizione\",\n\t\"bk:talisman_of_foresight_desc\": \"Apri gli occhi e vedi le stanze vicine!\",\n\t\"bk:scourge_ring\": \"Anello della maledizione\",\n\t\"bk:scourge_ring_desc\": \"Niente piu' maledizioni\",\n\t\"snek_0\": \"buona.\",\n\t\"snek_1\": \"Grazzzie\",\n\t\"snek_2\": \"Fantassstico\",\n\t\"snek_3\": \"come sssstai?\",\n\t\"snek_4\": \"Buona giornata\",\n\t\"snek_5\": \"Vuoi comprare qualcossssa?\",\n\t\"snek_6\": \"Devo sssoddisfare i miei clienti...\",\n\t\"snek_7\": \"Faro' cio' che devo!\",\n\t\"bk:snek\": \"Serpe\",\n\t\"bk:snek_desc\": \"ssnack?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Hei, hai una chiave in piu'?\",\n\t\"boxy_5\": \"Avresti qualche chiave da regalarmi?\",\n\t\"bk:blank\": \"Blank\",\n\t\"bk:blank_desc\": \"_Blank Text_\",\n\t\"bk:blank_bombs\": \"Blank Bombs\",\n\t\"bk:blank_bombs_desc\": \"Bullet Shield\",\n\t\"bk:explosive_bullets\": \"Proiettili esplosivi\",\n\t\"bk:explosive_bullets_desc\": \"Esplosivi\",\n\t\"bk:random_bullets\": \"Proiettili a caso\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Tazza\",\n\t\"bk:cup_desc\": \"Tazza per la nonna\",\n\t\"bk:cartridge\": \"Cartuccia\",\n\t\"bk:cartridge_desc\": \"Cartuccia per il mago nero\",\n\t\"bk:marriage_ring\": \"Anello di matrimonio\",\n\t\"bk:marriage_ring_desc\": \"Mago nero e nonna per sempre !\",\n\t\"boxy_7\": \"Voglio chiavi\",\n\t\"boxy_8\": \"Non hai abbastanza chiavi :(\",\n\t\"boxy_9\": \"Ho finalmente abbastanza chiavi per ^^aprire^^!\",\n\t\"roger_3\": \"Ti dispiace pagare?\",\n\t\"roger_4\": \"Niente sconti oggi\",\n\t\"roger_5\": \"Prima le bombe\",\n\t\"vampire_7\": \"Non hai abbastanza vita\",\n\t\"vampire_8\": \"Non faccio sconti\",\n\t\"vampire_9\": \"La tua vita e troppo bassa\",\n\t\"ach_bk:scourged\": \"Maledetto\",\n\t\"ach_bk:scourged_desc\": \"Prendi un gettone per una maledizione\",\n\t\"ach_bk:scourged_weapon\": \"Arma maledetta\",\n\t\"ach_bk:scourged_weapon_desc\": \"Prendi un arma maledetta\",\n\t\"rerolled\": \"Ripesca\",\n\t\"ach_bk:open_up\": \"Apri\",\n\t\"ach_bk:open_up_desc\": \"Compra tutto da Boxy\",\n\t\"ach_bk:snek\": \"Serpente domestico\",\n\t\"ach_bk:snek_desc\": \"Un serpente come amico\",\n\t\"bk:scourge_of_greed\": \"Maledizione dell'avidita'\",\n\t\"bk:scourge_of_greed_desc\": \"Prezzi alti\",\n\t\"killed_by\": \"Ucciso da\",\n\t\"kills\": \"Uccisioni\",\n\t\"time\": \"Tempo\",\n\t\"depth\": \"Profondita'\",\n\t\"bk:blank_bullets\": \"Proiettili Blank\",\n\t\"bk:blank_bullets_desc\": \"Blank\",\n\t\"bk:lego\": \"Costruttore\",\n\t\"bk:lego_desc\": \"pestarli fa male...\",\n\t\"bk:iron_armor\": \"Armatura di metallo\",\n\t\"bk:iron_armor_desc\": \"Da' scudi\",\n\t\"bk:round_shield\": \"Scudo rotondo\",\n\t\"bk:round_shield_desc\": \"assorbe danni da contatto\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"La leggenda in persona\",\n\t\"bk:inverted_arkhalis\": \"Arkhalis invertito\",\n\t\"bk:inverted_arkhalis_desc\": \"L'aiuto arriverà a chi e' a corto di salute\",\n\t\"bk:gun_sword\": \"Spada pistola\",\n\t\"bk:gun_sword_desc\": \"Preparatevi a passare dei guai, dei guai  molto grossi!\",\n\t\"ach_bk:scourge_king_desc\": \"10 punti maledizione\",\n\t\"ach_bk:scourge_king\": \"Cavaliere maledetto\",\n\t\"ach_bk:sting_operation\": \"Operazione pungilione\",\n\t\"ach_bk:sting_operation_desc\": \"Sconfiggi l'ape regina\",\n\t\"ach_bk:mummified\": \"Mummificato\",\n\t\"ach_bk:mummified_desc\": \"Sconfiggi il faraone\",\n\t\"ach_bk:democracy\": \"Democrazia\",\n\t\"ach_bk:democracy_desc\": \"Sconfiggi il Vecchio Re\",\n\t\"pharaoh_scream\": \"##PREPARATI AD ESSERE MUMMIFICATO!##\",\n\t\"queen_bee_scream\": \"##PER [cl yellow]LORD MIELE[cl]!##\",\n\t\"bk:half_heart\": \"Mezzo Cuore\",\n\t\"right\": \"Destra\",\n\t\"down\": \"Giu'\",\n\t\"left\": \"Sinistra\",\n\t\"up\": \"Su\",\n\t\"painting_cat\": \"Gatto Dipinto\",\n\t\"bk:axe\": \"Ascia\",\n\t\"bk:axe_desc\": \"Ha promesso di ritornare\",\n\t\"bk:guitar\": \"Chitarra\",\n\t\"bk:guitar_desc\": \"Non e' accordata\",\n\t\"bk:glass_sword\": \"Spada di Vetro\",\n\t\"bk:glass_sword_desc\": \"L'arma dei Maestri\",\n\t\"bk:chicken\": \"Aletta di Pollo\",\n\t\"bk:chicken_desc\": \"E' piccante\",\n\t\"bk:pickaxe\": \"Piccone\",\n\t\"bk:pickaxe_desc\": \"Scava, villico!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"meta' Mana\",\n\t\"bk:lava_wand\": \"Bacchetta Lava\",\n\t\"bk:lava_wand_desc\": \"Roba Bollente\",\n\t\"bk:web_wand\": \"Bacchetta spada\",\n\t\"bk:web_wand_desc\": \"Fornitore di World-wide web\",\n\t\"bk:slap_stick\": \"Batacchio\",\n\t\"bk:slap_stick_desc\": \"Slap\",\n\t\"sensivity\": \"Sensibilita'\",\n\t\"no\": \"No\",\n\t\"scale\": \"Scala\",\n\t\"ach_bk:ice\": \"Era Glaciale\",\n\t\"ach_bk:ice_desc\": \"Raggiungi le Rovine Ghiacciate\",\n\t\"ach_bk:library\": \"Testi Sacri\",\n\t\"ach_bk:library_desc\": \"Raggiungi la Biblioteca Segreta\",\n\t\"bk:ice_skates\": \"Pattini da ghiaccio\",\n\t\"bk:ice_skates_desc\": \"Immunita' al ghiaccio\",\n\t\"bk:campfire_in_bottle\": \"Falo' in bottiglia\",\n\t\"bk:campfire_in_bottle_desc\": \"Immunita' al gelo\",\n\t\"library\": \"Biblioteca Segreta\",\n\t\"ach_bk:cat_without_a_hat\": \"Gatto senza Cappello\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Trova il Dipinto del Gatto\",\n\t\"ach_bk:rich\": \"Carta igenica\",\n\t\"ach_bk:rich_desc\": \"Ottieni 99 monete\",\n\t\"ach_bk:rescue_operation\": \"Operazione di salvataggio\",\n\t\"ach_bk:rescue_operation_desc\": \"Salva un NPC\",\n\t\"ach_bk:tutorial\": \"Guru\",\n\t\"ach_bk:tutorial_desc\": \"Finisci il tutorial\",\n\t\"ach_bk:fancy_hat\": \"Cappello di Lusso\",\n\t\"ach_bk:fancy_hat_desc\": \"Compra un cappello\",\n\t\"ach_bk:unlock\": \"Sbloccatore\",\n\t\"ach_bk:unlock_desc\": \"Sblocca un oggetto\",\n\t\"floor_brightness\": \"Luminosita' del pavimento\",\n\t\"ach_bk:shielded\": \"Scudi su\",\n\t\"ach_bk:shielded_desc\": \"Ottieni uno scudo\",\n\t\"run_type\": \"modalita'\",\n\t\"run_regular\": \"Normale\",\n\t\"run_challenge\": \"Sfida\",\n\t\"damage_taken\": \"Danno subito\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Distanza Percorsa\",\n\t\"seed\": \"Seme\",\n\t\"score\": \"Punteggio\",\n\t\"new_high_score\": \"Nuovo Record!\",\n\t\"items_collected\": \"Oggetti collezionati\",\n\t\"boss_rush\": \"Boss Rush\",\n\t\"run_bossrush\": \"Boss rush\",\n\t\"bk:blindfold_desc\": \"RIP le mie armi\",\n\t\"bk:blindfold\": \"Bendato\",\n\t\"daily_run\": \"Partita Giornaliera\",\n\t\"builder_0_0\": \"certo, tieni\",\n\t\"builder_0_1\": \"non ho soldi per ste cose scusa :(\",\n\t\"builder_0\": \"Stavo pensando di fare una scorciatoia dal villaggio a qui, ma ho bisogno di altre [vr need] [ic 0] monete. Puoi aiutarmi?\",\n\t\"builder_1\": \"Ma non hai monete! :(\",\n\t\"builder_2\": \"Grazie per il tuo investimento!\",\n\t\"builder_3\": \"Finalmente ho abbastanza soldi per completare il progetto! Grazie mille!\",\n\t\"builder_4\": \"Okay, tranquillo :)!\",\n\t\"shortcut_is_broken\": \"La scorciatoia e' rotta\",\n\t\"ach_bk:boss_rush\": \"Sfidante dei Boss\",\n\t\"ach_bk:boss_rush_desc\": \"Sconfiggi tutti i Boss nella Boss Rush\",\n\t\"ach_bk:daily\": \"Gloria giornaliera\",\n\t\"ach_bk:daily_desc\": \"Completa la sfida giornaliera\",\n\t\"ach_bk:desert_shortcut\": \"Scorciatoia del Palazzo del Deserto\",\n\t\"ach_bk:desert_shortcut_desc\": \"Aggiusta la scorciatoria del Palazzo del Deserto\",\n\t\"ach_bk:jungle_shortcut\": \"Scorciatoia della Giungla Antica\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Aggiusta la scorciatoria della Giungla Antica\",\n\t\"ach_bk:ice_shortcut\": \"Scorciatoia delle Rovine Ghiacciate\",\n\t\"ach_bk:ice_shortcut_desc\": \"Aggiusta la scorciatoria del Rovine Ghiacciate\",\n\t\"ach_bk:library_shortcut\": \"Scorciatoia della Bibloteca Segreta\",\n\t\"ach_bk:library_shortcut_desc\": \"Aggiusta la scorciatoria della Bibloteca Segreta\",\n\t\"ach_bk:fashion_matters2\": \"Le apparenze contano\",\n\t\"ach_bk:fashion_matters2_desc\": \"Compra tutti i cappelli\",\n\t\"ach_bk:10_challenges\": \"Sfidante\",\n\t\"ach_bk:10_challenges_desc\": \"Completa 10 sfide\",\n\t\"ach_bk:20_challenges\": \"Sfidante 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Completa 20 sfide\",\n\t\"ach_bk:30_challenges\": \"Sfidante 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Completa 30 sfide\",\n\t\"ach_bk:bk_no_more\": \"Niente piu' BK\",\n\t\"ach_bk:bk_no_more_desc\": \"Sconfiggi il Burning Knight\",\n\t\"ach_bk:dm_no_more\": \"Niente piu' Mago Nero\",\n\t\"ach_bk:dm_no_more_desc\": \"Sconfiggi il Mago Nero\",\n\t\"ach_bk:egor_no_more\": \"Niente piu' Egor\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Ci risamo\",\n\t\"ach_bk:loop_desc\": \"Entra nel loop\",\n\t\"coins_collected\": \"Monete raccolte\",\n\t\"bk:cup_head\": \"Cup Head\",\n\t\"bk:cup_head_desc\": \"Fatti una tazza di te\",\n\t\"bk:mustache_hat\": \"Baffi\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Cappello elica\",\n\t\"bk:propeller_hat_desc\": \"Gira!\",\n\t\"bk:sunglasses\": \"Occhiali da sole\",\n\t\"bk:sunglasses_desc\": \"Funzionano anche con la luna!\",\n\t\"bk:cap\": \"Cappello\",\n\t\"bk:cap_desc\": \"Cool @-@\",\n\t\"bk:eyes\": \"Occhi\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Occhio\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Capelli\",\n\t\"bk:hair_desc\": \"Elegante\",\n\t\"won\": \"vinto\",\n\t\"won_message\": \"Hai vinto!\",\n\t\"garderobe_sign\": \"Camerino\",\n\t\"darkmarket_tip\": \"~~[cl purple]Maledizione[cl] o [cl yellow]30 monete[cl]@@\",\n\t\"mike_0\": \"Devi pagarmi [cl green]3 smeraldi\",\n\t\"mike_1\": \"Prova la Boss Rush per soli [cl green]3 smeraldi[cl]!\",\n\t\"bk:weird_potion\": \"Strana Pozione\",\n\t\"bk:weird_potion_desc\": \"Strani Proiettili\",\n\t\"bk:megaphone\": \"Megafono\",\n\t\"bk:megaphone_desc\": \"Proiettili Espandibili\",\n\t\"scourge\": \"Maledizione\",\n\t\"scourge_stats\": \"Maledizioni\",\n\t\"run_daily\": \"Giornaliera\",\n\t\"completed_on\": \"Completata il\",\n\t\"complete\": \"completata\",\n\t\"next_daily_in\": \"[cl gray]La prossima comincia in[cl]\",\n\t\"hours\": \"ore\",\n\t\"minutes\": \"minuti\",\n\t\"seconds\": \"secondi\",\n\t\"ach_bk:star\": \"La stella dello show\",\n\t\"ach_bk:star_desc\": \"Ottieni 3 orbitali\",\n\t\"ach_bk:family\": \"Piccola Famiglia Felice\",\n\t\"ach_bk:family_desc\": \"Ottieni 3 animali domestici\",\n\t\"ach_bk:return_to_sender\": \"No tu\",\n\t\"ach_bk:return_to_sender_desc\": \"Uccidi un nemico con il suo stesso proiettile\",\n\t\"ach_bk:van_no_gogh\": \"Van No Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Distruggi 100 dipinti\",\n\t\"ach_bk:dark_market\": \"Nascondiglio criminale\",\n\t\"ach_bk:dark_market_desc\": \"Scendi nel Mercato Nero\",\n\t\"ach_bk:spikes\": \"Roba Affilata\",\n\t\"ach_bk:spikes_desc\": \"Attiva 100 trappole in una sola partita\",\n\t\"ach_bk:white_flag\": \"Senza armi!\",\n\t\"ach_bk:white_flag_desc\": \"Completa una stanza senza mai usare armi\",\n\t\"quack\": \"[cl yellow]Quack![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfect\",\n\t\"bk_11\": \"TI PERDONO PER STA VOLTA..  MA ##NON## RIFARLO PIU'!\",\n\t\"leaderboard\": \"Leaderboard\",\n\t\"display\": \"Display\",\n\t\"around_you\": \"Intorno a te\",\n\t\"friends\": \"Amici\",\n\t\"global\": \"Globale\",\n\t\"loading\": \"Caricamento\",\n\t\"generating\": \"Generando\",\n\t\"cursor_radius\": \"Raggio Cursore\",\n\t\"no_scores_yet\": \"Nessun punteggio ancora\",\n\t\"no_score_yet\": \"Nessun punteggio ancora\",\n\t\"run\": \"Partita\",\n\t\"top\": \"Miglior\",\n\t\"quick_restart\": \"Ricomincia veloce\",\n\t\"painting_dungeon\": \"Dungeon\",\n\t\"painting_goose\": \"Mini Oca\",\n\t\"painting_chess\": \"Elefante volante\",\n\t\"painting_peach\": \"Un pesco\",\n\t\"bk:no_lamp\": \"Nessuna lampada\",\n\t\"bk:explosive_lamp\": \"Lampada esplosiva\",\n\t\"bk:explosive_lamp_desc\": \"Quando i boom sono piu' significativi\",\n\t\"bk:shielded_lamp\": \"Lampada scudo\",\n\t\"bk:shielded_lamp_desc\": \"Scudi su!\",\n\t\"lamp\": \"Lampada\",\n\t\"bk:brain\": \"Mega Cervello\",\n\t\"bk:brain_desc\": \"Dimensioni cervello: Mega\",\n\t\"bk:heart_amulet\": \"Amuleto Cuore\",\n\t\"bk:heart_amulet_desc\": \"+1 alla dimensione del cuore\",\n\t\"bk:star_amulet_desc\": \"Mana su\",\n\t\"bk:star_amulet\": \"Amuleto Stella\",\n\t\"bk:coin_amulet\": \"Amuleto Moneta\",\n\t\"bk:coin_amulet_desc\": \"Le monete valgono di piu'\",\n\t\"bk:key_amulet\": \"Amuleto Chiave\",\n\t\"bk:key_amulet_desc\": \"Le chiavi valgono di piu'\",\n\t\"bk:bomb_amulet\": \"Amuleto Bomba\",\n\t\"bk:bomb_amulet_desc\": \"Le bombe valgono di piu'\",\n\t\"bk:eye_amulet\": \"Amuleto Occhio\",\n\t\"bk:eye_amulet_desc\": \"Fa male essere inaccurati\",\n\t\"bk:eye_patch\": \"Benda sull'occhio\",\n\t\"bk:eye_patch_desc\": \"Siete pronti ragazzi?\",\n\t\"bk:toilet_paper\": \"Carta Igenica\",\n\t\"bk:toilet_paper_desc\": \"E sempre finita\",\n\t\"bk:decoy\": \"Esca\",\n\t\"bk:decoy_desc\": \"Esplode\",\n\t\"bk:wallet\": \"Amico portafoglio\",\n\t\"bk:wallet_desc\": \"Contiene le tue monete\",\n\t\"bk:skele_buddy\": \"Amico scheletrico\",\n\t\"bk:skele_buddy_desc\": \"SpaventosooOoO!\",\n\t\"bk:mega_bomb\": \"Mega bombe\",\n\t\"bk:mega_bomb_desc\": \"Dimensione Bombe: Mega\",\n\t\"bk:condensed_milk\": \"Latte condensato\",\n\t\"bk:condensed_milk_desc\": \"Pixel veloci - nemici piu' lenti\",\n\t\"bk:marshmallow\": \"Marshmallow\",\n\t\"bk:marshmallow_desc\": \"Appiccicoso\",\n\t\"bk:orbital_multiplier\": \"Moltiplicatore di orbitali\",\n\t\"bk:orbital_multiplier_desc\": \"Piu' orbitali!\",\n\t\"bk:pet_multiplier\": \"Moltiplicatore di animali domestici\",\n\t\"bk:pet_multiplier_desc\": \"Piu amici!\",\n\t\"bk:ghost_bullets\": \"Proiettli fantasma\",\n\t\"bk:ghost_bullets_desc\": \"I muri non li fermeranno\",\n\t\"bk:weight\": \"Pesi pesanti\",\n\t\"bk:weight_desc\": \"Moltiplicatore di gravita\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"Prendere o lasciare\",\n\t\"bk:ethernal_d6\": \"D6 Eterno\",\n\t\"bk:ethernal_d6_desc\": \"Ritira E\\/O Distruggi\",\n\t\"bk:billiard\": \"Biliardo\",\n\t\"bk:billiard_desc\": \"I proiettili rimbalzano\",\n\t\"bk:enraged_bullets\": \"Proiettili furiosi\",\n\t\"bk:enraged_bullets_desc\": \"Proiettile batte proiettile\",\n\t\"bk:rewind_button\": \"Pulsante per riavvolgere\",\n\t\"bk:rewind_button_desc\": \"Aspetta un attim..\",\n\t\"bk:piggy_bank\": \"Salvadanaio\",\n\t\"bk:piggy_bank_desc\": \"I miei risparmi di una vita\",\n\t\"coins\": \"Monete\",\n\t\"bk:death_star\": \"Death Star\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Saldatore\",\n\t\"bk:soldering_iron_desc\": \"E' caldo\",\n\t\"bk:can\": \"Lattina\",\n\t\"bk:can_desc\": \"Proiettili doppi\",\n\t\"bk:swimming_mask\": \"Maschera da nuoto\",\n\t\"bk:swimming_mask_desc\": \"E' un arma segreta\",\n\t\"bk:bullet_chair\": \"Sedia proiettile\",\n\t\"bk:bullet_chair_desc\": \"$ gambe 4 pistole\",\n\t\"bk:cell\": \"Cellula\",\n\t\"bk:cell_desc\": \"I proiettili si moltiplicano\",\n\t\"bk:brick\": \"iBrick\",\n\t\"bk:brick_desc\": \"Livelli piu grandi\",\n\t\"bk:ring_of_pain\": \"Anello del dolore\",\n\t\"bk:ring_of_pain_desc\": \"Farsi male fa male a tutti\",\n\t\"bk:schrodingers_cat\": \"Il Gatto di Schrödingers\",\n\t\"bk:schrodingers_cat_desc\": \"Essere o non essere (50% probabilita')\",\n\t\"bk:smoke_bomb\": \"Bomba fumogena\",\n\t\"bk:smoke_bomb_desc\": \"Fuga stile ninja\",\n\t\"bk:chest_ring\": \"Anello dei bauli\",\n\t\"bk:chest_ring_desc\": \"Piu' Bauli!\",\n\t\"bk:empty_shell\": \"Cartuccia vuota\",\n\t\"bk:empty_shell_desc\": \"Possibilita' di distruggerei proiettili nemici\",\n\t\"bk:parachute\": \"Paracadute\",\n\t\"bk:parachute_desc\": \"Immune ai dirupi\",\n\t\"bk:spiked_cookie\": \"Biscotto spinato\",\n\t\"bk:spiked_cookie_desc\": \"(munch) hei ha le spine (munch)\",\n\t\"bk:shooty\": \"Shooty\",\n\t\"bk:shooty_desc\": \"Spara!\",\n\t\"bk:rabbit_bullets\": \"Proiettili coniglio\",\n\t\"bk:rabbit_bullets_desc\": \"Si moltiplicano\",\n\t\"bk:pandoras_box\": \"Vaso di pandora\",\n\t\"bk:pandoras_box_desc\": \"C'e' il male dentro\",\n\t\"bk:bubbles\": \"Bolle\",\n\t\"bk:bubbles_desc\": \"Amici di bolla\",\n\t\"bk:match\": \"Fiammifero\",\n\t\"bk:match_desc\": \"Fuoco per tutti\",\n\t\"bk:hammer\": \"Martello\",\n\t\"bk:hammer_desc\": \"Rompe l'armatura\",\n\t\"bk:helmet\": \"Elmo di metallo\",\n\t\"bk:helmet_desc\": \"Possibilita' di ignorare danni subiti\",\n\t\"bk:beer\": \"Birra\",\n\t\"bk:beer_desc\": \"Danno furioso\",\n\t\"bk:the_eye\": \"L'occhio\",\n\t\"bk:the_eye_desc\": \"Sta guardando\",\n\t\"bk:mimics_tooth\": \"Il dente del Mimic\",\n\t\"bk:mimics_tooth_desc\": \"Attrae Mimics\",\n\t\"ach_bk:mimic\": \"Lo Spavento\",\n\t\"ach_bk:mimic_desc\": \"Trova un Mimic\",\n\t\"bk:paper_airplane\": \"Aereoplanino di carta\",\n\t\"bk:paper_airplane_desc\": \"Proiettili automatici\",\n\t\"ach_bk:ice_boss\": \"Let It Go\",\n\t\"ach_bk:ice_boss_desc\": \"Uccidi la regina di ghiaccio\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Ahem\",\n\t\"painting_agency\": \"Benvenuto in agenzia\",\n\t\"language\": \"Lingua\",\n\t\"inventory\": \"Inventario\",\n\t\"guitar\": \"Piu' volume!\",\n\t\"bk:pouch\": \"Borsa\",\n\t\"bk:alien_glasses\": \"Occhiali Alieni\",\n\t\"bk:alien_glasses_desc\": \"Vedo di piu'\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Lampada\",\n\t\"bk:fragile_lamp\": \"Lampada Fragile\",\n\t\"bk:fragile_lamp_desc\": \"1 hit K.O.\",\n\t\"painting_guitar\": \"Alza il volume!\",\n\t\"ach_bk:maanex\": \"Et tu, Brut?\",\n\t\"ach_bk:maanex_desc\": \"Uccidi Maanex mentre indossi la sua maschera\",\n\t\"dad_0\": \"figliolo![dl] Devo andare a trovare [cl red]la Lampada[cl]. Ti lascio al comando.\",\n\t\"dad_1\": \"Se non ritorno, non cercarmi. Ciao!\",\n\t\"son_0\": \"##NOOOOOOO##\",\n\t\"gobbo_0\": \"figliolo, [cl green]mio padre[cl] miha lasciato 20 anni fa. Devo andare a cercarlo.\",\n\t\"gobbo_1\": \"Ti lascio al comando. Ciao!\",\n\t\"dm_5\": \"Un nuovo e ^^migliore^^ [cl red]pupazzo[cl]![dl] ##MUHAHAHA##\",\n\t\"dm_6\": \"Mi senti, [cl red]Limpor?\",\n\t\"heinur_0\": \"##NO[dl], NON DI NUOVO!##\",\n\t\"nbk_0\": \"##SI, PADRONE##\",\n\t\"bk_12\": \"##HO FINITO I RE, COMBATTI CON ME, SCIOCCO!##\",\n\t\"bk:headshot_gun\": \"Pistola Storta\",\n\t\"bk:headshot_gun_desc\": \"Colpo alla testa\",\n\t\"bk:laser_cannon\": \"Cannone Laser\",\n\t\"bk:laser_cannon_desc\": \"Haha, laser go pew pew\",\n\t\"credits\": \"Credits\",\n\t\"head_0\": \"sciocco\",\n\t\"tech\": \"Techno\",\n\t\"ach_bk:collector\": \"Collezionista\",\n\t\"ach_bk:collector_desc\": \"Sblocca tutti gli oggetti\",\n\t\"bk:treasure_key\": \"Chiave Rossa\",\n\t\"bk:treasure_key_desc\": \"Apre Scappatoie\",\n\t\"bk:pass\": \"Pass\",\n\t\"bk:pass_desc\": \"Identificati!\",\n\t\"bk:bucket\": \"Secchio\",\n\t\"bk:bucket_desc\": \"Inutile senza il suo contenuto\",\n\t\"bk:water_bucket\": \"Secchio d'acqua\",\n\t\"bk:water_bucket_desc\": \"Calma [cl red]il Fuoco[cl]\",\n\t\"bk:snow_bucket\": \"Secchio di neve\",\n\t\"bk:snow_bucket_desc\": \"Forse, si scioglie\",\n\t\"m2_0\": \"Non mi riprenderò mai finanziariamente\",\n\t\"m2_1\": \"Ottimo lavoro!\",\n\t\"m2_2\": \"Hey, vuoi ^^migliorare^^ le tue  %%abilità%%?\",\n\t\"m2_3\": \"Usa ^^%%il Computer%%^^ per controllare la Chela!\",\n\t\"maanex2_0_0\": \"Prendi i miei soldi!\",\n\t\"maanex2_0_1\": \"Non questa volta, grazie.\",\n\t\"maanex2_0\": \"Okay, dammi[cl yellow][vr cost] monete[cl] e puoi provare la Chela!\",\n\t\"dm_7\": \"Facciamo una partita\",\n\t\"bkw_0\": \"UN ALTRO[cl red]INTRUSO[cl]!\",\n\t\"bkw_1\": \"##FUORI DI QUI##[dl], O USERO' LA FORZA!\",\n\t\"bkw_2\": \"Sto cercando [cl green]mio padre\",\n\t\"bkw_3\": \"TI HO _AVVERTITO_\",\n\t\"spanish_inquisition\": \"[cl red]Inquisizione Spagnola\",\n\t\"lp_0\": \"Ottimo lavoro, [cl purple]Ritta[cl][dl], riavvio [cl green]la simulazione[cl][dl].[dl].[dl].\",\n\t\"bk:broken_bucket\": \"Secchio Rotto\",\n\t\"bk:broken_bucket_desc\": \"Protecc\",\n\t\"bk:ankh\": \"Ankh\",\n\t\"bk:ankh_desc\": \"Vita Eterna\",\n\t\"bk:broken_ankh\": \"Ankh Rotto\",\n\t\"bk:broken_ankh_desc\": \"Vita Eterna?\",\n\t\"bk:what\": \"cosa\",\n\t\"bk:what_desc\": \"sul serio, COSA?\",\n\t\"bk:gold_minigun\": \"Minigun d'Oro\",\n\t\"bk:gold_minigun_desc\": \"Haha budget go brrr\",\n\t\"bk:gold_dagger\": \"Pugnale d'Oro\",\n\t\"bk:gold_dagger_desc\": \"Old but gold\",\n\t\"bk:gold_revolver\": \"Revolver d'Oro\",\n\t\"bk:gold_revolver_desc\": \"Ricoprimi d'Oro\",\n\t\"bk:gold_axe\": \"Ascia d'Oro\",\n\t\"bk:gold_axe_desc\": \"solo un ascia d'Oro\",\n\t\"painting_code\": \"Codice\",\n\t\"bk:katana\": \"Katana\",\n\t\"bk:katana_desc\": \"Chi e'[cl orange]il propietario[cl]?\",\n\t\"bk:smart_gun\": \"Smart Gun\",\n\t\"bk:smart_gun_desc\": \"Sa'\",\n\t\"bk:pop_gun\": \"Pop Gun\",\n\t\"bk:pop_gun_desc\": \"Molto Popolare\",\n\t\"bk:the_button\": \"Il Bottone\",\n\t\"bk:the_button_desc\": \"attacca in 8 direzioni\",\n\t\"bk:gold_sword\": \"Spada d'Oro\",\n\t\"bk:gold_sword_desc\": \"quando non hai nient'altro da comprare\",\n\t\"bk:donut\": \"Ciambella\",\n\t\"bk:donut_desc\": \"Non esitare\",\n\t\"bk:sudoku\": \"Sudoku\",\n\t\"bk:sudoku_desc\": \"Mezza stanza 'puff', ridotta in atomi\",\n\t\"bk:gps_ring\": \"Anello con GPS\",\n\t\"bk:gps_ring_desc\": \"possibilita' di rivelare la mappa \",\n\t\"bk:shield_potion\": \"Pozione Scudo\",\n\t\"bk:shield_potion_desc\": \"Succo di Scudo\",\n\t\"bk:trash_generator\": \"Generatore di Spazzatura\",\n\t\"bk:trash_generator_desc\": \"Si.\",\n\t\"bk:crabs_claw\": \"La chela del granchio\",\n\t\"bk:crabs_claw_desc\": \"Rompe qualsiasi armatura\",\n\t\"eg_3\": \"Buona giornata, signore\",\n\t\"eg_0_0\": \"Prendi ^^[cl lime]gli smeraldi[cl]^^\",\n\t\"eg_0_1\": \"Lasciali\",\n\t\"eg_0\": \"Prendi [cl lime]i miei smeraldi[cl], Ti supplico!\",\n\t\"eg_1\": \"Esco\",\n\t\"bk:reverse_card\": \"Carta Inverti\",\n\t\"bk:reverse_card_desc\": \"Rotolare attraverso i proiettili li riflette\",\n\t\"bk:magnet\": \"Magnete\",\n\t\"bk:magnet_desc\": \"Affetto ed Attrazione\",\n\t\"bk:glowing_mushroom\": \"Funghetti luminosi\",\n\t\"bk:glowing_mushroom_desc\": \"frequenze positive\",\n\t\"bk:tinfoil_hat\": \"cappello di carta stagnola\",\n\t\"bk:tinfoil_hat_desc\": \"Feels safe\",\n\t\"bk:rear_window\": \"Finestra sul Retro\",\n\t\"bk:rear_window_desc\": \"Ti guarda le spalle\",\n\t\"bk:refractor\": \"Rifrattore\",\n\t\"bk:refractor_desc\": \"Possibilita' di attaccare in tutte le direzioni\",\n\t\"bk:fork\": \"Forchetta\",\n\t\"bk:fork_desc\": \"Fa male\",\n\t\"bk:rock\": \"Pietra\",\n\t\"bk:rock_desc\": \"Danno ad un prezzo\",\n\t\"bk:coffee_grinder\": \"Macina Caffe'\",\n\t\"bk:coffee_grinder_desc\": \"proiettili piccoli e veloci\",\n\t\"integrations\": \"Integrazioni\",\n\t\"twitch\": \"Twitch\",\n\t\"streamer_username\": \"Streamer Username\",\n\t\"bk:shawarma\": \"Shwarma\",\n\t\"bk:shawarma_desc\": \"A volte i proiettili sono piu' grandi\",\n\t\"bk:cats_ear\": \"Orecchio di Gatto\",\n\t\"bk:cats_ear_desc\": \"schivata assurda\",\n\t\"luck\": \"fortuna\",\n\t\"bk:gamepad\": \"Gamepad\",\n\t\"bk:gamepad_desc\": \"FPS Stabili\",\n\t\"bk:hotdog\": \"Hotdog\",\n\t\"bk:bomb_shell\": \"Bomba Scudo\",\n\t\"bk:bomb_shell_desc\": \"Vita Strana\",\n\t\"painting_no_idea\": \"Nessun Idea\",\n\t\"painting_tinkerer\": \"Il Pensatore\",\n\t\"painting_in_loving_memory_of_ali\": \"In memoria di Ali\",\n\t\"painting_happy_accident\": \"incidente felice\",\n\t\"painting_observing_cheese\": \"Formaggio osservatore\",\n\t\"painting_chicken_enemy_unknown\": \"Gallina nemico sconosciuto\",\n\t\"painting_know_stuff\": \"Cose che si sanno\",\n\t\"painting_whoops\": \"Whoops\",\n\t\"painting_too_lake\": \"troppo lago\",\n\t\"painting_step_through\": \"Soglia\",\n\t\"painting_thats_a_moon\": \"E' una luna\",\n\t\"painting_totem\": \"Cerchio Magico\",\n\t\"painting_too_late\": \"Troppo Tardi\",\n\t\"painting_whipped_cream\": \"Panna Montata\",\n\t\"painting_beet_boys\": \"Beet Bois\",\n\t\"painting_moonshine\": \"Liquore di luna\",\n\t\"painting_void\": \"Il Vuoto\",\n\t\"painting_peasants\": \"Villici\"\n}"
  },
  {
    "path": "BurningKnight/Content/Locales/pl.json",
    "content": "﻿{\n\t\"bk:halo\": \"Aureola\",\n\t\"bk:halo_desc\": \"Zdrowie zwiekszone\",\n\t\"bk:revolver\": \"Rewolwer\",\n\t\"bk:sword\": \"Drewniany Miecz\",\n\t\"bk:sword_desc\": \"Nie jakis tam patyk\",\n\t\"bk:heart\": \"Serce\",\n\t\"resume\": \"Wznów\",\n\t\"settings\": \"Opcje\",\n\t\"restart\": \"Restart\",\n\t\"death_message\": \"Umarles\",\n\t\"descend\": \"Zejdz\",\n\t\"ascend\": \"Wejdz\",\n\t\"exit\": \"Wyjdz\",\n\t\"painting_rexcellent\": \"Wysmienicie\",\n\t\"painting_grannylisa\": \"Babciolisa\",\n\t\"painting_maanex\": \"Mysliciel\",\n\t\"painting_bk\": \"Przypieczony Rycerz\",\n\t\"painting_failpositive\": \"Imprezotwórca\",\n\t\"painting_old_man\": \"Naprawde Stary Czlowiek\",\n\t\"painting_arthouse\": \"Dom Sztuki\",\n\t\"painting_black\": \"Wszechswiat\",\n\t\"painting_milt\": \"Chlopiec w sniegu\",\n\t\"painting_skyscraper\": \"Samotny drapacz chmur\",\n\t\"painting_egor\": \"Plonacy Rex\",\n\t\"painting_null\": \"NULL\",\n\t\"painting_badosz\": \"Samotny Chlopiec w Lesie\",\n\t\"painting_banana\": \"BANANA\",\n\t\"painting_tv\": \"TV na niebie\",\n\t\"painting_company\": \"Dobre Towarzystwo\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Pies da Trasevol\",\n\t\"painting_lamp\": \"Bierz to\",\n\t\"painting_scream\": \"Lód\",\n\t\"painting_stars\": \"Strrraszna noc\",\n\t\"painting_fog\": \"W Oceanach\",\n\t\"painting_nufflee\": \"Hau\",\n\t\"by\": \"Autor:\",\n\t\"old_man_0\": \"To niebezpieczne!\",\n\t\"continue_run\": \"Kontynuuj Podejscie\",\n\t\"new_run\": \"Nowe Podejscie\",\n\t\"was_unlocked\": \"Zostal odblokowany!\",\n\t\"bk:revolver_desc\": \"Rece do góry, @everyone!\",\n\t\"bk:shovel\": \"Niebieska Lopata\",\n\t\"bk:shovel_desc\": \"Dlaczego jest niebieska???\",\n\t\"beet_0\": \"Siemka!\",\n\t\"beet_2\": \"Powiedz mi jego imie!\",\n\t\"npc_hurt_0\": \"Ojej.\",\n\t\"npc_hurt_1\": \"To boli.\",\n\t\"npc_hurt_2\": \"O nie.\",\n\t\"beet_3\": \"Dzieki <3\",\n\t\"beet_1\": \"Czy chcialbys zasadzic ^^nasionko^^?\",\n\t\"beet_1_0\": \"Tak!\",\n\t\"beet_1_1\": \"Nah.\",\n\t\"beet_4\": \"Seed to [vr seed]. Czy chcesz to zmienic?\",\n\t\"beet_4_0\": \"Tak!\",\n\t\"beet_4_1\": \"Nah.\",\n\t\"beet_5\": \"Niewazne\",\n\t\"beet_4_2\": \"Pozwólmy mu byc losowym!\",\n\t\"beet_6\": \"Ok. Seed to teraz [vr seed]!\",\n\t\"bk:idol\": \"Idol\",\n\t\"bk:idol_desc\": \"To pulapka!\",\n\t\"bk:key\": \"Zloty Klucz\",\n\t\"bk:infinite_bomb\": \"Nieskonczona Bomba\",\n\t\"bk:infinite_bomb_desc\": \"Bomba uzytkowa\",\n\t\"throw_coin\": \"Wrzuc Monete\",\n\t\"bk:potatoo\": \"Ziemniok\",\n\t\"bk:potatoo_desc\": \"Dzieli pociski\",\n\t\"bk:spectacles\": \"Okulary\",\n\t\"bk:spectacles_desc\": \"Odkrywa sekrety\",\n\t\"bk:cross\": \"Krzyz\",\n\t\"bk:cross_desc\": \"Zwieksza czas nietykalnosci po otrzymaniu obrazen\",\n\t\"bk:slime\": \"Szlam\",\n\t\"bk:slime_desc\": \"Odbijajace pociski\",\n\t\"bk:missile\": \"Rakieta\",\n\t\"bk:missile_desc\": \"Naprawadzajace pociski\",\n\t\"bk:rod_of_discord\": \"Rózdzka Discorda\",\n\t\"bk:rod_of_discord_desc\": \"Teleporter dla @everyone\",\n\t\"bk:goo\": \"Glut\",\n\t\"bk:goo_desc\": \"Orbitujacy przyjaciel\",\n\t\"bk:jelly\": \"Galaretka\",\n\t\"bk:jelly_desc\": \"^^Sprezysta^^\",\n\t\"bk:broken_stone\": \"Podniszczony Kamien\",\n\t\"bk:broken_stone_desc\": \"Porzadnie zbudowany orbital\",\n\t\"bk:nano_orb\": \"Nano Kula\",\n\t\"bk:nano_orb_desc\": \"Malutki przyjaciel\",\n\t\"bk:saturn\": \"Planeta\",\n\t\"bk:saturn_desc\": \"Oczywiscie, nadal ja kochamy\",\n\t\"bk:soap\": \"Mydlo\",\n\t\"bk:soap_desc\": \"Spowalnia twoje pociski\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"^^Przelosuj^^ przedmioty!\",\n\t\"bk:my_heart\": \"Moje Serduszko\",\n\t\"bk:my_heart_desc\": \"Zwieksza zdrowie\",\n\t\"bk:broken_heart\": \"Zlamane Serce\",\n\t\"bk:broken_heart_desc\": \"Zwieksza zdrowie\",\n\t\"bk:parcel\": \"Paczka\",\n\t\"bk:parcel_desc\": \"Zawiera lekarstwa\",\n\t\"bk:glass\": \"Szklo\",\n\t\"bk:glass_desc\": \"##Kruche## pociski\",\n\t\"bk:glass_bullet\": \"Szklany Pocisk\",\n\t\"bk:glass_bullet_desc\": \"Strzelaj nad kamieniami\",\n\t\"bk:broken_guitar\": \"Zepsuta Gitara\",\n\t\"bk:broken_guitar_desc\": \"Rock and Roll!\",\n\t\"bk:machine_gun\": \"Karabin\",\n\t\"bk:machine_gun_desc\": \"Maszynowy\",\n\t\"bk:grenade_launcher\": \"Granatnik\",\n\t\"bk:grenade_launcher_desc\": \"Kaboom!\",\n\t\"bk:shotgun\": \"Strzelba\",\n\t\"bk:shotgun_desc\": \"Prosto w twarz!\",\n\t\"bk:missile_launcher\": \"Rakietnica\",\n\t\"bk:missile_launcher_desc\": \"Cel namierzony!\",\n\t\"bk:burst_gun\": \"Pistolet maszynowy\",\n\t\"bk:burst_gun_desc\": \"Predkosc swiatla\",\n\t\"bk:flak_cannon\": \"Dzialo Odlamkowe\",\n\t\"bk:flak_cannon_desc\": \"Czas sie zabawic!\",\n\t\"bk:disk_gun\": \"Pistolet Dyskowy\",\n\t\"bk:disk_gun_desc\": \"Ostro pogrywasz\",\n\t\"bk:duck_gun\": \"Kacza Bron\",\n\t\"bk:duck_gun_desc\": \"Kwakers!\",\n\t\"bk:follower\": \"Podazacz\",\n\t\"bk:follower_desc\": \"Za mna!\",\n\t\"bk:portal_gun\": \"Pistolet Portalowy\",\n\t\"bk:portal_gun_desc\": \"Ciasto to klamstwo\",\n\t\"bk:snowflake\": \"Platek Sniegu\",\n\t\"bk:snowflake_desc\": \"Zimno.\",\n\t\"bk:restock\": \"Dostawa\",\n\t\"bk:restock_desc\": \"Nieskonczona dostawa do sklepu\",\n\t\"bk:charisma_ring_desc\": \"Czarny piatek!\",\n\t\"bk:charisma_ring\": \"Pierscien Charyzmy\",\n\t\"bk:battery\": \"Bateria\",\n\t\"tomb_0\": \"Tutaj spoczywa [cl green]Gobbo[cl] Wielki\",\n\t\"bk:homemade_dice\": \"Kostka Domowej Roboty\",\n\t\"bk:homemade_dice_desc\": \"^^Przelosuj^^ przedmioty! (Zrób to sam)\",\n\t\"shopkeeper_0\": \"##POWIEDZIALEM NIE RÓB TEGO!##\",\n\t\"shopkeeper_1\": \"Prosze, przestan!\",\n\t\"shopkeeper_2\": \"Nie rób tego.\",\n\t\"shopkeeper_3\": \"[cl red]##PRZYGOTUJ SIE NA SMIERC!##\",\n\t\"shopkeeper_4\": \"[cl red]ZLODZIEJ!\",\n\t\"shopkeeper_5\": \"[cl red]BRAC GO!\",\n\t\"desert\": \"Pustynny Palac\",\n\t\"jungle\": \"Starozytna Dzungla\",\n\t\"ice\": \"Lodowe Ruiny\",\n\t\"bk:iron_boots\": \"Metalowe Buty\",\n\t\"bk:iron_boots_desc\": \"Kolce cie nie skrzywdza. Nigdy wiecej.\",\n\t\"bk:mimic_totem\": \"Totem Mimików\",\n\t\"bk:mimic_totem_desc\": \"##NIGDY WIECEJ MIMIKÓW##\",\n\t\"back_to_town\": \"Wróc do Miasta\",\n\t\"bk:glass_gun\": \"Szklana Giwera\",\n\t\"bk:glass_gun_desc\": \"##Krucha##\",\n\t\"bk:glass_shard\": \"Odlamek Szkla\",\n\t\"bk:glass_shard_desc\": \"Raczej nic z tego nie ulozysz.\",\n\t\"bk:disk_10\": \"Plyta nr 10\",\n\t\"bk:disk_10_desc\": \"Sklepikarz\",\n\t\"bk:disk_1\": \"Plyta nr 1\",\n\t\"bk:disk_1_desc\": \"Dom\",\n\t\"bk:disk_2\": \"Plyta nr 2\",\n\t\"bk:disk_2_desc\": \"Las\",\n\t\"bk:disk_3\": \"Plyta nr 3\",\n\t\"bk:disk_3_desc\": \"Dzungla\",\n\t\"bk:disk_4\": \"Plyta nr 4\",\n\t\"bk:disk_4_desc\": \"Lód\",\n\t\"bk:disk_5\": \"Plyta nr 5\",\n\t\"bk:disk_5_desc\": \"Loch\",\n\t\"bk:disk_6\": \"Plyta nr 6\",\n\t\"bk:disk_6_desc\": \"Pieklo\",\n\t\"bk:disk_7\": \"Plyta nr 7\",\n\t\"bk:disk_7_desc\": \"???\",\n\t\"bk:disk_8\": \"Plyta nr 8\",\n\t\"bk:disk_8_desc\": \"Otchlan\",\n\t\"bk:disk_9\": \"Plyta nr 9\",\n\t\"bk:disk_9_desc\": \"Tnij\",\n\t\"bk:dagger\": \"Sztylet\",\n\t\"bk:dagger_desc\": \"Nostalgia...\",\n\t\"bk:spear\": \"Dzida\",\n\t\"bk:spear_desc\": \"Dluzsze rece?\",\n\t\"shopkeeper_6\": \"Witaj :)\",\n\t\"shopkeeper_7\": \"Siemka, moze [cl yellow]herbatki[cl]?\",\n\t\"shopkeeper_8\": \"Jak tam?\",\n\t\"back\": \"Wróc\",\n\t\"master_volume\": \"Dzwiek\",\n\t\"music\": \"Muzyka\",\n\t\"sfx\": \"Efekty Dzwiekowe\",\n\t\"graphics\": \"Grafika\",\n\t\"audio\": \"Audio\",\n\t\"ui_sfx\": \"Efekty Dzwiekowe w UI\",\n\t\"on\": \"Wlaczone\",\n\t\"off\": \"Wylaczone\",\n\t\"fullscreen\": \"Pelny Ekran\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Licznik FPS\",\n\t\"speedrun_timer\": \"Timer dla Speedrunerów\",\n\t\"screenshake\": \"Wstrzasy Ekranu\",\n\t\"freeze_frames\": \"Freeze Frames\",\n\t\"flash_frames\": \"Flash Frames\",\n\t\"reset_progress\": \"Zresetuj Progres\",\n\t\"blood_n_gore\": \"Krew i Flaki\",\n\t\"vegan_mode\": \"Tryb dla Weganów\",\n\t\"reset_settings\": \"Ustawienia Domyslne\",\n\t\"are_you_sure\": \"Czy jestes pewien?\",\n\t\"yes\": \"Tak\",\n\t\"reset_progress_dis\": \"To skasuje CALY twój postep!\",\n\t\"reset_settings_dis\": \"To ustawi WSZYSTKIE ustawienia na domyslne!\",\n\t\"autosave\": \"Automatyczny Zapis\",\n\t\"autopause\": \"Automatyczna Pauza\",\n\t\"input\": \"Wejscie\",\n\t\"use\": \"Uzyj\",\n\t\"active\": \"Aktywne\",\n\t\"bomb\": \"Bomba\",\n\t\"interact\": \"Interakcja\",\n\t\"swap\": \"Zmiana Broni\",\n\t\"roll\": \"Unik\",\n\t\"duck\": \"Kaczka\",\n\t\"pause\": \"Pauza\",\n\t\"none\": \"Nic\",\n\t\"keyboard_controls\": \"Klawiatura – Kontrolki\",\n\t\"gamepad_controls\": \"Pad - Kontrolki\",\n\t\"keyboard\": \"Klawiatura\",\n\t\"gamepad\": \"Pad\",\n\t\"game\": \"Gra\",\n\t\"select\": \"Wybierz\",\n\t\"cursor\": \"Kursor\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"Najpopularniejsze Osiagniecie\",\n\t\"ach_bk:overshake\": \"Przetrzesienie\",\n\t\"ach_bk:overshake_desc\": \"1000% wstrzasów ekranu\",\n\t\"ach_bk:rip\": \"Umrzyj\",\n\t\"bk:emerald\": \"Szmaragd\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Dzieki!^^\",\n\t\"shopkeeper_11\": \"Co za %%wymiana%%!\",\n\t\"shopkeeper_12\": \"Chcialbys moze ^^cos^^ [cl red]kupic[cl]?\",\n\t\"shopkeeper_13\": \"Tylko dla [cl green]ciebie[cl], tylko dzisiaj!\",\n\t\"shopkeeper_14\": \"Co za [cl yellow]oferta[cl]!\",\n\t\"bk:magnifier\": \"Lupa\",\n\t\"bk:magnifier_desc\": \"Duze pociski\",\n\t\"bk:mushroom_hat\": \"Grzybia Czapka\",\n\t\"bk:mushroom_hat_desc\": \"Zjadlbys?\",\n\t\"bk:stone_hat\": \"Kamienna Czapka\",\n\t\"bk:stone_hat_desc\": \"Ciezka\",\n\t\"bk:knight_hat\": \"Rycerska Czapka\",\n\t\"bk:knight_hat_desc\": \"Starzy dobrzy wrogowie...\",\n\t\"bk:cowboy_hat\": \"Kowbojski Kapelusz\",\n\t\"bk:cowboy_hat_desc\": \"Dzika Pólnoc..? Moze poludnie?\",\n\t\"bk:soup_hat\": \"Zupna Czapka\",\n\t\"bk:soup_hat_desc\": \"^^Mniam^^\",\n\t\"bk:gold_hat\": \"Zlota Czapka\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Bogactwo!\",\n\t\"bk:viking_hat\": \"Helm Vikingów\",\n\t\"bk:viking_hat_desc\": \"Ameryka!\",\n\t\"bk:dunce_hat\": \"Osla Czapka\",\n\t\"bk:dunce_hat_desc\": \"Osiol!\",\n\t\"bk:top_hat\": \"Cylinder\",\n\t\"bk:top_hat_desc\": \"Elegancja i klasa!\",\n\t\"bk:ushanka\": \"Uszatka\",\n\t\"bk:ushanka_desc\": \"Gdzie jest moja ##balalajka?##\",\n\t\"bk:valkyrie_hat\": \"Helm Walkirii\",\n\t\"bk:valkyrie_hat_desc\": \"Wierze ze ^^moge latac!^^, ale nie tym razem\",\n\t\"bk:skull_hat\": \"Czaszkoczapa\",\n\t\"bk:skull_hat_desc\": \"Pieniadze albo zycie!\",\n\t\"bk:grandma_head\": \"Glowa Babci\",\n\t\"bk:grandma_head_desc\": \"Herbatki?\",\n\t\"bk:diamond_helmet\": \"Diamentowy Helm\",\n\t\"bk:diamond_helmet_desc\": \"Nie kop prosto pod siebie!\",\n\t\"bk:villager_head\": \"Glowa Wiesniaka\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fez\",\n\t\"bk:fez_desc\": \"Czerwony\",\n\t\"bk:no_hat\": \"Usun Czapke\",\n\t\"bk:no_hat_desc\": \"Nie ma czapki, nie ma problemów!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"Attempt to call a null value\",\n\t\"accessorytrader_0\": \"##WYNOCHA STAD!## [dl]Albo kup te ^^piekniutkie^^ przedmiociki za jedyne ^^%%99 diamentów za sztuke%%^^!\",\n\t\"accessorytrader_1\": \"Czesc!\",\n\t\"accessorytrader_2\": \"Siemson!\",\n\t\"weapontrader_0\": \"Wejdz!\",\n\t\"weapontrader_1\": \"Dzien dobry, sir!\",\n\t\"weapontrader_2\": \"Chcialbys cos kupic?\",\n\t\"activetrader_0\": \"Najlepsze oferty na rynku!\",\n\t\"activetrader_1\": \"Placisz za 2 dostajesz 2!\",\n\t\"activetrader_2\": \"Daj mi donuta, [dl]prosze!!\",\n\t\"hattrader_0\": \"Chcesz byc taki cool jak ja? [dl]Kup sobie czapke!\",\n\t\"hattrader_1\": \"Chcesz byc taki cool jak ja? [dl]Ja tez, heh\",\n\t\"hattrader_2\": \"^^Cza cza czapki!^^\",\n\t\"granny_0\": \"Chcialbys troche herbatki, wnusiu?\",\n\t\"granny_1\": \"Moze herbaty?\",\n\t\"granny_2\": \"Herbaty?\",\n\t\"bk:xmas_hat\": \"Mikolajowa Czapka\",\n\t\"bk:xmas_hat_desc\": \"Wesolych Swiat!\",\n\t\"bk:pumpkin_hat\": \"Dynia\",\n\t\"bk:pumpkin_hat_desc\": \"^^Buuu^^\",\n\t\"bk:cage_key\": \"Klucz do klatki\",\n\t\"bk:cage_key_desc\": \"Ocal ^^jakiegos goscia^^!\",\n\t\"npc_0\": \"Uratuj mnie! Znajdz klucz!\",\n\t\"npc_1\": \"Dzieki za ratunek!\",\n\t\"npc_2\": \"Szybciej! Otwórz drzwi!\",\n\t\"npc_3\": \"Prosze! Pomóz mi!\",\n\t\"control_0\": \"Wcisnij [ic 0][ic 1] aby postawic bombe\",\n\t\"control_1\": \"Unikac mozesz ty! Nacisnij [ic 0][ic 1] aby moc zdobyc!\",\n\t\"control_2\": \"Nacisnij [ic 0][ic 1] aby zaatakowac\",\n\t\"control_3\": \"Nacisnij [ic 0][ic 1] aby zaczac interakcje\",\n\t\"control_4\": \"Kwa? [ic 0][ic 1]!\",\n\t\"control_5\": \"Nacisnij [ic 0][ic 1] aby zmienic bron\",\n\t\"shopkeeper_15\": \"Nie ma promocji!\",\n\t\"shopkeeper_16\": \"Zgarnij wiecej kasy i wróc!\",\n\t\"shopkeeper_17\": \"Najpierw zaplac!\",\n\t\"bk:frog\": \"Telezabs\",\n\t\"bk:frog_desc\": \"Szybka Podróz?\",\n\t\"bk:sword_orbital\": \"Miecz Orbitalny\",\n\t\"bk:sword_orbital_desc\": \"Sprawiedliwosc\",\n\t\"robbed\": \"Okradziony\",\n\t\"bk:gift_desc\": \"Co jest w srodku? Oby nie skarpetki.\",\n\t\"bk:spike_ring\": \"Pierscien z Kolcami\",\n\t\"bk:spike_ring_desc\": \"Twoi przeciwnicy musza zostac ##ukarani##!\",\n\t\"bk:fire_ring\": \"Pierscien Ognia\",\n\t\"bk:fire_ring_desc\": \"Pozwól twoim wrogom plonac\",\n\t\"bk:ice_ring\": \"Pierscien Mrozu\",\n\t\"bk:ice_ring_desc\": \"Ale z ciebie zimny typ\",\n\t\"bk:duck_ring\": \"Kaczy Pierscien\",\n\t\"bk:duck_ring_desc\": \"Teleportuj sie po trafieniu\",\n\t\"bk:dull_blade\": \"Tepe Ostrze\",\n\t\"bk:dull_blade_desc\": \"Zalacza efekt okaleczenia\",\n\t\"bk:sharp_blade\": \"Ostre Ostrze\",\n\t\"bk:sharp_blade_desc\": \"Samookaleczanie\",\n\t\"bk:obsidian_shield\": \"Obsydianowa Tarcza\",\n\t\"bk:obsidian_shield_desc\": \"Odrzut = 0\",\n\t\"bk:bill\": \"Rachunek\",\n\t\"bk:bill_desc\": \"99 dolarów\",\n\t\"control_6\": \"Uzyj przedmiotu aktywnego naciskajac [ic 0][ic 1]\",\n\t\"bk:clover\": \"Czterolistna Koniczyna\",\n\t\"bk:clover_desc\": \"Szczesciarz!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^Przelosuj %%swoje artefakty%%!^^\",\n\t\"brastin_0\": \"Znajdz obraz [cl purple]kota[cl]!\",\n\t\"elon_0\": \"Moge zamienic twoja bron w inna\",\n\t\"elon_1\": \"Prosze! Baw sie dobrze.\",\n\t\"bk:maanex_head\": \"Glowa Maanexa\",\n\t\"bk:maanex_head_desc\": \"Hmmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Zmus wrogów do naglych rozmyslan\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Plany Pietra\",\n\t\"bk:map_greenprints_desc\": \"Odkrywa mape\",\n\t\"bk:map\": \"Mapa\",\n\t\"bk:map_desc\": \"Pernamentnie odkrywa mape\",\n\t\"milt_1\": \"Chce prezent\",\n\t\"mapuzzle_0\": \"Grawitacja\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Skopiowane!\",\n\t\"isaac_0\": \"Zycie nia ma sensu...\",\n\t\"isaac_1\": \"Dlaczegoooooooo\",\n\t\"isaac_2\": \":szloch:\",\n\t\"discord_0\": \"Powiedz hi! discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"Unikaj, glupcze!\",\n\t\"tutorial\": \"Poradnik\",\n\t\"bk:the_key\": \"Klucz\",\n\t\"bk:the_key_desc\": \"Otwiera wyjscie\",\n\t\"bk:crying_bomb\": \"Placzaca Bomba\",\n\t\"bk:crying_bomb_desc\": \"Bomby teraz placza!\",\n\t\"bk:matches\": \"Zapalki\",\n\t\"bk:matches_desc\": \"Krótszy czas przed eksplozja\",\n\t\"bk:bomb_pack\": \"Paczka Bomb\",\n\t\"bk:bomb_pack_desc\": \"Wlozymy bomby w twoje bomby!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 bomb\",\n\t\"bk:weird_mushroom_desc\": \"Podwaja wszystko\",\n\t\"bk:weird_mushroom\": \"Dziwny Grzyb\",\n\t\"bk:bomb_shower\": \"Prysznic z Bomb\",\n\t\"bk:bomb_shower_desc\": \"Uwazaj podczas uzywania tej zabawki\",\n\t\"bk:black_belt\": \"Czarny Pas\",\n\t\"bk:black_belt_desc\": \"Wybuchów nigdy wiecej\",\n\t\"bk:ninjia_bomb\": \"Ninja Bomba\",\n\t\"bk:ninjia_bomb_desc\": \"Ból przywoluje bomby\",\n\t\"start_new_run\": \"Twoje obecne podejscie bedzie stracone!\",\n\t\"bk:laser_pointer\": \"Celownik Laserowy\",\n\t\"bk:laser_pointer_desc\": \"Wiem gdzie strzelac!\",\n\t\"ach_bk:marauder\": \"Rabus\",\n\t\"ach_bk:marauder_desc\": \"Zabij sklepikarza\",\n\t\"ach_bk:treasure_hunter\": \"Poszukiwacz skarbów\",\n\t\"ach_bk:treasure_hunter_desc\": \"Znajdz sekretny pokój\",\n\t\"ach_bk:dodge_master\": \"Mistrz uników\",\n\t\"ach_bk:dodge_master_desc\": \"Zabij bossa bez otrzymania obrazen\",\n\t\"ach_bk:dodge_overlord\": \"Lord Uników\",\n\t\"ach_bk:dodge_overlord_desc\": \"Ukoncz pietro bez otrzymania obrazen\",\n\t\"ach_bk:quackers\": \"Kwakers\",\n\t\"ach_bk:quackers_desc\": \"Overkwak\",\n\t\"ach_bk:tea_party\": \"Impreza u Babci\",\n\t\"ach_bk:tea_party_desc\": \"Badz na babcinej herbatkowej imprezie\",\n\t\"ach_bk:not_a_thief\": \"Nie Zlodziej\",\n\t\"ach_bk:not_a_thief_desc\": \"Ukoncz podejscie bez podnoszenia przedmiotów\",\n\t\"ach_bk:npc_party2\": \"Druzyna NPC\",\n\t\"ach_bk:npc_party2_desc\": \"Ocal wszystkich NPC\",\n\t\"bk:gold_coin\": \"Zlota Moneta\",\n\t\"bk:iron_coin\": \"Srebrna Moneta\",\n\t\"bk:copper_coin\": \"Miedziana Moneta\",\n\t\"bk:platinum_coin\": \"Platynowa Moneta\",\n\t\"bk:voodoo_doll\": \"Lalka Voodoo\",\n\t\"bk:voodoo_doll_desc\": \"Zabija wszystkich przeciwników w pokoju\",\n\t\"hub\": \"Miasto Unik\",\n\t\"castle\": \"Ruiny Zamku\",\n\t\"charger_0\": \"NIE WYKRYTO PRZEDMIOTU AKTYWNEGO\",\n\t\"charger_1\": \"PRZEDMIOT AKTYWNY JEST JUZ NALADOWANY\",\n\t\"charger_2\": \"GDZIE SA MOJE PIENIADZE, WORKU MIESA!\",\n\t\"charger_3\": \"##POWIEDZIALEM DAJ MI MOJE PIENIADZE!##\",\n\t\"charger_4\": \"##PRZEJME KONTROLE NAD SWIATEM!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Okej, zróbmy to!\",\n\t\"maanex_6_1\": \"Nah.\",\n\t\"maanex_6\": \"Dobra, daj mi [cl yellow][vr cost] monet[cl] A ja pozwole ci otworzyc jedna z tych trzech skrzyn. Okej?\",\n\t\"maanex_5\": \"Hej ty, chcialbys ^^wypróbowac^^ swoje szczescie?\",\n\t\"maanex_7\": \"To byla niezla frajda!\",\n\t\"maanex_8\": \"Zycze szczescia!\",\n\t\"maanex_9\": \"Cóz, nie tym razem :(\",\n\t\"maanex_10\": \"%%^^WOAH^^%%\",\n\t\"maanex_11\": \"Ale nie masz wystarczajacej ilosci pieniedzy!\",\n\t\"maanex_12\": \"##SYN?!##\",\n\t\"bk:amurs_arrow\": \"Strzala Amora\",\n\t\"bk:amurs_arrow_desc\": \"Zauraczajace pociski\",\n\t\"bk:amurs_bow\": \"Luk Amora\",\n\t\"bk:amurs_bow_desc\": \"Widze milosc\",\n\t\"bk:poison_flask\": \"Fiolka z Trucizna\",\n\t\"bk:poison_flask_desc\": \"Zatrute pociski\",\n\t\"bk:snowball\": \"Sniezka\",\n\t\"bk:snowball_desc\": \"Lodowe pociski\",\n\t\"bk:peper_desc\": \"Gorace pociski\",\n\t\"bk:peper\": \"Papryczka Chili\",\n\t\"bk:sale_coupon\": \"Kupon na Wyprzedaz\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Zwierzak w Pudelku\",\n\t\"bk:pet_box_desc\": \"Kto jest w srodku?\",\n\t\"bk:crate\": \"Skrzynka z Orbitalem\",\n\t\"bk:crate_desc\": \"Kto jest w srodku?\",\n\t\"bk:strawberry\": \"Truskawka\",\n\t\"bk:strawberry_desc\": \"Slodkie wspomnienia\",\n\t\"bk:wings\": \"Skrzydla\",\n\t\"bk:wings_desc\": \"Wierze, ze moge latac\",\n\t\"bk:coin_pouch\": \"Sakiewka z Monetami\",\n\t\"bk:coin_pouch_desc\": \"Daje monety\",\n\t\"bk:key_pouch\": \"Sakiewka z Kluczami\",\n\t\"bk:key_pouch_desc\": \"Daje klucze\",\n\t\"bk:bomb_pouch\": \"Sakiewka z Bombami\",\n\t\"bk:bomb_pouch_desc\": \"Daje bomby\",\n\t\"bk:pouch_pouch\": \"Sakiewka z Sakiewkami\",\n\t\"bk:pouch_pouch_desc\": \"Daje sakiewki\",\n\t\"bk:lightsaber\": \"Miecz Swietlówkowy\",\n\t\"bk:lightsaber_desc\": \"Byles wybrancem!\",\n\t\"bk:snail\": \"Slimak\",\n\t\"bk:snail_desc\": \"Slimak, slimak pokaz rogi\",\n\t\"bk:spike\": \"Kolczasta Kula\",\n\t\"bk:spike_desc\": \"Obrazenia zwiekszone\",\n\t\"bk:mushroom\": \"Grzyb\",\n\t\"bk:mushroom_desc\": \"Szybkosc zwiekszona\",\n\t\"bk:candy\": \"Cukierek\",\n\t\"bk:candy_desc\": \"^^Cukier^^, szybkosc strzelania zwiekszona\",\n\t\"bk:glasses\": \"Bryle\",\n\t\"bk:glasses_desc\": \"Celnosc zwiekszona\",\n\t\"bk:ruler\": \"Linijka\",\n\t\"bk:ruler_desc\": \"Zasieg strzalu zwiekszony\",\n\t\"bk:stopwatch\": \"Stopczas\",\n\t\"bk:stopwatch_desc\": \"Obrywanie kontroluje czas\",\n\t\"bk_0\": \"##NIE WAZ SIE TEGO TKNAC!##\",\n\t\"bk_1\": \"##POWIEDZIALEM NIE DOTYKAJ!##\",\n\t\"bk_2\": \"##NIE MOZESZ POKONAC [cl red]PLONACEGO RYCERZA[cl], GLUPCZE!##\",\n\t\"bk_3\": \"##SZYKUJ SIE NA SMIERC!##\",\n\t\"bk_4\": \"^^ZABAWNE^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Goraca wyprzedaz![cl]\",\n\t\"dm_0\": \"@@Witaj@@\",\n\t\"ach_bk:deal\": \"Niespodziewany Ruch\",\n\t\"ach_bk:deal_desc\": \"Dokonaj interesu z Mrocznym Magiem\",\n\t\"ach_bk:grannys_gift\": \"Prezent od Babci\",\n\t\"ach_bk:grannys_gift_desc\": \"Wez prezent od Babci\",\n\t\"ach_bk:shopper\": \"Kupuj Póki Mozesz\",\n\t\"ach_bk:shopper_desc\": \"Kup przedmiot w sklepie\",\n\t\"bk_5\": \"NA TWOIM MIEJSCU BYM Z NIM NIE ROZMAWIAL\",\n\t\"bk_6\": \"##ZABIJ GO, [cl lime]EDWARD[cl]!##\",\n\t\"bk_7\": \"[cl lime]EDWARD[cl], ##NIEEEEEE!!!!##\",\n\t\"bk_8\": \"OH PROSZE CIE, PRZESTAN WYSADZAC MÓJ ZAMEK!\",\n\t\"bk_9\": \"[cl pink]BABCIA[cl],[dl] CZY NIE MOZESZ PO PROSTU UMRZEC##?!?##\",\n\t\"bk_10\": \"MISTRZU,[dl] PRZYNIOSLEM [cl green]GOBLINA[cl]\",\n\t\"dm_1\": \"Bardzo dobrze[dl], dziekuje[dl] ci, [cl red]Limpor[cl]\",\n\t\"dm_2\": \"##Tak, tak, potrzebuje wiecej [cl orange]mocy[cl]!##\",\n\t\"dm_3\": \"##WIECEJ [cl orange]MOCY[cl]!\",\n\t\"dm_4\": \"Czuje [cl orange]moc[cl] pulsuje we mnie!\",\n\t\"granny_3\": \"Ty bedziesz pierwszy, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Witaj, [cl green]Gobbo[cl]!\",\n\t\"granny_5\": \"Zycze ci szczescia z twoim smutnym zadaniem!\",\n\t\"bk:meat_guy\": \"Miesogosc\",\n\t\"bk:meat_guy_desc\": \"Nadal nienawidzi Tofugoscia!\",\n\t\"bk:bullet_stone\": \"Pociskoglaz\",\n\t\"bk:bullet_stone_desc\": \"Nadal czuje niechec do mieczy!\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"Nie pomaga, ale daje baterie\",\n\t\"vibration\": \"Wibracja\",\n\t\"bk:sharp_arrow\": \"Ostra Strzala\",\n\t\"bk:sharp_arrow_desc\": \"Pociski przenikaja przez wrogów\",\n\t\"machine_0\": \"Wrzuc [cl yellow]monete\",\n\t\"player_0\": \"Tatus?? ##Co oni ci zrobili?!?##\",\n\t\"bk:boomerang\": \"Bumerang\",\n\t\"bk:boomerang_desc\": \"Bumerangowe pociski \",\n\t\"bk:backpack\": \"Plecak\",\n\t\"bk:backpack_desc\": \"Mój drogi przyjaciel (ok 10-15 monet)\",\n\t\"place_an_item\": \"Polóz Przedmiot\",\n\t\"bk:crystal\": \"Krysztal\",\n\t\"bk:crystal_desc\": \"Moc teczy\",\n\t\"bk:prism\": \"Pryzmat\",\n\t\"bk:prism_desc\": \"Pociski -> Tecza\",\n\t\"scourged\": \"Przeklety\",\n\t\"bk:bomb\": \"Bomba\",\n\t\"bk:scourge_of_egg\": \"Klatwa Jajka\",\n\t\"bk:scourge_of_egg_desc\": \"Pozamieniane nazwy przedmiotów\",\n\t\"bk:scourge_of_unknown\": \"Klatwa Niewiadomego\",\n\t\"bk:scourge_of_unknown_desc\": \"Ukryte Przedmioty\",\n\t\"bk:scourge_of_blood\": \"Klatwa Krwi\",\n\t\"bk:scourge_of_blood_desc\": \"Podwójne Klopoty (i przeciwnicy)\",\n\t\"bk:scourge_of_risk\": \"Klatwa Ryzyka\",\n\t\"bk:scourge_of_risk_desc\": \"Ukryte Zdrowie\",\n\t\"bk:scourge_of_keys\": \"Klatwa Kluczy\",\n\t\"bk:scourge_of_keys_desc\": \"Ukryte Znajdzki\",\n\t\"bk:scourge_of_lost\": \"Klatwa Zgubienia\",\n\t\"bk:scourge_of_lost_desc\": \"Amnezja\",\n\t\"bk:scourge_of_scourged\": \"Klatwa Przekletego\",\n\t\"bk:scourge_of_scourged_desc\": \"Klatwa Wszedzie\",\n\t\"bk:scourge_of_illness\": \"Klatwa Choroby\",\n\t\"bk:scourge_of_illness_desc\": \"Leczenie jest Oslabione\",\n\t\"bk:scourge_of_death\": \"Klatwa Smierci\",\n\t\"bk:scourge_of_death_desc\": \"Tryb Trudny\",\n\t\"bk:ancient_revolver\": \"Antyczny Rewolwer\",\n\t\"bk:ancient_revolver_desc\": \"Wyglada Fajnie\",\n\t\"bk:assault_rifle\": \"Karabin Szturmowy\",\n\t\"bk:assault_rifle_desc\": \"Piu piu\",\n\t\"fountain_0\": \"Przynies 5 monet a zostaniesz poblogoslawiony\",\n\t\"fountain_1\": \"Zostales czesciowo oczyszczony\",\n\t\"fountain_2\": \"Zostales calkowicie oczyszczony\",\n\t\"fountain_3\": \"Juz jestes czysty\",\n\t\"buffed\": \"Wzmocniony\",\n\t\"nerfed\": \"Oslabiony\",\n\t\"restored\": \"Zregenerowany\",\n\t\"damaged\": \"Skrzywdzony\",\n\t\"cleansed\": \"Oczyszczony\",\n\t\"gifted\": \"Obdarowany\",\n\t\"lucky\": \"Szczesliwy\",\n\t\"unlucky\": \"Pechowy\",\n\t\"max_hp\": \"Max HP\",\n\t\"touch\": \"Dotknij\",\n\t\"break\": \"Zniszcz\",\n\t\"no_coins\": \"Nie ma Monet\",\n\t\"old_man_6\": \"Niebezpiecznie jest isc samemu, wez to!\",\n\t\"roger_0\": \"Kabuum!\",\n\t\"roger_1\": \"##*BUUM*##\",\n\t\"roger_2\": \"Buum bum szakataka!\",\n\t\"bk:shield\": \"Tarcza\",\n\t\"bk:gift\": \"Prezent\",\n\t\"bk:shield_pouch\": \"Sakiewka z Tarczami\",\n\t\"bk:shield_pouch_desc\": \"Daje tarcze\",\n\t\"bk:shield_buddy\": \"Tarczowy Kumpel\",\n\t\"bk:shield_buddy_desc\": \"Obrywa za Ciebie\",\n\t\"bk:skeleton_key\": \"Kosciany Klucz\",\n\t\"bk:skeleton_key_desc\": \"99 kluczy\",\n\t\"bk:jar\": \"Sloik Zdrowia\",\n\t\"bk:jar_desc\": \"Jar Jar Klinks\",\n\t\"bk:star\": \"Gwiazda\",\n\t\"bk:star_desc\": \"On chronic\",\n\t\"bk:car_bomb\": \"Chodzaca Bomba\",\n\t\"bk:car_bomb_desc\": \"Bombowy Serwis Dostawczy\",\n\t\"bk:grenade\": \"Granat\",\n\t\"bk:grenade_desc\": \"Bomby wybuchaja przy dotknieciu\",\n\t\"trash_goblin_0\": \"Uwolnij mnie od mojej [cl purple]klatwy[cl]! Prosze!\",\n\t\"trash_goblin_1\": \"Jestem wolny! [dl] Dziekuje ci!\",\n\t\"boxy_0\": \"Czuje sie dzis kluczowo!\",\n\t\"boxy_1\": \"Jakie fajne pudelko!\",\n\t\"boxy_2\": \"Potrzebujesz papieru do pakowania?\",\n\t\"trash_goblin_2\": \"^^Przybiezeli do Betlejem...^^\",\n\t\"bk:vampire_bat\": \"Nietoperz Wampir\",\n\t\"bk:vampire_bat_desc\": \"Regen\",\n\t\"shields\": \"Tarcze\",\n\t\"bk:mustache\": \"Wasy\",\n\t\"bk:mustache_desc\": \"VIP\",\n\t\"bk:bloody_chest\": \"Krwawa Skrzynia\",\n\t\"bk:bloody_chest_desc\": \"Skrzynie lecza\",\n\t\"bk:bloody_shield\": \"Krwawa Tarcza\",\n\t\"bk:bloody_shield_desc\": \"Tarcze na zawsze\",\n\t\"bk:cutsaw\": \"Pila\",\n\t\"bk:cutsaw_desc\": \"Wrogowie zaplaca\",\n\t\"vampire_0\": \"Mniam!\",\n\t\"vampire_1\": \"Krwawo!\",\n\t\"vampire_2\": \"Jaka slodka!\",\n\t\"vampire_3\": \"Znamy zasady, [cl red]^^prawda[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"Jaka masz grupe krwi?\",\n\t\"vampire_6\": \"Jaka pyszna\",\n\t\"duck_2\": \"Chcialbys uczestniczyc w ankiecie?\",\n\t\"duck_7_0\": \"Tak\",\n\t\"duck_7_1\": \"Nie\",\n\t\"duck_7\": \"Czy dostaniesz ta skrzynie?\",\n\t\"duck_4\": \"Dobra robota, bierz swoja nagrode!\",\n\t\"duck_5\": \"Nie moge sie z toba zgodzic...\",\n\t\"duck_6_0\": \"Wszechswiat\",\n\t\"duck_6_1\": \"^^Kwaczki^^\",\n\t\"duck_6\": \"O czym mysle?\",\n\t\"duck_8_0\": \"[cl red]Czerwony[cl]\",\n\t\"duck_8_1\": \"[cl blue]Niebieski[cl]\",\n\t\"duck_8\": \"Jaki jest mój ulubiony ^^%%kolor%%^^?\",\n\t\"duck_9_0\": \"Kot\",\n\t\"duck_9_1\": \"Ty\",\n\t\"duck_9\": \"Kto powiedzial miau?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"Co lepsze\",\n\t\"duck_11_0\": \"Co, jajko?\",\n\t\"duck_11_1\": \"\\\\[_Dzga go._]\",\n\t\"duck_11\": \"Jestes fajnym chlopaczkiem\",\n\t\"duck_12_0\": \"Kurczak\",\n\t\"duck_12_1\": \"Jajko\",\n\t\"duck_12\": \"Co bylo pierwsze?\",\n\t\"duck_13_0\": \"Nic\",\n\t\"duck_13_1\": \"Przekaske\",\n\t\"duck_13_2\": \"Jajko\",\n\t\"duck_13_3\": \"Pieczony kurczak\",\n\t\"duck_13\": \"Co dzisiaj jadles?\",\n\t\"duck_14\": \"Aua.\",\n\t\"duck_17_0\": \"Oczywiscie\",\n\t\"duck_17_1\": \"##NJEEEEEE##\",\n\t\"duck_17\": \"Chcialbys ananasa na pizzy?\",\n\t\"duck_18_0\": \"Bialy!\",\n\t\"duck_18_1\": \"[cl yellow]Zólty[cl]!\",\n\t\"duck_18\": \"Jakiego koloru jest ser?\",\n\t\"nurse_0\": \"Wygladasz bardzo dobrze, slonko!\",\n\t\"nurse_1\": \"Moglabym cie uleczyc, ale potrzebuje [cl yellow][vr price] coins[cl]\",\n\t\"nurse_2\": \"Mam nadzieje ze nie bolalo\",\n\t\"elon_4\": \"Prosze, zabaw sie\",\n\t\"elon_2_0\": \"Okej\",\n\t\"elon_2_1\": \"Nah\",\n\t\"elon_2\": \"Pokazac ci magie?\",\n\t\"elon_3\": \"Moge zmienic twoja bron w inna\",\n\t\"elon_5\": \"Niewazne\",\n\t\"elon_7\": \"Ziom, gdzie twoja bron???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*Rumieni sie*\",\n\t\"gobetta_4\": \"Czy to... ty?\",\n\t\"gobetta_5\": \"To bylo tak dawno...\",\n\t\"ach_bk:desert\": \"Goraco\",\n\t\"ach_bk:desert_desc\": \"Dojdz do Pustynnego Palacu\",\n\t\"ach_bk:jungle\": \"Brzeczace Pszczólki\",\n\t\"ach_bk:jungle_desc\": \"Dojdz do Starozytnej Dzungli\",\n\t\"rooms_explored\": \"Odkrytych pokoi\",\n\t\"bk:shadow_cloak_desc\": \"Badz niczym cien\",\n\t\"bk:shadow_cloak\": \"Plaszcz Cienia\",\n\t\"bk:dynamite_stick\": \"Dynamit\",\n\t\"bk:dynamite_stick_desc\": \"Czy ty sie czlowieku chcesz wysadzic?\",\n\t\"bk:chalice_of_blood\": \"Kielich z Krwia\",\n\t\"bk:chalice_of_blood_desc\": \"Ból wywoluje gniew, gniew wywoluje obrazenia.\",\n\t\"bk:detonator\": \"Detonator\",\n\t\"bk:detonator_desc\": \"Powoduje detonacje materialów wybuchowych\",\n\t\"invincibility_time\": \"Czas Nietykalnosci\",\n\t\"accuracy\": \"Celnosc\",\n\t\"range\": \"Zasieg\",\n\t\"fire_rate\": \"Predkosc Strzalu\",\n\t\"speed\": \"Szybkosc\",\n\t\"bk:talisman_of_foresight\": \"Talizman Dalekowzrocznosci\",\n\t\"bk:talisman_of_foresight_desc\": \"Otwórz swe oczy i zobacz okoliczne pokoje!\",\n\t\"bk:scourge_ring\": \"Pierscien Klatwy\",\n\t\"bk:scourge_ring_desc\": \"Klatw nigdy wiecej\",\n\t\"snek_0\": \"Niezle.\",\n\t\"snek_1\": \"Dzieki ziomek\",\n\t\"snek_2\": \"Sssuper\",\n\t\"snek_3\": \"Sssiema\",\n\t\"snek_4\": \"Dzien dobry, ssssir\",\n\t\"snek_5\": \"Ssssprzedaje ciekawe przedmioty\",\n\t\"snek_6\": \"Klient musi byc usssatysssfakcjonowany...\",\n\t\"snek_7\": \"Zrobie, co bede musial!\",\n\t\"bk:snek\": \"Wunsz\",\n\t\"bk:snek_desc\": \"Przekassske?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Masz zapasowy klucz?\",\n\t\"boxy_5\": \"Moze oddasz nam troche kluczy?\",\n\t\"bk:blank\": \"Pustak\",\n\t\"bk:blank_desc\": \"_Pusty Tekst_\",\n\t\"bk:blank_bombs\": \"Puste Bomby\",\n\t\"bk:blank_bombs_desc\": \"Tarcza z pocisków\",\n\t\"bk:explosive_bullets\": \"Wybuchowe Pociski\",\n\t\"bk:explosive_bullets_desc\": \"Wybuchowe\",\n\t\"bk:random_bullets\": \"Losowe Pociski\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Kubek\",\n\t\"bk:cup_desc\": \"Babcia ma ochote sie pojawic\",\n\t\"bk:cartridge\": \"Kartridz\",\n\t\"bk:cartridge_desc\": \"Mroczny Mag ma ochote sie pojawic\",\n\t\"bk:marriage_ring\": \"Pierscionek Zareczynowy\",\n\t\"bk:marriage_ring_desc\": \"MM & Babcia na Zawsze!\",\n\t\"boxy_7\": \"Chce klucze\",\n\t\"boxy_8\": \"Wydaje mi sie, ze nie masz wystarczajacej ilosci kluczy :(\",\n\t\"boxy_9\": \"Nareszcie mam wystarczajaco kluczy, aby sie troche ^^otworzyc^^!\",\n\t\"roger_3\": \"Moze bys zaplacil, dla odmiany?\",\n\t\"roger_4\": \"Nie ma znizek\",\n\t\"roger_5\": \"Najpierw bomby\",\n\t\"vampire_7\": \"Nie jestes wystarczajaco zdrowy\",\n\t\"vampire_8\": \"U mnie nie ma znizek\",\n\t\"vampire_9\": \"Gosciu, ja nie chce cie zabic, wiesz?\",\n\t\"ach_bk:scourged\": \"Przeklety\",\n\t\"ach_bk:scourged_desc\": \"Podnies Przeklety Amulet\",\n\t\"ach_bk:scourged_weapon\": \"Przekleta Bron\",\n\t\"ach_bk:scourged_weapon_desc\": \"Podnies Przekleta Bron\",\n\t\"rerolled\": \"Przelosowane\",\n\t\"ach_bk:open_up\": \"Otwieranko\",\n\t\"ach_bk:open_up_desc\": \"Kup wszystko od Boxiego\",\n\t\"ach_bk:snek\": \"Wunsz Przyjaciel\",\n\t\"ach_bk:snek_desc\": \"Uzyj Wunsza jako swojego zwierzaka\",\n\t\"bk:scourge_of_greed\": \"Klatwa Chciwosci\",\n\t\"bk:scourge_of_greed_desc\": \"Wysokie ceny\",\n\t\"killed_by\": \"Zabity przez\",\n\t\"kills\": \"Zabójstwa\",\n\t\"time\": \"Czas\",\n\t\"depth\": \"Pietro\",\n\t\"bk:blank_bullets\": \"Puste Naboje\",\n\t\"bk:blank_bullets_desc\": \"Nazwa stwierdza ze sa puste\",\n\t\"bk:lego\": \"Konstruktor\",\n\t\"bk:lego_desc\": \"Zaczynasz wspólczuc swoim wrogom...\",\n\t\"bk:iron_armor\": \"Zelazna Zbroja\",\n\t\"bk:iron_armor_desc\": \"Daje tarcze\",\n\t\"bk:round_shield\": \"Okragla Tarcza\",\n\t\"bk:round_shield_desc\": \"Chroni przed obrazeniami kontaktowymi\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"Legenda we wlasnej osobie\",\n\t\"bk:inverted_arkhalis\": \"Odwrócona Arkhalis\",\n\t\"bk:inverted_arkhalis_desc\": \"Pomaga kiedy slabo u ciebie z zyciem\",\n\t\"bk:gun_sword\": \"Giweromiecz\",\n\t\"bk:gun_sword_desc\": \"Miecz czy giwera?\",\n\t\"ach_bk:scourge_king_desc\": \"Zdobadz 10 punktów klatwy\",\n\t\"ach_bk:scourge_king\": \"Przeklety Król\",\n\t\"ach_bk:sting_operation\": \"Operacja Zadlo\",\n\t\"ach_bk:sting_operation_desc\": \"Pokonaj Królowa Pszczól\",\n\t\"ach_bk:mummified\": \"Zmumifikowany\",\n\t\"ach_bk:mummified_desc\": \"Pokonaj Faroka\",\n\t\"ach_bk:democracy\": \"DEMOKRACJA\",\n\t\"ach_bk:democracy_desc\": \"Pokonaj Starego Króla\",\n\t\"pharaoh_scream\": \"##PRZYGOTUJ SIE NA MUMIFIKACJE!##\",\n\t\"queen_bee_scream\": \"##ZA LORDA [cl yellow]MIODU[cl]!##\",\n\t\"duck_19\": \"Moja siostra zostala wygnana do lochu kiedy... [cl red]on[cl]...    odkryl ze potrafi strzelac ogniem z ust... Ciekawe czy nadal tam jest?\",\n\t\"duck_20\": \"Kwaks! \",\n\t\"bk:half_heart\": \"Pól Serca\",\n\t\"right\": \"Prawo\",\n\t\"down\": \"Dól\",\n\t\"left\": \"Lewo\",\n\t\"up\": \"Góra\",\n\t\"painting_cat\": \"Obraz Kota\",\n\t\"bk:axe\": \"Siekiera\",\n\t\"bk:axe_desc\": \"Obiecal ze wróci\",\n\t\"bk:guitar\": \"Gitara\",\n\t\"bk:guitar_desc\": \"Rozstrojona\",\n\t\"bk:glass_sword\": \"Szklany Miecz\",\n\t\"bk:glass_sword_desc\": \"Bron mistrzów\",\n\t\"bk:chicken\": \"Skrzydelko z Kurczaka\",\n\t\"bk:chicken_desc\": \"Gorace\",\n\t\"bk:pickaxe\": \"Kilof\",\n\t\"bk:pickaxe_desc\": \"Kop, plebsie!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"Pól Many\",\n\t\"bk:lava_wand\": \"Lawowa Rózdzka\",\n\t\"bk:lava_wand_desc\": \"Goraco sie liczy\",\n\t\"bk:web_wand\": \"Pajecza Rózdzka\",\n\t\"bk:web_wand_desc\": \"Dostarcza siec na calym swiecie\",\n\t\"bk:slap_stick\": \"Patyk do Policzkowania\",\n\t\"bk:slap_stick_desc\": \"Klep\",\n\t\"sensivity\": \"Wrazliwosc\",\n\t\"no\": \"Nie\",\n\t\"scale\": \"Skala\",\n\t\"ach_bk:ice\": \"Epoka Lodowcowa\",\n\t\"ach_bk:ice_desc\": \"Dotrzyj do Lodowych Ruin\",\n\t\"ach_bk:library\": \"Swiete Teksty\",\n\t\"ach_bk:library_desc\": \"Dotrzyj do Sekretnej Biblioteki\",\n\t\"bk:ice_skates\": \"Lyzwy\",\n\t\"bk:ice_skates_desc\": \"Odpornosc na lód\",\n\t\"bk:campfire_in_bottle\": \"Ognisko w Butelce\",\n\t\"bk:campfire_in_bottle_desc\": \"Odpornosc na Zimno\",\n\t\"library\": \"Sekretna Biblioteka\",\n\t\"ach_bk:cat_without_a_hat\": \"Kot nie na plot\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Znajdz obraz kota\",\n\t\"ach_bk:rich\": \"Papier Toaletowy\",\n\t\"ach_bk:rich_desc\": \"+99 monet\",\n\t\"ach_bk:rescue_operation\": \"Operacja Ratunkowa\",\n\t\"ach_bk:rescue_operation_desc\": \"Uratuj NPC\",\n\t\"ach_bk:tutorial\": \"Guru\",\n\t\"ach_bk:tutorial_desc\": \"Ukoncz poradnik\",\n\t\"ach_bk:fancy_hat\": \"Niezla Czapka\",\n\t\"ach_bk:fancy_hat_desc\": \"Kup czapke\",\n\t\"ach_bk:unlock\": \"Odblokowywacz\",\n\t\"ach_bk:unlock_desc\": \"Odblokuj przedmiot\",\n\t\"floor_brightness\": \"Jasnosc Podlogi\",\n\t\"ach_bk:shielded\": \"Obrona\",\n\t\"ach_bk:shielded_desc\": \"Zdobadz tarcze\",\n\t\"run_type\": \"Typ podejscia\",\n\t\"run_regular\": \"Zwykly\",\n\t\"run_challenge\": \"Wyzwanie\",\n\t\"damage_taken\": \"Otrzymanych obrazen\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Przebyty dystans\",\n\t\"seed\": \"Seed\",\n\t\"score\": \"Wynik\",\n\t\"new_high_score\": \"Nowy rekord!\",\n\t\"items_collected\": \"Zdobyte przedmioty\",\n\t\"boss_rush\": \"Wyzwanie Bossów\",\n\t\"run_bossrush\": \"Wyzwanie Bossów\",\n\t\"bk:blindfold_desc\": \"RIP moje bronie\",\n\t\"bk:blindfold\": \"Na oslep\",\n\t\"daily_run\": \"Dzienne Podejscie\",\n\t\"builder_0_0\": \"Ta\",\n\t\"builder_0_1\": \"Potrzebuje tych pieniedzy\",\n\t\"builder_0\": \"Planuje wybudowac tu skrót, ale potrzebuje jeszcze [vr need] [ic 0] wiecej monet. Pomozesz mi?\",\n\t\"builder_1\": \"Ale nie masz zadnych pieniedzy! :(\",\n\t\"builder_2\": \"Dziekuje za panska inwestycje!\",\n\t\"builder_3\": \"Nareszcie mam wystarczajaco kasy na ten projekt! Bardzo dziekuje!\",\n\t\"builder_4\": \"Okej, przepraszam!\",\n\t\"shortcut_is_broken\": \"Skrót jest zepsuty\",\n\t\"ach_bk:boss_rush\": \"Pogromca Bossów\",\n\t\"ach_bk:boss_rush_desc\": \"Pokonaj wszystkich Bossów w Wyzwaniu Bossów\",\n\t\"ach_bk:daily\": \"Dzienna Chwala\",\n\t\"ach_bk:daily_desc\": \"Wygraj Dzienne Podejscie\",\n\t\"ach_bk:desert_shortcut\": \"Skrót do Pustynnego Palacu\",\n\t\"ach_bk:desert_shortcut_desc\": \"Napraw skrót do Pustynnego Palacu\",\n\t\"ach_bk:jungle_shortcut\": \"Skrót do Starozytnej Dzungli\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Napraw skrót do Starozytnej Dzungli\",\n\t\"ach_bk:ice_shortcut\": \"Skrót do Lodowych Ruin\",\n\t\"ach_bk:ice_shortcut_desc\": \"Napraw skrót do Lodowych Ruin\",\n\t\"ach_bk:library_shortcut\": \"Skrót do Sekretnej Biblioteki\",\n\t\"ach_bk:library_shortcut_desc\": \"Napraw skrót do Sekretnej Biblioteki\",\n\t\"ach_bk:fashion_matters2\": \"Moda\",\n\t\"ach_bk:fashion_matters2_desc\": \"Wykup czapki\",\n\t\"ach_bk:10_challenges\": \"Twardziel\",\n\t\"ach_bk:10_challenges_desc\": \"Wygraj 10 wyzwan\",\n\t\"ach_bk:20_challenges\": \"Twardziel 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Wygraj 20 wyzwan\",\n\t\"ach_bk:30_challenges\": \"Twardziel 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Wygraj 30 wyzwan\",\n\t\"ach_bk:bk_no_more\": \"PR nigdy wiecej\",\n\t\"ach_bk:bk_no_more_desc\": \"Pokonaj Plonacego Rycerza\",\n\t\"ach_bk:dm_no_more\": \"MM nigdy wiecej\",\n\t\"ach_bk:dm_no_more_desc\": \"Pokonaj Mrocznego Maga\",\n\t\"ach_bk:egor_no_more\": \"Egora nigdy wiecej\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Eh, no to jeszcze raz\",\n\t\"ach_bk:loop_desc\": \"Wejdz do petli\",\n\t\"coins_collected\": \"Zebranych monet\",\n\t\"bk:cup_head\": \"Filizanka\",\n\t\"bk:cup_head_desc\": \"Juz piata!\",\n\t\"bk:mustache_hat\": \"Wasy\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Czapka z Wiatraczkiem\",\n\t\"bk:propeller_hat_desc\": \"Kreci sie!\",\n\t\"bk:sunglasses\": \"Okulary Przeciwsloneczne\",\n\t\"bk:sunglasses_desc\": \"Na swiatlo ksiezycowe tez dzialaja!\",\n\t\"bk:cap\": \"Czapka\",\n\t\"bk:cap_desc\": \"Fajno @-@\",\n\t\"bk:eyes\": \"Oczy\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Oko\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Wlosy\",\n\t\"bk:hair_desc\": \"Tylko dla bogatych\",\n\t\"won\": \"Wygrana\",\n\t\"won_message\": \"Wygrales!\",\n\t\"you_won_demo\": \"To koniec demo :)\",\n\t\"garderobe_sign\": \"Przebieralnia\",\n\t\"darkmarket_tip\": \"~~[cl purple]Klatwa[cl] lub [cl yellow]30 monet[cl]@@\",\n\t\"mike_0\": \"Zaplac mi [cl green]3 szmaragdy\",\n\t\"mike_1\": \"Wypróbuj Wyzwanie Bossów za jedyne [cl green]3 szmaragdy[cl]!\",\n\t\"bk:weird_potion\": \"Dziwna Mikstura\",\n\t\"bk:weird_potion_desc\": \"Dziwne Pociski\",\n\t\"bk:megaphone\": \"Megafon\",\n\t\"bk:megaphone_desc\": \"Rozszerzajace sie pociski\",\n\t\"scourge\": \"Klatwa\",\n\t\"scourge_stats\": \"Klatwa\",\n\t\"run_daily\": \"Dzienny\",\n\t\"full_version\": \"Drzwi beda otwarte w pelnej wersji!\",\n\t\"completed_on\": \"Zaliczony w\",\n\t\"complete\": \"Zaliczony\",\n\t\"wishlist_pls\": \"Podoba ci sie demo, dodaj nas do listy zyczen na Steam! [cl red]burningknight.net\\/steam\",\n\t\"next_daily_in\": \"[cl gray]Nastepny zaczyna sie w[cl]\",\n\t\"hours\": \"godzin\",\n\t\"minutes\": \"minut\",\n\t\"seconds\": \"sekund\",\n\t\"ach_bk:star\": \"Gwiazda Show\",\n\t\"ach_bk:star_desc\": \"Zdobadz 3 orbitale\",\n\t\"ach_bk:family\": \"Szczesliwa Mala Rodzinka\",\n\t\"ach_bk:family_desc\": \"Zdobadz 3 zwierzatka\",\n\t\"ach_bk:return_to_sender\": \"Nje bo ty\",\n\t\"ach_bk:return_to_sender_desc\": \"Zabij przeciwnika jego wlasnym strzalem\",\n\t\"ach_bk:van_no_gogh\": \"Van Nie Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Zniszcz 100 obrazów\",\n\t\"ach_bk:boom\": \"Reakcja Lancuchowa\",\n\t\"ach_bk:boom_desc\": \"Rozsadz Lancuch 3 TNT\",\n\t\"ach_bk:dark_market\": \"Kryjówka Zbrodni\",\n\t\"ach_bk:dark_market_desc\": \"Wejdz do Czarnego Marketu\",\n\t\"ach_bk:spikes\": \"Ostro!\",\n\t\"ach_bk:spikes_desc\": \"Aktywuj 100 kolców podczas jednego podejscia\",\n\t\"ach_bk:white_flag\": \"Nie zawiera glutenu i broni\",\n\t\"ach_bk:white_flag_desc\": \"Pokonaj pokój bez uzywania broni\",\n\t\"quack\": \"[cl yellow]Kwa![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfect\",\n\t\"bk_11\": \"TYM RAZEM CI WYBACZAM... ALE ##NIE## RÓB TEGO WIECEJ!\",\n\t\"leaderboard\": \"Tabela Wyników\",\n\t\"display\": \"Pokaz\",\n\t\"around_you\": \"Wokól Ciebie\",\n\t\"friends\": \"Przyjaciele\",\n\t\"global\": \"Globalnie\",\n\t\"loading\": \"Ladowanie\",\n\t\"generating\": \"Generowanie\",\n\t\"cursor_radius\": \"Odleglosc Kursora\",\n\t\"no_scores_yet\": \"Jeszcze nie ma wyników\",\n\t\"no_score_yet\": \"Jeszcze nie ma wyniku\",\n\t\"run\": \"Podejscie\",\n\t\"top\": \"Top\",\n\t\"quick_restart\": \"Szybki Restart\",\n\t\"painting_dungeon\": \"Loch\",\n\t\"painting_goose\": \"Mala Gaska\",\n\t\"painting_chess\": \"Latajacy Slon\",\n\t\"painting_peach\": \"Drzewo Brzoskwiniowe\",\n\t\"bk:no_lamp\": \"Bez Lampy\",\n\t\"bk:explosive_lamp\": \"Wybuchowa Lampa\",\n\t\"bk:explosive_lamp_desc\": \"Kiedy bum znaczy wiecej\",\n\t\"bk:shielded_lamp\": \"Tarczowa Lampa\",\n\t\"bk:shielded_lamp_desc\": \"Tarcze w góre!\",\n\t\"lamp\": \"Lampa\",\n\t\"bk:brain\": \"Mega Mózg\",\n\t\"bk:brain_desc\": \"Wielkosc Umyslu: Mega\",\n\t\"bk:heart_amulet\": \"Sercowy Amulet\",\n\t\"bk:heart_amulet_desc\": \"+1 do Wielkosci Serc\",\n\t\"bk:star_amulet_desc\": \"Zwiekszenie many\",\n\t\"bk:star_amulet\": \"Gwiezdny Amulet\",\n\t\"bk:coin_amulet\": \"Pieniezny Amulet\",\n\t\"bk:coin_amulet_desc\": \"Monety sa warte wiecej\",\n\t\"bk:key_amulet\": \"Kluczowy Amulet\",\n\t\"bk:key_amulet_desc\": \"Kluczowy przedmiot, klucze warte wiecej\",\n\t\"bk:bomb_amulet\": \"Bombowy Amulet\",\n\t\"bk:bomb_amulet_desc\": \"Bombowa rzecz, bomby warte wiecej\",\n\t\"bk:eye_amulet\": \"Oczny Amulet\",\n\t\"bk:eye_amulet_desc\": \"To boli, gdy nie mozesz trafic\",\n\t\"bk:eye_patch\": \"Opaska na Oko\",\n\t\"bk:eye_patch_desc\": \"Jestescie gotowi?\",\n\t\"bk:toilet_paper\": \"Papier Toaletowy\",\n\t\"bk:toilet_paper_desc\": \"Zawsze sie konczy\",\n\t\"bk:decoy\": \"Wabik\",\n\t\"bk:decoy_desc\": \"Wybucha\",\n\t\"bk:wallet\": \"Portfelowy Kumpel\",\n\t\"bk:wallet_desc\": \"Trzyma twoje Monety\",\n\t\"bk:skele_buddy\": \"Szkiele Kumpel\",\n\t\"bk:skele_buddy_desc\": \"Straszny\",\n\t\"bk:mega_bomb\": \"Mega Bomba\",\n\t\"bk:mega_bomb_desc\": \"Wielkosc Bomby: Mega\",\n\t\"bk:condensed_milk\": \"Skondensowane Mleko\",\n\t\"bk:condensed_milk_desc\": \"Szybkie pixele - Wolni przeciwnicy\",\n\t\"bk:marshmallow\": \"Pianka\",\n\t\"bk:marshmallow_desc\": \"Klei sie\",\n\t\"bk:orbital_multiplier\": \"Podwajacz Orbitali\",\n\t\"bk:orbital_multiplier_desc\": \"Wiecej oritali!\",\n\t\"bk:pet_multiplier\": \"Podwajacz zwierzaków\",\n\t\"bk:pet_multiplier_desc\": \"Wiecej zwierzaków!\",\n\t\"bk:ghost_bullets\": \"Duchowe Pociski\",\n\t\"bk:ghost_bullets_desc\": \"Mur ich nie powstrzyma\",\n\t\"bk:weight\": \"Ciezki Odwaznik\",\n\t\"bk:weight_desc\": \"Grawitacja+\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"Bierz albo zostaw\",\n\t\"bk:ethernal_d6\": \"Wieczne D6\",\n\t\"bk:ethernal_d6_desc\": \"Przerzuca i/lub Niszczy\",\n\t\"bk:billiard\": \"Kula Biliardowa\",\n\t\"bk:billiard_desc\": \"Odbijajace pociski\",\n\t\"bk:enraged_bullets\": \"Zdenerwowane Pociski\",\n\t\"bk:enraged_bullets_desc\": \"Pociski niszcza Pociski\",\n\t\"bk:rewind_button\": \"Przycisk Przewijania\",\n\t\"bk:rewind_button_desc\": \"No chyba nie\",\n\t\"bk:piggy_bank\": \"Swinka Skarbonka\",\n\t\"bk:piggy_bank_desc\": \"Oszczednosci Zyciowe\",\n\t\"coins\": \"Monety\",\n\t\"bk:death_star\": \"Gwiazda Smierci\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Lutowane Zelazo\",\n\t\"bk:soldering_iron_desc\": \"Gorace\",\n\t\"bk:can\": \"Puszka\",\n\t\"bk:can_desc\": \"Podwójne pociski\",\n\t\"bk:swimming_mask\": \"Maska do Plywania\",\n\t\"bk:swimming_mask_desc\": \"To sekretna bron\",\n\t\"bk:bullet_chair\": \"Pociskrzeslo\",\n\t\"bk:bullet_chair_desc\": \"4 nogi 4 giwery\",\n\t\"bk:cell\": \"Komórka\",\n\t\"bk:cell_desc\": \"Pociski sie mnoza\",\n\t\"bk:brick\": \"iBrick\",\n\t\"bk:brick_desc\": \"Wieksze pietra\",\n\t\"bk:ring_of_pain\": \"Pierscien Bólu\",\n\t\"bk:ring_of_pain_desc\": \"Oberwanie bije wszystkich\",\n\t\"bk:schrodingers_cat\": \"Kot Schrödingera\",\n\t\"bk:schrodingers_cat_desc\": \"Byc albo nie byc (50% szans)\",\n\t\"bk:smoke_bomb\": \"Bomba Dymna\",\n\t\"bk:smoke_bomb_desc\": \"Poczuj sie jak Ninja\",\n\t\"bk:chest_ring\": \"Skrzyniowy Pierscien\",\n\t\"bk:chest_ring_desc\": \"Wiecej Skrzyn!\",\n\t\"bk:empty_shell\": \"Pusta Luska\",\n\t\"bk:empty_shell_desc\": \"Szansa na zniszczenie pocisków przeciwników\",\n\t\"bk:parachute\": \"Spadochron\",\n\t\"bk:parachute_desc\": \"Odpornosc na Dziury\",\n\t\"bk:spiked_cookie\": \"Kolczaste Ciasteczko\",\n\t\"bk:spiked_cookie_desc\": \"Kolczasty Slodziak\",\n\t\"bk:shooty\": \"Strzelik\",\n\t\"bk:shooty_desc\": \"On byc strzelac\",\n\t\"bk:rabbit_bullets\": \"Królicze Pociski\",\n\t\"bk:rabbit_bullets_desc\": \"Mnoza sie\",\n\t\"bk:pandoras_box\": \"Puszka Pandory\",\n\t\"bk:pandoras_box_desc\": \"Trzyma zlo\",\n\t\"bk:bubbles\": \"Baniek\",\n\t\"bk:bubbles_desc\": \"Przyjaciel Banka\",\n\t\"bk:match\": \"Zapalki\",\n\t\"bk:match_desc\": \"Ogien dla wszystkich\",\n\t\"bk:hammer\": \"Mlotek\",\n\t\"bk:hammer_desc\": \"Niszczyciel Zbroi\",\n\t\"bk:helmet\": \"Zelazny Helm\",\n\t\"bk:helmet_desc\": \"Szansa na zignorowanie obrazen\",\n\t\"bk:beer\": \"Piwo\",\n\t\"bk:beer_desc\": \"Zwieksza obrazenia po otrzymaniu obrazen\",\n\t\"bk:the_eye\": \"Oko\",\n\t\"bk:the_eye_desc\": \"On byc widziec\",\n\t\"bk:mimics_tooth\": \"Zab Mimika\",\n\t\"bk:mimics_tooth_desc\": \"Przyciaga Mimiki\",\n\t\"ach_bk:mimic\": \"Jump Scare\",\n\t\"ach_bk:mimic_desc\": \"Znajdz Mimika\",\n\t\"bk:paper_airplane\": \"Papierowy Samolocik\",\n\t\"bk:paper_airplane_desc\": \"Samonaprawadzajace pociski\",\n\t\"ach_bk:ice_boss\": \"Mam te Moc\",\n\t\"ach_bk:ice_boss_desc\": \"Zabij Królowa Lodu\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Ahem\",\n\t\"painting_agency\": \"Witamy w  Agencji\",\n\t\"inventory\": \"Ekwipunek\",\n\t\"language\": \"Jezyk\",\n\t\"bk:pouch\": \"Sakiewka\",\n\t\"bk:alien_glasses\": \"Kosmiczne Okulary\",\n\t\"bk:alien_glasses_desc\": \"Widze wiecej\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Celna Lampa\",\n\t\"bk:fragile_lamp\": \"Kruchliwa Lampa\",\n\t\"bk:fragile_lamp_desc\": \"1 hit K.O.\",\n\t\"guitar\": \"Glosniej!\",\n\t\"painting_guitar\": \"Glosniej!\",\n\t\"ach_bk:maanex\": \"Et tu, Brut?\",\n\t\"ach_bk:maanex_desc\": \"Zabij Maanexa noszac jego glowe\",\n\t\"dad_0\": \"Hej synek![dl] Musze odejsc i znalezc [cl red]Lampe[cl]. Zostawiam cie jako wladce.\",\n\t\"dad_1\": \"Jesli nie wroce, nie szukaj mnie. Pa!\",\n\t\"son_0\": \"##NIEEEEEE##\",\n\t\"gobbo_0\": \"Synu, [cl green]moj ojciec[cl] zostawil mnie 20 lat temu. Musze go odnalezc.\",\n\t\"gobbo_1\": \"Zostajesz nowym wladca. Pa!\",\n\t\"dm_5\": \"Nowy i ^^lepszy^^ [cl red]slugus[cl]![dl] ##MUHAHAHA##\",\n\t\"dm_6\": \"Slyszysz mnie, [cl red]Limpor?\",\n\t\"heinur_0\": \"##NIE[dl], NIE ZNOWU!##\",\n\t\"nbk_0\": \"##TAK, MISTRZU##\",\n\t\"bk_12\": \"##JESTEM KROLEM KROLOW, WIEC WALCZ ZE MNA, GLUPCZE!##\",\n\t\"bk:headshot_gun\": \"Wygiety Pistolet\",\n\t\"bk:headshot_gun_desc\": \"Headshot\",\n\t\"bk:laser_cannon\": \"Dzialo Laserowe\",\n\t\"bk:laser_cannon_desc\": \"Haha, laser robi piu piu\",\n\t\"credits\": \"Napisy\",\n\t\"head_0\": \"Glupiec\",\n\t\"tech\": \"Techno\",\n\t\"ach_bk:collector\": \"Kolekcjoner\",\n\t\"ach_bk:collector_desc\": \"Odblokuj wszystkie przedmioty\",\n\t\"bk:treasure_key\": \"Czerwony Klucz\",\n\t\"bk:treasure_key_desc\": \"Otwiera dziury w petli\",\n\t\"bk:pass\": \"Przepustka\",\n\t\"bk:pass_desc\": \"Ciekawe skad on mial twoje ID?\",\n\t\"bk:bucket\": \"Wiadro\",\n\t\"bk:bucket_desc\": \"Bezuzyteczne... bez zawartosci\",\n\t\"bk:water_bucket\": \"Wiadro z Woda\",\n\t\"bk:water_bucket_desc\": \"Uspokaja [cl red]Ogien[cl]\",\n\t\"bk:snow_bucket\": \"Wiadro ze Sniegiem\",\n\t\"bk:snow_bucket_desc\": \"Prawdopodobnie sie rozpusci\",\n\t\"m2_0\": \"Nigdy sie z tego finansowo nie wygrzebie\",\n\t\"m2_1\": \"Dobra robota!\",\n\t\"m2_2\": \"Hej ty, chcialbys ^^wyprobowac^^ twoje %%umiejetnosci%%?\",\n\t\"m2_3\": \"Uzyj ^^%%Komputera%%^^, aby kontrolowac lape!\",\n\t\"maanex2_0_0\": \"Bierz moje pieniadze!\",\n\t\"maanex2_0_1\": \"Nie tym razem, tnx.\",\n\t\"maanex2_0\": \"Okej, daj mi [cl yellow][vr cost] monet[cl] i mozesz wyprobowac lape szczescia!\",\n\t\"dm_7\": \"Zagrajmy w gre\",\n\t\"bkw_0\": \"KOLEJNY [cl red]INTRUZ[cl]!\",\n\t\"bkw_1\": \"##WYNOS SIE STAD##[dl], ALBO UZYJE SILY!\",\n\t\"bkw_2\": \"Szukam [cl green]mojego ojca\",\n\t\"bkw_3\": \"DALEM CI _OSTRZEZENIE_\",\n\t\"spanish_inquisition\": \"[cl red]Hiszpanska Inkwizycja\",\n\t\"lp_0\": \"Dobra robota, [cl purple]Ritta[cl][dl], restartujemy [cl green]symulacje[cl][dl].[dl].[dl].\",\n\t\"bk:broken_bucket\": \"Dziurawe Wiadro\",\n\t\"bk:broken_bucket_desc\": \"Szkoda ze Dziurawe...\",\n\t\"bk:ankh\": \"Ankh\",\n\t\"bk:ankh_desc\": \"Zycie Wieczne\",\n\t\"bk:broken_ankh\": \"Podniszczony Ankh\",\n\t\"bk:broken_ankh_desc\": \"Zycie Wieczne?\",\n\t\"bk:what\": \"co\",\n\t\"bk:what_desc\": \"Serio, CO?\",\n\t\"bk:gold_minigun\": \"Zloty Minigun\",\n\t\"bk:gold_minigun_desc\": \"Powiedz mi, czy slowo budzet naprawde istnieje?\",\n\t\"bk:gold_dagger\": \"Zloty Sztylet\",\n\t\"bk:gold_dagger_desc\": \"Stary ale zloty\",\n\t\"bk:gold_revolver\": \"Zloty Rewolwer\",\n\t\"bk:gold_revolver_desc\": \"Obsyp mnie zlotem\",\n\t\"bk:gold_axe\": \"Zlota Siekiera\",\n\t\"bk:gold_axe_desc\": \"Po prostu siekiera\",\n\t\"painting_code\": \"Kod\",\n\t\"bk:katana\": \"Katana\",\n\t\"bk:katana_desc\": \"Kto tu jest [cl orange]wlascicielem[cl]?\",\n\t\"bk:smart_gun\": \"Inteligenta Bron\",\n\t\"bk:smart_gun_desc\": \"On wie\",\n\t\"bk:pop_gun\": \"Pop Gun\",\n\t\"bk:pop_gun_desc\": \"Zadziwiajaco popularny\",\n\t\"bk:the_button\": \"Przycisk\",\n\t\"bk:the_button_desc\": \"Prosze, nie dotykaj niczego\",\n\t\"bk:gold_sword\": \"Zloty Miecz\",\n\t\"bk:gold_sword_desc\": \"Zloto jest zlote\",\n\t\"bk:donut\": \"Donut\",\n\t\"bk:donut_desc\": \"Nie wachaj sie\",\n\t\"bk:sudoku\": \"Sudoku\",\n\t\"bk:sudoku_desc\": \"Nie ma polowy pokoju, zredukowana do atomow\",\n\t\"bk:gps_ring\": \"Ring GPS\",\n\t\"bk:gps_ring_desc\": \"Szansa na odkrycie mapy\",\n\t\"bk:shield_potion\": \"Mikstura Obrony\",\n\t\"bk:shield_potion_desc\": \"Duzy lyk soku z tarczy\",\n\t\"bk:trash_generator\": \"Generator Smieci\",\n\t\"bk:trash_generator_desc\": \"Tak.\",\n\t\"bk:crabs_claw\": \"Krabie Kleszcze\",\n\t\"bk:crabs_claw_desc\": \"Niszczy kazda zbroje\",\n\t\"eg_3\": \"Dzien dobry, sir\",\n\t\"eg_0_0\": \"Wez ^^[cl lime]szmaragdy[cl]^^\",\n\t\"eg_0_1\": \"Zostaw je\",\n\t\"eg_0\": \"Zabierz [cl lime]moje szmaragdy[cl], blagam!\",\n\t\"eg_1\": \"Spadam z tad\",\n\t\"bk:reverse_card\": \"Karta Odwrotu\",\n\t\"bk:reverse_card_desc\": \"Rolowanie sie przez pociski odbija je\",\n\t\"bk:magnet\": \"Magnes\",\n\t\"bk:magnet_desc\": \"Przyciaganie i Dzialanie\",\n\t\"bk:glowing_mushroom\": \"Swiecacy Grzyb\",\n\t\"bk:glowing_mushroom_desc\": \"On byc wibru wibru\",\n\t\"bk:tinfoil_hat\": \"Czapka Foliowa\",\n\t\"bk:tinfoil_hat_desc\": \"Nareszcie... jestem bezpieczny\",\n\t\"bk:rear_window\": \"Lusterko\",\n\t\"bk:rear_window_desc\": \"Zabezpiecza tyly\",\n\t\"bk:refractor\": \"Refraktor\",\n\t\"bk:refractor_desc\": \"Szansa na atak we wszystkie strony\",\n\t\"bk:fork\": \"Widelec\",\n\t\"bk:fork_desc\": \"To boli\",\n\t\"bk:rock\": \"Kamien\",\n\t\"bk:rock_desc\": \"Obrazenia kazdym kosztem\",\n\t\"bk:coffee_grinder\": \"Maszyna do Kawy\",\n\t\"bk:coffee_grinder_desc\": \"Male i szybkie pociski\",\n\t\"integrations\": \"Integracje\",\n\t\"twitch\": \"Twitch\",\n\t\"streamer_username\": \"Nick Streamera\",\n\t\"bk:shawarma\": \"Shwarma\",\n\t\"bk:shawarma_desc\": \"Czasami pociski sa wieksze\",\n\t\"bk:cats_ear\": \"Ucho Kota\",\n\t\"bk:cats_ear_desc\": \"Slaby unik\",\n\t\"luck\": \"Szczescie\",\n\t\"bk:gamepad\": \"Pad\",\n\t\"bk:gamepad_desc\": \"Stabilne FPS\",\n\t\"bk:hotdog\": \"Hotdog\",\n\t\"bk:bomb_shell\": \"Skorupa Bomby\",\n\t\"bk:bomb_shell_desc\": \"Dziwne Zdrowie\",\n\t\"painting_no_idea\": \"Nie mam pojecia\",\n\t\"painting_tinkerer\": \"Majsterkowicz\",\n\t\"painting_in_loving_memory_of_ali\": \"We wspomnieniu Ali\",\n\t\"painting_happy_accident\": \"Szczesliwy Przypadek\",\n\t\"painting_observing_cheese\": \"Obserwacja Sera\",\n\t\"painting_chicken_enemy_unknown\": \"Kurczak Wrog Nieznany\",\n\t\"painting_know_stuff\": \"Wiem Rzeczy\",\n\t\"painting_whoops\": \"Whoops\",\n\t\"painting_too_lake\": \"Jezioro\",\n\t\"painting_step_through\": \"Prog\",\n\t\"painting_thats_a_moon\": \"To Ksiezyc\",\n\t\"painting_totem\": \"Magiczny Krag\",\n\t\"painting_too_late\": \"Za Pozno\",\n\t\"painting_whipped_cream\": \"Bita Smietana\",\n\t\"painting_beet_boys\": \"Buraki Polaki\",\n\t\"painting_moonshine\": \"Swiatlo\",\n\t\"painting_void\": \"Pustka\",\n\t\"painting_peasants\": \"Plebs\",\n\t\"bk:gold_lamp\": \"Zlota Lampa\",\n\t\"bk:gold_lamp_desc\": \"Kasa kasa kasa\",\n\t\"bk:sharp_lamp\": \"Ostra Lampa\",\n\t\"bk:sharp_lamp_desc\": \"Ostro\",\n\t\"bk:ancient_sword\": \"Antyczny Miecz\",\n\t\"bk:ancient_sword_desc\": \"Bardzo stary patyk\",\n\t\"ach_bk:unstoppable\": \"Niepowstrzymany\",\n\t\"ach_bk:unstoppable_desc\": \"Przejdz gre z dowolna Lampa\",\n\t\"no_emeralds\": \"Brak Szmaragdow\",\n\t\"bk:emerald_gun\": \"Szmaragdowa Giwera\",\n\t\"bk:emerald_gun_desc\": \"Najdrozsza bron na rynku\"\n}\n"
  },
  {
    "path": "BurningKnight/Content/Locales/pt.json",
    "content": "﻿{\n\t\"bk:halo\": \"Auréola\",\n\t\"bk:halo_desc\": \"Aumenta a vida\",\n\t\"bk:revolver\": \"Revólver\",\n\t\"bk:sword\": \"Espada de Madeira\",\n\t\"bk:sword_desc\": \"É mais do que um simples pedaço de pau\",\n\t\"bk:heart\": \"Coração\",\n\t\"resume\": \"Continuar\",\n\t\"settings\": \"Opções\",\n\t\"restart\": \"Reiniciar\",\n\t\"death_message\": \"Você morreu\",\n\t\"descend\": \"Descer\",\n\t\"ascend\": \"Subir\",\n\t\"exit\": \"Sair\",\n\t\"painting_rexcellent\": \"Excelente\",\n\t\"painting_grannylisa\": \"Grannylisa\",\n\t\"painting_maanex\": \"PENSADOR\",\n\t\"painting_bk\": \"Cavaleiro Torrado\",\n\t\"painting_failpositive\": \"Festeiro\",\n\t\"painting_old_man\": \"Cara muito velho\",\n\t\"painting_arthouse\": \"Casa da Arte\",\n\t\"painting_black\": \"Universo\",\n\t\"painting_milt\": \"Garoto na neve\",\n\t\"painting_skyscraper\": \"Arranha-céu solitário\",\n\t\"painting_egor\": \"Burning Rex\",\n\t\"painting_null\": \"NULO\",\n\t\"painting_badosz\": \"Garoto perdido na floresta\",\n\t\"painting_banana\": \"BANANA\",\n\t\"painting_tv\": \"TV nos céus\",\n\t\"painting_company\": \"Bem acompanhado\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Dog du Trasevol\",\n\t\"painting_lamp\": \"Pegue\",\n\t\"painting_scream\": \"Sorvete\",\n\t\"painting_stars\": \"Noite assustadora\",\n\t\"painting_fog\": \"Sete mares\",\n\t\"painting_nufflee\": \"Latido\",\n\t\"by\": \"por\",\n\t\"old_man_0\": \"É perigoso!\",\n\t\"continue_run\": \"Continuar partida\",\n\t\"new_run\": \"Nova partida\",\n\t\"was_unlocked\": \"Foi desbloqueado!\",\n\t\"bk:revolver_desc\": \"Mãos pra cima, @todos!\",\n\t\"bk:shovel\": \"Pá Azul\",\n\t\"bk:shovel_desc\": \"Mas por quê é azul???\",\n\t\"beet_0\": \"Oi!\",\n\t\"beet_2\": \"Me diga o nome!\",\n\t\"npc_hurt_0\": \"Ai.\",\n\t\"npc_hurt_1\": \"Isso dói.\",\n\t\"npc_hurt_2\": \"Ah não.\",\n\t\"beet_3\": \"Valeu <3\",\n\t\"beet_1\": \"Quer plantar uma ^^semente^^?\",\n\t\"beet_1_0\": \"Sim!\",\n\t\"beet_1_1\": \"Nah.\",\n\t\"beet_4\": \"A semente é [vr seed]. Quer mudar?\",\n\t\"beet_4_0\": \"Sim!\",\n\t\"beet_4_1\": \"Nah.\",\n\t\"beet_5\": \"Tanto faz.\",\n\t\"beet_4_2\": \"Quero que seja aleatória!\",\n\t\"beet_6\": \"Ok. A semente agora é [vr seed]!\",\n\t\"bk:idol\": \"Ídolo\",\n\t\"bk:idol_desc\": \"Uma armadilha escondida foi ativada!\",\n\t\"bk:key\": \"Chave Dourada\",\n\t\"bk:infinite_bomb\": \"Bomba Infinita\",\n\t\"bk:infinite_bomb_desc\": \"Bomba reutilizável\",\n\t\"throw_coin\": \"Jogue uma moeda\",\n\t\"bk:potatoo\": \"Batataaa\",\n\t\"bk:potatoo_desc\": \"Divide projéteis\",\n\t\"bk:spectacles\": \"Óculos\",\n\t\"bk:spectacles_desc\": \"Revela segredos\",\n\t\"bk:cross\": \"Cruz\",\n\t\"bk:cross_desc\": \"Aumenta o tempo de invencibilidade\",\n\t\"bk:slime\": \"Meleca\",\n\t\"bk:slime_desc\": \"Tiros ricocheteiam\",\n\t\"bk:missile\": \"Míssil\",\n\t\"bk:missile_desc\": \"Tiros teleguiados\",\n\t\"bk:rod_of_discord\": \"Bastão da Discórdia\",\n\t\"bk:rod_of_discord_desc\": \"Teleporte para @todos\",\n\t\"bk:goo\": \"Goo\",\n\t\"bk:goo_desc\": \"Amigo orbital\",\n\t\"bk:jelly\": \"Geléia!\",\n\t\"bk:jelly_desc\": \"^^Saltitante^^\",\n\t\"bk:broken_stone\": \"Pedra Quebrada\",\n\t\"bk:broken_stone_desc\": \"Orbital bem construído\",\n\t\"bk:nano_orb\": \"Nano Orbe\",\n\t\"bk:nano_orb_desc\": \"Micro-amigo\",\n\t\"bk:saturn\": \"Planeta\",\n\t\"bk:saturn_desc\": \"Mas é claro que ainda ainda o amamos\",\n\t\"bk:soap\": \"Sabonete\",\n\t\"bk:soap_desc\": \"Desacelera seus projéteis\",\n\t\"bk:d6\": \"D6\",\n\t\"bk:d6_desc\": \"^^Rola novamente^^ os itens!\",\n\t\"bk:my_heart\": \"Meu Coração\",\n\t\"bk:my_heart_desc\": \"Aumenta a vida\",\n\t\"bk:broken_heart\": \"Coração Partido\",\n\t\"bk:broken_heart_desc\": \"Aumenta a vida\",\n\t\"bk:parcel\": \"Pacote\",\n\t\"bk:parcel_desc\": \"Cura reutilizável\",\n\t\"bk:glass\": \"Vidro\",\n\t\"bk:glass_desc\": \"Projéteis ##frágeis##\",\n\t\"bk:glass_bullet\": \"Bala de Vidro\",\n\t\"bk:glass_bullet_desc\": \"Atire sobre pedras\",\n\t\"bk:broken_guitar\": \"Guitarra Quebrada\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Metralhadora\",\n\t\"bk:machine_gun_desc\": \"Automática\",\n\t\"bk:grenade_launcher\": \"Lança-granada\",\n\t\"bk:grenade_launcher_desc\": \"Buuumm!\",\n\t\"bk:shotgun\": \"Escopeta\",\n\t\"bk:shotgun_desc\": \"Sal na cara!\",\n\t\"bk:missile_launcher\": \"Lança-mísseis\",\n\t\"bk:missile_launcher_desc\": \"Alvo confirmado!\",\n\t\"bk:burst_gun\": \"Arma de Rajada\",\n\t\"bk:burst_gun_desc\": \"Velocidade da luz\",\n\t\"bk:flak_cannon\": \"Canhão Espalhado\",\n\t\"bk:flak_cannon_desc\": \"É hora da festa!\",\n\t\"bk:disk_gun\": \"Arma de Discos\",\n\t\"bk:disk_gun_desc\": \"Cortante\",\n\t\"bk:duck_gun\": \"Arma Patológica\",\n\t\"bk:duck_gun_desc\": \"Quakers!\",\n\t\"bk:follower\": \"Seguidor\",\n\t\"bk:follower_desc\": \"Siga-me os bons!\",\n\t\"bk:portal_gun\": \"Arma de Portal\",\n\t\"bk:portal_gun_desc\": \"O bolo é mentira\",\n\t\"bk:snowflake\": \"Floco de neve\",\n\t\"bk:snowflake_desc\": \"Congela todo mundo!\",\n\t\"bk:restock\": \"Reabastecer\",\n\t\"bk:restock_desc\": \"Suprimento infinito na loja\",\n\t\"bk:charisma_ring_desc\": \"Promoções Reais\",\n\t\"bk:charisma_ring\": \"Anel do Carisma\",\n\t\"bk:battery\": \"Bateria\",\n\t\"tomb_0\": \"Aqui jaz [cl green]Gobbo[cl] o Grande\",\n\t\"bk:homemade_dice\": \"Dado Improvisado\",\n\t\"bk:homemade_dice_desc\": \"^^Rola novamente^^ os itens! (DIY)\",\n\t\"shopkeeper_0\": \"##EU FALEI PRA NÃO FAZER ISSO!##\",\n\t\"shopkeeper_1\": \"Por favor, pare!\",\n\t\"shopkeeper_2\": \"Não faça isso.\",\n\t\"shopkeeper_3\": \"[cl red]##PREPARE-SE PARA MORRER!##\",\n\t\"shopkeeper_4\": \"[cl red]LADRÃO!\",\n\t\"shopkeeper_5\": \"[cl red]PEGA ELE!\",\n\t\"desert\": \"Palácio do Deserto\",\n\t\"jungle\": \"Floresta Antiga\",\n\t\"ice\": \"Ruínas de Gelo\",\n\t\"bk:iron_boots\": \"Botas de Ferro\",\n\t\"bk:iron_boots_desc\": \"Chega de se machucar nos espinhos\",\n\t\"bk:mimic_totem\": \"Totem de Mímico\",\n\t\"bk:mimic_totem_desc\": \"##CHEGA DE MÍMICOS##\",\n\t\"back_to_town\": \"Voltar para a Cidade\",\n\t\"bk:glass_gun\": \"Arma de Vidro\",\n\t\"bk:glass_gun_desc\": \"##Frágil##\",\n\t\"bk:glass_shard\": \"Pedaço de Vidro\",\n\t\"bk:glass_shard_desc\": \"Só uma parte de um todo\",\n\t\"bk:dagger\": \"Adaga\",\n\t\"bk:dagger_desc\": \"Nostalgia...\",\n\t\"bk:spear\": \"Lança\",\n\t\"bk:spear_desc\": \"Braços mais compridos?\",\n\t\"shopkeeper_6\": \"Boas-vindas :)\",\n\t\"shopkeeper_7\": \"E aí, tá afim de um pouco de [cl yellow]chá[cl]?\",\n\t\"shopkeeper_8\": \"Como vai?\",\n\t\"back\": \"Voltar\",\n\t\"master_volume\": \"Volume Geral\",\n\t\"music\": \"Música\",\n\t\"sfx\": \"Efeitos Sonoros\",\n\t\"graphics\": \"Gráficos\",\n\t\"audio\": \"Áudio\",\n\t\"ui_sfx\": \"Efeitos Sonoros de Interface\",\n\t\"on\": \"Ligado\",\n\t\"off\": \"Desligado\",\n\t\"fullscreen\": \"Tela Cheia\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Contador de FPS\",\n\t\"speedrun_timer\": \"Temporizador de Speedrun\",\n\t\"screenshake\": \"Tremor da Tela\",\n\t\"reset_progress\": \"Zerar Progresso\",\n\t\"blood_n_gore\": \"Sangue e Violência\",\n\t\"vegan_mode\": \"Modo Vegano\",\n\t\"reset_settings\": \"Zerar Configurações\",\n\t\"are_you_sure\": \"Tem certeza?\",\n\t\"yes\": \"Sim\",\n\t\"reset_progress_dis\": \"Isso apagará TODO o seu progresso!\",\n\t\"reset_settings_dis\": \"Isso vai voltar TODAS as configurações aos valores padrões!\",\n\t\"autosave\": \"Save Automático\",\n\t\"autopause\": \"Pause Automático\",\n\t\"input\": \"Comandos\",\n\t\"use\": \"Usar\",\n\t\"active\": \"Ativar\",\n\t\"bomb\": \"Bomba\",\n\t\"interact\": \"Interagir\",\n\t\"swap\": \"Trocar armas\",\n\t\"roll\": \"Rolar\",\n\t\"duck\": \"Pato\",\n\t\"pause\": \"Pausar\",\n\t\"none\": \"Nada\",\n\t\"keyboard_controls\": \"Comandos do Teclado\",\n\t\"gamepad_controls\": \"Comandos do Controle\",\n\t\"keyboard\": \"Teclado\",\n\t\"gamepad\": \"Controle\",\n\t\"game\": \"Jogo\",\n\t\"select\": \"Selecionar\",\n\t\"cursor\": \"Cursor\",\n\t\"bk:rip\": \"RIP\",\n\t\"ach_bk:rip_desc\": \"Morra\",\n\t\"ach_bk:overshake\": \"Tremor Exagerado\",\n\t\"ach_bk:overshake_desc\": \"1000% tremor de tela\",\n\t\"ach_bk:rip\": \"Conquista mais popular\",\n\t\"bk:emerald\": \"Esmeralda\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%%\",\n\t\"shopkeeper_10\": \"^^Obrigado!^^\",\n\t\"shopkeeper_11\": \"Mas que %%pechincha%%!\",\n\t\"shopkeeper_12\": \"Quer [cl red]comprar[cl] ^^alguma coisa^^?\",\n\t\"shopkeeper_13\": \"Só pra [cl green]você[cl], só hoje!\",\n\t\"shopkeeper_14\": \"Que bela [cl yellow]oferta[cl]!\",\n\t\"bk:magnifier\": \"Lupa\",\n\t\"bk:magnifier_desc\": \"Projéteis maiores\",\n\t\"bk:mushroom_hat\": \"Chapéu de Cogumelo\",\n\t\"bk:mushroom_hat_desc\": \"Gostoso?\",\n\t\"bk:stone_hat\": \"Chapéu de Pedra\",\n\t\"bk:stone_hat_desc\": \"Pesado\",\n\t\"bk:knight_hat\": \"Chapéu de Cavaleiro\",\n\t\"bk:knight_hat_desc\": \"Bons e velhos inimigos...\",\n\t\"bk:cowboy_hat\": \"Chapéu de Caubói\",\n\t\"bk:cowboy_hat_desc\": \"Velho oeste!\",\n\t\"bk:soup_hat\": \"Chapéu de Sopa\",\n\t\"bk:soup_hat_desc\": \"^^Nham-nham^^\",\n\t\"bk:gold_hat\": \"Chapéu Dourado\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Riqueza!\",\n\t\"bk:viking_hat\": \"Chapéu de Viking\",\n\t\"bk:viking_hat_desc\": \"América\",\n\t\"bk:dunce_hat\": \"Chapéu de Pedra\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Cartola\",\n\t\"bk:top_hat_desc\": \"Elegância!\",\n\t\"bk:ushanka\": \"Ushanka\",\n\t\"bk:ushanka_desc\": \"Cadê minha ##balalaika?##\",\n\t\"bk:valkyrie_hat\": \"Chapéu de Valkíria\",\n\t\"bk:valkyrie_hat_desc\": \"I believe ^^I can fly!^^\",\n\t\"bk:skull_hat\": \"Chapéu de Crânio\",\n\t\"bk:skull_hat_desc\": \"Dinheiro ou vida!\",\n\t\"bk:grandma_head\": \"Cabeça da Vovó\",\n\t\"bk:grandma_head_desc\": \"Chá?\",\n\t\"bk:diamond_helmet\": \"Elmo de Diamante\",\n\t\"bk:diamond_helmet_desc\": \"Cale a boca e cave!\",\n\t\"bk:villager_head\": \"Chapéu de Aldeão\",\n\t\"bk:villager_head_desc\": \"Hmm?\",\n\t\"bk:fez\": \"Fez\",\n\t\"bk:fez_desc\": \"Cúbito\",\n\t\"bk:no_hat\": \"Remover Chapéu\",\n\t\"bk:no_hat_desc\": \"Sem chapéu - sem problema!\",\n\t\"bk:null_hat\": \"NULO\",\n\t\"bk:null_hat_desc\": \"Tenta chamar um valor nulo\",\n\t\"accessorytrader_0\": \"##SAIA DAQUI!## [dl]Ou compre estes ^^deliciosos^^ itens por apenas ^^%%99 diamantes cada%%^^!\",\n\t\"accessorytrader_1\": \"Olá\",\n\t\"accessorytrader_2\": \"E aí?\",\n\t\"weapontrader_0\": \"Entre!\",\n\t\"weapontrader_1\": \"Bom dia, senhor!\",\n\t\"weapontrader_2\": \"Compre algo, sim?\",\n\t\"activetrader_0\": \"As melhores ofertas do mercado!\",\n\t\"activetrader_1\": \"Pague dois e leve dois!\",\n\t\"activetrader_2\": \"Me dê rosquinhas, [dl]por favor!!\",\n\t\"hattrader_0\": \"Quer ser descolado como eu? [dl]Compre uns chapéus!\",\n\t\"hattrader_1\": \"Quer ser descolado como eu? [dl]Eu também, garoto!\",\n\t\"hattrader_2\": \"^^Cha cha chapéus!^^\",\n\t\"granny_0\": \"Quer um pouco de chá?\",\n\t\"granny_1\": \"Faça uma pausa para o chá!\",\n\t\"granny_2\": \"Chá?\",\n\t\"bk:xmas_hat\": \"Gorro de Natal\",\n\t\"bk:xmas_hat_desc\": \"Feliz Natal!\",\n\t\"bk:pumpkin_hat\": \"Abóbora Esculpida\",\n\t\"bk:pumpkin_hat_desc\": \"^^Esqueleto muito muito assustador^^\",\n\t\"bk:cage_key\": \"Chave da Cela\",\n\t\"bk:cage_key_desc\": \"Salve ^^o cara^^!\",\n\t\"npc_0\": \"Me ajude! Ache a chave!\",\n\t\"npc_1\": \"Valeu por me salvar!\",\n\t\"npc_2\": \"Mais rápido! Destranque a porta!\",\n\t\"npc_3\": \"Por favor! Me ajude!\",\n\t\"control_0\": \"Pressione [ic 0][ic 1] para colocar uma bomba\",\n\t\"control_1\": \"Rolar você pode! Pressione [ic 0][ic 1] para adquirir o poder!\",\n\t\"control_2\": \"Pressione [ic 0][ic 1] para atacar\",\n\t\"control_3\": \"Pressione [ic 0][ic 1] para interagir\",\n\t\"control_4\": \"Quack? [ic 0][ic 1]!\",\n\t\"control_5\": \"Pressione [ic 0][ic 1] para mudar de arma\",\n\t\"shopkeeper_15\": \"Sem desconto pra você!\",\n\t\"shopkeeper_16\": \"Consiga mais dinheiro e volte!\",\n\t\"shopkeeper_17\": \"Primeiro o pagamento!\",\n\t\"bk:frog\": \"Tele Sapo\",\n\t\"bk:frog_desc\": \"Viagem rápida?\",\n\t\"bk:sword_orbital\": \"Espada Orbital\",\n\t\"bk:sword_orbital_desc\": \"Justiça\",\n\t\"robbed\": \"Roubado\",\n\t\"bk:gift_desc\": \"O que tem dentro?\",\n\t\"bk:spike_ring\": \"Anel de Espinho\",\n\t\"bk:spike_ring_desc\": \"Seus inimigos devem ser ##punidos##!\",\n\t\"bk:fire_ring\": \"Anel de Fogo\",\n\t\"bk:fire_ring_desc\": \"Deixe que seus inimigos queimem\",\n\t\"bk:ice_ring\": \"Anel de Gelo\",\n\t\"bk:ice_ring_desc\": \"Pare seus inimigos\",\n\t\"bk:duck_ring\": \"Anel do Pato\",\n\t\"bk:duck_ring_desc\": \"Teleporta após ser atingido\",\n\t\"bk:dull_blade\": \"Lâmina Cega\",\n\t\"bk:dull_blade_desc\": \"Aciona efeito de ferimento\",\n\t\"bk:sharp_blade\": \"Lâmina Afiada\",\n\t\"bk:sharp_blade_desc\": \"Dano a si próprio\",\n\t\"bk:obsidian_shield\": \"Escudo Obsidiano\",\n\t\"bk:obsidian_shield_desc\": \"Repulsão = 0\",\n\t\"bk:bill\": \"Conta\",\n\t\"bk:bill_desc\": \"99 dinheiros\",\n\t\"control_6\": \"Use o item ativo com [ic 0][ic 1]\",\n\t\"bk:clover\": \"Trevo de 4 Folhas\",\n\t\"bk:clover_desc\": \"Sorte!\",\n\t\"bk:d4\": \"D4\",\n\t\"bk:d4_desc\": \"^^Rola novamente %%seus artefatos%%!^^\",\n\t\"brastin_0\": \"Encontre a pintura do [cl purple]gato[cl]!\",\n\t\"elon_1\": \"Aqui está, divirta-se\",\n\t\"bk:maanex_head\": \"Cabeça do Maanex\",\n\t\"bk:maanex_head_desc\": \"Hmmmmm\",\n\t\"bk:maanex\": \"Maanex\",\n\t\"bk:maanex_desc\": \"Faz os inimigos pensarem um pouco\",\n\t\"mob_0\": \"Hmmmm\",\n\t\"bk:map_greenprints\": \"Esboços de Mapa\",\n\t\"bk:map_greenprints_desc\": \"Revela o mapa\",\n\t\"bk:map\": \"Mapa\",\n\t\"bk:map_desc\": \"Revela o mapa permanentemente\",\n\t\"milt_1\": \"Eu quero presente\",\n\t\"mapuzzle_0\": \"Gravidade.\",\n\t\"nullptr_0\": \"SEGFAULT.\",\n\t\"copied_to_clipboard\": \"Copiado!\",\n\t\"isaac_0\": \"A vida não faz sentido...\",\n\t\"isaac_1\": \"Por quêêêê\",\n\t\"isaac_2\": \":snif:\",\n\t\"discord_0\": \"Diga oi! discord.gg/rexcellent\",\n\t\"old_man_5\": \"Role, tolo!\",\n\t\"tutorial\": \"Tutorial\",\n\t\"bk:crying_bomb\": \"Bomba Chorona\",\n\t\"bk:crying_bomb_desc\": \"As bombas agora choram!\",\n\t\"bk:matches\": \"Fósforos\",\n\t\"bk:matches_desc\": \"Tempo de explosão mais curto\",\n\t\"bk:bomb_pack\": \"Bomba Empacotada\",\n\t\"bk:bomb_pack_desc\": \"Colocamos bombas nas suas bombas!\",\n\t\"bk:tnt\": \"TNT\",\n\t\"bk:tnt_desc\": \"99 bombas\",\n\t\"bk:weird_mushroom_desc\": \"Tudo em dobro\",\n\t\"bk:weird_mushroom\": \"Cogumelo Esquisito\",\n\t\"bk:bomb_shower\": \"Chuva de Bombas\",\n\t\"bk:bomb_shower_desc\": \"Nublado com chance de bombas\",\n\t\"bk:black_belt\": \"Faixa Preta\",\n\t\"bk:black_belt_desc\": \"Explodir não mais\",\n\t\"bk:ninjia_bomb\": \"Bomba Ninja\",\n\t\"bk:ninjia_bomb_desc\": \"Coloca bombas quando atingido\",\n\t\"start_new_run\": \"Sua partida atual será perdida!\",\n\t\"bk:laser_pointer\": \"Apontador Laser\",\n\t\"bk:laser_pointer_desc\": \"Mira limpa!\",\n\t\"ach_bk:marauder\": \"Saqueador\",\n\t\"ach_bk:marauder_desc\": \"Mate o vendedor\",\n\t\"ach_bk:treasure_hunter\": \"Caçador de Tesouro\",\n\t\"ach_bk:treasure_hunter_desc\": \"Encontre uma sala secreta\",\n\t\"ach_bk:dodge_master\": \"Mestre da Esquiva\",\n\t\"ach_bk:dodge_master_desc\": \"Mate um chefe sem ser atingido\",\n\t\"ach_bk:dodge_overlord\": \"Deus da Esquiva\",\n\t\"ach_bk:dodge_overlord_desc\": \"Complete um andar sem ser atingido uma única vez\",\n\t\"ach_bk:quackers\": \"Quackers\",\n\t\"ach_bk:quackers_desc\": \"Overquack\",\n\t\"ach_bk:tea_party\": \"Festa do Chá\",\n\t\"ach_bk:tea_party_desc\": \"Junte-se à Vovó na sua festa do chá\",\n\t\"ach_bk:not_a_thief\": \"Não sou um ladrão\",\n\t\"ach_bk:not_a_thief_desc\": \"Complete uma partida sem pegar nenhum item\",\n\t\"ach_bk:npc_party2\": \"Festa dos NPCs\",\n\t\"ach_bk:npc_party2_desc\": \"Salve todos os NPCs\",\n\t\"bk:gold_coin\": \"Moeda de Ouro\",\n\t\"bk:iron_coin\": \"Moeda de Ferro\",\n\t\"bk:copper_coin\": \"Moeda de Cobre\",\n\t\"bk:platinum_coin\": \"Moeda de Platina\",\n\t\"bk:voodoo_doll\": \"Boneca Vodu\",\n\t\"bk:voodoo_doll_desc\": \"Mata todos os inimigos da sala\",\n\t\"hub\": \"Cidade Dodge\",\n\t\"castle\": \"Ruínas do Castelo\",\n\t\"charger_0\": \"NENHUM ITEM ATIVO DETECTADO\",\n\t\"charger_1\": \"ITEM ATIVO JÁ ESTÁ CARREGADO\",\n\t\"charger_2\": \"CADÊ MEU DINHEIRO, SEU SACO DE CARNE!\",\n\t\"charger_3\": \"##EU DISSE PARA ME DAR MEU DINHEIRO!##\",\n\t\"charger_4\": \"##EU VOU DOMINAR O MUNDO!##\",\n\t\"charger_5\": \"##MUHAHAHAHA##\",\n\t\"maanex_6_0\": \"Claro, vamos nessa!\",\n\t\"maanex_6_1\": \"Nah.\",\n\t\"maanex_6\": \"Ok, me dê [cl yellow][vr cost] moedas[cl] e eu deixo você abrir um desses baús. Ok?\",\n\t\"maanex_5\": \"Ei cara, quer ^^tentar a sorte^^?\",\n\t\"maanex_7\": \"Isso foi divertido!\",\n\t\"maanex_8\": \"Boa sorte!\",\n\t\"maanex_9\": \"Bom, não desta vez :(\",\n\t\"maanex_10\": \"%%^^UAU^^%%\",\n\t\"maanex_11\": \"Mas você não tem dinheiro suficiente!\",\n\t\"maanex_12\": \"##FILHO?!##\",\n\t\"bk:amurs_arrow\": \"Flecha de Amur\",\n\t\"bk:amurs_arrow_desc\": \"Projéteis encantadores\",\n\t\"bk:amurs_bow\": \"Arco de Amur\",\n\t\"bk:amurs_bow_desc\": \"Eu vejo o amor\",\n\t\"bk:poison_flask\": \"Frasco de Veneno\",\n\t\"bk:poison_flask_desc\": \"Projéteis envenenados\",\n\t\"bk:snowball\": \"Bola de Neve\",\n\t\"bk:snowball_desc\": \"Projéteis congelados\",\n\t\"bk:peper_desc\": \"Projéteis picantes\",\n\t\"bk:peper\": \"Pimenta Malagueta\",\n\t\"bk:sale_coupon\": \"Cupom de Desconto\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Mascote na Caixa\",\n\t\"bk:pet_box_desc\": \"Quem está aí dentro?\",\n\t\"bk:crate\": \"Caixa Orbital\",\n\t\"bk:crate_desc\": \"Quem está aí dentro?\",\n\t\"bk:strawberry\": \"Morango\",\n\t\"bk:strawberry_desc\": \"Doces lembranças\",\n\t\"bk:wings\": \"Asas\",\n\t\"bk:wings_desc\": \"I belive I can fly\",\n\t\"bk:coin_pouch\": \"Bolsa de Moedas\",\n\t\"bk:coin_pouch_desc\": \"Fornece moedas\",\n\t\"bk:key_pouch\": \"Bolsa de Chaves\",\n\t\"bk:key_pouch_desc\": \"Fornece chaves\",\n\t\"bk:bomb_pouch\": \"Bolsa de Bombas\",\n\t\"bk:bomb_pouch_desc\": \"Fornece bombas\",\n\t\"bk:pouch_pouch\": \"Bolsa de Bolsa\",\n\t\"bk:pouch_pouch_desc\": \"Fornece bolsas\",\n\t\"bk:lightsaber\": \"Svetsabre\",\n\t\"bk:lightsaber_desc\": \"Você foi o escolhido!\",\n\t\"bk:snail\": \"Lesma\",\n\t\"bk:snail_desc\": \"Lentidão total\",\n\t\"bk:spike\": \"Espinho\",\n\t\"bk:spike_desc\": \"Dano aumentado\",\n\t\"bk:mushroom\": \"Cogumelo\",\n\t\"bk:mushroom_desc\": \"Velocidade aumentada\",\n\t\"bk:candy\": \"Guloseima\",\n\t\"bk:candy_desc\": \"^^Êxtase do açucar^^, cadência de disparo aumentada\",\n\t\"bk:glasses\": \"Óculos\",\n\t\"bk:glasses_desc\": \"Mais precisão\",\n\t\"bk:ruler\": \"Régua\",\n\t\"bk:ruler_desc\": \"Mais alcance\",\n\t\"bk:stopwatch\": \"Cronômetro\",\n\t\"bk:stopwatch_desc\": \"Ser ferido controla o tempo\",\n\t\"bk_0\": \"##NÃO OUSE TOCAR NISSO!##\",\n\t\"bk_1\": \"##EU DISSE PARA NÃO TOCAR NISSO!##\",\n\t\"bk_2\": \"##VOCÊ NÃO PODE DERROTAR [cl red]O CAVALEIRO ARDENTE[cl], SEU TOLO!##\",\n\t\"bk_3\": \"##PREPARE-SE PARA MORRER!##\",\n\t\"bk_4\": \"^^QUE PIADA^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Promoção especial![cl]\",\n\t\"dm_0\": \"@@Boas-vindas@@\",\n\t\"ach_bk:deal\": \"Movimento Excepcional\",\n\t\"ach_bk:deal_desc\": \"Faça negócio com o Mago Negro\",\n\t\"ach_bk:grannys_gift\": \"Presente da Vovó\",\n\t\"ach_bk:grannys_gift_desc\": \"Receba um presente da Vovó\",\n\t\"ach_bk:shopper\": \"Compre até Cair\",\n\t\"ach_bk:shopper_desc\": \"Compre um item em qualquer loja\",\n\t\"bk_5\": \"EU NEM PERDERIA TEMPO FALANDO COM ELE\",\n\t\"bk_6\": \"##MATE ELE, [cl lime]EDWARD[cl]!##\",\n\t\"bk_7\": \"[cl lime]EDWARD[cl], ##NÃÃÃOOO!!!!##\",\n\t\"bk_8\": \"AH QUALÉ, PARE DE EXPLODIR MEU CASTELO!\",\n\t\"bk_9\": \"[cl pink]VOVÓ[cl],[dl] TEM COMO VOCÊ MORRER, POR FAVOR##?!?##\",\n\t\"bk_10\": \"MEU MESTRE,[dl] EU TROUXE O [cl green]GOBLIN[cl]\",\n\t\"dm_1\": \"Muito bem[dl], obrigado[dl], [cl red]Limpor[cl]\",\n\t\"dm_2\": \"##Sim, sim, preciso de mais [cl orange]poder[cl]!##\",\n\t\"dm_3\": \"##MAIS [cl orange]PODER[cl]!\",\n\t\"dm_4\": \"Posso sentir [cl orange]o poder[cl] pulsando dentro de mim!\",\n\t\"granny_3\": \"Você será o primeiro, [cl red]Limpor[cl]!\",\n\t\"granny_4\": \"Bem-vindo, [cl green]Gobbo[cl]!\",\n\t\"granny_5\": \"Boa sorte na sua triste missão!\",\n\t\"bk:meat_guy\": \"Cara de Carne\",\n\t\"bk:meat_guy_desc\": \"Loucura!\",\n\t\"bk:bullet_stone\": \"Bala de Pedra\",\n\t\"bk:bullet_stone_desc\": \"Ele atac, ele proteg, mas o principal, ele é fofo pra caramb\",\n\t\"bk:batman\": \"Batman\",\n\t\"bk:batman_desc\": \"Não ajuda em nada, mas fornece baterias\",\n\t\"vibration\": \"Vibração\",\n\t\"bk:sharp_arrow\": \"Flecha Afiada\",\n\t\"bk:sharp_arrow_desc\": \"Projéteis penetrantes\",\n\t\"machine_0\": \"Insira uma [cl yellow]moeda\",\n\t\"player_0\": \"Papai?? ##O que eles fizeram com você?!?##\",\n\t\"bk:boomerang\": \"Bumerangue\",\n\t\"bk:boomerang_desc\": \"Projéteis bumerangue\",\n\t\"bk:backpack\": \"Mochila\",\n\t\"bk:backpack_desc\": \"Meu amigo urso\",\n\t\"place_an_item\": \"Coloque um item\",\n\t\"bk:crystal\": \"Cristal\",\n\t\"bk:crystal_desc\": \"O poder do arco-íris\",\n\t\"bk:prism\": \"Prisma\",\n\t\"bk:prism_desc\": \"Projéteis -> Arco-íris\",\n\t\"scourged\": \"Flagelado\",\n\t\"bk:bomb\": \"Bomba\",\n\t\"bk:scourge_of_egg\": \"Flagelo do Ovo\",\n\t\"bk:scourge_of_egg_desc\": \"Nomes dos itens embaralhados\",\n\t\"bk:scourge_of_unknown\": \"Flagelo do Desconhecido\",\n\t\"bk:scourge_of_unknown_desc\": \"Itens ocultos\",\n\t\"bk:scourge_of_blood\": \"Flagelo do Sangue\",\n\t\"bk:scourge_of_blood_desc\": \"Duplos problemas (e inimigos)\",\n\t\"bk:scourge_of_risk\": \"Flagelo do Risco\",\n\t\"bk:scourge_of_risk_desc\": \"Vida oculta\",\n\t\"bk:scourge_of_keys\": \"Flagelo das Chaves\",\n\t\"bk:scourge_of_keys_desc\": \"Consumíveis ocultos\",\n\t\"bk:scourge_of_lost\": \"Flagelo do Perdido\",\n\t\"bk:scourge_of_lost_desc\": \"Amnésia\",\n\t\"bk:scourge_of_scourged\": \"Flagelo do Flagelado\",\n\t\"bk:scourge_of_scourged_desc\": \"Flagelo por todo lado\",\n\t\"bk:scourge_of_illness\": \"Flagelo da Doença\",\n\t\"bk:scourge_of_illness_desc\": \"Vida nerfada\",\n\t\"bk:scourge_of_death\": \"Flagelo da Morte\",\n\t\"bk:scourge_of_death_desc\": \"Modo difícil\",\n\t\"bk:ancient_revolver\": \"Revólver Antigo\",\n\t\"bk:ancient_revolver_desc\": \"Parece bem legal\",\n\t\"bk:assault_rifle\": \"Rifle de Assalto\",\n\t\"bk:assault_rifle_desc\": \"Rajadas\",\n\t\"fountain_0\": \"Traga 5 moedas e terá uma benção\",\n\t\"fountain_1\": \"Recebeu purificação parcial\",\n\t\"fountain_2\": \"Recebeu purificação total\",\n\t\"fountain_3\": \"Você já está purificado\",\n\t\"buffed\": \"Bufado\",\n\t\"nerfed\": \"Nerfado\",\n\t\"restored\": \"Restaurado\",\n\t\"damaged\": \"Danificado\",\n\t\"cleansed\": \"Purificado\",\n\t\"gifted\": \"Presenteado\",\n\t\"lucky\": \"Sortudo\",\n\t\"unlucky\": \"Azarado\",\n\t\"max_hp\": \"Vida Máx.\",\n\t\"touch\": \"Toque\",\n\t\"break\": \"Quebre\",\n\t\"no_coins\": \"Sem moedas\",\n\t\"old_man_6\": \"É perigoso ir sozinho, leve isto!\",\n\t\"roger_0\": \"Buuumm!\",\n\t\"roger_1\": \"##*BUUM*##\",\n\t\"roger_2\": \"Boom boom shakataka!\",\n\t\"bk:shield\": \"Escudo\",\n\t\"bk:gift\": \"Presente\",\n\t\"bk:shield_pouch\": \"Bolsa de Escudos\",\n\t\"bk:shield_pouch_desc\": \"Fornece escudos\",\n\t\"bk:shield_buddy\": \"Amigo Escudo\",\n\t\"bk:shield_buddy_desc\": \"Ele proteg\",\n\t\"bk:skeleton_key\": \"Chave mestra\",\n\t\"bk:skeleton_key_desc\": \"99 chaves\",\n\t\"bk:jar\": \"Jarra de Vida\",\n\t\"bk:jar_desc\": \"Jar Jar Clinks\",\n\t\"bk:star\": \"Estrela\",\n\t\"bk:star_desc\": \"Ela proteg\",\n\t\"bk:car_bomb\": \"Carro Bomba\",\n\t\"bk:car_bomb_desc\": \"Serviço de entrega de bombas\",\n\t\"bk:grenade\": \"Granada\",\n\t\"bk:grenade_desc\": \"Detona ao contato\",\n\t\"trash_goblin_0\": \"Liberte-me do meu [cl purple]flagelo[cl]! Por favor!\",\n\t\"trash_goblin_1\": \"Estou livre![dl] Muito obrigado!\",\n\t\"boxy_0\": \"Chavexcelente!\",\n\t\"boxy_1\": \"Que caixa maneira!\",\n\t\"boxy_2\": \"Você precisa de papel para embrulho?\",\n\t\"trash_goblin_2\": \"^^Smoke on the water [ic 0] [ic 1]^^\",\n\t\"bk:vampire_bat\": \"Morcego Vampiro\",\n\t\"bk:vampire_bat_desc\": \"Regeneração\",\n\t\"shields\": \"Escudos\",\n\t\"bk:mustache\": \"Bigode\",\n\t\"bk:mustache_desc\": \"VIP\",\n\t\"bk:bloody_chest\": \"Baú Sangrento\",\n\t\"bk:bloody_chest_desc\": \"Baús curam\",\n\t\"bk:bloody_shield\": \"Escudo Sangrento\",\n\t\"bk:bloody_shield_desc\": \"Escudos eternos\",\n\t\"bk:cutsaw\": \"Serrote\",\n\t\"bk:cutsaw_desc\": \"Os inimigos vão pagar\",\n\t\"vampire_0\": \"Nham!\",\n\t\"vampire_1\": \"Incrível pra caramba!\",\n\t\"vampire_2\": \"Tão doce!\",\n\t\"vampire_3\": \"Nós conhecemos as regras, [cl red]^^certo[cl]?\",\n\t\"vampire_4\": \"^^Mmmmmmm^^\",\n\t\"vampire_5\": \"Qual seu tipo sanguíneo?\",\n\t\"vampire_6\": \"Tão gostoso\",\n\t\"duck_2\": \"Se importa em participar de uma pesquisa?\",\n\t\"duck_7_0\": \"Sim\",\n\t\"duck_7_1\": \"Não\",\n\t\"duck_7\": \"Você vai pegar este baú?\",\n\t\"duck_4\": \"Bom trabalho, fique com este baú!\",\n\t\"duck_5\": \"Não posso concordar com você...\",\n\t\"duck_6_0\": \"O universo\",\n\t\"duck_6_1\": \"^^Quarks^^\",\n\t\"duck_6\": \"No que estou pensando?\",\n\t\"duck_8_0\": \"[cl red]Vermelho[cl]\",\n\t\"duck_8_1\": \"[cl blue]Azul[cl]\",\n\t\"duck_8\": \"Qual é a minha ^^%%cor%%^^ favorita?\",\n\t\"duck_9_0\": \"Um gato\",\n\t\"duck_9_1\": \"Você acabou de dizer isso\",\n\t\"duck_9\": \"Quem disse miau?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"O que é melhor?\",\n\t\"duck_11_0\": \"O que, seu ovo?\",\n\t\"duck_11_1\": \"\\\\[_Ele o esfaqueou._]\",\n\t\"duck_11\": \"Você é um garoto atrevido\",\n\t\"duck_12_0\": \"Galinha\",\n\t\"duck_12_1\": \"Ovo\",\n\t\"duck_12\": \"Quem veio primeiro?\",\n\t\"duck_13_0\": \"Nada.\",\n\t\"duck_13_1\": \"Um lanchinho.\",\n\t\"duck_13_2\": \"Um ovo.\",\n\t\"duck_13_3\": \"Frango frito.\",\n\t\"duck_13\": \"O que você comeu hoje?\",\n\t\"duck_14\": \"Ai.\",\n\t\"duck_17_0\": \"Claro rapaz\",\n\t\"duck_17_1\": \"##NAAAAAH##\",\n\t\"duck_17\": \"Você gosta de abacaxi na sua pizza?\",\n\t\"duck_18_0\": \"Branco!\",\n\t\"duck_18_1\": \"[cl yellow]Amarelo[cl]!\",\n\t\"duck_18\": \"Qual é a cor do queijo?\",\n\t\"nurse_0\": \"Você está com uma ótima aparência, querido!\",\n\t\"nurse_1\": \"Eu poderia curá-lo um pouco, mas preciso de [cl yellow][vr price] moedas[cl]\",\n\t\"nurse_2\": \"Espero que não tenha machucado\",\n\t\"elon_4\": \"Aqui está, divirta-se\",\n\t\"elon_2_0\": \"Vambora\",\n\t\"elon_2_1\": \"Espere\",\n\t\"elon_2\": \"Quer experimentar minha mágica?\",\n\t\"elon_3\": \"Eu posso transformar sua arma em outra.\",\n\t\"elon_5\": \"Tanto faz.\",\n\t\"elon_7\": \"Mano, cadê sua arma???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*corando*\",\n\t\"gobetta_4\": \"É... você?\",\n\t\"gobetta_5\": \"Já faz tanto tempo...\",\n\t\"ach_bk:desert\": \"Quente e Seco\",\n\t\"ach_bk:desert_desc\": \"Chegue no Palácio do Deserto\",\n\t\"ach_bk:jungle\": \"Abelhas Barulhentas\",\n\t\"ach_bk:jungle_desc\": \"Chegue na Floresta Antiga\",\n\t\"rooms_explored\": \"Salas exploradas\",\n\t\"bk:shadow_cloak_desc\": \"Não, você\",\n\t\"bk:shadow_cloak\": \"Capa das Sombras\",\n\t\"bk:dynamite_stick\": \"Banana de Dinamite\",\n\t\"bk:dynamite_stick_desc\": \"Você quer explodir?\",\n\t\"bk:chalice_of_blood\": \"Cálice de Sangue\",\n\t\"bk:chalice_of_blood_desc\": \"A dor traz a fúria, a fúria traz mais dano\",\n\t\"bk:detonator\": \"Detonador\",\n\t\"bk:detonator_desc\": \"Detona explosivos\",\n\t\"invincibility_time\": \"Tempo de invencibilidade\",\n\t\"accuracy\": \"Precisão\",\n\t\"range\": \"Alcance\",\n\t\"fire_rate\": \"Cadência de Disparo\",\n\t\"speed\": \"Velocidade\",\n\t\"bk:talisman_of_foresight\": \"Talismã de Clarividência\",\n\t\"bk:talisman_of_foresight_desc\": \"Abra seus olhos e veja as salas ao redor!\",\n\t\"bk:scourge_ring\": \"Anel do Flagelo\",\n\t\"bk:scourge_ring_desc\": \"Sem mais flagelos\",\n\t\"snek_0\": \"Legal.\",\n\t\"snek_1\": \"Valeuuuu cara\",\n\t\"snek_2\": \"Innncrível\",\n\t\"snek_3\": \"E aí\",\n\t\"snek_4\": \"Bom dia, sssenhor!\",\n\t\"snek_5\": \"Tu quer comprar algo?\",\n\t\"snek_6\": \"Preciso ssssatisfazer o consumidor...\",\n\t\"snek_7\": \"Farei o que for precissso!\",\n\t\"bk:snek\": \"Snek\",\n\t\"bk:snek_desc\": \"Lanchinho?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Tem uma chave sobrando?\",\n\t\"boxy_5\": \"Se importa em doar algumas chaves?\",\n\t\"bk:blank\": \"Branco\",\n\t\"bk:blank_desc\": \"_Texto em branco_\",\n\t\"bk:blank_bombs\": \"Bombas em Branco\",\n\t\"bk:blank_bombs_desc\": \"Bala escudo\",\n\t\"bk:explosive_bullets\": \"Balas Explosivas\",\n\t\"bk:explosive_bullets_desc\": \"Explosivo\",\n\t\"bk:random_bullets\": \"Balas Aleatórias\",\n\t\"bk:random_bullets_desc\": \"RNG\",\n\t\"bk:cup\": \"Xícara\",\n\t\"bk:cup_desc\": \"A Vovó não vai resistir\",\n\t\"bk:cartridge\": \"Cartucho\",\n\t\"bk:cartridge_desc\": \"O Mago Negro não vai resistir\",\n\t\"bk:marriage_ring\": \"Anel de Casamento\",\n\t\"bk:marriage_ring_desc\": \"Mago Negro S2 Vovó pra sempre!\",\n\t\"boxy_7\": \"Eu quero chaves\",\n\t\"boxy_8\": \"Parece que você não tem chaves suficientes :(\",\n\t\"boxy_9\": \"Finalmente tenho bastante chaves para ^^abrir^^!\",\n\t\"roger_3\": \"Se importa em pagar?\",\n\t\"roger_4\": \"Sem descontos hoje\",\n\t\"roger_5\": \"Bombas em primeiro lugar\",\n\t\"vampire_7\": \"Você não está saudável o suficiente\",\n\t\"vampire_8\": \"Eu não dou desconto\",\n\t\"vampire_9\": \"Parece que sua vida está baixa\",\n\t\"ach_bk:scourged\": \"Flagelado\",\n\t\"ach_bk:scourged_desc\": \"Pegue uma Ficha de Flagelo\",\n\t\"ach_bk:scourged_weapon\": \"Arma Flagelada\",\n\t\"ach_bk:scourged_weapon_desc\": \"Pegue uma Arma Flagelada\",\n\t\"rerolled\": \"Rolado novamente\",\n\t\"ach_bk:open_up\": \"Abra\",\n\t\"ach_bk:open_up_desc\": \"Compre tudo do Boxy\",\n\t\"ach_bk:snek\": \"Mascote Snek\",\n\t\"ach_bk:snek_desc\": \"Faça Snek ser seu mascote\",\n\t\"bk:scourge_of_greed\": \"Flagelo da Ganância\",\n\t\"bk:scourge_of_greed_desc\": \"Preços altos\",\n\t\"killed_by\": \"Morto por\",\n\t\"kills\": \"Abates\",\n\t\"time\": \"Tempo\",\n\t\"depth\": \"Profundidade\",\n\t\"bk:blank_bullets\": \"Balas em Branco\",\n\t\"bk:blank_bullets_desc\": \"Branco\",\n\t\"bk:lego\": \"Construtor\",\n\t\"bk:lego_desc\": \"Não tanto pisar neles...\",\n\t\"bk:iron_armor\": \"Armadura de Ferro\",\n\t\"bk:iron_armor_desc\": \"Fornece escudos\",\n\t\"bk:round_shield\": \"Escudo Redondo\",\n\t\"bk:round_shield_desc\": \"Anula dano de colisão\",\n\t\"bk:arkhalis\": \"Arkhalis\",\n\t\"bk:arkhalis_desc\": \"A lenda em pessoa\",\n\t\"bk:inverted_arkhalis\": \"Arkhalis invertido\",\n\t\"bk:inverted_arkhalis_desc\": \"A ajuda virá quando a vida estiver baixa\",\n\t\"bk:gun_sword\": \"Espada Revólver\",\n\t\"bk:gun_sword_desc\": \"Prepare-se para problemas em dobro!\",\n\t\"ach_bk:scourge_king_desc\": \"Consiga 10 pontos de flagelo\",\n\t\"ach_bk:scourge_king\": \"Rei do Flagelo\",\n\t\"ach_bk:sting_operation\": \"Operação Picada\",\n\t\"ach_bk:sting_operation_desc\": \"Derrote a Abelha Rainha\",\n\t\"ach_bk:mummified\": \"Mumificado\",\n\t\"ach_bk:mummified_desc\": \"Derrote o Faraó\",\n\t\"ach_bk:democracy\": \"Democracia\",\n\t\"ach_bk:democracy_desc\": \"Derrote Velho Rei\",\n\t\"pharaoh_scream\": \"##PREPARE-SE PARA SER MUMIFICADO!##\",\n\t\"queen_bee_scream\": \"##PELO [cl yellow]SENHOR DO MEL[cl]!##\",\n\t\"bk:half_heart\": \"Meio Coração\",\n\t\"right\": \"Direita\",\n\t\"down\": \"Baixo\",\n\t\"left\": \"Esquerda\",\n\t\"up\": \"Cima\",\n\t\"painting_cat\": \"Pintura de Gato\",\n\t\"bk:axe\": \"Machado\",\n\t\"bk:axe_desc\": \"Ele prometeu voltar\",\n\t\"bk:guitar\": \"Violão\",\n\t\"bk:guitar_desc\": \"Está desafinado\",\n\t\"bk:glass_sword\": \"Espada de Vidro\",\n\t\"bk:glass_sword_desc\": \"A arma dos mestres\",\n\t\"bk:chicken\": \"Asa de Galinha\",\n\t\"bk:chicken_desc\": \"Picante\",\n\t\"bk:pickaxe\": \"Picareta\",\n\t\"bk:pickaxe_desc\": \"Cave, subordinado!\",\n\t\"bk:mana\": \"Mana\",\n\t\"bk:half_mana\": \"Meia-mana\",\n\t\"bk:lava_wand\": \"Varinha de Lava\",\n\t\"bk:lava_wand_desc\": \"Assuntos quentes\",\n\t\"bk:web_wand\": \"Varinha Aranha\",\n\t\"bk:web_wand_desc\": \"Provedor world-wide web\",\n\t\"bk:slap_stick\": \"Bastão de Tapa\",\n\t\"bk:slap_stick_desc\": \"Tapa\",\n\t\"sensivity\": \"Sensibilidade\",\n\t\"no\": \"Não\",\n\t\"scale\": \"Escala\",\n\t\"ach_bk:ice\": \"Era do Gelo\",\n\t\"ach_bk:ice_desc\": \"Chegue nas Ruínas Congeladas\",\n\t\"ach_bk:library\": \"Textos Sagrados\",\n\t\"ach_bk:library_desc\": \"Chegue na Biblioteca Secreta\",\n\t\"bk:ice_skates\": \"Patins de Gelo\",\n\t\"bk:ice_skates_desc\": \"Imunidade ao gelo\",\n\t\"bk:campfire_in_bottle\": \"Fogueira engarrafada\",\n\t\"bk:campfire_in_bottle_desc\": \"Imunidade a congelamento\",\n\t\"library\": \"Biblioteca Secreta\",\n\t\"ach_bk:cat_without_a_hat\": \"Gato sem chapéu\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Encontre a pintura do gato\",\n\t\"ach_bk:rich\": \"Papel Higiênico\",\n\t\"ach_bk:rich_desc\": \"Adquira 99 moedas\",\n\t\"ach_bk:rescue_operation\": \"Operação Resgate\",\n\t\"ach_bk:rescue_operation_desc\": \"Salve um NPC\",\n\t\"ach_bk:tutorial\": \"Guru\",\n\t\"ach_bk:tutorial_desc\": \"Conclua o tutorial\",\n\t\"ach_bk:fancy_hat\": \"Chapéu Maneiro\",\n\t\"ach_bk:fancy_hat_desc\": \"Compre um chapéu\",\n\t\"ach_bk:unlock\": \"Destravador\",\n\t\"ach_bk:unlock_desc\": \"Desbloqueie um item\",\n\t\"floor_brightness\": \"Brilho do chão\",\n\t\"ach_bk:shielded\": \"Levantar Escudos\",\n\t\"ach_bk:shielded_desc\": \"Adquira um coração escudo\",\n\t\"run_type\": \"Tipo de partida\",\n\t\"run_regular\": \"Regular\",\n\t\"run_challenge\": \"Desafio\",\n\t\"damage_taken\": \"Dano recebido\",\n\t\"km\": \"km\",\n\t\"distance_traveled\": \"Distância percorrida\",\n\t\"seed\": \"Semente\",\n\t\"score\": \"Pontuação\",\n\t\"new_high_score\": \"Novo recorde!\",\n\t\"items_collected\": \"Itens coletados\",\n\t\"boss_rush\": \"Boss Rush\",\n\t\"run_bossrush\": \"Boss rush\",\n\t\"bk:blindfold_desc\": \"RIP minhas armas\",\n\t\"bk:blindfold\": \"Venda\",\n\t\"daily_run\": \"Partida Diária\",\n\t\"builder_0_0\": \"É\",\n\t\"builder_0_1\": \"Vou precisar do dinheiro\",\n\t\"builder_0\": \"Estou planejando construir um atalho aqui, mas preciso de mais [vr need] [ic 0] moedas. Você pode me ajudar?\",\n\t\"builder_1\": \"Mas você não tem dinheiro! :(\",\n\t\"builder_2\": \"Obrigado pelo investimento!\",\n\t\"builder_3\": \"Finalmente tenho dinheiro o suficiente para terminar esse projeto! Muito obrigado!\",\n\t\"builder_4\": \"Ok, desculpe!\",\n\t\"shortcut_is_broken\": \"O atalho está quebrado\",\n\t\"ach_bk:boss_rush\": \"Desafiador de Chefes\",\n\t\"ach_bk:boss_rush_desc\": \"Derrote todos os chefes no modo Boss Rush\",\n\t\"ach_bk:daily\": \"Glória do Dia\",\n\t\"ach_bk:daily_desc\": \"Complete a Partida Diária\",\n\t\"ach_bk:desert_shortcut\": \"Atalho para o Palácio do Deserto\",\n\t\"ach_bk:desert_shortcut_desc\": \"Consertou o atalho para o Palácio do Deserto\",\n\t\"ach_bk:jungle_shortcut\": \"Atalho para a Floresta Antiga\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Consertou o atalho para a Floresta Antiga\",\n\t\"ach_bk:ice_shortcut\": \"Atalho para as Ruínas Congeladas\",\n\t\"ach_bk:ice_shortcut_desc\": \"Consertou o atalho para as Ruínas Congeladas\",\n\t\"ach_bk:library_shortcut\": \"Atalho para a Biblioteca Secreta\",\n\t\"ach_bk:library_shortcut_desc\": \"Consertou o atalho para a Biblioteca Secreta\",\n\t\"ach_bk:fashion_matters2\": \"Questão de moda\",\n\t\"ach_bk:fashion_matters2_desc\": \"Compre cada chapéu\",\n\t\"ach_bk:10_challenges\": \"Desafiador\",\n\t\"ach_bk:10_challenges_desc\": \"Complete 10 desafios\",\n\t\"ach_bk:20_challenges\": \"Desafiador 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Complete 20 desafios\",\n\t\"ach_bk:30_challenges\": \"Desafiador 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Complete 30 desafios\",\n\t\"ach_bk:bk_no_more\": \"Chega de BK\",\n\t\"ach_bk:bk_no_more_desc\": \"Derrote o próprio Burning Knight\",\n\t\"ach_bk:dm_no_more\": \"Chega de MN\",\n\t\"ach_bk:dm_no_more_desc\": \"Derrote o Mago Negro\",\n\t\"ach_bk:egor_no_more\": \"Chega de Egor\",\n\t\"ach_bk:egor_no_more_desc\": \"???\",\n\t\"ach_bk:loop\": \"Ah, lá vamos nós de novo\",\n\t\"ach_bk:loop_desc\": \"Entre no loop\",\n\t\"coins_collected\": \"Moedas coletadas\",\n\t\"bk:cup_head\": \"Cabeça de Xícara\",\n\t\"bk:cup_head_desc\": \"Tome uma xícara de chá\",\n\t\"bk:mustache_hat\": \"Bigode\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Chapéu Propulsor\",\n\t\"bk:propeller_hat_desc\": \"Ele gira\",\n\t\"bk:sunglasses\": \"Óculos de sol\",\n\t\"bk:sunglasses_desc\": \"Funciona à noite também!\",\n\t\"bk:cap\": \"Boné\",\n\t\"bk:cap_desc\": \"Da hora @-@\",\n\t\"bk:eyes\": \"Olhos\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Olho\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Cabelo\",\n\t\"bk:hair_desc\": \"Que chique\",\n\t\"won\": \"Venceu\",\n\t\"won_message\": \"Você venceu!\",\n\t\"garderobe_sign\": \"Provador\",\n\t\"darkmarket_tip\": \"~~[cl purple]Flagelo[cl] ou [cl yellow]30 moedas[cl]@@\",\n\t\"mike_0\": \"Tem que me pagar [cl green]3 esmeraldas\",\n\t\"mike_1\": \"Experimente o modo boss rush por [cl green]3 esmeraldas[cl]!\",\n\t\"bk:weird_potion\": \"Poção Esquisita\",\n\t\"bk:weird_potion_desc\": \"Projéteis estranhos\",\n\t\"bk:megaphone\": \"Megafone\",\n\t\"bk:megaphone_desc\": \"Projéteis expansivos\",\n\t\"scourge\": \"Flagelo\",\n\t\"scourge_stats\": \"Flagelo\",\n\t\"run_daily\": \"Diária\",\n\t\"completed_on\": \"Concluído em\",\n\t\"complete\": \"concluído\",\n\t\"next_daily_in\": \"[cl gray]Próxima começa em[cl]\",\n\t\"hours\": \"horas\",\n\t\"minutes\": \"minutos\",\n\t\"seconds\": \"segundos\",\n\t\"ach_bk:star\": \"A Estrela do Show\",\n\t\"ach_bk:star_desc\": \"Adquira 3 orbitais\",\n\t\"ach_bk:family\": \"Família felizinha\",\n\t\"ach_bk:family_desc\": \"Adquira 3 mascotes\",\n\t\"ach_bk:return_to_sender\": \"Não, você\",\n\t\"ach_bk:return_to_sender_desc\": \"Mate um inimigo com seu próprio projétil\",\n\t\"ach_bk:van_no_gogh\": \"Van sem Gogh\",\n\t\"ach_bk:van_no_gogh_desc\": \"Destrua 100 pinturas\",\n\t\"ach_bk:dark_market\": \"Esconderijo do Crime\",\n\t\"ach_bk:dark_market_desc\": \"Desça até o Mercado Negro\",\n\t\"ach_bk:spikes\": \"Assuntos Espinhosos\",\n\t\"ach_bk:spikes_desc\": \"Ative 100 espinhos em uma única partida\",\n\t\"ach_bk:white_flag\": \"Sem Armas\",\n\t\"ach_bk:white_flag_desc\": \"Conclua uma sala sem usar armas nem uma vez\",\n\t\"quack\": \"[cl yellow]Quack![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfeito\",\n\t\"bk_11\": \"EU TE PERDOO DESTA VEZ... MAS ##NÃO FAÇA## ISSO DE NOVO!\",\n\t\"leaderboard\": \"Leaderboard\",\n\t\"display\": \"Display\",\n\t\"around_you\": \"Ao seu redor\",\n\t\"friends\": \"Amigos\",\n\t\"global\": \"Global\",\n\t\"loading\": \"Carregando\",\n\t\"generating\": \"Gerando\",\n\t\"cursor_radius\": \"Raio do cursor\",\n\t\"no_scores_yet\": \"Sem pontuações ainda\",\n\t\"no_score_yet\": \"Sem pontuação ainda\",\n\t\"run\": \"Partida\",\n\t\"top\": \"Topo\",\n\t\"quick_restart\": \"Quack Reiniciar\",\n\t\"painting_dungeon\": \"Masmorra\",\n\t\"painting_goose\": \"Mini ganso\",\n\t\"painting_chess\": \"Elefante Voador\",\n\t\"painting_peach\": \"Pessegueira\",\n\t\"bk:no_lamp\": \"Sem lâmpada\",\n\t\"bk:explosive_lamp\": \"Lâmpada Explosiva\",\n\t\"bk:explosive_lamp_desc\": \"Quando o bum significa mais\",\n\t\"bk:shielded_lamp\": \"Lâmpada Protegida\",\n\t\"bk:shielded_lamp_desc\": \"Levantar Escudos!\",\n\t\"lamp\": \"Lâmpada\",\n\t\"bk:brain\": \"Mega Cérebro\",\n\t\"bk:brain_desc\": \"Poder da mente: Mega\",\n\t\"bk:heart_amulet\": \"Amuleto Coração\",\n\t\"bk:heart_amulet_desc\": \"+1 Tamanho de Coração\",\n\t\"bk:star_amulet_desc\": \"Mais mana\",\n\t\"bk:star_amulet\": \"Amuleto Estrela\",\n\t\"bk:coin_amulet\": \"Amuleto Moeda\",\n\t\"bk:coin_amulet_desc\": \"Moedas valem mais\",\n\t\"bk:key_amulet\": \"Amuleto Chave\",\n\t\"bk:key_amulet_desc\": \"Chaves valem mais\",\n\t\"bk:bomb_amulet\": \"Amuleto Bomba\",\n\t\"bk:bomb_amulet_desc\": \"Bombas valem mais\",\n\t\"bk:eye_amulet\": \"Amuleto Olho\",\n\t\"bk:eye_amulet_desc\": \"Dói ser tão impreciso\",\n\t\"bk:eye_patch\": \"Tapa-olho\",\n\t\"bk:eye_patch_desc\": \"Estão prontas, crianças?\",\n\t\"bk:toilet_paper\": \"Papel Higiênico\",\n\t\"bk:toilet_paper_desc\": \"Está sempre acabando\",\n\t\"bk:decoy\": \"Isca\",\n\t\"bk:decoy_desc\": \"Isso explode\",\n\t\"bk:wallet\": \"Amigo Carteira\",\n\t\"bk:wallet_desc\": \"Guarda suas moedas\",\n\t\"bk:skele_buddy\": \"Esquele-amigo\",\n\t\"bk:skele_buddy_desc\": \"Assustador\",\n\t\"bk:mega_bomb\": \"Mega Bomba\",\n\t\"bk:mega_bomb_desc\": \"Tamanho da bomba: Mega\",\n\t\"bk:condensed_milk\": \"Leite Condensado\",\n\t\"bk:condensed_milk_desc\": \"Pixeis mais rápidos, inimigos mais lentos\",\n\t\"bk:marshmallow\": \"Marshmallow\",\n\t\"bk:marshmallow_desc\": \"Pegajoso\",\n\t\"bk:orbital_multiplier\": \"Multiplicador Orbital\",\n\t\"bk:orbital_multiplier_desc\": \"Mais orbitais!\",\n\t\"bk:pet_multiplier\": \"Multiplicador de Mascotes\",\n\t\"bk:pet_multiplier_desc\": \"Mais mascotes!\",\n\t\"bk:ghost_bullets\": \"Balas Fantasmas\",\n\t\"bk:ghost_bullets_desc\": \"Não param nas paredes\",\n\t\"bk:weight\": \"Peso Pesado\",\n\t\"bk:weight_desc\": \"Ajuda a gravidade\",\n\t\"bk:d2\": \"D2\",\n\t\"bk:d2_desc\": \"É pegar ou largar\",\n\t\"bk:ethernal_d6\": \"D6 Eterno\",\n\t\"bk:ethernal_d6_desc\": \"Rola novamente e/ou destrói\",\n\t\"bk:billiard\": \"Bilhar\",\n\t\"bk:billiard_desc\": \"Projéteis ricocheteiam\",\n\t\"bk:enraged_bullets\": \"Balas Furiosas\",\n\t\"bk:enraged_bullets_desc\": \"Projéteis quebram projéteis\",\n\t\"bk:rewind_button\": \"Botão de Voltar\",\n\t\"bk:rewind_button_desc\": \"Espere aí\",\n\t\"bk:piggy_bank\": \"Cofrinho\",\n\t\"bk:piggy_bank_desc\": \"Minha economia inteira\",\n\t\"coins\": \"Moedas\",\n\t\"bk:death_star\": \"Estrela da Morte\",\n\t\"bk:death_star_desc\": \"RIP Alderan\",\n\t\"bk:soldering_iron\": \"Ferro de Solda\",\n\t\"bk:soldering_iron_desc\": \"É quente pra caramba\",\n\t\"bk:can\": \"Lata\",\n\t\"bk:can_desc\": \"Projéteis duplos\",\n\t\"bk:swimming_mask\": \"Máscara de Mergulho\",\n\t\"bk:swimming_mask_desc\": \"É uma arma secreta\",\n\t\"bk:bullet_chair\": \"Bala Cadeira\",\n\t\"bk:bullet_chair_desc\": \"4 pernas 4 armas\",\n\t\"bk:cell\": \"Célula\",\n\t\"bk:cell_desc\": \"Projéteis multiplicados\",\n\t\"bk:brick\": \"iTijolo\",\n\t\"bk:brick_desc\": \"Níveis maiores\",\n\t\"bk:ring_of_pain\": \"Anel da Dor\",\n\t\"bk:ring_of_pain_desc\": \"Ser ferido fere todo mundo\",\n\t\"bk:schrodingers_cat\": \"Gatos Schrödingers\",\n\t\"bk:schrodingers_cat_desc\": \"Ser Ou Não Ser (50% de chance)\",\n\t\"bk:smoke_bomb\": \"Bomba de Fumaça\",\n\t\"bk:smoke_bomb_desc\": \"Fuga no estilo ninja\",\n\t\"bk:chest_ring\": \"Anel do Baú\",\n\t\"bk:chest_ring_desc\": \"Mais baús!\",\n\t\"bk:empty_shell\": \"Casca Vazia\",\n\t\"bk:empty_shell_desc\": \"Chance de destruir projéteis inimigos\",\n\t\"bk:parachute\": \"Paraquedas\",\n\t\"bk:parachute_desc\": \"Imunidade a abismos\",\n\t\"bk:spiked_cookie\": \"Biscoito Espinhento\",\n\t\"bk:spiked_cookie_desc\": \"Menino espinhento\",\n\t\"bk:shooty\": \"Shooty\",\n\t\"bk:shooty_desc\": \"Ele, quem atira\",\n\t\"bk:rabbit_bullets\": \"Balas-coelho\",\n\t\"bk:rabbit_bullets_desc\": \"Elas se multiplicam\",\n\t\"bk:pandoras_box\": \"Caixa de Pandora\",\n\t\"bk:pandoras_box_desc\": \"Armazene o mal\",\n\t\"bk:bubbles\": \"Bolhas\",\n\t\"bk:bubbles_desc\": \"Amigo Bolha\",\n\t\"bk:match\": \"Fósforo\",\n\t\"bk:match_desc\": \"Fogo para todos\",\n\t\"bk:hammer\": \"Martelo\",\n\t\"bk:hammer_desc\": \"Quebra armaduras\",\n\t\"bk:helmet\": \"Elmo de Ferro\",\n\t\"bk:helmet_desc\": \"Chance de ignorar o dano\",\n\t\"bk:beer\": \"Cerveja\",\n\t\"bk:beer_desc\": \"Dano enfurece\",\n\t\"bk:the_eye\": \"O Olho\",\n\t\"bk:the_eye_desc\": \"Ele está observando\",\n\t\"bk:mimics_tooth\": \"Dente do Mímico\",\n\t\"bk:mimics_tooth_desc\": \"Atrai mímicos\",\n\t\"ach_bk:mimic\": \"Sustinho\",\n\t\"ach_bk:mimic_desc\": \"Encontre um mímico\",\n\t\"bk:paper_airplane\": \"Aviãozinho de papel\",\n\t\"bk:paper_airplane_desc\": \"Projéteis teleguiados\",\n\t\"ach_bk:ice_boss\": \"Livre Estou\",\n\t\"ach_bk:ice_boss_desc\": \"Mate a Rainha do Gelo\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Aham\",\n\t\"painting_agency\": \"Boas-vindas à agência\",\n\t\"language\": \"Idioma\",\n\t\"bk:pouch\": \"Bolsa\",\n\t\"bk:alien_glasses\": \"Óculos Alienígenas\",\n\t\"bk:alien_glasses_desc\": \"Eu vejo mais\",\n\t\"inventory\": \"Inventário\",\n\t\"bk:led\": \"LED\",\n\t\"bk:led_desc\": \"Lâmpada precisa\",\n\t\"bk:fragile_lamp\": \"Lâmpada Frágil\",\n\t\"bk:fragile_lamp_desc\": \"1 golpe mata\",\n\t\"painting_guitar\": \"Mais volume!\",\n\t\"ach_bk:maanex\": \"Até tu, Brutus?\",\n\t\"ach_bk:maanex_desc\": \"Mate Maanex usando sua cabeça\"\n}"
  },
  {
    "path": "BurningKnight/Content/Locales/qu.json",
    "content": "{\"bk:halo\":\"Quack\",\"bk:halo_desc\":\"Quack quack\",\"bk:revolver\":\"Quack\",\"bk:sword\":\"Quack Quack\",\"bk:sword_desc\":\"Quack quaaak quaaak QUACK\",\"bk:heart\":\"Quack\",\"resume\":\"Quack\",\"settings\":\"Quack\",\"restart\":\"Quack\",\"death_message\":\"Quack Quack\",\"descend\":\"Quack\",\"ascend\":\"Quack\",\"exit\":\"Quack\",\"painting_rexcellent\":\"Quack\",\"painting_grannylisa\":\"Quack\",\"painting_maanex\":\"Quack\",\"painting_bk\":\"Quack Quack\",\"painting_failpositive\":\"Quack Quack\",\"painting_old_man\":\"Quack Quack Quack\",\"painting_arthouse\":\"Quack Quack\",\"painting_black\":\"Quack\",\"painting_milt\":\"Quack qk qk qk\",\"painting_skyscraper\":\"Quack QUACK\",\"painting_egor\":\"Quack Quack\",\"painting_null\":\"Quack\",\"painting_badosz\":\"Quack Quack QUACK QUACK Quack\",\"painting_banana\":\"Quack\",\"painting_tv\":\"Quack quaaak quaaak quaaak\",\"painting_company\":\"Quack Quack\",\"painting_pico\":\"Quack-qk\",\"painting_liko\":\"Quack-quaaak\",\"painting_trasevol\":\"Quack qk Quack\",\"painting_lamp\":\"Quack qk\",\"painting_scream\":\"Quack\",\"painting_stars\":\"Quack qk\",\"painting_fog\":\"Quack qk Quack\",\"painting_nufflee\":\"Quack\",\"by\":\"quack\",\"old_man_0\":\"Quack'qk QUACK!\",\"continue_run\":\"Quack Quack\",\"new_run\":\"Quack Quack\",\"was_unlocked\":\"Quack quack!\",\"bk:revolver_desc\":\"Quack quaaak, @qk!\",\"bk:shovel\":\"Quack Quack\",\"bk:shovel_desc\":\"Quack QUACK quack QUACK qk???\",\"beet_0\":\"Quack!\",\"beet_2\":\"Quack QUACK quaaak quack!\",\"npc_hurt_0\":\"Quack.\",\"npc_hurt_1\":\"Quack QUACK.\",\"npc_hurt_2\":\"Quack QUACK.\",\"beet_3\":\"Quack <quack\",\"beet_1\":\"Quack quack qk QUACK quaaak quack ^^qk^^?\",\"beet_1_0\":\"Quack!\",\"beet_1_1\":\"Quack.\",\"beet_4\":\"Quack qk quaaak [quack quaaak]. Quack quaaak QUACK qk qk quaaak?\",\"beet_4_0\":\"Quack!\",\"beet_4_1\":\"Quack.\",\"beet_5\":\"Quack.\",\"beet_4_2\":\"Quack qk QUACK quaaak!\",\"beet_6\":\"Quack. Quack quack quaaak [qk QUACK]!\",\"bk:idol\":\"Quack\",\"bk:idol_desc\":\"Quack QUACK quaaak quack!\",\"bk:key\":\"Quack Quack\",\"bk:infinite_bomb\":\"Quack Quack\",\"bk:infinite_bomb_desc\":\"Quack qk\",\"throw_coin\":\"Quack quack Quack\",\"bk:potatoo\":\"Quack\",\"bk:potatoo_desc\":\"Quack qk\",\"bk:spectacles\":\"Quack\",\"bk:spectacles_desc\":\"Quack QUACK\",\"bk:cross\":\"Quack\",\"bk:cross_desc\":\"Quack quaaak quaaak\",\"bk:slime\":\"Quack\",\"bk:slime_desc\":\"Quack quack\",\"bk:missile\":\"Quack\",\"bk:missile_desc\":\"Quack qk\",\"bk:rod_of_discord\":\"Quack QUACK Quack\",\"bk:rod_of_discord_desc\":\"Quack qk @qk\",\"bk:goo\":\"Quack\",\"bk:goo_desc\":\"Quack qk\",\"bk:jelly\":\"Quack!\",\"bk:jelly_desc\":\"^^Quack^^\",\"bk:broken_stone\":\"Quack Quack\",\"bk:broken_stone_desc\":\"Quack-QUACK qk\",\"bk:nano_orb\":\"Quack Quack\",\"bk:nano_orb_desc\":\"Quack quaaak\",\"bk:saturn\":\"Quack\",\"bk:saturn_desc\":\"Quack quaaak qk quack quaaak quack\",\"bk:soap\":\"Quack\",\"bk:soap_desc\":\"Quack quaaak quack quack\",\"bk:d6\":\"Quack\",\"bk:d6_desc\":\"^^Quack^^ quack!\",\"bk:my_heart\":\"Quack Quack\",\"bk:my_heart_desc\":\"Quack quack\",\"bk:broken_heart\":\"Quack Quack\",\"bk:broken_heart_desc\":\"Quack quack\",\"bk:parcel\":\"Quack\",\"bk:parcel_desc\":\"Quack quaaak\",\"bk:glass\":\"Quack\",\"bk:glass_desc\":\"##Quack## QUACK\",\"bk:glass_bullet\":\"Quack Quack\",\"bk:glass_bullet_desc\":\"Quack quack QUACK\",\"bk:broken_guitar\":\"Quack Quack\",\"bk:broken_guitar_desc\":\"Quack'quack'QUACK!\",\"bk:machine_gun\":\"Quack Quack\",\"bk:machine_gun_desc\":\"Quack\",\"bk:grenade_launcher\":\"Quack Quack\",\"bk:grenade_launcher_desc\":\"Quack!\",\"bk:shotgun\":\"Quack\",\"bk:shotgun_desc\":\"Quack QUACK QUACK quack!\",\"bk:missile_launcher\":\"Quack Quack\",\"bk:missile_launcher_desc\":\"Quack quaaak!\",\"bk:burst_gun\":\"Quack Quack\",\"bk:burst_gun_desc\":\"Quack QUACK qk\",\"bk:flak_cannon\":\"Quack Quack\",\"bk:flak_cannon_desc\":\"Quack'quaaak quack QUACK!\",\"bk:disk_gun\":\"Quack Quack\",\"bk:disk_gun_desc\":\"Quack quaaak\",\"bk:duck_gun\":\"Quack Quack\",\"bk:duck_gun_desc\":\"Quack!\",\"bk:follower\":\"Quack\",\"bk:follower_desc\":\"Quack quack!\",\"bk:portal_gun\":\"Quack Quack\",\"bk:portal_gun_desc\":\"Quack quack QUACK QUACK\",\"bk:snowflake\":\"Quack\",\"bk:snowflake_desc\":\"Quack QUACK!\",\"bk:restock\":\"Quack\",\"bk:restock_desc\":\"Quack quaaak qk\",\"bk:charisma_ring_desc\":\"Quack Quack\",\"bk:charisma_ring\":\"Quack Quack\",\"bk:battery\":\"Quack\",\"tomb_0\":\"Quack qk [qk quack]Quack[quaaak] quack Quack\",\"bk:homemade_dice\":\"Quack Quack\",\"bk:homemade_dice_desc\":\"^^Quack^^ quaaak! (Quack)\",\"shopkeeper_0\":\"##Quack Quack Quack'Quack Quack Quack!##\",\"shopkeeper_1\":\"Quack, QUACK!\",\"shopkeeper_2\":\"Quack'quack QUACK quaaak.\",\"shopkeeper_3\":\"[quaaak quaaak]##Quack Quack Quack!##\",\"shopkeeper_4\":\"[qk qk]Quack!\",\"shopkeeper_5\":\"[quaaak quaaak]Quack Quack!\",\"desert\":\"Quack Quack\",\"jungle\":\"Quack Quack\",\"ice\":\"Quack Quack\",\"bk:iron_boots\":\"Quack Quack\",\"bk:iron_boots_desc\":\"Quack quack qk qk\",\"bk:mimic_totem\":\"Quack Quack\",\"bk:mimic_totem_desc\":\"##Quack Quack Quack##\",\"back_to_town\":\"Quack QUACK Quack\",\"bk:glass_gun\":\"Quack Quack\",\"bk:glass_gun_desc\":\"##Quack##\",\"bk:glass_shard\":\"Quack Quack\",\"bk:glass_shard_desc\":\"Quack quaaak quaaak quaaak quack quack\",\"bk:dagger\":\"Quack\",\"bk:dagger_desc\":\"Quack...\",\"bk:spear\":\"Quack\",\"bk:spear_desc\":\"Quack qk?\",\"shopkeeper_6\":\"Quack :)\",\"shopkeeper_7\":\"Quack, quack QUACK [quaaak QUACK]QUACK[QUACK]?\",\"shopkeeper_8\":\"Quack'qk quack?\",\"back\":\"Quack\",\"master_volume\":\"Quack Quack\",\"music\":\"Quack\",\"sfx\":\"Quack Quack\",\"graphics\":\"Quack\",\"audio\":\"Quack\",\"ui_sfx\":\"Quack Quack Quack\",\"on\":\"Quack\",\"off\":\"Quack\",\"fullscreen\":\"Quack\",\"vsync\":\"Quack-Quack\",\"fps\":\"Quack Quack\",\"speedrun_timer\":\"Quack Quack\",\"screenshake\":\"Quack Quack\",\"reset_progress\":\"Quack Quack\",\"blood_n_gore\":\"Quack'QUACK'Quack\",\"vegan_mode\":\"Quack Quack\",\"reset_settings\":\"Quack Quack\",\"are_you_sure\":\"Quack qk quaaak?\",\"yes\":\"Quack\",\"reset_progress_dis\":\"Quack QUACK qk Quack quaaak quaaak!\",\"reset_settings_dis\":\"Quack qk qk Quack quaaak quack QUACK quaaak QUACK!\",\"autosave\":\"Quack Quack\",\"autopause\":\"Quack Quack\",\"input\":\"Quack\",\"use\":\"Quack\",\"active\":\"Quack\",\"bomb\":\"Quack\",\"interact\":\"Quack\",\"swap\":\"Quack Quack\",\"roll\":\"Quack\",\"duck\":\"Quack\",\"pause\":\"Quack\",\"none\":\"Quack\",\"keyboard_controls\":\"Quack Quack\",\"gamepad_controls\":\"Quack Quack\",\"keyboard\":\"Quack\",\"gamepad\":\"Quack\",\"game\":\"Quack\",\"select\":\"Quack\",\"cursor\":\"Quack\",\"bk:rip\":\"Quack\",\"ach_bk:rip_desc\":\"Quack\",\"ach_bk:overshake\":\"Quack\",\"ach_bk:overshake_desc\":\"quack% qk quack\",\"ach_bk:rip\":\"Quack Quack Quack\",\"bk:emerald\":\"Quack\",\"shopkeeper_9\":\"%%^^$$$^^%%\",\"shopkeeper_10\":\"^^Quack!^^\",\"shopkeeper_11\":\"Quack QUACK %%QUACK%%!\",\"shopkeeper_12\":\"Quack [quaaak quaaak]qk[QUACK] ^^quaaak^^?\",\"shopkeeper_13\":\"Quack qk [QUACK quaaak]QUACK[quack], QUACK qk!\",\"shopkeeper_14\":\"Quack quaaak [QUACK quack]qk[quack]!\",\"bk:magnifier\":\"Quack\",\"bk:magnifier_desc\":\"Quack Quack\",\"bk:mushroom_hat\":\"Quack Quack\",\"bk:mushroom_hat_desc\":\"Quack?\",\"bk:stone_hat\":\"Quack Quack\",\"bk:stone_hat_desc\":\"Quack\",\"bk:knight_hat\":\"Quack Quack\",\"bk:knight_hat_desc\":\"Quack QUACK quack...\",\"bk:cowboy_hat\":\"Quack Quack\",\"bk:cowboy_hat_desc\":\"Quack quaaak!\",\"bk:soup_hat\":\"Quack Quack\",\"bk:soup_hat_desc\":\"^^Quack^^\",\"bk:gold_hat\":\"Quack Quack\",\"bk:gold_hat_desc\":\"[quack qk]Quack!\",\"bk:viking_hat\":\"Quack Quack\",\"bk:viking_hat_desc\":\"Quack!\",\"bk:dunce_hat\":\"Quack Quack\",\"bk:dunce_hat_desc\":\"@-@\",\"bk:top_hat\":\"Quack Quack\",\"bk:top_hat_desc\":\"Quack!\",\"bk:ushanka\":\"Quack\",\"bk:ushanka_desc\":\"Quack qk quack ##quaaak?##\",\"bk:valkyrie_hat\":\"Quack Quack\",\"bk:valkyrie_hat_desc\":\"Quack quaaak ^^Quack QUACK QUACK!^^\",\"bk:skull_hat\":\"Quack Quack\",\"bk:skull_hat_desc\":\"Quack quaaak quack!\",\"bk:grandma_head\":\"Quack Quack\",\"bk:grandma_head_desc\":\"Quack?\",\"bk:diamond_helmet\":\"Quack Quack\",\"bk:diamond_helmet_desc\":\"Quack quack QUACK QUACK!\",\"bk:villager_head\":\"Quack Quack\",\"bk:villager_head_desc\":\"Quack?\",\"bk:fez\":\"Quack\",\"bk:fez_desc\":\"Quack\",\"bk:no_hat\":\"Quack Quack\",\"bk:no_hat_desc\":\"Quack quaaak - QUACK quack!\",\"bk:null_hat\":\"Quack\",\"bk:null_hat_desc\":\"Quack qk qk quaaak quack QUACK\",\"accessorytrader_0\":\"##Quack Quack Quack Quack!## [quack]Quack quack qk ^^quack^^ quaaak qk quaaak ^^%%QUACK QUACK qk%%^^!\",\"accessorytrader_1\":\"Quack\",\"accessorytrader_2\":\"Quack!\",\"weapontrader_0\":\"Quack qk!\",\"weapontrader_1\":\"Quack quack, quack!\",\"weapontrader_2\":\"Quack quaaak', qk quaaak?\",\"activetrader_0\":\"Quack quaaak qk QUACK qk!\",\"activetrader_1\":\"Quack quaaak QUACK qk quaaak quack!\",\"activetrader_2\":\"Quack qk qk, [quack]QUACK!!\",\"hattrader_0\":\"Quack QUACK QUACK quack qk Quack QUACK? [QUACK]Quack quaaak quack!\",\"hattrader_1\":\"Quack quack quack qk quaaak Quack quack? [quack]Quack quaaak, QUACK.\",\"hattrader_2\":\"^^Quack QUACK quaaak!^^\",\"granny_0\":\"Quack qk QUACK?\",\"granny_1\":\"Quack quack quack QUACK!\",\"granny_2\":\"Quack?\",\"bk:xmas_hat\":\"Quack Quack\",\"bk:xmas_hat_desc\":\"Quack Quack!\",\"bk:pumpkin_hat\":\"Quack Quack\",\"bk:pumpkin_hat_desc\":\"^^Quack QUACK quaaak^^\",\"bk:cage_key\":\"Quack Quack\",\"bk:cage_key_desc\":\"Quack ^^qk quack^^!\",\"npc_0\":\"Quack qk! Quack quack quack!\",\"npc_1\":\"Quack QUACK qk quaaak!\",\"npc_2\":\"Quack! Quack quack QUACK!\",\"npc_3\":\"Quack! Quack QUACK!\",\"control_0\":\"Quack [qk qk][QUACK quaaak] quaaak qk QUACK qk\",\"control_1\":\"Quack quack qk! Quack [qk qk][QUACK quaaak] quaaak quaaak quack QUACK!\",\"control_2\":\"Quack [quack quack][quaaak qk] qk QUACK\",\"control_3\":\"Quack [qk qk][QUACK quaaak] quaaak quack\",\"control_4\":\"Quack? [quaaak quaaak][quack QUACK]!\",\"control_5\":\"Quack [qk qk][QUACK quaaak] quaaak quaaak qk\",\"shopkeeper_15\":\"Quack quaaak QUACK QUACK!\",\"shopkeeper_16\":\"Quack qk quack QUACK quack quack!\",\"shopkeeper_17\":\"Quack quack qk!\",\"bk:frog\":\"Quack Quack\",\"bk:frog_desc\":\"Quack QUACK?\",\"bk:sword_orbital\":\"Quack Quack\",\"bk:sword_orbital_desc\":\"Quack\",\"robbed\":\"Quack\",\"bk:gift_desc\":\"Quack'quaaak QUACK?\",\"bk:spike_ring\":\"Quack Quack\",\"bk:spike_ring_desc\":\"Quack QUACK quaaak quack ##qk##!\",\"bk:fire_ring\":\"Quack Quack\",\"bk:fire_ring_desc\":\"Quack quack QUACK qk\",\"bk:ice_ring\":\"Quack Quack\",\"bk:ice_ring_desc\":\"Quack quaaak qk\",\"bk:duck_ring\":\"Quack Quack\",\"bk:duck_ring_desc\":\"Quack qk quaaak quack\",\"bk:dull_blade\":\"Quack Quack\",\"bk:dull_blade_desc\":\"Quack quack quaaak\",\"bk:sharp_blade\":\"Quack Quack\",\"bk:sharp_blade_desc\":\"Quack QUACK\",\"bk:obsidian_shield\":\"Quack Quack\",\"bk:obsidian_shield_desc\":\"Quack = QUACK\",\"bk:bill\":\"Quack\",\"bk:bill_desc\":\"quack quack\",\"control_6\":\"Quack qk quack qk [quaaak quaaak][quack QUACK]\",\"bk:clover\":\"QUACK Quack Quack\",\"bk:clover_desc\":\"Quack!\",\"bk:d4\":\"Quack\",\"bk:d4_desc\":\"^^Quack %%quack QUACK%%!^^\",\"brastin_0\":\"Quack quaaak [quaaak quack]quack[QUACK] qk!\",\"elon_1\":\"Quack quaaak QUACK, qk quaaak\",\"bk:maanex_head\":\"Quack Quack\",\"bk:maanex_head_desc\":\"Quack\",\"bk:maanex\":\"Quack\",\"bk:maanex_desc\":\"Quack qk qk quaaak quaaak quack\",\"mob_0\":\"Quack\",\"bk:map_greenprints\":\"Quack Quack\",\"bk:map_greenprints_desc\":\"Quack qk QUACK\",\"bk:map\":\"Quack\",\"bk:map_desc\":\"Quack qk QUACK QUACK\",\"milt_1\":\"Quack quaaak qk\",\"mapuzzle_0\":\"Quack.\",\"nullptr_0\":\"Quack.\",\"copied_to_clipboard\":\"Quack!\",\"isaac_0\":\"Quack QUACK quack quack...\",\"isaac_1\":\"Quack\",\"isaac_2\":\":quack:\",\"discord_0\":\"Quack qk! quack.quack\\/quack\",\"old_man_5\":\"Quack, quaaak!\",\"tutorial\":\"Quack\",\"bk:crying_bomb\":\"Quack Quack\",\"bk:crying_bomb_desc\":\"Quack qk QUACK!\",\"bk:matches\":\"Quack\",\"bk:matches_desc\":\"Quack quaaak quaaak\",\"bk:bomb_pack\":\"Quack Quack\",\"bk:bomb_pack_desc\":\"Quack quaaak QUACK QUACK quaaak quack!\",\"bk:tnt\":\"Quack\",\"bk:tnt_desc\":\"QUACK qk\",\"bk:weird_mushroom_desc\":\"Quack Quack\",\"bk:weird_mushroom\":\"Quack Quack\",\"bk:bomb_shower\":\"Quack Quack\",\"bk:bomb_shower_desc\":\"Quack quaaak quack QUACK\",\"bk:black_belt\":\"Quack Quack\",\"bk:black_belt_desc\":\"Quack QUACK QUACK\",\"bk:ninjia_bomb\":\"Quack Quack\",\"bk:ninjia_bomb_desc\":\"Quack quack quack quack\",\"start_new_run\":\"Quack qk qk QUACK QUACK quack!\",\"bk:laser_pointer\":\"Quack Quack\",\"bk:laser_pointer_desc\":\"Quack QUACK quack!\",\"ach_bk:marauder\":\"Quack\",\"ach_bk:marauder_desc\":\"Quack quack quack\",\"ach_bk:treasure_hunter\":\"Quack Quack\",\"ach_bk:treasure_hunter_desc\":\"Quack quaaak QUACK QUACK\",\"ach_bk:dodge_master\":\"Quack Quack\",\"ach_bk:dodge_master_desc\":\"Quack quack quaaak quack QUACK qk\",\"ach_bk:dodge_overlord\":\"Quack Quack\",\"ach_bk:dodge_overlord_desc\":\"Quack quack quaaak quack QUACK qk qk\",\"ach_bk:quackers\":\"Quack\",\"ach_bk:quackers_desc\":\"Quack\",\"ach_bk:tea_party\":\"Quack Quack\",\"ach_bk:tea_party_desc\":\"Quack Quack quack quack QUACK quaaak\",\"ach_bk:not_a_thief\":\"Quack QUACK QUACK\",\"ach_bk:not_a_thief_desc\":\"Quack quack quaaak quack quaaak quack QUACK\",\"ach_bk:npc_party2\":\"Quack Quack\",\"ach_bk:npc_party2_desc\":\"Quack QUACK Quack\",\"bk:gold_coin\":\"Quack Quack\",\"bk:iron_coin\":\"Quack Quack\",\"bk:copper_coin\":\"Quack Quack\",\"bk:platinum_coin\":\"Quack Quack\",\"bk:voodoo_doll\":\"Quack Quack\",\"bk:voodoo_doll_desc\":\"Quack quaaak qk quack quack qk\",\"hub\":\"Quack Quack\",\"castle\":\"Quack Quack\",\"charger_0\":\"Quack Quack Quack Quack\",\"charger_1\":\"Quack Quack Quack Quack Quack\",\"charger_2\":\"Quack Quack Quack Quack, Quack, Quack Quack!\",\"charger_3\":\"##Quack Quack Quack Quack Quack Quack!##\",\"charger_4\":\"##Quack Quack Quack Quack Quack Quack!##\",\"charger_5\":\"##Quack##\",\"maanex_6_0\":\"Quack, quack'quack quaaak qk!\",\"maanex_6_1\":\"Quack.\",\"maanex_6\":\"Quack, QUACK quack [qk quaaak][quack quaaak] qk[quack] qk Quack qk QUACK qk quaaak qk quack quaaak quaaak. Quack?\",\"maanex_5\":\"Quack qk, quaaak ^^quack quack^^ qk qk?\",\"maanex_7\":\"Quack quack quack!\",\"maanex_8\":\"Quack quack!\",\"maanex_9\":\"Quack, quack qk quack :(\",\"maanex_10\":\"%%^^Quack^^%%\",\"maanex_11\":\"Quack quack quack'QUACK quaaak quack QUACK!\",\"maanex_12\":\"##Quack?!##\",\"bk:amurs_arrow\":\"Quack'quaaak Quack\",\"bk:amurs_arrow_desc\":\"Quack Quack\",\"bk:amurs_bow\":\"Quack'qk Quack\",\"bk:amurs_bow_desc\":\"Quack quaaak quack\",\"bk:poison_flask\":\"Quack Quack\",\"bk:poison_flask_desc\":\"Quack Quack\",\"bk:snowball\":\"Quack\",\"bk:snowball_desc\":\"Quack Quack Quack\",\"bk:peper_desc\":\"Quack Quack\",\"bk:peper\":\"Quack Quack\",\"bk:sale_coupon\":\"Quack Quack\",\"bk:sale_coupon_desc\":\"-quack%!\",\"bk:pet_box\":\"Quack quaaak qk Quack\",\"bk:pet_box_desc\":\"Quack'quack qk?\",\"bk:crate\":\"Quack Quack\",\"bk:crate_desc\":\"Quack'QUACK quack?\",\"bk:strawberry\":\"Quack\",\"bk:strawberry_desc\":\"Quack Quack\",\"bk:wings\":\"Quack\",\"bk:wings_desc\":\"Quack qk Quack quaaak quaaak\",\"bk:coin_pouch\":\"Quack Quack\",\"bk:coin_pouch_desc\":\"Quack Quack\",\"bk:key_pouch\":\"Quack Quack\",\"bk:key_pouch_desc\":\"Quack Quack\",\"bk:bomb_pouch\":\"Quack Quack\",\"bk:bomb_pouch_desc\":\"Quack Quack\",\"bk:pouch_pouch\":\"Quack Quack\",\"bk:pouch_pouch_desc\":\"Quack Quack\",\"bk:lightsaber\":\"Quack\",\"bk:lightsaber_desc\":\"Quack quaaak quack quack QUACK!\",\"bk:snail\":\"Quack\",\"bk:snail_desc\":\"Quack Quack\",\"bk:spike\":\"Quack\",\"bk:spike_desc\":\"Quack Quack\",\"bk:mushroom\":\"Quack\",\"bk:mushroom_desc\":\"Quack quack\",\"bk:candy\":\"Quack\",\"bk:candy_desc\":\"^^Quack quack^^, QUACK quaaak quaaak\",\"bk:glasses\":\"Quack\",\"bk:glasses_desc\":\"Quack Quack\",\"bk:ruler\":\"Quack\",\"bk:ruler_desc\":\"Quack Quack\",\"bk:stopwatch\":\"Quack\",\"bk:stopwatch_desc\":\"Quack Quack Quack quack Quack\",\"bk_0\":\"##Quack'Quack Quack Quack Quack Quack!##\",\"bk_1\":\"##Quack Quack Quack'Quack Quack Quack!##\",\"bk_2\":\"##Quack Quack'Quack Quack [QUACK QUACK]Quack Quack Quack[quaaak], Quack!##\",\"bk_3\":\"##Quack Quack Quack!##\",\"bk_4\":\"^^Quack Quack Quack^^\",\"shopkeeper_18\":\"[quaaak quaaak]^^Quack QUACK![quaaak]\",\"dm_0\":\"@@Quack@@\",\"ach_bk:deal\":\"Quack Quack\",\"ach_bk:deal_desc\":\"Quack QUACK QUACK QUACK qk Quack Quack\",\"ach_bk:grannys_gift\":\"Quack'quaaak Quack\",\"ach_bk:grannys_gift_desc\":\"Quack qk quaaak quaaak Quack\",\"ach_bk:shopper\":\"Quack qk QUACK Quack\",\"ach_bk:shopper_desc\":\"Quack quack QUACK quaaak qk quaaak\",\"bk_5\":\"Quack Quack'Quack Quack Quack Quack Quack Quack\",\"bk_6\":\"##Quack Quack, [QUACK qk]Quack[quack]!##\",\"bk_7\":\"[QUACK qk]Quack[quack], ##Quack!!!!##\",\"bk_8\":\"Quack Quack, Quack Quack Quack Quack!\",\"bk_9\":\"[quack quaaak]Quack[qk],[QUACK] Quack Quack Quack Quack, Quack##?!?##\",\"bk_10\":\"Quack Quack,[QUACK] Quack Quack [qk quack]Quack[quaaak]\",\"dm_1\":\"Quack quack[quaaak], qk QUACK[QUACK], [QUACK QUACK]Quack[quack]\",\"dm_2\":\"##Quack, quack, Quack qk qk [quaaak qk]QUACK[QUACK]!##\",\"dm_3\":\"##Quack [qk quack]Quack[quaaak]!\",\"dm_4\":\"Quack quack quack [quaaak qk]QUACK quaaak[quaaak] quack quaaak QUACK quack!\",\"granny_3\":\"Quack quack quack QUACK, [qk qk]Quack[quaaak]!\",\"granny_4\":\"Quack, [quack QUACK]Quack [quaaak quaaak][QUACK]!\",\"granny_5\":\"Quack quack quack qk quaaak QUACK!\",\"bk:meat_guy\":\"Quack Quack\",\"bk:meat_guy_desc\":\"Quack!\",\"bk:bullet_stone\":\"Quack Quack\",\"bk:bullet_stone_desc\":\"Quack quack, quack QUACK, quack quack QUACK, QUACK QUACK quack quack\",\"bk:batman\":\"Quack\",\"bk:batman_desc\":\"Quack'qk quack, qk QUACK QUACK\",\"vibration\":\"Quack\",\"bk:sharp_arrow\":\"Quack Quack\",\"bk:sharp_arrow_desc\":\"Quack Quack\",\"machine_0\":\"Quack qk [quaaak QUACK]quack\",\"player_0\":\"Quack?? ##Quack quack QUACK quaaak quaaak QUACK?!?##\",\"bk:boomerang\":\"Quack\",\"bk:boomerang_desc\":\"Quack Quack\",\"bk:backpack\":\"Quack\",\"bk:backpack_desc\":\"Quack Quack Quack\",\"place_an_item\":\"Quack quaaak Quack\",\"bk:crystal\":\"Quack\",\"bk:crystal_desc\":\"Quack Quack QUACK qk Quack\",\"bk:prism\":\"Quack\",\"bk:prism_desc\":\"Quack -> Quack\",\"scourged\":\"Quack\",\"bk:bomb\":\"Quack\",\"bk:scourge_of_egg\":\"Quack quaaak Quack\",\"bk:scourge_of_egg_desc\":\"Quack Quack Quack\",\"bk:scourge_of_unknown\":\"Quack quack Quack\",\"bk:scourge_of_unknown_desc\":\"Quack Quack\",\"bk:scourge_of_blood\":\"Quack QUACK Quack\",\"bk:scourge_of_blood_desc\":\"Quack Quack (qk Quack)\",\"bk:scourge_of_risk\":\"Quack quack Quack\",\"bk:scourge_of_risk_desc\":\"Quack Quack\",\"bk:scourge_of_keys\":\"Quack QUACK Quack\",\"bk:scourge_of_keys_desc\":\"Quack Quack\",\"bk:scourge_of_lost\":\"Quack quaaak Quack\",\"bk:scourge_of_lost_desc\":\"Quack\",\"bk:scourge_of_scourged\":\"Quack quaaak Quack\",\"bk:scourge_of_scourged_desc\":\"Quack Quack\",\"bk:scourge_of_illness\":\"Quack qk Quack\",\"bk:scourge_of_illness_desc\":\"Quack quack Quack\",\"bk:scourge_of_death\":\"Quack QUACK Quack\",\"bk:scourge_of_death_desc\":\"Quack\",\"bk:ancient_revolver\":\"Quack Quack\",\"bk:ancient_revolver_desc\":\"Quack Quack\",\"bk:assault_rifle\":\"Quack Quack\",\"bk:assault_rifle_desc\":\"Quack\",\"fountain_0\":\"Quack quaaak QUACK quack QUACK quack quack QUACK\",\"fountain_1\":\"Quack'qk quack qk qk\",\"fountain_2\":\"Quack'quack QUACK quaaak quack\",\"fountain_3\":\"Quack quack QUACK quack\",\"buffed\":\"Quack\",\"nerfed\":\"Quack\",\"restored\":\"Quack\",\"damaged\":\"Quack\",\"cleansed\":\"Quack\",\"gifted\":\"Quack\",\"lucky\":\"Quack\",\"unlucky\":\"Quack\",\"max_hp\":\"Quack Quack\",\"touch\":\"Quack\",\"break\":\"Quack\",\"no_coins\":\"Quack Quack\",\"old_man_6\":\"Quack'quack quaaak qk qk quaaak, quaaak qk!\",\"roger_0\":\"Quack!\",\"roger_1\":\"##*Quack*##\",\"roger_2\":\"Quack QUACK qk!\",\"bk:shield\":\"Quack\",\"bk:gift\":\"Quack\",\"bk:shield_pouch\":\"Quack Quack\",\"bk:shield_pouch_desc\":\"Quack Quack\",\"bk:shield_buddy\":\"Quack Quack\",\"bk:shield_buddy_desc\":\"Quack quaaak\",\"bk:skeleton_key\":\"Quack Quack\",\"bk:skeleton_key_desc\":\"quaaak QUACK\",\"bk:jar\":\"Quack Quack\",\"bk:jar_desc\":\"Quack Quack Quack\",\"bk:star\":\"Quack\",\"bk:star_desc\":\"Quack quaaak\",\"bk:car_bomb\":\"Quack Quack\",\"bk:car_bomb_desc\":\"Quack Quack Quack\",\"bk:grenade\":\"Quack\",\"bk:grenade_desc\":\"Quack Quack quaaak Quack\",\"trash_goblin_0\":\"Quack qk QUACK QUACK [quack quaaak]quaaak[qk]! Quack!\",\"trash_goblin_1\":\"Quack'quack quaaak![QUACK] Quack quack qk quaaak!\",\"boxy_0\":\"Quack!\",\"boxy_1\":\"Quack QUACK qk quack!\",\"boxy_2\":\"Quack quaaak quack quaaak?\",\"trash_goblin_2\":\"^^Quack qk QUACK QUACK [quack quack] [quaaak qk]^^\",\"bk:vampire_bat\":\"Quack Quack\",\"bk:vampire_bat_desc\":\"Quack\",\"shields\":\"Quack\",\"bk:mustache\":\"Quack\",\"bk:mustache_desc\":\"Quack\",\"bk:bloody_chest\":\"Quack Quack\",\"bk:bloody_chest_desc\":\"Quack Quack\",\"bk:bloody_shield\":\"Quack Quack\",\"bk:bloody_shield_desc\":\"Quack Quack\",\"bk:cutsaw\":\"Quack\",\"bk:cutsaw_desc\":\"Quack Quack Quack\",\"vampire_0\":\"Quack!\",\"vampire_1\":\"Quack quack!\",\"vampire_2\":\"Quack quack!\",\"vampire_3\":\"Quack quaaak quack qk, [QUACK QUACK]^^quaaak[quack]?\",\"vampire_4\":\"^^Quack^^\",\"vampire_5\":\"Quack'qk quaaak quack qk?\",\"vampire_6\":\"Quack QUACK\",\"duck_2\":\"Quack qk QUACK quaaak QUACK?\",\"duck_7_0\":\"Quack\",\"duck_7_1\":\"Quack\",\"duck_7\":\"Quack qk quaaak quack quack?\",\"duck_4\":\"Quack QUACK, quack QUACK QUACK!\",\"duck_5\":\"Quack qk'QUACK qk quaaak QUACK...\",\"duck_6_0\":\"Quack qk\",\"duck_6_1\":\"^^Quack^^\",\"duck_6\":\"Quack Quack'qk qk QUACK?\",\"duck_8_0\":\"[quack quack]Quack[qk]\",\"duck_8_1\":\"[quack quack]Quack[qk]\",\"duck_8\":\"Quack'QUACK quack quaaak ^^%%quack%%^^?\",\"duck_9_0\":\"Quack quaaak\",\"duck_9_1\":\"Quack qk QUACK quack\",\"duck_9\":\"Quack quack qk?\",\"duck_10_0\":\"qk\",\"duck_10_1\":\"QUACK\",\"duck_10\":\"Quack'QUACK QUACK?\",\"duck_11_0\":\"Quack, quaaak qk?\",\"duck_11_1\":\"\\\\[quaaak qk QUACK.QUACK]\",\"duck_11\":\"Quack QUACK quaaak QUACK QUACK\",\"duck_12_0\":\"Quack\",\"duck_12_1\":\"Quack\",\"duck_12\":\"Quack quaaak quaaak?\",\"duck_13_0\":\"Quack.\",\"duck_13_1\":\"Quack quaaak.\",\"duck_13_2\":\"Quack quaaak.\",\"duck_13_3\":\"Quack quaaak.\",\"duck_13\":\"Quack QUACK qk quack quack?\",\"duck_14\":\"Quack.\",\"duck_17_0\":\"Quack qk\",\"duck_17_1\":\"##Quack##\",\"duck_17\":\"Quack quaaak quaaak quack quack qk qk?\",\"duck_18_0\":\"Quack!\",\"duck_18_1\":\"[quack qk]Quack[qk]!\",\"duck_18\":\"Quack QUACK quack qk?\",\"nurse_0\":\"Quack qk qk quaaak quack, quaaak!\",\"nurse_1\":\"Quack qk QUACK qk quack quaaak, qk Quack QUACK [qk quaaak][quack qk] qk[quack]\",\"nurse_2\":\"Quack qk quack QUACK'quaaak qk\",\"elon_4\":\"Quack quaaak QUACK, qk quaaak\",\"elon_2_0\":\"Quack\",\"elon_2_1\":\"Quack quack\",\"elon_2\":\"Quack QUACK QUACK quack QUACK?\",\"elon_3\":\"Quack QUACK qk QUACK quack qk quack qk\",\"elon_5\":\"Quack\",\"elon_7\":\"Quack, quaaak QUACK quaaak QUACK???\",\"gobetta_0\":\"<quaaak\",\"gobetta_1\":\":qk\",\"gobetta_2\":\"=)\",\"gobetta_3\":\"*qk*\",\"gobetta_4\":\"Quack quack... QUACK?\",\"gobetta_5\":\"Quack'QUACK QUACK qk QUACK...\",\"ach_bk:desert\":\"Quack'QUACK'Quack\",\"ach_bk:desert_desc\":\"Quack quaaak Quack Quack\",\"ach_bk:jungle\":\"Quack Quack\",\"ach_bk:jungle_desc\":\"Quack quack Quack Quack\",\"rooms_explored\":\"Quack QUACK\",\"bk:shadow_cloak_desc\":\"Quack Quack\",\"bk:shadow_cloak\":\"Quack Quack\",\"bk:dynamite_stick\":\"Quack Quack\",\"bk:dynamite_stick_desc\":\"Quack QUACK quack quaaak quack?\",\"bk:chalice_of_blood\":\"Quack quack Quack\",\"bk:chalice_of_blood_desc\":\"Quack QUACK qk, quack quack quack\",\"bk:detonator\":\"Quack\",\"bk:detonator_desc\":\"Quack Quack\",\"invincibility_time\":\"Quack Quack\",\"accuracy\":\"Quack\",\"range\":\"Quack\",\"fire_rate\":\"Quack Quack\",\"speed\":\"Quack\",\"bk:talisman_of_foresight\":\"Quack qk Quack\",\"bk:talisman_of_foresight_desc\":\"Quack quack QUACK quaaak QUACK qk quaaak qk!\",\"bk:scourge_ring\":\"Quack Quack\",\"bk:scourge_ring_desc\":\"Quack Quack Quack\",\"snek_0\":\"Quack.\",\"snek_1\":\"Quack quaaak\",\"snek_2\":\"Quack\",\"snek_3\":\"Quack\",\"snek_4\":\"Quack QUACK, QUACK\",\"snek_5\":\"Quack qk qk QUACK?\",\"snek_6\":\"Quack quaaak QUACK QUACK qk qk...\",\"snek_7\":\"Quack QUACK qk, qk Quack qk!\",\"bk:snek\":\"Quack\",\"bk:snek_desc\":\"Quack?\",\"boxy_3\":\"^^:quack:^^\",\"boxy_4\":\"Quack quack qk quack?\",\"boxy_5\":\"Quack qk QUACK qk QUACK?\",\"bk:blank\":\"Quack\",\"bk:blank_desc\":\"qk Quack\",\"bk:blank_bombs\":\"Quack Quack\",\"bk:blank_bombs_desc\":\"Quack Quack\",\"bk:explosive_bullets\":\"Quack Quack\",\"bk:explosive_bullets_desc\":\"Quack\",\"bk:random_bullets\":\"Quack Quack\",\"bk:random_bullets_desc\":\"Quack\",\"bk:cup\":\"Quack\",\"bk:cup_desc\":\"Quack QUACK'qk quaaak quack qk\",\"bk:cartridge\":\"Quack\",\"bk:cartridge_desc\":\"Quack Quack QUACK'qk quaaak quack qk\",\"bk:marriage_ring\":\"Quack Quack\",\"bk:marriage_ring_desc\":\"Quack & Quack Quack!\",\"boxy_7\":\"Quack quack QUACK\",\"boxy_8\":\"Quack quack'QUACK QUACK qk quack quaaak QUACK :(\",\"boxy_9\":\"Quack Quack qk quaaak quack qk QUACK ^^QUACK quack^^!\",\"roger_3\":\"Quack QUACK?\",\"roger_4\":\"Quack qk quack\",\"roger_5\":\"Quack quack\",\"vampire_7\":\"Quack QUACK qk quaaak quack\",\"vampire_8\":\"Quack QUACK'quaaak quaaak quack\",\"vampire_9\":\"Quack quaaak quaaak quack qk quaaak\",\"ach_bk:scourged\":\"Quack\",\"ach_bk:scourged_desc\":\"Quack quaaak Quack Quack\",\"ach_bk:scourged_weapon\":\"Quack Quack\",\"ach_bk:scourged_weapon_desc\":\"Quack quack Quack Quack\",\"rerolled\":\"Quack\",\"ach_bk:open_up\":\"Quack Quack\",\"ach_bk:open_up_desc\":\"Quack qk QUACK Quack\",\"ach_bk:snek\":\"Quack Quack\",\"ach_bk:snek_desc\":\"Quack quack Quack quaaak QUACK QUACK QUACK\",\"bk:scourge_of_greed\":\"Quack quaaak Quack\",\"bk:scourge_of_greed_desc\":\"Quack Quack\",\"killed_by\":\"Quack quaaak\",\"kills\":\"Quack\",\"time\":\"Quack\",\"depth\":\"Quack\",\"bk:blank_bullets\":\"Quack Quack\",\"bk:blank_bullets_desc\":\"Quack\",\"bk:lego\":\"Quack\",\"bk:lego_desc\":\"Quack QUACK QUACK quack qk quack quaaak...\",\"bk:iron_armor\":\"Quack Quack\",\"bk:iron_armor_desc\":\"Quack Quack\",\"bk:round_shield\":\"Quack Quack\",\"bk:round_shield_desc\":\"Quack Quack Quack\",\"bk:arkhalis\":\"Quack\",\"bk:arkhalis_desc\":\"Quack Quack Quack\",\"bk:inverted_arkhalis\":\"Quack Quack\",\"bk:inverted_arkhalis_desc\":\"Quack quaaak qk quack quaaak quaaak quack\",\"bk:gun_sword\":\"Quack Quack\",\"bk:gun_sword_desc\":\"Quack quaaak QUACK qk quack QUACK QUACK!\",\"ach_bk:scourge_king_desc\":\"Quack quack Quack QUACK\",\"ach_bk:scourge_king\":\"Quack Quack\",\"ach_bk:sting_operation\":\"Quack Quack\",\"ach_bk:sting_operation_desc\":\"Quack qk Quack Quack\",\"ach_bk:mummified\":\"Quack\",\"ach_bk:mummified_desc\":\"Quack quack Quack\",\"ach_bk:democracy\":\"Quack\",\"ach_bk:democracy_desc\":\"Quack quack Quack Quack\",\"pharaoh_scream\":\"##Quack Quack Quack Quack!##\",\"queen_bee_scream\":\"##Quack Quack [quack qk]Quack Quack[quack]!##\",\"bk:half_heart\":\"Quack Quack\",\"right\":\"Quack\",\"down\":\"Quack\",\"left\":\"Quack\",\"up\":\"Quack\",\"painting_cat\":\"Quack Quack\",\"bk:axe\":\"Quack\",\"bk:axe_desc\":\"Quack quack QUACK quack\",\"bk:guitar\":\"Quack\",\"bk:guitar_desc\":\"Quack'quack quaaak\",\"bk:glass_sword\":\"Quack Quack\",\"bk:glass_sword_desc\":\"Quack QUACK quaaak QUACK\",\"bk:chicken\":\"Quack Quack\",\"bk:chicken_desc\":\"Quack'qk Quack\",\"bk:pickaxe\":\"Quack\",\"bk:pickaxe_desc\":\"Quack, quack!\",\"bk:mana\":\"Quack\",\"bk:half_mana\":\"Quack Quack\",\"bk:lava_wand\":\"Quack Quack\",\"bk:lava_wand_desc\":\"Quack Quack\",\"bk:web_wand\":\"Quack Quack\",\"bk:web_wand_desc\":\"Quack-quaaak qk QUACK\",\"bk:slap_stick\":\"Quack Quack\",\"bk:slap_stick_desc\":\"Quack\",\"sensivity\":\"Quack\",\"no\":\"Quack\",\"scale\":\"Quack\",\"ach_bk:ice\":\"Quack Quack\",\"ach_bk:ice_desc\":\"Quack qk Quack Quack\",\"ach_bk:library\":\"Quack Quack\",\"ach_bk:library_desc\":\"Quack QUACK Quack Quack\",\"bk:ice_skates\":\"Quack Quack\",\"bk:ice_skates_desc\":\"Quack Quack\",\"bk:campfire_in_bottle\":\"Quack quaaak qk Quack\",\"bk:campfire_in_bottle_desc\":\"Quack Quack\",\"library\":\"Quack Quack\",\"ach_bk:cat_without_a_hat\":\"Quack quack qk qk\",\"ach_bk:cat_without_a_hat_desc\":\"Quack QUACK QUACK qk\",\"ach_bk:rich\":\"Quack Quack\",\"ach_bk:rich_desc\":\"Quack quack qk\",\"ach_bk:rescue_operation\":\"Quack Quack\",\"ach_bk:rescue_operation_desc\":\"Quack QUACK Quack\",\"ach_bk:tutorial\":\"Quack\",\"ach_bk:tutorial_desc\":\"Quack quack QUACK\",\"ach_bk:fancy_hat\":\"Quack Quack\",\"ach_bk:fancy_hat_desc\":\"Quack quaaak quaaak\",\"ach_bk:unlock\":\"Quack\",\"ach_bk:unlock_desc\":\"Quack quaaak qk\",\"floor_brightness\":\"Quack Quack\",\"ach_bk:shielded\":\"Quack Quack\",\"ach_bk:shielded_desc\":\"Quack QUACK quack quaaak\",\"run_type\":\"Quack quack\",\"run_regular\":\"Quack\",\"run_challenge\":\"Quack\",\"damage_taken\":\"Quack quack\",\"km\":\"quack\",\"distance_traveled\":\"Quack qk\",\"seed\":\"Quack\",\"score\":\"Quack\",\"new_high_score\":\"Quack qk!\",\"items_collected\":\"Quack quack\",\"boss_rush\":\"Quack Quack\",\"run_bossrush\":\"Quack qk\",\"bk:blindfold_desc\":\"Quack quack qk\",\"bk:blindfold\":\"Quack\",\"daily_run\":\"Quack Quack\",\"builder_0_0\":\"Quack\",\"builder_0_1\":\"Quack quack quack QUACK qk qk\",\"builder_0\":\"Quack'QUACK QUACK QUACK QUACK QUACK quack quaaak, QUACK Quack qk [quack QUACK] [QUACK QUACK] qk quaaak. Quack quaaak quaaak quack?\",\"builder_1\":\"Quack quaaak quaaak QUACK QUACK! :(\",\"builder_2\":\"Quack quack quack QUACK!\",\"builder_3\":\"Quack quack qk QUACK quaaak quaaak QUACK quack QUACK! Quack quaaak QUACK!\",\"builder_4\":\"Quack, QUACK!\",\"shortcut_is_broken\":\"Quack QUACK qk\",\"ach_bk:boss_rush\":\"Quack Quack\",\"ach_bk:boss_rush_desc\":\"Quack quaaak quack quack quack Quack Quack\",\"ach_bk:daily\":\"Quack Quack\",\"ach_bk:daily_desc\":\"Quack quaaak Quack Quack\",\"ach_bk:desert_shortcut\":\"Quack Quack Quack\",\"ach_bk:desert_shortcut_desc\":\"Quack QUACK QUACK qk quack Quack Quack\",\"ach_bk:jungle_shortcut\":\"Quack Quack Quack\",\"ach_bk:jungle_shortcut_desc\":\"Quack qk qk QUACK quaaak Quack Quack\",\"ach_bk:ice_shortcut\":\"Quack Quack Quack\",\"ach_bk:ice_shortcut_desc\":\"Quack QUACK QUACK qk quack Quack Quack\",\"ach_bk:library_shortcut\":\"Quack Quack Quack\",\"ach_bk:library_shortcut_desc\":\"Quack qk qk QUACK quaaak Quack Quack\",\"ach_bk:fashion_matters2\":\"Quack Quack\",\"ach_bk:fashion_matters2_desc\":\"Quack QUACK quack quaaak\",\"ach_bk:10_challenges\":\"Quack\",\"ach_bk:10_challenges_desc\":\"Quack quaaak QUACK\",\"ach_bk:20_challenges\":\"Quack quaaak.QUACK\",\"ach_bk:20_challenges_desc\":\"Quack QUACK qk\",\"ach_bk:30_challenges\":\"Quack QUACK.qk\",\"ach_bk:30_challenges_desc\":\"Quack quack QUACK\",\"ach_bk:bk_no_more\":\"Quack quaaak quaaak\",\"ach_bk:bk_no_more_desc\":\"Quack qk Quack Quack quaaak\",\"ach_bk:dm_no_more\":\"Quack quaaak quaaak\",\"ach_bk:dm_no_more_desc\":\"Quack qk Quack Quack\",\"ach_bk:egor_no_more\":\"Quack QUACK QUACK\",\"ach_bk:egor_no_more_desc\":\"???\",\"ach_bk:loop\":\"Quack, quaaak quaaak qk quaaak\",\"ach_bk:loop_desc\":\"Quack qk quack\",\"coins_collected\":\"Quack QUACK\",\"bk:cup_head\":\"Quack Quack\",\"bk:cup_head_desc\":\"Quack qk quaaak qk QUACK\",\"bk:mustache_hat\":\"Quack\",\"bk:mustache_hat_desc\":\"Quack\",\"bk:propeller_hat\":\"Quack Quack\",\"bk:propeller_hat_desc\":\"Quack quaaak\",\"bk:sunglasses\":\"Quack\",\"bk:sunglasses_desc\":\"Quack QUACK quack quack!\",\"bk:cap\":\"Quack\",\"bk:cap_desc\":\"Quack @-@\",\"bk:eyes\":\"Quack\",\"bk:eyes_desc\":\"@ @\",\"bk:eye\":\"Quack\",\"bk:eye_desc\":\"@\",\"bk:hair\":\"Quack\",\"bk:hair_desc\":\"Quack\",\"won\":\"Quack\",\"won_message\":\"Quack Quack!\",\"garderobe_sign\":\"Quack Quack\",\"darkmarket_tip\":\"~~[qk QUACK]Quack[quaaak] qk [quack qk]quaaak qk[quack]@@\",\"mike_0\":\"Quack qk QUACK [quack QUACK]quaaak QUACK\",\"mike_1\":\"Quack quack QUACK quaaak qk [QUACK quaaak]qk quaaak[QUACK]!\",\"bk:weird_potion\":\"Quack Quack\",\"bk:weird_potion_desc\":\"Quack Quack\",\"bk:megaphone\":\"Quack\",\"bk:megaphone_desc\":\"Quack Quack\",\"scourge\":\"Quack\",\"scourge_stats\":\"Quack\",\"run_daily\":\"Quack\",\"completed_on\":\"Quack QUACK\",\"complete\":\"quaaak\",\"next_daily_in\":\"[qk quack]Quack quaaak QUACK[quack]\",\"hours\":\"quaaak\",\"minutes\":\"quack\",\"seconds\":\"qk\",\"ach_bk:star\":\"Quack Quack quaaak quack Quack\",\"ach_bk:star_desc\":\"Quack quaaak qk\",\"ach_bk:family\":\"Quack Quack Quack\",\"ach_bk:family_desc\":\"Quack quack quaaak\",\"ach_bk:return_to_sender\":\"Quack Quack\",\"ach_bk:return_to_sender_desc\":\"Quack qk quack qk quaaak QUACK qk\",\"ach_bk:van_no_gogh\":\"Quack Quack Quack\",\"ach_bk:van_no_gogh_desc\":\"Quack QUACK QUACK\",\"ach_bk:dark_market\":\"Quack Quack\",\"ach_bk:dark_market_desc\":\"Quack quaaak quaaak Quack Quack\",\"ach_bk:spikes\":\"Quack Quack\",\"ach_bk:spikes_desc\":\"Quack QUACK quack qk quack qk qk\",\"ach_bk:white_flag\":\"Quack Quack\",\"ach_bk:white_flag_desc\":\"Quack quaaak quack quaaak QUACK quaaak QUACK quaaak\",\"quack\":\"[qk quaaak]Quack![quaaak]\",\"pixel_perfect\":\"Quack Quack\",\"bk_11\":\"Quack Quack Quack Quack Quack... Quack ##Quack Quack## Quack Quack Quack!\",\"leaderboard\":\"Quack\",\"display\":\"Quack\",\"around_you\":\"Quack Quack\",\"friends\":\"Quack\",\"global\":\"Quack\",\"loading\":\"Quack\",\"generating\":\"Quack\",\"cursor_radius\":\"Quack Quack\",\"no_scores_yet\":\"Quack qk quaaak\",\"no_score_yet\":\"Quack quaaak QUACK\",\"run\":\"Quack\",\"top\":\"Quack\",\"quick_restart\":\"Quack Quack\",\"painting_dungeon\":\"Quack\",\"painting_goose\":\"Quack Quack\",\"painting_chess\":\"Quack Quack\",\"painting_peach\":\"Quack qk quack\",\"bk:no_lamp\":\"Quack Quack\",\"bk:explosive_lamp\":\"Quack Quack\",\"bk:explosive_lamp_desc\":\"Quack quack quack QUACK\",\"bk:shielded_lamp\":\"Quack Quack\",\"bk:shielded_lamp_desc\":\"Quack Quack!\",\"lamp\":\"Quack\",\"bk:brain\":\"Quack Quack\",\"bk:brain_desc\":\"Quack Quack: Quack\",\"bk:heart_amulet\":\"Quack Quack\",\"bk:heart_amulet_desc\":\"+quaaak quaaak Quack Quack\",\"bk:star_amulet_desc\":\"Quack Quack\",\"bk:star_amulet\":\"Quack Quack\",\"bk:coin_amulet\":\"Quack Quack\",\"bk:coin_amulet_desc\":\"Quack Quack Quack Quack\",\"bk:key_amulet\":\"Quack Quack\",\"bk:key_amulet_desc\":\"Quack Quack Quack Quack\",\"bk:bomb_amulet\":\"Quack Quack\",\"bk:bomb_amulet_desc\":\"Quack Quack Quack Quack\",\"bk:eye_amulet\":\"Quack Quack\",\"bk:eye_amulet_desc\":\"Quack Quack Quack Quack Quack\",\"bk:eye_patch\":\"Quack Quack\",\"bk:eye_patch_desc\":\"Quack Quack Quack, Quack?\",\"bk:toilet_paper\":\"Quack Quack\",\"bk:toilet_paper_desc\":\"Quack Quack Quack\",\"bk:decoy\":\"Quack\",\"bk:decoy_desc\":\"Quack Quack\",\"bk:wallet\":\"Quack Quack\",\"bk:wallet_desc\":\"Quack Quack Quack\",\"bk:skele_buddy\":\"Quack Quack\",\"bk:skele_buddy_desc\":\"Quack\",\"bk:mega_bomb\":\"Quack Quack\",\"bk:mega_bomb_desc\":\"Quack Quack: Quack\",\"bk:condensed_milk\":\"Quack Quack\",\"bk:condensed_milk_desc\":\"Quack Quack - Quack Quack\",\"bk:marshmallow\":\"Quack\",\"bk:marshmallow_desc\":\"Quack\",\"bk:orbital_multiplier\":\"Quack Quack\",\"bk:orbital_multiplier_desc\":\"Quack Quack!\",\"bk:pet_multiplier\":\"Quack Quack\",\"bk:pet_multiplier_desc\":\"Quack Quack!\",\"bk:ghost_bullets\":\"Quack Quack\",\"bk:ghost_bullets_desc\":\"Quack Quack Quack\",\"bk:weight\":\"Quack Quack\",\"bk:weight_desc\":\"Quack Quack\",\"bk:d2\":\"Quack\",\"bk:d2_desc\":\"Quack QUACK quack quaaak quack\",\"bk:ethernal_d6\":\"Quack Quack\",\"bk:ethernal_d6_desc\":\"Quack Quack\\/Quack Quack\",\"bk:billiard\":\"Quack\",\"bk:billiard_desc\":\"Quack Quack\",\"bk:enraged_bullets\":\"Quack Quack\",\"bk:enraged_bullets_desc\":\"Quack Quack Quack\",\"bk:rewind_button\":\"Quack Quack\",\"bk:rewind_button_desc\":\"Quack Quack\",\"bk:piggy_bank\":\"Quack Quack\",\"bk:piggy_bank_desc\":\"Quack Quack Quack\",\"coins\":\"Quack\",\"bk:death_star\":\"Quack Quack\",\"bk:death_star_desc\":\"Quack Quack\",\"bk:soldering_iron\":\"Quack Quack\",\"bk:soldering_iron_desc\":\"Quack'quaaak Quack\",\"bk:can\":\"Quack\",\"bk:can_desc\":\"Quack Quack\",\"bk:swimming_mask\":\"Quack Quack\",\"bk:swimming_mask_desc\":\"Quack'quaaak QUACK Quack Quack\",\"bk:bullet_chair\":\"Quack Quack\",\"bk:bullet_chair_desc\":\"QUACK Quack qk Quack\",\"bk:cell\":\"Quack\",\"bk:cell_desc\":\"Quack Quack\",\"bk:brick\":\"QUACK\",\"bk:brick_desc\":\"Quack Quack\",\"bk:ring_of_pain\":\"Quack Quack Quack\",\"bk:ring_of_pain_desc\":\"Quack Quack Quack Quack\",\"bk:schrodingers_cat\":\"Quack Quack\",\"bk:schrodingers_cat_desc\":\"Quack Quack Quack Quack Quack Quack (qk% quaaak)\",\"bk:smoke_bomb\":\"Quack Quack\",\"bk:smoke_bomb_desc\":\"Quack-quack Quack\",\"bk:chest_ring\":\"Quack Quack\",\"bk:chest_ring_desc\":\"Quack Quack!\",\"bk:empty_shell\":\"Quack Quack\",\"bk:empty_shell_desc\":\"Quack Quack Quack Quack Quack Quack\",\"bk:parachute\":\"Quack\",\"bk:parachute_desc\":\"Quack Quack\",\"bk:spiked_cookie\":\"Quack Quack\",\"bk:spiked_cookie_desc\":\"Quack Quack\",\"bk:shooty\":\"Quack\",\"bk:shooty_desc\":\"Quack Quack Quack\",\"bk:rabbit_bullets\":\"Quack Quack\",\"bk:rabbit_bullets_desc\":\"Quack Quack\",\"bk:pandoras_box\":\"Quack'quack Quack\",\"bk:pandoras_box_desc\":\"Quack quack Quack\",\"bk:bubbles\":\"Quack\",\"bk:bubbles_desc\":\"Quack Quack\",\"bk:match\":\"Quack\",\"bk:match_desc\":\"Quack Quack Quack\",\"bk:hammer\":\"Quack\",\"bk:hammer_desc\":\"Quack Quack\",\"bk:helmet\":\"Quack Quack\",\"bk:helmet_desc\":\"Quack Quack Quack Quack Quack\",\"bk:beer\":\"Quack\",\"bk:beer_desc\":\"Quack Quack\",\"bk:the_eye\":\"Quack Quack\",\"bk:the_eye_desc\":\"Quack Quack Quack\",\"bk:mimics_tooth\":\"Quack'qk Quack\",\"bk:mimics_tooth_desc\":\"Quack Quack\",\"ach_bk:mimic\":\"Quack Quack\",\"ach_bk:mimic_desc\":\"Quack Quack Quack\",\"bk:paper_airplane\":\"Quack Quack\",\"bk:paper_airplane_desc\":\"Quack Quack\",\"ach_bk:ice_boss\":\"Quack Quack Quack\",\"ach_bk:ice_boss_desc\":\"Quack Quack Quack Quack\",\"ice_queen_scream\":\"^^[qk quack]Quack\",\"painting_agency\":\"Quack quack QUACK qk\",\"language\":\"Quack\",\"bk:pouch\":\"Quack\",\"bk:alien_glasses\":\"Quack Quack\",\"bk:alien_glasses_desc\":\"Quack qk quaaak\",\"inventory\":\"Quack\",\"bk:led\":\"Quack\",\"bk:led_desc\":\"Quack Quack\",\"bk:fragile_lamp\":\"Quack Quack\",\"bk:fragile_lamp_desc\":\"QUACK QUACK Quack.Quack.\",\"painting_guitar\":\"Quack qk!\",\"ach_bk:maanex\":\"Quack qk, Quack?\",\"ach_bk:maanex_desc\":\"Quack Quack quaaak qk QUACK quaaak\",\"dad_0\":\"Quack qk![QUACK] Quack QUACK quack quack qk QUACK [qk qk]quaaak Quack[qk]. Quack quaaak quack quack qk.\",\"dad_1\":\"Quack Quack quack'QUACK quack, qk'quack quack quack quack. Quack!\",\"son_0\":\"##Quack##\",\"gobbo_0\":\"Quack, [quaaak qk]quaaak quack[quaaak] quack quaaak quack quack QUACK. Quack quack qk quaaak QUACK.\",\"gobbo_1\":\"Quack qk QUACK quaaak quaaak QUACK. Quack!\",\"dm_5\":\"Quack quack quack ^^quaaak^^ [quack quack]qk[qk]![QUACK] ##Quack##\",\"dm_6\":\"Quack QUACK QUACK qk, [quaaak quaaak]Quack?\",\"heinur_0\":\"##Quack[qk], Quack Quack!##\",\"nbk_0\":\"##Quack, Quack Quack##\",\"bk_12\":\"##Quack'Quack Quack Quack Quack, Quack Quack Quack, Quack!##\",\"bk:headshot_gun\":\"Quack Quack\",\"bk:headshot_gun_desc\":\"Quack\",\"bk:laser_cannon\":\"Quack Quack\",\"bk:laser_cannon_desc\":\"Quack, quack quack quaaak qk\",\"credits\":\"Quack\",\"ach_bk:collector\":\"Collector\",\"ach_bk:collector_desc\":\"Unlock all items\"}"
  },
  {
    "path": "BurningKnight/Content/Locales/ru.json",
    "content": "{\n\t\"bk:halo\": \"Нимб\",\n\t\"bk:halo_desc\": \"Увеличение HP\",\n\t\"bk:revolver\": \"Револьвер\",\n\t\"bk:sword\": \"Меч\",\n\t\"bk:sword_desc\": \"Не просто палка\",\n\t\"bk:heart\": \"Сердце\",\n\t\"resume\": \"Продолжить\",\n\t\"settings\": \"Настройки\",\n\t\"restart\": \"Начать заново\",\n\t\"death_message\": \"Ты помер\",\n\t\"descend\": \"Спуститься\",\n\t\"ascend\": \"Подняться\",\n\t\"exit\": \"Выход\",\n\t\"painting_rexcellent\": \"«П_рекс_восходно!»\",\n\t\"painting_grannylisa\": \"Граннилиза\",\n\t\"painting_maanex\": \"Думатель\",\n\t\"painting_bk\": \"Подгоревший Рыцарь\",\n\t\"painting_failpositive\": \"Диджей\",\n\t\"painting_old_man\": \"Ну оооочень старый старик\",\n\t\"painting_arthouse\": \"Арт Хаус\",\n\t\"painting_black\": \"Вселенная\",\n\t\"painting_milt\": \"Чувак в снегу\",\n\t\"painting_skyscraper\": \"Одинокий небоскрёб\",\n\t\"painting_egor\": \"Пого_рекс_вший\",\n\t\"painting_null\": \"НУЛЬ\",\n\t\"painting_badosz\": \"Потерявшийся пацан\",\n\t\"painting_banana\": \"Бананчик\",\n\t\"painting_tv\": \"Ящик на небесах\",\n\t\"painting_company\": \"Балдёжная компания\",\n\t\"painting_pico\": \"PICO-8\",\n\t\"painting_liko\": \"LIKO-12\",\n\t\"painting_trasevol\": \"Собака ля Трасевол\",\n\t\"painting_lamp\": \"Да возьми ты её\",\n\t\"painting_scream\": \"Мороженое\",\n\t\"painting_stars\": \"Стрёмная ночь\",\n\t\"painting_fog\": \"На морях\",\n\t\"painting_nufflee\": \"Гав\",\n\t\"by\": \"Автор\",\n\t\"old_man_0\": \"Там опасно!\",\n\t\"continue_run\": \"Продолжить забег\",\n\t\"new_run\": \"Новый забег\",\n\t\"was_unlocked\": \"Был открыт!\",\n\t\"bk:revolver_desc\": \"Руки вверх, @everyone!\",\n\t\"bk:shovel\": \"Синяя лопата\",\n\t\"bk:shovel_desc\": \"А чё она синяя-то?\",\n\t\"beet_0\": \"Привки!\",\n\t\"beet_2\": \"Как назвать?\",\n\t\"npc_hurt_0\": \"Ой.\",\n\t\"npc_hurt_1\": \"Блин, больно.\",\n\t\"npc_hurt_2\": \"О нет.\",\n\t\"beet_3\": \"Пасибки <3\",\n\t\"beet_1\": \"А ты не хочешь посадить ^^семечку^^?\",\n\t\"beet_1_0\": \"Да!\",\n\t\"beet_1_1\": \"Не.\",\n\t\"beet_4\": \"Семечка сейчас [vr seed]. Хочешь ее поменять?\",\n\t\"beet_4_0\": \"Да!\",\n\t\"beet_4_1\": \"Не.\",\n\t\"beet_5\": \"Ну ладно.\",\n\t\"beet_4_2\": \"Пусть будет случайным.\",\n\t\"beet_6\": \"Ок. Семечко теперь [vr seed]!\",\n\t\"bk:idol\": \"Идол\",\n\t\"bk:idol_desc\": \"Внезапно щёлкает скрытая ловушка!\",\n\t\"bk:key\": \"Золотой Ключик\",\n\t\"bk:infinite_bomb\": \"Бесконечная бомба\",\n\t\"bk:infinite_bomb_desc\": \"_Многоразовая_ бомба.\",\n\t\"throw_coin\": \"Кинуть Монетку\",\n\t\"bk:potatoo\": \"Картоошка\",\n\t\"bk:potatoo_desc\": \"Разделяет Пули\",\n\t\"bk:spectacles\": \"Очки\",\n\t\"bk:spectacles_desc\": \"Показывает секретки\",\n\t\"bk:cross\": \"Крест\",\n\t\"bk:cross_desc\": \"Увеличивает время неуязвимости\",\n\t\"bk:slime\": \"Слизь\",\n\t\"bk:slime_desc\": \"Отскакивающие пули\",\n\t\"bk:missile\": \"Ракета\",\n\t\"bk:missile_desc\": \"Самонаводка\",\n\t\"bk:rod_of_discord\": \"Посох Дискорда\",\n\t\"bk:rod_of_discord_desc\": \"Телепортатор для @everyone\",\n\t\"bk:goo\": \"Бяка\",\n\t\"bk:goo_desc\": \"Вращающийся друг\",\n\t\"bk:jelly\": \"Желешка\",\n\t\"bk:jelly_desc\": \"^^Прыгучая^^\",\n\t\"bk:broken_stone\": \"Сломанный камень\",\n\t\"bk:broken_stone_desc\": \"Прочный орбитал\",\n\t\"bk:nano_orb\": \"Нано-шар\",\n\t\"bk:nano_orb_desc\": \"Микродруг\",\n\t\"bk:saturn\": \"Планета\",\n\t\"bk:saturn_desc\": \"Конечно мы её еще любим\",\n\t\"bk:soap\": \"Мыло\",\n\t\"bk:soap_desc\": \"Замедляет пули\",\n\t\"bk:d6\": \"Шестигранка\",\n\t\"bk:d6_desc\": \"^^Реролл^^ предметов!\",\n\t\"bk:my_heart\": \"Моё Сердце\",\n\t\"bk:my_heart_desc\": \"Увеличивает _HP_\",\n\t\"bk:broken_heart\": \"Разбитое Сердце\",\n\t\"bk:broken_heart_desc\": \"Увеличивает _HP_\",\n\t\"bk:parcel\": \"Посылка\",\n\t\"bk:parcel_desc\": \"Многоразовое лечение\",\n\t\"bk:glass\": \"Стекляшка\",\n\t\"bk:glass_desc\": \"##Хрупкие## пули\",\n\t\"bk:glass_bullet\": \"Стеклянные Пули\",\n\t\"bk:glass_bullet_desc\": \"Стреляй над камнями\",\n\t\"bk:broken_guitar\": \"Сломанная Гитара\",\n\t\"bk:broken_guitar_desc\": \"Roll'n'rock!\",\n\t\"bk:machine_gun\": \"Автомат\",\n\t\"bk:machine_gun_desc\": \"Автоматический\",\n\t\"bk:grenade_launcher\": \"Базука\",\n\t\"bk:grenade_launcher_desc\": \"Ба-бах!\",\n\t\"bk:shotgun\": \"Дробаш\",\n\t\"bk:shotgun_desc\": \"Соль в лицо!\",\n\t\"bk:missile_launcher\": \"Ракетница\",\n\t\"bk:missile_launcher_desc\": \"_Цель обнаруженна_\",\n\t\"bk:burst_gun\": \"Пушка-фигулька\",\n\t\"bk:burst_gun_desc\": \"Фигня полнейшая\",\n\t\"bk:flak_cannon\": \"Пушка-Ватрушка\",\n\t\"bk:flak_cannon_desc\": \"Вечеринка\",\n\t\"bk:disk_gun\": \"Дискострел\",\n\t\"bk:disk_gun_desc\": \"Очень острый\",\n\t\"bk:duck_gun\": \"Крякалка\",\n\t\"bk:duck_gun_desc\": \"Кряк!\",\n\t\"bk:follower\": \"Последователь\",\n\t\"bk:follower_desc\": \"За мной!\",\n\t\"bk:portal_gun\": \"Портальная пушка\",\n\t\"bk:portal_gun_desc\": \"Тортик это ложь\",\n\t\"bk:snowflake\": \"Снежинка\",\n\t\"bk:snowflake_desc\": \"Морозит всех\",\n\t\"bk:restock\": \"Поставка\",\n\t\"bk:restock_desc\": \"Товар в магазе не заканчиватся\",\n\t\"bk:charisma_ring_desc\": \"Царские скидки\",\n\t\"bk:charisma_ring\": \"Харизматичное Кольцо\",\n\t\"bk:battery\": \"Батарейка\",\n\t\"tomb_0\": \"Здесь покоится Великий [cl green]Гоблин[cl]\",\n\t\"bk:homemade_dice\": \"Самодельный Кубик\",\n\t\"bk:homemade_dice_desc\": \"^^Реролл^^ предетов! (DIY)\",\n\t\"shopkeeper_0\": \"##Я СКАЗАЛ ПЕРЕСТАНЬ!##\",\n\t\"shopkeeper_1\": \"Оставновись!\",\n\t\"shopkeeper_2\": \"Не надо.\",\n\t\"shopkeeper_3\": \"[cl red]##ГОТОВЬСЯ К СМЕРТИ!##\",\n\t\"shopkeeper_4\": \"[cl red]ВОР!\",\n\t\"shopkeeper_5\": \"[cl red]ЛОВИ ЕГО!\",\n\t\"desert\": \"Пустынный замок\",\n\t\"jungle\": \"Древние джунгли\",\n\t\"ice\": \"Ледяные развалины\",\n\t\"bk:iron_boots\": \"Стальные ботинки\",\n\t\"bk:iron_boots_desc\": \"Шипы — не помеха\",\n\t\"bk:mimic_totem\": \"Тотем Мимиков\",\n\t\"bk:mimic_totem_desc\": \"##Смерть мимикам!##\",\n\t\"back_to_town\": \"Вернуться в Город\",\n\t\"bk:glass_gun\": \"Стеклянная пукалка\",\n\t\"bk:glass_gun_desc\": \"##Хрупкая##\",\n\t\"bk:glass_shard\": \"Осколок стекла\",\n\t\"bk:glass_shard_desc\": \"Остатки целого\",\n\t\"bk:disk_10\": \"Диск №10\",\n\t\"bk:disk_10_desc\": \"Торгаш\",\n\t\"bk:disk_1\": \"Диск 1\",\n\t\"bk:disk_1_desc\": \"Дом\",\n\t\"bk:disk_2\": \"Диск 2\",\n\t\"bk:disk_2_desc\": \"Лес\",\n\t\"bk:disk_3\": \"Диск 3\",\n\t\"bk:disk_3_desc\": \"Джунгли\",\n\t\"bk:disk_4\": \"Диск 4\",\n\t\"bk:disk_4_desc\": \"Лёд\",\n\t\"bk:disk_5\": \"Диск 5\",\n\t\"bk:disk_5_desc\": \"Замок\",\n\t\"bk:disk_6\": \"Диск 6\",\n\t\"bk:disk_6_desc\": \"Ад\",\n\t\"bk:disk_7\": \"Диск 7\",\n\t\"bk:disk_7_desc\": \"???\",\n\t\"bk:disk_8\": \"Диск 8\",\n\t\"bk:disk_8_desc\": \"Пустота\",\n\t\"bk:disk_9\": \"Диск 9\",\n\t\"bk:disk_9_desc\": \"Cut\",\n\t\"bk:dagger\": \"Кинжал\",\n\t\"bk:dagger_desc\": \"Ностальгия...\",\n\t\"bk:spear\": \"Копьё\",\n\t\"bk:spear_desc\": \"Длинные лапки\",\n\t\"shopkeeper_6\": \"Дратуте :)\",\n\t\"shopkeeper_7\": \"[cl yellow]Чая[cl] не хочешь?\",\n\t\"shopkeeper_8\": \"Как жизнь?\",\n\t\"back\": \"Назад\",\n\t\"master_volume\": \"Общая громкость\",\n\t\"music\": \"Музыка\",\n\t\"sfx\": \"Звуки\",\n\t\"graphics\": \"Графон\",\n\t\"audio\": \"Аудио\",\n\t\"ui_sfx\": \"Звуки кнопочек\",\n\t\"on\": \"ВКЛ.\",\n\t\"off\": \"ВЫКЛ.\",\n\t\"fullscreen\": \"Полный экран\",\n\t\"vsync\": \"V-Sync\",\n\t\"fps\": \"Счётчик FPS\",\n\t\"speedrun_timer\": \"Таймер\",\n\t\"screenshake\": \"Тряска экрана\",\n\t\"freeze_frames\": \"Кадры заморозки\",\n\t\"flash_frames\": \"Кадры вспышки\",\n\t\"reset_progress\": \"Сбросить прогресс\",\n\t\"blood_n_gore\": \"Кровь-кишки, страсти-мордасти\",\n\t\"vegan_mode\": \"Овощной режим\",\n\t\"reset_settings\": \"Сбросить настройки\",\n\t\"are_you_sure\": \"Ты уверен?\",\n\t\"yes\": \"Угу\",\n\t\"reset_progress_dis\": \"Это сотрёт весь твой прогресс!\",\n\t\"reset_settings_dis\": \"Это вернёт все настройки к изначальному значению!\",\n\t\"autosave\": \"Авто-сохранение\",\n\t\"autopause\": \"Авто-пауза\",\n\t\"input\": \"Управление\",\n\t\"use\": \"Использовать\",\n\t\"active\": \"Активка\",\n\t\"bomb\": \"Бомба\",\n\t\"interact\": \"Взаимодействие\",\n\t\"swap\": \"Смена Оружия\",\n\t\"roll\": \"Перекат\",\n\t\"duck\": \"Кряк\",\n\t\"pause\": \"Пауза\",\n\t\"none\": \"Ничего\",\n\t\"keyboard_controls\": \"Клава\",\n\t\"gamepad_controls\": \"Геймпад\",\n\t\"keyboard\": \"Клава\",\n\t\"gamepad\": \"Геймпад\",\n\t\"game\": \"Геймплей\",\n\t\"select\": \"Выбрать\",\n\t\"cursor\": \"Курсор\",\n\t\"bk:rip\": \"Покойся с миром...\",\n\t\"ach_bk:rip_desc\": \"Ну, умер и умер.\",\n\t\"ach_bk:overshake\": \"Перетряска\",\n\t\"ach_bk:overshake_desc\": \"1000% тряска экрана\",\n\t\"ach_bk:rip\": \"Самая Популярная Ачивка\",\n\t\"bk:emerald\": \"Изумруд\",\n\t\"shopkeeper_9\": \"%%^^$$$^^%\",\n\t\"shopkeeper_10\": \"^^Пасибки!^^\",\n\t\"shopkeeper_11\": \"Какое %%предложение%%!\",\n\t\"shopkeeper_12\": \"Не хочешь [cl red]купить[cl] ^^что-нибудь^^?\",\n\t\"shopkeeper_13\": \"Только сегодня, только для [cl green]вас[cl]!\",\n\t\"shopkeeper_14\": \"Какое [cl yellow]предложение[cl]!\",\n\t\"bk:magnifier\": \"Лупа\",\n\t\"bk:magnifier_desc\": \"Большие пули\",\n\t\"bk:mushroom_hat\": \"Грибная шапка\",\n\t\"bk:mushroom_hat_desc\": \"Вкусная?\",\n\t\"bk:stone_hat\": \"Окаменевшая шапка\",\n\t\"bk:stone_hat_desc\": \"Тяжелая\",\n\t\"bk:knight_hat\": \"Шлем Рыцаря\",\n\t\"bk:knight_hat_desc\": \"Старые добрые враги...\",\n\t\"bk:cowboy_hat\": \"Шляпа ковбоя\",\n\t\"bk:cowboy_hat_desc\": \"Дикий Запад!\",\n\t\"bk:soup_hat\": \"Супная шляпа\",\n\t\"bk:soup_hat_desc\": \"^^Вкусная.^^\",\n\t\"bk:gold_hat\": \"Золотая Шляпа\",\n\t\"bk:gold_hat_desc\": \"[cl yellow]Богач!\",\n\t\"bk:viking_hat\": \"Шлем викинга\",\n\t\"bk:viking_hat_desc\": \"Америка!\",\n\t\"bk:dunce_hat\": \"Шляпа балбеса\",\n\t\"bk:dunce_hat_desc\": \"@-@\",\n\t\"bk:top_hat\": \"Цилиндр\",\n\t\"bk:top_hat_desc\": \"Модно!\",\n\t\"bk:ushanka\": \"Ушанка\",\n\t\"bk:ushanka_desc\": \"Где моя ##балалайка##?\",\n\t\"bk:valkyrie_hat\": \"Шапка валькирии\",\n\t\"bk:valkyrie_hat_desc\": \"Я верю что ^^я могу летать^^!\",\n\t\"bk:skull_hat\": \"Черепушка\",\n\t\"bk:skull_hat_desc\": \"Кошелек или жизнь!\",\n\t\"bk:grandma_head\": \"Голова бабули\",\n\t\"bk:grandma_head_desc\": \"Чайку?\",\n\t\"bk:diamond_helmet\": \"Алмазный шлем\",\n\t\"bk:diamond_helmet_desc\": \"Иди копай!\",\n\t\"bk:villager_head\": \"Голова жителя\",\n\t\"bk:villager_head_desc\": \"Хмм?\",\n\t\"bk:fez\": \"Феска\",\n\t\"bk:fez_desc\": \"Кубит\",\n\t\"bk:no_hat\": \"Снять шляпу\",\n\t\"bk:no_hat_desc\": \"Нет шляпы — нет проблем!\",\n\t\"bk:null_hat\": \"NULL\",\n\t\"bk:null_hat_desc\": \"Попытка вызвать значение null\",\n\t\"accessorytrader_0\": \"##УБИРАЙСЯ ОТСЮДА!## [dl]Или купи эти ^^превосходные^^ предметы за ^^%%99 кристалов каждый%%^^!\",\n\t\"accessorytrader_1\": \"Здоров!\",\n\t\"accessorytrader_2\": \"Привет!\",\n\t\"weapontrader_0\": \"Заходи!\",\n\t\"weapontrader_1\": \"Как погода?\",\n\t\"weapontrader_2\": \"Купи что-нибудь, я хочу пообедать!\",\n\t\"activetrader_0\": \"Лучшие предложения на рынке!\",\n\t\"activetrader_1\": \"Заплати за два и получи два!\",\n\t\"activetrader_2\": \"Купи мне пончиков, [dl]пожалуйста!!\",\n\t\"hattrader_0\": \"Хочешь быть таким же ^^сногшибательным^^ как я? [dl]Купи шляпу!\",\n\t\"hattrader_1\": \"Хочешь быть таким же крутым, как я? [dl]Я тоже.\",\n\t\"hattrader_2\": \"^^Ха ха hats!^^\",\n\t\"granny_0\": \"Не хочешь чайку?\",\n\t\"granny_1\": \"Сделай паузу, выпей чайку!\",\n\t\"granny_2\": \"Чайку?\",\n\t\"bk:xmas_hat\": \"Колпак св. Николая\",\n\t\"bk:xmas_hat_desc\": \"С Рождеством!\",\n\t\"bk:pumpkin_hat\": \"Тыквище\",\n\t\"bk:pumpkin_hat_desc\": \"^^Spooky spooky skeleton^^\",\n\t\"bk:cage_key\": \"Ключ от Тюрьмы\",\n\t\"bk:cage_key_desc\": \"Спаси ^^чувака^^!\",\n\t\"npc_0\": \"Помоги мне! Найди ключ!\",\n\t\"npc_1\": \"Спасибо за спасение!\",\n\t\"npc_2\": \"Быстрей, открывай дверь!\",\n\t\"npc_3\": \"Пожалуйста, спаси меня!\",\n\t\"control_0\": \"Жмякни [ic 0][ic 1], чтобы поставить бомбу\",\n\t\"control_1\": \"Перекатываться ты можешь! Тыкни [ic 0][ic 1], чтобы обрести силу!\",\n\t\"control_2\": \"Нажми [ic 0][ic 1] чтобы стать опасным\",\n\t\"control_3\": \"Дотянись до [ic 0][ic 1], чтобы взаимодействовать\",\n\t\"control_4\": \"Кряк? [ic 0][ic 1]!\",\n\t\"control_5\": \"Используй [ic 0][ic 1], чтобы менять оружия\",\n\t\"shopkeeper_15\": \"Я не давал тебе скидок!\",\n\t\"shopkeeper_16\": \"Притащи побольше денег!\",\n\t\"shopkeeper_17\": \"Ты забыл заплатить!\",\n\t\"bk:frog\": \"Телегушка\",\n\t\"bk:frog_desc\": \"Телетуризм?\",\n\t\"bk:sword_orbital\": \"Меч Правосудия\",\n\t\"bk:sword_orbital_desc\": \"Он крутится. Справедливо!\",\n\t\"robbed\": \"Ограблен\",\n\t\"bk:gift_desc\": \"Что же там внутри?\",\n\t\"bk:spike_ring\": \"Колючее кольцо\",\n\t\"bk:spike_ring_desc\": \"Урон с касания\",\n\t\"bk:fire_ring\": \"Горящее кольцо\",\n\t\"bk:fire_ring_desc\": \"Поджог с касания\",\n\t\"bk:ice_ring\": \"Ледяное кольцо\",\n\t\"bk:ice_ring_desc\": \"Заморозка с касания\",\n\t\"bk:duck_ring\": \"Крякцо\",\n\t\"bk:duck_ring_desc\": \"Телепортация с урона\",\n\t\"bk:dull_blade\": \"Затупившаяся бритва\",\n\t\"bk:dull_blade_desc\": \"Тригеррит предметы на получение урона\",\n\t\"bk:sharp_blade\": \"Бритва\",\n\t\"bk:sharp_blade_desc\": \"Больно\",\n\t\"bk:obsidian_shield\": \"Обсидиановый Щит\",\n\t\"bk:obsidian_shield_desc\": \"Иммунитет к отбрасыванию\",\n\t\"bk:bill\": \"Валюта\",\n\t\"bk:bill_desc\": \"99 баксиков\",\n\t\"control_6\": \"Используй активку с помощью [ic 0][ic 1]\",\n\t\"bk:clover\": \"Четырёхлистник\",\n\t\"bk:clover_desc\": \"Счастливый!\",\n\t\"bk:d4\": \"Четырёхгранка\",\n\t\"bk:d4_desc\": \"^^Реролл %%твоих артифактов%%!^^\",\n\t\"brastin_0\": \"Найди картину [cl purple]с котом[cl]!\",\n\t\"elon_1\": \"Держи!\",\n\t\"bk:maanex_head\": \"Голова Маанекса\",\n\t\"bk:maanex_head_desc\": \"Хмммммм\",\n\t\"bk:maanex\": \"Маанекс\",\n\t\"bk:maanex_desc\": \"Заставляет врагов задуматься\",\n\t\"mob_0\": \"Хмммм\",\n\t\"bk:map_greenprints\": \"Чертежи Замка\",\n\t\"bk:map_greenprints_desc\": \"Открывает Карту\",\n\t\"bk:map\": \"Карта\",\n\t\"bk:map_desc\": \"Открывает Карту навсегда\",\n\t\"milt_1\": \"Я хочу подарочек\",\n\t\"mapuzzle_0\": \"Гравитация.\",\n\t\"nullptr_0\": \"ОШИБКА СЕГМЕНТАЦИИ.\",\n\t\"copied_to_clipboard\": \"Скопированно!\",\n\t\"isaac_0\": \"В жизни нет смысла...\",\n\t\"isaac_1\": \"Почему\",\n\t\"isaac_2\": \":sob:\",\n\t\"discord_0\": \"Скажи привет discord.gg\\/rexcellent\",\n\t\"old_man_5\": \"Катись, глупец!\",\n\t\"tutorial\": \"Обучение\",\n\t\"bk:crying_bomb\": \"Бомба-плакса\",\n\t\"bk:crying_bomb_desc\": \"Бомбы стреляют\",\n\t\"bk:matches\": \"Спички\",\n\t\"bk:matches_desc\": \"Уменьшает задержку перед взрывом у бомб\",\n\t\"bk:bomb_pack\": \"Пачка бомб\",\n\t\"bk:bomb_pack_desc\": \"Мы кладем бомбы в ваши бомбы!\",\n\t\"bk:tnt\": \"Динамит\",\n\t\"bk:tnt_desc\": \"99 взрывалок\",\n\t\"bk:weird_mushroom_desc\": \"Удваивает всё\",\n\t\"bk:weird_mushroom\": \"Стремный гриб\",\n\t\"bk:bomb_shower\": \"Бомбический душ\",\n\t\"bk:bomb_shower_desc\": \"Пусть льёт как из ведра! Бомбами!\",\n\t\"bk:black_belt\": \"Чёрный пояс\",\n\t\"bk:black_belt_desc\": \"Больше не взрывайся\",\n\t\"bk:ninjia_bomb\": \"Бомба Ниндзя\",\n\t\"bk:ninjia_bomb_desc\": \"Призывает подмогу при получении урона\",\n\t\"start_new_run\": \"Твой забег будет стёрт!\",\n\t\"bk:laser_pointer\": \"Лазерная указка\",\n\t\"bk:laser_pointer_desc\": \"Прицел\",\n\t\"ach_bk:marauder\": \"Мародёр\",\n\t\"ach_bk:marauder_desc\": \"Убей торговца\",\n\t\"ach_bk:treasure_hunter\": \"Искатель сокровищ\",\n\t\"ach_bk:treasure_hunter_desc\": \"Найди секретку\",\n\t\"ach_bk:dodge_master\": \"Мастер-уклонист\",\n\t\"ach_bk:dodge_master_desc\": \"Завали главаря без получения урона\",\n\t\"ach_bk:dodge_overlord\": \"Сверх-уклонист\",\n\t\"ach_bk:dodge_overlord_desc\": \"Пройди этаж без получения урона\",\n\t\"ach_bk:quackers\": \"Квакерz\",\n\t\"ach_bk:quackers_desc\": \"Переквакай\",\n\t\"ach_bk:tea_party\": \"Полуденный чай\",\n\t\"ach_bk:tea_party_desc\": \"Выпей чашечку чая с Бабусей\",\n\t\"ach_bk:not_a_thief\": \"Больше не вор\",\n\t\"ach_bk:not_a_thief_desc\": \"Заверши забег не украв не единого предмета\",\n\t\"ach_bk:npc_party2\": \"Туса\",\n\t\"ach_bk:npc_party2_desc\": \"Спаси всех NPC\",\n\t\"bk:gold_coin\": \"Золотая монета\",\n\t\"bk:iron_coin\": \"Железная монета\",\n\t\"bk:copper_coin\": \"Медная монета\",\n\t\"bk:platinum_coin\": \"Платиновая монета\",\n\t\"bk:voodoo_doll\": \"Кукла Вуду\",\n\t\"bk:voodoo_doll_desc\": \"Убивает всех врагов в комнате\",\n\t\"hub\": \"Город доджей\",\n\t\"castle\": \"Руины\",\n\t\"charger_0\": \"АКТИВКА НЕ ОБНАРУЖЕННА\",\n\t\"charger_1\": \"АКТИВКА УЖЕ ЗАРЯЖЕННА\",\n\t\"charger_2\": \"ГДЕ МОИ ДЕНЬГИ, МЕШОК С МЯСОМ?\",\n\t\"charger_3\": \"##Я СКАЗАЛ ДАЙ МНЕ ДЕНЬГИY!##\",\n\t\"charger_4\": \"##Я ЗАХВАЧУ ВЕСЬ МИР!##\",\n\t\"charger_5\": \"##МУХАХАХАХАХАХА##\",\n\t\"maanex_6_0\": \"Конечно, давай!\",\n\t\"maanex_6_1\": \"Найн.\",\n\t\"maanex_6\": \"Окей, дай мне [cl yellow][vr cost] монет[cl] и я дам тебе открыть один сундук, идет?\",\n\t\"maanex_5\": \"Эй ты, не хочешь ^^испытать удачу^^?\",\n\t\"maanex_7\": \"Это было весело!\",\n\t\"maanex_8\": \"Удачи!\",\n\t\"maanex_9\": \"Ну, повезет в следующий раз :(\",\n\t\"maanex_10\": \"%%^^ВАУ^^%\",\n\t\"maanex_11\": \"Но у тебя нет столько денег!\",\n\t\"maanex_12\": \"##СЫН?!##\",\n\t\"bk:amurs_arrow\": \"Стрела Амура\",\n\t\"bk:amurs_arrow_desc\": \"Влюбляющие пули\",\n\t\"bk:amurs_bow\": \"Лук Амура\",\n\t\"bk:amurs_bow_desc\": \"Я вижу любовь\",\n\t\"bk:poison_flask\": \"Склянка с ядом\",\n\t\"bk:poison_flask_desc\": \"Отравленные пули\",\n\t\"bk:snowball\": \"Снежок\",\n\t\"bk:snowball_desc\": \"Леденящие пули\",\n\t\"bk:peper_desc\": \"Горячие пули\",\n\t\"bk:peper\": \"Острый перчик\",\n\t\"bk:sale_coupon\": \"Купон на Скидон\",\n\t\"bk:sale_coupon_desc\": \"-50%!\",\n\t\"bk:pet_box\": \"Кот в коробке\",\n\t\"bk:pet_box_desc\": \"А кто же внутри?\",\n\t\"bk:crate\": \"Коробка с орбиталами\",\n\t\"bk:crate_desc\": \"А кто же внутри?\",\n\t\"bk:strawberry\": \"Клубничка\",\n\t\"bk:strawberry_desc\": \"Сладкие воспоминания\",\n\t\"bk:wings\": \"Крылья\",\n\t\"bk:wings_desc\": \"Я не верю, что могу летать\",\n\t\"bk:coin_pouch\": \"Мешочек с монетами\",\n\t\"bk:coin_pouch_desc\": \"Дает монеты\",\n\t\"bk:key_pouch\": \"Мешочек с ключами\",\n\t\"bk:key_pouch_desc\": \"Дает ключи\",\n\t\"bk:bomb_pouch\": \"Бомбический мешочек\",\n\t\"bk:bomb_pouch_desc\": \"Дает бомбы\",\n\t\"bk:pouch_pouch\": \"Мешочек с мешочками\",\n\t\"bk:pouch_pouch_desc\": \"Он точно не дает мешочки\",\n\t\"bk:lightsaber\": \"Светсейбер\",\n\t\"bk:lightsaber_desc\": \"Ты был избранным!\",\n\t\"bk:snail\": \"Улитка\",\n\t\"bk:snail_desc\": \"Замедляет врагов\",\n\t\"bk:spike\": \"Колючка\",\n\t\"bk:spike_desc\": \"+1 к урону\",\n\t\"bk:mushroom\": \"Гриб\",\n\t\"bk:mushroom_desc\": \"Буст скорость\",\n\t\"bk:candy\": \"Конфетка\",\n\t\"bk:candy_desc\": \"^^Повышает бодрость^^, увеличивает скорость стрельбы\",\n\t\"bk:glasses\": \"Очки\",\n\t\"bk:glasses_desc\": \"Повышенная точность\",\n\t\"bk:ruler\": \"Линейка\",\n\t\"bk:ruler_desc\": \"+1 к дальности атаки\",\n\t\"bk:stopwatch\": \"Секундомер\",\n\t\"bk:stopwatch_desc\": \"Получение урона замедляет время\",\n\t\"bk_0\": \"##НЕ СМЕЙ ТРОГАТЬ ЭТО!##\",\n\t\"bk_1\": \"##Я СКАЗАЛ НЕ ТРОГАЙ!!##\",\n\t\"bk_2\": \"##ТЫ НЕ МОЖЕШЬ ПОБЕДИТЬ МЕНЯ, [cl red]ГОРЯЩЕГО РЫЦАРЯ[cl], ГЛУПЕЦ!##\",\n\t\"bk_3\": \"##ПРИГОТОВЬСЯ ВСТРЕТИТЬ СВОЮ КОНЧИНУ!##\",\n\t\"bk_4\": \"^^КАКАЯ ШУТКА^^\",\n\t\"shopkeeper_18\": \"[cl red]^^Горячая распродажа![cl]\",\n\t\"dm_0\": \"@@Добро пожаловать@@\",\n\t\"ach_bk:deal\": \"Выдающийся ход\",\n\t\"ach_bk:deal_desc\": \"Соверши сделку с Темным Магом\",\n\t\"ach_bk:grannys_gift\": \"Подарок Бабушки\",\n\t\"ach_bk:grannys_gift_desc\": \"Получи подарок от Бабуси\",\n\t\"ach_bk:shopper\": \"Покупки до упада\",\n\t\"ach_bk:shopper_desc\": \"Купи предмет в магазе\",\n\t\"bk_5\": \"Я БЫ НЕ ОБРАЩАЛ ВНИМАНИЯ НА ЭТУ ПИСКЛЮ\",\n\t\"bk_6\": \"##УБЕЙ ЕГО, [cl lime]ЭДВАРД[cl]!##\",\n\t\"bk_7\": \"[cl lime]ЭДВАРТ[cl], ##НЕЕЕЕЕЕТ!!!!##\",\n\t\"bk_8\": \"ПЕРЕСТАНЬ ВЗРЫВАТЬ МОЙ ЗАМОК!\",\n\t\"bk_9\": \"[cl pink]СТАРУХА[cl],[dl] ТЫ МОЖЕШЬ УЖЕ СГИНУТЬ, ПОЖАЛУЙСТА##?!?##\",\n\t\"bk_10\": \"МАСТЕР,[dl] Я ПРИВЕЛ [cl green]ГОБЛИНА[cl]\",\n\t\"dm_1\": \"Очень хорошо[dl], спасибо[dl], [cl red]Лимпор[cl]\",\n\t\"dm_2\": \"##Да, да, мне нужно больше[cl orange]мощи[cl]!##\",\n\t\"dm_3\": \"##БОЛЬШЕ [cl orange]МОЩИ[cl]!\",\n\t\"dm_4\": \"Я чуствую [cl orange]мощь[cl] пульсирующую во мне!\",\n\t\"granny_3\": \"Ты будешь первым, [cl red]Лимпор[cl]!\",\n\t\"granny_4\": \"Добро пожаловать, [cl green]Гоббо [vr id][cl]!\",\n\t\"granny_5\": \"Удачи в твоем печальном квесте!\",\n\t\"bk:meat_guy\": \"Мясной товарищ\",\n\t\"bk:meat_guy_desc\": \"Мощный!\",\n\t\"bk:bullet_stone\": \"Каменный стрелок\",\n\t\"bk:bullet_stone_desc\": \"Он аттакует и защищает!\",\n\t\"bk:batman\": \"Батарейкман\",\n\t\"bk:batman_desc\": \"Не помогает, но зато дает батарейки\",\n\t\"vibration\": \"Вибрация\",\n\t\"bk:sharp_arrow\": \"Острая стрела\",\n\t\"bk:sharp_arrow_desc\": \"Сквозные пули\",\n\t\"machine_0\": \"Вставьте [cl yellow]монету\",\n\t\"bk:boomerang\": \"Бумеранг\",\n\t\"bk:boomerang_desc\": \"Пули вернутся\",\n\t\"bk:backpack\": \"Рюкзак\",\n\t\"bk:backpack_desc\": \"Больше места\",\n\t\"place_an_item\": \"Положить предмет\",\n\t\"bk:crystal\": \"Кристалл\",\n\t\"bk:crystal_desc\": \"Сила Радуги\",\n\t\"bk:prism\": \"Призма\",\n\t\"bk:prism_desc\": \"Пули -> Радуга\",\n\t\"scourged\": \"Проклят\",\n\t\"bk:bomb\": \"Бомба\",\n\t\"bk:scourge_of_egg\": \"Проклятие Яйца\",\n\t\"bk:scourge_of_egg_desc\": \"Перепутанные названия\",\n\t\"bk:scourge_of_unknown\": \"Проклятие Неизвестности\",\n\t\"bk:scourge_of_unknown_desc\": \"Спрятанные предметы\",\n\t\"bk:scourge_of_blood\": \"Проклятие Крови\",\n\t\"bk:scourge_of_blood_desc\": \"Больше врагов\",\n\t\"bk:scourge_of_risk\": \"Проклятие Риска\",\n\t\"bk:scourge_of_risk_desc\": \"Спрятанное здоровье\",\n\t\"bk:scourge_of_keys\": \"Проклятие Ключей\",\n\t\"bk:scourge_of_keys_desc\": \"Спрятанные пикапы\",\n\t\"bk:scourge_of_lost\": \"Проклятие Потерянного\",\n\t\"bk:scourge_of_lost_desc\": \"Амнезия\",\n\t\"bk:scourge_of_scourged\": \"Проклятие Проклятого\",\n\t\"bk:scourge_of_scourged_desc\": \"Проклятия Везде\",\n\t\"bk:scourge_of_illness\": \"Проклятие Больного\",\n\t\"bk:scourge_of_illness_desc\": \"Сердца лечат меньше\",\n\t\"bk:scourge_of_death\": \"Проклятие Смерти\",\n\t\"bk:scourge_of_death_desc\": \"Хардмод\",\n\t\"bk:ancient_revolver\": \"Древний револьвер\",\n\t\"bk:ancient_revolver_desc\": \"Выглядит Классно\",\n\t\"bk:assault_rifle\": \"Штурмовая винтовка\",\n\t\"bk:assault_rifle_desc\": \"Пиу-пиу!\",\n\t\"fountain_0\": \"Принеси пять монет и я благославлю тебя\",\n\t\"fountain_1\": \"Ты был частично очищен\",\n\t\"fountain_2\": \"Ты был полностью очищен\",\n\t\"fountain_3\": \"Ты уже очищен\",\n\t\"buffed\": \"Баффнут\",\n\t\"nerfed\": \"Понерфлен\",\n\t\"restored\": \"Возрождён\",\n\t\"damaged\": \"Увечен\",\n\t\"damage\": \"Урон\",\n\t\"cleansed\": \"Очищен\",\n\t\"gifted\": \"Одарён\",\n\t\"lucky\": \"Счастливчик\",\n\t\"unlucky\": \"Неудачник\",\n\t\"max_hp\": \"Максимальные HP\",\n\t\"touch\": \"Потрогать\",\n\t\"break\": \"Сломать\",\n\t\"no_coins\": \"Нет монет\",\n\t\"old_man_6\": \"Опасно идти одному, возми это!\",\n\t\"roger_0\": \"Бум!\",\n\t\"roger_1\": \"##*БУМ*##\",\n\t\"roger_2\": \"Бум бум шакалака!\",\n\t\"bk:shield\": \"Щит\",\n\t\"bk:gift\": \"Подарок\",\n\t\"bk:shield_pouch\": \"Мешочек с щитами\",\n\t\"bk:shield_pouch_desc\": \"Дает щиты\",\n\t\"bk:shield_buddy\": \"Щитовик\",\n\t\"bk:shield_buddy_desc\": \"Защитник\",\n\t\"bk:skeleton_key\": \"Ключ Скелета\",\n\t\"bk:skeleton_key_desc\": \"99 ключиков\",\n\t\"bk:jar\": \"Склянка со Здоровьем\",\n\t\"bk:jar_desc\": \"Джем\",\n\t\"bk:star\": \"Звезда\",\n\t\"bk:star_desc\": \"Защита\",\n\t\"bk:car_bomb\": \"Бомбы на Колесах\",\n\t\"bk:car_bomb_desc\": \"Система доставки бомб к врагам\",\n\t\"bk:grenade\": \"Граната\",\n\t\"bk:grenade_desc\": \"Бомбы взрываются при касании\",\n\t\"trash_goblin_0\": \"Спаси меня от моего [cl purple]проклятия[cl]! Пожалуйста!\",\n\t\"trash_goblin_1\": \"Я свободен![dl] Спасибо тебе огромное!\",\n\t\"boxy_0\": \"Балдёж\",\n\t\"boxy_1\": \"Какая упаковка!\",\n\t\"boxy_2\": \"Тебе нужна обёрточная бумага?\",\n\t\"trash_goblin_2\": \"^^Туман над рекой^^\",\n\t\"bk:vampire_bat\": \"Мышь-вампир\",\n\t\"bk:vampire_bat_desc\": \"Реген\",\n\t\"shields\": \"Щиты\",\n\t\"bk:mustache\": \"Усы\",\n\t\"bk:mustache_desc\": \"ВИП\",\n\t\"bk:bloody_chest\": \"Кровавый Сундук\",\n\t\"bk:bloody_chest_desc\": \"Сундуки лечят\",\n\t\"bk:bloody_shield\": \"Кровавый щит\",\n\t\"bk:bloody_shield_desc\": \"Щиты навсегда\",\n\t\"bk:cutsaw\": \"Пила\",\n\t\"bk:cutsaw_desc\": \"Враги заплатят\",\n\t\"vampire_0\": \"Нам!\",\n\t\"vampire_1\": \"Балдёж\",\n\t\"vampire_2\": \"Мммм\",\n\t\"vampire_3\": \"Мы знаем правила, [cl red]^^не так ли[cl]?\",\n\t\"vampire_4\": \"^^Мммммм^^\",\n\t\"vampire_5\": \"Какая у тебя группа крови?\",\n\t\"vampire_6\": \"Вкуснятина\",\n\t\"duck_2\": \"Ответишь на пару вопросов?\",\n\t\"duck_7_0\": \"Давай\",\n\t\"duck_7_1\": \"Не\",\n\t\"duck_7\": \"Ты получишь этот сундук?\",\n\t\"duck_4\": \"Красавчик, держи сундук!\",\n\t\"duck_5\": \"Не могу согласиться...\",\n\t\"duck_6_0\": \"Вселенная\",\n\t\"duck_6_1\": \"^^Кваки^^\",\n\t\"duck_6\": \"О чём я думаю?\",\n\t\"duck_8_0\": \"[cl red]Красный[cl]\",\n\t\"duck_8_1\": \"[cl blue]Синий[cl]\",\n\t\"duck_8\": \"Какой мой любимый ^^%%цвет%%^^?\",\n\t\"duck_9_0\": \"Кошка\",\n\t\"duck_9_1\": \"Ты\",\n\t\"duck_9\": \"Кто сказал \\\"мяу\\\"?\",\n\t\"duck_10_0\": \"0\",\n\t\"duck_10_1\": \"1\",\n\t\"duck_10\": \"Что лучше?\",\n\t\"duck_11_0\": \"Да что, ты, яйцо?\",\n\t\"duck_11_1\": \"\\\\[_Он ударил его._]\",\n\t\"duck_11\": \"Ты соус\",\n\t\"duck_12_0\": \"Курица\",\n\t\"duck_12_1\": \"Яйцо\",\n\t\"duck_12\": \"Что было первым?\",\n\t\"duck_13_0\": \"Ничего.\",\n\t\"duck_13_1\": \"Снек.\",\n\t\"duck_13_2\": \"Яйцо.\",\n\t\"duck_13_3\": \"Жаренная курица.\",\n\t\"duck_13\": \"Что я ел сегодня?\",\n\t\"duck_14\": \"Ой.\",\n\t\"duck_17_0\": \"Конечно\",\n\t\"duck_17_1\": \"##НАНИ##\",\n\t\"duck_17\": \"Как насчёт ананасов на твоей пицце?\",\n\t\"duck_18_0\": \"Белого!\",\n\t\"duck_18_1\": \"[cl yellow]Желтого[cl]!\",\n\t\"duck_18\": \"Какого цвета сыр?\",\n\t\"nurse_0\": \"Ты выглядишь прекрасно, дорогой!\",\n\t\"nurse_1\": \"Я могу тебя подлечить, но мне нужно [cl yellow][vr price] монет[cl]\",\n\t\"nurse_2\": \"Надеюсь, это было не больно\",\n\t\"elon_4\": \"Держи, удачи\",\n\t\"elon_2_0\": \"Поехали\",\n\t\"elon_2_1\": \"Погодь\",\n\t\"elon_2\": \"Хочешь испытать мою магию?\",\n\t\"elon_3\": \"Я могу трансмутировать твое оружие\",\n\t\"elon_5\": \"Ну ладно\",\n\t\"elon_7\": \"Бро, где твое оружие???\",\n\t\"gobetta_0\": \"<3\",\n\t\"gobetta_1\": \":3\",\n\t\"gobetta_2\": \"=)\",\n\t\"gobetta_3\": \"*blush*\",\n\t\"gobetta_4\": \"Это... ты?\",\n\t\"gobetta_5\": \"Столько лет прошло...\",\n\t\"ach_bk:desert\": \"Сухо да Жарко\",\n\t\"ach_bk:desert_desc\": \"Дойди до Пустынного замка\",\n\t\"ach_bk:jungle\": \"Жужжащие пчёлки\",\n\t\"ach_bk:jungle_desc\": \"Доберись до Древних джунгей\",\n\t\"rooms_explored\": \"Комнат исследовано\",\n\t\"bk:shadow_cloak_desc\": \"No U\",\n\t\"bk:shadow_cloak\": \"Мантия-неведимка\",\n\t\"bk:dynamite_stick\": \"Гильза динамита\",\n\t\"bk:dynamite_stick_desc\": \"Хочешь бомбануть?\",\n\t\"bk:chalice_of_blood\": \"Кубок с кровью\",\n\t\"bk:chalice_of_blood_desc\": \"Боль вызывает злость, злость повышает урон\",\n\t\"bk:detonator\": \"Детонатор\",\n\t\"bk:detonator_desc\": \"Активирует взрывы\",\n\t\"invincibility_time\": \"Время неуязвимости\",\n\t\"accuracy\": \"Точность\",\n\t\"range\": \"Дальность\",\n\t\"fire_rate\": \"Скорость атаки\",\n\t\"speed\": \"Скорость\",\n\t\"bk:talisman_of_foresight\": \"Талисман Предвидения\",\n\t\"bk:talisman_of_foresight_desc\": \"Открой глаза и увидь соседние комнаты!\",\n\t\"bk:scourge_ring\": \"Проклятое кольцо\",\n\t\"bk:scourge_ring_desc\": \"Иммунитет к проклятиям\",\n\t\"snek_0\": \"Найс.\",\n\t\"snek_1\": \"Шшшшпасибо\",\n\t\"snek_2\": \"Класшшш\",\n\t\"snek_3\": \"Привет\",\n\t\"snek_4\": \"Доброго времени шшуток\",\n\t\"snek_5\": \"Купи шшшто-нибудь?\",\n\t\"snek_6\": \"Мне нужно удоволетворить покупателя...\",\n\t\"snek_7\": \"Я шшшшделаю то, шшшто я должен!\",\n\t\"bk:snek\": \"Смей\",\n\t\"bk:snek_desc\": \"Снэк?\",\n\t\"boxy_3\": \"^^:wave:^^\",\n\t\"boxy_4\": \"Найдется лишний ключ?\",\n\t\"boxy_5\": \"Дай пару ключей?\",\n\t\"bk:blank\": \"Пустышка\",\n\t\"bk:blank_desc\": \"_Пустой текст_\",\n\t\"bk:blank_bombs\": \"Пустые бомбы\",\n\t\"bk:blank_bombs_desc\": \"_Пустота_\",\n\t\"bk:explosive_bullets\": \"Бомбические пули\",\n\t\"bk:explosive_bullets_desc\": \"Взрываются\",\n\t\"bk:random_bullets\": \"Случайные пули\",\n\t\"bk:random_bullets_desc\": \"Заруинет ваш забег (или спасет)\",\n\t\"bk:cup\": \"Чашка\",\n\t\"bk:cup_desc\": \"Бабуля не сможет не прийти\",\n\t\"bk:cartridge\": \"Картридж\",\n\t\"bk:cartridge_desc\": \"Темный Маг обещал зайти поиграть\",\n\t\"bk:marriage_ring\": \"Обручальное кольцо\",\n\t\"bk:marriage_ring_desc\": \"Темный Маг & Бабуля навсегда!\",\n\t\"boxy_7\": \"Я хочу ключей\",\n\t\"boxy_8\": \"У тебя не достаточно ключей :(\",\n\t\"boxy_9\": \"Теперь у меня хватает ключей чтобы ^^открыться^^!\",\n\t\"roger_3\": \"Я не против если ты заплатишь\",\n\t\"roger_4\": \"Сегодня нет скидок\",\n\t\"roger_5\": \"Бомбы вперед\",\n\t\"vampire_7\": \"Ты нездоров\",\n\t\"vampire_8\": \"Я не даю скидок\",\n\t\"vampire_9\": \"Кажется, уровень твоего здоровья оставляет желать лучшего.\",\n\t\"ach_bk:scourged\": \"Проклятый\",\n\t\"ach_bk:scourged_desc\": \"Получи токен проклятия\",\n\t\"ach_bk:scourged_weapon\": \"Проклятое оружие\",\n\t\"ach_bk:scourged_weapon_desc\": \"Получи проклятое оружие\",\n\t\"rerolled\": \"Зарероленно\",\n\t\"ach_bk:open_up\": \"Открывашка\",\n\t\"ach_bk:open_up_desc\": \"Купи всё в магазине Бокси\",\n\t\"ach_bk:snek\": \"Змея в сапоге\",\n\t\"ach_bk:snek_desc\": \"Заполучи торговца змея в качестве питомца\",\n\t\"bk:scourge_of_greed\": \"Проклятие жадности\",\n\t\"bk:scourge_of_greed_desc\": \"Высокие цены\",\n\t\"killed_by\": \"Убийца\",\n\t\"kills\": \"Убито существ\",\n\t\"time\": \"Время\",\n\t\"depth\": \"Уровень\",\n\t\"bk:blank_bullets\": \"Пустые пули\",\n\t\"bk:blank_bullets_desc\": \"Пусто\",\n\t\"bk:lego\": \"Конструктор\",\n\t\"bk:lego_desc\": \"На него так больно наступать...\",\n\t\"bk:iron_armor\": \"Стальная броня\",\n\t\"bk:iron_armor_desc\": \"Даёт щиты\",\n\t\"bk:round_shield\": \"Круглый щит\",\n\t\"bk:round_shield_desc\": \"Иммунитет к контактному урону\",\n\t\"bk:arkhalis\": \"Аркалис\",\n\t\"bk:arkhalis_desc\": \"Легендарный меч\",\n\t\"bk:inverted_arkhalis\": \"Анти-Аркалис\",\n\t\"bk:inverted_arkhalis_desc\": \"Подмога при 1 _HP_\",\n\t\"bk:gun_sword\": \"Пушкамеч\",\n\t\"bk:gun_sword_desc\": \"Мутант\",\n\t\"ach_bk:scourge_king_desc\": \"Живи теперь с этим\",\n\t\"ach_bk:scourge_king\": \"Проклятый Король\",\n\t\"ach_bk:sting_operation\": \"Жальная операция\",\n\t\"ach_bk:sting_operation_desc\": \"Победи Королеву Пчелу\",\n\t\"ach_bk:mummified\": \"Мумифицирован\",\n\t\"ach_bk:mummified_desc\": \"Победи Фараона\",\n\t\"ach_bk:democracy\": \"Демократия\",\n\t\"ach_bk:democracy_desc\": \"Победи Короля\",\n\t\"pharaoh_scream\": \"##ПРИГОТОВЬСЯ СТАТЬ МУМИЕЙ!##\",\n\t\"queen_bee_scream\": \"##ЗА [cl yellow]HONEY LORD'A[cl]!##\",\n\t\"bk:half_heart\": \"Пол сердца\",\n\t\"right\": \"Вправо\",\n\t\"down\": \"Вниз\",\n\t\"left\": \"Влево\",\n\t\"up\": \"Вверх\",\n\t\"painting_cat\": \"Кот\",\n\t\"bk:axe\": \"Топор\",\n\t\"bk:axe_desc\": \"Он улетел, но обещал вернуться\",\n\t\"bk:guitar\": \"Гитара\",\n\t\"bk:guitar_desc\": \"Сильно расстроена.\",\n\t\"bk:glass_sword\": \"Стеклянный Меч\",\n\t\"bk:glass_sword_desc\": \"Оружие мастеров\",\n\t\"bk:chicken\": \"Крылышко\",\n\t\"bk:chicken_desc\": \"Ай, пальчики обжёг\",\n\t\"bk:pickaxe\": \"Кирка\",\n\t\"bk:pickaxe_desc\": \"Копай давай\",\n\t\"bk:mana\": \"Мана\",\n\t\"bk:half_mana\": \"Пол-очка Маны\",\n\t\"bk:lava_wand\": \"Посох лавы\",\n\t\"bk:lava_wand_desc\": \"Горячий\",\n\t\"bk:web_wand\": \"Паучий посох\",\n\t\"bk:web_wand_desc\": \"Провайдер web-сервисов\",\n\t\"bk:slap_stick\": \"Палка-шлепалка\",\n\t\"bk:slap_stick_desc\": \"Шлёп\",\n\t\"sensivity\": \"Чувствительность\",\n\t\"no\": \"Нет\",\n\t\"scale\": \"Приближение\",\n\t\"ach_bk:ice\": \"Ледниковый период\",\n\t\"ach_bk:ice_desc\": \"Доберись до Ледяных развалин\",\n\t\"ach_bk:library\": \"Пропавшие тексты\",\n\t\"ach_bk:library_desc\": \"Доберись до Секретной бибилотеки\",\n\t\"bk:ice_skates\": \"Коньки\",\n\t\"bk:ice_skates_desc\": \"Иммунитет ко льду\",\n\t\"bk:campfire_in_bottle\": \"Костёр в бутылке\",\n\t\"bk:campfire_in_bottle_desc\": \"Иммунитет к заморозке\",\n\t\"library\": \"Секретная библиотека\",\n\t\"ach_bk:cat_without_a_hat\": \"Кот без шляпы\",\n\t\"ach_bk:cat_without_a_hat_desc\": \"Найди картину с Котом\",\n\t\"ach_bk:rich\": \"Туалетная бумага\",\n\t\"ach_bk:rich_desc\": \"Собери 99 монет\",\n\t\"ach_bk:rescue_operation\": \"Спасательная операция\",\n\t\"ach_bk:rescue_operation_desc\": \"Спаси NPC\",\n\t\"ach_bk:tutorial\": \"Гуру\",\n\t\"ach_bk:tutorial_desc\": \"Закончи туториал\",\n\t\"ach_bk:fancy_hat\": \"Клевая шляпа\",\n\t\"ach_bk:fancy_hat_desc\": \"Купи шляпу\",\n\t\"ach_bk:unlock\": \"Открыватель\",\n\t\"ach_bk:unlock_desc\": \"Разблокируй предмет\",\n\t\"floor_brightness\": \"Яркость пола\",\n\t\"ach_bk:shielded\": \"Поднять щиты\",\n\t\"ach_bk:shielded_desc\": \"Заполучи сердце-щит\",\n\t\"run_type\": \"Тип забега\",\n\t\"run_regular\": \"Обычный\",\n\t\"run_challenge\": \"Испытание\",\n\t\"damage_taken\": \"Урон получен\",\n\t\"km\": \"км\",\n\t\"distance_traveled\": \"Дистанция\",\n\t\"seed\": \"Сид\",\n\t\"score\": \"Счет\",\n\t\"new_high_score\": \"Новый рекорд!\",\n\t\"items_collected\": \"Вещей собрано\",\n\t\"boss_rush\": \"Босс-раш\",\n\t\"run_bossrush\": \"Босс-раш\",\n\t\"bk:blindfold\": \"Повязка\",\n\t\"daily_run\": \"Дейлик\",\n\t\"builder_0_0\": \"Да\",\n\t\"builder_0_1\": \"Мне самому нужны деньги\",\n\t\"builder_0\": \"Я планирую построить туннель сюды, но мне нужно еще [vr need] [ic 0]. Можешь помочь?\",\n\t\"builder_1\": \"Но у тебя вообще нет денег!\",\n\t\"builder_2\": \"Спасибо за инвестицию!\",\n\t\"builder_3\": \"У меня наконец достаточно денег для окончания этого проекта! Спасибо огромное!\",\n\t\"builder_4\": \"Ок, прости!\",\n\t\"shortcut_is_broken\": \"Туннель сломан\",\n\t\"ach_bk:boss_rush\": \"Покоритель боссов\",\n\t\"ach_bk:boss_rush_desc\": \"Победи всех боссов в Босс-раше\",\n\t\"ach_bk:daily\": \"Дневная слава\",\n\t\"ach_bk:daily_desc\": \"Выйграй дейлик\",\n\t\"ach_bk:desert_shortcut\": \"Пустынный туннель\",\n\t\"ach_bk:desert_shortcut_desc\": \"Почини туннель, ведущий в Пустынный дворец\",\n\t\"ach_bk:jungle_shortcut\": \"Туннель в джунгли\",\n\t\"ach_bk:jungle_shortcut_desc\": \"Почини туннель, ведущий в Древние джунгли\",\n\t\"ach_bk:ice_shortcut\": \"Ледяной туннель\",\n\t\"ach_bk:ice_shortcut_desc\": \"Почини туннель, ведущий в Ледяные развалины\",\n\t\"ach_bk:library_shortcut\": \"Туннель в библиотеку\",\n\t\"ach_bk:library_shortcut_desc\": \"Почини туннель, ведущий в Секретную библиотеку\",\n\t\"ach_bk:fashion_matters2\": \"Мода важна\",\n\t\"ach_bk:fashion_matters2_desc\": \"Купи все шапки\",\n\t\"ach_bk:10_challenges\": \"Упорный\",\n\t\"ach_bk:10_challenges_desc\": \"Выполни 10 вызовов\",\n\t\"ach_bk:20_challenges\": \"Упорный 2.0\",\n\t\"ach_bk:20_challenges_desc\": \"Выполни 20 вызовов\",\n\t\"ach_bk:30_challenges\": \"Упорный 3.0\",\n\t\"ach_bk:30_challenges_desc\": \"Выполни 30 вызовов\",\n\t\"ach_bk:bk_no_more\": \"Конец Горящему рыцарю\",\n\t\"ach_bk:bk_no_more_desc\": \"Победи самого Горящего рыцаря\",\n\t\"ach_bk:dm_no_more\": \"Конец Тёмному магу\",\n\t\"ach_bk:dm_no_more_desc\": \"Победи Тёмного мага\",\n\t\"ach_bk:egor_no_more\": \"Конец Егору\",\n\t\"ach_bk:egor_no_more_desc\": \"(ツ)\",\n\t\"ach_bk:loop\": \"Давай по новой...\",\n\t\"ach_bk:loop_desc\": \"Войди в петлю\",\n\t\"coins_collected\": \"Монет собрано\",\n\t\"bk:cup_head\": \"Чашкаголова\",\n\t\"bk:cup_head_desc\": \"Выпей чаю\",\n\t\"bk:mustache_hat\": \"Усы\",\n\t\"bk:mustache_hat_desc\": \"AFK\",\n\t\"bk:propeller_hat\": \"Шапка с моторчиком\",\n\t\"bk:propeller_hat_desc\": \"Он крутится\",\n\t\"bk:sunglasses\": \"Солнечные очки\",\n\t\"bk:sunglasses_desc\": \"Также работают с Луной!\",\n\t\"bk:cap\": \"Кепка\",\n\t\"bk:cap_desc\": \"Крутой @-@\",\n\t\"bk:eyes\": \"Глаза\",\n\t\"bk:eyes_desc\": \"@ @\",\n\t\"bk:eye\": \"Глаз\",\n\t\"bk:eye_desc\": \"@\",\n\t\"bk:hair\": \"Волосы\",\n\t\"bk:hair_desc\": \"Ну наконец\",\n\t\"won\": \"Победа\",\n\t\"won_message\": \"Ты победил!\",\n\t\"garderobe_sign\": \"Гардероб\",\n\t\"darkmarket_tip\": \"~~[cl purple]Проклятие[cl] или [cl yellow]30 монет[cl]@@\",\n\t\"mike_0\": \"Заплати мне [cl green]3 изумруда\",\n\t\"mike_1\": \"Попробуй Босс-раш всего за [cl green]3 изумруда[cl]!\",\n\t\"bk:weird_potion\": \"Стрёмное-зелье\",\n\t\"bk:weird_potion_desc\": \"Странные пули\",\n\t\"bk:megaphone\": \"Мегафон\",\n\t\"bk:megaphone_desc\": \"Увелечение пуль\",\n\t\"scourge\": \"Проклятия\",\n\t\"scourge_stats\": \"Проклятия\",\n\t\"run_daily\": \"Дейлик\",\n\t\"completed_on\": \"Достигнуто\",\n\t\"complete\": \"достигнуто\",\n\t\"next_daily_in\": \"[cl gray]Следующий начинается через[cl]\",\n\t\"hours\": \"часов\",\n\t\"minutes\": \"минут\",\n\t\"seconds\": \"секунд\",\n\t\"ach_bk:star\": \"Звезда Шоу\",\n\t\"ach_bk:star_desc\": \"Собери 3 орбитала\",\n\t\"ach_bk:family\": \"Счастливая семья\",\n\t\"ach_bk:family_desc\": \"Собери 3 питомца\",\n\t\"ach_bk:return_to_sender\": \"No U\",\n\t\"ach_bk:return_to_sender_desc\": \"Убей врага его же пулей\",\n\t\"ach_bk:van_no_gogh\": \"Ван Не Гог\",\n\t\"ach_bk:van_no_gogh_desc\": \"Сломай 100 картин\",\n\t\"ach_bk:boom\": \"Цепная реакция\",\n\t\"ach_bk:boom_desc\": \"Взорви цепь из 3 динамитов\",\n\t\"ach_bk:dark_market\": \"Криминальная нычка\",\n\t\"ach_bk:dark_market_desc\": \"Спустись в Тёмный рынок\",\n\t\"ach_bk:spikes\": \"Шипами Замок не испортишь\",\n\t\"ach_bk:spikes_desc\": \"Активируй 100 шипов за 1 забег\",\n\t\"ach_bk:white_flag\": \"Пацифист\",\n\t\"ach_bk:white_flag_desc\": \"Зачисти комнату не используя оружия\",\n\t\"quack\": \"[cl yellow]Кряк![cl]\",\n\t\"pixel_perfect\": \"Pixel Perfect\",\n\t\"bk_11\": \"Я ПРОЩАЮ ТЕБЯ. НО ##НЕ ДЕЛАЙ## ЭТО ОПЯТЬ!\",\n\t\"leaderboard\": \"Таблица рекордов\",\n\t\"display\": \"Фильтр\",\n\t\"around_you\": \"Вокруг Тебя\",\n\t\"friends\": \"Друзья\",\n\t\"global\": \"Все\",\n\t\"loading\": \"Загружаем\",\n\t\"generating\": \"Генерируем\",\n\t\"cursor_radius\": \"Радиус Курсора\",\n\t\"no_scores_yet\": \"Еще нет счетов\",\n\t\"no_score_yet\": \"Еще нет счета\",\n\t\"run\": \"Забег\",\n\t\"top\": \"Топ\",\n\t\"quick_restart\": \"Быстрый рестарт\",\n\t\"painting_dungeon\": \"Замок\",\n\t\"painting_goose\": \"Мини-гусь\",\n\t\"painting_chess\": \"Летучий слон\",\n\t\"painting_peach\": \"Персиковое дерево\",\n\t\"bk:no_lamp\": \"Нет лампы\",\n\t\"bk:explosive_lamp\": \"Взрывная лампа\",\n\t\"bk:explosive_lamp_desc\": \"Когда ты слишком любишь все взрывать\",\n\t\"bk:shielded_lamp\": \"Щитовая лампа\",\n\t\"bk:shielded_lamp_desc\": \"Поднять щиты!\",\n\t\"lamp\": \"Лампа\",\n\t\"bk:brain\": \"Мегамозг\",\n\t\"bk:brain_desc\": \"Что если использовать разум на 100%\",\n\t\"bk:heart_amulet\": \"Сердечный амулет\",\n\t\"bk:heart_amulet_desc\": \"+1 к размеру сердца\",\n\t\"bk:star_amulet_desc\": \"+1 к Мане\",\n\t\"bk:star_amulet\": \"Звёздный амулет\",\n\t\"bk:coin_amulet\": \"Денежный амулет\",\n\t\"bk:coin_amulet_desc\": \"Ценность монет выше\",\n\t\"bk:key_amulet\": \"Амулет ключей\",\n\t\"bk:key_amulet_desc\": \"Ключей дается больше\",\n\t\"bk:bomb_amulet\": \"Бомбический амулет\",\n\t\"bk:bomb_amulet_desc\": \"Бомб даётся больше\",\n\t\"bk:eye_amulet\": \"Глазной амулет\",\n\t\"bk:eye_amulet_desc\": \"Как же больно быть неточным\",\n\t\"bk:eye_patch\": \"Повязка на глаз\",\n\t\"bk:eye_patch_desc\": \"Так точно капитан!\",\n\t\"bk:toilet_paper\": \"Туалетная бумага\",\n\t\"bk:toilet_paper_desc\": \"Всегда заканчиватся\",\n\t\"bk:decoy\": \"Приманка\",\n\t\"bk:decoy_desc\": \"Она взрывается\",\n\t\"bk:wallet\": \"Кошелёчек\",\n\t\"bk:wallet_desc\": \"Хранит деньги\",\n\t\"bk:skele_buddy\": \"Хранитель замка\",\n\t\"bk:skele_buddy_desc\": \"Стрёмный\",\n\t\"bk:mega_bomb\": \"Мегабомба\",\n\t\"bk:mega_bomb_desc\": \"Мега бом-бом!\",\n\t\"bk:condensed_milk\": \"Сгущёнка\",\n\t\"bk:condensed_milk_desc\": \"Шустрые пиксели — медленные противники\",\n\t\"bk:marshmallow\": \"Маршмеллоу X_X\",\n\t\"bk:marshmallow_desc\": \"Липкая штука\",\n\t\"bk:orbital_multiplier\": \"Множитель орбиталов\",\n\t\"bk:orbital_multiplier_desc\": \"Больше орбиталов богу орбиталов!\",\n\t\"bk:pet_multiplier\": \"Множитель питомцев\",\n\t\"bk:pet_multiplier_desc\": \"Больше питомцев!\",\n\t\"bk:ghost_bullets\": \"Пули-привидения\",\n\t\"bk:ghost_bullets_desc\": \"Стены не помеха\",\n\t\"bk:weight\": \"Гиря\",\n\t\"bk:weight_desc\": \"Усиливает гравитацию\",\n\t\"bk:d2\": \"Д2\",\n\t\"bk:d2_desc\": \"Возьми или оставь\",\n\t\"bk:ethernal_d6\": \"Небесный Д6\",\n\t\"bk:ethernal_d6_desc\": \"Рероллит и\\/или уничтожает\",\n\t\"bk:billiard\": \"Бильярдный шар\",\n\t\"bk:billiard_desc\": \"Пули отскакивают от пуль\",\n\t\"bk:enraged_bullets\": \"Разозленные пули\",\n\t\"bk:enraged_bullets_desc\": \"Пули ломают пули\",\n\t\"bk:rewind_button\": \"Кнопка Перемотки\",\n\t\"bk:rewind_button_desc\": \"Исправь своё будещее\",\n\t\"bk:piggy_bank\": \"Свинка-копилка\",\n\t\"bk:piggy_bank_desc\": \"Мои сбережения\",\n\t\"coins\": \"Монеты\",\n\t\"bk:death_star\": \"Звезда смерти\",\n\t\"bk:death_star_desc\": \"RIP Альдеран\",\n\t\"bk:soldering_iron\": \"Паяльник\",\n\t\"bk:soldering_iron_desc\": \"Горячий\",\n\t\"bk:can\": \"Банка\",\n\t\"bk:can_desc\": \"Удвоенные пули\",\n\t\"bk:swimming_mask\": \"Плавательная маска\",\n\t\"bk:swimming_mask_desc\": \"Секретное оружие\",\n\t\"bk:bullet_chair\": \"Реактивный стул\",\n\t\"bk:bullet_chair_desc\": \"4 ноги 4 пухи\",\n\t\"bk:cell\": \"Клетка\",\n\t\"bk:cell_desc\": \"Пули рождаются\",\n\t\"bk:brick\": \"iКирпич\",\n\t\"bk:brick_desc\": \"Оверпрайснутые уровни\",\n\t\"bk:ring_of_pain\": \"Кольцо Боли\",\n\t\"bk:ring_of_pain_desc\": \"Получение урона бьет всех\",\n\t\"bk:schrodingers_cat\": \"Кот Шредингера\",\n\t\"bk:schrodingers_cat_desc\": \"Бить или не быть (50% шанс)\",\n\t\"bk:smoke_bomb\": \"Дымовуха\",\n\t\"bk:smoke_bomb_desc\": \"Побег в стиле ниндзя\",\n\t\"bk:chest_ring\": \"Кольцо сундуков\",\n\t\"bk:chest_ring_desc\": \"Больше сундуков!\",\n\t\"bk:empty_shell\": \"Пустая гильза\",\n\t\"bk:empty_shell_desc\": \"Шанс уничтожить пули противников\",\n\t\"bk:parachute\": \"Парашют\",\n\t\"bk:parachute_desc\": \"Иммунитет к дыркам\",\n\t\"bk:spiked_cookie\": \"Шипастая печенька\",\n\t\"bk:spiked_cookie_desc\": \"Я бы её не съел\",\n\t\"bk:shooty\": \"Стреляка\",\n\t\"bk:shooty_desc\": \"Он стреляет\",\n\t\"bk:rabbit_bullets\": \"Кроличьи пули\",\n\t\"bk:rabbit_bullets_desc\": \"Они размножаются\",\n\t\"bk:pandoras_box\": \"Коробка Пандоры\",\n\t\"bk:pandoras_box_desc\": \"Ты должен был бороться со злом!\",\n\t\"bk:bubbles\": \"Мыльные пузыри\",\n\t\"bk:bubbles_desc\": \"Друг\",\n\t\"bk:match\": \"Спичка\",\n\t\"bk:match_desc\": \"Огонь для всех\",\n\t\"bk:hammer\": \"Молот\",\n\t\"bk:hammer_desc\": \"Я твою броню ломал\",\n\t\"bk:helmet\": \"Стальной шлем\",\n\t\"bk:helmet_desc\": \"Шанс не получить урон\",\n\t\"bk:beer\": \"Пивко\",\n\t\"bk:beer_desc\": \"Урон вызывает злость\",\n\t\"bk:the_eye\": \"Глазик\",\n\t\"bk:the_eye_desc\": \"Он смотрит\",\n\t\"bk:mimics_tooth\": \"Зуб Мимика\",\n\t\"bk:mimics_tooth_desc\": \"Притягивает Мимиков\",\n\t\"ach_bk:mimic\": \"Рояль в кустах\",\n\t\"ach_bk:mimic_desc\": \"Найди мимика\",\n\t\"bk:paper_airplane\": \"Бумажный самолётик\",\n\t\"bk:paper_airplane_desc\": \"Самонаводящиеся пули\",\n\t\"ach_bk:ice_boss\": \"Отпусти её, да забудь\",\n\t\"ach_bk:ice_boss_desc\": \"Убей Снежную королеву\",\n\t\"ice_queen_scream\": \"^^[cl cyan]Кхе-кхе\",\n\t\"painting_agency\": \"Добро пожаловать в агенство\",\n\t\"painting_horatio\": \"Гораций\",\n\t\"painting_zweihandler\": \"Звейгандлер\",\n\t\"language\": \"Язык\",\n\t\"bk:pouch\": \"Мешочек\",\n\t\"bk:alien_glasses\": \"Инопланетные очки\",\n\t\"bk:alien_glasses_desc\": \"Я вижу больше\",\n\t\"inventory\": \"Хлам\",\n\t\"bk:led\": \"Светодиод\",\n\t\"bk:led_desc\": \"Точная лампа\",\n\t\"bk:fragile_lamp\": \"Хрупкая лампочка\",\n\t\"bk:fragile_lamp_desc\": \"1 хит K.O.\",\n\t\"painting_guitar\": \"Больше Звука!\",\n\t\"ach_bk:maanex\": \"И ты, Брут?\",\n\t\"ach_bk:maanex_desc\": \"Убей Маанекса с его шляпой на голове\",\n\t\"dad_0\": \"Сын, [dl] я ухожу искать [cl red]Лампу[cl]. Я оставляю тебя править вместо меня.\",\n\t\"dad_1\": \"Если я не вернусь, не ищи меня. Прощай!\",\n\t\"son_0\": \"##НЕЕЕЕТ##\",\n\t\"gobbo_0\": \"Сын, [cl green]мой отец[cl] оставил меня 20 лет назад. Я отправляюсь его искать.\",\n\t\"gobbo_1\": \"Ты остаёшься за главного. Расти большой, не будь лапшой. Прощай!\",\n\t\"dm_5\": \"Новая и ^^улучшенная^^ [cl red]марионетка[cl]![dl] ##АХАХАХА##\",\n\t\"dm_6\": \"Ты слышишь меня, [cl red]Лимпор?\",\n\t\"heinur_0\": \"##НЕТ[dl], ТОЛЬКО НЕ ОПЯТЬ!##\",\n\t\"nbk_0\": \"##ДА, МОЙ ПОВЕЛИТЕЛЬ##\",\n\t\"bk_12\": \"##У МЕНЯ ЗАКОНЧИЛИСЬ СОСУДЫ, ТАК ЧТО ДЕРИСЬ СО МНОЙ, ГЛУПЕЦ!##\",\n\t\"bk:headshot_gun\": \"Погнутый пистоль\",\n\t\"bk:headshot_gun_desc\": \"Headshot\",\n\t\"bk:laser_cannon\": \"Лазерная пуха\",\n\t\"bk:laser_cannon_desc\": \"Не канон\",\n\t\"credits\": \"Кредиты\",\n\t\"head_0\": \"Глупец\",\n\t\"tech\": \"Техно\",\n\t\"ach_bk:collector\": \"Коллектор\",\n\t\"ach_bk:collector_desc\": \"Собери все предметы\",\n\t\"bk:treasure_key\": \"Красный ключ\",\n\t\"bk:treasure_key_desc\": \"Открывает временные дыры\",\n\t\"bk:pass\": \"Пропуск\",\n\t\"bk:pass_desc\": \"Ты кто?\",\n\t\"bk:bucket\": \"Ведро\",\n\t\"bk:bucket_desc\": \"Бесполезно само по себе\",\n\t\"bk:water_bucket\": \"Ведро с водой\",\n\t\"bk:water_bucket_desc\": \"Тушит [cl red]Огонь[cl]\",\n\t\"bk:snow_bucket\": \"Ведро со снегом\",\n\t\"bk:snow_bucket_desc\": \"А снег не растает?\",\n\t\"m2_0\": \"Я обанкротился\",\n\t\"m2_1\": \"Красавчик!\",\n\t\"m2_2\": \"Эй, не хочешь ^^потесить^^ свой %%скилл%%?\",\n\t\"m2_3\": \"Используй ^^%%Компуктор%%^^ чтоб управлять [cl yellow]Клешнёй[cl]!\",\n\t\"maanex2_0_0\": \"Погнали!\",\n\t\"maanex2_0_1\": \"Не в этот раз, спс.\",\n\t\"maanex2_0\": \"Дай мне [cl yellow][vr cost] монет[cl] и я дам тебе одну попытку!\",\n\t\"dm_7\": \"Давай поиграем\",\n\t\"bkw_0\": \"ЕЩЕ ОДИН [cl red]ШПИОН[cl]!\",\n\t\"bkw_1\": \"##МАРШ ОТСЮДА##[dl], ИЛИ Я ТЕБЯ ЗАСТАВЛЮ!\",\n\t\"bkw_2\": \"Но я ищу [cl green]своего отца[cl]...\",\n\t\"bkw_3\": \"Я ТЕБЯ _ПРЕДУПРЕДИЛ_\",\n\t\"spanish_inquisition\": \"[cl red]Испанская инквизиция\",\n\t\"lp_0\": \"Молодец, [cl purple]Рита[cl][dl], перезапускаю [cl green]симуляцию[cl][dl].[dl].[dl].\",\n\t\"bk:broken_bucket\": \"Сломанное ведро\",\n\t\"bk:broken_bucket_desc\": \"Бульк\",\n\t\"bk:ankh\": \"Анкх\",\n\t\"bk:ankh_desc\": \"Жизнь Свыше\",\n\t\"bk:broken_ankh\": \"Сломанный Анкх\",\n\t\"bk:broken_ankh_desc\": \"Жизнь Свыше?\",\n\t\"bk:what\": \"Что\",\n\t\"bk:what_desc\": \"Серьезно, ЧТО?\",\n\t\"bk:gold_minigun\": \"Золотой миниган\",\n\t\"bk:gold_minigun_desc\": \"Хаха, прощай бюджет\",\n\t\"bk:gold_dagger\": \"Золотой кинжал\",\n\t\"bk:gold_dagger_desc\": \"Мал да удал\",\n\t\"bk:gold_revolver\": \"Золотой Револьвер\",\n\t\"bk:gold_revolver_desc\": \"Покрой меня золотом\",\n\t\"bk:gold_axe\": \"Золотой топор\",\n\t\"bk:gold_axe_desc\": \"Вот ответ на все вопросы\",\n\t\"painting_code\": \"Код\",\n\t\"bk:katana\": \"Катана\",\n\t\"bk:katana_desc\": \"Кто же [cl orange]хозяин[cl]?\",\n\t\"bk:smart_gun\": \"Умный пистолет\",\n\t\"bk:smart_gun_desc\": \"Он знает\",\n\t\"bk:pop_gun\": \"Хлопушка\",\n\t\"bk:pop_gun_desc\": \"Очень популярная\",\n\t\"bk:the_button\": \"Кнопка\",\n\t\"bk:the_button_desc\": \"Бласт-волна\",\n\t\"bk:gold_sword\": \"Золотой меч\",\n\t\"bk:gold_sword_desc\": \"Когда денег столько, что девать их некуда\",\n\t\"bk:donut\": \"Пончик\",\n\t\"bk:donut_desc\": \"Не сопротивляйся\",\n\t\"bk:sudoku\": \"Судоку\",\n\t\"bk:sudoku_desc\": \"Сносит половину комнаты\",\n\t\"bk:gps_ring\": \"GPS Кольцо\",\n\t\"bk:gps_ring_desc\": \"Шанс полностью открыть карту\",\n\t\"bk:shield_potion\": \"Щитовое зелье\",\n\t\"bk:shield_potion_desc\": \"Дает... щиты!\",\n\t\"bk:trash_generator\": \"Генератор мусора\",\n\t\"bk:trash_generator_desc\": \"Угу.\",\n\t\"bk:crabs_claw\": \"Клешня краба\",\n\t\"bk:crabs_claw_desc\": \"Ломает любую броню\",\n\t\"eg_3\": \"Доброго времени суток\",\n\t\"eg_0_0\": \"Взять ^^[cl lime]изумруды[cl]^^\",\n\t\"eg_0_1\": \"Оставить\",\n\t\"eg_0\": \"Прошу тебя, возьми [cl lime]мои изумруды[cl]!\",\n\t\"eg_1\": \"Пожалуй, я пойду, всего хорошего\",\n\t\"bk:reverse_card\": \"Карта смены хода\",\n\t\"bk:reverse_card_desc\": \"Перекат через пули отражает их\",\n\t\"bk:magnet\": \"Магнит\",\n\t\"bk:magnet_desc\": \"Притягивает сомнительные личности\",\n\t\"bk:glowing_mushroom\": \"Шапка трюфеля\",\n\t\"bk:glowing_mushroom_desc\": \"Ему классно\",\n\t\"bk:tinfoil_hat\": \"Шапочка из фольги\",\n\t\"bk:tinfoil_hat_desc\": \"Ощущение безопасности\",\n\t\"bk:rear_window\": \"Зеркало заднего вида\",\n\t\"bk:rear_window_desc\": \"Прикроет спину\",\n\t\"bk:refractor\": \"Отражатель\",\n\t\"bk:refractor_desc\": \"Шанс атаковать во все направления\",\n\t\"bk:fork\": \"Вилка\",\n\t\"bk:fork_desc\": \"Один удар — четыре дырки\",\n\t\"bk:rock\": \"Каменюга\",\n\t\"bk:rock_desc\": \"Урон за плату\",\n\t\"bk:coffee_grinder\": \"Кофемолка\",\n\t\"bk:coffee_grinder_desc\": \"Мелкие и быстрые пульки\",\n\t\"integrations\": \"Интеграции\",\n\t\"twitch\": \"Твитч\",\n\t\"streamer_username\": \"Ник Стримера\",\n\t\"bk:shawarma\": \"Шавуха\",\n\t\"bk:shawarma_desc\": \"Иногда пули больше\",\n\t\"bk:cats_ear\": \"Ухо кота\",\n\t\"bk:cats_ear_desc\": \"Sick dodge\",\n\t\"luck\": \"Удача\",\n\t\"bk:gamepad\": \"Геймпад\",\n\t\"bk:gamepad_desc\": \"Стабильный FPS\",\n\t\"bk:hotdog\": \"Стильный хот-дог\",\n\t\"bk:hotdog_desc\": \"Удача & _HP_\",\n\t\"bk:bomb_shell\": \"Оболочка бомбы\",\n\t\"bk:bomb_shell_desc\": \"Странное здоровье\",\n\t\"painting_no_idea\": \"Без понятия\",\n\t\"painting_tinkerer\": \"Мыслитель\",\n\t\"painting_in_loving_memory_of_ali\": \"В память об Али\",\n\t\"painting_happy_accident\": \"Счастливая случайность\",\n\t\"painting_observing_cheese\": \"Наблюдая сыр\",\n\t\"painting_chicken_enemy_unknown\": \"Куриный враг неизвестен\",\n\t\"painting_know_stuff\": \"Знай\",\n\t\"painting_whoops\": \"Упс\",\n\t\"painting_too_lake\": \"Слишком мокро\",\n\t\"painting_step_through\": \"Переход\",\n\t\"painting_thats_a_moon\": \"Это луна\",\n\t\"painting_totem\": \"Магический круг\",\n\t\"painting_too_late\": \"Слишком поздно\",\n\t\"painting_whipped_cream\": \"Взбитые сливки\",\n\t\"painting_beet_boys\": \"Редиски\",\n\t\"painting_moonshine\": \"Лунный свет\",\n\t\"painting_void\": \"Пустота\",\n\t\"painting_peasants\": \"Работники\",\n\t\"logged_in_as\": \"Залогинен как\",\n\t\"not_logged_in\": \"Не залогинен\",\n\t\"failed_to_login\": \"Попытка залогинится провалилась\",\n\t\"logging_in\": \"Логинимся[dl].[dl].[dl].\",\n\t\"twitch_0\": \"Pog!\",\n\t\"twitch_1_0\": \"Нда\",\n\t\"twitch_1_1\": \"Ннет\",\n\t\"twitch_1\": \"Ты хочешь врубить режим Стримера?\",\n\t\"twitch_2\": \"Скажи мне твой ник на Твитче!\",\n\t\"twitch_3\": \"Добро пожаловать в чат, [cl purple]@[vr username][cl]!\",\n\t\"twitch_4\": \"Окейла.\",\n\t\"twitch_5_0\": \"Угу\",\n\t\"twitch_5_1\": \"Нее\",\n\t\"twitch_5\": \"Твой ник на твитче [cl purple]@[vr username][cl]. Хочешь изменить его?\",\n\t\"run_twitch\": \"Твитч\",\n\t\"happening_bk:hurt\": \"Ауч\",\n\t\"happening_bk:big_hurt\": \"Большой ауч\",\n\t\"happening_bk:omega_hurt\": \"ОМЕГА АУЧ\",\n\t\"happening_bk:confused\": \"Конфуз\",\n\t\"happening_bk:snail\": \"Улитка\",\n\t\"happening_bk:broken\": \"Сломанная бронь\",\n\t\"happening_bk:darkness\": \"Минус свет\",\n\t\"happening_bk:scourge_token\": \"Плохой токен\",\n\t\"happening_bk:risk\": \"Скрытое здоровье\",\n\t\"happening_bk:double_trouble\": \"Двойные проблемы\",\n\t\"happening_bk:rage\": \"Приступ злости\",\n\t\"happening_bk:regular_tp\": \"Телепорт\",\n\t\"happening_bk:reset\": \"Хард-ресет\",\n\t\"happening_bk:sudoku\": \"Судоку\",\n\t\"happening_bk:items_hurt\": \"Предметы бьют\",\n\t\"happening_bk:scourged\": \"Загрязние\",\n\t\"happening_bk:reroll_items\": \"Реролл\",\n\t\"happening_bk:reroll_weapon\": \"Новые оружия\",\n\t\"happening_bk:nerf\": \"Нерф\",\n\t\"happening_bk:rob\": \"Кража\",\n\t\"happening_bk:steal\": \"Минус оружие\",\n\t\"happening_bk:give_artifact\": \"Рандомный артифакт\",\n\t\"happening_bk:give_weapon\": \"Рандомное оружие\",\n\t\"happening_bk:give_random_item\": \"Рандомный предмет\",\n\t\"happening_bk:give_random_consumable\": \"Рандомный пикап\",\n\t\"happening_bk:invincible\": \"Неуязвимость\",\n\t\"happening_bk:treasure_tp\": \"Кладоискатель\",\n\t\"happening_bk:small_heal\": \"Нанохилка\",\n\t\"happening_bk:heal\": \"Хилка\",\n\t\"happening_bk:omega_heal\": \"ОМЕГА ХИЛКА\",\n\t\"happening_bk:shielded\": \"Защита\",\n\t\"happening_bk:cleanse\": \"Очищение\",\n\t\"happening_bk:chest\": \"Сокровище\",\n\t\"happening_bk:buffed\": \"Баффнут\",\n\t\"happening_bk:gift\": \"Подарок\",\n\t\"happening_bk:entrance_tp\": \"Опять 25\",\n\t\"happening_bk:exit_tp\": \"Пора валить\",\n\t\"twitch_next\": \"Что будет дальше?\",\n\t\"total_votes\": \"голоса\",\n\t\"bk:gold_lamp\": \"Золотая лампа\",\n\t\"bk:gold_lamp_desc\": \"Время — деньги, а денег что? Мало.\",\n\t\"bk:sharp_lamp\": \"Острая Лампа\",\n\t\"bk:sharp_lamp_desc\": \"Для любителей Melee\",\n\t\"bk:ancient_sword\": \"Древний Меч\",\n\t\"bk:ancient_sword_desc\": \"Супер старая палка\",\n\t\"ach_bk:unstoppable\": \"Неостановимый\",\n\t\"ach_bk:unstoppable_desc\": \"Пройди игру с любой лампой\",\n\t\"no_emeralds\": \"Нет изумрудов\",\n\t\"bk:emerald_gun\": \"Изумрудный пистоль\",\n\t\"bk:emerald_gun_desc\": \"Самое дорогое оружие в стране\",\n\t\"minimap\": \"Миникарта\",\n\t\"quality\": \"Качество\",\n\t\"normal\": \"Нормальное\",\n\t\"potato\": \"Картошка\",\n\t\"happening_bk:bomb\": \"Взрывная атака\",\n\t\"happening_bk:slide\": \"Ледниковый период\",\n\t\"20_years_later\": \"20 лет спустя\",\n\t\"painting_ducktective\": \"Селезень-сыщик\",\n\t\"boss_oldking\" : \"Старый Король\",\n\t\"boss_pharaoh\" : \"Фараон\",\n\t\"boss_queenbee\" : \"Королева Пчела\",\n\t\"boss_icequeen\" : \"Королева Льда\",\n\t\"boss_burningknight\" : \"Горящий Рыцарь\",\n\t\"boss_dm\" : \"Темный Маг\",\n\t\"painting_bug\" : \"Не баг, а фича!\",\n\t\"revive\" : \"Воскресить\",\n\t\"cave\": \"Изумрудные Пещеры\",\n\t\"coop_sign\": \"Нажми любую кнопку на геймпаде, чтобы присоединиться\",\n\t\"bk:party_hat\": \"Парти Шапка\",\n\t\"bk:party_hat_desc\": \"Почему же мне так грустно\",\n\t\"bk:police_hat\": \"Полишапка\",\n\t\"bk:police_hat_desc\": \"Держис подальше от порталов\",\n\t\"bk:spike_hat\": \"Шипошляп\",\n\t\"bk:spike_hat_desc\": \"Тык\",\n\t\"bk:hood\": \"Плащ\",\n\t\"bk:hood_desc\": \"Найди кольцо\",\n\t\"bk:bullet_hat\": \"Пустая Гильза\",\n\t\"bk:bullet_hat_desc\": \"Пиу\",\n\t\"remove_player\" : \"Зажми [ic 0] чтобы убрать игрока\",\n\t\"bk:spook\": \"Спук\",\n\t\"bk:spook_desc\": \"Бу\",\n\t\"bk:mask\": \"Маска\",\n\t\"bk:mask_desc\": \"Оставайся на 127.0.0.1\",\n\t\"bk:sword_polish\": \"Масло Для Меча\",\n\t\"bk:sword_polish_desc\": \"Большие Мелее Аттаки\",\n\t\"bk:pumpkin_juice\": \"Тыквенный Сок\",\n\t\"bk:pumpkin_juice_desc\": \"Балдеж\",\n\t\"bk:bouncy_glove\": \"Прыгучая Перчатка\",\n\t\"bk:bouncy_glove_desc\": \"Бонкь\",\n\t\"seeded\": \"(сидованный)\"\n}\n"
  },
  {
    "path": "BurningKnight/Content/README.txt",
    "content": "https://bit.ly/2SMSOLM\n"
  },
  {
    "path": "BurningKnight/Content/Shaders/bk.fx",
    "content": "﻿#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat time;\nfloat a;\nfloat2 pos;\nfloat2 size;\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat2 cof = float2(1.0 / size.x, 1.0 / size.y);\n    float x = (pos.x - input.TextureCoordinates.x) * cof.x;\n    float y = (pos.y - input.TextureCoordinates.y) * cof.y;\n    float v = floor(sin(time * 4.0 + y * 8.0));\n\n\tfloat2 ps = float2(\n        clamp(input.TextureCoordinates.x + v / (cof.x * 10.0), pos.x, pos.x + size.x),\n        clamp(input.TextureCoordinates.y + floor(sin(time * 2.0 + x)) / (cof.y * 20.0), pos.y, pos.y + size.y)\n    );\n    \n    float4 color = tex2D(s0, ps);\n    \n    float xx = (ps.x - pos.x) * cof.x;\n    float yy = (ps.y - pos.y) * cof.y;\n\n    float dx = (xx - 0.5);\n    float dy = (yy + 0.5);\n    float d = sqrt(dx * dx + dy * dy);\n\n    float sum = max(0.0, 1.41 - d * 2.0 + cos(time * 1.4));\n\n    color.r = min(1.0, sum + color.r);\n    color.g = min(1.0, sum + color.g);\n    color.b = min(1.0, sum + color.b);\n\n    return float4(1.0, abs(cos(time * 2.0) / 2.5) + color.g, color.b * 0.5, color.a * a);\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/chasm.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\n\n// Flash\nfloat y;\nfloat h;\nbool enabled;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat4 color = tex2D(s0, input.TextureCoordinates);\n\n\tif (enabled) {\n\t    color.rgb = color.rgb * (1 - (input.TextureCoordinates.y - y) / h);\n\t}\n\n\treturn color;\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/entity.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\n\n// Flash\nfloat flash;\nfloat flashReplace;\nfloat4 flashColor;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat4 color = tex2D(s0, input.TextureCoordinates);\n\t\n\tif (flash > 0.01f && color.a > 0.01f) {\n\t\tif (flashReplace > 0.5f) {\n\t\t\tcolor = flashColor * flash;\n\t\t} else {\n\t\t\tcolor += flashColor * flash;\n\t\t}\n\t}\n\n\treturn color;\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/fog.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nTexture2D SpriteTexture;\nsampler s0;\n\nfloat time;\nfloat cx;\nfloat cy;\nfloat tx;\nfloat ty;\n\n#define mod(x,y) (x-y*floor(x/y))\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n  float v = (tex2D(s0, float2(\n    mod(input.TextureCoordinates.x + cx + tx * time, 1.0), \n    mod(input.TextureCoordinates.y + cy + ty * time, 1.0)\n  )).r * cos(time * 100.0 + tex2D(s0, float2(\n    mod(input.TextureCoordinates.x + cx + tx * time, 1.0),\n    mod(input.TextureCoordinates.y + cy + ty * time, 1.0)\n  )).r * 10.0) * 0.5 + 0.5);\n      \n  return float4(v, v, v, v * 0.15f);//v * (1 - smoothstep(0.75f, 0.3f, length(input.TextureCoordinates - float2(0.5f, 0.5f)))));\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/item.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\n\nfloat time;\nfloat size;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat4 color = tex2D(s0, input.TextureCoordinates);\n\t\n\tif ((time + input.TextureCoordinates.x + input.TextureCoordinates.y) % 0.5f < size) {\n\t\tcolor.r = 1;\n\t\tcolor.g = 1;\n\t\tcolor.b = 1;\n\t}\n\n\treturn color;\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/screen.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_5_0\n\t#define PS_SHADERMODEL ps_5_0\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\nfloat blur;\nfloat split;\nbool vignette;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat4 color;\n\t\n\tif (split > 0.001f) {\n\t\tfloat smx = 1.0f / 320 * split;\n\t\tfloat smy = 1.0f / 180 * split;\n        float4 l = tex2D(s0, float2(input.TextureCoordinates.x + smx, input.TextureCoordinates.y + smy));\n        \n        color = float4(l.r, \n            tex2D(s0, float2(input.TextureCoordinates.x, input.TextureCoordinates.y)).g,\n            tex2D(s0, float2(input.TextureCoordinates.x - smx, input.TextureCoordinates.y - smy)).b, l.a);\n\t} else { \n\t\tcolor = tex2D(s0, float2(input.TextureCoordinates.x, input.TextureCoordinates.y));\n\t}\n\t\n\tfloat v = 1.0f;\n\t\n\tif (vignette) {\n\t    v = smoothstep(0.75f, 0.2f, length(input.TextureCoordinates - float2(0.5f, 0.5f))) * 0.75f + 0.25f;\n\t}\n    \n\tif (blur > 0.001f) {\n        float mx = 1.0f / 320 * blur;\n        float my = 1.0f / 180 * blur;\n        \t\n\t\tfor (int xx = -2; xx < 3; xx++) {\n\t\t\tfor (int yy = -2; yy < 3; yy++) {\n\t\t\t\tif (xx != 0 || yy != 0) {\n\t\t\t\t\tcolor += tex2D(s0, input.TextureCoordinates + float2(mx * xx , my * yy)) / sqrt(xx * xx + yy * yy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t  color /= 14.8203f;\n\t}\n\n\treturn color * v;\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/terrain.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_4_0_level_9_1\n\t#define PS_SHADERMODEL ps_4_0_level_9_1\n#endif\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nTexture2D SpriteTexture;\nsampler s0;\n\nbool enabled;\nfloat2 tilePosition;\nfloat2 edgePosition;\nfloat flow;\nfloat time;\nfloat sy;\nfloat h;\n\n#define mod(x,y) (x-y*floor(x/y))\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n\tfloat cy = input.TextureCoordinates.y;\n\t\t\n\tif (flow > 0.1f) {\n\t\tcy -= tilePosition.y;\n\t\tcy -= time * flow - sy;\n\t\tcy -= h * floor(cy / h);\n\t\tcy += tilePosition.y;\n\t}\n\n\tfloat4 color = tex2D(s0, float2(input.TextureCoordinates.x, cy));\n\n\tif (enabled == true) {\n\t\tfloat4 mask = tex2D(s0, float2(\n\t\t\tinput.TextureCoordinates.x - tilePosition.x + edgePosition.x,\n      input.TextureCoordinates.y - tilePosition.y + edgePosition.y\n\t\t));\n\t\t\n\t\tif (mask.r == 1 && mask.g == 0 && mask.b == 0 && mask.a == 1) {\n\t\t\tif (flow > 0.6f) {\n\t\t\t\tcolor.a = 0.5f;\n\t\t\t}\n\t\t\t\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\treturn mask;\n\t}\n\n\treturn color;\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/Shaders/ui.fx",
    "content": "#if OPENGL\n\t#define SV_POSITION POSITION\n\t#define VS_SHADERMODEL vs_3_0\n\t#define PS_SHADERMODEL ps_3_0\n#else\n\t#define VS_SHADERMODEL vs_5_0\n\t#define PS_SHADERMODEL ps_5_0\n#endif\n\nTexture2D SpriteTexture;\nsampler s0;\nfloat black;\nfloat bx;\nfloat by;\nfloat bottom;\n\nsampler2D SpriteTextureSampler = sampler_state {\n\tTexture = <SpriteTexture>;\n};\n\nstruct VertexShaderOutput {\n\tfloat4 Position : SV_POSITION;\n\tfloat4 Color : COLOR0;\n\tfloat2 TextureCoordinates : TEXCOORD0;\n};\n\nfloat4 MainPS(VertexShaderOutput input) : COLOR {\n  if (black < 1.0f) { \n\t\tfloat dx = input.TextureCoordinates.x - bx;\n\t\tfloat dy = (input.TextureCoordinates.y - by) * 0.5625f;\n\t\n\t\tif (sqrt(dx * dx + dy * dy) > black) {\n\t\t\treturn float4(0, 0, 0, 1);\n\t\t}\n\t}\n\n\treturn tex2D(s0, float2(input.TextureCoordinates.x, input.TextureCoordinates.y)) * (bottom > 0.5 ? float4(0.0, 0.0, 0.0, 0.5) : float4(1.0, 1.0, 1.0, 1.0));\n}\n\ntechnique SpriteDrawing {\n\tpass P0 {\n\t\tPixelShader = compile PS_SHADERMODEL MainPS();\n\t}\n};"
  },
  {
    "path": "BurningKnight/Content/achievements.json",
    "content": "{\n\t\"bk:overshake\": {\n\t\t\"secret\": true\n\t},\n\t\"bk:rip\": {},\n\t\"bk:marauder\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:treasure_hunter\": {},\n\t\"bk:dodge_master\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:dodge_overlord\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:quackers\": {\n\t\t\"secret\": true\n\t},\n\t\"bk:not_a_thief\": {\n\t\t\"secret\": true\n\t},\n\t\"bk:npc_party2\": {\n\t\t\"max\": 13,\n\t\t\"group\": \"c\"\n\t},\n\t\"bk:scourge_king\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:deal\": {},\n\t\"bk:grannys_gift\": {},\n\t\"bk:shopper\": {},\n\t\"bk:desert\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:jungle\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:scourged\": {},\n\t\"bk:scourged_weapon\": {},\n\t\"bk:open_up\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:snek\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:sting_operation\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:mummified\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:democracy\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:ice\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:library\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:cat_without_a_hat\": {\n\t\t\"group\": \"c\"\n\t},\n\t\"bk:rich\": {\n\t\t\"group\": \"b\"\n\t},\n\t\"bk:rescue_operation\": {\n\t\t\"group\": \"c\"\n\t},\n\t\"bk:tutorial\": {},\n\t\"bk:fancy_hat\": {},\n\t\"bk:unlock\": {},\n\t\"bk:shielded\": {},\n\t\"bk:boss_rush\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:daily\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:desert_shortcut\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:jungle_shortcut\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:ice_shortcut\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:library_shortcut\": {\n\t\t\"group\": \"a\"\n\t},\n\t\"bk:fashion_matters2\": {\n\t\t\"max\": 29\n\t},\n\t\"bk:ice_boss\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:bk_no_more\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:dm_no_more\": {\n\t\t\"secret\": true\n\t},\n\t\"bk:loop\": {},\n\t\"bk:star\": {\n\t\t\"unlock\": \"bk:star\"\n\t},\n\t\"bk:family\": {},\n\t\"bk:return_to_sender\": {\n\t\t\"group\": \"d\"\n\t},\n\t\"bk:van_no_gogh\": {},\n\t\"bk:dark_market\": {},\n\t\"bk:spikes\": {\n\t\t\"unlock\": \"bk:iron_boots\"\n\t},\n\t\"bk:white_flag\": {},\n\t\"bk:mimic\": {\n\t\t\"unlock\": \"bk:mimic_totem\",\n\t\t\"secret\": true\n\t},\n\t\"bk:maanex\": {\n\t\t\"secret\": true\n\t},\n\t\"bk:collector\": {},\n\t\"bk:unstoppable\": {}\n}"
  },
  {
    "path": "BurningKnight/Content/bin/Shaders/test",
    "content": ""
  },
  {
    "path": "BurningKnight/Content/items.json",
    "content": "{\"bk:sword\":{\"id\":\"bk:sword\",\"time\":0.649999976158142,\"type\":7,\"single\":true,\"pool\":16777248,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":14,\"h\":26,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\",\"knockback\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":3.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":3.5},\"weapon\":0},\"bk:heart\":{\"id\":\"bk:heart\",\"animation\":\"item_heart\",\"time\":0.100000001490116,\"type\":5,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:ModifyHp\",\"amount\":2}],\"renderer\":{}},\"bk:halo\":{\"id\":\"bk:halo\",\"time\":0.100000001490116,\"single\":true,\"pool\":269484226,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"amount\":2,\"give_hp\":false,\"single\":true,\"set\":false,\"bomb\":false},{\"id\":\"bk:ModifyHp\",\"single\":false,\"amount\":2,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:gold_coin\":{\"id\":\"bk:gold_coin\",\"animation\":\"gold_coin\",\"time\":0.100000001490116,\"type\":2,\"chance\":0.0346670001745224,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:GiveGold\",\"amount\":15}],\"renderer\":{}},\"bk:iron_coin\":{\"id\":\"bk:iron_coin\",\"animation\":\"iron_coin\",\"time\":0.100000001490116,\"type\":2,\"chance\":0.100000001490116,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:GiveGold\",\"amount\":5}],\"renderer\":{}},\"bk:copper_coin\":{\"id\":\"bk:copper_coin\",\"animation\":\"copper_coin\",\"time\":0.100000001490116,\"type\":2,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:GiveGold\",\"amount\":1}],\"renderer\":{}},\"bk:platinum_coin\":{\"id\":\"bk:platinum_coin\",\"animation\":\"platinum_coin\",\"time\":0.100000001490116,\"type\":2,\"chance\":0.00999999977648258,\"single\":true,\"auto_pickup\":true,\"pool\":65,\"uses\":[{\"id\":\"bk:GiveGold\",\"amount\":25}],\"renderer\":{}},\"bk:key\":{\"id\":\"bk:key\",\"animation\":\"key\",\"time\":0.100000001490116,\"type\":4,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:GiveKey\",\"amount\":1}],\"renderer\":{}},\"bk:bomb\":{\"id\":\"bk:bomb\",\"time\":0.100000001490116,\"type\":3,\"single\":true,\"auto_pickup\":true,\"pool\":1,\"uses\":[{\"id\":\"bk:GiveBomb\",\"amount\":1}],\"renderer\":{}},\"bk:infinite_bomb\":{\"id\":\"bk:infinite_bomb\",\"time\":1,\"type\":1,\"single\":true,\"pool\":8912966,\"uses\":[{\"id\":\"bk:SpawnBomb\"}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:revolver\":{\"id\":\"bk:revolver\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"pool\":16777248,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"default\",\"range\":10,\"speed\":15,\"damage\":1,\"amount\":1,\"speedm\":15,\"scale\":1,\"scalem\":1,\"rect\":true,\"dsb\":false,\"accuracy\":5,\"single\":false,\"modifiers\":[],\"cursor\":false,\"mana\":0,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":5,\"nx\":9,\"ny\":2.5},\"weapon\":1},\"bk:shotgun\":{\"id\":\"bk:shotgun\",\"time\":1,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"shot\",\"range\":8,\"amount\":5,\"speed\":15,\"speedm\":25,\"scale\":0.5,\"accuracy\":70,\"damage\":1,\"scalem\":1,\"rect\":true,\"modifiers\":[],\"dsb\":false,\"prefab\":\"bk:shotgun\",\"single\":false,\"cursor\":false,\"sfx\":\"item_shotgun_fire\",\"sfxn\":2,\"mana\":0,\"rsfx\":true,\"shells\":true,\"color\":\"\",\"tomb\":false,\"emeralds\":false,\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":6,\"oy\":5,\"nx\":19,\"ny\":2},\"lock\":true,\"uprice\":0,\"weapon\":1},\"bk:idol\":{\"id\":\"bk:idol\",\"time\":0.100000001490116,\"type\":6,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:SpawnItems\",\"items\":[[6,\"bk:coin\"]]},{\"id\":\"bk:SpawnMobs\",\"count\":10}],\"renderer\":{}},\"bk:the_sword\":{\"id\":\"bk:the_sword\",\"time\":0.300000011920929,\"type\":7,\"chance\":0,\"single\":true,\"auto\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":10000,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":5,\"oy\":16,\"stay\":true,\"invert_back\":true,\"nx\":5},\"weapon\":0},\"bk:potatoo\":{\"id\":\"bk:potatoo\",\"time\":0.100000001490116,\"single\":true,\"pool\":301989954,\"uses\":[{\"id\":\"bk:MakeProjectilesSplitOnDeath\"}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:spectacles\":{\"id\":\"bk:spectacles\",\"time\":0.100000001490116,\"single\":true,\"pool\":32838,\"uses\":[{\"id\":\"bk:DiscoverSecretRooms\"}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:cross\":{\"id\":\"bk:cross\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:ModifyStat\"}],\"renderer\":{}},\"bk:slime\":{\"id\":\"bk:slime\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeProjectilesBounce\"}],\"renderer\":{}},\"bk:missile\":{\"id\":\"bk:missile\",\"time\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":268435522,\"uses\":[{\"id\":\"bk:MakeProjectilesHomeIn\",\"speed\":1},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"missile\"},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":-0.300000011920929,\"add_fire_rate\":true,\"ranged_rate\":0,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:rod_of_discord\":{\"id\":\"bk:rod_of_discord\",\"time\":0.100000001490116,\"type\":7,\"single\":true,\"pool\":268443714,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":2,\"cursor\":false,\"damage\":0,\"amount\":1,\"sfx\":\"item_wand_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":false,\"color\":\"white\",\"speed\":20,\"speedm\":20,\"dsb\":false,\"scale\":1,\"scalem\":1,\"rect\":true,\"wait\":false,\"prefab\":\"bk:discord_rod\",\"texture\":\"discord\",\"mdr\":2}],\"renderer\":{\"id\":\"bk:Stick\",\"ox\":3.5,\"oy\":12,\"nx\":3.5,\"ny\":0},\"lock\":true,\"uprice\":5,\"weapon\":2},\"bk:goo\":{\"id\":\"bk:goo\",\"time\":0.100000001490116,\"single\":true,\"pool\":264258,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:goo\"}],\"renderer\":{}},\"bk:jelly\":{\"id\":\"bk:jelly\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:jelly\"}],\"renderer\":{}},\"bk:broken_stone\":{\"id\":\"bk:broken_stone\",\"time\":0.100000001490116,\"single\":true,\"pool\":786498,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:broken_stone\"}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:nano_orb\":{\"id\":\"bk:nano_orb\",\"time\":0.100000001490116,\"single\":true,\"quality\":3,\"pool\":262210,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:nano_orb\"}],\"renderer\":{}},\"bk:saturn\":{\"id\":\"bk:saturn\",\"time\":0.100000001490116,\"single\":true,\"pool\":262210,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:planet\"}],\"renderer\":{}},\"bk:soap\":{\"id\":\"bk:soap\",\"time\":0.100000001490116,\"single\":true,\"quality\":3,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeProjectilesSlowDown\",\"amount\":1.5},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"small\"}],\"renderer\":{}},\"bk:d6\":{\"id\":\"bk:d6\",\"time\":4,\"type\":1,\"single\":true,\"pool\":70,\"uses\":[{\"id\":\"bk:RerollItems\",\"types\":[2,3,4,5,8],\"s_new\":false,\"ignore\":true}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:my_heart\":{\"id\":\"bk:my_heart\",\"time\":0.100000001490116,\"single\":true,\"pool\":4268162,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"amount\":2,\"single\":true,\"set\":false,\"bomb\":false}],\"renderer\":{}},\"bk:broken_heart\":{\"id\":\"bk:broken_heart\",\"time\":0.100000001490116,\"single\":true,\"pool\":4259970,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"give_hp\":false,\"amount\":2,\"single\":true}],\"renderer\":{}},\"bk:parcel\":{\"id\":\"bk:parcel\",\"time\":3,\"type\":1,\"single\":true,\"pool\":82,\"uses\":[{\"id\":\"bk:ModifyHp\"}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:glass\":{\"id\":\"bk:glass\",\"time\":0.100000001490116,\"single\":true,\"pool\":268435522,\"uses\":[{\"id\":\"bk:MakeProjectilesShatternOnDeath\"}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:broken_guitar\":{\"id\":\"bk:broken_guitar\",\"time\":0.100000001490116,\"single\":true,\"pool\":32838,\"uses\":[{\"id\":\"bk:UseOnEvent\",\"use\":\"bk:SpawnProjectiles\",\"tp\":\"BurningKnight.entity.events.PlayerRolledEvent\",\"us\":{\"id\":\"bk:SpawnProjectiles\",\"texture\":\"default\",\"amount\":6,\"speed\":3}}],\"renderer\":{}},\"bk:machine_gun\":{\"id\":\"bk:machine_gun\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"auto\":true,\"pool\":285212738,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"damage\":1,\"amount\":1,\"speed\":15,\"speedm\":15,\"dsb\":false,\"scale\":1,\"scalem\":1,\"texture\":\"rect\",\"rect\":true,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_machine\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"tomb\":false,\"emeralds\":false,\"ang\":0,\"range\":20}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":6,\"oy\":6,\"nx\":19,\"ny\":3.5},\"weapon\":1},\"bk:grenade_launcher\":{\"id\":\"bk:grenade_launcher\",\"time\":1,\"type\":7,\"single\":true,\"pool\":8388674,\"uses\":[{\"id\":\"bk:ShootQueue\",\"texture\":\"grenade\",\"speed\":10,\"prefab\":\"bk:grenade\",\"accuracy\":30,\"amn\":1,\"dl\":0,\"damage\":0}],\"renderer\":{\"id\":\"bk:Stick\",\"h\":true,\"nx\":12,\"ny\":4.5,\"ox\":0,\"oy\":4},\"lock\":true,\"uprice\":1,\"weapon\":1},\"bk:missile_launcher\":{\"id\":\"bk:missile_launcher\",\"time\":0.100000001490116,\"type\":7,\"single\":true,\"pool\":25165890,\"uses\":[{\"id\":\"bk:ShootQueue\",\"texture\":\"missile\",\"speed\":4,\"prefab\":\"bk:missile\",\"accuracy\":30,\"amn\":1,\"dl\":0,\"damage\":0,\"rect\":true,\"wait\":true,\"amount\":1,\"speedm\":4,\"scale\":1,\"scalem\":1,\"single\":false,\"mana\":0,\"modifiers\":[],\"cursor\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"color\":\"\",\"dsb\":false,\"tomb\":false,\"emeralds\":false,\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":3,\"nx\":10,\"ny\":3},\"lock\":true,\"uprice\":5,\"weapon\":1},\"bk:burst_gun\":{\"id\":\"bk:burst_gun\",\"time\":0.200000002980232,\"type\":7,\"single\":true,\"auto\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":5,\"texture\":\"default\",\"accuracy\":50,\"scale\":0.5,\"scalem\":0.699999988079071,\"damage\":1.20000004768372,\"amount\":1,\"speedm\":10,\"rect\":true,\"range\":50,\"dsb\":false,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_burst\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"tomb\":false,\"emeralds\":false,\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":6,\"nx\":13,\"ny\":4.5},\"weapon\":1},\"bk:flak_cannon\":{\"id\":\"bk:flak_cannon\",\"time\":1,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":15,\"texture\":\"default\",\"accuracy\":30,\"scale\":1,\"scalem\":1,\"prefab\":\"bk:flak\",\"wait\":true,\"speedm\":15,\"damage\":1,\"amount\":1,\"rect\":true,\"dsb\":false,\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0,\"range\":30}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":3,\"nx\":15,\"ny\":4},\"lock\":true,\"uprice\":2,\"weapon\":1},\"bk:disk_gun\":{\"id\":\"bk:disk_gun\",\"time\":0.400000005960464,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":10,\"texture\":\"disk\",\"accuracy\":0,\"scale\":1,\"scalem\":1,\"prefab\":\"bk:disk\",\"light\":false,\"damage\":4,\"amount\":1,\"speedm\":10,\"dsb\":true,\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0,\"range\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":1,\"oy\":6,\"nx\":12,\"ny\":4},\"lock\":true,\"uprice\":4,\"weapon\":1},\"bk:duck_gun\":{\"id\":\"bk:duck_gun\",\"time\":1,\"type\":7,\"chance\":0.100000001490116,\"single\":true,\"pool\":83918914,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":3,\"texture\":\"square\",\"accuracy\":0,\"scale\":1,\"scalem\":1,\"prefab\":\"bk:duck\",\"damage\":5,\"speedm\":3,\"knockback\":3000,\"rect\":true,\"wait\":true,\"amount\":1,\"dsb\":false,\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"quck\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0,\"range\":80}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":7,\"nx\":9,\"ny\":2.5,\"invert_back\":false},\"lock\":true,\"uprice\":4,\"weapon\":1},\"bk:follower\":{\"id\":\"bk:follower\",\"time\":0.100000001490116,\"type\":7,\"single\":true,\"pool\":25165890,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":4,\"texture\":\"missile\",\"accuracy\":0,\"scale\":1,\"scalem\":1,\"prefab\":\"bk:follower\",\"damage\":0,\"speedm\":4,\"knockback\":1,\"rect\":true,\"wait\":true,\"amount\":1,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"color\":\"\",\"dsb\":false,\"tomb\":false,\"emeralds\":false,\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":7,\"nx\":14,\"ny\":3.5},\"lock\":true,\"uprice\":6,\"weapon\":1},\"bk:portal_gun\":{\"id\":\"bk:portal_gun\",\"time\":0.5,\"type\":7,\"single\":true,\"auto\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"speed\":7,\"texture\":\"small\",\"accuracy\":32,\"scale\":1,\"scalem\":1.29999995231628,\"prefab\":\"bk:portal\",\"damage\":1.5,\"speedm\":7,\"knockback\":1,\"amount\":1,\"rect\":true,\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"dsb\":false,\"ang\":0,\"range\":16}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":0,\"oy\":6,\"nx\":15,\"ny\":3.5},\"lock\":true,\"uprice\":8,\"weapon\":1},\"bk:restock\":{\"id\":\"bk:restock\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"pool\":2195968,\"uses\":[{\"id\":\"bk:MakeShopRestock\"}],\"renderer\":{}},\"bk:charisma_ring\":{\"id\":\"bk:charisma_ring\",\"time\":0.100000001490116,\"single\":true,\"pool\":134251014,\"uses\":[{\"id\":\"bk:SaleItems\"}],\"renderer\":{}},\"bk:battery\":{\"id\":\"bk:battery\",\"time\":0.100000001490116,\"type\":8,\"single\":true,\"auto_pickup\":true,\"pool\":65,\"uses\":[{\"id\":\"bk:ModifyActiveCharge\",\"percent\":true,\"amount\":100}],\"renderer\":{}},\"bk:homemade_dice\":{\"id\":\"bk:homemade_dice\",\"time\":3,\"type\":1,\"single\":true,\"pool\":70,\"uses\":[{\"id\":\"bk:RerollAndHide\",\"types\":[8,2,3,4,5],\"s_new\":false}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:iron_boots\":{\"id\":\"bk:iron_boots\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:PreventDamage\",\"sp\":true}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:glass_gun\":{\"id\":\"bk:glass_gun\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"default\",\"range\":16,\"speed\":30,\"speedm\":30,\"accuracy\":10,\"damage\":10,\"amount\":1,\"scale\":1,\"scalem\":1,\"rect\":true,\"single\":false,\"cursor\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"dsb\":false,\"mana\":0,\"tomb\":false,\"emeralds\":false,\"color\":\"\",\"ang\":0},{\"id\":\"bk:UseOnEvent\",\"use\":\"bk:GiveWeapon\",\"tp\":\"BurningKnight.entity.events.PlayerHurtEvent\",\"us\":{\"id\":\"bk:GiveWeapon\",\"item\":\"bk:glass_shard\",\"single\":false},\"single\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":3,\"oy\":6,\"nx\":15,\"ny\":3.5},\"lock\":true,\"uprice\":1,\"weapon\":1},\"bk:glass_shard\":{\"id\":\"bk:glass_shard\",\"time\":0.25,\"type\":7,\"chance\":0,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":16,\"h\":26,\"angle\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":2,\"oy\":9,\"stay\":true,\"invert_back\":true,\"nx\":3,\"ny\":0},\"weapon\":0},\"bk:dagger\":{\"id\":\"bk:dagger\",\"time\":0.5,\"type\":7,\"single\":true,\"auto\":true,\"pool\":16777248,\"uses\":[{\"id\":\"bk:MeleeArc\",\"h\":16,\"w\":20,\"damage\":1,\"time\":0.200000002980232,\"angle\":0}],\"renderer\":{\"id\":\"bk:Stick\",\"mv\":8,\"nx\":2.5,\"ny\":0,\"ox\":2.5,\"oy\":12},\"lock\":true,\"uprice\":0,\"weapon\":0},\"bk:spear\":{\"id\":\"bk:spear\",\"time\":0.5,\"type\":7,\"single\":true,\"auto\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MeleeArc\",\"h\":12,\"w\":26,\"damage\":1,\"time\":0.200000002980232,\"angle\":0}],\"renderer\":{\"id\":\"bk:Stick\",\"mv\":8,\"ox\":3.5,\"oy\":21,\"nx\":3.5,\"ny\":0,\"h\":false},\"weapon\":0},\"bk:emerald\":{\"id\":\"bk:emerald\",\"time\":0.100000001490116,\"type\":2,\"single\":true,\"auto_pickup\":true,\"pool\":256,\"uses\":[{\"id\":\"bk:GiveEmeralds\"}],\"renderer\":{}},\"bk:magnifier\":{\"id\":\"bk:magnifier\",\"time\":0.100000001490116,\"single\":true,\"pool\":268435654,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"amount\":1.5,\"single\":false,\"any\":true,\"chance\":1,\"damage\":1,\"rne\":false,\"explosive\":false}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:spike\":{\"id\":\"bk:spike\",\"time\":0.100000001490116,\"chance\":0.75,\"single\":true,\"pool\":2162882,\"uses\":[{\"id\":\"bk:ModifyStats\",\"speed\":1,\"add_speed\":false,\"damage\":0.75,\"add_damage\":true,\"fire_rate\":1,\"add_fire_rate\":false,\"accuracy\":1,\"add_accuracy\":false,\"range\":1,\"add_range\":false,\"single\":false,\"ranged_rate\":0,\"add_ranged_rate\":true}],\"renderer\":{}},\"bk:mushroom_hat\":{\"id\":\"bk:mushroom_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:stone_hat\":{\"id\":\"bk:stone_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:knight_hat\":{\"id\":\"bk:knight_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":8},\"bk:cowboy_hat\":{\"id\":\"bk:cowboy_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:soup_hat\":{\"id\":\"bk:soup_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:gold_hat\":{\"id\":\"bk:gold_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":99},\"bk:viking_hat\":{\"id\":\"bk:viking_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":9},\"bk:dunce_hat\":{\"id\":\"bk:dunce_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:top_hat\":{\"id\":\"bk:top_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":2},\"bk:ushanka\":{\"id\":\"bk:ushanka\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:valkyrie_hat\":{\"id\":\"bk:valkyrie_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:skull_hat\":{\"id\":\"bk:skull_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:grandma_head\":{\"id\":\"bk:grandma_head\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":7},\"bk:diamond_helmet\":{\"id\":\"bk:diamond_helmet\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":15},\"bk:villager_head\":{\"id\":\"bk:villager_head\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":15},\"bk:fez\":{\"id\":\"bk:fez\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:no_hat\":{\"id\":\"bk:no_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{}},\"bk:null_hat\":{\"id\":\"bk:null_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:xmas_hat\":{\"id\":\"bk:xmas_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":15},\"bk:pumpkin_hat\":{\"id\":\"bk:pumpkin_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":12},\"bk:cage_key\":{\"id\":\"bk:cage_key\",\"time\":0.300000011920929,\"type\":7,\"chance\":0,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":0,\"oy\":3.5,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":12,\"ny\":3},\"weapon\":0},\"bk:frog\":{\"id\":\"bk:frog\",\"time\":2,\"type\":1,\"single\":true,\"pool\":67110986,\"uses\":[{\"id\":\"bk:Teleport\",\"self\":true}],\"renderer\":{},\"lock\":true,\"uprice\":2},\"bk:sword_orbital\":{\"id\":\"bk:sword_orbital\",\"time\":0.100000001490116,\"single\":true,\"pool\":262210,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"orbital\":\"bk:sword\"}],\"renderer\":{}},\"bk:gift\":{\"id\":\"bk:gift\",\"time\":0.100000001490116,\"type\":1,\"single\":true,\"single_use\":true,\"pool\":268435522,\"uses\":[{\"id\":\"bk:GiveItem\",\"on_stand\":true,\"random\":true}],\"renderer\":{}},\"bk:spike_ring\":{\"id\":\"bk:spike_ring\",\"time\":0.100000001490116,\"single\":true,\"pool\":136380486,\"uses\":[{\"id\":\"bk:DoOnEnemyCollision\",\"uses\":[{\"id\":\"bk:ModifyHp\",\"amount\":-1}]}],\"renderer\":{}},\"bk:fire_ring\":{\"id\":\"bk:fire_ring\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217798,\"uses\":[{\"id\":\"bk:DoOnEnemyCollision\",\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:burning\",\"time\":5}]}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:ice_ring\":{\"id\":\"bk:ice_ring\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217798,\"uses\":[{\"id\":\"bk:DoOnEnemyCollision\",\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:frozen\",\"time\":5}]}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:duck_ring\":{\"id\":\"bk:duck_ring\",\"time\":0.100000001490116,\"chance\":0.00999999977648258,\"single\":true,\"pool\":202375238,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"uses\":[{\"id\":\"bk:Teleport\",\"self\":true}]}],\"renderer\":{}},\"bk:snowflake\":{\"id\":\"bk:snowflake\",\"time\":2,\"type\":1,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:DoWith\",\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:frozen\",\"time\":5}],\"all\":true,\"tag\":8,\"single\":false}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:dull_blade\":{\"id\":\"bk:dull_blade\",\"type\":1,\"chance\":0,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:TriggerHurtEvent\"}],\"renderer\":{}},\"bk:sharp_blade\":{\"id\":\"bk:sharp_blade\",\"type\":1,\"chance\":0,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:ModifyHp\",\"amount\":-1}],\"renderer\":{}},\"bk:obsidian_shield\":{\"id\":\"bk:obsidian_shield\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:SetKnockbackModifier\"}],\"renderer\":{}},\"bk:bill\":{\"id\":\"bk:bill\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"scourged\":true,\"pool\":2097668,\"uses\":[{\"id\":\"bk:GiveGold\",\"amount\":99},{\"id\":\"bk:Scourge\",\"amount\":2}],\"renderer\":{}},\"bk:clover\":{\"id\":\"bk:clover\",\"time\":0.100000001490116,\"single\":true,\"pool\":134221826,\"uses\":[{\"id\":\"bk:ModifyLuck\",\"amount\":2}],\"renderer\":{}},\"bk:d4\":{\"id\":\"bk:d4\",\"time\":8,\"type\":1,\"single\":true,\"pool\":70,\"uses\":[{\"id\":\"bk:RerollItemsOnPlayer\"}],\"renderer\":{}},\"bk:maanex_head\":{\"id\":\"bk:maanex_head\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:maanex\":{\"id\":\"bk:maanex\",\"time\":1,\"type\":1,\"single\":true,\"pool\":70,\"uses\":[],\"renderer\":{}},\"bk:map_greenprints\":{\"id\":\"bk:map_greenprints\",\"time\":0.100000001490116,\"type\":1,\"single\":true,\"single_use\":true,\"pool\":134221894,\"uses\":[{\"id\":\"bk:RevealMap\"}],\"renderer\":{}},\"bk:map\":{\"id\":\"bk:map\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:RevealMap\"}],\"renderer\":{}},\"bk:crying_bomb\":{\"id\":\"bk:crying_bomb\",\"time\":0.100000001490116,\"single\":true,\"pool\":8912962,\"uses\":[{\"id\":\"bk:ModifyBombs\",\"spawn_bullets\":true},{\"id\":\"bk:GiveBomb\",\"amount\":10,\"single\":false}],\"renderer\":{}},\"bk:matches\":{\"id\":\"bk:matches\",\"time\":0.100000001490116,\"single\":true,\"pool\":8388674,\"uses\":[{\"id\":\"bk:ModifyBombs\",\"spawn_bullets\":false,\"set_fuse\":true,\"fuse_time\":0.5},{\"id\":\"bk:GiveBomb\",\"amount\":5}],\"renderer\":{}},\"bk:bomb_pack\":{\"id\":\"bk:bomb_pack\",\"time\":0.100000001490116,\"single\":true,\"pool\":8913474,\"uses\":[{\"id\":\"bk:ModifyBombs\",\"spawn_bullets\":false,\"set_fuse\":false,\"fuse_time\":0.5,\"spawn_bombs\":true},{\"id\":\"bk:GiveBomb\",\"amount\":5,\"single\":false}],\"renderer\":{}},\"bk:tnt\":{\"id\":\"bk:tnt\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":33296,\"uses\":[{\"id\":\"bk:GiveBomb\",\"amount\":99}],\"renderer\":{}},\"bk:weird_mushroom\":{\"id\":\"bk:weird_mushroom\",\"time\":0.100000001490116,\"type\":1,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"single_use\":true,\"pool\":404750402,\"uses\":[{\"id\":\"bk:DuplicateItems\"},{\"id\":\"bk:DuplicateMobs\"}],\"renderer\":{}},\"bk:bomb_shower\":{\"id\":\"bk:bomb_shower\",\"time\":2,\"type\":1,\"single\":true,\"pool\":8912962,\"uses\":[{\"id\":\"bk:SpawnBomb\",\"amount\":10,\"randomly\":true}],\"renderer\":{}},\"bk:black_belt\":{\"id\":\"bk:black_belt\",\"time\":0.100000001490116,\"single\":true,\"pool\":8388674,\"uses\":[{\"id\":\"bk:PreventDamage\",\"bms\":true,\"cs\":false,\"sp\":false,\"lv\":false}],\"renderer\":{}},\"bk:ninjia_bomb\":{\"id\":\"bk:ninjia_bomb\",\"time\":0.100000001490116,\"single\":true,\"pool\":8921154,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"uses\":[{\"id\":\"bk:SpawnBomb\",\"randomly\":true,\"amount\":8}]}],\"renderer\":{}},\"bk:laser_pointer\":{\"id\":\"bk:laser_pointer\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:GiveLaserAim\"}],\"renderer\":{}},\"bk:voodoo_doll\":{\"id\":\"bk:voodoo_doll\",\"time\":0.100000001490116,\"type\":1,\"single\":true,\"single_use\":true,\"pool\":35660354,\"uses\":[{\"id\":\"bk:KillMob\",\"all\":true,\"single\":false}],\"renderer\":{}},\"bk:amurs_arrow\":{\"id\":\"bk:amurs_arrow\",\"time\":0.100000001490116,\"single\":true,\"pool\":134221890,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"buff_time\":10,\"buff\":\"bk:charmed\",\"chance\":0.100000001490116,\"amount\":1,\"damage\":1,\"infinite_buff\":false,\"single\":false,\"any\":true,\"rne\":false,\"explosive\":false,\"samount\":true,\"sdamage\":true,\"srange\":true,\"range\":1},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"damage\":1,\"rne\":false,\"buff\":\"bk:charmed\",\"infinite_buff\":false,\"buff_time\":10}],\"renderer\":{}},\"bk:amurs_bow\":{\"id\":\"bk:amurs_bow\",\"time\":1,\"type\":7,\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"arrow\",\"rect\":true,\"speed\":10,\"damage\":0.100000001490116,\"modifiers\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:charmed\",\"time\":10}],\"amount\":1,\"speedm\":10,\"scale\":1,\"scalem\":1,\"dsb\":false,\"single\":false,\"cursor\":false,\"sfx\":\"item_bow_attack\",\"mana\":0,\"tomb\":false,\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0,\"range\":20},{\"id\":\"bk:ModifyProjectiles\",\"buff\":\"bk:charmed\",\"buff_time\":10,\"chance\":1,\"amount\":1,\"damage\":1,\"infinite_buff\":false,\"single\":false,\"any\":false,\"samount\":true,\"sdamage\":true,\"srange\":true,\"range\":1,\"rne\":false,\"explosive\":false}],\"renderer\":{\"id\":\"bk:Stick\",\"ox\":2,\"oy\":8,\"nx\":9,\"ny\":8,\"h\":true},\"weapon\":1},\"bk:poison_flask\":{\"id\":\"bk:poison_flask\",\"time\":0.100000001490116,\"single\":true,\"pool\":134219850,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"buff_time\":5,\"buff\":\"bk:poison\",\"chance\":0.300000011920929,\"amount\":1,\"damage\":1,\"infinite_buff\":false,\"single\":false,\"any\":true,\"rne\":false,\"explosive\":false},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"damage\":1,\"rne\":false,\"buff\":\"bk:poison\",\"infinite_buff\":false,\"buff_time\":5}],\"renderer\":{}},\"bk:snowball\":{\"id\":\"bk:snowball\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"buff_time\":5,\"buff\":\"bk:frozen\",\"chance\":0.300000011920929,\"amount\":1,\"damage\":1,\"infinite_buff\":false,\"single\":false,\"any\":true,\"rne\":false,\"explosive\":false},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"damage\":1,\"rne\":false,\"buff\":\"bk:frozen\",\"infinite_buff\":false,\"buff_time\":5}],\"renderer\":{}},\"bk:peper\":{\"id\":\"bk:peper\",\"time\":0.100000001490116,\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"buff_time\":5,\"buff\":\"bk:burning\",\"chance\":0.300000011920929,\"amount\":1,\"damage\":1,\"infinite_buff\":false,\"single\":false,\"any\":true,\"rne\":false,\"explosive\":false},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":1,\"damage\":1,\"rne\":false,\"buff\":\"bk:burning\",\"infinite_buff\":false,\"buff_time\":5}],\"renderer\":{}},\"bk:sale_coupon\":{\"id\":\"bk:sale_coupon\",\"time\":0.100000001490116,\"type\":1,\"single\":true,\"single_use\":true,\"pool\":518,\"uses\":[{\"id\":\"bk:SaleItems\",\"single\":false,\"wu\":true}],\"renderer\":{}},\"bk:pet_box\":{\"id\":\"bk:pet_box\",\"time\":0.100000001490116,\"type\":6,\"single\":true,\"pool\":268451930,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":true,\"pet\":\"\"}],\"renderer\":{}},\"bk:crate\":{\"id\":\"bk:crate\",\"time\":0.100000001490116,\"type\":6,\"single\":true,\"pool\":90,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"random\":true}],\"renderer\":{}},\"bk:strawberry\":{\"id\":\"bk:strawberry\",\"time\":0.100000001490116,\"single\":true,\"pool\":268566602,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:strawberry\"}],\"renderer\":{}},\"bk:wings\":{\"id\":\"bk:wings\",\"time\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":403820544,\"uses\":[{\"id\":\"bk:GiveFlight\",\"single\":false},{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"p\":false,\"hw\":true,\"st\":true,\"bp\":false,\"fp\":true}],\"renderer\":{}},\"bk:coin_pouch\":{\"id\":\"bk:coin_pouch\",\"time\":0.100000001490116,\"single\":true,\"pool\":149586,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:coin_pouch\"}],\"renderer\":{}},\"bk:key_pouch\":{\"id\":\"bk:key_pouch\",\"time\":0.100000001490116,\"single\":true,\"pool\":149586,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:key_pouch\"}],\"renderer\":{}},\"bk:bomb_pouch\":{\"id\":\"bk:bomb_pouch\",\"time\":0.100000001490116,\"single\":true,\"pool\":9062482,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:bomb_pouch\"}],\"renderer\":{}},\"bk:pouch_pouch\":{\"id\":\"bk:pouch_pouch\",\"time\":0.100000001490116,\"chance\":0.200000002980232,\"single\":true,\"pool\":149586,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:pouch_pouch\"}],\"renderer\":{}},\"bk:pouch\":{\"id\":\"bk:pouch\",\"time\":0.100000001490116,\"type\":10,\"single\":true,\"auto_pickup\":true,\"pool\":131089,\"uses\":[{\"id\":\"bk:SpawnDrop\",\"drop\":\"bk:pouch\"}],\"renderer\":{}},\"bk:pickaxe\":{\"id\":\"bk:pickaxe\",\"time\":0.5,\"type\":7,\"single\":true,\"quality\":1,\"pool\":8388674,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":false,\"chance\":1,\"damage\":1,\"mine\":true,\"rne\":false}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":6.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":6.5,\"ny\":0},\"weapon\":0},\"bk:shovel\":{\"id\":\"bk:shovel\",\"time\":1,\"type\":7,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":16,\"h\":32,\"angle\":0,\"single\":false,\"knockback\":0,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:MeleeArc\",\"damage\":1,\"w\":16,\"h\":32,\"time\":0.200000002980232,\"angle\":-0.25,\"single\":false,\"knockback\":0,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:MeleeArc\",\"damage\":1,\"w\":16,\"h\":32,\"time\":0.200000002980232,\"angle\":0.25,\"single\":false,\"knockback\":0,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":3.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":3,\"ny\":0},\"lock\":true,\"uprice\":2,\"weapon\":0},\"bk:lightsaber\":{\"id\":\"bk:lightsaber\",\"time\":0.5,\"type\":7,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":12,\"h\":16,\"angle\":0},{\"id\":\"bk:MeleeArc\",\"damage\":1,\"w\":12,\"h\":16,\"time\":0.200000002980232,\"angle\":-0.25},{\"id\":\"bk:MeleeArc\",\"damage\":1,\"w\":12,\"h\":16,\"time\":0.200000002980232,\"angle\":0.25},{\"id\":\"bk:MeleeArc\",\"damage\":1,\"w\":12,\"h\":16,\"time\":0.200000002980232,\"angle\":0.5}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":2,\"oy\":20,\"stay\":true,\"invert_back\":true,\"st\":0.300000011920929,\"max_angle\":360,\"rt\":0.0500000007450581,\"nx\":2,\"ny\":0},\"weapon\":0},\"bk:snail\":{\"id\":\"bk:snail\",\"time\":2,\"type\":1,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:DoWith\",\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:slow\",\"time\":10}],\"all\":true,\"tag\":4}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:mushroom\":{\"id\":\"bk:mushroom\",\"time\":0.100000001490116,\"single\":true,\"pool\":134219842,\"uses\":[{\"id\":\"bk:ModifyStats\",\"speed\":0.5,\"add_speed\":true,\"damage\":1,\"add_damage\":false,\"fire_rate\":1,\"add_fire_rate\":false,\"accuracy\":1,\"add_accuracy\":false,\"range\":1,\"add_range\":false}],\"renderer\":{}},\"bk:candy\":{\"id\":\"bk:candy\",\"time\":0.100000001490116,\"chance\":0.200000002980232,\"single\":true,\"pool\":1048642,\"uses\":[{\"id\":\"bk:ModifyStats\",\"speed\":1,\"add_speed\":false,\"damage\":1,\"add_damage\":false,\"fire_rate\":1.5,\"add_fire_rate\":true,\"accuracy\":1,\"add_accuracy\":false,\"range\":1,\"add_range\":false,\"single\":false,\"ranged_rate\":0,\"add_ranged_rate\":true}],\"renderer\":{},\"lock\":true,\"uprice\":8},\"bk:glasses\":{\"id\":\"bk:glasses\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:ModifyStats\",\"speed\":1,\"add_speed\":false,\"damage\":1,\"add_damage\":false,\"fire_rate\":1,\"add_fire_rate\":false,\"accuracy\":2,\"add_accuracy\":false,\"range\":1,\"add_range\":false}],\"renderer\":{}},\"bk:ruler\":{\"id\":\"bk:ruler\",\"time\":0.100000001490116,\"single\":true,\"pool\":268435650,\"uses\":[{\"id\":\"bk:ModifyStats\",\"speed\":1,\"add_speed\":false,\"damage\":1,\"add_damage\":false,\"fire_rate\":1,\"add_fire_rate\":false,\"accuracy\":1,\"add_accuracy\":false,\"range\":1,\"add_range\":true}],\"renderer\":{}},\"bk:glass_bullet\":{\"id\":\"bk:glass_bullet\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeLayerPassable\",\"fp\":true,\"st\":true,\"fpl\":false,\"single\":false,\"p\":false,\"bp\":false}],\"renderer\":{}},\"bk:stopwatch\":{\"id\":\"bk:stopwatch\",\"time\":0.100000001490116,\"single\":true,\"pool\":1048642,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"uses\":[{\"id\":\"bk:DoWith\",\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:slow\",\"time\":15}],\"same_room\":true,\"all\":true,\"tag\":4}]}],\"renderer\":{}},\"bk:meat_guy\":{\"id\":\"bk:meat_guy\",\"time\":0.100000001490116,\"single\":true,\"pool\":131146,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:meat_guy\"}],\"renderer\":{}},\"bk:bullet_stone\":{\"id\":\"bk:bullet_stone\",\"time\":0.100000001490116,\"single\":true,\"pool\":790594,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"random\":false,\"orbital\":\"bk:bullet_stone\"}],\"renderer\":{}},\"bk:batman\":{\"id\":\"bk:batman\",\"time\":0.100000001490116,\"single\":true,\"pool\":132170,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:batman\"}],\"renderer\":{}},\"bk:sharp_arrow\":{\"id\":\"bk:sharp_arrow\",\"time\":0.100000001490116,\"single\":true,\"pool\":134221890,\"uses\":[{\"id\":\"bk:MakeLayerPassable\",\"st\":false,\"fp\":true,\"im\":true,\"single\":false,\"p\":false,\"bp\":false}],\"renderer\":{}},\"bk:boomerang\":{\"id\":\"bk:boomerang\",\"time\":0.100000001490116,\"single\":true,\"pool\":16450,\"uses\":[{\"id\":\"bk:MakeProjectilesBoomerang\"},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"boomerang\"}],\"renderer\":{}},\"bk:backpack\":{\"id\":\"bk:backpack\",\"time\":0.100000001490116,\"single\":true,\"pool\":135754,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:backpack\"}],\"renderer\":{}},\"bk:crystal\":{\"id\":\"bk:crystal\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":403865672,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:crystal\"}],\"renderer\":{}},\"bk:prism\":{\"id\":\"bk:prism\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":2392076,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"random\":false,\"orbital\":\"bk:prism\"}],\"renderer\":{}},\"bk:scourge_of_egg\":{\"id\":\"bk:scourge_of_egg\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_egg\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_unknown\":{\"id\":\"bk:scourge_of_unknown\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_unknown\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_blood\":{\"id\":\"bk:scourge_of_blood\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_blood\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_risk\":{\"id\":\"bk:scourge_of_risk\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_risk\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_keys\":{\"id\":\"bk:scourge_of_keys\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_keys\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_lost\":{\"id\":\"bk:scourge_of_lost\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_lost\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_scourged\":{\"id\":\"bk:scourge_of_scourged\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_scourged\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_illness\":{\"id\":\"bk:scourge_of_illness\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_illness\",\"single\":false}],\"renderer\":{}},\"bk:scourge_of_death\":{\"id\":\"bk:scourge_of_death\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_death\",\"single\":false},{\"id\":\"bk:ModifyHp\",\"amount\":1,\"to_min\":true}],\"renderer\":{}},\"bk:ancient_revolver\":{\"id\":\"bk:ancient_revolver\",\"time\":0.300000011920929,\"type\":7,\"chance\":0,\"single\":true,\"auto\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"rect\",\"range\":12,\"speed\":15,\"damage\":1.5,\"amount\":1,\"speedm\":15,\"scale\":1,\"scalem\":1,\"rect\":true,\"dsb\":false,\"accuracy\":10,\"modifiers\":[],\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":3,\"nx\":9,\"ny\":1},\"weapon\":1},\"bk:assault_rifle\":{\"id\":\"bk:assault_rifle\",\"time\":0.600000023841858,\"type\":7,\"single\":true,\"quality\":2,\"pool\":285245504,\"uses\":[{\"id\":\"bk:ShootQueue\",\"damage\":1,\"amount\":1,\"speed\":15,\"speedm\":15,\"dsb\":false,\"scale\":0.75,\"scalem\":0.899999976158142,\"range\":32,\"accuracy\":15,\"rect\":true,\"texture\":\"rect\",\"single\":false,\"mana\":0,\"cursor\":false,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"emeralds\":false,\"color\":\"\",\"ang\":0,\"dl\":0.0799999982118607,\"knockback\":6}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":6,\"oy\":6,\"nx\":19,\"ny\":3.5},\"weapon\":1},\"bk:shield\":{\"id\":\"bk:shield\",\"time\":0.100000001490116,\"type\":5,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:ModifyShieldHearts\",\"amount\":1,\"to_min\":false}],\"renderer\":{}},\"bk:shield_pouch\":{\"id\":\"bk:shield_pouch\",\"time\":0.100000001490116,\"single\":true,\"pool\":149586,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:shield_pouch\"}],\"renderer\":{}},\"bk:shield_buddy\":{\"id\":\"bk:shield_buddy\",\"time\":0.100000001490116,\"single\":true,\"pool\":131146,\"uses\":[{\"id\":\"bk:SpawnPet\",\"random\":false,\"pet\":\"bk:shield_buddy\"}],\"renderer\":{}},\"bk:skeleton_key\":{\"id\":\"bk:skeleton_key\",\"time\":0.100000001490116,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":2097156,\"uses\":[{\"id\":\"bk:GiveKey\",\"amount\":99}],\"renderer\":{}},\"bk:jar\":{\"id\":\"bk:jar\",\"time\":0.100000001490116,\"single\":true,\"quality\":1,\"pool\":269484226,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"amount\":3,\"give_hp\":true,\"single\":true,\"set\":false,\"bomb\":false}],\"renderer\":{}},\"bk:star\":{\"id\":\"bk:star\",\"time\":3,\"type\":1,\"single\":true,\"pool\":33554432,\"uses\":[{\"id\":\"bk:GiveBuff\",\"buff\":\"bk:invincible\",\"time\":10},{\"id\":\"bk:DoOnTimer\",\"time\":10,\"uses\":[{\"id\":\"bk:SetMusicSpeed\",\"speed\":1}]},{\"id\":\"bk:SetMusicSpeed\",\"speed\":2}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:car_bomb\":{\"id\":\"bk:car_bomb\",\"time\":0.100000001490116,\"single\":true,\"pool\":8912896,\"uses\":[{\"id\":\"bk:MakeBombsHome\",\"single\":false},{\"id\":\"bk:GiveBomb\",\"single\":false,\"amount\":5}],\"renderer\":{}},\"bk:grenade\":{\"id\":\"bk:grenade\",\"time\":0.100000001490116,\"single\":true,\"pool\":8912898,\"uses\":[{\"id\":\"bk:MakeBombsExplodeOnTouch\"},{\"id\":\"bk:GiveBomb\",\"single\":false,\"amount\":5}],\"renderer\":{}},\"bk:vampire_bat\":{\"id\":\"bk:vampire_bat\",\"time\":0.100000001490116,\"single\":true,\"pool\":6291456,\"uses\":[{\"id\":\"bk:Regen\",\"speed\":14,\"kills\":true,\"chests\":false,\"purchase\":false,\"single\":false}],\"renderer\":{}},\"bk:mustache\":{\"id\":\"bk:mustache\",\"time\":0.100000001490116,\"single\":true,\"pool\":4194368,\"uses\":[{\"id\":\"bk:Regen\",\"speed\":1,\"kills\":false,\"chests\":false,\"purchase\":true}],\"renderer\":{}},\"bk:bloody_chest\":{\"id\":\"bk:bloody_chest\",\"time\":0.100000001490116,\"single\":true,\"pool\":4263938,\"uses\":[{\"id\":\"bk:Regen\",\"speed\":1,\"kills\":false,\"chests\":true,\"purchase\":false}],\"renderer\":{}},\"bk:bloody_shield\":{\"id\":\"bk:bloody_shield\",\"time\":0.100000001490116,\"single\":true,\"pool\":6356992,\"uses\":[{\"id\":\"bk:ReplaceHeartsWithShields\"},{\"id\":\"bk:ModifyShieldHearts\",\"amount\":1,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:cutsaw\":{\"id\":\"bk:cutsaw\",\"time\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":39845952,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"uses\":[{\"id\":\"bk:DoWith\",\"uses\":[{\"id\":\"bk:ModifyHp\",\"amount\":-3,\"to_min\":false,\"to_max\":false}],\"same_room\":true,\"tag\":516}]}],\"renderer\":{}},\"bk:shadow_cloak\":{\"id\":\"bk:shadow_cloak\",\"time\":3,\"type\":1,\"single\":true,\"quality\":1,\"pool\":134225920,\"uses\":[{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:invisible\",\"time\":10}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:dynamite_stick\":{\"id\":\"bk:dynamite_stick\",\"type\":1,\"single\":true,\"pool\":8391168,\"uses\":[{\"id\":\"bk:Explode\"}],\"renderer\":{}},\"bk:chalice_of_blood\":{\"id\":\"bk:chalice_of_blood\",\"time\":2,\"type\":1,\"single\":true,\"pool\":140517376,\"uses\":[{\"id\":\"bk:ModifyHp\",\"single\":false,\"amount\":-1,\"to_min\":false,\"to_max\":false},{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:rage\",\"time\":15}],\"renderer\":{}},\"bk:detonator\":{\"id\":\"bk:detonator\",\"type\":1,\"single\":true,\"pool\":524800,\"uses\":[{\"id\":\"bk:DetonateBombs\"}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:talisman_of_foresight\":{\"id\":\"bk:talisman_of_foresight\",\"single\":true,\"quality\":1,\"pool\":167804928,\"uses\":[{\"id\":\"bk:DiscoverSideRooms\"}],\"renderer\":{}},\"bk:scourge_ring\":{\"id\":\"bk:scourge_ring\",\"single\":true,\"quality\":1,\"pool\":134250496,\"uses\":[{\"id\":\"bk:GiveScourgeImmunity\"}],\"renderer\":{}},\"bk:snek\":{\"id\":\"bk:snek\",\"single\":true,\"quality\":2,\"pool\":0,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:snek\"}],\"renderer\":{}},\"bk:blank\":{\"id\":\"bk:blank\",\"time\":1,\"type\":1,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:Blank\",\"single\":false}],\"renderer\":{}},\"bk:blank_bombs\":{\"id\":\"bk:blank_bombs\",\"single\":true,\"pool\":8388678,\"uses\":[{\"id\":\"bk:MakeBombsBlank\",\"single\":false},{\"id\":\"bk:GiveBomb\",\"single\":false,\"amount\":5}],\"renderer\":{}},\"bk:blank_bullets\":{\"id\":\"bk:blank_bullets\",\"single\":true,\"pool\":8388678,\"uses\":[{\"id\":\"bk:MakeProjectilesBlankOnDeath\",\"single\":false},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"ranged_rate\":-0.25,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:explosive_bullets\":{\"id\":\"bk:explosive_bullets\",\"single\":true,\"pool\":8392770,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":1,\"amount\":1,\"damage\":1,\"explosive\":true},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true,\"ranged_rate\":-1,\"add_ranged_rate\":true}],\"renderer\":{}},\"bk:random_bullets\":{\"id\":\"bk:random_bullets\",\"single\":true,\"quality\":1,\"pool\":66,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":1,\"amount\":1,\"damage\":1,\"explosive\":false,\"rne\":true,\"ecs\":3},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":1,\"damage\":1,\"rne\":true,\"buff\":\"bk:frozen\",\"infinite_buff\":false,\"buff_time\":1,\"ecs\":3}],\"renderer\":{}},\"bk:cup\":{\"id\":\"bk:cup\",\"single\":true,\"quality\":1,\"pool\":1114112,\"uses\":[{\"id\":\"bk:AffectDealChance\",\"single\":false,\"gr\":1,\"agr\":true,\"dm\":0,\"adm\":true}],\"renderer\":{}},\"bk:cartridge\":{\"id\":\"bk:cartridge\",\"single\":true,\"quality\":1,\"pool\":2162688,\"uses\":[{\"id\":\"bk:AffectDealChance\",\"single\":false,\"gr\":0,\"agr\":true,\"dm\":1,\"adm\":true}],\"renderer\":{}},\"bk:marriage_ring\":{\"id\":\"bk:marriage_ring\",\"single\":true,\"quality\":1,\"pool\":3211264,\"uses\":[{\"id\":\"bk:AffectDealChance\",\"single\":false,\"gr\":0,\"agr\":true,\"dm\":0,\"adm\":true,\"bt\":true}],\"renderer\":{}},\"bk:scourge_of_greed\":{\"id\":\"bk:scourge_of_greed\",\"time\":0.100000001490116,\"type\":11,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:EnableScourge\",\"scourge\":\"bk:of_greed\",\"single\":false}],\"renderer\":{}},\"bk:lego\":{\"id\":\"bk:lego\",\"single\":true,\"pool\":16466,\"uses\":[{\"id\":\"bk:LeaveLego\"}],\"renderer\":{}},\"bk:iron_armor\":{\"id\":\"bk:iron_armor\",\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:DoOnNewFloor\",\"single\":false,\"uses\":[{\"id\":\"bk:ModifyShieldHearts\",\"single\":false,\"amount\":1,\"to_min\":false,\"to_max\":false}]}],\"renderer\":{}},\"bk:round_shield\":{\"id\":\"bk:round_shield\",\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":402653256,\"uses\":[{\"id\":\"bk:PreventDamage\",\"single\":false,\"cnt\":true},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":-0.200000002980232,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"ranged_rate\":0,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:arkhalis\":{\"id\":\"bk:arkhalis\",\"time\":0.5,\"type\":7,\"chance\":0.200000002980232,\"single\":true,\"quality\":2,\"pool\":83894338,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false},{\"id\":\"bk:DoUsesIf\",\"single\":false,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"damage\":1,\"amount\":1,\"speed\":10,\"speedm\":10,\"dsb\":false,\"scale\":1,\"scalem\":1,\"rect\":true,\"cursor\":true,\"range\":10}]}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":4.5,\"oy\":14,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":4.5},\"weapon\":0},\"bk:inverted_arkhalis\":{\"id\":\"bk:inverted_arkhalis\",\"time\":0.5,\"type\":7,\"chance\":0.100000001490116,\"single\":true,\"quality\":1,\"pool\":83894338,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false},{\"id\":\"bk:DoUsesIf\",\"single\":false,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"damage\":1,\"amount\":1,\"speed\":10,\"speedm\":10,\"dsb\":false,\"scale\":1,\"scalem\":1,\"rect\":true,\"cursor\":true,\"range\":10}],\"opt\":1}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":4.5,\"oy\":14,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":4.5,\"ny\":0},\"weapon\":0},\"bk:gun_sword\":{\"id\":\"bk:gun_sword\",\"time\":0.5,\"type\":7,\"chance\":0.300000011920929,\"single\":true,\"quality\":2,\"pool\":50331714,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false},{\"id\":\"bk:SimpleShoot\",\"single\":false,\"damage\":1,\"amount\":1,\"speed\":10,\"speedm\":10,\"dsb\":false,\"scale\":1,\"scalem\":1,\"rect\":true,\"cursor\":true,\"range\":10}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":6,\"oy\":16,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":6,\"ny\":0},\"weapon\":0},\"bk:half_heart\":{\"id\":\"bk:half_heart\",\"animation\":\"item_half_heart\",\"time\":0.100000001490116,\"type\":5,\"single\":true,\"auto_pickup\":true,\"pool\":321,\"uses\":[{\"id\":\"bk:ModifyHp\",\"amount\":1,\"single\":false,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:axe\":{\"id\":\"bk:axe\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"pool\":16777248,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"axe\",\"range\":0,\"speed\":15,\"damage\":2,\"amount\":1,\"speedm\":15,\"scale\":1,\"scalem\":1,\"rect\":true,\"dsb\":false,\"accuracy\":0,\"single\":false,\"modifiers\":[],\"cursor\":false,\"sfx\":\"item_axe_throw\",\"sfxn\":0,\"rsfx\":false,\"wait\":true,\"prefab\":\"bk:axe\",\"shells\":false,\"mana\":0,\"color\":\"\"}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":1,\"oy\":13,\"nx\":7,\"ny\":3},\"lock\":true,\"uprice\":1,\"weapon\":1},\"bk:guitar\":{\"id\":\"bk:guitar\",\"time\":0.600000023841858,\"type\":7,\"single\":true,\"quality\":1,\"auto\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":20,\"h\":35,\"angle\":0,\"single\":false,\"hs\":\"item_ukulele\",\"as\":\"item_sword_attack\",\"knockback\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":5,\"oy\":1,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":5,\"ny\":17},\"weapon\":0},\"bk:glass_sword\":{\"id\":\"bk:glass_sword\",\"time\":0.5,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":8,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:UseOnEvent\",\"single\":false,\"tp\":\"BurningKnight.entity.events.PlayerHurtEvent\",\"use\":\"bk:GiveWeapon\",\"us\":{\"id\":\"bk:GiveWeapon\",\"single\":false,\"item\":\"bk:glass_shard\"}}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":3.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":3.5},\"weapon\":0},\"bk:chicken\":{\"id\":\"bk:chicken\",\"time\":0.5,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":10,\"h\":26,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":false,\"chance\":1,\"damage\":1,\"rne\":false,\"buff\":\"bk:burning\",\"infinite_buff\":false,\"buff_time\":10}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":4,\"oy\":14,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":5,\"ny\":1},\"weapon\":0},\"bk:mana\":{\"id\":\"bk:mana\",\"animation\":\"mana\",\"time\":0.100000001490116,\"type\":12,\"single\":true,\"auto_pickup\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyMana\",\"single\":false,\"amount\":2,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:half_mana\":{\"id\":\"bk:half_mana\",\"animation\":\"half_mana\",\"time\":0.100000001490116,\"type\":12,\"single\":true,\"auto_pickup\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyMana\",\"single\":false,\"amount\":1,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:lava_wand\":{\"id\":\"bk:lava_wand\",\"time\":0.5,\"type\":7,\"single\":true,\"quality\":1,\"pool\":66,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":2,\"cursor\":false,\"damage\":1,\"amount\":1,\"sfx\":\"item_magic_lava_cast\",\"sfxn\":0,\"rsfx\":false,\"shells\":false,\"color\":\"orange\",\"speed\":10,\"speedm\":10,\"dsb\":false,\"scale\":1,\"scalem\":1,\"knockback\":0,\"rect\":true,\"texture\":\"magic\",\"prefab\":\"bk:lava_wand\"}],\"renderer\":{\"id\":\"bk:Stick\",\"oy\":12,\"ox\":2.5,\"nx\":2.5,\"ny\":0},\"weapon\":2},\"bk:web_wand\":{\"id\":\"bk:web_wand\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":2,\"cursor\":false,\"damage\":1,\"amount\":1,\"sfx\":\"item_magic_web_cast\",\"sfxn\":0,\"rsfx\":true,\"shells\":false,\"color\":\"white\",\"speed\":10,\"speedm\":10,\"dsb\":false,\"scale\":1,\"scalem\":1,\"knockback\":0,\"rect\":true,\"texture\":\"magic\",\"prefab\":\"bk:web_wand\"}],\"renderer\":{\"id\":\"bk:Stick\",\"oy\":12,\"ox\":2.5,\"nx\":2.5,\"ny\":0},\"weapon\":2},\"bk:slap_stick\":{\"id\":\"bk:slap_stick\",\"time\":0.200000002980232,\"type\":7,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":0.100000001490116,\"time\":0.25,\"w\":30,\"h\":48,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\",\"knockback\":100000}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":5,\"oy\":19,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":5,\"ny\":0},\"weapon\":0},\"bk:ice_skates\":{\"id\":\"bk:ice_skates\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:GiveBuffImmunity\",\"single\":false,\"ice\":true,\"buff\":\"\"}],\"renderer\":{}},\"bk:campfire_in_bottle\":{\"id\":\"bk:campfire_in_bottle\",\"time\":0.100000001490116,\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:GiveBuffImmunity\",\"single\":false,\"ice\":false,\"buff\":\"bk:frozen\"}],\"renderer\":{}},\"bk:blindfold\":{\"id\":\"bk:blindfold\",\"chance\":0,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:BlindFold\"}],\"renderer\":{}},\"bk:cup_head\":{\"id\":\"bk:cup_head\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":10},\"bk:mustache_hat\":{\"id\":\"bk:mustache_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":8},\"bk:propeller_hat\":{\"id\":\"bk:propeller_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:sunglasses\":{\"id\":\"bk:sunglasses\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:cap\":{\"id\":\"bk:cap\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":7},\"bk:eyes\":{\"id\":\"bk:eyes\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":8},\"bk:eye\":{\"id\":\"bk:eye\",\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":9},\"bk:hair\":{\"id\":\"bk:hair\",\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":13},\"bk:weird_potion\":{\"id\":\"bk:weird_potion\",\"single\":true,\"pool\":268468292,\"uses\":[{\"id\":\"bk:MakeProjectileShrink\"},{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":1,\"amount\":2,\"damage\":1,\"rne\":false,\"explosive\":false,\"samount\":true,\"sdamage\":false,\"srange\":false,\"range\":1}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:megaphone\":{\"id\":\"bk:megaphone\",\"single\":true,\"pool\":32836,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":1,\"amount\":0.300000011920929,\"damage\":1,\"rne\":false,\"explosive\":false,\"samount\":true,\"sdamage\":false,\"srange\":false,\"range\":1},{\"id\":\"bk:MakeProjectileExpand\"}],\"renderer\":{},\"lock\":true,\"uprice\":7},\"bk:no_lamp\":{\"id\":\"bk:no_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{}},\"bk:explosive_lamp\":{\"id\":\"bk:explosive_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":true,\"bomb\":false,\"give_hp\":false,\"amount\":0},{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":true,\"bomb\":true,\"give_hp\":true,\"amount\":6},{\"id\":\"bk:GiveItem\",\"single\":false,\"item\":\"bk:blindfold\",\"animate\":false,\"hide\":true},{\"id\":\"bk:GiveItem\",\"single\":false,\"animate\":false,\"item\":\"bk:grenade\",\"hide\":true}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:shielded_lamp\":{\"id\":\"bk:shielded_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyShieldHearts\",\"single\":false,\"amount\":4,\"to_min\":false,\"to_max\":false},{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":true,\"bomb\":false,\"give_hp\":false,\"amount\":0},{\"id\":\"bk:GiveItem\",\"single\":false,\"animate\":false,\"hide\":false,\"item\":\"bk:iron_armor\"},{\"id\":\"bk:GiveItem\",\"single\":false,\"animate\":false,\"hide\":false,\"item\":\"bk:helmet\"}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:brain\":{\"id\":\"bk:brain\",\"chance\":0.5,\"single\":true,\"quality\":1,\"pool\":1073164,\"uses\":[{\"id\":\"bk:SuperHot\"}],\"renderer\":{},\"lock\":true,\"uprice\":10},\"bk:heart_amulet\":{\"id\":\"bk:heart_amulet\",\"time\":0.100000001490116,\"single\":true,\"quality\":1,\"pool\":192,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"amount\":2,\"give_hp\":true,\"single\":true,\"set\":false,\"bomb\":false}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:star_amulet\":{\"id\":\"bk:star_amulet\",\"time\":0.100000001490116,\"single\":true,\"pool\":4259906,\"uses\":[{\"id\":\"bk:ModifyManaMax\",\"single\":false,\"amount\":1}],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:coin_amulet\":{\"id\":\"bk:coin_amulet\",\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":134251008,\"uses\":[{\"id\":\"bk:ModifyConsumableWeights\",\"single\":false,\"amount\":2,\"coins\":true,\"keys\":false,\"bombs\":false}],\"renderer\":{},\"lock\":true,\"uprice\":26},\"bk:key_amulet\":{\"id\":\"bk:key_amulet\",\"single\":true,\"quality\":1,\"pool\":201851392,\"uses\":[{\"id\":\"bk:ModifyConsumableWeights\",\"single\":false,\"amount\":2,\"coins\":false,\"keys\":true,\"bombs\":false}],\"renderer\":{},\"lock\":true,\"uprice\":32},\"bk:bomb_amulet\":{\"id\":\"bk:bomb_amulet\",\"single\":true,\"quality\":1,\"pool\":167781376,\"uses\":[{\"id\":\"bk:ModifyConsumableWeights\",\"single\":false,\"amount\":2,\"coins\":false,\"keys\":false,\"bombs\":true}],\"renderer\":{}},\"bk:eye_amulet\":{\"id\":\"bk:eye_amulet\",\"single\":true,\"pool\":140509184,\"uses\":[{\"id\":\"bk:MakeProjectilesHurtOnMiss\"},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":1,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{},\"lock\":true,\"uprice\":12},\"bk:eye_patch\":{\"id\":\"bk:eye_patch\",\"single\":true,\"pool\":194,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":1,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":-1,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:toilet_paper\":{\"id\":\"bk:toilet_paper\",\"time\":1,\"type\":1,\"chance\":0.100000001490116,\"single\":true,\"pool\":84,\"uses\":[{\"id\":\"bk:TeleportToShop\"}],\"renderer\":{},\"lock\":true,\"uprice\":5},\"bk:decoy\":{\"id\":\"bk:decoy\",\"time\":4,\"type\":1,\"single\":true,\"quality\":1,\"pool\":33554442,\"uses\":[{\"id\":\"bk:PlaceDecoy\"}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:wallet\":{\"id\":\"bk:wallet\",\"single\":true,\"quality\":1,\"pool\":135178,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:wallet\"}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:skele_buddy\":{\"id\":\"bk:skele_buddy\",\"single\":true,\"quality\":1,\"pool\":33685514,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:skele_buddy\"}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:mega_bomb\":{\"id\":\"bk:mega_bomb\",\"single\":true,\"pool\":524866,\"uses\":[{\"id\":\"bk:ModifyBombs\",\"single\":false,\"radius\":2},{\"id\":\"bk:GiveBomb\",\"single\":false,\"amount\":5}],\"renderer\":{},\"lock\":true,\"uprice\":16},\"bk:condensed_milk\":{\"id\":\"bk:condensed_milk\",\"single\":true,\"pool\":67109442,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":0.100000001490116,\"samount\":true,\"amount\":1,\"sdamage\":true,\"damage\":1,\"srange\":true,\"range\":1,\"rne\":false,\"explosive\":false,\"buff\":\"bk:slow\",\"infinite_buff\":false,\"buff_time\":5},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"damage\":1,\"mine\":false,\"rne\":false,\"buff\":\"bk:slow\",\"infinite_buff\":false,\"buff_time\":5}],\"renderer\":{},\"lock\":true,\"uprice\":12},\"bk:marshmallow\":{\"id\":\"bk:marshmallow\",\"single\":true,\"pool\":262216,\"uses\":[{\"id\":\"bk:SpawnOrbital\",\"single\":false,\"random\":false,\"orbital\":\"bk:marshmallow\"}],\"renderer\":{},\"lock\":true,\"uprice\":4},\"bk:orbital_multiplier\":{\"id\":\"bk:orbital_multiplier\",\"single\":true,\"quality\":2,\"pool\":134217802,\"uses\":[{\"id\":\"bk:InvokeItems\",\"single\":true,\"pets\":false,\"orbitals\":true,\"any\":false},{\"id\":\"bk:SpawnOrbital\",\"single\":true,\"random\":true,\"orbital\":\"\",\"oin\":true}],\"renderer\":{},\"lock\":true,\"uprice\":13},\"bk:pet_multiplier\":{\"id\":\"bk:pet_multiplier\",\"single\":true,\"quality\":2,\"pool\":134221890,\"uses\":[{\"id\":\"bk:InvokeItems\",\"single\":true,\"pets\":true,\"orbitals\":false,\"any\":false},{\"id\":\"bk:SpawnPet\",\"single\":true,\"random\":true,\"pet\":\"\",\"oin\":true}],\"renderer\":{},\"lock\":true,\"uprice\":30},\"bk:ghost_bullets\":{\"id\":\"bk:ghost_bullets\",\"single\":true,\"quality\":1,\"pool\":8258,\"uses\":[{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"st\":false,\"fp\":true,\"iw\":true,\"p\":false,\"bp\":false}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:weight\":{\"id\":\"bk:weight\",\"single\":true,\"pool\":66114,\"uses\":[{\"id\":\"bk:SpeedUpOrbitals\",\"single\":false},{\"id\":\"bk:SpawnOrbital\",\"single\":true,\"random\":true,\"orbital\":\"\"}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:d2\":{\"id\":\"bk:d2\",\"type\":1,\"single\":true,\"quality\":2,\"pool\":33557570,\"uses\":[{\"id\":\"bk:RerollItems\",\"single\":false,\"cc\":0,\"d2\":true,\"types\":[],\"s_new\":false}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:ethernal_d6\":{\"id\":\"bk:ethernal_d6\",\"time\":3,\"type\":1,\"single\":true,\"pool\":18,\"uses\":[{\"id\":\"bk:RerollItems\",\"single\":false,\"cc\":0.300000011920929,\"d2\":false,\"types\":[],\"s_new\":false}],\"renderer\":{}},\"bk:billiard\":{\"id\":\"bk:billiard\",\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"p\":true,\"st\":false,\"bp\":false,\"fp\":true}],\"renderer\":{},\"lock\":true,\"uprice\":3},\"bk:enraged_bullets\":{\"id\":\"bk:enraged_bullets\",\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"p\":false,\"st\":false,\"bp\":true,\"fp\":true}],\"renderer\":{},\"lock\":true,\"uprice\":2},\"bk:rewind_button\":{\"id\":\"bk:rewind_button\",\"time\":2,\"type\":1,\"single\":true,\"pool\":2050,\"uses\":[{\"id\":\"bk:TeleportToPrevRoom\"}],\"renderer\":{}},\"bk:piggy_bank\":{\"id\":\"bk:piggy_bank\",\"type\":1,\"single\":true,\"single_use\":true,\"pool\":8388672,\"uses\":[{\"id\":\"bk:BreakPiggyBank\"}],\"renderer\":{}},\"bk:death_star\":{\"id\":\"bk:death_star\",\"time\":0.400000005960464,\"type\":7,\"single\":true,\"pool\":16777282,\"uses\":[{\"id\":\"bk:MeleeArc\",\"single\":false,\"damage\":1,\"w\":14,\"h\":24,\"time\":0.200000002980232,\"angle\":0,\"knockback\":0,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":false,\"chance\":1,\"damage\":1,\"mine\":false,\"rne\":false,\"ecs\":3,\"buff\":\"bk:broken_armor\",\"infinite_buff\":true,\"buff_time\":1}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":5,\"oy\":15,\"nx\":5,\"ny\":3,\"stay\":true},\"weapon\":0},\"bk:soldering_iron\":{\"id\":\"bk:soldering_iron\",\"single\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"samount\":true,\"amount\":1,\"sdamage\":true,\"damage\":1,\"srange\":true,\"range\":1,\"rne\":false,\"explosive\":false,\"buff\":\"bk:burning\",\"infinite_buff\":false,\"buff_time\":10},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.300000011920929,\"damage\":1,\"mine\":false,\"rne\":false,\"buff\":\"bk:burning\",\"infinite_buff\":false,\"buff_time\":10},{\"id\":\"bk:MakeProjectilesKillWithBuff\",\"single\":false,\"buff\":\"bk:frozen\"}],\"renderer\":{},\"lock\":true,\"uprice\":2},\"bk:can\":{\"id\":\"bk:can\",\"single\":true,\"quality\":1,\"pool\":32848,\"uses\":[{\"id\":\"bk:ModifyShoot\",\"single\":false,\"amount\":1}],\"renderer\":{},\"lock\":true,\"uprice\":4},\"bk:alien_glasses\":{\"id\":\"bk:alien_glasses\",\"single\":true,\"quality\":2,\"pool\":270540880,\"uses\":[{\"id\":\"bk:ModifyShoot\",\"single\":false,\"amount\":2},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":-5,\"add_accuracy\":true,\"range\":0,\"add_range\":true,\"ranged_rate\":0,\"add_ranged_rate\":true}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:swimming_mask\":{\"id\":\"bk:swimming_mask\",\"single\":true,\"quality\":2,\"pool\":8421440,\"uses\":[{\"id\":\"bk:ModifyShoot\",\"single\":false,\"amount\":2}],\"renderer\":{},\"lock\":true,\"uprice\":8},\"bk:bullet_chair\":{\"id\":\"bk:bullet_chair\",\"single\":true,\"scourged\":true,\"pool\":32768,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":-0.5,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true},{\"id\":\"bk:ModifyShoot\",\"single\":false,\"amount\":3}],\"renderer\":{},\"lock\":true,\"uprice\":6},\"bk:cell\":{\"id\":\"bk:cell\",\"single\":true,\"quality\":1,\"pool\":66,\"uses\":[{\"id\":\"bk:MakeProjectilesSplit\"},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"circle\"}],\"renderer\":{},\"lock\":true,\"uprice\":1},\"bk:brick\":{\"id\":\"bk:brick\",\"single\":true,\"pool\":8912896,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":true}],\"renderer\":{}},\"bk:ring_of_pain\":{\"id\":\"bk:ring_of_pain\",\"single\":true,\"scourged\":true,\"pool\":6299648,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"single\":false,\"uses\":[{\"id\":\"bk:DoWith\",\"single\":false,\"uses\":[{\"id\":\"bk:ModifyHp\",\"single\":false,\"amount\":-4,\"to_min\":false,\"to_max\":false}],\"all\":true,\"same_room\":true,\"tag\":8}]},{\"id\":\"bk:ModifyHp\",\"single\":true,\"amount\":-1,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:schrodingers_cat\":{\"id\":\"bk:schrodingers_cat\",\"time\":1,\"type\":1,\"single\":true,\"pool\":74,\"uses\":[{\"id\":\"bk:Random\",\"single\":false,\"uses\":[{\"id\":\"bk:ModifyHp\",\"single\":false,\"amount\":-1,\"to_min\":false,\"to_max\":false},{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:invincible\",\"time\":10}]}],\"renderer\":{}},\"bk:smoke_bomb\":{\"id\":\"bk:smoke_bomb\",\"single\":true,\"pool\":6,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"single\":false,\"uses\":[{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:invisible\",\"time\":10},{\"id\":\"bk:Poof\"}]}],\"renderer\":{}},\"bk:chest_ring\":{\"id\":\"bk:chest_ring\",\"single\":true,\"pool\":134217794,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"crc\":20,\"md\":0}],\"renderer\":{}},\"bk:empty_shell\":{\"id\":\"bk:empty_shell\",\"single\":true,\"pool\":1048576,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"crc\":0,\"md\":10}],\"renderer\":{}},\"bk:parachute\":{\"id\":\"bk:parachute\",\"single\":true,\"quality\":3,\"pool\":66,\"uses\":[{\"id\":\"bk:GiveBuffImmunity\",\"single\":false,\"ice\":false,\"pit\":true}],\"renderer\":{}},\"bk:spiked_cookie\":{\"id\":\"bk:spiked_cookie\",\"single\":true,\"quality\":1,\"pool\":135178,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:spiked_cookie\"}],\"renderer\":{}},\"bk:shooty\":{\"id\":\"bk:shooty\",\"single\":true,\"quality\":1,\"pool\":1179658,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:shooty\"}],\"renderer\":{}},\"bk:rabbit_bullets\":{\"id\":\"bk:rabbit_bullets\",\"single\":true,\"quality\":2,\"pool\":2105344,\"uses\":[{\"id\":\"bk:MakeProjectileReshoot\"}],\"renderer\":{}},\"bk:pandoras_box\":{\"id\":\"bk:pandoras_box\",\"time\":1,\"type\":1,\"single\":true,\"pool\":82,\"uses\":[{\"id\":\"bk:Pokemon\"}],\"renderer\":{}},\"bk:bubbles\":{\"id\":\"bk:bubbles\",\"single\":true,\"pool\":131082,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:bubblo\"}],\"renderer\":{}},\"bk:match\":{\"id\":\"bk:match\",\"time\":2,\"type\":1,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:DoWith\",\"single\":false,\"uses\":[{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:burning\",\"time\":5}],\"same_room\":true,\"all\":true,\"tag\":8}],\"renderer\":{}},\"bk:hammer\":{\"id\":\"bk:hammer\",\"time\":3,\"type\":1,\"single\":true,\"auto_pickup\":true,\"pool\":66,\"uses\":[{\"id\":\"bk:DoWith\",\"single\":false,\"uses\":[{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:broken_armor\",\"time\":20000}],\"all\":true,\"same_room\":true,\"tag\":4104}],\"renderer\":{}},\"bk:helmet\":{\"id\":\"bk:helmet\",\"single\":true,\"quality\":1,\"pool\":65602,\"uses\":[{\"id\":\"bk:ModifyShieldHearts\",\"single\":false,\"amount\":2,\"to_min\":false,\"to_max\":false},{\"id\":\"bk:BlockDamage\",\"single\":false,\"chance\":10}],\"renderer\":{}},\"bk:beer\":{\"id\":\"bk:beer\",\"single\":true,\"pool\":8388672,\"uses\":[{\"id\":\"bk:DoOnHurt\",\"single\":false,\"uses\":[{\"id\":\"bk:GiveBuff\",\"single\":false,\"buff\":\"bk:rage\",\"time\":15}]}],\"renderer\":{}},\"bk:the_eye\":{\"id\":\"bk:the_eye\",\"single\":true,\"quality\":2,\"pool\":131086,\"uses\":[{\"id\":\"bk:SpawnPet\",\"single\":false,\"random\":false,\"pet\":\"bk:the_eye\"}],\"renderer\":{}},\"bk:mimics_tooth\":{\"id\":\"bk:mimics_tooth\",\"single\":true,\"pool\":134217752,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"crc\":0,\"md\":0,\"mimic\":100}],\"renderer\":{}},\"bk:mimic_totem\":{\"id\":\"bk:mimic_totem\",\"single\":true,\"pool\":134217742,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"crc\":0,\"md\":0,\"mimic\":-100}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:paper_airplane\":{\"id\":\"bk:paper_airplane\",\"single\":true,\"quality\":2,\"pool\":8405008,\"uses\":[{\"id\":\"bk:MakeProjectilesHomeIn\",\"single\":false,\"better\":true},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"carrot\"},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"ranged_rate\":-0.400000005960464,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:led\":{\"id\":\"bk:led\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:GiveItem\",\"single\":false,\"animate\":false,\"hide\":true,\"item\":\"bk:eye_amulet\"}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:fragile_lamp\":{\"id\":\"bk:fragile_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:GiveItem\",\"single\":false,\"animate\":false,\"hide\":true,\"item\":\"bk:spike\",\"amount\":4},{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":true,\"bomb\":false,\"give_hp\":false},{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"gm\":false,\"sp\":false,\"tr\":true,\"crc\":0,\"md\":0,\"mimic\":0}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:headshot_gun\":{\"id\":\"bk:headshot_gun\",\"time\":0.400000005960464,\"type\":7,\"chance\":0.100000001490116,\"single\":true,\"pool\":16779330,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":0,\"cursor\":false,\"damage\":2,\"amount\":1,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"speed\":15,\"speedm\":15,\"dsb\":false,\"scale\":1,\"scalem\":1,\"modifiers\":[],\"rect\":true,\"ang\":0.5,\"tomb\":false,\"emeralds\":false,\"range\":20}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":1,\"oy\":6,\"nx\":7,\"ny\":2},\"weapon\":1},\"bk:laser_cannon\":{\"id\":\"bk:laser_cannon\",\"time\":3,\"type\":7,\"single\":true,\"quality\":1,\"pool\":16777282,\"uses\":[{\"id\":\"bk:ShootLaser\",\"single\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"nx\":14,\"ny\":4,\"ox\":1,\"oy\":4},\"lock\":true,\"uprice\":3,\"weapon\":1},\"bk:treasure_key\":{\"id\":\"bk:treasure_key\",\"time\":0.400000005960464,\"type\":7,\"chance\":0,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":3,\"time\":0.25,\"single\":false,\"w\":14,\"h\":24,\"angle\":0,\"knockback\":0,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":0,\"oy\":3.5,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":12,\"ny\":3},\"weapon\":0},\"bk:pass\":{\"id\":\"bk:pass\",\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"gm\":true,\"crc\":0,\"md\":0,\"mimic\":0}],\"renderer\":{}},\"bk:bucket\":{\"id\":\"bk:bucket\",\"type\":1,\"single\":true,\"quality\":2,\"pool\":0,\"uses\":[{\"id\":\"bk:Bucket\",\"single\":false,\"wt\":false,\"snw\":false}],\"renderer\":{}},\"bk:water_bucket\":{\"id\":\"bk:water_bucket\",\"type\":1,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:Bucket\",\"single\":false,\"wt\":true,\"snw\":false}],\"renderer\":{}},\"bk:snow_bucket\":{\"id\":\"bk:snow_bucket\",\"type\":1,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:Bucket\",\"single\":false,\"wt\":false,\"snw\":true}],\"renderer\":{}},\"bk:broken_bucket\":{\"id\":\"bk:broken_bucket\",\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":13},\"bk:ankh\":{\"id\":\"bk:ankh\",\"single\":true,\"quality\":2,\"pool\":6324224,\"uses\":[{\"id\":\"bk:GivePhase\",\"single\":false}],\"renderer\":{}},\"bk:broken_ankh\":{\"id\":\"bk:broken_ankh\",\"single\":true,\"quality\":1,\"pool\":3227648,\"uses\":[{\"id\":\"bk:GivePhase\",\"single\":false,\"amount\":1,\"broken\":true}],\"renderer\":{}},\"bk:what\":{\"id\":\"bk:what\",\"time\":1,\"type\":7,\"single\":true,\"quality\":2,\"pool\":16810560,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":0,\"cursor\":false,\"damage\":1,\"amount\":1,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"color\":\"\",\"speed\":3,\"speedm\":3,\"dsb\":false,\"scale\":1,\"scalem\":1,\"ang\":0,\"prefab\":\"bk:what\",\"texture\":\"circle\",\"tomb\":false,\"emeralds\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":6,\"oy\":4,\"nx\":17,\"ny\":4},\"weapon\":1},\"bk:gold_minigun\":{\"id\":\"bk:gold_minigun\",\"time\":0.100000001490116,\"type\":7,\"single\":true,\"quality\":1,\"pool\":25182272,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":0,\"cursor\":false,\"damage\":1,\"amount\":1,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"speed\":20,\"speedm\":20,\"dsb\":false,\"scale\":1,\"scalem\":1,\"ang\":0,\"texture\":\"coin\",\"rect\":true,\"range\":20,\"knockback\":10,\"accuracy\":32,\"tomb\":false,\"emeralds\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"nx\":18,\"ny\":6,\"ox\":6,\"oy\":6},\"lock\":true,\"uprice\":99,\"weapon\":1},\"bk:gold_dagger\":{\"id\":\"bk:gold_dagger\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"quality\":2,\"pool\":16793664,\"uses\":[{\"id\":\"bk:MeleeArc\",\"single\":false,\"damage\":4,\"w\":24,\"h\":24,\"time\":0.200000002980232,\"angle\":0,\"knockback\":1,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\"}],\"renderer\":{\"id\":\"bk:Stick\",\"nx\":2.5,\"ny\":0,\"ox\":2.5,\"oy\":11,\"mv\":12},\"lock\":true,\"uprice\":99,\"weapon\":0},\"bk:gold_revolver\":{\"id\":\"bk:gold_revolver\",\"time\":0.5,\"type\":7,\"single\":true,\"quality\":1,\"pool\":50331712,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"single\":false,\"mana\":0,\"cursor\":false,\"damage\":4,\"amount\":1,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"speed\":15,\"speedm\":15,\"dsb\":false,\"scale\":2,\"scalem\":2,\"ang\":0,\"range\":5,\"prefab\":\"bk:soap\",\"knockback\":5,\"accuracy\":60,\"rect\":true,\"tomb\":false,\"emeralds\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":4,\"nx\":9,\"ny\":2},\"lock\":true,\"uprice\":99,\"weapon\":1},\"bk:gold_axe\":{\"id\":\"bk:gold_axe\",\"time\":0.300000011920929,\"type\":7,\"single\":true,\"quality\":2,\"pool\":16810048,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"gold_axe\",\"range\":0,\"speed\":15,\"damage\":1,\"amount\":1,\"speedm\":15,\"scale\":1,\"scalem\":1,\"rect\":true,\"dsb\":false,\"accuracy\":0,\"single\":false,\"modifiers\":[],\"cursor\":false,\"sfx\":\"item_axe_throw\",\"sfxn\":0,\"rsfx\":false,\"wait\":false,\"prefab\":\"bk:axe\",\"shells\":false,\"mana\":0,\"color\":\"\",\"ang\":0,\"tomb\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":1,\"oy\":13,\"nx\":7,\"ny\":3},\"lock\":true,\"uprice\":99,\"weapon\":0},\"bk:katana\":{\"id\":\"bk:katana\",\"time\":0.5,\"type\":7,\"single\":true,\"quality\":1,\"pool\":16777220,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":2,\"time\":0.25,\"w\":20,\"h\":30,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\",\"knockback\":2},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":false,\"chance\":1,\"damage\":1,\"mine\":false,\"rne\":false,\"buff\":\"bk:bleeding\",\"infinite_buff\":false,\"buff_time\":10}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":4,\"oy\":24,\"stay\":true,\"invert_back\":true,\"st\":0.0500000007450581,\"nx\":4,\"ny\":0,\"min_angle\":-20,\"max_angle\":200},\"weapon\":0},\"bk:smart_gun\":{\"id\":\"bk:smart_gun\",\"time\":0.400000005960464,\"type\":7,\"chance\":0.5,\"single\":true,\"quality\":2,\"pool\":83890240,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"damage\":1,\"amount\":1,\"speed\":10,\"speedm\":15,\"dsb\":false,\"scale\":1,\"scalem\":1,\"texture\":\"rect\",\"rect\":true,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_machine\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"tomb\":true,\"ang\":0,\"modifiers\":[],\"range\":5,\"knockback\":3,\"accuracy\":5,\"emeralds\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":5,\"oy\":7,\"nx\":16,\"ny\":4,\"invert_back\":false},\"lock\":true,\"uprice\":29,\"weapon\":1},\"bk:pop_gun\":{\"id\":\"bk:pop_gun\",\"time\":0.150000005960464,\"type\":7,\"single\":true,\"quality\":1,\"auto\":true,\"pool\":16785472,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"damage\":1,\"amount\":1,\"speed\":10,\"speedm\":15,\"dsb\":false,\"scale\":0.800000011920929,\"scalem\":1.20000004768372,\"texture\":\"shot\",\"rect\":true,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_machine\",\"sfxn\":0,\"rsfx\":false,\"shells\":true,\"color\":\"\",\"tomb\":false,\"ang\":0,\"modifiers\":[],\"range\":4,\"knockback\":0,\"accuracy\":48,\"prefab\":\"bk:shotgun\",\"emeralds\":false}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":5,\"oy\":7,\"nx\":16,\"ny\":4,\"invert_back\":false},\"lock\":true,\"uprice\":15,\"weapon\":1},\"bk:the_button\":{\"id\":\"bk:the_button\",\"time\":1,\"type\":1,\"chance\":0.5,\"single\":true,\"quality\":1,\"pool\":201330754,\"uses\":[{\"id\":\"bk:FireInAllDirs\",\"single\":false}],\"renderer\":{}},\"bk:gold_sword\":{\"id\":\"bk:gold_sword\",\"time\":0.400000005960464,\"type\":7,\"single\":true,\"quality\":2,\"pool\":16781376,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":5,\"time\":0.25,\"w\":18,\"h\":28,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\",\"knockback\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":3.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":3.5},\"lock\":true,\"uprice\":99,\"weapon\":0},\"bk:donut\":{\"id\":\"bk:donut\",\"single\":true,\"pool\":194,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":-0.300000011920929,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":1,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:sudoku\":{\"id\":\"bk:sudoku\",\"time\":5,\"type\":1,\"single\":true,\"quality\":1,\"pool\":37756994,\"uses\":[{\"id\":\"bk:KillMob\",\"all\":false,\"single\":false,\"half\":true}],\"renderer\":{}},\"bk:gps_ring\":{\"id\":\"bk:gps_ring\",\"single\":true,\"pool\":134742082,\"uses\":[{\"id\":\"bk:Random\",\"single\":false,\"uses\":[{\"id\":\"bk:RevealMap\",\"single\":false},{\"id\":\"bk:Poof\",\"single\":false}]}],\"renderer\":{}},\"bk:shield_potion\":{\"id\":\"bk:shield_potion\",\"time\":6,\"type\":1,\"single\":true,\"quality\":1,\"pool\":134742082,\"uses\":[{\"id\":\"bk:ModifyShieldHearts\",\"single\":false,\"amount\":1,\"to_min\":false,\"to_max\":false}],\"renderer\":{}},\"bk:trash_generator\":{\"id\":\"bk:trash_generator\",\"time\":5,\"type\":1,\"single\":true,\"quality\":1,\"pool\":2114,\"uses\":[{\"id\":\"bk:GiveRandomPickup\"}],\"renderer\":{}},\"bk:crabs_claw\":{\"id\":\"bk:crabs_claw\",\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":0.0500000007450581,\"samount\":false,\"amount\":1,\"sdamage\":false,\"damage\":1,\"srange\":false,\"range\":1,\"rne\":false,\"explosive\":false,\"buff\":\"bk:broken_armor\",\"infinite_buff\":true,\"buff_time\":1},{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":0.100000001490116,\"damage\":1,\"mine\":false,\"rne\":false,\"buff\":\"bk:broken_armor\",\"infinite_buff\":true,\"buff_time\":1}],\"renderer\":{}},\"bk:reverse_card\":{\"id\":\"bk:reverse_card\",\"single\":true,\"pool\":135331840,\"uses\":[{\"id\":\"bk:MakeRollKickProjectiles\"}],\"renderer\":{}},\"bk:magnet\":{\"id\":\"bk:magnet\",\"single\":true,\"quality\":3,\"pool\":578,\"uses\":[{\"id\":\"bk:MakeItemsAttact\"}],\"renderer\":{}},\"bk:glowing_mushroom\":{\"id\":\"bk:glowing_mushroom\",\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":39},\"bk:tinfoil_hat\":{\"id\":\"bk:tinfoil_hat\",\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":69},\"bk:rear_window\":{\"id\":\"bk:rear_window\",\"single\":true,\"quality\":1,\"pool\":134219782,\"uses\":[{\"id\":\"bk:ChanceToUseWeapon\",\"single\":false,\"back\":true,\"up\":false,\"down\":false,\"chance\":16}],\"renderer\":{}},\"bk:refractor\":{\"id\":\"bk:refractor\",\"single\":true,\"quality\":1,\"pool\":35667972,\"uses\":[{\"id\":\"bk:ChanceToUseWeapon\",\"single\":false,\"back\":true,\"up\":true,\"down\":true,\"chance\":33}],\"renderer\":{}},\"bk:fork\":{\"id\":\"bk:fork\",\"chance\":0.5,\"single\":true,\"quality\":2,\"pool\":2138116,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0.100000001490116,\"add_speed\":true,\"damage\":1.5,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true,\"ranged_rate\":0,\"add_ranged_rate\":true}],\"renderer\":{}},\"bk:rock\":{\"id\":\"bk:rock\",\"single\":true,\"quality\":1,\"pool\":38887432,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":-0.200000002980232,\"add_speed\":true,\"damage\":1,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true}],\"renderer\":{}},\"bk:coffee_grinder\":{\"id\":\"bk:coffee_grinder\",\"single\":true,\"quality\":2,\"pool\":1573458,\"uses\":[{\"id\":\"bk:ModifyProjectiles\",\"single\":false,\"any\":true,\"chance\":1,\"samount\":false,\"amount\":0.699999988079071,\"sdamage\":false,\"damage\":0.699999988079071,\"srange\":false,\"range\":2,\"rne\":false,\"explosive\":false},{\"id\":\"bk:ModifyProjectileTexture\",\"single\":false,\"texture\":\"circle\"},{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":1,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true,\"ranged_rate\":0,\"add_ranged_rate\":true}],\"renderer\":{}},\"bk:shawarma\":{\"id\":\"bk:shawarma\",\"single\":true,\"quality\":1,\"pool\":540744,\"uses\":[{\"id\":\"bk:ModEachAttack\",\"single\":false}],\"renderer\":{}},\"bk:cats_ear\":{\"id\":\"bk:cats_ear\",\"single\":true,\"quality\":1,\"pool\":8258,\"uses\":[{\"id\":\"bk:BlockDamage\",\"single\":false,\"chance\":10},{\"id\":\"bk:ModifyLuck\",\"single\":false}],\"renderer\":{}},\"bk:gamepad\":{\"id\":\"bk:gamepad\",\"single\":true,\"quality\":1,\"pool\":6,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0.5,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true},{\"id\":\"bk:ModifyLuck\",\"single\":false}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:hotdog\":{\"id\":\"bk:hotdog\",\"chance\":0.5,\"single\":true,\"quality\":1,\"pool\":2112,\"uses\":[{\"id\":\"bk:ModifyLuck\",\"single\":false},{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":false,\"bomb\":false,\"give_hp\":false}],\"renderer\":{}},\"bk:bomb_shell\":{\"id\":\"bk:bomb_shell\",\"single\":true,\"pool\":8454208,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"single\":true,\"set\":false,\"bomb\":true,\"amount\":2}],\"renderer\":{}},\"bk:gold_lamp\":{\"id\":\"bk:gold_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"gm\":false,\"sp\":true,\"tr\":false,\"crc\":0,\"md\":0,\"mimic\":0}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:sharp_lamp\":{\"id\":\"bk:sharp_lamp\",\"type\":13,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:ModifyMaxHp\",\"single\":false,\"set\":false,\"bomb\":false,\"amount\":2},{\"id\":\"bk:ModifyGen\",\"single\":false,\"xl\":false,\"gm\":false,\"sp\":false,\"tr\":false,\"ml\":true,\"crc\":0,\"md\":0,\"mimic\":0}],\"renderer\":{},\"lock\":true,\"uprice\":0},\"bk:ancient_sword\":{\"id\":\"bk:ancient_sword\",\"time\":0.5,\"type\":7,\"single\":true,\"pool\":0,\"uses\":[{\"id\":\"bk:MeleeArc\",\"damage\":6,\"time\":0.25,\"w\":14,\"h\":26,\"angle\":0,\"single\":false,\"hs\":\"item_sword_hit\",\"as\":\"item_sword_attack\",\"knockback\":0}],\"renderer\":{\"id\":\"bk:MovingAngled\",\"ox\":3.5,\"oy\":13,\"stay\":true,\"invert_back\":true,\"st\":0.150000005960464,\"nx\":3.5},\"weapon\":0},\"bk:emerald_gun\":{\"id\":\"bk:emerald_gun\",\"time\":3,\"type\":7,\"chance\":0.100000001490116,\"single\":true,\"quality\":2,\"pool\":0,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"texture\":\"big\",\"range\":30,\"speed\":20,\"damage\":60,\"amount\":1,\"speedm\":20,\"scale\":2,\"scalem\":2,\"rect\":false,\"dsb\":false,\"accuracy\":5,\"single\":false,\"modifiers\":[],\"cursor\":true,\"mana\":0,\"tomb\":false,\"sfx\":\"item_gun_fire\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"emeralds\":true,\"color\":\"green\",\"ang\":0},{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"p\":false,\"st\":true,\"bp\":true,\"fp\":true,\"iw\":false,\"im\":true}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":2,\"oy\":5,\"nx\":14,\"ny\":3},\"lock\":true,\"uprice\":999,\"weapon\":1},\"bk:party_hat\":{\"id\":\"bk:party_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":69},\"bk:police_hat\":{\"id\":\"bk:police_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":59},\"bk:spike_hat\":{\"id\":\"bk:spike_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":39},\"bk:hood\":{\"id\":\"bk:hood\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":29},\"bk:bullet_hat\":{\"id\":\"bk:bullet_hat\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":19},\"bk:spook\":{\"id\":\"bk:spook\",\"time\":2,\"type\":7,\"single\":true,\"quality\":2,\"pool\":18907140,\"uses\":[{\"id\":\"bk:SimpleShoot\",\"damage\":2,\"amount\":1,\"speed\":5,\"speedm\":5,\"dsb\":false,\"scale\":1,\"scalem\":1,\"texture\":\"skull\",\"rect\":false,\"single\":false,\"mana\":0,\"cursor\":false,\"sfx\":\"item_gun_machine\",\"sfxn\":0,\"rsfx\":true,\"shells\":true,\"color\":\"yellow\",\"tomb\":false,\"emeralds\":false,\"ang\":0,\"range\":1000,\"prefab\":\"bk:skull\",\"modifiers\":[],\"wait\":false},{\"id\":\"bk:MakeLayerPassable\",\"single\":false,\"p\":false,\"st\":false,\"bp\":false,\"fp\":true,\"im\":true}],\"renderer\":{\"id\":\"bk:Angled\",\"ox\":6,\"oy\":6,\"nx\":19,\"ny\":3.5},\"lock\":true,\"uprice\":32,\"weapon\":1},\"bk:mask\":{\"id\":\"bk:mask\",\"time\":0.100000001490116,\"type\":9,\"single\":true,\"pool\":0,\"uses\":[],\"renderer\":{},\"lock\":true,\"uprice\":9},\"bk:sword_polish\":{\"id\":\"bk:sword_polish\",\"single\":true,\"quality\":2,\"pool\":134283328,\"uses\":[{\"id\":\"bk:ModifyArc\",\"single\":false,\"any\":true,\"chance\":1,\"damage\":1,\"scale\":1.5,\"mine\":false,\"rne\":false}],\"renderer\":{},\"lock\":true,\"uprice\":48},\"bk:pumpkin_juice\":{\"id\":\"bk:pumpkin_juice\",\"single\":true,\"pool\":8324,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":1,\"add_fire_rate\":true,\"ranged_rate\":0,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":-3,\"add_range\":true}],\"renderer\":{}},\"bk:bouncy_glove\":{\"id\":\"bk:bouncy_glove\",\"single\":true,\"quality\":1,\"pool\":2,\"uses\":[{\"id\":\"bk:ModifyStats\",\"single\":false,\"speed\":0,\"add_speed\":true,\"damage\":0,\"add_damage\":true,\"fire_rate\":0,\"add_fire_rate\":true,\"ranged_rate\":0,\"add_ranged_rate\":true,\"accuracy\":0,\"add_accuracy\":true,\"range\":0,\"add_range\":true,\"knockback\":2,\"add_knockback\":true},{\"id\":\"bk:MakeProjectilesBounce\",\"single\":false}],\"renderer\":{}}}"
  },
  {
    "path": "BurningKnight/Content/keys.json",
    "content": "{\n\t\"left\" : [ \"A\" ],\n\t\"right\" : [ \"D\" ],\n\t\"up\" : [ \"W\" ],\n\t\"down\" : [ \"S\" ],\n\t\"move\" : [ \"left_stick\" ],\n\t\"cursor\": [ \"right_stick\" ],\n\n\t\"shift\" : [ \"L-Shift\", \"R-Shift\" ],\n\t\"roll\" : [ \"Mouse1\", \"button_leftshoulder\" ],\n\n\t\"use\" : [ \"Mouse0\", \"button_rightshoulder\" ],\n\t\"scroll\" : [ \"MouseWheel\" ],\n\t\"switch\" : [ \"L-Shift\", \"R-Shift\", \"button_b\" ],\n\t\"active\" : [ \"Space\", \"button_a\" ],\n\t\"bomb\" : [ \"Q\", \"button_y\" ],\n\n\t\"interact\" : [ \"E\", \"button_x\" ],\n\t\"pause\" : [ \"Escape\", \"button_back\" ],\n\t\"mouse\" : [ \"Mouse0\" ],\n\t\"start\" : [ \"Space\", \"Mouse0\", \"Mouse1\", \"button_start\", \"Return\", \"Enter\", \"button_x\", \"button_a\", \"button_rightshoulder\", \"button_leftshoulder\" ],\n\n\t\"map\" : [ \"Tab\", \"dpad_up\" ],\n\t\"toggle_minimap\" : [ \"M\" ],\n\t\"zoom_out\" : [ \"-\" ],\n\t\"zoom_in\" : [ \"=\" ],\n\n\t\"ui_up\" : [ \"Up\",  \"dpad_up\" ],\n\t\"ui_down\" : [ \"Down\", \"dpad_down\" ],\n\t\"ui_right\" : [ \"Right\",  \"dpad_right\" ],\n\t\"ui_left\" : [ \"Left\", \"dpad_left\" ],\n\t\"ui_accept\" : [ \"Mouse0\", \"Return\", \"Enter\", \"button_x\", \"button_a\", \"button_rightshoulder\", \"button_leftshoulder\" ]\n}"
  },
  {
    "path": "BurningKnight/Events.cs",
    "content": "using System;\n\nnamespace BurningKnight {\n\tpublic class Events {\n\t\tpublic static bool XMas;\n\t\tpublic static bool Halloween;\n\n\t\tstatic Events() {\n\t\t\tvar now = DateTime.Now;\n\n\t\t\tXMas = now.Month == 12 && now.Day < 26;\n\t\t\tHalloween = now.Month == 10;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"BurningKnight\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"BurningKnight\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2019\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"D31D0D40-105E-47D5-A5D0-F6E30328BF86\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]"
  },
  {
    "path": "BurningKnight/README.md",
    "content": "# Burning Knight Content\n\nThis is the juicy bit, the content of the game. The quality of code kept drifting lower and lower in the end of the project,\nbut please, give me some points for even just finishing this massive project.\n\nHave fun exploring the place, I recommend doing it inside of an IDE, Github is not too friendly for exploring huge amount of files.\n\nHere are some starting pointers for you:\n\n* [0x32a3bbaa](https://en.wikipedia.org/wiki/Memory_corruption)\n* [Player class](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/entity/creature/player/Player.cs)\n* [Level class](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/level/Level.cs)\n* [InGameState class (main game state)](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/state/InGameState.cs)"
  },
  {
    "path": "BurningKnight/Settings.cs",
    "content": "using BurningKnight.level;\nusing BurningKnight.save;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity.component.logic;\nusing Lens.graphics.gamerenderer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight {\n\tpublic class Settings {\n\t\t// Audio\n\t\tpublic static float MasterVolume {\n\t\t\tget => Audio.MasterVolume;\n\n\t\t\tset {\n\t\t\t\tAudio.MasterVolume = value;\n\t\t\t\tAudio.UpdateMusicVolume(Audio.MasterVolume * musicVolume);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate static float musicVolume;\n\t\tpublic static float MusicVolume {\n\t\t\tget => musicVolume;\n\n\t\t\tset {\n\t\t\t\tmusicVolume = value;\n\t\t\t\tAudio.UpdateMusicVolume(Audio.MasterVolume * musicVolume);\n\t\t\t}\n\t\t}\n\n\t\tpublic static float SfxVolume {\n\t\t\tget => Audio.SfxVolume;\n\t\t\tset => Audio.SfxVolume = value;\n\t\t}\n\t\t\n\t\t// Graphics\n\t\tpublic static bool Fullscreen;\n\t\tpublic static bool Vsync;\n\t\tpublic static bool Blood;\n\t\tpublic static bool UiSfx;\n\t\tpublic static bool Minimap;\n\t\tpublic static int Cursor;\n\t\tpublic static bool RotateCursor;\n\t\tpublic static float FreezeFrames;\n\t\tpublic static float FlashFrames;\n\t\tpublic static bool ShowFps;\n\t\tpublic static bool Flashes;\n\t\tpublic static bool LowQuality;\n\t\tpublic static bool Vignette;\n\n\t\tpublic static bool PixelPerfect {\n\t\t\tget => Engine.PixelPerfect;\n\t\t\tset => Engine.PixelPerfect = value;\n\t\t}\n\n\t\tprivate static float floorDarkness;\n\n\t\tpublic static float FloorDarkness {\n\t\t\tget => floorDarkness;\n\n\t\t\tset {\n\t\t\t\tfloorDarkness = value;\n\t\t\t\tLevel.FloorColor = new Color(floorDarkness, floorDarkness, floorDarkness, 1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic static float GameScale {\n\t\t\tget => PixelPerfectGameRenderer.GameScale;\n\t\t\tset => PixelPerfectGameRenderer.GameScale = value;\n\t\t}\n\n\t\t// Game\n\t\tpublic static bool SpeedrunMode;\n\t\tpublic static bool SpeedrunTimer;\n\t\tpublic static float Screenshake;\n\t\tpublic static bool Vegan;\n\t\tpublic static bool Autopause;\n\t\tpublic static bool Autosave;\n\t\tpublic static string Gamepad;\n\t\tpublic static bool Vibrate;\n\t\tpublic static float Sensivity;\n\t\tpublic static float CursorRadius;\n\t\tpublic static string Language;\n\t\n\t\t// Not saved\n\t\tpublic static bool HideUi;\n\t\tpublic static bool HideCursor;\n\n\t\tstatic Settings() {\n\t\t\tSetup();\n\t\t}\n\n\t\tpublic static void Setup() {\n\t\t\tFullscreen = true;\n\t\t\tShowFps = false;\n\t\t\tBlood = true;\n\t\t\tUiSfx = true;\n\t\t\tVsync = true;\n\t\t\tScreenshake = 0.35f;\n\t\t\tSpeedrunMode = false;\n\t\t\tSpeedrunTimer = false;\n\t\t\tFreezeFrames = 0.5f;\n\t\t\tFlashFrames = 0.5f;\n\t\t\tSfxVolume = 0.6f;\n\t\t\tMusicVolume = 0.4f;\n\t\t\tAudio.MasterVolume = 1f;\n\t\t\tCursor = 0;\n\t\t\tRotateCursor = false;\n\t\t\tVegan = false;\n\t\t\tVignette = true;\n\t\t\tAutopause = false;\n\t\t\tAutosave = true;\n\t\t\tGamepad = null;\n\t\t\tVibrate = true;\n\t\t\tSensivity = 1.5f;\n\t\t\tGameScale = 1f;\n\t\t\tFloorDarkness = 1f;\n\t\t\tPixelPerfect = false;\n\t\t\tCursorRadius = 1f;\n\t\t\tMinimap = true;\n\t\t\tFlashes = true;\n\t\t\tLowQuality = false;\n\t\t\tLanguage = Locale.PrefferedClientLanguage;\n\t\t\t\n\t\t\tShakeComponent.Modifier = Screenshake;\n\t\t\tEngine.FreezeModifier = FreezeFrames;\n\t\t\tEngine.FlashModifier = FlashFrames;\n\t\t\tEngine.Flashes = Flashes;\n\t\t}\n\t\t\n\t\tpublic static void Load() {\n\t\t\tFullscreen = GlobalSave.IsTrue(\"s_fullscreen\");\n\t\t\tShowFps = GlobalSave.IsTrue(\"s_fps\");\n\t\t\tBlood = GlobalSave.IsTrue(\"s_blood\");\n\t\t\tUiSfx = GlobalSave.IsTrue(\"s_uisfx\");\n\t\t\tVsync = GlobalSave.IsTrue(\"s_vsync\");\n\t\t\tSpeedrunMode = GlobalSave.IsTrue(\"s_sm\");\n\t\t\tSpeedrunTimer = GlobalSave.IsTrue(\"s_stmr\");\n\t\t\tScreenshake = GlobalSave.GetFloat(\"s_screenshake\");\n\t\t\tSfxVolume = GlobalSave.GetFloat(\"s_sfx\");\n\t\t\tFreezeFrames = GlobalSave.GetFloat(\"s_frf\");\n\t\t\tFlashFrames = GlobalSave.GetFloat(\"s_ff\");\n\t\t\tMusicVolume = GlobalSave.GetFloat(\"s_music\");\n\t\t\tMasterVolume = GlobalSave.GetFloat(\"s_master\");\n\t\t\tCursor = GlobalSave.GetInt(\"s_cursor\");\n\t\t\tRotateCursor = GlobalSave.IsTrue(\"s_rotate_cursor\", true);\n\t\t\tVegan = GlobalSave.IsTrue(\"s_v\", false);\n\t\t\tAutosave = GlobalSave.IsTrue(\"s_as\");\n\t\t\tAutopause = GlobalSave.IsTrue(\"s_ap\");\n\t\t\tGamepad = GlobalSave.GetString(\"s_gp\");\n\t\t\tVibrate = GlobalSave.IsTrue(\"s_vb\", true);\n\t\t\tMinimap = GlobalSave.IsTrue(\"s_mm\", true);\n\t\t\tFlashes = GlobalSave.IsTrue(\"s_fl\", true);\n\t\t\tVignette = GlobalSave.IsTrue(\"s_vgn\", true);\n\t\t\tLowQuality = GlobalSave.IsTrue(\"s_lq\", false);\n\t\t\tSensivity = GlobalSave.GetFloat(\"s_ss\", 1);\n\t\t\tGameScale = GlobalSave.GetFloat(\"s_gs\", 1);\n\t\t\tFloorDarkness = GlobalSave.GetFloat(\"s_fd\", 1);\n\t\t\tPixelPerfect = GlobalSave.IsTrue(\"s_pp\", false);\n\t\t\tCursorRadius = GlobalSave.GetFloat(\"s_cr\", 1);\n\t\t\tLanguage = GlobalSave.GetString(\"s_ln\", Locale.PrefferedClientLanguage);\n\t\t\tLocale.Load(Language);\n\n\t\t\tShakeComponent.Modifier = Screenshake;\n\t\t\tEngine.FreezeModifier = FreezeFrames;\n\t\t\tEngine.FlashModifier = FlashFrames;\n\t\t\tEngine.Flashes = Flashes;\n\t\t}\n\n\t\tpublic static void Save() {\n\t\t\tGlobalSave.Put(\"s_fullscreen\", Fullscreen);\n\t\t\tGlobalSave.Put(\"s_fps\", ShowFps);\n\t\t\tGlobalSave.Put(\"s_blood\", Blood);\n\t\t\tGlobalSave.Put(\"s_uisfx\", UiSfx);\n\t\t\tGlobalSave.Put(\"s_vsync\", Vsync);\n\t\t\tGlobalSave.Put(\"s_sm\", SpeedrunMode);\n\t\t\tGlobalSave.Put(\"s_stmr\", SpeedrunTimer);\n\t\t\tGlobalSave.Put(\"s_frf\", FreezeFrames);\n\t\t\tGlobalSave.Put(\"s_ff\", FlashFrames);\n\t\t\tGlobalSave.Put(\"s_screenshake\", Screenshake);\n\t\t\tGlobalSave.Put(\"s_sfx\", SfxVolume);\n\t\t\tGlobalSave.Put(\"s_music\", MusicVolume);\n\t\t\tGlobalSave.Put(\"s_master\", MasterVolume);\n\t\t\tGlobalSave.Put(\"s_cursor\", Cursor);\n\t\t\tGlobalSave.Put(\"s_rotate_cursor\", RotateCursor);\n\t\t\tGlobalSave.Put(\"s_v\", Vegan);\n\t\t\tGlobalSave.Put(\"s_as\", Autosave);\n\t\t\tGlobalSave.Put(\"s_ap\", Autopause);\n\t\t\tGlobalSave.Put(\"s_gp\", Gamepad);\n\t\t\tGlobalSave.Put(\"s_vb\", Vibrate);\n\t\t\tGlobalSave.Put(\"s_ss\", Sensivity);\n\t\t\tGlobalSave.Put(\"s_gs\", GameScale);\n\t\t\tGlobalSave.Put(\"s_fd\", FloorDarkness);\n\t\t\tGlobalSave.Put(\"s_pp\", PixelPerfect);\n\t\t\tGlobalSave.Put(\"s_cr\", CursorRadius);\n\t\t\tGlobalSave.Put(\"s_ln\", Language);\n\t\t\tGlobalSave.Put(\"s_mm\", Minimap);\n\t\t\tGlobalSave.Put(\"s_fl\", Flashes);\n\t\t\tGlobalSave.Put(\"s_lq\", LowQuality);\n\t\t\tGlobalSave.Put(\"s_vgn\", Vignette);\n\t\t}\n\n\t\tpublic static void Generate() {\n\t\t\tSetup();\n\t\t\tSave();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/Tags.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight {\n\tpublic class Tags {\n\t\tpublic static int Player = new BitTag(\"player\");\n\t\tpublic static int PlayerTarget = new BitTag(\"player_target\");\n\t\tpublic static int Cursor = new BitTag(\"cursor\");\n\t\tpublic static int Mob = new BitTag(\"mob\");\n\t\tpublic static int Boss = new BitTag(\"boss\");\n\t\tpublic static int BurningKnight = new BitTag(\"burning_knight\");\n\t\tpublic static int PlayerSave = new BitTag(\"player_save\");\n\t\tpublic static int LevelSave = new BitTag(\"level_save\");\n\t\tpublic static int Bomb = new BitTag(\"bomb\");\n\t\t\n\t\tpublic static int Room = new BitTag(\"room\");\n\t\tpublic static int TeleportTrigger = new BitTag(\"teleport_trigger\");\n\t\tpublic static int Lock = new BitTag(\"lock\");\n\t\tpublic static int MustBeKilled = new BitTag(\"must_be_killed\");\n\t\tpublic static int Teleport = new BitTag(\"teleport\");\n\t\tpublic static int Statue = new BitTag(\"statue\");\n\n\t\tpublic static int HasShadow = new BitTag(\"shadow\");\n\t\tpublic static int Mess = new BitTag(\"mess\");\n\t\t\n\t\tpublic static int Checkpoint = new BitTag(\"checkpoint\");\n\t\tpublic static int Entrance = new BitTag(\"entrance\");\n\t\tpublic static int HiddenEntrance = new BitTag(\"hidden_entrance\");\n\t\tpublic static int Item = new BitTag(\"item\");\n\t\tpublic static int ShopKeeper = new BitTag(\"shop_keeper\");\n\t\tpublic static int Npc = new BitTag(\"npc\");\n\n\t\tpublic static int Button = new BitTag(\"button\");\n\t\tpublic static int Chest = new BitTag(\"chest\");\n\t\tpublic static int Projectile = new BitTag(\"projectile\");\n\t\tpublic static int MobProjectile = new BitTag(\"mob_projectile\");\n\t\tpublic static int PlayerProjectile = new BitTag(\"player_projectile\");\n\n\t\tpublic static int Laser = new BitTag(\"laser\");\n\t\tpublic static int FireParticle = new BitTag(\"fire_particle\");\n\t\tpublic static int TextParticle = new BitTag(\"text_particle\");\n\t\tpublic static int Door = new BitTag(\"door\");\n\n\t\tpublic static string[] AllTags;\n\t\t\n\t\tstatic Tags() {\n\t\t\tAllTags = new string[BitTag.Total];\n\t\t\tvar i = 0;\n\t\t\t\n\t\t\tforeach (var t in BitTag.Tags) {\n\t\t\t\tAllTags[i] = t.Name;\n\t\t\t\t\n\t\t\t\ti++;\n\t\t\t\t\n\t\t\t\tif (i == BitTag.Total) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/CommonAse.cs",
    "content": "﻿using BurningKnight.entity.item;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.assets {\n\tpublic static class CommonAse {\n\t\tpublic static AnimationData Items;\n\t\tpublic static AnimationData Ui;\n\t\tpublic static AnimationData Projectiles;\n\t\tpublic static AnimationData Particles;\n\t\tpublic static AnimationData Props;\n\t\t\n\t\tpublic static TextureRegion Missing;\n\t\t\n\t\tpublic static void Load() {\n\t\t\tItems = Animations.Get(\"items\");\n\t\t\tUi = Animations.Get(\"ui\");\n\t\t\tProjectiles = Animations.Get(\"projectiles\");\n\t\t\tParticles = Animations.Get(\"particles\");\n\t\t\tProps = Animations.Get(\"props\");\n\n\t\t\tMissing = Items.GetSlice(\"missing\");\n\t\t\tTextures.Missing = Missing;\n\t\t\tItem.UnknownRegion = Items.GetSlice(\"unknown\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/Dialogs.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.ui.dialog;\r\nusing BurningKnight.ui.imgui;\r\nusing BurningKnight.ui.imgui.node;\r\nusing Lens.assets;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.assets {\r\n\tpublic static class Dialogs {\r\n\t\tprivate static Dictionary<string, Dialog> dialogs = new Dictionary<string, Dialog>();\r\n\r\n\t\tpublic static void RegisterCallback(string id, Func<Dialog, DialogComponent, Dialog> callback) {\r\n\t\t\tvar a = Get(id)?.Callbacks;\r\n\r\n\t\t\tif (a == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\ta.Clear();\r\n\t\t\ta.Add(callback);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Load() {\r\n\t\t\tvar dir = FileHandle.FromRoot(\"Dialogs\");\r\n\t\t\t\r\n\t\t\tforeach (var f in dir.ListFileHandles()) {\r\n\t\t\t\tif (f.Extension == \".json\") {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tvar name = f.NameWithoutExtension;\r\n\t\t\t\t\t\tvar root = JsonValue.Parse(f.ReadAll());\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t// Create nodes\r\n\t\t\t\t\t\tforeach (var vl in root.AsJsonArray) {\r\n\t\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t\tImNode.Create(name, vl);\r\n\t\t\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t// Connect em\r\n\t\t\t\t\t\tforeach (var node in ImNodes.Nodes) {\r\n\t\t\t\t\t\t\tnode.Value.ReadOutputs();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t// Parse\r\n\t\t\t\t\t\tforeach (var node in ImNodes.Nodes) {\r\n\t\t\t\t\t\t\tParseNode(node.Value);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tImNodes.Nodes.Clear();\r\n\t\t\t\t\t\tImNode.LastId = 0;\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate static void ParseNode(ImNode node) {\r\n\t\t\tif (node is DialogNode n) {\r\n\t\t\t\tAdd(n.Convert());\t\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Add(Dialog dialog) {\r\n\t\t\tdialogs[dialog.Id] = dialog;\r\n\t\t}\r\n\r\n\t\tpublic static Dialog Get(string id) {\r\n\t\t\tif (!dialogs.TryGetValue(id, out var dialog)) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\treturn dialog;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/Font.cs",
    "content": "﻿using Lens.assets;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended.BitmapFonts;\n\nnamespace BurningKnight.assets {\n\tpublic class Font {\n\t\tpublic static BitmapFont Small;\n\t\tpublic static BitmapFont Medium;\n\t\tpublic static SpriteFont Test;\n\t\t\n\t\tpublic static void Load() {\n\t\t\tSmall = LoadFont(\"Fonts/small_font\");\n\t\t\tMedium = LoadFont(\"Fonts/large_font\");\n\t\t\t// Test = Assets.Content.Load<SpriteFont>(\"Fonts/fnt\");\n\t\t}\n\n\t\tpublic static BitmapFont LoadFont(string name) {\n\t\t\treturn Assets.Content.Load<BitmapFont>(name);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/ImGuiHelper.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.ui.imgui;\r\nusing BurningKnight.ui.imgui.node;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.input;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing Vector2 = System.Numerics.Vector2;\r\n\r\nnamespace BurningKnight.assets {\r\n\tpublic static class ImGuiHelper {\r\n\t\tpublic static ImGuiRenderer Renderer;\r\n\t\tpublic static IntPtr ItemsTexture;\r\n\t\tpublic static IntPtr ProjectilesTexture;\r\n\t\tpublic static unsafe ImGuiTextFilterPtr filter2 = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\r\n\r\n\t\tpublic static void Init() {\r\n\t\t\ttry {\r\n\t\t\t\tRenderer = new ImGuiRenderer(Engine.Instance);\r\n\t\t\t\tImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 4f);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void BindTextures() {\r\n\t\t\ttry {\r\n\t\t\t\tItemsTexture = Renderer.BindTexture(CommonAse.Items.Texture);\r\n\t\t\t\tProjectilesTexture = Renderer.BindTexture(CommonAse.Projectiles.Texture);\r\n\t\t\t\tAssets.ImGuiEnabled = true;\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate static List<int> toRemove = new List<int>();\r\n\t\tprivate static bool loadedFont;\r\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\r\n\t\tprivate static Vector2 size = new Vector2(200, 400);\r\n\t\tprivate static Color gridColor = new Color(0.15f, 0.15f, 0.15f, 1f);\r\n\t\tprivate static Color gridMainColor = new Color(0.35f, 0.15f, 0.15f, 1f);\r\n\t\tprivate static int gridSize = 128;\r\n\t\tprivate static Vector2? target;\r\n\t\tprivate static bool grid = true;\r\n\t\t\r\n\t\tpublic static void Begin() {\r\n\t\t\tif (!loadedFont) {\r\n\t\t\t\tloadedFont = true;\r\n\t\t\t\tRenderer.RebuildFontAtlas();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tRenderer.BeforeLayout(Engine.GameTime);\r\n\t\t}\r\n\r\n\t\tpublic static void End() {\r\n\t\t\tRenderer.AfterLayout();\r\n\t\t}\r\n\r\n\t\tpublic static void ClearNodes() {\r\n\t\t\tImNodes.Nodes.Clear();\r\n\t\t\tImNode.LastId = 0;\r\n\t\t}\r\n\r\n\t\tpublic static void Node(ImNode node) {\r\n\t\t\tImNodes.Nodes[node.Id] = node;\r\n\t\t}\r\n\r\n\t\tpublic static bool BeforeRender() {\r\n\t\t\tif (grid) {\r\n\t\t\t\tvar list = ImGui.GetBackgroundDrawList();\r\n\r\n\t\t\t\tvar width = Engine.Instance.GetScreenWidth();\r\n\t\t\t\tvar height = Engine.Instance.GetScreenHeight();\r\n\t\t\t\tvar off = ImNode.Offset;\r\n\r\n\t\t\t\tfor (float x = off.X % gridSize; x <= width - off.X % gridSize; x += gridSize) {\r\n\t\t\t\t\tlist.AddLine(new Vector2(x, 0), new Vector2(x, height), ((int) (off.X - x) == 0 ? gridMainColor : gridColor).PackedValue);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (float y = off.Y % gridSize; y <= height - off.Y % gridSize; y += gridSize) {\r\n\t\t\t\t\tlist.AddLine(new Vector2(0, y), new Vector2(width, y), ((int) (off.Y - y) == 0 ? gridMainColor : gridColor).PackedValue);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tRenderVoidMenu();\r\n\r\n\t\t\tif (target.HasValue) {\r\n\t\t\t\tImNode.Offset += (target.Value - ImNode.Offset) * Engine.Delta * 10f;\r\n\r\n\t\t\t\tif ((target.Value - ImNode.Offset).Length() <= 3f) {\r\n\t\t\t\t\ttarget = null;\r\n\t\t\t\t}\r\n\t\t\t} else if (ImGui.IsMouseDragging(2) || Input.Keyboard.IsDown(Keys.Space, true)) {\r\n\t\t\t\tImNode.Offset += ImGui.GetIO().MouseDelta;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tforeach (var n in ImNodes.Nodes) {\r\n\t\t\t\tvar node = n.Value;\r\n\r\n\t\t\t\tif (!hideFiltred || filter.PassFilter(node.GetName())) {\r\n\t\t\t\t\tnode.Render();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (node.Done) {\r\n\t\t\t\t\ttoRemove.Add(n.Key);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tCurrentActive?.RemoveEmptyConnection();\r\n\r\n\t\t\tif (toRemove.Count > 0) {\r\n\t\t\t\tvar c = ImNodes.Nodes.Count - 1;\r\n\t\t\t\t\r\n\t\t\t\tforeach (var k in toRemove) {\r\n\t\t\t\t\tif (ImNodes.Nodes[k].Id == c) {\r\n\t\t\t\t\t\tImNode.LastId--;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tImNodes.Nodes.Remove(k);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\ttoRemove.Clear();\r\n\t\t\t}\r\n\r\n\t\t\tif (pasted != null) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tvar root = JsonValue.Parse(pasted);\r\n\r\n\t\t\t\t\tif (root.IsJsonObject) {\r\n\t\t\t\t\t\tvar val = root[\"imnode\"];\r\n\t\t\t\t\t\tvar node = ImNode.Create(val, true);\r\n\r\n\t\t\t\t\t\tif (node != null) {\r\n\t\t\t\t\t\t\tnode.New = true;\r\n\t\t\t\t\t\t\tnode.Position = ImGui.GetIO().MousePos;\r\n\t\t\t\t\t\t\tImNode.Focused = node;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpasted = null;\r\n\t\t\t}\r\n\r\n\t\t\tif (toAdd != null) {\r\n\t\t\t\tvar node = ImNodeRegistry.Create(toAdd);\r\n\t\t\t\t\r\n\t\t\t\tif (node != null) {\r\n\t\t\t\t\tnode.New = true;\r\n\t\t\t\t\tnode.Position = ImGui.GetIO().MousePos;\r\n\t\t\t\t\tnode.File = DialogEditor.Current;\r\n\t\t\t\t\tImNode.Focused = node;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tNode(node);\r\n\t\t\t\ttoAdd = null;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\r\n\r\n\t\t\tif (!ImGui.Begin(\"Nodes\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tpublic static void RenderNodes() {\r\n\t\t\tImGui.Checkbox(\"Show grid\", ref grid);\r\n\r\n\t\t\tfilter.Draw(\"Filter\");\r\n\t\t\tImGui.Checkbox(\"Hide filtred\", ref hideFiltred);\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tRenderMenu();\r\n\r\n\t\t\tImNode first = null;\r\n\t\t\tvar sawFocused = false;\r\n\t\t\t\r\n\t\t\tforeach (var p in ImNodes.Nodes) {\r\n\t\t\t\tvar node = p.Value;\r\n\t\t\t\tvar name = node.GetName();\r\n\r\n\t\t\t\tif (!filter.PassFilter(name)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (first == null) {\r\n\t\t\t\t\tfirst = node;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (ImNode.Focused == node) {\r\n\t\t\t\t\tnode.ForceFocus = true;\r\n\t\t\t\t\tsawFocused = true;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Selectable($\"#{node.Id} {name}\", ImNode.Focused == node)) {\r\n\t\t\t\t\tImNode.Focused = node;\r\n\t\t\t\t\tnode.ForceFocus = true;\r\n\t\t\t\t\tsawFocused = true;\r\n\r\n\t\t\t\t\ttarget =\r\n\t\t\t\t\t\t-node.RealPosition + new Vector2((Engine.Instance.GetScreenWidth() - node.Size.X) / 2,\r\n\t\t\t\t\t\t\t(Engine.Instance.GetScreenHeight() - node.Size.Y) / 2);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (ImGui.OpenPopupOnItemClick(\"node_menu\", 1)) {\r\n\t\t\t\t\tCurrentMenu = node;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!sawFocused) {\r\n\t\t\t\tImNode.Focused = first;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\r\n\t\tpublic static ImNode CurrentMenu;\r\n\t\tprivate static string pasted;\r\n\t\tprivate static string toAdd;\r\n\t\tprivate static bool hideFiltred;\r\n\r\n\t\tpublic static void RenderPaste() {\r\n\t\t\tif (ImGui.Selectable(\"Paste (Ctrl+V)\")) {\r\n\t\t\t\tPaste();\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderVoidMenu() {\r\n\t\t\tif (ImGui.BeginPopupContextVoid(\"void_menu\")) {\r\n\t\t\t\tRenderPaste();\r\n\t\t\t\tRenderAddNew();\r\n\t\t\t}\r\n\r\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftControl, true) || Input.Keyboard.IsDown(Keys.RightControl, true)) {\r\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.C, true)) {\r\n\t\t\t\t\tCopy(false);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.V, true)) {\r\n\t\t\t\t\tPaste();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D, true) && ImNode.Focused != null) {\r\n\t\t\t\t\tImNode.Focused.Remove();\r\n\t\t\t\t}\t\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate static void RenderAddNew() {\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tforeach (var p in ImNodeRegistry.Defined) {\r\n\t\t\t\tif (ImGui.Selectable(p.Key)) {\r\n\t\t\t\t\ttoAdd = p.Key;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tprivate static void Copy(bool menu = true) {\r\n\t\t\tvar root = new JsonObject();\r\n\r\n\t\t\tif (menu && CurrentMenu != null) {\r\n\t\t\t\tCurrentMenu.Save(root);\r\n\t\t\t} else if (ImNode.Focused != null) {\r\n\t\t\t\tImNode.Focused.Save(root);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetClipboardText($\"{{ \\\"imnode\\\" : {root} }}\");\r\n\t\t}\r\n\r\n\t\tprivate static void Paste() {\r\n\t\t\ttry {\r\n\t\t\t\tvar text = ImGui.GetClipboardText();\r\n\t\t\t\tpasted = text;\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error(e);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderMenu(bool window = false) {\r\n\t\t\tif (window ? ImGui.BeginPopupContextWindow(\"window_node_menu\", 1) : ImGui.BeginPopupContextItem(\"node_menu\", 1)) {\r\n\t\t\t\tif (ImGui.Selectable(\"Copy (Ctrl+C)\")) {\r\n\t\t\t\t\tCopy();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tRenderPaste();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Selectable(\"Delete (Ctrl+D)\")) {\r\n\t\t\t\t\tCurrentMenu.Remove();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tRenderAddNew();\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static ImNode CurrentActive;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/Palette.cs",
    "content": "﻿using System.Collections.Generic;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets {\n\tpublic static class Palette {\n\t\tpublic static Dictionary<string, Color> Colors = new Dictionary<string, Color>();\n\t\t\n\t\tpublic static Color[] Default = new[] {\n\t\t\tColorUtils.FromHex(\"#ff0040\"),\n\t\t\tColorUtils.FromHex(\"#131313\"),\n\t\t\tColorUtils.FromHex(\"#1b1b1b\"),\n\t\t\tColorUtils.FromHex(\"#272727\"),\n\t\t\tColorUtils.FromHex(\"#3d3d3d\"),\n\t\t\tColorUtils.FromHex(\"#5d5d5d\"),\n\t\t\tColorUtils.FromHex(\"#858585\"),\n\t\t\tColorUtils.FromHex(\"#b4b4b4\"),\n\t\t\tColorUtils.FromHex(\"#ffffff\"),\n\t\t\tColorUtils.FromHex(\"#c7cfdd\"),\n\t\t\tColorUtils.FromHex(\"#92a1b9\"),\n\t\t\tColorUtils.FromHex(\"#657392\"),\n\t\t\tColorUtils.FromHex(\"#424c6e\"),\n\t\t\tColorUtils.FromHex(\"#2a2f4e\"),\n\t\t\tColorUtils.FromHex(\"#1a1932\"),\n\t\t\tColorUtils.FromHex(\"#0e071b\"),\n\t\t\tColorUtils.FromHex(\"#1c121c\"),\n\t\t\tColorUtils.FromHex(\"#391f21\"),\n\t\t\tColorUtils.FromHex(\"#5d2c28\"),\n\t\t\tColorUtils.FromHex(\"#8a4836\"),\n\t\t\tColorUtils.FromHex(\"#bf6f4a\"),\n\t\t\tColorUtils.FromHex(\"#e69c69\"),\n\t\t\tColorUtils.FromHex(\"#f6ca9f\"),\n\t\t\tColorUtils.FromHex(\"#f9e6cf\"),\n\t\t\tColorUtils.FromHex(\"#edab50\"),\n\t\t\tColorUtils.FromHex(\"#e07438\"),\n\t\t\tColorUtils.FromHex(\"#c64524\"),\n\t\t\tColorUtils.FromHex(\"#8e251d\"),\n\t\t\tColorUtils.FromHex(\"#ff5000\"),\n\t\t\tColorUtils.FromHex(\"#ed7614\"),\n\t\t\tColorUtils.FromHex(\"#ffa214\"),\n\t\t\tColorUtils.FromHex(\"#ffc825\"),\n\t\t\tColorUtils.FromHex(\"#ffeb57\"),\n\t\t\tColorUtils.FromHex(\"#d3fc7e\"),\n\t\t\tColorUtils.FromHex(\"#99e65f\"),\n\t\t\tColorUtils.FromHex(\"#5ac54f\"),\n\t\t\tColorUtils.FromHex(\"#33984b\"),\n\t\t\tColorUtils.FromHex(\"#1e6f50\"),\n\t\t\tColorUtils.FromHex(\"#134c4c\"),\n\t\t\tColorUtils.FromHex(\"#0c2e44\"),\n\t\t\tColorUtils.FromHex(\"#00396d\"),\n\t\t\tColorUtils.FromHex(\"#0069aa\"),\n\t\t\tColorUtils.FromHex(\"#0098dc\"),\n\t\t\tColorUtils.FromHex(\"#00cdf9\"),\n\t\t\tColorUtils.FromHex(\"#0cf1ff\"),\n\t\t\tColorUtils.FromHex(\"#94fdff\"),\n\t\t\tColorUtils.FromHex(\"#fdd2ed\"),\n\t\t\tColorUtils.FromHex(\"#f389f5\"),\n\t\t\tColorUtils.FromHex(\"#db3ffd\"),\n\t\t\tColorUtils.FromHex(\"#7a09fa\"),\n\t\t\tColorUtils.FromHex(\"#3003d9\"),\n\t\t\tColorUtils.FromHex(\"#0c0293\"),\n\t\t\tColorUtils.FromHex(\"#03193f\"),\n\t\t\tColorUtils.FromHex(\"#3b1443\"),\n\t\t\tColorUtils.FromHex(\"#622461\"),\n\t\t\tColorUtils.FromHex(\"#93388f\"),\n\t\t\tColorUtils.FromHex(\"#ca52c9\"),\n\t\t\tColorUtils.FromHex(\"#c85086\"),\n\t\t\tColorUtils.FromHex(\"#f68187\"),\n\t\t\tColorUtils.FromHex(\"#f5555d\"),\n\t\t\tColorUtils.FromHex(\"#ea323c\"),\n\t\t\tColorUtils.FromHex(\"#c42430\"),\n\t\t\tColorUtils.FromHex(\"#891e2b\"),\n\t\t\tColorUtils.FromHex(\"#571c27\")\n\t\t};\n\n\t\tstatic Palette() {\n\t\t\tDefine(\"red\", Default[60]);\n\t\t\tDefine(\"green\", Default[36]);\n\t\t\tDefine(\"blue\", Default[41]);\n\t\t\tDefine(\"yellow\", Default[32]);\n\t\t\tDefine(\"orange\", Default[30]);\n\t\t\tDefine(\"brown\", Default[20]);\n\t\t\tDefine(\"gray\", Default[6]);\n\t\t\tDefine(\"purple\", Default[56]);\n\t\t\tDefine(\"pink\", Default[59]);\n\t\t\tDefine(\"lime\", Default[34]);\n\t\t\tDefine(\"blue\", Default[11]);\n\t\t\tDefine(\"cyan\", Default[43]);\n\t\t}\n\n\t\tpublic static void Define(string s, Color c) {\n\t\t\tColors[s] = c;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/Shaders.cs",
    "content": "﻿using Lens;\nusing Lens.assets;\nusing Lens.graphics.gamerenderer;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.assets {\n\tpublic class Shaders {\n\t\tpublic static Effect Ui;\n\t\tpublic static Effect Entity;\n\t\tpublic static Effect Terrain;\n\t\tpublic static Effect Screen;\n\t\tpublic static Effect Fog;\n\t\tpublic static Effect Chasm;\n\t\tpublic static Effect Item;\n\t\tpublic static Effect Bk;\n\t\t\n\t\tpublic static void Load() {\n\t\t\tUi = Effects.Get(\"ui\");\n\t\t\tEntity = Effects.Get(\"entity\");\n\t\t\tTerrain = Effects.Get(\"terrain\");\n\t\t\tScreen = Effects.Get(\"screen\");\n\t\t\tFog = Effects.Get(\"fog\");\n\t\t\tChasm = Effects.Get(\"chasm\");\n\t\t\tItem = Effects.Get(\"item\");\n\t\t\tBk = Effects.Get(\"bk\");\n\n\t\t\tEngine.Instance.StateRenderer.GameEffect = Screen;\n\t\t\t// Engine.Instance.StateRenderer.UiEffect = Ui;\n\t\t}\n\n\t\tpublic static void Begin(Effect effect) {\n\t\t\tvar state = Engine.Instance.StateRenderer;\n\t\t\t\n\t\t\tstate.End();\n\t\t\tstate.SurfaceEffect = effect;\n\t\t\tstate.SpriteSortMode = SpriteSortMode.Immediate;\n\t\t\teffect.CurrentTechnique.Passes[0].Apply();\n\t\t\tstate.Begin();\n\t\t}\n\n\t\tpublic static void End() {\n\t\t\tvar state = Engine.Instance.StateRenderer;\n\t\t\t\n\t\t\tstate.End();\n\t\t\tstate.SpriteSortMode = GameRenderer.DefaultSortMode;\n\t\t\tstate.SurfaceEffect = null;\n\t\t\tstate.Begin();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/achievements/Achievement.cs",
    "content": "using Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.assets.achievements {\n\tpublic class Achievement {\n\t\tpublic readonly string Id;\n\t\tpublic bool Unlocked { get; internal set; }\n\t\tpublic int Max;\n\t\tpublic string Unlock = \"\";\n\t\tpublic bool Secret;\n\t\tpublic string Group = \"\";\n\t\tpublic string CompletionDate = \"???\";\n\t\t\n\t\tpublic Achievement(string id) {\n\t\t\tId = id;\n\t\t}\n\n\t\tpublic void Load(JsonValue root) {\n\t\t\tMax = root[\"max\"].Int(0);\n\t\t\tUnlock = root[\"unlock\"].String(\"\");\n\t\t\tSecret = root[\"secret\"].Bool(false);\n\t\t\tGroup = root[\"group\"].String(\"\");\n\t\t}\n\n\t\tpublic void Save(JsonValue root) {\n\t\t\tif (Max > 0) {\n\t\t\t\troot[\"max\"] = Max;\n\t\t\t}\n\n\t\t\tif (Unlock.Length > 0) {\n\t\t\t\troot[\"unlock\"] = Unlock;\n\t\t\t}\n\n\t\t\tif (Secret) {\n\t\t\t\troot[\"secret\"] = true;\n\t\t\t}\n\n\t\t\tif (Group.Length > 0) {\n\t\t\t\troot[\"group\"] = Group;\n\t\t\t}\n\t\t}\n\n\t\tpublic class UnlockedEvent : Event {\n\t\t\tpublic Achievement Achievement;\n\t\t}\n\n\t\tpublic class LockedEvent : Event {\n\t\t\tpublic Achievement Achievement;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/achievements/Achievements.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.save;\r\nusing BurningKnight.ui.imgui;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.input;\r\nusing Lens.lightJson;\r\nusing Lens.lightJson.Serialization;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace BurningKnight.assets.achievements {\r\n\tpublic delegate void AchievementUnlockedCallback(string id);\r\n\tpublic delegate void AchievementLockedCallback(string id);\r\n\tpublic delegate void AchievementProgressSetCallback(string id, int progress, int max);\r\n\t\r\n\tpublic static class Achievements {\r\n\t\tpublic static Dictionary<string, Achievement> Defined = new Dictionary<string, Achievement>();\r\n\t\tpublic static List<string> AchievementBuffer = new List<string>();\r\n\t\tpublic static List<string> ItemBuffer = new List<string>();\r\n\r\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\r\n\r\n\t\tpublic static AchievementUnlockedCallback UnlockedCallback;\r\n\t\tpublic static AchievementLockedCallback LockedCallback;\r\n\t\tpublic static AchievementProgressSetCallback ProgressSetCallback;\r\n\t\tpublic static Action PostLoadCallback;\r\n\t\t\r\n\t\tpublic static Achievement Get(string id) {\r\n\t\t\treturn Defined.TryGetValue(id, out var a) ? a : null;\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Load() {\r\n\t\t\tLoad(FileHandle.FromRoot(\"achievements.json\"));\r\n\t\t\tLoadState();\r\n\t\t}\r\n\r\n\t\tprivate static void Load(FileHandle handle) {\r\n\t\t\tif (!handle.Exists()) {\r\n\t\t\t\tLog.Error($\"Achievement data {handle.FullPath} does not exist!\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar root = JsonValue.Parse(handle.ReadAll());\r\n\r\n\t\t\tforeach (var item in root.AsJsonObject) {\r\n\t\t\t\tvar a = new Achievement(item.Key);\r\n\t\t\t\ta.Load(item.Value);\r\n\t\t\t\tDefined[item.Key] = a;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Save() {\r\n\t\t\tvar root = new JsonObject();\r\n\r\n\t\t\tforeach (var a in Defined.Values) {\r\n\t\t\t\tvar data = new JsonObject();\r\n\t\t\t\ta.Save(data);\r\n\t\t\t\troot[a.Id] = data;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar file = File.CreateText(FileHandle.FromRoot(\"achievements.json\").FullPath);\r\n\t\t\tvar writer = new JsonWriter(file);\r\n\t\t\twriter.Write(root);\r\n\t\t\tfile.Close();\r\n\r\n\t\t\tLocale.Save();\r\n\t\t}\r\n\r\n\t\tpublic static void LockAll() {\r\n\t\t\ttry {\r\n\t\t\t\tforeach (var a in Defined.Values) {\r\n\t\t\t\t\ta.Unlocked = false;\r\n\t\t\t\t}\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error(e);\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void LoadState() {\r\n\t\t\tforeach (var a in Defined.Values) {\r\n\t\t\t\ta.Unlocked = GlobalSave.IsTrue($\"ach_{a.Id}\");\r\n\t\t\t\ta.CompletionDate = GlobalSave.GetString($\"ach_{a.Id}_date\", \"???\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void SetProgress(string id, int progress, int max = -1) {\r\n\t\t\tif (Assets.DataModified) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (progress == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar a = Get(id);\r\n\r\n\t\t\tif (a == null) {\r\n\t\t\t\tLog.Error($\"Unknown achievement {id}!\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (a.Unlocked) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (max == -1) {\r\n\t\t\t\tLog.Info($\"Reading max as {a.Max} for {id}\");\r\n\t\t\t\tmax = a.Max;\r\n\t\t\t}\r\n\r\n\t\t\tif (max == 0) {\r\n\t\t\t\tLog.Error($\"Max for {id} is 0\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar idt = $\"ach_{a.Id}\";\r\n\r\n\t\t\tif (progress < max) {\r\n\t\t\t\tGlobalSave.Put(idt, progress);\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\tProgressSetCallback?.Invoke(id, progress, max);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error(e);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (progress >= max) {\r\n\t\t\t\tLog.Info($\"Progress {progress} is >= than {max} for {id}\");\r\n\t\t\t\tReallyUnlock(id, a);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Unlock(string id) {\r\n\t\t\tif (Assets.DataModified) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar a = Get(id);\r\n\r\n\t\t\tif (a == null) {\r\n\t\t\t\tLog.Error($\"Unknown achievement {id}!\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (a.Unlocked || GlobalSave.IsTrue($\"ach_{a.Id}\")) {\r\n\t\t\t\ta.Unlocked = true;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tReallyUnlock(id, a);\r\n\t\t}\r\n\r\n\t\tprivate static void ReallyUnlock(string id, Achievement a) {\r\n\t\t\ta.Unlocked = true;\r\n\t\t\ta.CompletionDate = DateTime.Now.ToString(\"dd/MM/yyy\");\r\n\t\t\t\r\n\t\t\tGlobalSave.Put($\"ach_{a.Id}\", true);\r\n\t\t\tGlobalSave.Put($\"ach_{a.Id}_date\", a.CompletionDate);\r\n\t\t\t\r\n\t\t\tLog.Info($\"Achievement {id} was complete on {a.CompletionDate}!\");\r\n\r\n\t\t\tvar e = new Achievement.UnlockedEvent {\r\n\t\t\t\tAchievement = a\r\n\t\t\t};\r\n\r\n\t\t\tEngine.Instance?.State?.Area?.EventListener?.Handle(e);\r\n\t\t\tEngine.Instance?.State?.Ui?.EventListener?.Handle(e);\r\n\r\n\t\t\tif (!string.IsNullOrEmpty(a.Unlock)) {\r\n\t\t\t\tItems.Unlock(a.Unlock);\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\tUnlockedCallback?.Invoke(id);\r\n\t\t\t} catch (Exception ex) {\r\n\t\t\t\tLog.Error(ex);\r\n\t\t\t}\r\n\r\n\t\t\tif (!AchievementBuffer.Contains(id)) {\r\n\t\t\t\tAchievementBuffer.Add(id);\r\n\t\t\t}\r\n\r\n\t\t\tvar area = Engine.Instance?.State?.Area;\r\n\t\t\t\r\n\t\t\tif (area != null) {\r\n\t\t\t\tvar player = LocalPlayer.Locate(area);\r\n\r\n\t\t\t\tif (player != null) {\r\n\t\t\t\t\tAnimationUtil.Confetti(player.Center);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Lock(string id) {\r\n\t\t\tvar a = Get(id);\r\n\r\n\t\t\tif (a == null) {\r\n\t\t\t\tLog.Error($\"Unknown achievement {id}!\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!a.Unlocked) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\ta.Unlocked = false;\r\n\t\t\tGlobalSave.Put($\"ach_{a.Id}\", false);\r\n\t\t\t\r\n\t\t\tLog.Info($\"Achievement {id} was locked!\");\r\n\r\n\t\t\tvar e = new Achievement.LockedEvent {\r\n\t\t\t\tAchievement = a\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tEngine.Instance.State.Area.EventListener.Handle(e);\r\n\t\t\tEngine.Instance.State.Ui.EventListener.Handle(e);\r\n\t\t\t\r\n\t\t\ttry {\r\n\t\t\t\tLockedCallback?.Invoke(id);\r\n\t\t\t} catch (Exception ex) {\r\n\t\t\t\tLog.Error(ex);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tprivate static string achievementName = \"\";\r\n\t\tprivate static Achievement selected;\r\n\t\tprivate static bool hideLocked;\r\n\t\tprivate static bool hideUnlocked;\r\n\t\tprivate static bool forceFocus;\r\n\r\n\t\tprivate static void RenderSelectedInfo() {\r\n\t\t\tvar open = true;\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Achievement\", ref open, ImGuiWindowFlags.AlwaysAutoResize)) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!open) {\r\n\t\t\t\tselected = null;\r\n\t\t\t\tImGui.End();\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Text(selected.Id);\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tImGui.InputText(\"Unlocks\", ref selected.Unlock, 128);\r\n\t\t\tImGui.InputText(\"Group\", ref selected.Group, 128);\r\n\r\n\t\t\tImGui.InputInt(\"Max progress\", ref selected.Max);\r\n\t\t\tImGui.Checkbox(\"Secret\", ref selected.Secret);\r\n\t\t\t\r\n\t\t\tvar u = selected.Unlocked;\r\n\t\t\t\r\n\t\t\tif (ImGui.Checkbox(\"Unlocked\", ref u)) {\r\n\t\t\t\tif (u) {\r\n\t\t\t\t\tUnlock(selected.Id);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tLock(selected.Id);\r\n\t\t\t\t}\t\t\t\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Delete##ach\")) {\r\n\t\t\t\tDefined.Remove(selected.Id);\r\n\t\t\t\tselected = null;\r\n\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tvar k = $\"ach_{selected.Id}\";\r\n\t\t\tvar name = Locale.Get(k);\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Name##ac\", ref name, 64)) {\r\n\t\t\t\tLocale.Map[k] = name;\r\n\t\t\t}\r\n\r\n\t\t\tvar key = $\"ach_{selected.Id}_desc\";\r\n\t\t\tvar desc = Locale.Get(key);\r\n\t\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Description##ac\", ref desc, 256)) {\r\n\t\t\t\tLocale.Map[key] = desc;\r\n\t\t\t}\r\n\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\r\n\t\tprivate static int count;\r\n\t\t\r\n\t\tpublic static void RenderDebug() {\r\n\t\t\tif (!WindowManager.Achievements) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (selected != null) {\r\n\t\t\t\tRenderSelectedInfo();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\r\n\r\n\t\t\tif (!ImGui.Begin(\"Achievements\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Button(\"New\")) {\r\n\t\t\t\tImGui.OpenPopup(\"New achievement\");\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Save\")) {\r\n\t\t\t\tLog.Info(\"Saving achievements\");\r\n\t\t\t\tSave();\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"New achievement\")) {\r\n\t\t\t\tImGui.PushItemWidth(300);\r\n\t\t\t\tImGui.InputText(\"Id\", ref achievementName, 64);\r\n\t\t\t\tImGui.PopItemWidth();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Create\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\r\n\t\t\t\t\tDefined[achievementName] = selected = new Achievement(achievementName);\r\n\t\t\t\t\tachievementName = \"\";\r\n\t\t\t\t\tforceFocus = true;\r\n\t\t\t\t\t\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\t\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\r\n\t\t\t\t\tachievementName = \"\";\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tif (ImGui.Button(\"Unlock all\")) {\r\n\t\t\t\tforeach (var a in Defined.Keys) {\r\n\t\t\t\t\tUnlock(a);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Lock all\")) {\r\n\t\t\t\tforeach (var a in Defined.Keys) {\r\n\t\t\t\t\tLock(a);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\tImGuiHelper.filter2.Draw(\"Search\");\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\t\t\tImGui.Text($\"{count}\");\r\n\t\t\tcount = 0;\r\n\r\n\t\t\tImGui.Checkbox(\"Hide unlocked\", ref hideUnlocked);\r\n\t\t\tImGui.SameLine();\r\n\t\t\tImGui.Checkbox(\"Hide locked\", ref hideLocked);\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y;\r\n\t\t\tImGui.BeginChild(\"ScrollingRegionItems\", new System.Numerics.Vector2(0, -height), \r\n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\r\n\r\n\t\t\tforeach (var i in Defined.Values) {\r\n\t\t\t\tImGui.PushID(i.Id);\r\n\r\n\t\t\t\tif (forceFocus && i == selected) {\r\n\t\t\t\t\tImGui.SetScrollHereY();\r\n\t\t\t\t\tforceFocus = false;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (ImGuiHelper.filter2.PassFilter(i.Id)) {\r\n\t\t\t\t\tif ((hideLocked && !i.Unlocked) || (hideUnlocked && i.Unlocked)) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcount++;\r\n\r\n\t\t\t\t\tif (ImGui.Selectable(i.Id, i == selected)) {\r\n\t\t\t\t\t\tselected = i;\r\n\r\n\t\t\t\t\t\tif (ImGui.IsMouseDown(1)) {\r\n\t\t\t\t\t\t\tif (ImGui.Button(\"Give\")) {\r\n\t\t\t\t\t\t\t\tLocalPlayer.Locate(Engine.Instance.State.Area)\r\n\t\t\t\t\t\t\t\t\t?.GetComponent<InventoryComponent>()\r\n\t\t\t\t\t\t\t\t\t.Pickup(Items.CreateAndAdd(\r\n\t\t\t\t\t\t\t\t\t\tselected.Id, Engine.Instance.State.Area\r\n\t\t\t\t\t\t\t\t\t), true);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.PopID();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.EndChild();\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\r\n\t\tpublic static bool IsComplete(string id) {\r\n\t\t\tvar ach = Get(id);\r\n\t\t\treturn ach != null && ach.Unlocked;\r\n\t\t}\r\n\r\n\t\tpublic static bool IsGroupComplete(string group) {\r\n\t\t\tvar found = false;\r\n\r\n\t\t\tforeach (var a in Defined.Values) {\r\n\t\t\t\tif (a.Group == group) {\r\n\t\t\t\t\tfound = true;\r\n\r\n\t\t\t\t\tif (!a.Unlocked) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn found;\r\n\t\t} \r\n\t}\r\n}\r\n"
  },
  {
    "path": "BurningKnight/assets/input/Control.cs",
    "content": "using Lens.input;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.assets.input {\n\tpublic class Control {\n\t\tpublic Keys[] Keys;\n\t\tpublic MouseButtons[] MouseButtons;\n\t\tpublic Buttons[] Buttons;\n\t\tpublic string Id;\n\n\t\tpublic Control(string id, params Keys[] keys) {\n\t\t\tId = id;\n\t\t\tKeys = keys;\n\t\t}\n\n\t\tpublic Control Gamepad(params Buttons[] buttons) {\n\t\t\tButtons = buttons;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Control Mouse(params MouseButtons[] buttons) {\n\t\t\tMouseButtons = buttons;\n\t\t\treturn this;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/input/Controls.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing BurningKnight.save;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.lightJson.Serialization;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.assets.input {\n\tpublic static class Controls {\n\t\tprivate static List<Control> controls = new List<Control>();\n\t\tprivate static List<Control> custom = new List<Control>();\n\n\t\tpublic static FileHandle BindingsHandle => new FileHandle($\"{SaveManager.SaveDir}keybindings_{Version}.json\");\n\t\t\n\t\tpublic const int Version = 2;\n\n\t\tpublic const string Up = \"up\";\n\t\tpublic const string Left = \"left\";\n\t\tpublic const string Down = \"down\";\n\t\tpublic const string Right = \"right\";\n\t\t\n\t\tpublic const string Active = \"active\";\n\t\tpublic const string Use = \"use\";\n\t\tpublic const string Bomb = \"bomb\";\n\t\tpublic const string Interact = \"interact\";\n\t\tpublic const string Swap = \"swap\";\n\n\t\tpublic const string Roll = \"roll\";\n\t\tpublic const string Duck = \"duck\";\n\t\tpublic const string Map = \"map\";\n\t\t\n\t\tpublic const string Pause = \"pause\";\n\n\t\tpublic const string GameStart = \"game_start\";\n\t\tpublic const string Cancel = \"cancel\";\n\t\t\n\t\tpublic const string Fullscreen = \"fullscreen\";\n\t\tpublic const string Fps = \"fps\";\n\n\t\tpublic const string UiUp = \"ui_up\";\n\t\tpublic const string UiDown = \"ui_down\";\n\t\tpublic const string UiLeft = \"ui_left\";\n\t\tpublic const string UiRight = \"ui_right\";\n\t\tpublic const string UiAccept = \"ui_accept\";\n\t\tpublic const string UiSelect = \"ui_select\";\n\t\tpublic const string UiBack = \"ui_back\";\n\n\t\tpublic const string QuickRestart = \"quick_restart\";\n\n\t\tstatic Controls() {\n\t\t\tcontrols.Clear();\n\t\t\t\n\t\t\tcontrols.Add(new Control(Up, Keys.W, Keys.Up));\n\t\t\tcontrols.Add(new Control(Left, Keys.A, Keys.Left));\n\t\t\tcontrols.Add(new Control(Down, Keys.S, Keys.Down));\n\t\t\tcontrols.Add(new Control(Right, Keys.D, Keys.Right));\n\n\t\t\tcontrols.Add(new Control(Active, Keys.Space).Gamepad(Buttons.RightShoulder));\n\t\t\tcontrols.Add(new Control(Use).Mouse(MouseButtons.Left).Gamepad(Buttons.RightTrigger));\n\n\t\t\tcontrols.Add(new Control(Bomb, Keys.Q).Gamepad(Buttons.LeftShoulder));\n\t\t\tcontrols.Add(new Control(Interact, Keys.E).Gamepad(Buttons.X));\n\t\t\tcontrols.Add(new Control(Swap, Keys.LeftShift).Gamepad(Buttons.A));\n\t\t\tcontrols.Add(new Control(Roll).Mouse(MouseButtons.Right).Gamepad(Buttons.LeftTrigger));\n\t\t\tcontrols.Add(new Control(Duck, Keys.R).Gamepad(Buttons.B));\n\t\t\tcontrols.Add(new Control(Map, Keys.M).Gamepad(Buttons.RightShoulder));\n\n\t\t\tcontrols.Add(new Control(Pause, Keys.Escape).Gamepad(Buttons.Back));\n\t\t\t\n\t\t\tcontrols.Add(new Control(Fullscreen, Keys.F11));\n\t\t\tcontrols.Add(new Control(Fps, Keys.F2));\n\n\t\t\tcontrols.Add(new Control(Cancel, Keys.Escape).Gamepad(Buttons.Back));\n\t\t\tcontrols.Add(new Control(GameStart, Keys.Space, Keys.Enter, Keys.X, Keys.Enter, Keys.Space).Gamepad(Buttons.X, Buttons.Start));\n\t\t\t\n\t\t\tcontrols.Add(new Control(UiUp, Keys.W, Keys.Up).Gamepad(Buttons.LeftThumbstickUp, Buttons.RightThumbstickUp, Buttons.DPadUp));\n\t\t\tcontrols.Add(new Control(UiDown, Keys.S, Keys.Down).Gamepad(Buttons.LeftThumbstickDown, Buttons.RightThumbstickDown, Buttons.DPadDown));\n\t\t\tcontrols.Add(new Control(UiLeft, Keys.A, Keys.Left).Gamepad(Buttons.LeftThumbstickLeft, Buttons.RightThumbstickLeft, Buttons.DPadLeft));\n\t\t\tcontrols.Add(new Control(UiRight, Keys.D, Keys.Right).Gamepad(Buttons.LeftThumbstickRight, Buttons.RightThumbstickRight, Buttons.DPadRight));\n\t\t\tcontrols.Add(new Control(UiAccept).Mouse(MouseButtons.Left, MouseButtons.Right));\n\t\t\tcontrols.Add(new Control(UiSelect, Keys.X, Keys.Enter, Keys.Space).Gamepad(Buttons.X, Buttons.A, Buttons.Y));\n\t\t\tcontrols.Add(new Control(UiBack, Keys.Escape).Gamepad(Buttons.Back, Buttons.B));\n\t\t\t\n\t\t\tcontrols.Add(new Control(QuickRestart, Keys.R, Keys.P).Gamepad(Buttons.X));\n\t\t}\n\n\t\tpublic static void Bind() {\n\t\t\tBind(custom);\n\t\t}\n\t\t\n\t\tpublic static void BindDefault() {\n\t\t\tBind(controls);\n\t\t}\n\n\t\tprivate static void Bind(List<Control> controls) {\n\t\t\tInput.ClearBindings();\n\n\t\t\tforeach (var c in controls) {\n\t\t\t\tif (c.Keys != null) {\n\t\t\t\t\tInput.Bind(c.Id, c.Keys);\n\t\t\t\t}\n\n\t\t\t\tif (c.Buttons != null) {\n\t\t\t\t\tInput.Bind(c.Id, c.Buttons);\n\t\t\t\t}\n\n\t\t\t\tif (c.MouseButtons != null) {\n\t\t\t\t\tInput.Bind(c.Id, c.MouseButtons);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Save() {\n\t\t\ttry {\n\t\t\t\tvar p = BindingsHandle.FullPath;\n\t\t\t\tLog.Info($\"Saving keybindings to {p}\");\n\n\t\t\t\tvar file = File.CreateText(p);\n\t\t\t\tvar writer = new JsonWriter(file, true);\n\t\t\t\tvar root = new JsonObject();\n\n\t\t\t\tforeach (var t in (custom.Count == 0 ? controls : custom)) {\n\t\t\t\t\tvar o = new JsonObject();\n\n\t\t\t\t\tif (t.Keys != null) {\n\t\t\t\t\t\tvar a = new JsonArray();\n\n\t\t\t\t\t\tforeach (var k in t.Keys) {\n\t\t\t\t\t\t\ta.Add(k.ToString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to[\"keys\"] = a;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (t.MouseButtons != null) {\n\t\t\t\t\t\tvar a = new JsonArray();\n\n\t\t\t\t\t\tforeach (var k in t.MouseButtons) {\n\t\t\t\t\t\t\ta.Add(k.ToString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to[\"mouse\"] = a;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (t.Buttons != null) {\n\t\t\t\t\t\tvar a = new JsonArray();\n\n\t\t\t\t\t\tforeach (var k in t.Buttons) {\n\t\t\t\t\t\t\ta.Add(k.ToString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to[\"gamepad\"] = a;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\troot[t.Id] = o;\n\t\t\t\t}\n\n\t\t\t\twriter.Write(root);\n\t\t\t\tfile.Close();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Load() {\n\t\t\ttry {\n\t\t\t\tvar handle = BindingsHandle;\n\n\t\t\t\tif (!handle.Exists()) {\n\t\t\t\t\tLog.Info(\"Keybindings file was not found, creating new one\");\n\n\t\t\t\t\tBindDefault();\n\t\t\t\t\tSave();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tLog.Info(\"Loading keybindings\");\n\n\t\t\t\tvar root = JsonValue.Parse(handle.ReadAll());\n\t\t\t\tcustom.Clear();\n\n\t\t\t\tforeach (var pair in root.AsJsonObject) {\n\t\t\t\t\tvar control = new Control(pair.Key);\n\t\t\t\t\t\n\t\t\t\t\tif (pair.Value[\"keys\"].IsJsonArray) {\n\t\t\t\t\t\tvar l = new List<Keys>();\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var k in pair.Value[\"keys\"].AsJsonArray) {\n\t\t\t\t\t\t\tif (Enum.TryParse<Keys>(k.String(\"\"), out var key)) {\n\t\t\t\t\t\t\t\tl.Add(key);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.Error($\"Unknown key {k}\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontrol.Keys = l.ToArray();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (pair.Value[\"mouse\"].IsJsonArray) {\n\t\t\t\t\t\tvar l = new List<MouseButtons>();\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var k in pair.Value[\"mouse\"].AsJsonArray) {\n\t\t\t\t\t\t\tif (Enum.TryParse<MouseButtons>(k.String(\"\"), out var key)) {\n\t\t\t\t\t\t\t\tl.Add(key);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.Error($\"Unknown mouse button {k}\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontrol.MouseButtons = l.ToArray();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (pair.Value[\"gamepad\"].IsJsonArray) {\n\t\t\t\t\t\tvar l = new List<Buttons>();\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var k in pair.Value[\"gamepad\"].AsJsonArray) {\n\t\t\t\t\t\t\tif (Enum.TryParse<Buttons>(k.String(\"\"), out var key)) {\n\t\t\t\t\t\t\t\tl.Add(key);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.Error($\"Unknown gamepad button {k}\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontrol.Buttons = l.ToArray();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcustom.Add(control);\n\t\t\t\t}\n\n\t\t\t\tBind();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static string Find(string id, bool gamepad, bool both = false) {\n\t\t\tvar k = \"None\";\n\t\t\tstring a = null;\n\t\t\tstring b = null;\n\t\t\t\n\t\t\tif (!gamepad) {\n\t\t\t\tboth = false;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in (custom.Count == 0 ? controls : custom)) {\n\t\t\t\tif (c.Id == id) {\n\t\t\t\t\tif (c.Buttons != null && c.Buttons.Length > 0) {\n\t\t\t\t\t\ta = c.Buttons[0].ToString();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (c.Keys != null && c.Keys.Length > 0) {\n\t\t\t\t\t\tb = c.Keys[0].ToString();\n\t\t\t\t\t} else if (c.MouseButtons != null && c.MouseButtons.Length > 0) {\n\t\t\t\t\t\tb = c.MouseButtons[0].ToString();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (both) {\n\t\t\t\tif (a != null && b != null) {\n\t\t\t\t\tk = $\"{a} / {b}\";\n\t\t\t\t} else if (a != null) {\n\t\t\t\t\tk = a;\n\t\t\t\t}\n\t\t\t} else if (gamepad && a != null) {\n\t\t\t\tk = a;\n\t\t\t} else if (!gamepad && b != null) {\n\t\t\t\tk = b;\n\t\t\t}\n\t\t\t\n\t\t\tif (k == \"Left\") {\n\t\t\t\tk = \"LMB\";\n\t\t\t} else if (k == \"Right\") {\n\t\t\t\tk = \"RMB\";\n\t\t\t} else if (k == \"Middle\") {\n\t\t\t\tk = \"MMB\";\n\t\t\t} else if (k.Length == 2 && k[0] == 'D') {\n\t\t\t\tk = k[1].ToString();\n\t\t\t} else if (k.StartsWith(\"Left\")) {\n\t\t\t\tk = $\"Left {k.Substring(4, k.Length - 4)}\";\n\t\t\t} else if (k.StartsWith(\"Right\")) {\n\t\t\t\tk = $\"Right {k.Substring(5, k.Length - 5)}\";\n\t\t\t} else if (k.EndsWith(\"Left\")) {\n\t\t\t\tk = $\"{k.Substring(0, k.Length - 4)} Left\";\n\t\t\t} else if (k.EndsWith(\"Right\")) {\n\t\t\t\tk = $\"{k.Substring(0, k.Length - 5)} Right\";\n\t\t\t} else if (k.EndsWith(\"Down\")) {\n\t\t\t\tk = $\"{k.Substring(0, k.Length - 4)} Down\";\n\t\t\t} else if (k.EndsWith(\"Up\")) {\n\t\t\t\tk = $\"{k.Substring(0, k.Length - 2)} Up\";\n\t\t\t}\n\n\t\t\treturn k;\n\t\t}\n\n\n\t\tpublic static string FindSlice(string name, bool gamepad) {\n\t\t\tvar id = Find(name, gamepad);\n\n\t\t\tif (id == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tif (gamepad) {\n\t\t\t\tif (id == \"Left Trigger\") {\n\t\t\t\t\treturn \"button_lt\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (id == \"Left Shoulder\") {\n\t\t\t\t\treturn \"button_lb\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (id == \"Right Trigger\") {\n\t\t\t\t\treturn \"button_rt\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (id == \"Right Shoulder\") {\n\t\t\t\t\treturn \"button_rb\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn $\"button_{id.ToLower()}\";\n\t\t\t} else {\n\t\t\t\tid = id.ToLower();\n\t\t\t\t\n\t\t\t\tif (id == \"lmb\") {\n\t\t\t\t\treturn \"button_lmb\";\n\t\t\t\t}\n\n\t\t\t\tif (id == \"rmb\") {\n\t\t\t\t\treturn \"button_rmb\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (id.Contains(\"shift\")) {\n\t\t\t\t\treturn \"key_shift\";\n\t\t\t\t}\n\n\t\t\t\tif (id.Contains(\"caps\")) {\n\t\t\t\t\treturn \"key_capslock\";\n\t\t\t\t}\n\n\t\t\t\tif (id.Contains(\"ntrl\")) {\n\t\t\t\t\treturn \"key_control\";\n\t\t\t\t}\n\n\t\t\t\treturn $\"key_{id}\";\n\t\t\t}\n\n\t\t\treturn id;\n\t\t}\n\n\t\tpublic static void Replace(string id, Keys key) {\n\t\t\tforeach (var c in (custom.Count == 0 ? controls : custom)) {\n\t\t\t\tif (c.Id == id) {\n\t\t\t\t\tc.Keys = new[] {key};\n\t\t\t\t\tc.MouseButtons = null;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Replace(string id, Buttons button) {\n\t\t\tforeach (var c in (custom.Count == 0 ? controls : custom)) {\n\t\t\t\tif (c.Id == id) {\n\t\t\t\t\tc.Buttons = new[] {button};\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Replace(string id, MouseButtons button) {\n\t\t\tforeach (var c in (custom.Count == 0 ? controls : custom)) {\n\t\t\t\tif (c.Id == id) {\n\t\t\t\t\tc.MouseButtons = new[] {button};\n\t\t\t\t\tc.Keys = null;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/items/ItemData.cs",
    "content": "using BurningKnight.entity.item;\nusing BurningKnight.save;\nusing Lens.lightJson;\n\nnamespace BurningKnight.assets.items {\n\tpublic class ItemData {\n\t\tpublic JsonValue Root;\n\t\tpublic JsonValue Uses;\n\t\tpublic JsonValue Renderer;\n\n\t\tpublic bool AutoPickup;\n\t\tpublic bool Automatic;\n\t\tpublic bool SingleUse;\n\t\tpublic string Animation;\n\t\tpublic string Id;\n\t\tpublic float UseTime;\n\t\tpublic ItemType Type;\n\t\tpublic ItemQuality Quality;\n\t\tpublic Chance Chance;\n\t\tpublic int Pools;\n\t\tpublic bool Single = true;\n\t\tpublic bool Lockable;\n\t\tpublic bool Scourged;\n\t\tpublic int UnlockPrice = 1;\n\n\t\tpublic WeaponType WeaponType;\n\n\t\tpublic bool Unlocked => !Lockable || GlobalSave.IsTrue(Id);\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/items/Items.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.renderer;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.lightJson;\nusing Lens.lightJson.Serialization;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.assets.items {\n\tpublic static class Items {\n\t\tpublic const string PlaceholderItem = \"bk:my_heart\";\n\t\t\n\t\tpublic static Dictionary<string, ItemData> Datas = new Dictionary<string, ItemData>();\n\t\tprivate static Dictionary<ItemType, List<ItemData>> byType = new Dictionary<ItemType, List<ItemData>>();\n\t\tprivate static Dictionary<int, List<ItemData>> byPool = new Dictionary<int, List<ItemData>>();\n\t\t\n\t\tpublic static void Load() {\n\t\t\tLoad(FileHandle.FromRoot(\"items.json\"));\n\t\t}\n\n\t\tpublic static void Load(FileHandle handle) {\n\t\t\tif (!handle.Exists()) {\n\t\t\t\tLog.Error($\"Item data {handle.FullPath} does not exist!\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (handle.IsDirectory()) {\n\t\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in handle.ListDirectoryHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (handle.Extension != \".json\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar d = handle.ReadAll();\n\t\t\tvar num = JsonCounter.Calculate(d);\n\n\t\t\tLog.Debug($\"Item data number is {num}\");\n\n\t\t\tif (num != Assets.ItemData) {\n\t\t\t\tAssets.DataModified = true;\n\t\t\t}\n\t\t\t\n\t\t\tvar root = JsonValue.Parse(d);\n\n\t\t\tforeach (var item in root.AsJsonObject) {\n\t\t\t\tParseItem(item.Key, item.Value);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Save() {\n\t\t\tvar root = new JsonObject();\n\n\t\t\tforeach (var item in Datas.Values) {\n\t\t\t\tvar data = new JsonObject();\n\n\t\t\t\tdata[\"id\"] = item.Id;\n\n\t\t\t\tif (item.Animation != null) {\n\t\t\t\t\tdata[\"animation\"] = item.Animation;\n\t\t\t\t}\n\n\t\t\t\tif (Math.Abs(item.UseTime) > 0.01f) {\n\t\t\t\t\tdata[\"time\"] = item.UseTime;\n\t\t\t\t}\n\n\t\t\t\tif (item.Type != ItemType.Artifact) {\n\t\t\t\t\tdata[\"type\"] = (int) item.Type;\n\t\t\t\t}\n\n\t\t\t\tif (Math.Abs(item.Chance.Any - 1f) > 0.01f) {\n\t\t\t\t\tdata[\"chance\"] = item.Chance.ToJson();\n\t\t\t\t}\n\n\t\t\t\tif (item.Single) {\n\t\t\t\t\tdata[\"single\"] = item.Single;\n\t\t\t\t}\n\n\t\t\t\tif (item.Scourged) {\n\t\t\t\t\tdata[\"scourged\"] = true;\n\t\t\t\t}\n\n\t\t\t\tif (item.Quality != ItemQuality.Wooden) {\n\t\t\t\t\tdata[\"quality\"] = (int) item.Quality;\n\t\t\t\t}\n\n\t\t\t\tif (item.AutoPickup) {\n\t\t\t\t\tdata[\"auto_pickup\"] = item.AutoPickup;\n\t\t\t\t}\n\n\t\t\t\tif (item.Automatic) {\n\t\t\t\t\tdata[\"auto\"] = item.Automatic;\n\t\t\t\t}\n\n\t\t\t\tif (item.SingleUse) {\n\t\t\t\t\tdata[\"single_use\"] = item.SingleUse;\n\t\t\t\t}\n\n\t\t\t\tdata[\"pool\"] = item.Pools;\n\t\t\t\tdata[\"uses\"] = item.Uses;\n\n\t\t\t\tif (item.Renderer.IsJsonObject) {\n\t\t\t\t\tdata[\"renderer\"] = item.Renderer;\n\t\t\t\t}\n\n\t\t\t\tif (item.Lockable) {\n\t\t\t\t\tdata[\"lock\"] = item.Lockable;\n\t\t\t\t\tdata[\"uprice\"] = item.UnlockPrice;\n\t\t\t\t}\n\n\t\t\t\tif (item.Type == ItemType.Weapon) {\n\t\t\t\t\tdata[\"weapon\"] = (int) item.WeaponType;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\troot[item.Id] = data;\n\t\t\t}\n\t\t\t\n\t\t\tvar file = File.CreateText(FileHandle.FromRoot(\"items.json\").FullPath);\n\t\t\tvar writer = new JsonWriter(file);\n\t\t\twriter.Write(root);\n\t\t\tfile.Close();\n\n\t\t\tLocale.Save();\n\t\t}\n\t\t\n\t\tprivate static void OnChanged(object sender, FileSystemEventArgs args) {\n\t\t\tLog.Debug($\"Reloading {args.FullPath}\");\n\t\t\tLoad(new FileHandle(args.FullPath));\n\t\t}\n\n\t\tprivate static int TryToApply(ItemData data, int pool, ItemPool pl) {\n\t\t\tif (!pl.Contains(pool)) {\n\t\t\t\tList<ItemData> datas;\n\n\t\t\t\tif (!byPool.TryGetValue(pl.Id, out datas)) {\n\t\t\t\t\tdatas = new List<ItemData>();\n\t\t\t\t\tbyPool[pl.Id] = datas;\n\t\t\t\t}\n\n\t\t\t\tdatas.Add(data);\n\t\t\t\treturn pl.Apply(pool);\n\t\t\t}\n\n\t\t\treturn pool;\n\t\t}\n\t\t\n\t\tprivate static void ParseItem(string id, JsonValue item) {\n\t\t\tvar a = item[\"animation\"];\n\t\t\tvar animation = a == JsonValue.Null ? null : a.AsString;\n\n\t\t\tvar type = (ItemType) item[\"type\"].Int(0);\n\t\t\tvar p = item[\"auto_pickup\"];\n\t\t\tvar pickup = p == JsonValue.Null ? (type == ItemType.Key || type == ItemType.Bomb || type == ItemType.Heart || type == ItemType.Coin) : p.Bool(false);\n\t\t\t\n\t\t\tvar data = new ItemData {\n\t\t\t\tId = id,\n\t\t\t\tUseTime = item[\"time\"].Number(0),\n\t\t\t\tType = type,\n\t\t\t\tQuality = (ItemQuality) item[\"quality\"].AsInteger,\n\t\t\t\tRoot = item,\n\t\t\t\tUses = item[\"uses\"],\n\t\t\t\tRenderer = (item[\"renderer\"].IsJsonObject ? item[\"renderer\"] : JsonValue.Null),\n\t\t\t\tAnimation = animation,\n\t\t\t\tAutoPickup = pickup,\n\t\t\t\tSingle = item[\"single\"].Bool(true),\n\t\t\t\tAutomatic = item[\"auto\"].Bool(false),\n\t\t\t\tSingleUse = item[\"single_use\"].Bool(false),\n\t\t\t\tScourged = item[\"scourged\"].Bool(false),\n\t\t\t\tChance = Chance.Parse(item[\"chance\"]),\n\t\t\t\tLockable = item[\"lock\"].Bool(false)\n\t\t\t};\n\n\t\t\tif (data.Type == ItemType.Weapon) {\n\t\t\t\tdata.WeaponType = (WeaponType) item[\"weapon\"].Int(0);\n\t\t\t}\n\n\t\t\tif (data.Lockable) {\n\t\t\t\tdata.UnlockPrice = item[\"uprice\"];\n\t\t\t}\n\t\t\t\n\t\t\tvar pl = item[\"pool\"];\n\t\t\tvar pools = 0;\n\n\t\t\tif (pl == JsonValue.Null) {\n\t\t\t\tswitch (data.Type) {\n\t\t\t\t\tcase ItemType.Key:\n\t\t\t\t\tcase ItemType.Coin:\n\t\t\t\t\tcase ItemType.Bomb:\n\t\t\t\t\tcase ItemType.Heart:\n\t\t\t\t\t\tpools = TryToApply(data, pools, ItemPool.Consumable);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ItemType.Artifact:\n\t\t\t\t\tcase ItemType.Weapon:\n\t\t\t\t\tcase ItemType.Active:\t\t\t\t\t\t\n\t\t\t\t\t\tpools = TryToApply(data, pools, ItemPool.Treasure);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar pls = pl.Int(0);\n\n\t\t\t\tfor (var i = 0; i < ItemPool.Count; i++) {\n\t\t\t\t\tif (ItemPool.ById[i].Contains(pls)) {\n\t\t\t\t\t\tpools = TryToApply(data, pools, ItemPool.ById[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdata.Pools = pools;\n\n\t\t\tDatas[id] = data;\n\t\t\tList<ItemData> all;\n\n\t\t\tif (!byType.TryGetValue(data.Type, out all)) {\n\t\t\t\tall = new List<ItemData>();\n\t\t\t\tbyType[data.Type] = all;\n\t\t\t}\n\t\t\t\n\t\t\tall.Add(data);\n\t\t}\n\n\t\tprivate static string[] coinIds = {\n\t\t\t\"bk:copper_coin\",\n\t\t\t\"bk:iron_coin\",\n\t\t\t\"bk:gold_coin\",\n\t\t\t\"bk:platinum_coin\"\n\t\t};\n\n\t\tprivate static float[] coinChances = {\n\t\t\t1f,\n\t\t\t1f / 10f,\n\t\t\t1f / 50f,\n\t\t\t1f / 100f\n\t\t};\n\n\t\tpublic static Item Create(string id) {\n\t\t\tif (id == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tif (id == \"bk:coin\") {\n\t\t\t\tid = coinIds[Rnd.Chances(coinChances)];\n\t\t\t}\n\t\t\t\n\t\t\tif (!Datas.TryGetValue(id, out var data)) {\n\t\t\t\tLog.Error($\"Unknown item {id}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn Create(data);\n\t\t}\n\n\t\tpublic static Item Create(ItemData data) {\n\t\t\tvar item = new Item {\n\t\t\t\tUseTime = data.UseTime,\n\t\t\t\tId = data.Id,\n\t\t\t\tType = data.Type,\n\t\t\t\tAutoPickup = data.AutoPickup,\n\t\t\t\tAnimation = data.Animation,\n\t\t\t\tAutomatic = data.Automatic,\n\t\t\t\tSingleUse = data.SingleUse,\n\t\t\t\tScourged = data.Scourged,\n\t\t\t\tUses = ParseUses(data.Uses)\n\t\t\t};\n\t\t\t\n\t\t\tif (data.Renderer != JsonValue.Null) {\n\t\t\t\tif (data.Renderer.IsString) {\n\t\t\t\t\tvar name = data.Renderer.AsString;\n\t\t\t\t\titem.Renderer = RendererRegistry.Create(name);\n\n\t\t\t\t\tCheckRendererForNull(item, name);\n\t\t\t\t} else if (data.Renderer.IsJsonObject) {\n\t\t\t\t\tvar name = data.Renderer[\"id\"].String(\"bk:Angled\");\n\t\t\t\t\titem.Renderer = RendererRegistry.Create(name);\n\n\t\t\t\t\tCheckRendererForNull(item, name);\n\t\t\t\t\t\n\t\t\t\t\tif (item.Renderer != null) {\n\t\t\t\t\t\titem.Renderer.Item = item;\n\t\t\t\t\t\titem.Renderer.Setup(data.Renderer);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tLog.Error($\"Invalid renderer declaration in item {data.Id}\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var u in item.Uses) {\n\t\t\t\tu.Item = item;\n\t\t\t\tu.Init();\n\t\t\t}\n\n\t\t\treturn item;\n\t\t}\n\n\t\tprivate static void CheckRendererForNull(Item item, string name) {\n\t\t\tif (item.Renderer == null) {\n\t\t\t\tLog.Error($\"Unknown renderer {name} in item {item.Id}, did you register it?\");\n\t\t\t}\n\t\t}\n\n\t\tpublic static ItemUse[] ParseUses(JsonValue data) {\n\t\t\tif (data != JsonValue.Null) {\n\t\t\t\tvar uses = new List<ItemUse>();\n\n\t\t\t\tif (data.IsString) {\n\t\t\t\t\tvar use = ParseItemUse(data.AsString, null);\n\n\t\t\t\t\tif (use != null) {\n\t\t\t\t\t\tuses.Add(use);\n\t\t\t\t\t}\n\t\t\t\t} else if (data.IsJsonArray) {\n\t\t\t\t\tforeach (var d in data.AsJsonArray) {\n\t\t\t\t\t\tif (d.IsJsonObject) {\n\t\t\t\t\t\t\tif (!d[\"id\"].IsString) {\n\t\t\t\t\t\t\t\tLog.Error(\"Item has no id\");\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar use = ParseItemUse(d[\"id\"], d);\n\n\t\t\t\t\t\t\tif (use != null) {\n\t\t\t\t\t\t\t\tuses.Add(use);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (d.IsString) {\n\t\t\t\t\t\t\tvar use = ParseItemUse(d.AsString, null);\n\n\t\t\t\t\t\t\tif (use != null) {\n\t\t\t\t\t\t\t\tuses.Add(use);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (data.IsJsonObject) {\n\t\t\t\t\tvar obj = data.AsJsonObject;\n\t\t\t\t\t\n\t\t\t\t\tif (!obj[\"id\"].IsString) {\n\t\t\t\t\t\tLog.Error(\"Item has no id\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar use = ParseItemUse(obj[\"id\"], obj);\n\n\t\t\t\t\t\tif (use != null) {\n\t\t\t\t\t\t\tuses.Add(use);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tLog.Error(\"Invalid item use declaration\");\n\t\t\t\t}\n\n\t\t\t\treturn uses.ToArray();\n\t\t\t}\n\n\t\t\treturn new ItemUse[0];\n\t\t}\n\n\t\tprivate static ItemUse ParseItemUse(string id, JsonValue? data) {\n\t\t\tvar use = UseRegistry.Create(id);\n\n\t\t\tif (use == null) {\n\t\t\t\tLog.Error($\"Invalid item use id ({id}), did you register it?\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (data.HasValue) {\n\t\t\t\tuse.Setup(data.Value);\n\t\t\t}\n\n\t\t\treturn use;\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic static List<ItemData> GetPool(ItemPool pool) {\n\t\t\treturn byPool.TryGetValue(pool.Id, out var b) ? b : new List<ItemData>();\n\t\t}\n\n\t\tprivate static string[] veganProofItems = {\n\t\t\t\"bk:chicken\", \"bk:shawarma\", \"bk:hotdog\"\n\t\t};\n\t\t\n\t\tpublic static bool ShouldAppear(string id) {\n\t\t\tif (id == \"bk:coin\") {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (id == \"bk:blindfold\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (!Datas.TryGetValue(id, out var data)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Settings.Vegan && veganProofItems.Contains(id)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn ShouldAppear(data);\n\t\t}\n\n\t\t\n\t\tpublic static bool ShouldAppear(ItemData t) {\n\t\t\tif (LevelSave.MeleeOnly && t.Type == ItemType.Weapon && t.WeaponType != WeaponType.Melee) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn (Run.Type == RunType.Daily || !t.Lockable || GlobalSave.IsTrue(t.Id)) && (!t.Single || Run.Statistics == null ||\n\t\t\t                                                    (!Run.Statistics.Items.Contains(t.Id) &&\n\t\t\t                                                     !Run.Statistics.Banned.Contains(t.Id))) && t.Id != \"bk:the_sword\";\n\t\t}\n\n\t\tpublic static List<string> GeneratedOnFloor = new List<string>();\n\n\t\tpublic static List<ItemData> GeneratePool(List<ItemData> types, Func<ItemData, bool> filter = null, PlayerClass c = PlayerClass.Any) {\n\t\t\tvar datas = new List<ItemData>();\n\n\t\t\tforeach (var t in types) {\n\t\t\t\tif (ShouldAppear(t) && (filter == null || filter(t)) && !GeneratedOnFloor.Contains(t.Id)) {\n\t\t\t\t\tdatas.Add(t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn datas;\n\t\t}\n\n\t\tpublic static string GenerateAndRemove(List<ItemData> datas, Func<ItemData, bool> filter = null, bool removeFromFloor = false) {\n\t\t\tdouble sum = 0;\n\t\t\t\n\t\t\tforeach (var chance in datas) {\n\t\t\t\tif (filter == null || filter(chance)) {\n\t\t\t\t\tsum += chance.Chance.Calculate(PlayerClass.Any);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar value = Rnd.Double(sum);\n\t\t\tsum = 0;\n\n\t\t\tstring id = null;\n\t\t\tItemData data = null;\n\t\t\t\n\t\t\tforeach (var t in datas) {\n\t\t\t\tif (filter == null || filter(t)) {\n\t\t\t\t\tsum += t.Chance.Calculate(PlayerClass.Any);\n\t\t\t\t\t\n\t\t\t\t\tif (value < sum) {\n\t\t\t\t\t\tid = t.Id;\n\t\t\t\t\t\tdata = t;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (id != null) {\n\t\t\t\tif (removeFromFloor) {\n\t\t\t\t\tGeneratedOnFloor.Add(id);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdatas.Remove(data);\n\t\t\t\treturn id;\n\t\t\t}\n\n\t\t\treturn PlaceholderItem;\n\t\t}\n\t\n\t\tprivate static string Generate(List<ItemData> types, Func<ItemData, bool> filter, PlayerClass c) {\n\t\t\tdouble sum = 0;\n\t\t\tvar datas = GeneratePool(types, filter, c);\n\t\t\t\n\t\t\tforeach (var chance in datas) {\n\t\t\t\tsum += chance.Chance.Calculate(c);\n\t\t\t}\n\n\t\t\tvar value = Rnd.Double(sum);\n\t\t\tsum = 0;\n\n\t\t\tforeach (var t in datas) {\n\t\t\t\tsum += t.Chance.Calculate(c);\n\n\t\t\t\tif (value < sum) {\n\t\t\t\t\treturn t.Id;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn PlaceholderItem;\n\t\t}\n\n\t\tpublic static string Generate(ItemType type, Func<ItemData, bool> filter = null, PlayerClass c = PlayerClass.Any) {\n\t\t\tif (!byType.TryGetValue(type, out var types)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn Generate(types, filter, c);\n\t\t}\n\n\t\tpublic static string Generate(ItemPool pool, Func<ItemData, bool> filter = null, PlayerClass c = PlayerClass.Any) {\n\t\t\tif (!byPool.TryGetValue(pool.Id, out var types)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn Generate(types, filter, c);\n\t\t}\n\n\t\tpublic static string Generate(Func<ItemData, bool> filter = null, PlayerClass c = PlayerClass.Any) {\n\t\t\treturn Generate(Datas.Values.ToList(), filter, c);\n\t\t}\n\n\n\t\tpublic static Item CreateAndAdd(string id, Area area, bool scourgeFree = true) {\n\t\t\tvar item = Create(id);\n\n\t\t\tif (item == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tarea.Add(item);\n\t\t\titem.AddDroppedComponents();\n\n\t\t\tif (scourgeFree && (!Datas.ContainsKey(id) || !Datas[id].Scourged)) {\n\t\t\t\titem.Scourged = false;\n\t\t\t}\n\t\t\t\n\t\t\treturn item;\n\t\t}\n\n\t\tpublic static bool Has(string id) {\n\t\t\treturn Datas.ContainsKey(id);\n\t\t}\n\n\t\tpublic static void Unlock(string id) {\n\t\t\tif (!Datas.TryGetValue(id, out var data)) {\n\t\t\t\tLog.Error($\"Unknown item {id}\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!data.Lockable) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (data.Unlocked) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGlobalSave.Put(data.Id, true);\n\n\t\t\tvar e = new Item.UnlockedEvent {\n\t\t\t\tData = data\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tEngine.Instance.State.Ui.EventListener.Handle(e);\n\t\t\t\tEngine.Instance.State.Area.EventListener.Handle(e);\n\n\t\t\t\tif (!Achievements.ItemBuffer.Contains(id)) {\n\t\t\t\t\tAchievements.ItemBuffer.Add(id);\n\t\t\t\t}\n\t\t\t} catch (Exception er) {\n\t\t\t\tLog.Error(er);\n\t\t\t}\n\n\t\t\tCheckForCollector();\n\t\t}\n\n\t\tpublic static void CheckForCollector() {\n\t\t\tif (Achievements.Get(\"bk:collector\").Unlocked) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var item in Datas.Values) {\n\t\t\t\tif (item.Lockable && !item.Unlocked) {\n\t\t\t\t\tLog.Info($\"Collector achievement was not unlocked cuz {item.Id}\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tAchievements.Unlock(\"bk:collector\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/lighting/EntityLight.cs",
    "content": "using Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.lighting {\n\tpublic class EntityLight : Light {\n\t\tpublic Entity Entity;\n\n\t\tpublic override Vector2 GetPosition() {\n\t\t\treturn Entity.Center;\n\t\t}\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/lighting/Light.cs",
    "content": "using Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.lighting {\n\tpublic abstract class Light {\n\t\tprivate bool dirty = true;\n\t\tprivate bool locked;\n\t\t\n\t\tprotected float radius = 32;\n\n\t\tpublic float Radius {\n\t\t\tget => radius;\n\n\t\t\tset {\n\t\t\t\tif (!locked) {\n\t\t\t\t\tradius = value;\n\t\t\t\t\tdirty = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic Color Color;\n\t\tpublic Vector2 Scale = Vector2.Zero;\n\n\t\tpublic void Lock() {\n\t\t\tif (locked) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlocked = true;\n\t\t\t\n\t\t\tTween.To(0, Color.A, x => {\n\t\t\t\tColor.A = (byte) x;\n\t\t\t}, 0.4f).OnEnd = () => Lights.Remove(this, true);\n\t\t}\n\n\t\tpublic void Start(float target) {\n\t\t\tradius = target;\n\n\t\t\tTween.To(255, Color.A, x => {\n\t\t\t\tColor.A = (byte) x; \n\t\t\t}, 0.4f);\n\t\t}\n\t\t\n\t\tpublic void Update(float dt) {\n\t\t\tif (dirty) {\n\t\t\t\tUpdateCache();\n\t\t\t}\n\t\t}\n\n\t\tpublic void UpdateCache() {\n\t\t\tScale.X = radius / 128f;\n\t\t\tScale.Y = Scale.X;\n\t\t}\n\t\t\n\t\tpublic abstract Vector2 GetPosition();\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/lighting/LightComponent.cs",
    "content": "using ImGuiNET;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.lighting {\n\tpublic class LightComponent : Component {\n\t\tpublic Light Light;\n\n\t\tpublic LightComponent(Entity entity, float radius, Color color) {\n\t\t\tLight = Lights.New(entity, radius, color);\n\t\t\tLight.UpdateCache();\n\t\t}\n\n\t\tpublic LightComponent(Light light) {\n\t\t\tLight = light;\n\t\t\tLights.Add(light);\n\t\t\tLight.UpdateCache();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tLight.Update(dt);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tLights.Remove(Light);\n\t\t}\n\t\t\n\t\tpublic override void RenderDebug() {\n\t\t\tbase.RenderDebug();\n\t\t\tvar v = Light.Radius;\n\n\t\t\tif (ImGui.DragFloat(\"Radius\", ref v)) {\n\t\t\t\tLight.Radius = v;\n\t\t\t}\n\n\t\t\tvar color = new System.Numerics.Vector4(Light.Color.R / 255f, Light.Color.G / 255f, Light.Color.B / 255f, Light.Color.A / 255f);\n\n\t\t\tif (ImGui.DragFloat4(\"Color\", ref color)) {\n\t\t\t\tLight.Color = new Color(color.X * 255, color.Y * 255, color.Z * 255, color.W * 255);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/lighting/Lights.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.debug;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.ui.imgui;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.assets.lighting {\n\tpublic static class Lights {\n\t\tpublic static float Flash;\n\t\tpublic const byte AuraAlpha = 100;\n\t\t\n\t\tprivate static TextureRegion region;\n\n\t\tprivate static List<Light> lights = new List<Light>();\n\t\tprivate static RenderTarget2D surface;\n\n\t\tpublic static BlendState Blend;\n\t\tprivate static BlendState messBlend;\n\t\t\n\t\tpublic static void Init() {\n\t\t\tvar v = Run.Depth == 0 ? 0.9f : 0.25f;\n\t\t\t\n\t\t\tClearColor = new Color(v, v, v, 1f);\n\t\t\t\n\t\t\tif (region == null) {\n\t\t\t\tregion = Textures.Get(\"light\");\n\n\t\t\t\tBlend = new BlendState {\n\t\t\t\t\tColorSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.One,\n\t\t\t\t\tColorDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.One,\n\t\t\t\t\tColorBlendFunction = BlendFunction.Add\n\t\t\t\t};\n\n\t\t\t\tmessBlend = new BlendState {\n\t\t\t\t\tColorBlendFunction = BlendFunction.Add,\n\t\t\t\t\tColorSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.DestinationColor,\n\t\t\t\t\tColorDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.Zero,\n\t\t\t\t\t\n\t\t\t\t\tAlphaSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.DestinationAlpha\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tsurfaceBlend = messBlend;\n\t\t\t}\n\n\t\t\tif (surface == null) {\n\t\t\t\tsurface = new RenderTarget2D(\n\t\t\t\t\tEngine.GraphicsDevice, Display.Width + 1, Display.Height + 1, false,\n\t\t\t\t\tEngine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Render() {\n\t\t\tif (Flash > 0) {\n\t\t\t\tFlash -= Engine.Delta * 8;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!LevelLayerDebug.Lights || !(Engine.Instance.State is InGameState)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (EnableFog) {\n\t\t\t\tInGameState.RenderFog();\n\t\t\t}\n\n\t\t\tvar state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\tstate.End();\n\t\t\t\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(surface);\n\t\t\t\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\tGraphics.Clear(Color.Transparent);\n\n\t\t\tGraphics.Color.A = AuraAlpha;\n\n\t\t\tforeach (var p in Run.Level.Area.Tagged[Tags.Projectile]) {\n\t\t\t\t((BasicProjectileGraphicsComponent) p.GraphicsComponent).RenderLight();\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var p in Run.Level.Area.Tagged[Tags.Laser]) {\n\t\t\t\t((LaserGraphicsComponent) p.GraphicsComponent).RenderTopLight();\n\t\t\t}\n\t\t\t\n\t\t\tstate.End();\n\t\t\t\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.Additive, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\t\n\t\t\tGraphics.Render(surface, Camera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, Camera.Instance.Position.Y % 1));\n\t\t\t\n\t\t\tstate.End();\n\t\t\tGraphics.Color.A = 255;\n\t\t\t\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(surface);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, lightBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\n\t\t\tGraphics.Clear(ClearColor);\n\n\t\t\tforeach (var light in lights) {\n\t\t\t\tGraphics.Color = light.Color;\n\t\t\t\tGraphics.Render(region, light.GetPosition(), 0, region.Center, light.Scale * RadiusMod);\t\n\t\t\t}\n\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\n\t\t\tRun.Level?.RenderTileLights();\n\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\t\n\t\t\tvar c = Camera.Instance;\n\t\t\tvar z = c.Zoom;\n\t\t\tvar n = Math.Abs(z - 1) > 0.01f;\n\t\t\t\t\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = 1;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, surfaceBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\tGraphics.Color = new Color(color.X, color.Y, color.Z, alpha);\n\n\t\t\tGraphics.Render(surface, Camera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, \n\t\t\tCamera.Instance.Position.Y % 1));\n\t\t\tGraphics.Color = Color.White;\n\t\t\tGraphics.Batch.End();\n\t\t\t\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = z;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\t\t\t\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tstate.Begin();\n\t\t}\n\n\t\tprivate static float alpha = 1f;\n\t\tprivate static System.Numerics.Vector3 color = System.Numerics.Vector3.One;\n\t\tprivate static BlendState surfaceBlend = BlendState.NonPremultiplied;\n\t\tprivate static int surfaceBlendId = 5;\n\t\tpublic static float RadiusMod = 1;\n\t\tpublic static bool EnableFog = true;\n\t\tpublic static Color ClearColor;\n\n\t\tprivate static BlendState lightBlend = BlendState.Additive;\n\t\tprivate static int lightBlendId = 0;\n\t\t\n\t\tprivate static string[] blends = {\n\t\t\t\"Additive\", \"AlphaBlend\", \"NonPremultiplied\", \"Opaque\", \"Level\", \"Mess\"\n\t\t};\n\n\t\tprivate static BlendState BlendIdToBlend(int id) {\n\t\t\tswitch (id) {\n\t\t\t\tcase 0: default: return BlendState.Additive;\n\t\t\t\tcase 1: return BlendState.AlphaBlend;\n\t\t\t\tcase 2: return BlendState.NonPremultiplied;\n\t\t\t\tcase 3: return BlendState.Opaque;\n\t\t\t\tcase 4: return Blend;\n\t\t\t\tcase 5: return messBlend;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderDebug() {\n\t\t\tif (!WindowManager.Lighting) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!ImGui.Begin(\"Lighting\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tImGui.Checkbox(\"Enabled\", ref LevelLayerDebug.Lights);\n\t\t\tImGui.Checkbox(\"Enable fog\", ref EnableFog);\n\t\t\tImGui.DragFloat(\"Radius mod\", ref RadiusMod);\n\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tImGui.InputFloat(\"Surface alpha\", ref alpha);\n\t\t\tImGui.InputFloat3(\"Surface tint\", ref color);\n\n\t\t\tif (ImGui.Combo(\"Surface blend\", ref surfaceBlendId, blends, blends.Length)) {\n\t\t\t\tsurfaceBlend = BlendIdToBlend(surfaceBlendId);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tif (ImGui.Combo(\"Light blend\", ref lightBlendId, blends, blends.Length)) {\n\t\t\t\tlightBlend = BlendIdToBlend(lightBlendId);\n\t\t\t}\n\t\t\t\n\t\t\tvar c = new System.Numerics.Vector4(ClearColor.R / 255f, ClearColor.G / 255f, ClearColor.B / 255f, ClearColor.A / 255f);\n\n\t\t\tif (ImGui.InputFloat4(\"Color\", ref c)) {\n\t\t\t\tClearColor = new Color(c.X, c.Y, c.Z, c.W);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.End();\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tlights.Clear();\n\t\t}\n\n\t\tpublic static void DestroySurface() {\n\t\t\tsurface?.Dispose();\n\t\t\tsurface = null;\n\t\t}\n\n\t\tpublic static Light New(Entity entity, float radius, Color color) {\n\t\t\tvar light = new EntityLight {\n\t\t\t\tRadius = 0,\n\t\t\t\tEntity = entity,\n\t\t\t\tColor = color\n\t\t\t};\n\n\t\t\tlight.Start(radius);\n\t\t\tAdd(light);\n\t\t\t\n\t\t\treturn light;\n\t\t}\n\n\t\tpublic static void Add(Light light) {\n\t\t\tlights.Add(light);\n\t\t}\n\n\t\tpublic static void Remove(Light light, bool fast = false) {\n\t\t\tif (fast) {\n\t\t\t\tlights.Remove(light);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlight.Lock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/lighting/PositionedLight.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.lighting {\n\tpublic class PositionedLight : Light {\n\t\tpublic Vector2 Position;\n\n\t\tpublic override Vector2 GetPosition() {\n\t\t\treturn Position;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/loot/Drops.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.item;\nusing Lens.util;\n\nnamespace BurningKnight.assets.loot {\n\tpublic static class Drops {\n\t\tpublic static Dictionary<string, Drop> Defined = new Dictionary<string, Drop>();\n\n\t\tstatic Drops() {\n\t\t\tDefine(\"wooden_chest\", new OneOfDrop(\n\t\t\t\tnew AnyDrop(\n\t\t\t\t\tnew SimpleDrop(0.7f, 1, 2, \"bk:key\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:bomb\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:troll_bomb\"),\n\t\t\t\t\tnew SimpleDrop(0.6f, 1, 4, \"bk:coin\")\n\t\t\t\t),\n\t\t\t\t\n\t\t\t\tnew PoolDrop(ItemPool.WoodenChest)\n\t\t\t));\n\t\t\t\n\t\t\tDefine(\"gold_chest\", new PoolDrop(ItemPool.GoldChest));\n\t\t\tDefine(\"double_chest\", new PoolDrop(ItemPool.DoubleChest));\n\t\t\tDefine(\"triple_chest\", new PoolDrop(ItemPool.TripleChest));\n\t\t\tDefine(\"red_chest\", new PoolDrop(ItemPool.RedChest));\n\t\t\t\n\t\t\tDefine(\"stone_chest\", new AnyDrop(\n\t\t\t\tnew PoolDrop(ItemPool.StoneChest),\n\t\t\t\t\n\t\t\t\tnew AnyDrop(\n\t\t\t\t\tnew SimpleDrop(0.7f, 1, 2, \"bk:key\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:bomb\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:troll_bomb\"),\n\t\t\t\t\tnew SimpleDrop(0.6f, 1, 4, \"bk:coin\")\n\t\t\t\t) { Chance = 0.5f }\n\t\t\t));\n\t\t\t\n\t\t\tDefine(\"scourged_chest\", new PoolDrop(ItemPool.ScourgedChest));\n\t\t\tDefine(\"duck_chest\", new PoolDrop(ItemPool.DuckChest));\n\n\t\t\tDefine(\"pouch\", new OneOfDrop(\n\t\t\t\tnew SimpleDrop(0.7f, 1, 2, \"bk:key\"),\n\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:bomb\"),\n\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:troll_bomb\"),\n\t\t\t\tnew SimpleDrop(0.6f, 1, 4, \"bk:coin\")\n\t\t\t));\n\t\t\t\n\t\t\tDefine(\"rock\", new SingleDrop(\"bk:pickaxe\", 0.001f));\n\t\t\t\n\t\t\tDefine(\"tinted_rock\", new OneOfDrop(\n\t\t\t\tnew SimpleDrop(0.2f, 1, 2, \"bk:key\"),\n\t\t\t\tnew SimpleDrop(0.2f, 1, 2, \"bk:bomb\"),\n\t\t\t\tnew SimpleDrop(0.2f, 1, 2, \"bk:troll_bomb\"),\n\t\t\t\tnew SimpleDrop(0.4f, 1, 1, \"bk:heart\"),\n\t\t\t\tnew SimpleDrop(0.5f, 1, 2, \"bk:shield\")\n\t\t\t));\n\t\t\t\n\t\t\tDefine(\"safe\", new AnyDrop(\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new [] {\n\t\t\t\t\t\t\"bk:coin\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tChance = 0.8f,\n\t\t\t\t\tMin = 3,\n\t\t\t\t\tMax = 10\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new[] {\n\t\t\t\t\t\t\"bk:key\"\n\t\t\t\t\t},\n\n\t\t\t\t\tChance = 0.5f,\n\t\t\t\t\tMin = 1,\n\t\t\t\t\tMax = 4\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new [] {\n\t\t\t\t\t\t\"bk:bomb\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tChance = 0.3f,\n\t\t\t\t\tMin = 1,\n\t\t\t\t\tMax = 2\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew PoolDrop(ItemPool.Safe)\n\t\t\t));\n\n\t\t\tDefine(\"charger\", new AnyDrop(\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new [] {\n\t\t\t\t\t\t\"bk:battery\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tChance = 0.5f,\n\t\t\t\t\tMin = 1,\n\t\t\t\t\tMax = 2\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new [] {\n\t\t\t\t\t\t\"bk:coin\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tChance = 0.5f,\n\t\t\t\t\tMin = 1,\n\t\t\t\t\tMax = 3\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew PoolDrop(ItemPool.Charger, 0.5f)\n\t\t\t));\n\t\t\t\n\t\t\tDefine(\"vending_machine\", new AnyDrop(\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tChance = 1f,\n\t\t\t\t\tItems = new[] {\n\t\t\t\t\t\t\"bk:coin\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tMin = 2,\n\t\t\t\t\tMax = 7\n\t\t\t\t}, \n\t\t\t\t\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tChance = 0.3f,\n\t\t\t\t\tItems = new[] {\n\t\t\t\t\t\t\"bk:key\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t));\n\n\t\t\tDefine(\"boxy\", new OneOfDrop(\n\t\t\t\tnew OneOfDrop(\n\t\t\t\t\tnew SimpleDrop(0.7f, 1, 1, \"bk:coin_pouch\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 1, \"bk:bloody_chest\"),\n\t\t\t\t\tnew SimpleDrop(0.5f, 1, 1, \"bk:backpack\"),\n\t\t\t\t\tnew SimpleDrop(0.6f, 1, 1, \"bk:star\")\n\t\t\t\t) {\n\t\t\t\t\tChance = 0.9f\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tnew SimpleDrop {\n\t\t\t\t\tItems = new [] {\n\t\t\t\t\t\t\"bk:coin\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tChance = 0.8f,\n\t\t\t\t\tMin = 5,\n\t\t\t\t\tMax = 8\n\t\t\t\t}\n\t\t\t));\n\t\t}\n\n\t\tpublic static Drop Get(string drop) {\n\t\t\tif (!Defined.TryGetValue(drop, out var d)) {\n\t\t\t\tLog.Error($\"Unknown drop {drop}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn d;\n\t\t}\n\t\t\n\t\tpublic static void Define(string id, Drop drop, Mod mod = null) {\n\t\t\tDefined[$\"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}\"] = drop;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/loot/LootTables.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing BurningKnight.entity.creature.drop;\nusing ImGuiNET;\nusing Lens.lightJson;\nusing Lens.lightJson.Serialization;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.assets.loot {\n\tpublic static class LootTables {\n\t\tpublic static Dictionary<string, Drop> Defined = new Dictionary<string, Drop>();\n\t\tpublic static Dictionary<string, JsonValue> Data = new Dictionary<string, JsonValue>();\n\t\tpublic static int LastDropId;\n\n\t\tpublic static void Load() {\n\t\t\tif (true) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLoad(FileHandle.FromRoot(\"Loot/\"));\n\t\t}\n\n\t\tprivate static void Load(FileHandle handle) {\n\t\t\tif (!handle.Exists()) {\n\t\t\t\tLog.Error($\"Loot table {handle.FullPath} does not exist!\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (handle.IsDirectory()) {\n\t\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in handle.ListDirectoryHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (handle.Extension != \".json\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar root = JsonValue.Parse(handle.ReadAll());\n\n\t\t\tforeach (var table in root.AsJsonObject) {\n\t\t\t\ttry {\n\t\t\t\t\tParseTable(table.Key, table.Value);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Save() {\n\t\t\tLog.Info(\"Saving loot tables\");\n\t\t\t\n\t\t\tvar root = new JsonObject();\n\n\t\t\tforeach (var d in Data) {\n\t\t\t\troot[d.Key] = d.Value;\n\t\t\t}\n\t\t\t\n\t\t\tvar file = File.CreateText(FileHandle.FromRoot(\"Loot/loot.json\").FullPath);\n\t\t\tvar writer = new JsonWriter(file);\n\t\t\twriter.Write(root);\n\t\t\tfile.Close();\n\t\t}\n\n\t\tpublic static void ParseTable(string id, JsonValue table) {\n\t\t\tvar drop = ParseDrop(table);\n\n\t\t\tif (drop == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tDefined[id] = drop;\n\t\t\tData[id] = table;\n\t\t}\n\n\t\tpublic static JsonValue WriteDrop(Drop drop) {\n\t\t\tvar o = new JsonObject();\n\n\t\t\to[\"type\"] = drop.GetId();\n\t\t\tdrop.Save(o);\n\n\t\t\treturn o;\n\t\t}\n\n\t\tpublic static Drop ParseDrop(JsonValue table) {\n\t\t\tvar type = table[\"type\"].String(null);\n\n\t\t\tif (type == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (!DropRegistry.Defined.TryGetValue(type, out var t)) {\n\t\t\t\tLog.Error($\"Unknown drop type {type}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar drop = (Drop) Activator.CreateInstance(t.Type);\n\t\t\ttable[\"id\"] = LastDropId++;\n\t\t\tdrop.Load(table);\n\n\t\t\treturn drop;\n\t\t}\n\n\t\tpublic static bool RenderDrop(JsonValue drop) {\n\t\t\tvar id = drop[\"type\"].String(\"missing\");\n\n\t\t\tif (DropRegistry.Defined.TryGetValue(id, out var info)) {\n\t\t\t\tif (ImGui.TreeNode($\"{id}%##{drop[\"id\"].AsInteger}\")) {\n\t\t\t\t\tinfo.Render(drop);\n\t\t\t\t\tImGui.TreePop();\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tImGui.BulletText($\"Unknown type {id}\");\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/mod/Mod.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.assets.mod {\n\tpublic abstract class Mod {\n\t\tpublic string Prefix { get; protected set; } = \"null\";\n\n\t\tpublic abstract void Init();\n\t\tpublic abstract void Destroy();\n\t\tpublic abstract void Update(float dt);\n\t\tpublic abstract void Render();\n\t\t\n\t\tpublic static Mod Load(FileHandle file) {\n\t\t\tvar dll = Assembly.LoadFile(file.FullPath);\n\n\t\t\tforeach (var type in dll.ExportedTypes) {\n\t\t\t\tif (typeof(Mod).IsAssignableFrom(type)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar mod = (Mod) Activator.CreateInstance(type);\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn mod;\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/mod/Mods.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Lens.assets;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.assets.mod {\n\tpublic static class Mods {\n\t\tpublic static Dictionary<string, Mod> Loaded = new Dictionary<string, Mod>();\n\t\tpublic static string BurningKnight = \"bk\";\n\t\t\n\t\tpublic static void Load() {\n\t\t\tif (!Assets.LoadMods) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar dir = FileHandle.FromRoot(\"Mods/\");\n\n\t\t\tif (!dir.Exists()) {\n\t\t\t\tLog.Error(\"Mod directory was not found, creating and exiting.\");\n\t\t\t\tdir.MakeDirectory();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tLog.Info(\"Found mod directory\");\n\n\t\t\tforeach (var handle in dir.ListFileHandles()) {\n\t\t\t\tif (handle.Extension != \".dll\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar mod = Mod.Load(handle);\n\n\t\t\t\tif (mod == null) {\n\t\t\t\t\tLog.Error($\"Failed to load mod {handle.Name}\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar prefix = mod.Prefix;\n\n\t\t\t\tif (Loaded.ContainsKey(prefix)) {\n\t\t\t\t\tLog.Error($\"Conflicting mods with the same prefix {prefix}\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tLog.Info($\"Loaded mod {prefix}\");\n\t\t\t\tLoaded[prefix] = mod;\n\t\t\t\tmod.Init();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Update(float dt) {\n\t\t\tforeach (var mod in Loaded.Values) {\n\t\t\t\tmod.Update(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Render() {\n\t\t\tforeach (var mod in Loaded.Values) {\n\t\t\t\tmod.Render();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tforeach (var mod in Loaded.Values) {\n\t\t\t\tmod.Destroy();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/AnimatedParticle.cs",
    "content": "﻿using BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing Lens.assets;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.assets.particle {\n\tpublic class AnimatedParticle : Particle {\n\t\tpublic Animation Animation;\n\n\t\tpublic AnimatedParticle(ParticleController controller, ParticleRenderer renderer, string animation, string tag = null) : base(controller, renderer) {\n\t\t\tAnimation = Animations.Create(animation);\n\n\t\t\tif (tag != null) {\n\t\t\t\tAnimation.Tag = tag;\n\t\t\t}\n\n\t\t\tAnimation.OnEnd += () => { Done = true; };\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tAnimation.Update(dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/Particle.cs",
    "content": "using BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle {\n\tpublic class Particle {\n\t\tpublic ParticleController Controller;\n\t\tpublic ParticleRenderer Renderer;\n\t\t\n\t\tpublic Vector2 Position;\n\t\tpublic Vector2 Velocity;\n\n\t\tpublic float Z;\n\t\tpublic float Zv;\n\t\t\n\t\tpublic float Angle;\n\t\tpublic float AngleVelocity;\n\n\t\tpublic float T;\n\t\tpublic float Alpha = 1f;\n\t\tpublic float Scale = 1f;\n\t\tpublic bool Done;\n\t\tpublic int Rnd;\n\n\t\tpublic Particle(ParticleController controller, ParticleRenderer renderer) {\n\t\t\tController = controller;\n\t\t\tRenderer = renderer;\n\n\t\t\tAngle = Lens.util.math.Rnd.AnglePI();\n\t\t\tRnd = Lens.util.math.Rnd.Int(1024);\n\t\t\tT = Lens.util.math.Rnd.Float(1f);\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/ParticleEmitter.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle {\n\tpublic class ParticleEmitter : ParticleSystem {\n\t\tpublic float Rate;\n\t\tpublic float Elapsed;\n\t\tpublic float TillDeath;\n\t\t\n\t\tpublic ParticleEmitter(Func<Particle> create, int min, int max, Vector2 position, float rate, float time = -1) : base(create, min, max, position) {\n\t\t\tRate = rate;\n\t\t\tTillDeath = time;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tif (TillDeath > -1) {\n\t\t\t\tTillDeath -= dt;\n\n\t\t\t\tif (TillDeath <= 0) {\n\t\t\t\t\tDone = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tElapsed += dt;\n\t\t\t\n\t\t\twhile (Elapsed > Rate) {\n\t\t\t\tElapsed -= Rate;\n\t\t\t\tAddParticle();\n\t\t\t}\n\t\t\t\n\t\t\tbase.Update(dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/ParticleEntity.cs",
    "content": "using BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.assets.particle {\n\t// Wraps particle for cases, when particle system is too much\n\tpublic class ParticleEntity : Entity {\n\t\tpublic Particle Particle;\n\n\t\tpublic ParticleEntity(Particle particle) {\n\t\t\tParticle = particle;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tWidth = 0;\n\t\t\tHeight = 0;\n\t\t\t\n\t\t\tParticle.Controller.Init(Particle, this);\n\t\t\tAlwaysActive = true;\n\n\t\t\tDepth = Layers.FloorParticles;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (Particle.Controller.Update(Particle, dt) || Particle.Done) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Depth == Layers.FloorParticles || Depth == Layers.FlyingMob) {\n\t\t\t\tDepth = Particle.Z > 1 ? Layers.FlyingMob : Layers.FloorParticles;\n\t\t\t}\n\n\t\t\tPosition = Particle.Position;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\t\t\t\n\t\t\tif (!Particle.Done) {\n\t\t\t\tParticle.Renderer.Render(Particle);\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddShadow() {\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tif (!Particle.Done) {\n\t\t\t\tParticle.Renderer.RenderShadow(Particle);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/ParticleSystem.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle {\n\tpublic class ParticleSystem : Entity {\n\t\tpublic List<Particle> Particles = new List<Particle>();\n\t\tpublic Func<Particle> Create;\n\t\t\n\t\tpublic ParticleSystem(Func<Particle> create, int min, int max, Vector2 position) {\n\t\t\tCreate = create;\n\t\t\tPosition = position;\n\n\t\t\tvar count = Rnd.Int(min, max + 1);\n\n\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\tAddParticle();\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddParticle() {\n\t\t\tvar particle = Create();\n\t\t\tparticle.Controller.Init(particle, this);\n\t\t\t\n\t\t\tParticles.Add(particle);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tfor (int i = Particles.Count - 1; i >= 0; i--) {\n\t\t\t\tvar particle = Particles[i];\n\n\t\t\t\tif (particle.Controller.Update(particle, dt) || particle.Done) {\n\t\t\t\t\tParticles.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Particles.Count == 0) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tforeach (var particle in Particles) {\n\t\t\t\tif (!particle.Done) {\n\t\t\t\t\tparticle.Renderer.Render(particle);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/Particles.cs",
    "content": "using System;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle {\n\tpublic static class Particles {\n\t\tprivate static ParticleRenderer[] dustRenderers = {\n\t\t\tnew TexturedParticleRenderer(\"dust_0\"),\n\t\t\tnew TexturedParticleRenderer(\"dust_1\"),\n\t\t\tnew TexturedParticleRenderer(\"dust_2\")\n\t\t};\n\t\t\n\t\tprivate static ParticleRenderer[] ashRenderers = {\n\t\t\tnew TexturedParticleRenderer(\"d_1\"),\n\t\t\tnew TexturedParticleRenderer(\"d_2\"),\n\t\t\tnew TexturedParticleRenderer(\"d_3\"),\n\t\t\tnew TexturedParticleRenderer(\"d_4\")\n\t\t};\n\t\t\n\t\tprivate static ParticleRenderer[] rainRenderers = {\n\t\t\tnew TexturedParticleRenderer(\"rain_1\"),\n\t\t\tnew TexturedParticleRenderer(\"rain_2\"),\n\t\t\tnew TexturedParticleRenderer(\"rain_3\")\n\t\t};\n\n\t\tprivate static ParticleRenderer planksRenderer = new RandomFrameRenderer(\"planks_particle\");\n\t\t\n\t\tpublic static ParticleRenderer BkDeathRenderer = new TexturedParticleRenderer(\"natural\");\n\t\tpublic static ParticleRenderer SparkRenderer = new TexturedParticleRenderer(\"spark\");\n\t\tpublic static ParticleRenderer BloodRenderer = new TexturedParticleRenderer(\"blood\");\n\t\tpublic static ParticleRenderer ScourgeRenderer = new TexturedParticleRenderer(\"curse\");\n\t\tpublic static ParticleRenderer AnimatedRenderer = new AnimatedParticleRenderer();\n\t\tpublic static ParticleRenderer LavaRenderer = new TexturedParticleRenderer(\"lava\");\n\n\t\tpublic static Particle Textured(string slice) {\n\t\t\treturn new Particle(Controllers.Simple, new TexturedParticleRenderer(slice));\n\t\t}\n\t\t\n\t\tpublic static AnimatedParticle Animated(string animation, string tag = null) {\n\t\t\treturn new AnimatedParticle(Controllers.Animated, AnimatedRenderer, animation, tag);\n\t\t}\n\n\t\tpublic static Particle Lava() {\n\t\t\treturn new Particle(Controllers.Lava, LavaRenderer);\n\t\t}\n\n\t\tpublic static Particle Dust() {\n\t\t\treturn new Particle(Controllers.Simple, dustRenderers[Rnd.Int(3)]);\n\t\t}\n\t\t\n\t\tpublic static Particle Ash() {\n\t\t\treturn new Particle(Controllers.Ash, ashRenderers[Rnd.Int(3)]);\n\t\t}\n\t\t\n\t\tpublic static Particle Scourge() {\n\t\t\treturn new Particle(Controllers.Scourge, ScourgeRenderer);\n\t\t}\n\n\t\tpublic static Particle Plank() {\n\t\t\treturn new Particle(Controllers.Destroy, planksRenderer);\n\t\t}\n\t\t\n\t\tpublic static Particle Spark() {\n\t\t\treturn new Particle(Controllers.Spark, SparkRenderer);\n\t\t}\n\n\t\tpublic static Particle Rain() {\n\t\t\treturn new Particle(Controllers.Rain, rainRenderers[Rnd.Int(3)]);\n\t\t}\n\n\t\tpublic static ParticleEntity Wrap(Particle particle, Area area, Vector2 where) {\n\t\t\tvar e = new ParticleEntity(particle);\n\t\t\te.Position = where;\n\t\t\te.Particle.Position = where;\n\n\t\t\tarea.Add(e);\n\t\t\t\n\t\t\treturn e;\n\t\t}\n\n\t\tpublic static void BreakSprite(Area area, TextureRegion region, Vector2 position, int depth = -1) {\n\t\t\tvar s = 5;\n\t\t\t\t\t\t\n\t\t\tfor (int x = 0; x < region.Width; x += s) {\n\t\t\t\tfor (int y = 0; y < region.Height; y += s) {\n\t\t\t\t\tvar r = new TextureRegion(region, s, s);\n\t\t\t\t\t\n\t\t\t\t\tr.Source.X += x;\n\t\t\t\t\tr.Source.Y += y;\n\t\t\t\t\t\n\t\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Destroy, new TexturedParticleRenderer {\n\t\t\t\t\t\tRegion = r\n\t\t\t\t\t}));\n\n\t\t\t\t\tpart.Particle.Angle = (float) (Math.Atan2(r.Center.Y - y, r.Center.X - x) - Math.PI + Rnd.Float(-1, 1));\n\t\t\t\t\tpart.Position = position + new Vector2(x, y);\n\t\t\t\t\tarea.Add(part);\n\n\t\t\t\t\tif (depth != -1) {\n\t\t\t\t\t\tpart.Depth = depth;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/AnimatedParticleController.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class AnimatedParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\t\t\t\n\t\t\tparticle.AngleVelocity = Rnd.Float(0.6f, 1) * 16 * (Rnd.Chance() ? -1 : 1);\n\n\t\t\tvar a = Rnd.AnglePI();\n\t\t\tvar f = Rnd.Float(0.6f, 1f) * 40f;\n\t\t\t\n\t\t\tparticle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f);\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\n\t\t\tif (particle.Scale <= 0f) {\n\t\t\t\tparticle.Scale = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tparticle.AngleVelocity -= particle.AngleVelocity * dt * 4;\n\t\t\tparticle.Velocity -= particle.Velocity * dt * 4;\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/AshController.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\n\tpublic class AshController : ParticleController {\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Velocity -= particle.Velocity * dt * 2;\n\n\t\t\tif (particle.T >= 0.3f) {\n\t\t\t\tparticle.Scale -= dt * 1.5f;\n\n\t\t\t\tif (particle.Scale <= 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/BkDeathParticleController.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class BkDeathParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\n\t\t\tvar a = Rnd.AnglePI();\n\t\t\tvar d = Rnd.Float(60, 90);\n\t\t\t\n\t\t\tparticle.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Velocity -= particle.Velocity * (dt * 2);\n\t\t\tparticle.Alpha -= dt;\n\n\t\t\tif (particle.Alpha <= 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/BloodParticleController.cs",
    "content": "using Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class BloodParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\t\t\t\n\t\t\tparticle.AngleVelocity = Rnd.Float(0.6f, 1) * 5 * (Rnd.Chance() ? -1 : 1);\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Scale -= dt * 2f;\n\n\t\t\tif (particle.Scale <= 0f) {\n\t\t\t\tparticle.Scale = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tparticle.Velocity.X -= particle.Velocity.X * dt;\n\t\t\tparticle.Velocity.Y += dt * 256;\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/Controllers.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\n\tpublic static class Controllers {\n\t\tpublic static ParticleController Simple = new SimpleParticleController();\n\t\tpublic static ParticleController Destroy = new DestroyParticleController();\n\t\tpublic static ParticleController Float = new FloatParticleController();\n\t\tpublic static ParticleController BkDeath = new BkDeathParticleController();\n\t\tpublic static ParticleController Spark = new SparkParticleController();\n\t\tpublic static ParticleController Blood = new BloodParticleController();\n\t\tpublic static ParticleController Scourge = new ScourgeController();\n\t\tpublic static ParticleController Ash = new AshController();\n\t\tpublic static ParticleController Animated = new AnimatedParticleController();\n\t\tpublic static ParticleController Rain = new RainParticleController();\n\t\tpublic static ParticleController Lava = new LavaController();\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/DestroyParticleController.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class DestroyParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tparticle.Position = owner.Center;\n\t\t\tparticle.AngleVelocity = Rnd.Float(0.6f, 1) * Rnd.Float(24, 48) * (Rnd.Chance() ? -1 : 1);\n\n\t\t\tvar a = particle.Angle;\n\t\t\tvar f = Rnd.Float(0.6f, 1f) * Rnd.Float(80, 120f);\n\n\t\t\tparticle.Angle = 0;\n\t\t\tparticle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f);\n\t\t\tparticle.Zv = Rnd.Float(1, 3);\n\n\t\t\tparticle.T = Rnd.Float(1f);\n\t\t}\n\t\t\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\n\t\t\tparticle.AngleVelocity -= particle.AngleVelocity * dt * 4;\n\t\t\tparticle.Velocity -= particle.Velocity * dt * 2;\n\n\t\t\tparticle.Z += particle.Zv * dt * 60;\n\n\t\t\tif (particle.Z <= 0) {\n\t\t\t\tparticle.Z = 0;\n\t\t\t\tparticle.Zv = 0;\n\t\t\t\tparticle.Velocity.X = 0;\n\t\t\t\tparticle.Velocity.Y = 0;\n\t\t\t} else {\n\t\t\t\tparticle.Zv -= dt * 5;\n\t\t\t}\n\n\t\t\tparticle.Update(dt);\n\n\t\t\tif (particle.T >= 5f) {\n\t\t\t\tparticle.Alpha -= dt * 0.3f;\n\n\t\t\t\tif (particle.Alpha <= 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/FloatParticleController.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\r\n\tpublic class FloatParticleController : ParticleController {\r\n\t\tpublic override bool Update(Particle particle, float dt) {\r\n\t\t\tparticle.T += dt;\r\n\t\t\tparticle.Position += particle.Velocity * dt;\r\n\t\t\tparticle.Velocity -= particle.Velocity * dt * 2;\r\n\t\t\t\r\n\t\t\tif (particle.T >= 1.7f) {\r\n\t\t\t\tparticle.Scale -= dt * 3f;\r\n\r\n\t\t\t\tif (particle.Scale <= 0) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.Update(particle, dt);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/HealthParticleController.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\n\tpublic class HealthParticleController : ParticleController {\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.Velocity.Y += dt * 256;\n\t\t\tparticle.Position.Y += particle.Velocity.Y * dt;\n\t\t\tparticle.Alpha -= dt;\n\n\t\t\tif (particle.Alpha <= 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/LavaController.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\n\tpublic class LavaController : ParticleController {\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Velocity.X -= particle.Velocity.X * dt * 4;\n\t\t\tparticle.Velocity.Y += dt * 40;\n\n\t\t\tif (particle.Velocity.Y > 0) {\n\t\t\t\tparticle.Scale -= dt * 0.5f;\n\n\t\t\t\tif (particle.Scale <= 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/ParticleController.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class ParticleController {\n\t\tpublic virtual void Init(Particle particle, Entity owner) {\n\t\t\tparticle.Position = owner.Center;\n\t\t}\n\t\t\n\t\tpublic virtual bool Update(Particle particle, float dt) {\n\t\t\tparticle.Update(dt);\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/RainParticleController.cs",
    "content": "using Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class RainParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\t\t\t\n\t\t\tparticle.AngleVelocity = Rnd.Float(0.6f, 1) * 5 * (Rnd.Chance() ? -1 : 1);\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Scale -= dt * 4f;\n\n\t\t\tif (particle.Scale <= 0f) {\n\t\t\t\tparticle.Scale = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tparticle.Velocity.X -= particle.Velocity.X * dt;\n\t\t\tparticle.Velocity.Y += dt * 256;\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/ScourgeController.cs",
    "content": "namespace BurningKnight.assets.particle.controller {\n\tpublic class ScourgeController : SimpleParticleController {\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Scale -= dt * 0.5f;\n\n\t\t\tif (particle.Scale <= 0f) {\n\t\t\t\tparticle.Scale = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tparticle.AngleVelocity -= particle.AngleVelocity * dt * 4;\n\t\t\tparticle.Velocity.X -= particle.Velocity.X * dt * 5;\n\t\t\tparticle.Velocity.Y -= dt * 60f;\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/SimpleParticleController.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class SimpleParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\t\t\t\n\t\t\tparticle.AngleVelocity = Rnd.Float(0.6f, 1) * 16 * (Rnd.Chance() ? -1 : 1);\n\n\t\t\tvar a = Rnd.AnglePI();\n\t\t\tvar f = Rnd.Float(0.6f, 1f) * 40f;\n\t\t\t\n\t\t\tparticle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f);\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.T += dt;\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.Position += particle.Velocity * dt;\n\t\t\tparticle.Scale -= dt;\n\n\t\t\tif (particle.Scale <= 0f) {\n\t\t\t\tparticle.Scale = 0;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tparticle.AngleVelocity -= particle.AngleVelocity * dt * 4;\n\t\t\tparticle.Velocity -= particle.Velocity * dt * 4;\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/controller/SparkParticleController.cs",
    "content": "using Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.assets.particle.controller {\n\tpublic class SparkParticleController : ParticleController {\n\t\tpublic override void Init(Particle particle, Entity owner) {\n\t\t\tbase.Init(particle, owner);\n\n\t\t\tparticle.AngleVelocity = Rnd.Sign() * Rnd.Float(1, 2);\n\t\t\tparticle.Scale = 0;\n\t\t\tparticle.Alpha = 1f;\n\t\t\tparticle.T = 0;\n\t\t}\n\n\t\tpublic override bool Update(Particle particle, float dt) {\n\t\t\tparticle.Angle += particle.AngleVelocity * dt;\n\t\t\tparticle.T += dt;\n\t\t\t\n\t\t\tif (particle.T < 1f) {\n\t\t\t\tparticle.Scale += dt;\n\n\t\t\t\tif (particle.Scale >= 1f) {\n\t\t\t\t\tparticle.Scale = 1f;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparticle.AngleVelocity -= particle.AngleVelocity * dt;\n\t\t\t\t\n\t\t\t\tif (particle.T > 2f) {\n\t\t\t\t\tparticle.Scale -= dt * 0.5f;\n\n\t\t\t\t\tif (particle.Scale <= 0) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.Update(particle, dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/BuffParticle.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class BuffParticle : Entity {\n\t\tpublic Buff Buff;\n\t\tpublic Entity Entity;\n\t\tpublic int Id;\n\n\t\tprivate TextureRegion region;\n\t\tprivate Vector2 scale = new Vector2(0, Display.UiScale * 3);\n\t\tprivate bool removing;\n\t\t\n\t\tpublic BuffParticle(Buff buff, Entity entity) {\n\t\t\tBuff = buff;\n\t\t\tEntity = entity;\n\t\t\tId = entity.GetComponent<BuffsComponent>().Particles.Count;\n\n\t\t\tregion = CommonAse.Ui.GetSlice(buff.GetIcon());\n\t\t\tWidth = 8 * Display.UiScale;\n\t\t\tHeight = region.Height * Display.UiScale;\n\t\t\t\n\t\t\tTween.To(Display.UiScale, scale.X, x => scale.X = x, 0.3f);\n\t\t\tTween.To(Display.UiScale, scale.Y, x => scale.Y = x, 0.3f);\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Entity.Done) {\n\t\t\t\tRemove();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Remove() {\n\t\t\tif (removing) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tremoving = true;\n\t\t\t\n\t\t\tTween.To(Display.UiScale * 4, scale.X, x => scale.X = x, 0.3f);\n\t\t\tTween.To(0, scale.Y, x => scale.Y = x, 0.3f).OnEnd = () => {\n\t\t\t\tDone = true;\n\n\t\t\t\tforeach (var p in Entity.GetComponent<BuffsComponent>().Particles) {\n\t\t\t\t\tif (p.Id > Id) {\n\t\t\t\t\t\tp.Id--;\n\t\t\t\t\t\tp.lastX -= (Width + 4) * 0.5f;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprivate float lastX;\n\n\t\tpublic override void Render() {\n\t\t\tvar origin = region.Center;\n\t\t\tvar tar = (Entity.GetComponent<BuffsComponent>().Particles.Count - 1) * (Width + 4) * 0.5f;\n\n\t\t\tlastX += (tar - lastX) * Engine.Delta * 5;\n\t\t\t\n\t\t\tvar x = Id * (Width + 4) - lastX;\n\t\t\tvar pos = Entity.TopCenter;\n\n\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\tpos -= new Vector2(0, z.Z);\n\t\t\t}\n\t\t\t\n\t\t\tCenter = Camera.Instance.CameraToUi(pos) + new Vector2(x, scale.X - Display.UiScale - 8);\n\n\t\t\tGraphics.Render(region, Position + origin, 0, origin, scale);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/ConfettiParticle.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class ConfettiParticle : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate float t;\n\t\tprivate float rotationOffset;\n\t\tprivate float z;\n\t\tprivate float vz;\n\t\tprivate float vx;\n\t\tprivate float speed;\n\t\tprivate Color color;\n\t\tprivate float scale = 1;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tcolor = ColorUtils.FromHSV(Rnd.Float(360), 100, 100);\n\t\t\t\n\t\t\tspeed = Rnd.Float(0.5f, 2f);\n\t\t\tvx = Rnd.Float(-5, 5);\n\t\t\tvz = -Rnd.Float(5, 12);\n\t\t\tt = Rnd.Float(10);\n\t\t\trotationOffset = Rnd.Float(0.5f, 2f);\n\n\t\t\tAlwaysActive = true;\n\n\t\t\tWidth = Rnd.Float(6, 10);\n\t\t\tHeight = Width * 0.3f;\n\t\t\tregion = CommonAse.Particles.GetSlice(\"fire\");\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt * speed * 6;\n\n\t\t\tX += vx * dt * 50;\n\t\t\tvx -= vx * dt * 10;\n\n\t\t\tz += vz * dt * 10;\n\t\t\tvz += 20 * dt;\n\n\t\t\tif (vz >= 0) {\n\t\t\t\tif (z > 0) {\n\t\t\t\t\tz = 0;\n\t\t\t\t}\n\n\t\t\t\tscale -= dt;\n\n\t\t\t\tif (scale <= 0) {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Center + new Vector2(0, z), (float) Math.Sin(t * rotationOffset), region.Center,  new Vector2((float) Math.Cos(t * 0.5f) * Width * scale, Height * scale));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/ConsumableParticle.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class ConsumableParticle : Entity {\n\t\tprivate Vector2 target = new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\n\t\tprivate TextureRegion region;\n\t\tprivate float angle;\n\t\tprivate float angleV;\n\t\tprivate float speed;\n\t\tprivate bool tweened;\n\t\tprivate Player player;\n\t\tprivate Vector2 scale = new Vector2(0, Display.UiScale * 2);\n\t\tprivate Action callback;\n\t\tprivate Vector2 offset;\n\t\t\n\t\tpublic ConsumableParticle(TextureRegion r, Player p, bool item = false, Action call = null, bool emerald = false) {\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tregion = r;\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\n\t\t\tplayer = p;\n\n\t\t\toffset = new Vector2(Rnd.Int(-4, 4), Height + Rnd.Int(-4, 4));\n\t\t\tspeed = Rnd.Float(1, 2f) * (Rnd.Chance() ? -1 : 1);\n\n\t\t\tvar s = item ? Display.UiScale : Rnd.Float(1f, 2f);\n\n\t\t\tTween.To(s, scale.X, x => scale.X = x, 0.3f);\n\t\t\tTween.To(s, scale.Y, x => scale.Y = x, 0.3f);\n\n\t\t\tif (item) {\n\t\t\t\ttarget += new Vector2(Display.UiWidth, Display.UiHeight);\n\t\t\t} else if (emerald) {\n\t\t\t\ttarget += new Vector2(Display.UiWidth, 0);\n\t\t\t}\n\n\t\t\tcallback = call;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (player == null || Camera.Instance == null) {\n\t\t\t\tDone = true;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCenter = Camera.Instance.CameraToUi(player.TopCenter) - offset;\n\n\t\t\tTimer.Add(() => {\n\t\t\t\ttweened = true;\n\t\t\t\tcallback?.Invoke();\n\t\t\t\t\n\t\t\t\tTween.To(target.X, X, x => X = x, 1f, Ease.QuadInOut);\n\t\t\t\tTween.To(target.Y, Y, x => Y = x, 1f, Ease.QuadInOut).OnEnd = () => {\n\t\t\t\t\tDone = true;\n\t\t\t\t};\n\t\t\t}, 1f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (tweened) {\n\t\t\t\tangleV += dt * speed * 2;\n\t\t\t\tangle += angleV * dt * 20;\n\t\t\t\t\n\t\t\t\tscale.X -= dt * 2.2f;\n\t\t\t\tscale.Y -= dt * 2.2f;\n\n\t\t\t\tif (scale.X <= 0) {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar pos = player.TopCenter;\n\n\t\t\t\tif (player.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\tpos -= new Vector2(0, z.Z);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tCenter = Camera.Instance.CameraToUi(pos) - offset;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tvar origin = region.Center;\n\t\t\tGraphics.Render(region, Position + origin, angle, origin, scale);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/EpicSpawn.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.entity;\r\nusing Lens;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.assets.particle.custom {\r\n\tpublic class EpicSpawn : Entity {\r\n\t\tprivate TextureRegion region;\r\n\t\tprivate TextureRegion ray;\r\n\t\tprivate float scale;\r\n\t\tprivate float angle;\r\n\t\tprivate float t;\r\n\t\tprivate List<Ray> rays = new List<Ray>();\r\n\t\tprivate float tt;\r\n\t\tprivate float lastRay = 0.25f;\r\n\r\n\t\tpublic Action OnEnd;\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\ttt = Rnd.Float(1024);\r\n\r\n\t\t\tDepth = Layers.Ui;\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tAlwaysVisible = true;\r\n\r\n\t\t\tregion = CommonAse.Particles.GetSlice(\"epic_spawn\");\r\n\t\t\tray = CommonAse.Particles.GetSlice(\"ray\");\r\n\t\t\t\r\n\t\t\tWidth = region.Width;\r\n\t\t\tHeight = region.Height;\r\n\r\n\t\t\tAddComponent(new LightComponent(this, 64f, ColorUtils.WhiteColor));\r\n\t\t\tTween.To(0.5f, scale, x => scale = x, 0.5f, Ease.BackOut);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tlastRay -= dt;\r\n\r\n\t\t\tif (lastRay <= 0) {\r\n\t\t\t\tlastRay = Math.Max(0.1f, (5f - t) / 20f);\r\n\t\t\t\trays.Add(new Ray {\r\n\t\t\t\t\tAngle = Rnd.AnglePI()\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tGetComponent<LightComponent>().Light.Radius = scale * 2f;\r\n\r\n\t\t\tt += dt;\r\n\t\t\ttt += dt;\r\n\r\n\t\t\tif (t > 0.5f) {\r\n\t\t\t\tangle += (t - 0.5f) * 300 * dt;\r\n\t\t\t\tscale += dt * scale;\r\n\t\t\t}\r\n\r\n\t\t\tif (scale >= 12) {\r\n\t\t\t\tDone = true;\r\n\t\t\t\tOnEnd?.Invoke();\r\n\t\t\t}\r\n\r\n\t\t\tforeach (var r in rays) {\t\t\t\t\r\n\t\t\t\tr.Scale.Y = r.Scale.X = Math.Min(1, r.Scale.X + dt);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tGraphics.Render(region, Position + region.Center, angle, region.Center, new Vector2(scale));\r\n\r\n\t\t\tforeach (var r in rays) {\r\n\t\t\t\tGraphics.Render(ray, Center, r.Angle + t - (0.5f) * (1 + t * 0.02f), new Vector2(0, 30), r.Scale);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate class Ray {\r\n\t\t\tpublic float Angle;\r\n\t\t\tpublic Vector2 Scale;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/FadingParticle.cs",
    "content": "using Lens.entity;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class FadingParticle : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate Vector2 scale = Vector2.One;\n\t\tprivate Vector4 color;\n\n\t\tpublic FadingParticle(TextureRegion sprite, Color tint) {\n\t\t\tregion = sprite;\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tWidth = sprite.Width;\n\t\t\tHeight = sprite.Height;\n\n\t\t\tcolor.X = tint.R / 255f;\n\t\t\tcolor.Y = tint.G / 255f;\n\t\t\tcolor.Z = tint.B / 255f;\n\t\t\tcolor.W = tint.A / 255f;\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tscale.X -= dt * 0.8f;\n\t\t\tscale.Y = scale.X;\n\n\t\t\tif (scale.X <= 0) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tvar shader = Shaders.Entity;\n\t\t\tShaders.Begin(shader);\n\n\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\tshader.Parameters[\"flashColor\"].SetValue(color);\n\t\t\t\n\t\t\tGraphics.Render(region, Center, 0, region.Center, scale);\n\n\t\t\tShaders.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/FireEmitter.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class FireEmitter : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate float t;\n\t\t\n\t\tpublic float Scale = 1;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tregion = CommonAse.Particles.GetSlice(\"fire_emitter\");\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\t\t\tt = Rnd.Float(6);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt * 10;\n\t\t}\n\n\t\tprivate static Color ca = new Color(1f, 0.5f, 0f, 0.5f);\n\t\tprivate static Color cb = new Color(1f, 0.5f, 0f, 1f);\n\n\t\tpublic override void Render() {\n\t\t\tvar s = Scale * (float) ((Math.Cos(t * 0.5f) * Math.Sin((t + 0.2f) * 0.8f)) * 0.25f + 0.75f);\n\t\t\tGraphics.Color = ca;\n\t\t\tGraphics.Render(region, Position, 0, region.Center, new Vector2(s));\n\t\t\tGraphics.Color = cb;\n\t\t\tGraphics.Render(region, Position, 0, region.Center, new Vector2(s * 0.5f));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/FireParticle.cs",
    "content": "using System;\r\nusing BurningKnight.entity;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.state;\r\nusing Lens;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing VelcroPhysics.Dynamics;\r\nusing MathUtils = Lens.util.MathUtils;\r\n\r\nnamespace BurningKnight.assets.particle.custom {\r\n\tpublic class FireParticle : Entity {\r\n\t\tpublic static TextureRegion Region;\r\n\t\t\r\n\t\tpublic Entity Owner;\r\n\t\tpublic float Delay;\r\n\r\n\t\tpublic float T;\r\n\t\tpublic float Scale;\r\n\t\tpublic float ScaleTar;\r\n\t\tpublic Vector2 Offset;\r\n\t\tpublic float Vy;\r\n\t\tpublic float Vx;\r\n\t\tpublic bool Growing;\r\n\t\tpublic float SinOffset;\r\n\t\tpublic float Mod;\r\n\r\n\t\tpublic float R = 1f;\r\n\t\tpublic float G = 1f;\r\n\t\tpublic float B = 1f;\r\n\t\tpublic float Size = 1;\r\n\t\tpublic bool Hurts;\r\n\t\t\r\n\t\tpublic Vector2? Target;\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tif (Region == null) {\r\n\t\t\t\tRegion = CommonAse.Particles.GetSlice(\"fire\");\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tAddTag(Tags.FireParticle);\r\n\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tAlwaysVisible = true;\r\n\t\t\t\r\n\t\t\tGrowing = true;\r\n\t\t\tScaleTar = Rnd.Float(0.5f, 0.9f) * Size;\r\n\r\n\t\t\tif (Mod < 0.01f) {\r\n\t\t\t\tMod = Rnd.Float(0.7f, 1f);\r\n\t\t\t}\r\n\r\n\t\t\tSinOffset = Rnd.Float(3.2f);\r\n\r\n\t\t\tif (Math.Abs(Offset.X) + Math.Abs(Offset.Y) < 0.1f) {\r\n\t\t\t\tOffset = new Vector2(Rnd.Float(-4, 4) * XChange, Rnd.Float(-2, 2));\r\n\t\t\t}\r\n\r\n\t\t\tDepth = Layers.TileLights + 1;\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tif (Hurts) {\r\n\t\t\t\tAddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true, true));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tif (Delay > 0) {\r\n\t\t\t\tDelay -= dt;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tT += dt;\r\n\r\n\t\t\tif (T > 0.3f) {\r\n\t\t\t\tif (Run.Level != null && Run.Level.Biome is CaveBiome) {\r\n\t\t\t\t\tR = Math.Max(0, R - dt * 3 * Mod);\r\n\t\t\t\t\tG = Math.Max(0, G - dt * 0.3f * Mod);\r\n\t\t\t\t\tB = Math.Max(0, B - dt * Mod);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tR = Math.Max(0, R - dt * 0.3f * Mod);\r\n\t\t\t\t\tG = Math.Max(0, G - dt * Mod);\r\n\t\t\t\t\tB = Math.Max(0, B - dt * 3 * Mod);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (Growing) {\r\n\t\t\t\tScale += dt;\r\n\r\n\t\t\t\tif (Scale >= ScaleTar) {\r\n\t\t\t\t\tScale = ScaleTar;\r\n\t\t\t\t\tGrowing = false;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tScale -= dt * (Target.HasValue ? 0.33f : 0.5f);\r\n\r\n\t\t\t\tif (Scale <= 0) {\r\n\t\t\t\t\tDone = true;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tVy += dt * Mod * 20;\r\n\r\n\t\t\tif (Target.HasValue) {\r\n\t\t\t\tvar t = Target.Value;\r\n\r\n\t\t\t\tvar dx = t.X - Position.X - Offset.X;\r\n\t\t\t\tvar dy = t.Y - Position.Y - Offset.Y;\r\n\t\t\t\tvar d = MathUtils.Distance(Vx, Vy) + dt * 30;\r\n\t\t\t\t\r\n\t\t\t\tvar angle = Math.Atan2(dy, dx);\r\n\t\t\t\tvar va = Math.Atan2(-Vy, -Vx);\r\n\r\n\t\t\t\tva = MathUtils.LerpAngle(va, angle, dt * 4);\r\n\r\n\t\t\t\tVx = (float) -Math.Cos(va) * d;\r\n\t\t\t\tVy = (float) -Math.Sin(va) * d;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tOffset.X -= Vx * dt;\r\n\t\t\tOffset.Y -= Vy * dt;\r\n\t\t\t\r\n\t\t\tif (Owner != null) {\r\n\t\t\t\tX = Owner.CenterX; \r\n\t\t\t\tY = Owner.Bottom;\r\n\r\n\t\t\t\tif (Owner.TryGetComponent<ZComponent>(out var z)) {\r\n\t\t\t\t\tY -= z.Z;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (Hurts) {\r\n\t\t\t\tGetComponent<CircleBodyComponent>().Position = Position + Offset;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent cse) {\r\n\t\t\t\tif (cse.Entity is Player p) {\r\n\t\t\t\t\tp.GetComponent<HealthComponent>().ModifyHealth(-1, this);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic float XChange = 1;\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\t\r\n\t\t}\r\n\t\t\r\n\t\tpublic void ActuallyRender() {\r\n\t\t\tif (Delay > 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar a = (float) Math.Cos(T * 5f + SinOffset) * 0.4f;\r\n\t\t\tvar pos = Position + Offset + Region.Center;\r\n\r\n\t\t\tpos.X += (float) Math.Cos(SinOffset + T * 2.5f) * Scale * 8 * XChange;\r\n\t\t\r\n\t\t\tGraphics.Color = new Color(R, G, B, 0.5f);\r\n\t\t\tGraphics.Render(Region, pos, a, Region.Center, new Vector2(Scale * 10));\r\n\t\t\tGraphics.Color = new Color(R, G, B, 1f);\r\n\t\t\tGraphics.Render(Region, pos, a, Region.Center, new Vector2(Scale * 5));\r\n\t\t}\r\n\r\n\t\tpublic static void Hook(Area area) {\r\n\t\t\tarea.Add(new RenderTrigger(() => {\r\n\t\t\t\tvar state = Engine.Instance.StateRenderer;\r\n\r\n\t\t\t\tstate.End();\r\n\t\t\t\tvar b = state.BlendState;\r\n\t\t\t\tstate.BlendState = BlendState.Additive;\r\n\t\t\t\tstate.Begin();\r\n\t\t\t\t\r\n\t\t\t\tforeach (var e in area.Tagged[Tags.FireParticle]) {\r\n\t\t\t\t\t((FireParticle) e).ActuallyRender();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\r\n\t\t\t\tstate.End();\r\n\t\t\t\tstate.BlendState = b;\r\n\t\t\t\tstate.Begin();\r\n\t\t\t}, Layers.WindFx));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/ProjectileParticle.cs",
    "content": "using Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class ProjectileParticle : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate float scale;\n\t\tprivate float angle;\n\t\tprivate Color color = new Color(0.5f, 0.5f, 1f, 1f);\n\t\tprivate Color secondColor = new Color(0.5f, 0.5f, 1f, 0.5f);\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\n\t\t\tscale = Rnd.Float(5, 8);\n\t\t\tangle = Rnd.AnglePI();\n\t\t\tregion = CommonAse.Particles.GetSlice(\"fire\");\n\n\t\t\tWidth = scale;\n\t\t\tHeight = scale;\n\n\t\t\tDepth = 0;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tscale -= dt * 10;\n\t\t\tangle += scale * dt * 6;\n\t\t\t\n\t\t\tif (scale <= 0) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = secondColor;\n\t\t\tGraphics.Render(region, Position, angle, region.Center, new Vector2(scale));\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, angle, region.Center, new Vector2(scale * 0.5f));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/RainParticle.cs",
    "content": "using System;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class RainParticle : Entity {\n\t\tprivate Color color;\n\t\tprivate float target;\n\t\tprivate float size;\n\t\tprivate float speed;\n\t\tprivate bool poofed;\n\n\t\tpublic bool End;\n\t\tpublic bool Custom;\n\n\t\tprivate float delay;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t\tDepth = Layers.WindFx;\n\n\t\t\tReset();\n\n\t\t\tif (!Custom) {\n\t\t\t\tY = Camera.Instance.Y + Rnd.Float(Display.Height + 100);\n\t\t\t} else {\n\t\t\t\tdelay = Rnd.Float(0, 2f);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Reset() {\n\t\t\tif (End) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tcolor = new Color(Rnd.Float(0.3f, 0.5f), Rnd.Float(0.4f, 0.7f), Rnd.Float(0.7f, 0.8f), Rnd.Float(0.5f, 1f));\n\t\t\tX = Rnd.Float(Camera.Instance.X - 150, Camera.Instance.Right + 150);\n\t\t\tY = Camera.Instance.Y - Rnd.Float(50, 60);\n\t\t\tsize = Rnd.Float(20, 50);\n\t\t\ttarget = Camera.Instance.Y + Rnd.Float(Display.Height + 100);\n\t\t\tspeed = Rnd.Float(1f, 1.5f);\n\t\t\tpoofed = false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (delay > 0) {\n\t\t\t\tdelay -= dt;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar s = dt * 300f * speed;\n\t\t\tPosition += MathUtils.CreateVector(Weather.RainAngle, s);\n\n\t\t\tif (Y >= target) {\n\t\t\t\tif (!poofed) {\n\t\t\t\t\tpoofed = true;\n\t\t\t\t\tvar pos = Position + MathUtils.CreateVector(Weather.RainAngle, size);\n\n\t\t\t\t\tif (!Player.InBuilding) {\n\t\t\t\t\t\tvar c = Rnd.Int(2, 5);\n\n\t\t\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Rain());\n\n\t\t\t\t\t\t\tpart.Position = pos;\n\t\t\t\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(-40, 40), Rnd.Float(-30, -50));\n\t\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 1.6f);\n\t\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t\t\tpart.Depth = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsize -= 0.5f * s * (float) Math.Sin(Weather.RainAngle);\n\n\t\t\t\tif (size <= 0) {\n\t\t\t\t\tReset();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Position.Y > Camera.Instance.Bottom + 20) {\n\t\t\t\tReset();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Player.InBuilding) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Batch.DrawLine(X, Y, X + (float) Math.Cos(Weather.RainAngle) * size, Y + (float) Math.Sin(Weather.RainAngle) * size, color);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/SnowParticle.cs",
    "content": "using System;\nusing System.Numerics;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class SnowParticle : Entity {\n\t\tprivate static TextureRegion region;\n\n\t\tprivate Color color;\n\t\tprivate float target;\n\t\tprivate Vector2 size;\n\t\tprivate float speed;\n\t\tprivate float delay;\n\t\tprivate float t;\n\n\t\tpublic bool End;\n\t\tpublic bool Custom;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (region == null) {\n\t\t\t\tregion = CommonAse.Particles.GetSlice(\"circ\");\n\t\t\t}\n\n\t\t\tAlwaysActive = true;\n\t\t\tDepth = Layers.WindFx;\n\t\t\t\n\t\t\tReset();\n\t\t\tdelay = 0;\n\n\t\t\tif (!Custom) {\n\t\t\t\tY = Camera.Instance.Y + Rnd.Float(Display.Height + 20);\n\t\t\t} else {\n\t\t\t\tdelay = Rnd.Float(0, 10f);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Reset() {\n\t\t\tif (End) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar v = Rnd.Float(0.8f, 1f);\n\t\t\tcolor = new Color(v, v, v, Rnd.Float(0.8f, 1f));\n\t\t\tX = Rnd.Float(Camera.Instance.X - 150, Camera.Instance.Right + 150);\n\t\t\tY = Camera.Instance.Y - Rnd.Float(50, 60);\n\t\t\tsize = new Vector2(Rnd.Float(0.05f, 0.3f));\n\t\t\ttarget = Camera.Instance.Y + Rnd.Float(Display.Height + 20);\n\t\t\tspeed = Rnd.Float(1f, 1.5f);\n\t\t\tdelay = Rnd.Float(0, 5f);\n\t\t\tt = Rnd.Float(3);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tif (delay > 0) {\n\t\t\t\tdelay -= dt;\n\n\t\t\t\tif (!Custom && OnScreen) {\n\t\t\t\t\tdelay = 0;\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (Y >= target) {\n\t\t\t\tsize.X -= dt * 0.1f;\n\t\t\t\tsize.Y = size.X;\n\n\t\t\t\tif (size.X <= 0) {\n\t\t\t\t\tCustom = false;\n\t\t\t\t\tReset();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tPosition += MathUtils.CreateVector(Weather.RainAngle, dt * 30f * speed) + new Vector2((float) Math.Cos(t * 2 * speed) * dt * 10, 0);\n\t\t\t\n\t\t\tif (Position.Y > Camera.Instance.Bottom + 20) {\n\t\t\t\tReset();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Player.InBuilding) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, 0, Vector2.Zero, size);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/TextParticle.cs",
    "content": "using Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class TextParticle : Entity {\n\t\tprivate string text;\n\t\t\n\t\tpublic string Text {\n\t\t\tget => text;\n\t\t\t\n\t\t\tset {\n\t\t\t\tif (tweened) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttext = value;\n\t\t\t\tfullText = $\"{(HasSign ? (Negative ? \"-\" : \"+\") : \"\")}{(count > 0 ? $\"{count} \" : \"\")} {text}\";\n\n\t\t\t\tvar size = Font.Medium.MeasureString(fullText);\n\n\t\t\t\torigin = size / 2;\n\t\t\t\tWidth = size.Width;\n\t\t\t\tHeight = size.Height;\n\t\t\t\tgamePosition = start;\n\n\t\t\t\tscale.X = 0;\n\t\t\t\tscale.Y = 3;\n\t\t\t\tt = 0;\n\n\t\t\t\tTween.To(1, scale.X, x => scale.X = x, 0.3f);\n\t\t\t\tTween.To(1, scale.Y, x => scale.Y = x, 0.3f);\n\t\t\t}\n\t\t}\n\n\t\tprivate float count;\n\n\t\tpublic float Count {\n\t\t\tget => count;\n\n\t\t\tset {\n\t\t\t\tcount = value;\n\t\t\t\t// To update the text\n\t\t\t\tText = text;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic bool HasSign;\n\t\tpublic bool Negative;\n\t\tpublic bool Stacks = true;\n\t\t\n\t\tprivate string fullText;\n\t\tprivate Vector2 start;\n\t\tprivate Vector2 origin;\n\t\tprivate Vector2 scale;\n\t\tprivate float t;\n\t\tprivate bool tweened;\n\t\tprivate Vector2 gamePosition;\n\t\tprivate Vector2 offset;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tscale.X = 0;\n\t\t\tscale.Y = 0;\n\n\t\t\tTween.To(1, scale.X, x => scale.X = x, 0.2f);\n\t\t\tTween.To(1, scale.Y, x => scale.Y = x, 0.2f);\n\n\t\t\toffset.Y = 8;\n\t\t\tTween.To(0, offset.Y, x => offset.Y = x, 0.3f);\n\t\t\t\n\t\t\tAddTag(Tags.TextParticle);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tstart = Center;\n\t\t\tgamePosition = Center;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Camera.Instance == null) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tt += dt;\n\n\t\t\tif (!tweened && t >= 2f) {\n\t\t\t\ttweened = true;\n\t\t\t\t\n\t\t\t\tTween.To(0, scale.X, x => scale.X = x, 0.15f, Ease.QuadIn);\n\t\t\t\tTween.To(3, scale.Y, x => scale.Y = x, 0.15f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\tDone = true;\n\t\t\t\t};\n\n\t\t\t\tTween.To(-18, offset.Y, x => offset.Y = x, 0.15f, Ease.QuadIn);\n\t\t\t}\n\n\t\t\tif (!tweened) {\n\t\t\t\tforeach (var p in Area.Tagged[Tags.TextParticle]) {\n\t\t\t\t\tvar part = (TextParticle) p;\n\n\t\t\t\t\tif (part == this) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar rect = new Rectangle((int) gamePosition.X, (int) gamePosition.Y, (int) Width, (int) Height);\n\n\t\t\t\t\tif (rect.Intersects(new Rectangle((int) part.gamePosition.X, (int) part.gamePosition.Y, (int) part.Width, (int) part.Height))) {\n\t\t\t\t\t\tvar s = dt * 300;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (part.gamePosition.Y <= gamePosition.Y) {\n\t\t\t\t\t\t\tpart.gamePosition.Y -= s;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// gamePosition.Y += s;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCenter = Camera.Instance.CameraToUi(gamePosition) + offset;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (fullText != null) {\n\t\t\t\tGraphics.Print(fullText, Font.Medium, Center, 0, origin, scale);\n\t\t\t}\n\t\t}\n\n\t\tpublic static TextParticle Add(Entity owner, string text, float count = 0, bool hasSign = false, bool minus = false) {\n\t\t\tvar where = owner.TopCenter - new Vector2(0, 4);\n\t\t\tvar min = 72f;\n\t\t\tTextParticle prt = null;\n\t\t\t\n\t\t\tforeach (var p in Engine.Instance.State.Ui.Tagged[Tags.TextParticle]) {\n\t\t\t\tvar pr = (TextParticle) p;\n\n\t\t\t\tif (!pr.Stacks) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (pr.text == text && pr.Negative == minus && !pr.tweened) {\n\t\t\t\t\tvar d = (pr.gamePosition - where).Length();\n\t\t\t\t\t\n\t\t\t\t\tif(d < min) {\n\t\t\t\t\t\tmin = d;\n\t\t\t\t\t\tprt = pr; \n\t\t\t\t\t}\n\t\t\t\t} \n\t\t\t}\n\n\t\t\tif (prt != null) {\n\t\t\t\tprt.Count += count;\n\t\t\t\treturn prt;\n\t\t\t}\n\t\t\t\n\t\t\tvar part = new TextParticle();\n\t\t\tpart.BottomCenter = where;\n\t\t\tEngine.Instance.State.Ui.Add(part);\n\t\t\t\n\t\t\tpart.HasSign = hasSign;\n\t\t\tpart.Count = count;\n\t\t\tpart.Negative = minus;\n\t\t\tpart.Text = text;\n\n\t\t\treturn part;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/custom/TileParticle.cs",
    "content": "using BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Tile = BurningKnight.level.tile.Tile;\n\nnamespace BurningKnight.assets.particle.custom {\n\tpublic class TileParticle : Entity {\n\t\tprivate static Vector2 origin = new Vector2(8, 24);\n\t\tprivate static Vector2 originB = new Vector2(8, 8);\n\t\tpublic static float MaxZ = Display.Height;\n\t\t\n\t\tpublic TextureRegion Top;\n\t\tpublic TextureRegion TopTarget;\n\t\tpublic TextureRegion Side;\n\t\tpublic TextureRegion Sides;\n\t\tpublic Vector2 Scale = new Vector2(0, 3);\n\t\tpublic float Z;\n\t\tpublic Tile Tile;\n\t\tpublic Tile OriginalTile;\n\t\tpublic bool FromBottom;\n\t\tpublic Vector2 Target;\n\t\tpublic float TargetZ;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tHeight = 24;\n\t\t\t\n\t\t\tAlwaysActive = true;\n\n\t\t\tif (FromBottom) {\n\t\t\t\tvar level = Run.Level;\n\t\t\t\tvar x = (int) (X / 16);\n\t\t\t\tvar y = (int) ((Y + 8) / 16);\n\n\t\t\t\tOriginalTile = level.Get(x, y);\n\n\t\t\t\tif (OriginalTile == Tile.Chasm) {\n\t\t\t\t\tDone = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!OriginalTile.IsWall()) {\n\t\t\t\t\tZ = -8;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tScale.X = 1;\n\t\t\t\tScale.Y = 1;\n\t\t\t\t\n\t\t\t\tlevel.Set(x, y, Tile.Chasm);\n\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t\t\t\n\t\t\t\tTween.To(MaxZ, Z, z => {\n\t\t\t\t\tif (z > 8) {\n\t\t\t\t\t\tDepth = Layers.FlyingMob;\n\t\t\t\t\t}\n\n\t\t\t\t\tZ = z;\n\t\t\t\t}, 0.5f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\tTween.To(Target.X, X, v => X = v, 1f, Ease.QuadInOut);\n\t\t\t\t\tTween.To(Target.Y, Y, v => Y = v, 1f, Ease.QuadInOut).OnEnd = () => {\n\t\t\t\t\t\tx = (int) ((Target.X + 8) / 16);\n\t\t\t\t\t\ty = (int) ((Target.Y + 8) / 16);\n\n\t\t\t\t\t\tif (level.Get(x, y) != Tile.Chasm) {\n\t\t\t\t\t\t\tTop = TopTarget;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tTargetZ = -8;\n\t\t\t\t\t\t\tTile = OriginalTile;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tAnimateFall();\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tZ = MaxZ;\n\t\t\t\tDepth = Layers.FlyingMob;\n\n\t\t\t\tTween.To(1f, Scale.X, x => Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1f, Scale.Y, x => Scale.Y = x, 0.4f);\n\n\t\t\t\tAnimateFall();\n\t\t\t}\n\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t}\n\n\t\tprivate void AnimateFall() {\n\t\t\tTween.To(TargetZ, Z, x => {\n\t\t\t\tZ = x;\n\n\t\t\t\tif (Z <= 8f) {\n\t\t\t\t\tDepth = 0;\n\t\t\t\t}\n\t\t\t}, 0.5f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\tif (TargetZ >= -0.01f) {\n\t\t\t\t\tScale.X = 3;\n\t\t\t\t\tScale.Y = 0.3f;\n\t\t\t\t}\n\n\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).Emit($\"level_rock_{Rnd.Int(1, 3)}\", 0.5f);\n\n\t\t\t\tif (TargetZ < 0) {\n\t\t\t\t\tFinish();\n\t\t\t\t} else {\n\t\t\t\t\tTween.To(1, Scale.X, x => Scale.X = x, 0.5f);\n\t\t\t\t\tTween.To(1, Scale.Y, x => Scale.Y = x, 0.5f).OnEnd = () => { Finish(); };\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\t\n\t\tprivate void Finish() {\n\t\t\tvar level = Run.Level;\n\t\t\tvar x = (int) (CenterX / 16);\n\t\t\tvar y = (int) ((Y + 8) / 16);\n\n\t\t\tlevel.Liquid[level.ToIndex(x, y)] = 0;\n\t\t\tlevel.Set(x, y, Tile);\n\t\t\tlevel.UpdateTile(x, y);\n\t\t\tlevel.ReCreateBodyChunk(x, y);\n\n\t\t\tDone = true;\n\t\t}\n\n\t\tpublic void RenderShadow() {\n\t\t\tif (Z >= 0) {\n\t\t\t\tvar or = Top.Center;\n\t\t\t\tGraphics.Render(Top, Position + or + new Vector2(0, 16), 0, or, Scale);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tvar v = Position + originB - new Vector2(0, Z - 16);\n\t\t\t\n\t\t\tGraphics.Render(Top, Position + origin - new Vector2(0, Z), 0, origin, Scale);\n\n\t\t\tif (Z >= 0) {\n\t\t\t\tGraphics.Render(Side, v, 0, originB, Scale);\n\t\t\t\tGraphics.Render(Sides, v, 0, originB, Scale);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/renderer/AnimatedParticleRenderer.cs",
    "content": "﻿using Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.renderer {\n\tpublic class AnimatedParticleRenderer : ParticleRenderer {\n\t\tpublic override void Render(Particle particle) {\n\t\t\tvar part = (AnimatedParticle) particle;\n\t\t\tvar region = part.Animation.GetCurrentTexture();\n\t\t\t\n\t\t\tGraphics.Render(region, part.Position, part.Angle, region.Center, new Vector2(particle.Scale));\n\t\t}\n\n\t\tpublic override void RenderShadow(Particle particle) {\n\t\t\tvar part = (AnimatedParticle) particle;\n\t\t\tvar region = part.Animation.GetCurrentTexture();\n\t\t\t\n\t\t\tGraphics.Render(region, part.Position + new Vector2(0, 6), part.Angle, region.Center, new Vector2(particle.Scale));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/renderer/HealthParticleRenderer.cs",
    "content": "using Lens.graphics;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.assets.particle.renderer {\r\n\tpublic class HealthParticleRenderer : TexturedParticleRenderer {\r\n\t\tprivate float scale;\r\n\t\t\r\n\t\tpublic HealthParticleRenderer(TextureRegion r, float sx) {\r\n\t\t\tRegion = r;\r\n\t\t\tscale = sx;\r\n\t\t}\r\n\r\n\t\tpublic override void Render(Particle particle) {\r\n\t\t\tGraphics.Color = new Color(1f, 1f, 1f, particle.Alpha);\r\n\t\t\tGraphics.Render(Region, particle.Position, 0, Vector2.Zero, new Vector2(scale, 1));\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/particle/renderer/ParticleRenderer.cs",
    "content": "namespace BurningKnight.assets.particle.renderer {\n\tpublic class ParticleRenderer {\n\t\tpublic virtual void Render(Particle particle) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void RenderShadow(Particle particle) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/particle/renderer/RandomFrameRenderer.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing BurningKnight.util;\r\nusing Lens.assets;\r\nusing Lens.graphics;\r\nusing Lens.graphics.animation;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.assets.particle.renderer {\r\n\tpublic class RandomFrameRenderer : ParticleRenderer {\r\n\t\tprivate List<AnimationFrame> animation;\r\n\r\n\t\tpublic RandomFrameRenderer(string anim) {\r\n\t\t\tanimation = Animations.Get(anim).Layers.First().Value;\r\n\t\t}\r\n\r\n\t\tpublic override void Render(Particle particle) {\r\n\t\t\tvar region = animation[particle.Rnd % animation.Count].Texture;\r\n\r\n\t\t\tGraphics.Color.A = (byte) MathUtils.Clamp(0, 255, particle.Alpha * 255);\r\n\t\t\tGraphics.Render(region, particle.Position - new Vector2(0, particle.Z), particle.Angle, region.Center, new Vector2(particle.Scale));\r\n\t\t\tGraphics.Color.A = 255;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/assets/particle/renderer/TexturedParticleRenderer.cs",
    "content": "using Lens.assets;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.particle.renderer {\n\tpublic class TexturedParticleRenderer : ParticleRenderer {\n\t\tpublic TextureRegion Region;\n\n\t\tpublic TexturedParticleRenderer(string slice) {\n\t\t\tRegion = Animations.Get(\"particles\").GetSlice(slice);\n\t\t}\n\n\t\tpublic TexturedParticleRenderer(TextureRegion r) {\n\t\t\tRegion = r;\n\t\t}\n\t\t\n\t\tpublic TexturedParticleRenderer() {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Render(Particle particle) {\n\t\t\tvar s = particle.Alpha <= 0.99f;\n\n\t\t\tif (s) {\n\t\t\t\tGraphics.Color = new Color(1f, 1f, 1f, particle.Alpha);\t\n\t\t\t}\n\n\t\t\tGraphics.Render(Region, particle.Position - new Vector2(0, particle.Z), particle.Angle, Region.Center, new Vector2(particle.Scale));\n\t\t\t\n\t\t\tif (s) {\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderShadow(Particle particle) {\n\t\t\tif (particle.Z > 0.9f) {\n\t\t\t\tGraphics.Render(Region, particle.Position, particle.Angle, Region.Center, new Vector2(particle.Scale));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/prefabs/Prefab.cs",
    "content": "using System;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.rooms;\nusing BurningKnight.save;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.assets.prefabs {\n\tpublic class Prefab {\n\t\tpublic PrefabData[] Datas;\n\t\tpublic Level Level;\n\n\t\tpublic void Place(Level level, int x, int y) {\n\t\t\tvar pos = new Vector2(x * 16, y * 16);\n\t\t\tvar reader = new FileReader(null);\n\t\t\t\n\t\t\tforeach (var d in Datas) {\n\t\t\t\tif (d.Type == typeof(Level)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar e = (SaveableEntity) Activator.CreateInstance(d.Type);\n\t\t\t\t\n\t\t\t\tlevel.Area.Add(e, false);\n\t\t\t\treader.SetData(d.Data);\n\n\t\t\t\te.Load(reader);\n\n\t\t\t\tif (e is Room r) {\n\t\t\t\t\tr.MapX += x;\n\t\t\t\t\tr.MapY += y;\n\t\t\t\t} else {\n\t\t\t\t\te.Position += pos;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\te.PostInit();\n\t\t\t}\n\n\t\t\tfor (int ty = 0; ty < Level.Height && ty + y < level.Height; ty++) {\n\t\t\t\tfor (int tx = 0; tx < Level.Width && tx + x < level.Width; tx++) {\n\t\t\t\t\tvar i = Level.ToIndex(tx, ty);\n\t\t\t\t\tvar i2 = level.ToIndex(tx + x, ty + y);\n\t\t\t\t\t\n\t\t\t\t\tlevel.Tiles[i2] = Level.Tiles[i];\n\t\t\t\t\tlevel.Liquid[i2] = Level.Liquid[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/assets/prefabs/Prefabs.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.assets.prefabs {\n\tpublic static class Prefabs {\n\t\tprivate static Dictionary<string, Prefab> loaded = new Dictionary<string, Prefab>();\n\t\tprivate static List<string> paths = new List<string>();\n\t\tprivate static PrefabSaver saver = new PrefabSaver();\n\n\t\tpublic static void Reload() {\n\t\t\tloaded.Clear();\n\t\t\tLoad();\n\t\t}\n\t\t\n\t\tpublic static void Load() {\n\t\t\tLoad(FileHandle.FromRoot(\"Prefabs/\"));\n\t\t\tRun.Level = null;\n\t\t}\n\n\t\tpublic static Prefab Get(string id) {\n\t\t\treturn loaded.TryGetValue(id, out var fab) ? fab : null;\n\t\t}\n\n\t\tprivate static void Load(FileHandle handle) {\n\t\t\tif (!handle.Exists()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (handle.IsDirectory()) {\n\t\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in handle.ListDirectoryHandles()) {\n\t\t\t\t\tLoad(file);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (handle.Extension != \".lvl\") {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLog.Info($\"Loading prefab {handle.FullPath}\");\n\t\t\t\n\t\t\ttry {\n\t\t\t\tvar prefab = new Prefab();\n\t\t\t\tvar stream = new FileReader(handle.FullPath);\n\n\t\t\t\tif (stream.ReadInt32() != SaveManager.MagicNumber) {\n\t\t\t\t\tLog.Error(\"Invalid magic number!\");\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar version = stream.ReadInt16();\n\n\t\t\t\tif (version > SaveManager.Version) {\n\t\t\t\t\tLog.Error($\"Unknown version {version}\");\n\t\t\t\t} else if (version < SaveManager.Version) {\n\t\t\t\t\t// do something on it\n\t\t\t\t}\n\n\t\t\t\tif (stream.ReadByte() != (byte) SaveType.Level) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsaver.Load(new Area {NoInit = true}, stream, false);\n\n\t\t\t\tprefab.Level = Run.Level;\n\t\t\t\tprefab.Datas = ArrayUtils.Clone(saver.Datas);\n\t\t\t\tsaver.Datas.Clear();\n\n\t\t\t\tloaded[handle.NameWithoutExtension] = prefab;\n\t\t\t\tRun.Level = null;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error($\"Failed to load prefab {handle.NameWithoutExtension}\");\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate static void OnChanged(object sender, FileSystemEventArgs args) {\n\t\t\tLog.Debug($\"Reloading {args.FullPath}\");\n\t\t\tLoad(new FileHandle(args.FullPath));\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tloaded.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/BiomeCommand.cs",
    "content": "using BurningKnight.level.biome;\r\n\r\nnamespace BurningKnight.debug {\r\n\tpublic class BiomeCommand : ConsoleCommand {\r\n\t\tpublic BiomeCommand() {\r\n\t\t\tName = \"biome\";\r\n\t\t\tShortName = \"b\";\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Run(Console Console, string[] Args) {\r\n\t\t\tif (Args.Length == 1) {\r\n\t\t\t\tstate.Run.Level.SetBiome(BiomeRegistry.Get(Args[0]));\r\n\t\t\t} else {\r\n\t\t\t\tConsole.Print(\"/biome [id]\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/debug/BuffCommand.cs",
    "content": "using BurningKnight.assets;\r\nusing BurningKnight.assets.mod;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\n\r\nnamespace BurningKnight.debug {\r\n\tpublic class BuffCommand : ConsoleCommand {\r\n\t\tpublic BuffCommand() {\r\n\t\t\tShortName = \"bf\";\r\n\t\t\tName = \"buff\";\r\n\t\t}\r\n\r\n\t\tpublic override void Run(Console Console, string[] Args) {\r\n\t\t\tif (Args.Length > 0 && Args.Length < 2) {\r\n\t\t\t\tvar id = Args[0];\r\n\r\n\t\t\t\tif (!id.Contains(\":\")) {\r\n\t\t\t\t\tid = $\"{Mods.BurningKnight}:{id}\";\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar player = LocalPlayer.Locate(Console.GameArea);\r\n\t\t\t\tplayer.GetComponent<BuffsComponent>().Add(id).TimeLeft = 128;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/debug/CheatWindow.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.ui.imgui;\nusing ImGuiNET;\nusing Lens;\n\nnamespace BurningKnight.debug {\n\tpublic static class CheatWindow {\n\t\tpublic static bool AutoGodMode = BK.Version.Dev;\n\t\tpublic static bool InfiniteActive;\n\t\tpublic static bool NoSleep;\n\t\t\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.Cheats) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!ImGui.Begin(\"Cheats\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\n\n\t\t\tif (player != null) {\n\t\t\t\tImGui.Checkbox(\"God Mode\", ref player.GetComponent<HealthComponent>().Unhittable);\n\t\t\t}\n\t\t\t\n\n\t\t\tif (ImGui.Checkbox(\"Auto god mode\", ref AutoGodMode) && player != null) {\n\t\t\t\tplayer.GetComponent<HealthComponent>().Unhittable = AutoGodMode;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tif (ImGui.Checkbox(\"Infinite active charge\", ref InfiniteActive) && player != null && InfiniteActive) {\n\t\t\t\tplayer.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:battery\", player.Area));\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"No Sleep\", ref NoSleep);\n\t\t\t\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/Console.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.state;\nusing BurningKnight.ui.imgui;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\n\nnamespace BurningKnight.debug {\n\tpublic unsafe class Console {\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 200);\n\t\tprivate static System.Numerics.Vector2 spacer = new System.Numerics.Vector2(4, 1);\n\t\tprivate static System.Numerics.Vector4 color = new System.Numerics.Vector4(1, 0.4f, 0.4f, 1f);\n\t\t\n\t\tprivate ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate List<ConsoleCommand> commands = new List<ConsoleCommand>();\n\t\tprivate string input = \"\";\n\n\t\tpublic List<string> Lines = new List<string>();\n\t\tpublic Area GameArea;\n\t\tpublic static bool Open;\n\n\t\tprivate bool forceFocus;\n\t\t\n\t\tpublic Console(Area area) {\n\t\t\tGameArea = area;\n\n\t\t\tcommands.Add(new SpawnCommand());\n\t\t\tcommands.Add(new GiveCommand());\n\t\t\tcommands.Add(new HealCommand());\n\t\t\tcommands.Add(new GodModeCommand());\n\t\t\tcommands.Add(new LevelCommand());\n\t\t\tcommands.Add(new DebugCommand());\n\t\t\tcommands.Add(new DieCommand());\n\t\t\tcommands.Add(new ZoomCommand());\n\t\t\tcommands.Add(new HurtCommand());\n\t\t\tcommands.Add(new EntityCommand());\n\t\t\tcommands.Add(new SaveCommand());\n\t\t\tcommands.Add(new BiomeCommand());\n\t\t\tcommands.Add(new ExploreCommand());\n\t\t\tcommands.Add(new PassableCommand());\n\t\t\tcommands.Add(new BuffCommand());\n\t\t\tcommands.Add(new TileCommand());\n\t\t\tcommands.Add(new HappeningCommand());\n\t\t}\n\n\t\tpublic void AddCommand(ConsoleCommand command) {\n\t\t\tcommands.Add(command);\n\t\t}\n\t\t\n\t\tpublic void Print(string str) {\n\t\t\tLines.Add(str);\n\t\t\tLog.Debug(str);\n\t\t}\n\n\t\tpublic void Update(float dt) {\n\t\t\tif (InGameState.ToolsEnabled && Input.Keyboard.WasPressed(Keys.F1, true)) {\n\t\t\t\tOpen = !Open;\n\t\t\t\tCamera.Instance.Detached = Open;\n\t\t\t\tInput.EnableImGuiFocus = Open;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Render() {\n\t\t\tif (!WindowManager.Console) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (forceFocus) {\n\t\t\t\tImGui.SetNextWindowCollapsed(false);\n\t\t\t}\n\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\t\t\tImGui.SetNextWindowPos(new System.Numerics.Vector2(10, Engine.Instance.GetScreenHeight() - size.Y - 10), ImGuiCond.Once);\n\t\t\tImGui.Begin(\"Console\", ImGuiWindowFlags.NoTitleBar);\n\n\t\t\t/* filter.Draw(\"##console\");\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Clear\")) {\n\t\t\t\tLines.Clear();\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();*/\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeightWithSpacing();\n\t\t\tImGui.BeginChild(\"ScrollingRegionConsole\", new System.Numerics.Vector2(0, -height), \n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\t\t\tImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, spacer);\n\t\t\t\n\t\t\tforeach (var t in Lines) {\n\t\t\t\tif (filter.PassFilter(t)) {\n\t\t\t\t\tvar popColor = false;\n\n\t\t\t\t\tif (t[0] == '>') {\n\t\t\t\t\t\tpopColor = true;\n\t\t\t\t\t\tImGui.PushStyleColor(ImGuiCol.Text, color);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tImGui.TextUnformatted(t);\n\n\t\t\t\t\tif (popColor) {\n\t\t\t\t\t\tImGui.PopStyleColor();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui.PopStyleVar();\n\t\t\tImGui.EndChild();\n\t\t\tImGui.Separator();\n\n\t\t\tif (ImGui.InputText(\"##Input\", ref input, 128, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tRunCommand(input);\n\t\t\t\tinput = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SetItemDefaultFocus();\n\n\t\t\tif (forceFocus) {\n\t\t\t\tImGui.SetKeyboardFocusHere(-1);\n\t\t\t}\n\n\t\t\tforceFocus = false;\n\t\t\tImGui.End();\n\t\t}\n\n\t\tpublic void RunCommand(string input) {\n\t\t\tinput = input.TrimEnd();\t\n\t\t\n\t\t\tLines.Add($\"> {input}\");\n\t\t\t\n\t\t\tvar parts = input.Split(null);\n\t\t\tvar name = parts[0];\n\n\t\t\tforeach (var command in commands) {\n\t\t\t\tif (command.Name.Equals(name) || command.ShortName.Equals(name)) {\n\t\t\t\t\tvar args = new string[parts.Length - 1];\n\t\t\t\t\t\n\t\t\t\t\tfor (int i = 0; i < args.Length; i++) {\n\t\t\t\t\t\targs[i] = parts[i + 1];\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcommand.Run(this, args);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPrint(\"Unknown command\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/debug/ConsoleCommand.cs",
    "content": "namespace BurningKnight.debug {\n\tpublic abstract class ConsoleCommand {\n\t\tpublic enum Access {\n\t\t\tEveryone,\n\t\t\tTesters,\n\t\t\tDevelopers\n\t\t}\n\n\t\tpublic Access RunPermission = Access.Everyone;\n\t\tpublic string Name;\n\t\tpublic string ShortName;\n\n\t\tpublic abstract void Run(Console Console, string[] Args);\n\n\t\tpublic virtual string AutoComplete(string input) {\n\t\t\treturn \"\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/DebugCommand.cs",
    "content": "using BurningKnight.physics;\n\nnamespace BurningKnight.debug {\n\tpublic class DebugCommand : ConsoleCommand {\n\t\tpublic DebugCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"debug\";\n\t\t\t\tShortName = \"d\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tPhysics.RenderDebug = !Physics.RenderDebug;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/DieCommand.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.debug {\n\tpublic class DieCommand : ConsoleCommand {\n\t\tpublic DieCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"kill\";\n\t\t\t\tShortName = \"k\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tforeach (var player in Console.GameArea.Tagged[Tags.Player]) {\n\t\t\t\tplayer.GetComponent<HealthComponent>().Kill(null);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/EntityCommand.cs",
    "content": "using Lens.game;\n\nnamespace BurningKnight.debug {\n\tpublic class EntityCommand : ConsoleCommand {\n\t\tpublic EntityCommand() {\n\t\t\tName = \"entity\";\n\t\t\tShortName = \"e\";\n\t\t}\n\t\t\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tGameState.RenderDebug = !GameState.RenderDebug;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/ExploreCommand.cs",
    "content": "namespace BurningKnight.debug {\n\tpublic class ExploreCommand : ConsoleCommand {\n\t\tpublic ExploreCommand() {\n\t\t\tName = \"explore\";\n\t\t\tShortName = \"ex\";\n\t\t}\n\t\t\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tvar level = state.Run.Level;\n\n\t\t\tfor (var i = 0; i < level.Explored.Length; i++) {\n\t\t\t\tlevel.Explored[i] = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/GiveCommand.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing Lens.input;\nusing Lens.util;\n\nnamespace BurningKnight.debug {\n\tpublic class GiveCommand : ConsoleCommand {\n\t\tpublic GiveCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tShortName = \"gv\";\n\t\t\t\tName = \"give\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tvar player = LocalPlayer.Locate(Console.GameArea);\n\n\t\t\tfor (var i = 0; i < Args.Length; i++) {\n\t\t\t\tvar id = Args[i];\n\t\t\t\tvar count = 1;\n\t\t\t\tvar cursed = false;\n\n\t\t\t\tif (!id.Contains(\":\")) {\n\t\t\t\t\tid = $\"{Mods.BurningKnight}:{id}\";\n\t\t\t\t}\n\n\t\t\t\tif (id.EndsWith(\"_\")) {\n\t\t\t\t\tid = id.Substring(0, id.Length - 1);\n\t\t\t\t\tcursed = true;\n\t\t\t\t}\n\n\t\t\t\tif (i < Args.Length - 1) {\n\t\t\t\t\tvar c = Args[i + 1];\n\n\t\t\t\t\tif (int.TryParse(c, out count) && count > 0) {\n\t\t\t\t\t\ti++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcount = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (id != \"bk:coin\" && !Items.Has(id)) {\n\t\t\t\t\tConsole.Print($\"Unknown item {id}\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tLog.Info($\"Giving {id} x{count}\");\n\n\t\t\t\tfor (var j = 0; j < count; j++) {\n\t\t\t\t\tvar item = Items.CreateAndAdd(id, Console.GameArea);\n\n\t\t\t\t\tif (cursed) {\n\t\t\t\t\t\titem.Scourged = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tplayer?.GetComponent<InventoryComponent>().Pickup(item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/GodModeCommand.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\n\nnamespace BurningKnight.debug {\n\tpublic class GodModeCommand : ConsoleCommand {\n\t\tpublic GodModeCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"gm\";\n\t\t\t\tShortName = \"g\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tvar all = Console.GameArea.Tagged[Tags.Player];\n\t\t\t\n\t\t\tforeach (var player in all) {\n\t\t\t\tvar health = player.GetComponent<HealthComponent>();\n\t\t\t\thealth.Unhittable = !health.Unhittable;\n\t\t\t\t\n\t\t\t\tTextParticle.Add(player, \"God Mode\", 1, true, !health.Unhittable);\n\t\t\t\tConsole.Print(health.Unhittable ? \"God mode is on\" : \"God mode is off\");\n\t\t\t}\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/HappeningCommand.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.twitch.happening;\nusing Lens;\nusing Lens.util;\nusing Lens.util.timer;\n\nnamespace BurningKnight.debug {\n\tpublic class HappeningCommand : ConsoleCommand {\n\t\tpublic HappeningCommand() {\n    \tName = \"HappeningCommand\";\n    \tShortName = \"hp\";\n    }\n    \n    public override void Run(Console Console, string[] Args) {\n    \tif (Args.Length == 1) {\n\t      var h = HappeningRegistry.Get(Args[0]);\n\n\t      if (h == null) {\n\t\t      return;\n\t      }\n\n\t      try {\n\t\t      var p = LocalPlayer.Locate(Engine.Instance.State.Area);\n\t\t\t\t\th.Happen(p);\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\th.End(p);\n\t\t\t\t\t}, h.GetVoteDelay());\n\t      } catch (Exception e) {\n\t\t      Log.Error(e);\n\t      }\n      }\n    }\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/HealCommand.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.debug {\n\tpublic class HealCommand : ConsoleCommand {\n\t\tpublic HealCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"heal\";\n\t\t\t\tShortName = \"h\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tforeach (var player in Console.GameArea.Tagged[Tags.Player]) {\n\t\t\t\tvar component = player.GetComponent<HealthComponent>();\n\t\t\t\tcomponent.SetHealth(component.MaxHealth, null);\n\t\t\t}\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/HurtCommand.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.debug {\n\tpublic class HurtCommand : ConsoleCommand {\n\t\tpublic HurtCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"hurt\";\n\t\t\t\tShortName = \"o\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tforeach (var player in Console.GameArea.Tagged[Tags.Player]) {\n\t\t\t\tplayer.GetComponent<HealthComponent>().ModifyHealth(-1, player);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/LevelCommand.cs",
    "content": "using System;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.player;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.debug {\n\tpublic class LevelCommand : ConsoleCommand {\n\t\tpublic LevelCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"lvl\";\n\t\t\t\tShortName = \"l\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tif (Args.Length > 0) {\n\t\t\t\tstate.Run.Depth = Int32.Parse(Args[0]);\n\t\t\t\tstate.Run.ActualDepth = -10;\n\n\t\t\t\tif (Args.Length > 1) {\n\t\t\t\t\tstate.Run.Loop = Int32.Parse(Args[1]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/LevelLayerDebug.cs",
    "content": "using BurningKnight.ui.imgui;\nusing ImGuiNET;\n\nnamespace BurningKnight.debug {\n\tpublic static class LevelLayerDebug {\n\t\tpublic static bool Chasms = true;\n\t\tpublic static bool Floor = true;\n\t\tpublic static bool Liquids = true;\n\t\tpublic static bool Mess = true;\n\t\tpublic static bool Sides = true;\n\t\tpublic static bool Walls = true;\n\t\tpublic static bool Blood = true;\n\t\tpublic static bool Lights = true;\n\t\tpublic static bool TileLight = true;\n\t\tpublic static bool Shadows = true;\n\t\tpublic static bool Rocks = true;\n\t\t\t\t\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.LayerDebug) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!ImGui.Begin(\"Layer Debug\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"Show\")) {\n\t\t\t\tChasms = Floor = Liquids = Mess = Sides = Walls = Blood = Lights = TileLight = Rocks = Shadows = true;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SameLine();\n\n\t\t\tif (ImGui.Button(\"Hide\")) {\n\t\t\t\tChasms = Floor = Liquids = Mess = Sides = Walls = Blood = Lights = TileLight = Rocks = Shadows = false;\n\t\t\t}\n\n\t\t\tImGui.Checkbox(\"Chasms\", ref Chasms);\n\t\t\tImGui.Checkbox(\"Floor\", ref Floor);\n\t\t\tImGui.Checkbox(\"Mess\", ref Mess);\n\t\t\tImGui.Checkbox(\"Liquids\", ref Liquids);\n\t\t\tImGui.Checkbox(\"Shadows\", ref Shadows);\n\t\t\tImGui.Checkbox(\"Sides\", ref Sides);\n\t\t\tImGui.Checkbox(\"Walls\", ref Walls);\n\t\t\tImGui.Checkbox(\"Blood\", ref Blood);\n\t\t\tImGui.Checkbox(\"Lights\", ref Lights);\n\t\t\tImGui.Checkbox(\"Tile Light\", ref TileLight);\n\t\t\tImGui.Checkbox(\"Rocks\", ref Rocks);\n\t\t\t\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/LootTableEditor.cs",
    "content": "using BurningKnight.assets.loot;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.ui.imgui;\nusing ImGuiNET;\nusing Lens.input;\nusing Lens.lightJson;\nusing Microsoft.Xna.Framework.Input;\nusing ImGui = ImGuiNET.ImGui;\n\nnamespace BurningKnight.debug {\n\tpublic static class LootTableEditor {\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\n\n\t\tprivate static int id;\n\t\tprivate static int count;\n\t\tprivate static string selectedTable;\n\t\tprivate static string poolName = \"\";\n\t\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.LootTable) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\n\t\t\tif (!ImGui.Begin(\"Loot Table Editor\")) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"Save\")) {\n\t\t\t\tLootTables.Save();\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"New##pe\")) {\n\t\t\t\tImGui.OpenPopup(\"Add Item##pe\");\t\n\t\t\t}\n\n\t\t\tif (selectedTable != null) {\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Delete\")) {\n\t\t\t\t\tLootTables.Defined.Remove(selectedTable);\n\t\t\t\t\tLootTables.Data.Remove(selectedTable);\n\t\t\t\t\t\n\t\t\t\t\tselectedTable = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfilter.Draw(\"\");\n\t\t\tImGui.SameLine();\n\t\t\tImGui.Text($\"{count}\");\n\n\t\t\tif (ImGui.BeginPopupModal(\"Add Item##pe\")) {\n\t\t\t\tImGui.PushItemWidth(300);\n\t\t\t\tImGui.InputText(\"Id\", ref poolName, 64);\n\t\t\t\tImGui.PopItemWidth();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Add\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\n\t\t\t\t\tselectedTable = poolName;\n\t\t\t\t\tLootTables.Defined[poolName] = new AnyDrop();\n\t\t\t\t\tLootTables.Data[poolName] = new JsonObject {\n\t\t\t\t\t\t[\"type\"] = \"any\"\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tpoolName = \"\";\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\n\t\t\t\t\tpoolName = \"\";\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.EndPopup();\n\t\t\t}\n\t\t\t\n\t\t\tif (selectedTable != null) {\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"Remove##pe\")) {\n\t\t\t\t\tLootTables.Defined.Remove(selectedTable);\n\t\t\t\t\tselectedTable = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcount = 0;\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y;\n\t\t\tImGui.BeginChild(\"rolingRegionItems##Pe\", new System.Numerics.Vector2(0, -height), \n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\n\t\t\tforeach (var i in LootTables.Defined) {\n\t\t\t\tImGui.PushID($\"{id}___m\");\n\n\t\t\t\tif (filter.PassFilter(i.Key)) {\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (ImGui.Selectable($\"{i.Key}##ped\", i.Key  == selectedTable)) {\n\t\t\t\t\t\tselectedTable = i.Key;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tImGui.PopID();\n\t\t\t\tid++;\n\t\t\t}\n\n\t\t\tid = 0;\n\n\t\t\tImGui.EndChild();\n\t\t\tImGui.End();\n\n\t\t\tif (selectedTable == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar show = true;\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\n\t\t\tif (!ImGui.Begin(\"Loot Table\", ref show)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!show) {\n\t\t\t\tselectedTable = null;\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tLootTables.RenderDrop(LootTables.Data[selectedTable]);\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/PassableCommand.cs",
    "content": "using BurningKnight.level;\r\n\r\nnamespace BurningKnight.debug {\r\n\tpublic class PassableCommand : ConsoleCommand {\r\n\t\tpublic PassableCommand() {\r\n\t\t\tName = \"passable\";\r\n\t\t\tShortName = \"p\";\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Run(Console Console, string[] Args) {\r\n\t\t\tLevel.RenderPassable = !Level.RenderPassable;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/debug/PoolEditor.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.input;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.debug {\n\tpublic static class PoolEditor {\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static unsafe ImGuiTextFilterPtr popupFilter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\n\t\tprivate static System.Numerics.Vector2 popupSize = new System.Numerics.Vector2(400, 400);\n\t\tprivate static string selectedItem;\n\t\tprivate static int id;\n\t\tprivate static int count;\n\t\t\n\t\tpublic static int Pool;\n\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.PoolEditor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\n\t\t\tif (!ImGui.Begin(\"Pool Editor##re\")) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tImGui.Combo(\"Pool##pe\", ref Pool, ItemPool.Names, ItemPool.Count);\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tfilter.Draw(\"\");\n\t\t\tImGui.SameLine();\n\t\t\tImGui.Text($\"{count}\");\n\n\t\t\tif (ImGui.Button(\"Add##pe\")) {\n\t\t\t\tImGui.OpenPopup(\"Add Item##pe\");\t\n\t\t\t}\n\n\t\t\tif (ImGui.BeginPopupModal(\"Add Item##pe\")) {\n\t\t\t\tImGui.SetWindowSize(popupSize);\n\t\t\t\t\n\t\t\t\tpopupFilter.Draw(\"\");\n\t\t\t\tImGui.BeginChild(\"ScrollinegionUses##reee\", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), \n\t\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\t\t\t\t\n\t\t\t\tImGui.Separator();\n\n\t\t\t\tforeach (var i in Items.Datas) {\n\t\t\t\t\tImGui.PushID($\"{id}__itm\");\n\t\t\t\t\n\t\t\t\t\tif (!BitHelper.IsBitSet(i.Value.Pools, Pool) && popupFilter.PassFilter(i.Key) && ImGui.Selectable($\"{i.Key}##d\", selectedItem == i.Key)) {\n\t\t\t\t\t\tselectedItem = i.Key;\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.PopID();\n\t\t\t\t\tid++;\n\t\t\t\t}\n\n\t\t\t\tid = 0;\n\n\t\t\t\tImGui.EndChild();\n\t\t\t\tImGui.Separator();\n\n\t\t\t\tif (selectedItem != null && (ImGui.Button(\"Add\") || Input.Keyboard.WasPressed(Keys.Enter, true))) {\n\t\t\t\t\tItemEditor.Selected = Items.Datas[selectedItem];\n\t\t\t\t\tItemEditor.ForceFocus = true;\n\t\t\t\t\t\n\t\t\t\t\tItemEditor.Selected.Pools = BitHelper.SetBit(ItemEditor.Selected.Pools, Pool, true);\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.EndPopup();\n\t\t\t}\n\t\t\t\n\t\t\tif (ItemEditor.Selected != null) {\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"Remove##pe\")) {\n\t\t\t\t\tItemEditor.Selected.Pools = BitHelper.SetBit(ItemEditor.Selected.Pools, Pool, false);\n\t\t\t\t\tItemEditor.Selected = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcount = 0;\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y;\n\t\t\tImGui.BeginChild(\"rollingRegionItems##Pe\", new System.Numerics.Vector2(0, -height), \n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\n\t\t\tforeach (var i in Items.Datas.Values) {\n\t\t\t\tImGui.PushID($\"{id}___m\");\n\n\t\t\t\tif (filter.PassFilter(i.Id)) {\n\t\t\t\t\tif (!BitHelper.IsBitSet(i.Pools, Pool)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (ImGui.Selectable($\"{i.Id}##ped\", i == ItemEditor.Selected)) {\n\t\t\t\t\t\tif (i != ItemEditor.Selected) {\n\t\t\t\t\t\t\tItemEditor.Selected = i;\n\t\t\t\t\t\t\tItemEditor.ForceFocus = true;\n\t\t\t\t\t\t\tWindowManager.ItemEditor = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tImGui.PopID();\n\t\t\t\tid++;\n\t\t\t}\n\n\t\t\tid = 0;\n\n\t\t\tImGui.EndChild();\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/SaveCommand.cs",
    "content": "using System.Threading;\nusing BurningKnight.save;\nusing Lens;\nusing Lens.util.file;\n\nnamespace BurningKnight.debug {\n\tpublic class SaveCommand : ConsoleCommand {\n\t\tpublic SaveCommand() {\n\t\t\tName = \"save\";\n\t\t\tShortName = \"s\";\n\t\t}\n\t\t\n\t\tpublic override void Run(Console console, string[] args) {\n\t\t\tif (args.Length == 0 || args.Length > 3) {\n\t\t\t\tconsole.Print(\"save [save path] (save type)\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar path = args[0];\n\t\t\tvar saveType = args.Length == 1 ? \"all\" : args[1];\n\t\t\tvar area = Engine.Instance.State.Area;\n\t\t\t\n\t\t\tvar thread = new Thread(() => {\n\t\t\t\tswitch (saveType) {\n\t\t\t\t\tcase \"all\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Level, false, path);\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Player, false, path);\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Game, false, path);\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Global, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"level\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Level, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"player\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Player, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"game\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Game, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"global\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Global, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Level, false, path);\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Player, false, path);\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Game, false, path);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"prefab\": {\n\t\t\t\t\t\tSaveManager.Save(area, SaveType.Level, false, $\"{FileHandle.FromRoot(\"Prefabs/\").FullPath}/{path}.lvl\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tconsole.Print($\"Unknown save type {saveType}. Should be one of all, level, player, game, global, run, prefab\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\tconsole.Print($\"Done saving {saveType}\");\n\t\t\t});\n\t\t\t\n\t\t\tthread.Start();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/SpawnCommand.cs",
    "content": "using System;\nusing BurningKnight.ui.editor;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.debug {\n\tpublic class SpawnCommand : ConsoleCommand {\n\t\tpublic SpawnCommand() {\n\t\t\tName = \"spawn\";\n\t\t\tShortName = \"s\";\n\t\t}\n\t\t\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tif (Args.Length != 1) {\n\t\t\t\tConsole.Print(\"Usage: spawn [entity]\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar name = Args[0];\n\t\t\tvar small = name.ToLower();\n\n\t\t\tforeach (var type in EntityEditor.Types) {\n\t\t\t\tif (type.Name.ToLower() == small) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar entity = (Entity) Activator.CreateInstance(type.Type);\n\t\t\t\t\t\tConsole.GameArea.Add(entity);\n\t\t\t\t\t\tentity.BottomCenter = Console.GameArea.Tagged[Tags.Player][0].BottomCenter;\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\tConsole.Print($\"Failed to create entity {name}, consult @egordorichev\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tConsole.Print($\"Unknown entity {name}\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/TileCommand.cs",
    "content": "namespace BurningKnight.debug {\n\tpublic class TileCommand : ConsoleCommand {\n\t\tpublic TileCommand() {\n\t\t\tName = \"tile\";\n\t\t\tShortName = \"t\";\n\t\t}\n\t\t\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tvar level = state.Run.Level;\n\n\t\t\tif (level != null) {\n\t\t\t\t// level.Resize(level.Width, level.Height);\n\t\t\t\tlevel.RefreshSurfaces();\n\t\t\t\tlevel.TileUp(true);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/debug/ZoomCommand.cs",
    "content": "using System;\nusing Lens;\n\nnamespace BurningKnight.debug {\n\tpublic class ZoomCommand : ConsoleCommand {\n\t\tpublic ZoomCommand() {\n\t\t\t_Init();\n\t\t}\n\n\t\tprotected void _Init() {\n\t\t\t{\n\t\t\t\tName = \"zoom\";\n\t\t\t\tShortName = \"z\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Run(Console Console, string[] Args) {\n\t\t\tif (Args.Length == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfloat Zoom = Math.Max(0, Single.Parse(Args[0]));\n\t\t\tEngine.Instance.SetWindowed((int) (Display.Width * Zoom), (int) (Display.Height * Zoom));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/BlankMaker.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity {\n\tpublic static class BlankMaker {\n\t\tpublic const float Radius = 48f;\n\t\t\n\t\tpublic static void Make(Vector2 where, Area area, float r = Radius) {\n\t\t\tforeach (var p in area.Tagged[Tags.Projectile]) {\n\t\t\t\tif (p.DistanceTo(where) <= r) {\n\t\t\t\t\t((Projectile) p).Break();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var e in area.Tagged[Tags.MustBeKilled]) {\n\t\t\t\tif (e.DistanceTo(where) <= r) {\n\t\t\t\t\te.GetAnyComponent<BodyComponent>()?.KnockbackFrom(where, 10f);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 10; i++) {\n\t\t\t\tvar a = i * 0.1f * Math.PI * 2 + Rnd.Float(-0.1f, 0.1f);\n\t\t\t\tAnimationUtil.PoofFrom(where + MathUtils.CreateVector(a, r - 8), where);\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = 0; i < 10; i++) {\n\t\t\t\tvar a = Rnd.AnglePI();\n\t\t\t\tvar d = Rnd.Float(r);\n\t\t\t\t\n\t\t\t\tAnimationUtil.PoofFrom(where + MathUtils.CreateVector(a, d), where);\n\t\t\t}\t\t\t\n\t\t\t\n\t\t\tCamera.Instance.Shake(6);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/Cursor.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity {\n\tpublic class Cursor : Entity, CustomCameraJumper {\n\t\tprivate static TextureRegion[] regions;\n\n\t\tprivate Vector2 scale = new Vector2(1);\n\t\tprivate Vector2 stickOffset;\n\t\tprivate bool needsAdjusting = true;\n\t\tprivate bool readTint = true;\n\t\tprivate Color tint;\n\t\tprivate Vector2 lastPos;\n\n\t\tpublic Player Player;\n\t\tpublic Vector2 GamePosition;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t\tDepth = Layers.Cursor;\n\t\t\tWidth = 0;\n\t\t\tHeight = 0;\n\t\t\t\n\t\t\tAddTag(Tags.Cursor);\n\n\t\t\tif (regions == null) {\n\t\t\t\tregions = new[] {\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_a\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_b\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_c\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_d\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_e\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_f\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_g\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_j\"),\n\t\t\t\t\tCommonAse.Ui.GetSlice(\"cursor_k\")\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Player.Dead) {\n\t\t\t\tvar found = false;\n\t\t\t\t\n\t\t\t\tforeach (var e in Area.Entities.Entities) {\n\t\t\t\t\tif (e is Cursor && e != this) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (found) {\n\t\t\t\t\tDone = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (readTint) {\n\t\t\t\treadTint = false;\n\t\t\t\ttint = Player.Tint;\n\t\t\t}\n\n\t\t\tvar input = Player.GetComponent<InputComponent>();\n\t\t\t\n\t\t\tif (input.KeyboardEnabled && (Input.Mouse.WasMoved || !input.GamepadEnabled || input.GamepadData == null || input.GamepadData.Attached)) {\n\t\t\t\tvar pos = Input.Mouse.ScreenPosition;\n\n\t\t\t\tif (pos != lastPos) {\n\t\t\t\t\tlastPos = pos;\n\t\t\t\t\tPosition = Camera.Instance.CameraToUi(GamePosition = Camera.Instance.ScreenToCamera(pos));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar controller = input.GamepadEnabled ? input.GamepadData : null;\n\t\t\t\n\t\t\tif (controller != null && Engine.Instance.State is InGameState st && !st.Paused && !st.Died && !Run.Won) {\n      \tif (needsAdjusting) {\n\t        needsAdjusting = false;\n\t        Position = Camera.Instance.CameraToUi(GamePosition = Player.Center);\n        }\n\t\t\t\t\n\t\t\t\tvar stick = controller.GetRightStick();\n\n      \tvar dx = stick.X;\n      \tvar dy = stick.Y;\n      \tvar d = (float) Math.Sqrt(dx * dx + dy * dy);\n\n      \tif (d > 1) {\n      \t\tstick /= d;\n      \t} else {\n      \t\tstick *= d;\n      \t}\n\n        var l = stick.Length();\n\n        if (l > 0.25f) {\n      \t\tvar target = MathUtils.CreateVector(Math.Atan2(dy, dx), 1f);\n\n      \t\tdx = target.X - stickOffset.X;\n      \t\tdy = target.Y - stickOffset.Y;\n\n      \t\td = (float) Math.Sqrt(dx * dx + dy * dy);\n\n      \t\tif (d > 1) {\n      \t\t\tdx /= d;\n      \t\t\tdy /= d;\n      \t\t} else {\n      \t\t\tdx *= d;\n      \t\t\tdy *= d;\n      \t\t}\n\n      \t\tstickOffset += l * new Vector2(dx, dy) * dt * 10f * Settings.Sensivity;\n\t        Position = Camera.Instance.CameraToUi(GamePosition = (Player.Center + stickOffset * (48 * Settings.CursorRadius)));\n\n      \t\tdouble a = 0;\n      \t\tvar pressed = false;\n\n      \t\tif (controller.DPadLeftCheck) {\n      \t\t\ta = Math.PI;\n      \t\t\tpressed = true;\n      \t\t} else if (controller.DPadDownCheck) {\n      \t\t\ta = Math.PI / 2f;\n      \t\t\tpressed = true;\n      \t\t} else if (controller.DPadUpCheck) {\n      \t\t\ta = Math.PI * 1.5f;\n      \t\t\tpressed = true;\n      \t\t} else if (controller.DPadRightCheck) {\n      \t\t\tpressed = true;\n      \t\t}\n\n      \t\tif (pressed) {\n      \t\t\tPosition = Camera.Instance.CameraToUi(GamePosition = (Player.Center + MathUtils.CreateVector(a, 48)));\n      \t\t}\n        }\n      }\n\n\t\t\tif (Input.WasPressed(Controls.Use, input)) {\n\t\t\t\tTween.To(1.3f, scale.X, x => { scale.X = scale.Y = x; }, 0.05f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, scale.X, x => { scale.X = scale.Y = x; }, 0.15f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Settings.HideCursor) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar r = regions[Settings.Cursor];\n\n\t\t\tif (InGameState.Multiplayer) {\n\t\t\t\tGraphics.Color = tint;\n\t\t\t}\n\n\t\t\tGraphics.Render(r, Position, 0, r.Center, scale);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\tpublic Vector2 Jump(Camera.Target target) {\n\t\t\treturn new Vector2();\n\t\t\t/*Position = Camera.Instance.CameraToUi(GamePosition = Camera.Instance.ScreenToCamera(Input.Mouse.ScreenPosition));\n\t\t\treturn new Vector2((CenterX - Display.UiWidth * 0.5f) * target.Priority, (CenterY - Display.UiHeight * 0.5f) * target.Priority * Display.Viewport * 1.6f)*/;\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/DamageType.cs",
    "content": "namespace BurningKnight.entity {\n\tpublic enum DamageType {\n\t\tRegular,\n\t\tExplosive,\n\t\tCustom,\n\t\tContact,\n\t\tMelee\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/ExplosionMaker.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity {\n\tpublic static class ExplosionMaker {\n\t\tpublic static void BreakRock(Level level, Dot ww, int x, int y, Tile l) {\n\t\t\tAudioEmitterComponent.Dummy(level.Area, ww).Emit($\"level_rock_{Rnd.Int(1, 3)}\", 0.5f);\n\n\t\t\tif (l.IsRock()) {\n\t\t\t\tDrop.Create(l == Tile.TintedRock ? \"bk:tinted_rock\" : \"bk:rock\", null, level.Area, ww);\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\n\t\t\t\tpart.Position = ww;\n\t\t\t\tlevel.Area.Add(part);\n\t\t\t}\n\n\t\t\tParticles.BreakSprite(level.Area, (l == Tile.TintedRock ? level.Tileset.TintedRock : (l == Tile.MetalBlock ? level.Tileset.MetalBlock : level.Tileset.Rock))[Rnd.Int(4)], ww);\n\n\t\t\tlevel.Set(x, y, Tile.Ember);\n\t\t\tlevel.UpdateTile(x, y);\n\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t}\n\n\t\tpublic static void Make(Entity whoHurts, float hurtRadius = 32f, bool leave = true, Vec2 where = null, float damage = 16, float scale = 1, bool damageOwner = true) {\n\t\t\tCamera.Instance.Shake(10 * scale);\n\t\t\tAudio.SfxVolumeBuffer = 0.5f;\n\t\t\tAudio.SfxVolumeBufferResetTimer = 1f;\n\t\t\t\n\t\t\tvar w = where == null ? whoHurts.Center : new Vector2(where.X, where.Y);\n\n\t\t\tAnimationUtil.Explosion(w, scale);\n\n\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\tvar explosion = new ParticleEntity(Particles.Animated(\"explosion\", \"smoke\"));\n\t\t\t\texplosion.Position = w;\n\t\t\t\twhoHurts.Area.Add(explosion);\n\t\t\t\texplosion.Depth = 31;\n\t\t\t\texplosion.Particle.Scale = scale;\n\t\t\t\texplosion.Particle.AngleVelocity = 0;\n\t\t\t\texplosion.AddShadow();\n\n\t\t\t\tvar a = explosion.Particle.Angle - Math.PI / 2;\n\t\t\t\tvar d = 16;\n\n\t\t\t\texplosion.Particle.Position += new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t\t\n\t\t\t\tif (i == 0) {\n\t\t\t\t\texplosion.AddComponent(new AudioEmitterComponent {\n\t\t\t\t\t\tDestroySounds = false\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\texplosion.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"level_explosion\", 3);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = 0; i < 6; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\tpart.Position = w + new Vector2(Rnd.Int(-4, 4), Rnd.Int(-4, 4));\n\t\t\t\twhoHurts.Area.Add(part);\n\t\t\t\tpart.Depth = 30;\n\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 80);\n\t\t\t}\n\t\t\t\n\t\t\tEngine.Instance.Split = 1f;\n\t\t\tEngine.Instance.Flash = 1f;\n\t\t\tEngine.Instance.Freeze = 1f;\n\n\t\t\tvar damager = whoHurts;\n\n\t\t\tif (whoHurts is Bomb b && b.Owner != null) {\n\t\t\t\tdamager = b.Owner;\n\t\t\t}\n\t\t\t\t\t\n\t\t\tforeach (var e in whoHurts.Area.GetEntitesInRadius(w, hurtRadius, typeof(ExplodableComponent))) {\n\t\t\t\tif (e == whoHurts && !damageOwner) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\te.GetAnyComponent<BodyComponent>()?.KnockbackFrom(whoHurts, 4f);\n\t\t\t\te.GetComponent<ExplodableComponent>().HandleExplosion(damager, whoHurts, damage);\n\t\t\t}\n\n\t\t\tif (Settings.Flashes) {\n\t\t\t\tCamera.Instance.TextureZoom -= 0.05f;\n\t\t\t\tTween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.2f);\n\t\t\t}\n\n\t\t\tif (leave) {\n\t\t\t\twhoHurts.Area.Add(new ExplosionLeftOver {\n\t\t\t\t\tCenter = w\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar xx = (int) Math.Floor(w.X / 16f);\n\t\t\tvar yy = (int) Math.Floor(w.Y / 16f);\n\t\t\tvar r = (int) Math.Floor(hurtRadius / 16f);\n\t\t\tvar level = Run.Level;\n\t\t\tvar ice = level.Biome is IceBiome;\n\t\t\t\t\n\t\t\tfor (int x = -r; x <= r; x++) {\n\t\t\t\tfor (int y = -r; y <= r; y++) {\n\t\t\t\t\tvar xm = x * 16;\n\t\t\t\t\tvar ym = y * 16;\n\t\t\t\t\t\t\n\t\t\t\t\tif (Math.Sqrt(xm * xm + ym * ym) <= hurtRadius) {\n\t\t\t\t\t\tvar index = level.ToIndex(x + xx, y + yy);\n\t\t\t\t\t\tvar l = level.Get(index, true);\n\t\t\t\t\t\tvar ww = new Dot((x + xx) * 16 + 8, (y + yy) * 16 + 8);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tif (l.IsRock()) {\n\t\t\t\t\t\t\tBreakRock(level, ww, x + xx, y + yy, l);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t} \n\t\t\t\t\t\t\n\t\t\t\t\t\tvar tile = level.Get(index);\n\n\t\t\t\t\t\tif (tile == Tile.Crack) {\n\t\t\t\t\t\t\tDiscoverCrack(whoHurts, level, x + xx, y + yy);\n\t\t\t\t\t\t} else if (tile == Tile.Planks || (ice && tile == Tile.WallA)) {\n\t\t\t\t\t\t\tlevel.Break((x + xx) * 16, (y + yy) * 16);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void CheckForCracks(Level level, Room room, Entity who) {\n\t\t\tif (room != null) {\n\t\t\t\tfor (var y = room.MapY; y < room.MapY + room.MapY; y++) {\n\t\t\t\t\tfor (var x = room.MapX; x < room.MapX + room.MapW; x++) {\n\t\t\t\t\t\tif (level.IsInside(x, y) && level.Get(x, y) == Tile.Crack) {\n\t\t\t\t\t\t\tDiscoverCrack(who, level, x, y);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void DiscoverCrack(Entity who, Level level, int x, int y) {\n\t\t\tvar index = level.ToIndex(x, y);\n\t\t\t\n\t\t\tlevel.Set(index, Tile.FloorA);\n\t\t\tlevel.Set(index, Tile.Ember);\n\t\t\tlevel.UpdateTile(x, y);\n\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t\tlevel.LoadPassable();\n\t\t\t\t\t\t\t\t\n\t\t\twho.HandleEvent(new SecretRoomFoundEvent {\n\t\t\t\tWho = who\n\t\t\t});\n\t\t\t\n\t\t\tAchievements.Unlock(\"bk:treasure_hunter\");\n\t\t\t\n\t\t\tLightUp(x * 16 + 8, y * 16 + 8);\n\t\t\tLevel.Animate(who.Area, x, y);\n\t\t}\n\n\t\tpublic static void LightUp(float X, float Y) {\n\t\t\tvar x = (int) (X / 16f);\n\t\t\tvar y = (int) (Y / 16f);\n\t\t\tvar d = 2;\n\n\t\t\tfor (int xx = -d; xx <= d; xx++) {\n\t\t\t\tfor (int yy = -d; yy <= d; yy++) {\n\t\t\t\t\tvar ds = Math.Sqrt(xx * xx + yy * yy);\n\n\t\t\t\t\tif (ds <= d) {\n\t\t\t\t\t\tvar level = Run.Level;\n\t\t\t\t\t\tvar index = level.ToIndex(xx + x, yy + y);\n\n\t\t\t\t\t\tlevel.Light[index] = (float) Math.Max(level.Light[index], Math.Max(0.1f, (d - ds) / d));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/HealthType.cs",
    "content": "namespace BurningKnight.entity {\n\tpublic enum HealthType {\n\t\tRegular,\n\t\tShield,\n\t\tBomb\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/Layers.cs",
    "content": "﻿namespace BurningKnight.entity {\n\tpublic static class Layers {\n\t\tpublic const int Chasm = -12;\n\t\tpublic const int UnderFloor = -11;\n\t\tpublic const int Floor = -10;\n\t\tpublic const int Blood = -9;\n\t\tpublic const int Liquid = -8;\n\t\tpublic const int FloorParticles = -7;\n\t\tpublic const int Entrance = -6;\n\t\tpublic const int Shadows = -5;\n\t\tpublic const int Rocks = -4;\n\t\tpublic const int Sides = -2;\n\t\tpublic const int Door = 0;\n\t\tpublic const int Creature = 0;\n\t\t\n\t\tpublic const int Lock = 2;\n\t\tpublic const int Wall = 3;\n\t\tpublic const int WallDecor = 4;\n\t\tpublic const int FlyingMob = 5;\n\t\tpublic const int TileLights = 6;\n\t\tpublic const int WindFx = 7;\n\t\tpublic const int InGameUi = 8;\n\t\tpublic const int Light = 9;\n\t\t\n\t\tpublic const int Ui = 10;\n\t\tpublic const int Console = 11;\n\t\tpublic const int Bk = 12;\n\t\tpublic const int Cursor = 13;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/Lego.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity {\n\tpublic class Lego : Entity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddComponent(new ScalableSliceComponent(\"particles\", $\"lego_{Rnd.Int(3)}\"));\n\t\t\t\n\t\t\tvar s = GetComponent<ScalableSliceComponent>();\n\t\t\tvar region = s.Sprite;\n\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\t\t\ts.Origin.Y = Height;\n\t\t\t\n\t\t\ts.Animate();\n\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, Width, Height));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Creature c && !c.IsFriendly()) {\n\t\t\t\t\tif (c.GetComponent<HealthComponent>().ModifyHealth(-10, this, DamageType.Custom)) {\n\t\t\t\t\t\tAnimationUtil.Ash(Center);\n\t\t\t\t\t\tDone = true;\n\t\t\t\t\t\tCamera.Instance.Shake(5);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/RenderTrigger.cs",
    "content": "﻿using System;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity {\n\tpublic class RenderTrigger : Entity {\n\t\tprivate Action method;\n\t\tpublic Entity Entity;\n\t\t\n\t\t\n\t\tpublic RenderTrigger(Action method, int depth) {\n\t\t\tDepth = depth;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tthis.method = method;\n\t\t}\n\t\t\n\t\tpublic RenderTrigger(Entity entity, Action method, int depth) {\n\t\t\tDepth = depth;\n\t\t\tEntity = entity;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tthis.method = method;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Entity != null && Entity.Done) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmethod();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/RenderTriggerManager.cs",
    "content": "using System.Collections.Generic;\nusing Lens.entity;\n\nnamespace BurningKnight.entity {\n\tpublic class RenderTriggerManager {\n\t\tprivate Entity entity;\n\t\tprivate List<RenderTrigger> triggers = new List<RenderTrigger>();\n\t\t\n\t\tpublic RenderTriggerManager(Entity e) {\n\t\t\tentity = e;\n\t\t}\n\t\t\n\t\tpublic void Add(RenderTrigger trigger) {\n\t\t\tentity.Area.Add(trigger);\n\t\t\ttriggers.Add(trigger);\n\t\t}\n\n\t\tpublic void Update() {\n\t\t\tif (entity.Done) {\n\t\t\t\tDestroy();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var t in triggers) {\n\t\t\t\tif (t.Done || t.Area != entity.Area) {\n\t\t\t\t\tt.Done = false;\n\t\t\t\t\tt.Area = null;\n\t\t\t\t\tt.Components = null;\n\t\t\t\t\tentity.Area.Add(t);\n\t\t\t\t}\n\t\t\t} \n\t\t}\n\n\t\tpublic void Destroy() {\n\t\t\tforeach (var t in triggers) {\n\t\t\t\tt.Done = true;\n\t\t\t\tentity.Area.Remove(t);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/SpawnPoint.cs",
    "content": "using BurningKnight.save;\r\nusing BurningKnight.ui.editor;\r\nusing Lens;\r\nusing Lens.graphics;\r\nusing MonoGame.Extended;\r\n\r\nnamespace BurningKnight.entity {\r\n\tpublic class SpawnPoint : SaveableEntity, PlaceableEntity {\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\tAddTag(Tags.Checkpoint);\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tif (Engine.EditingLevel) {\r\n\t\t\t\tGraphics.Batch.FillRectangle(X, Y, Width, Height, ColorUtils.WhiteColor);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/bomb/Bomb.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.bomb {\n\tpublic delegate void BombUpdateCallback(Bomb b, float dt);\n\tpublic delegate void BombDeathCallback(Bomb b);\n\t\n\tpublic class Bomb : Entity, CollisionFilterEntity {\n\t\tpublic const float ExplosionTime = 1f;\n\t\tprivate readonly float explosionTime; \n\n\t\tpublic BombUpdateCallback Controller;\n\t\tpublic BombDeathCallback OnDeath;\n\n\t\tpublic Bomb Parent;\n\t\tpublic Entity Owner;\n\n\t\tpublic float Scale;\n\t\tpublic float T;\n\t\tpublic bool ExplodeOnTouch;\n\t\t\n\t\tpublic Bomb(Entity owner, float time = ExplosionTime, Bomb parent = null) {\n\t\t\texplosionTime = time + Rnd.Float(-0.1f, 1f);\n\t\t\t\n\t\t\tParent = parent;\n\t\t\tOwner = owner;\n\n\t\t\tScale = parent?.Scale * 0.7f ?? 1;\n\t\t\t\n\t\t\tCamera.Instance.Shake(6);\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new BombGraphicsComponent(\"items\", \"bomb\"));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new RoomComponent());\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 32f * Scale, new Color(1f, 0.3f, 0.3f, 1f)));\n\t\t\tAddTag(Tags.Bomb);\n\n\t\t\tWidth = 10 * Scale;\n\t\t\tHeight = 13 * Scale;\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height));\n\t\t\tAddComponent(new ExplodeComponent {\n\t\t\t\tRadius = 32,\n\t\t\t\tTimer = explosionTime\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"bomb_placed\");\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic void MoveToMouse() {\n\t\t\tVelocityTo(AngleTo(Owner.GetComponent<CursorComponent>().Cursor.GamePosition));\n\t\t}\n\n\t\tpublic void VelocityTo(float angle, float force = 100f) {\n\t\t\tvar component = GetComponent<RectBodyComponent>();\n\t\t\tvar vec = new Vector2((float) Math.Cos(angle) * force, (float) Math.Sin(angle) * force);\n\t\t\t\n\t\t\tPosition += vec * 0.05f;\n\t\t\t\n\t\t\tcomponent.Body.LinearDamping = 5;\n\t\t\tcomponent.Velocity = vec;\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Creature);\n\t\t}\n\n\t\tprivate bool sent;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tT += dt;\n\n\t\t\tif (!sent) {\n\t\t\t\tsent = true;\n\t\t\t\t\n\t\t\t\t// Not placed in init, so that room component had a chance to guess the room\t\t\t\t\n\t\t\t\tOwner?.HandleEvent(new BombPlacedEvent {\n\t\t\t\t\tBomb = this,\n\t\t\t\t\tOwner = Owner\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tController?.Invoke(this, dt);\n\t\t}\n\t\t\n\t\tpublic void Explode() {\n\t\t\tOnDeath?.Invoke(this);\n\t\t\tDone = true;\n\t\t\tvar r = GetComponent<ExplodeComponent>().Radius;\n\t\t\tExplosionMaker.Make(this, r, scale: r / 32f);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Projectile p) {\n\t\t\t\t\tGetComponent<RectBodyComponent>().KnockbackFrom(p);\n\n\t\t\t\t\tif (!p.HasFlag(ProjectileFlags.FlyOverStones)) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t} else if (ExplodeOnTouch && cse.Entity is Creature ca && Owner is Creature cb && ca.IsFriendly() != cb.IsFriendly()) {\n\t\t\t\t\tExplode();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/bomb/controller/TargetBombController.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.bomb.controller {\n\tpublic static class TargetBombController {\n\t\tpublic static BombUpdateCallback Make(Entity target, float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar d = Math.Max(100, b.Velocity.Length());\n\t\t\t\tvar a = b.Velocity.ToAngle();\n\t\t\t\t\n\t\t\t\tif (target == null) {\n\t\t\t\t\tvar md = 320000f;\n\n\t\t\t\t\tforeach (var m in (p.Owner.TryGetComponent<RoomComponent>(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) {\n\t\t\t\t\t\tif (m.GetComponent<HealthComponent>().Unhittable) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar dd = m.DistanceTo(p);\n\n\t\t\t\t\t\tif (dd < md) {\n\t\t\t\t\t\t\tmd = dd;\n\t\t\t\t\t\t\ttarget = m;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (target == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (target.Done) {\n\t\t\t\t\ttarget = null;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ta = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 4);\n\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/ArmoredBuff.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class ArmoredBuff : Buff {\n\t\tpublic const string Id = \"bk:armored\";\n\t\t\n\t\tpublic ArmoredBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.GetComponent<BuffsComponent>().Remove<BrokenArmorBuff>();\n\t\t}\n\n\t\tpublic override void HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme) {\n\t\t\t\tif (hme.Amount < 0) {\n\t\t\t\t\thme.Amount /= 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbase.HandleEvent(e);\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"armor\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BleedingBuff.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BleedingBuff : Buff {\n\t\tpublic static Vector4 Color = new Vector4(0.5f, 0f, 0f, 1f);\n\t\tpublic const string Id = \"bk:bleeding\";\n\t\tpublic const float Delay = 0.5f;\n\t\tprivate float tillDamage = Delay;\n\n\t\tpublic BleedingBuff() : base(Id) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\ttillDamage -= dt;\n\n\t\t\tif (tillDamage <= 0) {\n\t\t\t\ttillDamage = Delay;\n\t\t\t\tEntity.GetComponent<HealthComponent>().ModifyHealth(-1, Entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"blood\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BrokenArmorBuff.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BrokenArmorBuff : Buff {\n\t\tpublic const string Id = \"bk:broken_armor\";\n\t\t\n\t\tpublic BrokenArmorBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.GetComponent<BuffsComponent>().Remove<ArmoredBuff>();\n\t\t}\n\n\t\tpublic override void HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme) {\n\t\t\t\tif (hme.Amount < 0) {\n\t\t\t\t\thme.Amount *= 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbase.HandleEvent(e);\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"broken_armor\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/Buff.cs",
    "content": "﻿using Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class Buff {\n\t\tpublic Entity Entity;\n\t\tpublic float TimeLeft;\n\t\tpublic float Duration = 1f;\n\t\tpublic bool Infinite;\n\t\tpublic readonly string Type;\n\n\t\tpublic Buff(string id) {\n\t\t\tType = id;\n\t\t}\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\tTimeLeft = Duration;\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\tif (!Infinite) {\n\t\t\t\tTimeLeft -= dt;\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void HandleEvent(Event e) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual string GetIcon() {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BuffCheckEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BuffCheckEvent : Event {\n\t\tpublic Entity Entity;\n\t\tpublic Buff Buff;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BuffInfo.cs",
    "content": "using System;\nusing BurningKnight.entity.projectile;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BuffInfo {\n\t\tpublic Type Buff;\n\t\tpublic ProjectileGraphicsEffect Effect;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BuffRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.projectile;\n\nnamespace BurningKnight.entity.buff {\n\tpublic static class BuffRegistry {\n\t\tpublic static Dictionary<string, BuffInfo> All = new Dictionary<string, BuffInfo>();\n\n\t\tstatic BuffRegistry() {\n\t\t\tAdd<BurningBuff>(BurningBuff.Id, ProjectileGraphicsEffect.Burning);\n\t\t\tAdd<CharmedBuff>(CharmedBuff.Id, ProjectileGraphicsEffect.Charming);\n\t\t\tAdd<PoisonBuff>(PoisonBuff.Id, ProjectileGraphicsEffect.Poison);\n\t\t\tAdd<FrozenBuff>(FrozenBuff.Id, ProjectileGraphicsEffect.Freezing);\n\t\t\tAdd<SlowBuff>(SlowBuff.Id, ProjectileGraphicsEffect.Slowing);\n\t\t\tAdd<ArmoredBuff>(ArmoredBuff.Id);\n\t\t\tAdd<BrokenArmorBuff>(BrokenArmorBuff.Id, ProjectileGraphicsEffect.BrokenArmor);\n\t\t\tAdd<InvincibleBuff>(InvincibleBuff.Id);\n\t\t\tAdd<RageBuff>(RageBuff.Id);\n\t\t\tAdd<InvisibleBuff>(InvisibleBuff.Id);\n\t\t\tAdd<BuffedBuff>(BuffedBuff.Id);\n\t\t\tAdd<BleedingBuff>(BleedingBuff.Id);\n\t\t\tAdd<ConfusedBuff>(ConfusedBuff.Id);\n\t\t}\n\t\t\n\t\tpublic static void Add<T>(string id, ProjectileGraphicsEffect effect = ProjectileGraphicsEffect.Normal) where T : Buff {\n\t\t\tAll[id] = new BuffInfo {\n\t\t\t\tBuff = typeof(T),\n\t\t\t\tEffect = effect\n\t\t\t};\n\t\t}\n\n\t\tpublic static void Remove(string id) {\n\t\t\tAll.Remove(id);\n\t\t}\n\t\t\n\t\tpublic static Buff Create(string id) {\n\t\t\tif (!All.TryGetValue(id, out var buff)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn (Buff) Activator.CreateInstance(buff.Buff);\n\t\t}\n\n\t\tpublic static Buff Create<T>() where T : Buff {\n\t\t\treturn (Buff) Activator.CreateInstance(typeof(T));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BuffedBuff.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BuffedBuff : Buff {\n\t\tpublic const string Id = \"bk:buffed\";\n\t\t\n\t\tpublic BuffedBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"buffed\";\n\t\t}\n\n\t\tpublic override void HandleEvent(Event e) {\n\t\t\tif (e is MeleeArc.CreatedEvent meae) {\n\t\t\t\tmeae.Arc.Damage *= 2;\n\t\t\t} else if (e is ProjectileCreatedEvent pce) {\n\t\t\t\tpce.Projectile.Damage *= 2;\n\t\t\t} else if (e is HealthModifiedEvent hme) {\n\t\t\t\tif (hme.Amount < 0) {\n\t\t\t\t\thme.Amount *= 0.5f;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbase.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/BurningBuff.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class BurningBuff : Buff {\n\t\tpublic static Vector4 Color = new Vector4(0.5f, 0f, 0f, 1f);\n\t\tpublic const string Id = \"bk:burning\";\n\t\tpublic const float Delay = 1f;\n\t\t\n\t\tprivate float tillDamage = Delay;\n\t\tprivate float lastParticle;\n\n\t\tpublic BurningBuff() : base(Id) {\n\t\t\tInfinite = true;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.GetComponent<BuffsComponent>().Remove<FrozenBuff>();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle += dt;\n\n\t\t\tif (lastParticle >= 0.5f) {\n\t\t\t\tlastParticle = 0;\n\n\t\t\t\tEntity.Area.Add(new FireParticle {\n\t\t\t\t\tOwner = Entity\n\t\t\t\t});\n\t\t\t}\n\n\t\t\ttillDamage -= dt;\n\n\t\t\tif (tillDamage <= 0) {\n\t\t\t\ttillDamage = Delay;\n\t\t\t\tEntity.GetComponent<HealthComponent>().ModifyHealth(-1, Entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"fire\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/CharmedBuff.cs",
    "content": "﻿using BurningKnight.assets;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.component;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class CharmedBuff : Buff {\n\t\tpublic const string Id = \"bk:charmed\";\n\t\tpublic static Vector4 Color = new Vector4(0.5f, -0.2f, 0.5f, 1f);\n\n\t\tprivate float lastParticle;\n\n\t\tpublic CharmedBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\t\t\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle += dt;\n\n\t\t\tif (lastParticle >= 0.4f) {\n\t\t\t\tlastParticle = 0;\n\n\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"heart_{Rnd.Int(1, 4)}\"))));\n\t\t\t\tpart.Position = Entity.Center;\n\n\t\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t\n\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\tpart.Particle.Alpha = 0.9f;\n\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"love\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/ConfusedBuff.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class ConfusedBuff : Buff {\n\t\tpublic const string Id = \"bk:confused\";\n\t\t\n\t\tpublic ConfusedBuff() : base(Id) {\n\t\t\tDuration = 128;\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (Entity.TryGetComponent<RectBodyComponent>(out var b)) {\n\t\t\t\tb.Confused = true;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<SensorBodyComponent>(out var sb)) {\n\t\t\t\tsb.Confused = true;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<CircleBodyComponent>(out var cb)) {\n\t\t\t\tcb.Confused = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<RectBodyComponent>(out var b)) {\n\t\t\t\tb.Confused = false;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<SensorBodyComponent>(out var sb)) {\n\t\t\t\tsb.Confused = false;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<CircleBodyComponent>(out var cb)) {\n\t\t\t\tcb.Confused = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"confused\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/FrozenBuff.cs",
    "content": "using BurningKnight.entity.component;\r\nusing Lens.entity.component.logic;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.buff {\r\n\tpublic class FrozenBuff : Buff {\r\n\t\tpublic const string Id = \"bk:frozen\";\r\n\t\tpublic static Vector4 Color = new Vector4(0.5f, 0.5f, 1f, 1f);\r\n\t\t\r\n\t\tpublic FrozenBuff() : base(Id) {\r\n\t\t\tDuration = 3;\r\n\t\t}\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tEntity.GetComponent<BuffsComponent>().Remove<BurningBuff>();\r\n\r\n\t\t\tif (Entity.TryGetComponent<StateComponent>(out var s)) {\r\n\t\t\t\ts.Pause++;\r\n\t\t\t}\r\n\r\n\t\t\tvar a = Entity.GetAnyComponent<AnimationComponent>();\r\n\r\n\t\t\tif (a != null) {\r\n\t\t\t\ta.Animation.Paused = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\t\t\t\r\n\t\t\tvar body = Entity.GetAnyComponent<BodyComponent>();\r\n\r\n\t\t\tif (body != null) {\r\n\t\t\t\tbody.Velocity -= body.Velocity * (dt * 20);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (Entity.TryGetComponent<StateComponent>(out var s)) {\r\n\t\t\t\ts.Pause--;\r\n\t\t\t}\r\n\r\n\t\t\tvar a = Entity.GetAnyComponent<AnimationComponent>();\r\n\r\n\t\t\tif (a != null) {\r\n\t\t\t\ta.Animation.Paused = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override string GetIcon() {\r\n\t\t\treturn \"snow\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/buff/InvincibleBuff.cs",
    "content": "using BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class InvincibleBuff : Buff {\n\t\tpublic const string Id = \"bk:invincible\";\n\t\t\n\t\tpublic InvincibleBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override void HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme) {\n\t\t\t\thme.Handled = true;\n\t\t\t}\n\t\t\t\n\t\t\tbase.HandleEvent(e);\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"star\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/InvisibleBuff.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class InvisibleBuff : Buff {\n\t\tpublic static Vector4 Color = new Vector4(0.3f, 0.3f, 0.7f, 0.5f);\n\t\t\n\t\tpublic const string Id = \"bk:invisible\";\n\t\tpublic InvisibleBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"invisible\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/PoisonBuff.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class PoisonBuff : Buff {\n\t\tpublic static Vector4 Color = new Vector4(0.1f, 0.5f, 0.1f, 1f);\n\t\tpublic const string Id = \"bk:poison\";\n\t\tprivate const float Delay = 2f;\n\n\t\tprivate float tillDamage = Delay;\n\t\tprivate float lastParticle;\n\t\t\n\t\tpublic PoisonBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle += dt;\n\n\t\t\tif (lastParticle >= 0.5f) {\n\t\t\t\tlastParticle = 0;\n\n\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"poison_{Rnd.Int(1, 4)}\"))));\n\t\t\t\tpart.Position = Entity.Center;\n\n\t\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t\n\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\tpart.Particle.Alpha = 0.8f;\n\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t}\n\t\t\t\n\t\t\ttillDamage -= dt;\n\n\t\t\tif (tillDamage <= 0) {\n\t\t\t\ttillDamage = Delay;\n\t\t\t\tEntity.GetComponent<HealthComponent>().ModifyHealth(-2, Entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"poison\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/ProjectileShaderHelper.cs",
    "content": "using BurningKnight.entity.projectile;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic static class ProjectileShaderHelper {\n\t\tpublic static Color GetColor(this ProjectileGraphicsEffect effect) {\n\t\t\tswitch (effect) {\n\t\t\t\tcase ProjectileGraphicsEffect.Poison: return ProjectileColor.Green;\n\t\t\t\tcase ProjectileGraphicsEffect.Charming: return ProjectileColor.Pink;\n\t\t\t\tcase ProjectileGraphicsEffect.Freezing: return ProjectileColor.Cyan;\n\t\t\t\tcase ProjectileGraphicsEffect.Slowing: return ProjectileColor.Brown;\n\t\t\t\tcase ProjectileGraphicsEffect.Burning: return ProjectileColor.Orange;\n\t\t\t\tcase ProjectileGraphicsEffect.BrokenArmor: return ProjectileColor.Gray;\n\t\t\t\t\t\n\t\t\t\tdefault: return ProjectileColor.Yellow;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/RageBuff.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class RageBuff : Buff {\n\t\tpublic const string Id = \"bk:rage\";\n\t\t\n\t\tpublic RageBuff() : base(Id) {\n\t\t\tDuration = 10;\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"rage\";\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (Entity is Player) {\n\t\t\t\tTextParticle.Add(Entity, Locale.Get(\"damage\"), 1, true);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Entity is Player) {\n\t\t\t\tTextParticle.Add(Entity, Locale.Get(\"damage\"), 1, true, true);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void HandleEvent(Event e) {\n\t\t\tif (e is MeleeArc.CreatedEvent meae) {\n\t\t\t\tmeae.Arc.Damage *= 2;\n\t\t\t} else if (e is ProjectileCreatedEvent pce) {\n\t\t\t\tpce.Projectile.Damage *= 2;\n\t\t\t}\n\t\t\t\n\t\t\tbase.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/buff/SlowBuff.cs",
    "content": "using BurningKnight.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.buff {\n\tpublic class SlowBuff : Buff {\n\t\tpublic const string Id = \"bk:slow\";\n\t\tpublic static Vector4 Color = new Vector4(0.4f - 0.5f, 0.26f - 0.5f, 0.12f - 0.5f, 1f);\n\n\t\tpublic SlowBuff() : base(Id) {\n\t\t\tDuration = 5;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (Entity.TryGetComponent<RectBodyComponent>(out var b)) {\n\t\t\t\tb.Slow = true;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<SensorBodyComponent>(out var sb)) {\n\t\t\t\tsb.Slow = true;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<CircleBodyComponent>(out var cb)) {\n\t\t\t\tcb.Slow = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<RectBodyComponent>(out var b)) {\n\t\t\t\tb.Slow = false;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<SensorBodyComponent>(out var sb)) {\n\t\t\t\tsb.Slow = false;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<CircleBodyComponent>(out var cb)) {\n\t\t\t\tcb.Slow = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetIcon() {\n\t\t\treturn \"snail\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/AimComponent.cs",
    "content": "using BurningKnight.entity.creature.mob;\r\nusing Lens.entity.component;\r\nusing Lens.input;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class AimComponent : Component {\r\n\t\tpublic enum AimType {\r\n\t\t\tCursor,\r\n\t\t\tTarget,\r\n\t\t\tAnyPlayer\r\n\t\t}\r\n\r\n\t\tpublic AimComponent(AimType t) {\r\n\t\t\tTheType = t;\r\n\t\t}\r\n\r\n\t\tpublic AimType TheType;\r\n\t\tpublic Vector2 Aim;\r\n\t\tpublic Vector2 RealAim;\r\n\t\tpublic Vector2 Center;\r\n\t\tpublic bool ShowLaserLine;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (TheType == AimType.Cursor) {\r\n\t\t\t\tAim = Entity.GetComponent<CursorComponent>().Cursor.GamePosition;\r\n\t\t\t} else if (TheType == AimType.Target) {\r\n\t\t\t\tRealAim = Aim = ((Mob) Entity).Target?.Center ?? Input.Mouse.GamePosition;\r\n\t\t\t} else {\r\n\t\t\t\tvar a = GetComponent<RoomComponent>().Room.Tagged[Tags.Player];\r\n\r\n\t\t\t\tif (a.Count > 0) {\r\n\t\t\t\t\tRealAim = Aim = a[0].Center;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (TheType == AimType.Cursor) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tCenter = Entity.Center;\r\n\r\n\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\r\n\t\t\t\tCenter.Y -= z.Z;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/AnimationComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.graphics;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class AnimationComponent : GraphicsComponent {\n\t\tpublic Animation Animation;\n\t\tpublic Color Tint = Color.White;\n\t\tprivate string name;\n\t\tprivate ColorSet set;\n\n\t\tpublic float ShadowOffset;\n\t\tpublic Vector2 Scale = Vector2.One;\n\t\tpublic float Angle;\n\t\tpublic float OriginY;\n\t\tpublic float OriginX;\n\t\tpublic bool AddOrigin = true;\n\t\tpublic bool Centered;\n\n\t\tpublic bool Flash;\n\t\tpublic readonly string Id;\n\t\t\n\t\tpublic AnimationComponent(string animationName, string layer = null, string tag = null) {\n\t\t\tname = animationName;\n\t\t\tId = animationName;\n\t\t\t\n\t\t\tReloadAnimation(layer, tag);\n\t\t}\n\t\t\n\t\tpublic AnimationComponent(string animationName, ColorSet set) {\n\t\t\tname = animationName;\n\t\t\tId = animationName;\n\t\t\t\n\t\t\tthis.set = set;\n\t\t\t\n\t\t\tReloadAnimation();\n\t\t}\n\n\t\tpublic void SetAutoStop(bool stop) {\n\t\t\tAnimation.AutoStop = stop;\n\t\t}\n\t\t\n\t\tprivate void ReloadAnimation(string layer = null, string tag = null) {\n\t\t\tvar data = set == null ? Animations.Get(name) : Animations.GetColored(name, set);\n\n\t\t\tif (data != null) {\n\t\t\t\tAnimation = data.CreateAnimation(layer);\n\n\t\t\t\tif (tag != null) {\n\t\t\t\t\tAnimation.Tag = tag;\n\t\t\t\t}\n\n\t\t\t\tOriginX = Animation.GetCurrentTexture().Width / 2f;\n\t\t\t\tOriginY = Animation.GetCurrentTexture().Height;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Animations.Reload) {\n\t\t\t\tReloadAnimation();\n\t\t\t}\n\t\t\t\n\t\t\tAnimation?.Update(dt);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar pos = (Centered ? Entity.Center : Entity.Position) + Offset;\n\n\t\t\tif (shadow) {\n\t\t\t\tFlippedVerticaly = !FlippedVerticaly;\n\t\t\t\tpos.Y += Animation.GetCurrentTexture().Height - ShadowOffset * 2;\n\t\t\t}\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<InteractableComponent>(out var component) && component.OutlineAlpha > 0.05f) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(component.OutlineAlpha);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tCallRender(pos + d, shadow);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tvar stopShader = !shadow && StartShaders();\n\n\t\t\tGraphics.Color = Tint;\n\t\t\tCallRender(pos, shadow);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t\t\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tif (shadow) {\n\t\t\t\tFlippedVerticaly = !FlippedVerticaly;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected bool StartShaders() {\n\t\t\tif (Flash || (Entity.TryGetComponent<HealthComponent>(out var health) && health.RenderInvt && (health.InvincibilityTimer > health.InvincibilityTimerMax / 2f || health.InvincibilityTimer % 0.1f > 0.05f))) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (Entity.TryGetComponent<BuffsComponent>(out var buffs)) {\n\t\t\t\tif (buffs.Has<InvisibleBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(InvisibleBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (buffs.Has<InvincibleBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tvar t = buffs.Buffs[typeof(InvincibleBuff)].TimeLeft;\n\n\t\t\t\t\tif (t < 2f && t % 0.3f < 0.15f) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.FromHSV(Engine.Time * 180 % 360, 100, 100).ToVector4());\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (buffs.Has<FrozenBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(0f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(FrozenBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (buffs.Has<BurningBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(0f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(BurningBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (buffs.Has<PoisonBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(0f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(PoisonBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (buffs.Has<SlowBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(0f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(SlowBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (buffs.Has<CharmedBuff>()) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(0f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(CharmedBuff.Color);\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprotected virtual void CallRender(Vector2 pos, bool shadow) {\n\t\t\tif (Animation == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar region = Animation.GetCurrentTexture();\n\t\t\tvar or = new Vector2(OriginX, shadow ? region.Height - OriginY : OriginY);\n\t\t\t\n\t\t\tGraphics.Render(region, AddOrigin ? pos + or : pos, shadow ^ Flipped ? -Angle : Angle, or, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is StateChangedEvent ev && Animation != null) {\n\t\t\t\tvar tag = ev.NewState.Name.ToLower().Replace(\"state\", \"\");\n\t\t\t\t\n\t\t\t\tif (Animation.HasTag(tag)) {\n\t\t\t\t\tAnimation.Tag = tag;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic void Animate(Action callback = null) {\n\t\t\tTween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f);\n\t\t\tTween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\tTween.To(1, Scale.X, x => Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1, Scale.Y, x => Scale.Y = x, 0.4f);\n\n\t\t\t\tcallback?.Invoke();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/AudioEmitterComponent.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.entity.component;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Audio;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class AudioEmitterComponent : Component {\r\n\t\tpublic static AudioListener Listener;\r\n\t\tpublic static Vector2 ListenerPosition;\r\n\t\t\r\n\t\tpublic static float PositionScale = 0.00000001f;\r\n\t\tpublic static float Distance = 200;\r\n\t\t\r\n\t\tpublic AudioEmitter Emitter = new AudioEmitter();\r\n\t\tpublic float PitchMod;\r\n\t\tpublic bool DestroySounds = false;\r\n\r\n\t\tpublic Dictionary<string, Sfx> Playing = new Dictionary<string, Sfx>();\r\n\r\n\t\tpublic class Sfx {\r\n\t\t\tpublic SoundEffectInstance Effect;\r\n\t\t\tpublic float BaseVolume = 1f;\r\n\t\t\tpublic bool KeepAround;\r\n\t\t\tpublic bool ApplyBuffer;\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (DestroySounds) {\r\n\t\t\t\tStopAll();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void StopAll() {\r\n\t\t\tforeach (var s in Playing.Values) {\r\n\t\t\t\ts.Effect.Stop();\r\n\t\t\t\ts.Effect.Dispose();\r\n\t\t\t}\r\n\r\n\t\t\tPlaying.Clear();\r\n\t\t}\r\n\t\t\r\n\t\tprivate void UpdatePosition() {\r\n\t\t\tEmitter.Position = new Vector3(Entity.CenterX * PositionScale, 0, Entity.CenterY * PositionScale);\r\n\r\n\t\t\tif (Listener != null) {\r\n\t\t\t\tvar d = (ListenerPosition - Entity.Center).Length();\r\n\r\n\t\t\t\tforeach (var s in Playing.Values) {\r\n\t\t\t\t\ts.Effect.Volume = MathUtils.Clamp(0, 1, (1 - Math.Min(Distance, d) / Distance) * Settings.MasterVolume * Settings.SfxVolume * s.BaseVolume * (s.ApplyBuffer ? Audio.SfxVolumeBuffer : 1));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} // 6y0204mm\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (Playing.Count == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tUpdatePosition();\r\n\t\t\tvar keys = Playing.Keys.ToArray();\r\n\t\t\t\r\n\t\t\tforeach (var k in keys) {\r\n\t\t\t\tvar s = Playing[k];\r\n\r\n\t\t\t\tif (!s.KeepAround && s.Effect.State != SoundState.Playing) {\r\n\t\t\t\t\tPlaying.Remove(k);\r\n\t\t\t\t} else if (Listener != null) {\r\n\t\t\t\t\ts.Effect.Apply3D(Listener, Emitter);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic SoundEffectInstance EmitRandomizedPrefixed(string sfx, int prefixMax, float volume = 1f, bool insert = true, bool looped = false, bool tween = false, float sz = 0.4f) {\r\n\t\t\tif (sfx == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\r\n\t\t\treturn Emit($\"{sfx}_{Rnd.Int(1, prefixMax + 1)}\", volume, PitchMod + Rnd.Float(-sz, sz), insert, looped, tween);\r\n\t\t}\r\n\t\t\r\n\t\tpublic SoundEffectInstance EmitRandomized(string sfx, float volume = 1f, bool insert = true, bool looped = false, bool tween = false, float sz = 0.4f) {\r\n\t\t\tif (sfx == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn Emit(sfx, volume, PitchMod + Rnd.Float(-sz, sz), insert, looped, tween);\r\n    }\r\n\r\n\t\tpublic SoundEffectInstance Emit(string sfx, float volume = 1f, float pitch = 0f, bool insert = true, bool looped = false, bool tween = false) {\r\n\t\t\tif (!Assets.LoadSfx || sfx == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\tSfx instance;\r\n\t\t\tvar v = volume * 0.8f;\r\n\r\n\t\t\tif (!insert) {\r\n\t\t\t\tv *= Audio.MasterVolume * Audio.SfxVolume * Audio.SfxVolumeBuffer;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar applyBuffer = !sfx.StartsWith(\"level_explosion\");\r\n\r\n\t\t\t/*if (applyBuffer) {\r\n\t\t\t\tv *= Audio.SfxVolumeBuffer;\r\n\t\t\t}*/\r\n\r\n\t\t\tif (!insert || !Playing.TryGetValue(sfx, out instance)) {\r\n\t\t\t\tvar sound = Audio.GetSfx(sfx);\r\n\r\n\t\t\t\tif (sound == null) {\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinstance = new Sfx {\r\n\t\t\t\t\tEffect = sound.CreateInstance(),\r\n\t\t\t\t\tKeepAround = tween,\r\n\t\t\t\t\tApplyBuffer = applyBuffer\r\n\t\t\t\t};\r\n\r\n\t\t\t\tif (insert) {\r\n\t\t\t\t\tPlaying[sfx] = instance;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinstance.Effect.IsLooped = looped;\r\n\t\t\t}\r\n\r\n\t\t\tinstance.BaseVolume = tween ? 0 : v;\r\n\r\n\t\t\tif (tween) {\r\n\t\t\t\tvar t = Tween.To(v, 0, x => instance.BaseVolume = x, 0.5f);\r\n\r\n\t\t\t\tt.Delay = 1f;\r\n\t\t\t\tt.OnStart = () => {\r\n\t\t\t\t\tinstance.Effect.Play();\r\n\t\t\t\t\tinstance.KeepAround = false;\r\n\t\t\t\t\tinstance.Effect.Apply3D(Listener, Emitter);\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tUpdatePosition();\r\n\t\t\t\r\n\t\t\tinstance.Effect.Stop();\r\n\t\t\tinstance.Effect.Pitch = MathUtils.Clamp(-1f, 1f, pitch);\r\n\r\n\t\t\tif (!tween) {\r\n\t\t\t\tinstance.Effect.Play();\r\n\t\t\t}\r\n\r\n\t\t\tif (Listener != null) {\r\n\t\t\t\tinstance.Effect.Apply3D(Listener, Emitter);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn instance.Effect;\r\n\t\t}\r\n\r\n\t\tpublic static AudioEmitterComponent Dummy(Area area, Vector2 where) {\r\n\t\t\tvar entity = new EmitterDummy();\r\n\t\t\tvar component = new AudioEmitterComponent();\r\n\r\n\t\t\tarea.Add(entity);\r\n\t\t\tentity.AddComponent(component);\r\n\t\t\tentity.Center = where;\r\n\t\t\tentity.AlwaysActive = true;\r\n\r\n\t\t\treturn component;\r\n\t\t}\r\n\r\n\t\tprivate class EmitterDummy : Entity {\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\tif (GetComponent<AudioEmitterComponent>().Playing.Count == 0) {\r\n\t\t\t\t\tDone = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "BurningKnight/entity/component/BodyComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.entity.events;\nusing BurningKnight.physics;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.component {\n\tpublic class BodyComponent : SaveableComponent {\n\t\tpublic Body Body;\n\t\tpublic Vector2 Acceleration;\n\t\tpublic Vector2 Knockback;\n\t\tpublic float KnockbackModifier = 1;\n\t\tpublic Vector2 Offset;\n\t\tpublic bool Slow;\n\t\tpublic bool CanCollide = true;\n\t\tpublic bool Confused;\n\t\t\n\t\tpublic Vector2 Velocity {\n\t\t\tget => Slow ? Body.LinearVelocity * 2 : Body.LinearVelocity;\n\t\t\tset => Body.LinearVelocity = Slow ? value / 2 : value;\n\t\t}\n\n\t\tpublic Vector2 Position {\n\t\t\tget => Body.Position;\n\t\t\tset => Body.Position = value;\n\t\t}\n\n\t\tpublic float Angle {\n\t\t\tget => Body.Rotation;\n\t\t\tset => Body.Rotation = value;\n\t\t}\n\t\t\n\t\tprotected virtual void PositionChangedListener() {\n\t\t\tif (Body != null) {\n\t\t\t\ttry {\n\t\t\t\t\tBody.Position = Entity.Position + Offset;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.PositionChanged += PositionChangedListener;\n\t\t\t\n\t\t\tif (Body != null) {\n\t\t\t\ttry {\n\t\t\t\t\tBody.Position = Entity.Position + Offset;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tEntity.PositionChanged -= PositionChangedListener;\n\n\t\t\tif (Body != null) {\n\t\t\t\ttry {\n\t\t\t\t\tPhysics.RemoveBody(Body);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\n\t\t\t\tBody = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\tif (Entity is CollisionFilterEntity filter) {\n\t\t\t\treturn filter.ShouldCollide(entity);\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tpublic virtual void OnCollision(Entity entity) {\n\t\t\tEntity.HandleEvent(new CollisionStartedEvent {\n\t\t\t\tEntity = entity,\n\t\t\t\tBody = this\n\t\t\t});\n\t\t}\n\n\t\tpublic virtual void OnCollisionEnd(Entity entity) {\n\t\t\tEntity.HandleEvent(new CollisionEndedEvent {\n\t\t\t\tEntity = entity,\n\t\t\t\tBody = this\n\t\t\t});\n\t\t}\n\n\t\tpublic void KnockbackFrom(Entity entity, float force = 1f, float rnd = 0) {\n\t\t\tif (entity == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (entity.TryGetComponent<StatsComponent>(out var s)) {\n\t\t\t\tforce *= s.Knockback;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity == Entity) {\n\t\t\t\tKnockbackFrom(Rnd.AnglePI(), force, rnd);\n\t\t\t} else {\n\t\t\t\tKnockbackFrom(entity.Center, force, rnd);\n\t\t\t}\n\t\t}\n\n\t\tpublic void KnockbackFrom(Vector2 point, float force = 1f, float rnd = 0) {\n\t\t\tKnockbackFrom(Entity.AngleTo(point) - (float) Math.PI, force, rnd);\n\t\t}\n\n\t\tpublic virtual void KnockbackFrom(float a, float force = 1f, float rnd = 0) {\t\t\n\t\t\tforce *= KnockbackModifier * 30;\n\n\t\t\tif (force <= 0.02f) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (rnd > 0.01f) {\n\t\t\t\ta += Rnd.Float(-rnd, rnd);\n\t\t\t}\n\n\t\t\tKnockback.X += (float) Math.Cos(a) * force;\n\t\t\tKnockback.Y += (float) Math.Sin(a) * force;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (Body == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar velocity = Body.LinearVelocity;\n\t\t\tvelocity.X += Acceleration.X + Knockback.X * dt * 60;\n\t\t\tvelocity.Y += Acceleration.Y + Knockback.Y * dt * 60;\n\n\t\t\tKnockback.X -= Knockback.X * dt * 10f;\n\t\t\tKnockback.Y -= Knockback.Y * dt * 10f;\n\n\t\t\tif (Entity.GraphicsComponent != null && !Entity.GraphicsComponent.CustomFlip && velocity.Length() > 0.1f) {\n\t\t\t\tEntity.GraphicsComponent.Flipped = velocity.X < 0;\n\t\t\t}\n\t\t\t\n\t\t\tBody.LinearVelocity = velocity;\n\t\t\tEntity.Position = Body.Position - Offset;\n\t\t}\n\n\t\tpublic override void Load(FileReader reader) {\n\t\t\tbase.Load(reader);\n\t\t\tBody?.SetTransform(Entity.Position, 0);\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tImGui.DragFloat(\"Knockback modifier\", ref KnockbackModifier);\n\t\t\t\n\t\t\tif (Body == null) {\n\t\t\t\tImGui.BulletText(\"Body is null\");\n\t\t\t} else {\n\t\t\t\tvar vel = Body.LinearVelocity;\n\t\t\t\tvar v = new System.Numerics.Vector2(vel.X, vel.Y);\n\n\t\t\t\tif (ImGui.DragFloat2(\"Velocity\", ref v)) {\n\t\t\t\t\tBody.LinearVelocity = vel;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (ImGui.Button(\"Sync body\")) {\n\t\t\t\t\tPositionChangedListener();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void Resize(float x, float y, float w, float h, bool center = false) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/BombGraphicsComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.bomb;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class BombGraphicsComponent : SliceComponent {\n\t\tpublic BombGraphicsComponent(string image, string slice) : base(image, slice) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar timer = Entity.GetComponent<ExplodeComponent>();\n\t\t\tvar origin = new Vector2(Sprite.Center.X, shadow ? 0 : Sprite.Source.Height);\n\t\t\tvar stopShader = false;\n\t\t\tvar bomb = (Bomb) Entity;\n\t\t\t\n\t\t\tif (!shadow && (timer.Timer < 1f ? timer.Timer % 0.3f > 0.1f : timer.Timer % 0.5f > 0.4f)) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\t\t\t\t\t\n\t\t\t\tstopShader = true;\n\t\t\t}\n\n\t\t\tGraphics.Render(Sprite, Entity.Position + new Vector2(origin.X, origin.Y + (shadow ? Sprite.Height : 0)),\n\t\t\t\t0, origin, new Vector2(\n\t\t\t\t\t\t(float) ((Math.Cos(timer.Timer * 16) / 2f) + 1) * bomb.Scale * Math.Min(bomb.T * 4f, 1), \n\t\t\t\t\t\t(float) ((Math.Cos(timer.Timer * 16 + Math.PI) / 3f) + 1) * bomb.Scale\n\t\t\t\t\t), \n\t\t\t\tGraphics.ParseEffect(false, shadow));\n\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/BuffsComponent.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.events;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.component {\n\tpublic class BuffsComponent : SaveableComponent {\n\t\tpublic Dictionary<Type, Buff> Buffs = new Dictionary<Type, Buff>();\n\t\tprivate List<Type> immune = new List<Type>();\n\t\t\n\t\tpublic List<BuffParticle> Particles = new List<BuffParticle>();\n\t\tpublic bool IceImmunity;\n\t\tpublic bool PitImmunity;\n\n\t\tpublic void AddImmunity<T>() {\n\t\t\tvar type = typeof(T);\n\n\t\t\tif (!immune.Contains(type)) {\n\t\t\t\timmune.Add(type);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic Buff Add(Buff buff) {\n\t\t\tif (buff == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar type = buff.GetType();\n\t\t\t\n\t\t\tif (Buffs.ContainsKey(type)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var t in immune) {\n\t\t\t\tif (t == type) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (Send(new BuffCheckEvent {\n\t\t\t\t\tEntity = Entity,\n\t\t\t\t\tBuff = buff\n\t\t\t})) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tBuffs[type] = buff;\n\t\t\tbuff.Entity = Entity;\n\t\t\tbuff.Init();\n\t\t\t\n\t\t\tSend(new BuffAddedEvent {\n\t\t\t\tBuff = buff\n\t\t\t});\n\n\t\t\tif (Engine.Instance.State is InGameState && buff.GetIcon() != null) {\n\t\t\t\tvar part = new BuffParticle(buff, Entity);\n\t\t\t\tParticles.Add(part);\n\t\t\t\tEngine.Instance.State.Ui.Add(part);\n\t\t\t}\n\n\t\t\treturn buff;\n\t\t}\n\n\t\tpublic Buff Add(string id) {\n\t\t\treturn Add(BuffRegistry.Create(id));\n\t\t}\n\n\t\tpublic bool Has<T>() {\n\t\t\treturn Buffs.ContainsKey(typeof(T));\n\t\t}\n\n\t\tpublic void Remove<T>() {\n\t\t\tRemove(typeof(T));\n\t\t}\n\n\t\tpublic void Remove(Type type) {\n\t\t\tif (Buffs.TryGetValue(type, out var buff)) {\n\t\t\t\tif (!Send(new BuffRemovedEvent {\n\t\t\t\t\tBuff = buff\n\t\t\t\t})) {\n\t\t\t\t\tbuff.Destroy();\n\t\t\t\t\tBuffs.Remove(type);\n\n\t\t\t\t\tvar toRemove = -1;\n\n\t\t\t\t\tfor (var i = 0; i < Particles.Count; i++) {\n\t\t\t\t\t\tif (Particles[i].Buff == buff) {\n\t\t\t\t\t\t\ttoRemove = i;\n\t\t\t\t\t\t\tParticles[i].Remove();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (toRemove != -1) {\n\t\t\t\t\t\tParticles.RemoveAt(toRemove);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool addedIcons;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!addedIcons) {\n\t\t\t\taddedIcons = true;\n\n\t\t\t\tforeach (var b in Buffs.Values) {\n\t\t\t\t\tvar part = new BuffParticle(b, Entity);\n\t\t\t\t\tParticles.Add(part);\n\t\t\t\t\tEngine.Instance.State.Ui.Add(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var buff in Buffs.Values) {\t\t\t\t\n\t\t\t\tbuff.Update(dt);\n\t\t\t}\n\n\t\t\tforeach (var key in Buffs.Keys.ToList()) {\n\t\t\t\tvar buff = Buffs[key];\n\n\t\t\t\tif (buff.TimeLeft <= 0) {\n\t\t\t\t\tRemove(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte((byte) Buffs.Count);\n\t\t\t\n\t\t\tforeach (var buff in Buffs.Values) {\n\t\t\t\tstream.WriteString(buff.Type);\n\t\t\t\tstream.WriteFloat(buff.TimeLeft);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader reader) {\n\t\t\tbase.Load(reader);\n\t\t\tvar count = reader.ReadByte();\n\n\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\tvar buff = Add(reader.ReadString());\n\t\t\t\tbuff.TimeLeft = reader.ReadFloat();\n\t\t\t\tbuff.Entity = Entity;\n\t\t\t\tbuff.Init();\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tforeach (var b in Buffs.Values) {\n\t\t\t\tb.HandleEvent(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (e is TileCollisionStartEvent tileStart) {\n\t\t\t\tif (tileStart.Tile == Tile.Water) {\n\t\t\t\t\tRemove<BurningBuff>();\n\t\t\t\t}\n\t\t\t}/* else if (e is FlagCollisionStartEvent flagStart) {\n\t\t\t\tif (flagStart.Flag == Flag.Burning) {\n\t\t\t\t\tAdd<BurningBuff>();\n\t\t\t\t}\n\t\t\t}*/\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate static string toAdd = \"\";\n\n\t\tpublic override void RenderDebug() {\n\t\t\tif (ImGui.InputText(\"Buff\", ref toAdd, 128)) {\n\t\t\t\tAdd(toAdd);\n\t\t\t\ttoAdd = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\tif (ImGui.Button(\"Add\")) {\n\t\t\t\tAdd(toAdd);\n\t\t\t\ttoAdd = \"\";\n\t\t\t}\n\n\t\t\tif (Buffs.Count == 0) {\n\t\t\t\tImGui.BulletText(\"No buffs\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"Remove all\")) {\n\t\t\t\tforeach (var b in Buffs.Values) {\n\t\t\t\t\tb.TimeLeft = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var b in Buffs.Values) {\n\t\t\t\tif (toAdd.Length > 0 && !BuffRegistry.All.ContainsKey(toAdd)) {\n\t\t\t\t\tImGui.BulletText(\"Unknown buff\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.TreeNode($\"{b.Type}\")) {\n\t\t\t\t\tImGui.Text($\"{b.TimeLeft} seconds left\");\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button($\"Remove##{b.Type}\")) {\n\t\t\t\t\t\tb.TimeLeft = 0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button($\"Renew##{b.Type}\")) {\n\t\t\t\t\t\tb.TimeLeft = b.Duration;\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.Checkbox($\"Infinite##{b.Type}\", ref b.Infinite);\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/CircleBodyComponent.cs",
    "content": "﻿using BurningKnight.physics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\n\nnamespace BurningKnight.entity.component {\n\tpublic class CircleBodyComponent : BodyComponent {\n\t\tpublic CircleBodyComponent(float x, float y, float r, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) {\n\t\t\tif (center) {\n\t\t\t\tx -= r;\n\t\t\t\ty -= r;\n\t\t\t\tOffset = new Vector2(r, r);\n\t\t\t}\n\n\t\t\tBody = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type);\n\t\t\tBody.FixedRotation = true;\n\t\t\tBody.UserData = this;\n\t\t\tBody.LinearDamping = 0;\n\n\t\t\tBody.CreateFixture(new CircleShape(r, 1) {\n\t\t\t\tPosition = new Vector2(x + r, y + r),\n\t\t\t}).IsSensor = sensor;\n\t\t}\n\n\t\tpublic override void Resize(float x, float y, float w, float h, bool center = false) {\n\t\t\tvar fixture = Body.FixtureList[0];\n\t\t\tvar sensor = fixture.IsSensor;\n\t\t\t\n\t\t\tBody.DestroyFixture(fixture);\n\n\t\t\tvar r = w / 2f;\n\t\t\t\n\t\t\tif (center) {\n\t\t\t\tx -= r;\n\t\t\t\ty -= r;\n\t\t\t\tOffset = new Vector2(r, r);\n\t\t\t}\n\t\t\t\n\t\t\tBody.CreateFixture(new CircleShape(r, 1) {\n\t\t\t\tPosition = new Vector2(x + r, y + r),\n\t\t\t}).IsSensor = sensor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/CloseDialogComponent.cs",
    "content": "using System;\nusing BurningKnight.level;\nusing BurningKnight.physics;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class CloseDialogComponent : Component {\n\t\tpublic int Radius = 32 * 32;\n\t\tpublic int RadiusMax = 64 * 64;\n\t\tpublic bool UseLineOfSight = true;\n\n\t\tpublic string[] Variants;\n\t\tprivate Entity trigger;\n\n\t\tpublic Func<Entity, bool> CanTalk;\n\t\tpublic Func<Entity, string> DecideVariant;\n\n\t\tpublic CloseDialogComponent(params string[] vars) {\n\t\t\tVariants = vars;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tif (!Entity.OnScreen || Variants.Length == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!Entity.TryGetComponent<DialogComponent>(out var d)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (d.Current != null) {\n\t\t\t\tif (trigger != null && trigger.DistanceToSquared(Entity) > RadiusMax) {\n\t\t\t\t\ttrigger = null;\n\t\t\t\t\td.Close();\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var p in Entity.Area.Tagged[Tags.Player]) {\n\t\t\t\tif (p.DistanceToSquared(Entity) <= Radius && (!UseLineOfSight || CanSee(p.Center, Entity))) {\n\t\t\t\t\tif (CanTalk == null || CanTalk(Entity)) {\n\t\t\t\t\t\td.Start(DecideVariant?.Invoke(p) ?? Variants[Rnd.Int(Variants.Length)]);\n\t\t\t\t\t\ttrigger = p;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate static bool RayShouldCollide(Entity entity) {\n\t\t\treturn entity is ProjectileLevelBody;\n\t\t}\n\n\t\tprotected bool CanSee(Vector2 from, Entity e) {\n\t\t\tvar min = 1f;\n\t\t\tvar found = false;\n\t\t\t\n\t\t\tPhysics.World.RayCast((fixture, point, normal, fraction) => {\n\t\t\t\tif (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) {\n\t\t\t\t\tmin = fraction;\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn min;\n\t\t\t}, from, e.Center);\n\n\t\t\treturn !found;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/CollisionFilterComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class CollisionFilterComponent : Component {\n\t\tpublic List<Func<Entity, Entity, CollisionResult>> Filter = new List<Func<Entity, Entity, CollisionResult>>();\n\n\t\tpublic CollisionResult Invoke(Entity colliding) {\n\t\t\tforeach (var f in Filter) {\n\t\t\t\tvar v = f(Entity, colliding);\n\n\t\t\t\tif (v != CollisionResult.Default) {\n\t\t\t\t\treturn v;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn CollisionResult.Default;\n\t\t}\n\n\t\tpublic static void Add(Entity e, Func<Entity, Entity, CollisionResult> filter) {\n\t\t\tCollisionFilterComponent c;\n\n\t\t\tif (!e.TryGetComponent(out c)) {\n\t\t\t\tc = new CollisionFilterComponent();\n\t\t\t\te.AddComponent(c);\n\t\t\t}\n\t\t\t\n\t\t\tc.Filter.Add(filter);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/CursorComponent.cs",
    "content": "using Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class CursorComponent : Component {\n\t\tpublic Cursor Cursor;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/DoorBodyComponent.cs",
    "content": "﻿using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.component {\n\tpublic class DoorBodyComponent : RectBodyComponent {\n\t\tpublic DoorBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) : base(x, y, w, h, type, sensor, center) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tBody.IsSensor = false;\n\t\t}\n\n\t\tprivate bool ShouldBeSensor() {\n\t\t\treturn !(Entity.TryGetComponent<LockComponent>(out var l) && l.Lock.IsLocked);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\t/*if (entity is Projectile) {\n\t\t\t\treturn false;\n\t\t\t}*/\n\t\t\t\n\t\t\tif (entity is Player && ShouldBeSensor()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/DropModifier.cs",
    "content": "using System.Collections.Generic;\r\nusing BurningKnight.entity.item;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic interface DropModifier {\r\n\t\tvoid ModifyDrops(List<Item> drops);\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/DropsComponent.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.item;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.component {\n\tpublic class DropsComponent : Component {\n\t\tpublic List<Drop> Drops = new List<Drop>();\n\n\t\tpublic DropsComponent() {\n\t\t\t\n\t\t}\n\n\t\tpublic DropsComponent(string dropId) {\n\t\t\tAdd(dropId);\n\t\t}\n\n\t\tpublic void Add(string dropId) {\n\t\t\tif (!assets.loot.Drops.Defined.TryGetValue(dropId, out var d)) {\n\t\t\t\tLog.Error($\"Unknown drop {dropId}\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDrops.Add(d);\n\t\t}\n\n\t\tpublic void Add(params Drop[] drops) {\n\t\t\tDrops.AddRange(drops);\n\t\t}\n\t\t\n\t\tpublic void SpawnDrops() {\n\t\t\tDrop.Create(Drops, Entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ExplodableComponent.cs",
    "content": "using System;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ExplodableComponent : Component {\n\t\tpublic Action OnExplosion;\n\n\t\tpublic void HandleExplosion(Entity entity, Entity origin, float damage) {\n\t\t\tOnExplosion?.Invoke();\n\n\t\t\tSend(new ExplodedEvent {\n\t\t\t\tWho = entity,\n\t\t\t\tOrigin = origin ?? entity,\n\t\t\t\tDamage = damage\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ExplodeComponent.cs",
    "content": "using BurningKnight.entity.bomb;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ExplodeComponent : Component {\n\t\tpublic float Timer;\n\t\tpublic float Radius = 32f;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tTimer -= dt;\n\n\t\t\tif (Timer <= 0) {\n\t\t\t\tif (Entity is Bomb b) {\n\t\t\t\t\tb.Explode();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEntity.Done = true;\n\t\t\t\tExplosionMaker.Make(Entity, Radius);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ExtraAnimationComponent.cs",
    "content": "using Lens.graphics.animation;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class ExtraAnimationComponent : AnimationComponent {\r\n\t\tpublic ExtraAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\r\n\t\t}\r\n\r\n\t\tpublic ExtraAnimationComponent(string animationName, ColorSet set) : base(animationName, set) {\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/FollowerComponent.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class FollowerComponent : Component {\n\t\tpublic Entity Following;\n\t\tpublic Entity Follower;\n\t\tpublic float MaxDistance = 16;\n\t\tpublic float Pause = -1;\n\t\tpublic bool Paused;\n\t\tpublic float FollowSpeed = 3;\n\n\t\tpublic void DestroyAll() {\n\t\t\tif (Follower != null) {\n\t\t\t\tFollower.GetComponent<FollowerComponent>().DestroyAll();\n\t\t\t\tFollower.Done = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Remove() {\n\t\t\tif (Following != null) {\n\t\t\t\tvar f = Following.GetComponent<FollowerComponent>();\n\n\t\t\t\tf.Follower = Follower;\n\n\t\t\t\tif (Follower != null) {\n\t\t\t\t\tf.Follower.GetComponent<FollowerComponent>().Following = Following;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tFollower = null;\n\t\t\tFollowing = null;\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Follower != null && Follower.Done) {\n\t\t\t\tFollower = null;\n\t\t\t}\n\t\t\t\n\t\t\tif (Following != null) {\n\t\t\t\tif (Following.Done) {\n\t\t\t\t\tFollowing.GetComponent<FollowerComponent>().Remove();\n\t\t\t\t\tFollowing = null;\n\t\t\t\t}\n\n\t\t\t\tif (Following == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar body = Entity.GetAnyComponent<BodyComponent>();\n\n\t\t\t\tif (body == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar sp = dt * 16f;\n\t\t\t\tbody.Velocity -= body.Velocity * (sp * 0.4f);\n\n\t\t\t\tif (Paused) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Pause > 0) {\n\t\t\t\t\tPause -= dt;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = Following.DxTo(Entity);\n\t\t\t\tvar dy = Following.DyTo(Entity);\n\t\t\t\tvar d = Math.Sqrt(dx * dx + dy * dy);\n\n\t\t\t\tif (d > 1024f || !Entity.OnScreen) {\n\t\t\t\t\tAnimationUtil.Poof(Entity.Center);\n\t\t\t\t\tEntity.Center = Following.Center + Rnd.Vector(-16, 16);\n\t\t\t\t\tAnimationUtil.Poof(Entity.Center);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (d < 12) {\n\t\t\t\t\tsp *= -1;\n\t\t\t\t} else if (d < MaxDistance) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Following.TryGetComponent<RectBodyComponent>(out var rb)) {\n\t\t\t\t\tbody.Velocity = body.Velocity.Lerp(rb.Velocity, dt * FollowSpeed);\n\t\t\t\t} else if (Following.TryGetComponent<CircleBodyComponent>(out var cb)) {\n\t\t\t\t\tbody.Velocity = body.Velocity.Lerp(cb.Velocity, dt * FollowSpeed);\n\t\t\t\t} else if (Following.TryGetComponent<SensorBodyComponent>(out var sb)) {\n\t\t\t\t\tbody.Velocity = body.Velocity.Lerp(sb.Velocity, dt * FollowSpeed);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbody.Velocity -= new Vector2(dx * sp, dy * sp);\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddFollower(Entity e) {\n\t\t\tif (e == Entity) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!e.HasComponent<FollowerComponent>()) {\n\t\t\t\te.AddComponent(new FollowerComponent());\n\t\t\t}\n\n\t\t\tif (Follower != null) {\n\t\t\t\tFollower.GetComponent<FollowerComponent>().AddFollower(e);\n\t\t\t} else {\n\t\t\t\tFollower = e;\n\t\t\t\te.GetComponent<FollowerComponent>().Following = Entity;\n\t\t\t}\n\n\t\t\tif (Entity is Player) {\n\t\t\t\tvar depth = 0;\n\t\t\t\tvar entity = Entity;\n\n\t\t\t\twhile (entity != null) {\n\t\t\t\t\tentity = entity.GetComponent<FollowerComponent>().Follower;\n\n\t\t\t\t\tif (entity != null) {\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (depth >= 3) {\n\t\t\t\t\tAchievements.Unlock(\"bk:family\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/GamepadComponent.cs",
    "content": "using System;\r\nusing BurningKnight.assets.items;\r\nusing Lens.entity.component;\r\nusing Lens.entity.component.logic;\r\nusing Lens.input;\r\nusing Lens.util;\r\nusing Lens.util.camera;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class GamepadComponent : Component {\r\n\t\tpublic static GamepadData Current;\r\n\r\n\t\tprivate GamepadData controller;\r\n\r\n\t\tpublic GamepadData Controller {\r\n\t\t\tget => controller;\r\n\r\n\t\t\tset {\r\n\t\t\t\tcontroller = value;\r\n\t\t\t\tEntity.GetComponent<InputComponent>().GamepadData = value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic string GamepadId;\r\n\r\n\t\tstatic GamepadComponent() {\r\n\t\t\tCamera.OnShake += () => {\r\n\t\t\t\tif (Current == null || !Settings.Vibrate || Settings.Gamepad == null) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar am = Camera.Instance.GetComponent<ShakeComponent>().Amount;\r\n\r\n\t\t\t\tif (am < 5) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar a = Math.Max(1, am / 20f);\r\n\t\t\t\tCurrent.Rumble(a, Math.Max(0.1f, a * 0.5f));\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tUpdateState();\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\tController?.StopRumble();\r\n\t\t}\r\n\r\n\t\tprivate void UpdateState() {\r\n\t\t\tif (Settings.Gamepad != GamepadId && Settings.Gamepad != null) {\r\n\t\t\t\tfor (int i = 0; i < 4; i++) {\r\n\t\t\t\t\tvar c = GamePad.GetCapabilities(i);\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (c.IsConnected && c.Identifier == Settings.Gamepad) {\r\n\t\t\t\t\t\tController = Input.Gamepads[i];\r\n\t\t\t\t\t\tGamepadId = Settings.Gamepad;\r\n\t\t\t\t\t\tCurrent = Controller;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tLog.Info($\"Connected {GamePad.GetState(i)}\");\r\n\t\t\t\t\t\tItems.Unlock(\"bk:gamepad\");\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tSettings.Gamepad = null;\r\n\t\t\t} else if (Controller == null) {\r\n\t\t\t\tfor (int i = 0; i < 4; i++) {\r\n\t\t\t\t\tif (GamePad.GetCapabilities(i).IsConnected) {\r\n\t\t\t\t\t\tController = Input.Gamepads[i];\r\n\t\t\t\t\t\tGamepadId = GamePad.GetCapabilities(i).Identifier;\r\n\t\t\t\t\t\tCurrent = Controller;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tSettings.Gamepad = GamepadId;\r\n\t\t\t\t\t\tLog.Info($\"Connected {GamePad.GetState(i)}\");\r\n\t\t\t\t\t\tItems.Unlock(\"bk:gamepad\");\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tSettings.Gamepad = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\t\t\tUpdateState();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/HatComponent.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class HatComponent : ItemComponent {\n\t\tpublic bool DoNotRender;\n\t\tprivate bool loaded;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.GetComponent<InputComponent>().InitCallback = Setup;\n\t\t}\n\n\t\tpublic void Setup() {\n\t\t\tloaded = true;\n\t\t\t\n\t\t\tif (Item == null) {\n\t\t\t\tvar hat = GlobalSave.GetString($\"hat_{Entity.GetComponent<InputComponent>().Index}\");\n\t\t\t\tLog.Debug($\"hat_{Entity.GetComponent<InputComponent>().Index}\");\n\n\t\t\t\tif (hat != null) {\n\t\t\t\t\tSet(Items.CreateAndAdd(hat, Entity.Area), false);\n\t\t\t\t} else {\n\t\t\t\t\tSet(Items.CreateAndAdd(\"bk:no_hat\", Entity.Area), false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn item.Type == ItemType.Hat;\n\t\t}\n\t\t\n\t\tpublic override void Set(Item item, bool animate = true) {\n\t\t\tbase.Set(item, animate);\n\n\t\t\tif (loaded) {\n\t\t\t\tGlobalSave.Put($\"hat_{Entity.GetComponent<InputComponent>().Index}\", item?.Id);\n\t\t\t}\n\n\t\t\tif (item != null) {\n\t\t\t\tDoNotRender = item.Id == \"bk:no_hat\";\n\n\t\t\t\tif (Entity.HasComponent<LightComponent>()) {\n\t\t\t\t\tEntity.GetComponent<LightComponent>().Light.Color =\n\t\t\t\t\t\titem.Id == \"bk:glowing_mushroom\" ? new Color(0.05f, 0.4f, 1f, 1f) : Player.LightColor;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnItemSet(Item previous) {\n\t\t\tbase.OnItemSet(previous);\n\t\t\t\n\t\t\tforeach (var i in Entity.Area.Tagged[Tags.Item]) {\n\t\t\t\tif (i is EmeraldStand st) {\n\t\t\t\t\tst.RecalculatePrice();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/HealthComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class HealthComponent : SaveableComponent {\n\t\tprivate float health;\n\t\tpublic byte Phases;\n\n\t\tpublic bool RenderInvt;\n\t\tpublic float Health => health;\n\t\tpublic int MaxHealthCap = -1;\n\t\tpublic bool AutoKill = true;\n\t\tpublic bool SaveMaxHp;\n\t\tpublic bool PreventDamageInInvincibility = true;\n\n\t\tpublic bool HasNoHealth => health <= 0.01f;\n\t\tpublic float Percent => Health / MaxHealth;\n\n\t\tpublic bool SetHealth(float hp, Entity setter, bool mod = true, DamageType type = DamageType.Regular) {\n\t\t\tif (Math.Abs(hp - health) < 0.01f) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (hp < health) {\n\t\t\t\tif (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tvar old = health;\n\t\t\tvar h = MathUtils.Clamp(0, maxHealth, hp);\n\n\t\t\tvar e = new HealthModifiedEvent {\n\t\t\t\tAmount = h - old,\n\t\t\t\tWho = Entity,\n\t\t\t\tFrom = setter,\n\t\t\t\tType = type\n\t\t\t};\n\t\t\t\n\t\t\tif (!Send(e)) {\n\t\t\t\th = old + e.Amount;\n\n\t\t\t\tif (old > h) {\n\t\t\t\t\tInvincibilityTimer = mod ? InvincibilityTimerMax : 0.1f;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (e.Amount > 0) {\n\t\t\t\t\tEmitParticles(HealthType.Regular);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thealth = h;\n\n\t\t\t\tSend(new PostHealthModifiedEvent {\n\t\t\t\t\tAmount = e.Amount,\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tFrom = setter,\n\t\t\t\t\tType = type\n\t\t\t\t});\n\n\t\t\t\tTryToKill(setter, type);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void TryToKill(Entity e, DamageType type) {\n\t\t\tif (health <= 0.1f && (!Entity.TryGetComponent<HeartsComponent>(out var c) || c.Total == 0) && AutoKill) { \n\t\t\t\tKill(e, type);\n\t\t\t}\n\t\t}\n\n\t\tpublic bool LastModifiedHearts;\n\n\t\tpublic bool ModifyHealth(float amount, Entity setter, DamageType type = DamageType.Regular) {\n\t\t\tLastModifiedHearts = false;\n\t\t\tif (amount < 0 && Entity is Player && (Run.Depth != -2 && Run.Depth < 1)) {\n\t\t\t\tif (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0) || Health <= 0.01f) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tSend(new HealthModifiedEvent {\n\t\t\t\t\tAmount = 0,\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tFrom = null\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tInvincibilityTimer = InvincibilityTimerMax;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (amount < 0) {\n\t\t\t\tif (Entity.TryGetComponent<HeartsComponent>(out var hearts)) {\n\t\t\t\t\tif (hearts.Total > 0) {\n\t\t\t\t\t\tif (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0)) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (hearts.Hurt((int) Math.Round(amount), setter, type)) {\n\t\t\t\t\t\t\tInvincibilityTimer = InvincibilityTimerMax;\n\t\t\t\t\t\t\tTryToKill(setter, type);\n\t\t\t\t\t\t\tLastModifiedHearts = true;\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn SetHealth(health + (amount), setter, true, type);\n\t\t}\n\n\t\tprivate int maxHealth;\n\n\t\tpublic int MaxHealth {\n\t\t\tget => maxHealth;\n\t\t\tset {\n\t\t\t\tif (maxHealth == value) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar old = maxHealth;\n\t\t\t\tvar nw = Math.Max(0, value);\n\n\t\t\t\tif (MaxHealthCap > -1) {\n\t\t\t\t\tnw = Math.Min(MaxHealthCap, nw);\n\t\t\t\t}\n\n\t\t\t\tif (!Send(new MaxHealthModifiedEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tAmount = nw - old\n\t\t\t\t})) {\n\t\t\t\t\tmaxHealth = nw;\n\t\t\t\t\thealth = Math.Min(health, maxHealth);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic int InitMaxHealth {\n\t\t\tset {\n\t\t\t\tmaxHealth = value;\n\t\t\t\thealth = maxHealth;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool dead;\n\t\tpublic bool Unhittable;\n\t\tpublic float InvincibilityTimer;\n\t\tpublic float InvincibilityTimerMax = 0.5f;\n\n\t\tpublic bool Dead => dead;\n\n\t\tpublic void Kill(Entity from, DamageType damageType = DamageType.Regular) {\n\t\t\tif (Phases > 0) {\n\t\t\t\tPhases--;\n\n\t\t\t\tmaxHealth = Math.Max(1, maxHealth);\n\t\t\t\thealth = (int) Math.Floor((Entity is Player ? 0.5f : 1f) * maxHealth);\n\n\t\t\t\tSend(new RevivedEvent {\n\t\t\t\t\tWhoDamaged = from,\n\t\t\t\t\tWho = Entity\n\t\t\t\t});\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (dead) {\n\t\t\t\tEntity.Done = true;\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\thealth = 0;\n\n\t\t\tif (!Send(new DiedEvent {\n\t\t\t\tFrom = from,\n\t\t\t\tWho = Entity,\n\t\t\t\tDamageType = damageType\n\t\t\t})) {\n\t\t\t\tdead = true;\n\t\t\t\tEntity.Done = true;\t\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Needed for loading\n\t\tpublic HealthComponent() {\n\t\t\t\n\t\t}\n\n\t\tpublic void EmitParticles(HealthType type) {\n\t\t\tvar slice = \"heart\";\n\n\t\t\tswitch (type) {\n\t\t\t\tcase HealthType.Shield: {\n\t\t\t\t\tslice = \"shield\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase HealthType.Bomb: {\n\t\t\t\t\tslice = \"bomb\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"{slice}_{Rnd.Int(1, 4)}\"))));\n\t\t\t\t\t\tpart.Position = Entity.Center;\n\n\t\t\t\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t\n\t\t\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\t\t\tpart.Particle.Alpha = 0.9f;\n\t\t\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t\t\t}, i * 0.5f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemCheckEvent ev && ev.Item.Type == ItemType.Heart) {\n\t\t\t\tSend(new ItemAddedEvent {\n\t\t\t\t\tItem = ev.Item,\n\t\t\t\t\tWho = Entity\n\t\t\t\t});\n\n\t\t\t\tAudio.PlaySfx(ev.Item.Id == \"bk:shield\" ? \"item_shield\" : \"item_heart\");\n\t\t\t\t\n\t\t\t\tev.Item.Use(Entity);\n\n\t\t\t\tEngine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null\n\t\t\t\t\t? ev.Item.GetComponent<AnimatedItemGraphicsComponent>().Animation.GetFirstCurrent()\n\t\t\t\t\t: ev.Item.Region, (Player) Entity));\n\t\t\t\t\n\t\t\t\tev.Item.Done = true;\n\t\t\t\treturn true;\n\t\t\t} else if (e is ExplodedEvent b && !b.Handled) {\n\t\t\t\tItems.Unlock(\"bk:infinite_bomb\");\n\n\t\t\t\tif (Entity is Player && b.Who == Entity && Entity.GetComponent<LampComponent>().Item?.Id == \"bk:explosive_lamp\") {\n\t\t\t\t\t\n\t\t\t\t} else {\n\t\t\t\t\tModifyHealth(Entity is Player ? -2 : -b.Damage, b.Who, DamageType.Explosive);\n\n\t\t\t\t\tvar component = Entity.GetAnyComponent<BodyComponent>();\n\t\t\t\t\tcomponent?.KnockbackFrom(b.Who, 2);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic bool IsFull() {\n\t\t\treturn Math.Abs(health - MaxHealth) < 0.01f;\n\t\t}\n\n\t\tpublic bool CanPickup(Item item) {\n\t\t\tif (item.Id.Contains(\"heart\")) {\n\t\t\t\treturn !IsFull();\n\t\t\t}\n\n\t\t\tif (!Entity.TryGetComponent<HeartsComponent>(out var h)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn h.CanHaveMore;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tInvincibilityTimer = Math.Max(0, InvincibilityTimer - dt);\n\t\t}\n\t\t\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteFloat(health);\n\t\t\tstream.WriteByte(Phases);\n\n\t\t\tif (SaveMaxHp) {\n\t\t\t\tstream.WriteByte((byte) maxHealth);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\thealth = stream.ReadFloat();\n\t\t\tPhases = stream.ReadByte();\n\n\t\t\tif (SaveMaxHp) {\n\t\t\t\tmaxHealth = stream.ReadByte();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tvar hp = health;\n\t\t\t\n\t\t\tif (ImGui.InputFloat(\"Health\", ref hp)) {\n\t\t\t\thealth = hp;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.InputInt(\"Max health\", ref maxHealth);\n\n\t\t\tvar v = (int) Phases;\n\n\t\t\tif (ImGui.InputInt(\"Phases\", ref v)) {\n\t\t\t\tPhases = (byte) v;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Unhittable\", ref Unhittable);\n\n\t\t\tif (ImGui.Button(\"Heal\")) {\n\t\t\t\tModifyHealth(maxHealth - health, null);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Hurt\")) {\n\t\t\t\tModifyHealth(-1, null);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Kill\")) {\n\t\t\t\tModifyHealth(-health, null);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/InteractDialogComponent.cs",
    "content": "using BurningKnight.ui.dialog;\r\nusing Lens.entity;\r\nusing Lens.entity.component;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class InteractDialogComponent : Component {\r\n\t\tprivate string dialog;\r\n\t\tprivate bool started;\r\n\t\tprivate Entity toStart;\r\n\t\t\r\n\t\tpublic InteractDialogComponent(string d) {\r\n\t\t\tdialog = d;\r\n\t\t}\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\t\r\n\t\t\tEntity.AddComponent(new InteractableComponent(Interact) {\r\n\t\t\t\tCanInteract = e => !started\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\t// Delayed setup to avoid interaction flowing into this dialog\r\n\t\t\tif (toStart != null) {\r\n\t\t\t\tvar d = GetComponent<DialogComponent>();\r\n\r\n\t\t\t\td.OnNext += OnNext;\r\n\t\t\t\td.Start(dialog, toStart);\r\n\t\t\t\r\n\t\t\t\tstarted = true;\r\n\t\t\t\ttoStart = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void OnNext(DialogComponent d) {\r\n\t\t\tif (d.Current == null) {\r\n\t\t\t\td.OnNext -= OnNext;\r\n\t\t\t\tstarted = false;\r\n\t\t\t}\t\t\t\r\n\t\t}\r\n\r\n\t\tprivate bool Interact(Entity e) {\r\n\t\t\tif (started) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\ttoStart = e;\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/InteractableComponent.cs",
    "content": "using System;\nusing Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class InteractableComponent : Component {\n\t\tpublic Func<Entity, bool> Interact;\n\t\tpublic Func<Entity, bool> CanInteract;\n\t\tpublic Action<Entity> OnStart;\n\t\tpublic Action<Entity> OnEnd;\n\t\tpublic Func<Entity> AlterInteraction;\n\t\tpublic Entity CurrentlyInteracting;\n\t\tpublic float OutlineAlpha;\n\n\t\tpublic InteractableComponent(Func<Entity, bool> interact) {\n\t\t\tInteract = interact;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tOutlineAlpha += ((CurrentlyInteracting == null ? 0 : 1) - OutlineAlpha) * dt * 8;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/InteractableSliceComponent.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.util;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class InteractableSliceComponent : SliceComponent {\n\t\tpublic Vector2 Scale = Vector2.One;\n\t\t\n\t\tpublic InteractableSliceComponent(string image, string slice) : base(image, slice) {}\n\n\t\tpublic InteractableSliceComponent(AnimationData image, string slice) : base(image, slice) {}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar origin = new Vector2(Sprite.Width / 2, Sprite.Height);\n\t\t\tvar pos = Entity.Position + origin + Offset;\n\t\t\t\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, pos, 0, new Vector2(origin.X, 0), Scale, Graphics.ParseEffect(Flipped, !FlippedVerticaly));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\tpos -= new Vector2(0, z.Z);\n\t\t\t}\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<InteractableComponent>(out var component) && component.OutlineAlpha > 0.05f) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(component.OutlineAlpha);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(Sprite, pos + d, 0, origin, Scale);\n\t\t\t\t}\n\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tvar stopShader = false;\n\t\t\t\n\t\t\tif (Entity.TryGetComponent<HealthComponent>(out var health) && health.RenderInvt) {\n\t\t\t\tvar i = health.InvincibilityTimer;\n\n\t\t\t\tif (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\t\t\t\t\t\n\t\t\t\t\tstopShader = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(Sprite, pos, 0, origin, Scale);\n\t\t\t\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/InventoryComponent.cs",
    "content": "﻿using System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.level;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.component {\n\tpublic class InventoryComponent : SaveableComponent {\n\t\tpublic List<Item> Items = new List<Item>();\n\t\tpublic bool Busy;\n\n\t\tpublic bool Pickup(Item item, bool animate = true) {\n\t\t\tif (item == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tvar e = new ItemCheckEvent {\n\t\t\t\tItem = item,\n\t\t\t\tAnimate = animate\n\t\t\t};\n\t\t\t\n\t\t\tif (!Send(e)) {\n\t\t\t\tif (e.Blocked) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Entity is Player p && (item.Type == ItemType.Scourge || item.Type == ItemType.Artifact || item.Type == ItemType.ConsumableArtifact)) {\n\t\t\t\t\tif (item.Type == ItemType.ConsumableArtifact) {\n\t\t\t\t\t\tp.AnimateItemPickup(item, () => {\n\t\t\t\t\t\t\titem.Use(p);\n\t\t\t\t\t\t\titem.Done = true;\n\t\t\t\t\t\t}, false);\n\t\t\t\t\t} else if (animate) {\n\t\t\t\t\t\tp.AnimateItemPickup(item, () => {\n\t\t\t\t\t\t\tif (item.Type == ItemType.Scourge) {\n\t\t\t\t\t\t\t\tAchievements.Unlock(\"bk:scourged\");\n\t\t\t\t\t\t\t\tvar center = Entity.Center;\n\t\t\t\n\t\t\t\t\t\t\t\tfor (var i = 0; i < 10; i++) {\n\t\t\t\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Scourge());\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tpart.Position = center + Rnd.Vector(-4, 4);\n\t\t\t\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\t\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\t\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tAdd(item);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (item.Type == ItemType.Scourge) {\n\t\t\t\t\t\t\tAchievements.Unlock(\"bk:scourged\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\titem.Unknown = false;\n\t\t\tEntity.Area.Remove(item);\n\t\t\titem.Done = false;\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic bool Has(string id) {\n\t\t\tforeach (var i in Items) {\n\t\t\t\tif (i.Id == id) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic void Add(Item item) {\n\t\t\tif (item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (item.HasComponent<OwnerComponent>()) {\n\t\t\t\titem.RemoveComponent<OwnerComponent>();\n\t\t\t}\n\t\t\t\n\t\t\tItems.Add(item);\n\n\t\t\titem.RemoveDroppedComponents();\n\t\t\titem.AddComponent(new OwnerComponent(Entity));\n\n\t\t\titem.Use(Entity);\n\n\t\t\tif (Entity is Player && !item.Touched && item.Scourged) {\n\t\t\t\tRun.AddScourge(true);\n\t\t\t}\n\t\t\t\n\t\t\tvar e = new ItemAddedEvent {\n\t\t\t\tItem = item,\n\t\t\t\tWho = Entity\n\t\t\t};\n\t\t\t\n\t\t\tSend(e);\t\t\n\t\t\titem.Touched = true;\n\t\t}\n\n\t\tpublic void RemoveAndDispose(string id) {\n\t\t\tforeach (var i in Items) {\n\t\t\t\tif (i.Id == id) {\n\t\t\t\t\tRemove(i, true);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Remove(Item item, bool dispose = false) {\n\t\t\tItems.Remove(item);\n\n\t\t\tvar e = new ItemRemovedEvent {\n\t\t\t\tItem = item,\n\t\t\t\tOwner = Entity\n\t\t\t};\n\t\t\t\n\t\t\tSend(e);\n\t\t\titem.HandleEvent(e);\n\n\t\t\tif (dispose) {\n\t\t\t\titem.Done = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\titem.Center = Entity.Center;\n\t\t\tEntity.Area.Add(item);\n\t\t\titem.AddDroppedComponents();\n\t\t\titem.RemoveComponent<OwnerComponent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tforeach (var item in Items) {\n\t\t\t\tif (item.HandleOwnerEvent(e)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tfor (int i = Items.Count - 1; i >= 0; i--) {\n\t\t\t\tvar item = Items[i];\n\n\t\t\t\tif (item.Done) {\n\t\t\t\t\tRemove(item);\n\t\t\t\t} else {\n\t\t\t\t\tvar o = item.Owner;\n\t\t\t\t\n\t\t\t\t\tforeach (var u in item.Uses) {\n\t\t\t\t\t\tu.Update(o, item, dt);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tstream.WriteInt16((short) Items.Count);\n\t\t\t\n\t\t\tforeach (var item in Items) {\n\t\t\t\titem.Save(stream);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tvar count = stream.ReadInt16();\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar item = new Item();\n\n\t\t\t\tEntity.Area.Add(item, false);\n\t\t\t\t\n\t\t\t\titem.Load(stream);\n\t\t\t\titem.LoadedSelf = false;\n\t\t\t\titem.PostInit();\n\t\t\t\t\n\t\t\t\tPickup(item, false);\n\t\t\t\tEntity.Area.Remove(item);\n\n\t\t\t\titem.Done = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tImGui.Text($\"Total {Items.Count} items\");\n\t\t\t\n\t\t\tforeach (var item in Items) {\n\t\t\t\tImGui.BulletText(item.Id);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ItemComponent.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ItemComponent : SaveableComponent {\n\t\tpublic Item Item { get; protected set; }\n\t\tpublic bool DontSave;\n\t\tpublic bool UpdateItem;\n\n\t\tpublic bool Has(string id) {\n\t\t\treturn Item?.Id == id;\n\t\t}\n\t\t\n\t\tpublic virtual void Set(Item item, bool animate = true) {\n\t\t\tvar prev = Item;\n\t\t\t\n\t\t\tif (!animate && Item != null) {\n\t\t\t\tDrop();\n\t\t\t\tItem = null;\n\n\t#if DEBUG\n\t\t\t\tdebugItem = \"\";\n\t#endif\n\t\t\t}\n\n\t\t\tif (item == null) {\n\t\t\t\tItem = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tEntity.Area.Remove(item);\n\t\t\titem.RemoveDroppedComponents();\n\t\t\titem.AddComponent(new OwnerComponent(Entity));\n\n\t\t\tif (!animate) {\n\t\t\t\tSetupItem(item, prev);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Item != null) {\n\t\t\t\tDrop();\n\t\t\t\tItem = null;\n#if DEBUG\n\t\t\t\tdebugItem = \"\";\n#endif\n\t\t\t}\n\t\t\t\n\t\t\tif (Entity is Player p) {\n\t\t\t\tp.AnimateItemPickup(item, () => {\n\t\t\t\t\tSetupItem(item, prev);\n\t\t\t\t}, false);\n\t\t\t} else {\n\t\t\t\tSetupItem(item, prev);\n\t\t\t}\n\t\t}\n\n\t\tprivate void SetupItem(Item item, Item previous) {\n\t\t\tSend(new ItemAddedEvent {\n\t\t\t\tItem = item,\n\t\t\t\tComponent = this,\n\t\t\t\tWho = Entity,\n\t\t\t\tOld = previous\n\t\t\t});\n\t\t\t\n\t\t\tItem = item;\n\n\t\t\tif (Entity is Player && !item.Touched && item.Scourged) {\n\t\t\t\tRun.AddScourge(true);\n\t\t\t}\n\n\t\t\titem.Done = false;\n\t\t\titem.Touched = true;\n\t\t\titem.RemoveDroppedComponents();\n\t\t\n\t#if DEBUG\n\t\t\tdebugItem = item.Id;\n\t#endif\n\n\t\t\tOnItemSet(previous);\n\t\t}\n\n\t\tprotected virtual void OnItemSet(Item previous) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic Item Drop() {\n\t\t\tvar e = new ItemRemovedEvent {\n\t\t\t\tItem = Item\n\t\t\t};\n\t\t\t\n\t\t\tSend(e);\n\n\t\t\tItem.Center = Entity.Center - new Vector2(0, 4);\n\t\t\tEntity.Area.Add(Item);\n\t\t\tItem.RemoveComponent<OwnerComponent>();\n\t\t\tItem.AddDroppedComponents();\n\n\t\t\tvar item = Item;\n\t\t\tItem = null;\n\n\t#if DEBUG\n\t\t\tdebugItem = \"\";\n\t#endif\n\n\t\t\treturn item;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Item != null) {\n\t\t\t\tif (Item.Done) {\n\t\t\t\t\tItem = null;\n\n\t#if DEBUG\n\t\t\t\t\tdebugItem = \"\";\n\t#endif\n\t\t\t\t} else {\n\t\t\t\t\tItem.Center = Entity.Center;\n\n\t\t\t\t\tif (UpdateItem) {\n\t\t\t\t\t\tItem.Update(dt);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool ShouldReplace(Item item) {\n\t\t\treturn Item == null;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (Item != null && Item.HandleOwnerEvent(e)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tif (e is ItemCheckEvent ev && !ev.Handled && ShouldReplace(ev.Item)) {\n\t\t\t\tif (Entity is Player && Item != null && Item.Scourged) {\n\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\tev.Blocked = true;\n\t\t\t\t\tEntity.GetComponent<DialogComponent>().StartAndClose($\"~~{Locale.Get(\"scourged\")}~~\", 2);\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSet(ev.Item, ev.Animate);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tif (DontSave) {\n\t\t\t\tstream.WriteBoolean(false);\n\t\t\t\treturn;\n\t\t\t}\n \t\t\t\n\t\t\tstream.WriteBoolean(Item != null);\n\t\t\tItem?.Save(stream);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tif (stream.ReadBoolean()) {\n\t\t\t\tvar item = new Item();\n\n\t\t\t\tEntity.Area.Add(item, false);\n\t\t\t\t\n\t\t\t\titem.Load(stream);\n\t\t\t\titem.LoadedSelf = false;\n\t\t\t\titem.PostInit();\n\n\t\t\t\tSet(item, false);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Exchange(ItemComponent component) {\n\t\t\tvar tmp = component.Item;\n\t\t\tcomponent.Item = Item;\n\n\t\t\tif (Item != null) {\n\t\t\t\tif (!Item.HasComponent<OwnerComponent>()) {\n\t\t\t\t\tItem.AddComponent(new OwnerComponent(component.Entity));\n\t\t\t\t} else {\n\t\t\t\t\tItem.GetComponent<OwnerComponent>().Owner = component.Entity;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tItem = tmp;\n\n\t\t\tif (Item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!Item.HasComponent<OwnerComponent>()) {\n\t\t\t\tItem.AddComponent(new OwnerComponent(Entity));\n\t\t\t} else {\n\t\t\t\tItem.GetComponent<OwnerComponent>().Owner = Entity;\n\t\t\t}\n\t\t}\n\t\t\n\t\t#if DEBUG\n\t\tprivate string debugItem = \"\";\n\n\t\tpublic override void RenderDebug() {\n\t\t\tif (Item != null) {\n\t\t\t\tImGui.Text($\"Use time: {Item.UseTime}\");\n\t\t\t\tImGui.Text($\"Delay: {Item.Delay}\");\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.InputText(\"Item\", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tvar item = Items.CreateAndAdd(debugItem, Entity.Area);\n\t\t\t\tSet(item);\n\t\t\t}\n\t\t}\n\t\t#endif\n\n\t\tpublic void Cleanse() {\n\t\t\tif (Item != null && Item.Scourged) {\n\t\t\t\tItem.Scourged = false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/LockComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.component {\n\tpublic class LockComponent : Component, Subscriber {\n\t\tpublic Lock Lock;\n\t\tpublic Action<Entity> OnOpen;\n\n\t\tprivate Vector2 offset;\n\t\t\n\t\tpublic LockComponent(Entity entity, Lock l, Vector2 offset) {\n\t\t\tLock = l;\n\n\t\t\tl.Owner = entity;\n\t\t\tLock.AlwaysActive = true;\n\t\t\tLock.Move = false;\n\n\t\t\tentity.Area.Add(Lock);\n\t\t\tentity.Area.EventListener.Subscribe<LockOpenedEvent>(this);\n\n\t\t\tif (Lock.Interactable()) {\n\t\t\t\tLock.AddComponent(new RectBodyComponent(-(entity.Width - Lock.Width) / 2f - offset.X - 2, \n\t\t\t\t\t-(entity.Height - Lock.Height) / 2f - offset.Y - 2, entity.Width + 4, entity.Height + 4, BodyType.Static, true));\n\t\t\t}\n\n\t\t\tLock.Center = entity.Center + offset;\n\t\t\tthis.offset = offset;\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tLock.AddComponent(new OwnerComponent(Entity));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Lock.Done) {\n\t\t\t\tif (Engine.EditingLevel && Entity is ConditionDoor) {\n\t\t\t\t\tEntity.Done = true;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tLock.Center = Entity.Center + offset;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is LockOpenedEvent ev && ev.Lock == Lock) {\n\t\t\t\tOnOpen?.Invoke(ev.Who);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tLock.Done = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ManaComponent.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ManaComponent : SaveableComponent {\n\t\tprivate byte manaMax = 6;\n\t\tprivate byte mana = 6;\n\n\t\tpublic int ManaMax {\n\t\t\tget => manaMax;\n\t\t\tset {\n\t\t\t\tmanaMax = (byte) MathUtils.Clamp(2, 254, value);\n\t\t\t\tmana = (byte) MathUtils.Clamp(2, manaMax, mana);\n\t\t\t}\n\t\t}\n\n\t\tpublic int Mana => mana;\n\n\t\tpublic void ModifyMana(int amount) {\n\t\t\tmana = (byte) MathUtils.Clamp(0, manaMax, mana + amount);\n\t\t}\n\n\t\tpublic void SetMana(int amount) {\n\t\t\tmana = (byte) MathUtils.Clamp(0, manaMax, amount);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tmanaMax = stream.ReadByte();\n\t\t\tmana = stream.ReadByte();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte(manaMax);\n\t\t\tstream.WriteByte(mana);\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemCheckEvent ev && ev.Item.Type == ItemType.Mana) {\n\t\t\t\tSend(new ItemAddedEvent {\n\t\t\t\t\tItem = ev.Item,\n\t\t\t\t\tWho = Entity\n\t\t\t\t});\n\n\t\t\t\tAudio.PlaySfx(\"item_mana\");\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"star_{Rnd.Int(1, 4)}\"))));\n\t\t\t\t\t\tpart.Position = Entity.Center;\n\n\t\t\t\t\t\tif (Entity.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t\n\t\t\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\t\t\tpart.Particle.Alpha = 0.9f;\n\t\t\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t\t\t}, i * 0.2f);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tev.Item.Use(Entity);\n\n\t\t\t\tEngine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null\n\t\t\t\t\t? ev.Item.GetComponent<AnimatedItemGraphicsComponent>().Animation.GetFirstCurrent()\n\t\t\t\t\t: ev.Item.Region, (Player) Entity));\n\t\t\t\t\n\t\t\t\tev.Item.Done = true;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\t\n\t\tpublic override void RenderDebug() {\n\t\t\tvar v = (int) mana;\n\n\t\t\tif (ImGui.InputInt(\"Mana\", ref v)) {\n\t\t\t\tmana = (byte) v;\n\t\t\t}\n\n\t\t\tv = manaMax;\n\n\t\t\tif (ImGui.InputInt(\"Max Mana\", ref v)) {\n\t\t\t\tmanaMax = (byte) v;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"Reset\")) {\n\t\t\t\tModifyMana(manaMax - mana);\n\t\t\t}\n\t\t}\n\n\t\tpublic bool IsFull() {\n\t\t\treturn mana == manaMax;\n\t\t}\n\t\t\n\t\tpublic bool CanPickup(Item item) {\n\t\t\treturn !IsFull();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/MobAnimationComponent.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.creature.mob;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\n\nnamespace BurningKnight.entity.component {\n\tpublic class MobAnimationComponent : AnimationComponent {\n\t\tpublic MobAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\n\t\t\t\n\t\t}\n\n\t\tpublic MobAnimationComponent(string animationName, ColorSet set) : base(animationName, set) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (!shadow) {\n\t\t\t\tvar m = (Mob) Entity;\n\n\t\t\t\tif (m.HasPrefix) {\n\t\t\t\t\tvar p = m.Prefix;\n\t\t\t\t\tvar pos = Entity.Position + Offset;\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(p.GetColor());\n\n\t\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\t\tCallRender(pos + d, false);\n\t\t\t\t\t}\n\n\t\t\t\t\tShaders.End();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbase.Render(shadow);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/NoCornerBodyComponent.cs",
    "content": "﻿using BurningKnight.physics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.entity.component {\n\tpublic class NoCornerBodyComponent : BodyComponent {\n\t\tpublic NoCornerBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) {\n\t\t\tif (center) {\n\t\t\t\tx -= w / 2;\n\t\t\t\ty -= h / 2;\n\t\t\t}\n\n\t\t\tBody = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type);\n\t\t\tBody.FixedRotation = true;\n\t\t\tBody.UserData = this;\n\t\t\tBody.LinearDamping = 0;\n\n\t\t\tfloat mx = w / 3f;\n\t\t\tfloat my = h / 3f;\n\n\t\t\tFixtureFactory.AttachPolygon(new Vertices(4) {\n\t\t\t\tnew Vector2(x, y + my), new Vector2(x + mx, y), \n\t\t\t\tnew Vector2(x + w - mx, y), new Vector2(x + w, y + my),\n\t\t\t\tnew Vector2(x + w, y + h - my), new Vector2(x + w - mx, y + h),\n\t\t\t\tnew Vector2(x + mx, y + h), new Vector2(x, y + h - my)\n\t\t\t}, 1f, Body);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/OrbitGiverComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class OrbitGiverComponent : Component {\n\t\tpublic List<Entity> Orbiting = new List<Entity>();\n\t\tpublic float RadiusMultiplier = 1;\n\t\tpublic float T;\n\t\tpublic float Speed = 1;\n\n\t\tprivate float count;\n\t\tprivate Vector2 center;\n\t\t\n\t\tpublic void DestroyAll() {\n\t\t\tforeach (var o in Orbiting) {\n\t\t\t\to.Done = true;\n\t\t\t}\n\n\t\t\tOrbiting.Clear();\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tT += dt * Speed;\n\t\t\tcount += (Orbiting.Count - count) * dt * 4;\n\n\t\t\tif (Entity.DistanceTo(center) > 32f) {\n\t\t\t\tcenter = Entity.Center;\n\t\t\t} else {\n\t\t\t\tcenter += (Entity.Center - center) * (dt * 8);\n\t\t\t}\n\n\t\t\tfor (var i = Orbiting.Count - 1; i >= 0; i--) {\n\t\t\t\tvar e = Orbiting[i];\n\t\t\t\tvar component = e.GetComponent<OrbitalComponent>();\n\t\t\t\tvar d = component.Radius * RadiusMultiplier;\n\t\t\t\tvar a = i / count * Math.PI * 2 - T * 1.5f;\n\n\t\t\t\tif (e.Done) {\n\t\t\t\t\tRemoveOrbiter(e);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcomponent.CurrentAngle = (float) a;\n\t\t\t\tvar target = center + new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\n\t\t\t\tif (component.Lerp) {\n\t\t\t\t\te.Center += (target - e.Center) * (dt * 8);\n\t\t\t\t} else {\n\t\t\t\t\te.Center = target;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddOrbiter(Entity e) {\n\t\t\tif (!e.HasComponent<OrbitalComponent>()) {\n\t\t\t\te.AddComponent(new OrbitalComponent());\n\t\t\t}\n\n\t\t\t/*if (Entity is Player && Orbiting.Count == 0) {\n\t\t\t\tEntity.GetComponent<AudioEmitterComponent>().Emit(\"item_orbitals\", 0.5f, looped: true, tween: true);\n\t\t\t}\t*/\t\t\n\t\t\t\n\t\t\te.GetComponent<OrbitalComponent>().Orbiting = Entity;\n\t\t\tOrbiting.Add(e);\n\n\t\t\tif (Entity is Player && Orbiting.Count >= 3) {\n\t\t\t\tAchievements.Unlock(\"bk:star\");\n\t\t\t}\n\t\t}\n\n\t\tpublic void RemoveOrbiter(Entity e) {\n\t\t\tOrbiting.Remove(e);\n\t\t\te.GetComponent<OrbitalComponent>().Orbiting = null;\n\n\t\t\tif (Orbiting.Count == 0) {\n\t\t\t\tRemoveSound();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tforeach (var o in Orbiting) {\n\t\t\t\to.GetComponent<OrbitalComponent>().Orbiting = null;\n\t\t\t}\n\n\t\t\tRemoveSound();\n\t\t\tOrbiting.Clear();\n\t\t}\n\n\t\tprivate void RemoveSound() {\n\t\t\t/*if (Entity is Player) {\n\t\t\t\tvar c = Entity.GetComponent<AudioEmitterComponent>();\n\n\t\t\t\tforeach (var s in c.Playing) {\n\t\t\t\t\tif (s.Key == \"item_orbitals\") {\n\t\t\t\t\t\tvar e = s.Value;\n\t\t\t\t\t\t\n\t\t\t\t\t\te.Effect.IsLooped = false;\n\t\t\t\t\t\te.Effect.Pause();\n\n\t\t\t\t\t\tTween.To(0, 1f, x => e.BaseVolume = x, 0.3f);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}*/\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/OrbitalComponent.cs",
    "content": "using Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class OrbitalComponent : Component {\n\t\tpublic float Radius = 20;\n\t\tpublic bool Lerp;\n\t\tpublic Entity Orbiting;\n\t\tpublic float CurrentAngle;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/OwnerComponent.cs",
    "content": "using Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class OwnerComponent : Component {\n\t\tpublic Entity Owner;\n\n\t\tpublic OwnerComponent(Entity owner) {\n\t\t\tOwner = owner;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/PoolDropsComponent.cs",
    "content": "using BurningKnight.entity.creature;\r\nusing BurningKnight.entity.creature.drop;\r\nusing BurningKnight.entity.item;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class PoolDropsComponent : DropsComponent {\r\n\t\tpublic PoolDropsComponent(ItemPool pool, float chance, int min, int max) {\r\n\t\t\tAdd(new PoolDrop(pool, chance, min, max));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/QuackInteractionComponent.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class QuackInteractionComponent : Component {\n\t\tprivate Action<Player> action;\n\t\t\n\t\tpublic QuackInteractionComponent(Action<Player> callback) {\n\t\t\taction = callback;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.Subscribe<QuackEvent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is QuackEvent q) {\n\t\t\t\tif (q.Player.DistanceTo(Entity) <= 72f) {\n\t\t\t\t\taction(q.Player);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/RandomFrameComponent.cs",
    "content": "using System.Linq;\nusing Lens.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class RandomFrameComponent : GraphicsComponent {\n\t\tpublic TextureRegion Sprite;\n\t\tpublic Color Tint = ColorUtils.WhiteColor;\n\t\t\n\t\tpublic RandomFrameComponent(string anim) {\n\t\t\tvar list = Animations.Get(anim).Layers.First().Value;\n\t\t\tSprite = list[Rnd.Int(list.Count)].Texture;\n\t\t}\n\t\t\n\t\tpublic override void Render(bool shadow) {\n\t\t\tGraphics.Color = Tint;\n\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position + new Vector2(0, Sprite.Height), 0, Vector2.Zero, Vector2.One, Graphics.ParseEffect(Flipped, !FlippedVerticaly));\n\t\t\t} else {\n\t\t\t\tvar pos = Entity.Position;\n\n\t\t\t\tif (Entity.TryGetComponent<ZComponent>(out var c)) {\n\t\t\t\t\tpos.Y -= c.Z;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tGraphics.Render(Sprite, pos);\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/RectBodyComponent.cs",
    "content": "﻿using BurningKnight.physics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.entity.component {\n\tpublic class RectBodyComponent : BodyComponent {\n\t\tpublic RectBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) {\n\t\t\tif (center) {\n\t\t\t\tx -= w / 2;\n\t\t\t\ty -= h / 2;\n\t\t\t\tOffset = new Vector2(w / 2, h / 2);\n\t\t\t}\n\n\t\t\tBody = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type);\n\n\t\t\tBody.FixedRotation = true;\n\t\t\tBody.UserData = this;\n\t\t\tBody.LinearDamping = 0;\n\n\t\t\tif (type == BodyType.Static) {\n\t\t\t\tKnockbackModifier = 0;\n\t\t\t}\n\t\t\t\n\t\t\tFixtureFactory.AttachPolygon(new Vertices(4) {\n\t\t\t\tnew Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h)\n\t\t\t}, 1f, Body).IsSensor = sensor;\n\t\t}\n\n\t\tpublic override void Resize(float x, float y, float w, float h, bool center = false) {\n\t\t\tvar fixture = Body.FixtureList[0];\n\t\t\tvar sensor = fixture.IsSensor;\n\t\t\t\n\t\t\tBody.DestroyFixture(fixture);\n\n\t\t\tif (center) {\n\t\t\t\tx -= w / 2;\n\t\t\t\ty -= h / 2;\n\t\t\t\tOffset = new Vector2(w / 2, h / 2);\n\t\t\t}\n\t\t\t\n\t\t\tFixtureFactory.AttachPolygon(new Vertices(4) {\n\t\t\t\tnew Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h)\n\t\t\t}, 1f, Body).IsSensor = sensor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/RoomComponent.cs",
    "content": "﻿using BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing ImGuiNET;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class RoomComponent : Component {\n\t\tpublic Room Room;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tFindRoom();\n\n\t\t\tEntity.PositionChanged += FindRoom;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Room == null) {\n\t\t\t\tFindRoom();\n\t\t\t}\n\t\t}\n\n\t\tpublic void FindRoom() {\n\t\t\tvar old = Room;\n\t\t\t\n\t\t\tif (old != null) {\n\t\t\t\tif ((Entity is Boss b && b.Target != null) || old.Contains(Entity.Center)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var room in Entity.Area.Tagged[Tags.Room]) {\n\t\t\t\tif (room.Contains(Entity.Center)) {\n\t\t\t\t\tRoom = (Room) room;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (old != null && Entity is Mob && !(Entity is Boss) && !old.Contains(Entity.Center)) {\n\t\t\t\told = null;\n\t\t\t}\n\n\t\t\tif (old != Room) {\n\t\t\t\told?.Tagged.Remove(Entity);\n\t\t\t\tRoom?.Tagged.Add(Entity);\n\n\t\t\t\tSend(new RoomChangedEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tOld = old,\n\t\t\t\t\tNew = Room,\n\t\t\t\t\tWasDiscovered = Room == null || Room.Explored,\n\t\t\t\t\tJustDiscovered = Room != null && !Room.Explored\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tRoom?.Tagged.Remove(Entity);\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tImGui.Text(Room == null ? \"null\" : $\"{Room.Type}#{Room.Y}\");\n\t\t}\n\n\t\tpublic override void OnTagRemoved(int i) {\n\t\t\tbase.OnTagRemoved(i);\n\n\t\t\tif (Room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tRoom.Tagged[i].Remove(Entity);\n\t\t}\n\n\t\tpublic override void OnTagAdded(int i) {\n\t\t\tbase.OnTagAdded(i);\n\n\t\t\tif (Room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar a = Room.Tagged[i];\n\n\t\t\tif (!a.Contains(Entity)) {\n\t\t\t\ta.Add(Entity);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ScalableSliceComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ScalableSliceComponent : SliceComponent {\n\t\tpublic Vector2 Scale = Vector2.One;\n\t\tpublic Vector2 Origin;\n\t\t\n\t\tpublic ScalableSliceComponent(TextureRegion region) : base(\"\", null) {\n\t\t\tSprite = region;\n\t\t}\n\t\t\n\t\tpublic ScalableSliceComponent(string image, string slice) : base(image, slice) {\n\t\t\t\n\t\t}\n\n\t\tpublic ScalableSliceComponent(AnimationData image, string slice) : base(image, slice) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Set(TextureRegion region) {\n\t\t\tbase.Set(region);\n\t\t\tOrigin = Sprite.Center;\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position + Origin + new Vector2(0, ShadowZ + Sprite.Height), Angle, Origin, Scale, Graphics.ParseEffect(Flipped, ShadowZ > 0 ? FlippedVerticaly : !FlippedVerticaly));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar stopShader = false;\n\n\t\t\tif (Entity.TryGetComponent<HealthComponent>(out var health) && health.RenderInvt) {\n\t\t\t\tvar i = health.InvincibilityTimer;\n\n\t\t\t\tif (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\t\t\t\t\t\n\t\t\t\t\tstopShader = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(Sprite, Entity.Position + Origin, Angle, Origin, Scale);\n\t\t\t\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Animate(Action callback = null) {\n\t\t\tTween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f);\n\t\t\tTween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\tTween.To(1, Scale.X, x => Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1, Scale.Y, x => Scale.Y = x, 0.4f);\n\n\t\t\t\tcallback?.Invoke();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/SensorBodyComponent.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.component {\n\tpublic class SensorBodyComponent : RectBodyComponent {\n\t\tpublic SensorBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool center = false) : base(x, y, w, h, type, true, center) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void KnockbackFrom(float a, float force = 1, float rnd = 0) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ShadowComponent.cs",
    "content": "using System;\nusing Lens.entity.component;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ShadowComponent : Component {\n\t\tpublic Action Callback;\n\t\t\n\t\tpublic ShadowComponent(Action render = null) {\n\t\t\tCallback = render ?? (() => {\n\t\t\t\tEntity.GraphicsComponent.Render(true);\n\t\t\t});\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.AddTag(Tags.HasShadow);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tEntity.RemoveTag(Tags.HasShadow);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/SimpleZAnimationComponent.cs",
    "content": "using Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class SimpleZAnimationComponent : AnimationComponent {\n\t\tpublic SimpleZAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\n\t\t}\n\n\t\tprotected override void CallRender(Vector2 pos, bool shadow) {\n\t\t\tvar component = GetComponent<ZComponent>();\n\n\t\t\tvar region = Animation.GetCurrentTexture();\n\t\t\tvar origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height);\n\n\t\t\tif (!shadow) {\n\t\t\t\tpos.Y -= component.Z;\n\t\t\t}\n\n\t\t\tGraphics.Render(region, pos + origin, shadow ^ Flipped ? -Angle : Angle, origin, Scale,\n\t\t\t\tGraphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/SliceComponent.cs",
    "content": "﻿using BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing Lens.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class SliceComponent : GraphicsComponent {\n\t\tpublic TextureRegion Sprite;\n\t\tpublic int ShadowZ;\n\t\tpublic float Angle;\n\t\t\n\t\tpublic SliceComponent(string image, string slice) {\n\t\t\tSet(image, slice);\n\t\t}\n\n\t\tpublic SliceComponent(AnimationData image, string slice) {\n\t\t\tSet(image.GetSlice(slice));\n\t\t}\n\n\t\tpublic SliceComponent(TextureRegion region) {\n\t\t\tSet(region);\n\t\t}\n\n\t\tpublic void Set(string image, string slice) {\n\t\t\tif (image == null || slice == null) {\n\t\t\t\tSprite = Textures.Missing;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tSet(Animations.Get(image).GetSlice(slice));\n\t\t}\n\t\t\n\t\tpublic virtual void Set(TextureRegion region) {\n\t\t\tSprite = region;\n\t\t}\n\n\t\tpublic void AddShadow() {\n\t\t\tEntity.AddComponent(new ShadowComponent(RenderShadow));\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tRender(true);\n\t\t}\n\n\t\tpublic void SetOwnerSize() {\n\t\t\tEntity.Width = Sprite.Width;\n\t\t\tEntity.Height = Sprite.Height;\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar o = Sprite.Center;\n\t\t\t\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position + new Vector2(0, (int) Sprite.Height + ShadowZ) + o, Angle, o, Vector2.One, Graphics.ParseEffect(Flipped, ShadowZ > 0 ? FlippedVerticaly : !FlippedVerticaly));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar stopShader = false;\n\n\t\t\tif (Entity.TryGetComponent<HealthComponent>(out var health) && health.RenderInvt) {\n\t\t\t\tvar i = health.InvincibilityTimer;\n\n\t\t\t\tif (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\t\t\t\t\t\n\t\t\t\t\tstopShader = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(Sprite, Entity.Position + o, Angle, o);\n\t\t\t\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/SparkEmitterComponent.cs",
    "content": "using BurningKnight.assets.particle;\nusing Lens.entity.component;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class SparkEmitterComponent : Component {\n\t\tprivate readonly float delay;\n\t\tprivate readonly float chance;\n\t\t\n\t\tprivate float sinceLast;\n\t\t\n\t\tpublic SparkEmitterComponent(float delay, float chance) {\n\t\t\tthis.delay = delay;\n\t\t\tthis.chance = chance;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tsinceLast += dt;\n\n\t\t\tif (sinceLast > delay) {\n\t\t\t\tsinceLast = 0;\n\n\t\t\t\tif (Rnd.Chance(chance)) {\n\t\t\t\t\tvar p = Particles.Wrap(Particles.Spark(), Entity.Area, new Vector2(Rnd.Float(Entity.Width) + Entity.X,\n\t\t\t\t\t\tRnd.Float(Entity.Height) + Entity.Y));\n\n\t\t\t\t\tp.Depth = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/StatsComponent.cs",
    "content": "using System;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item.util;\r\nusing BurningKnight.level.rooms;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.entity.component;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class StatsComponent : SaveableComponent {\r\n\t\tprivate float speed = 1;\r\n\t\tprivate float damage = 1;\r\n\t\tprivate float fireRate = 1;\r\n\t\tprivate float rangedRate = 1;\r\n\t\tprivate float accuracy = 1;\r\n\t\tprivate float range = 1;\r\n\t\tprivate float knockback = 1;\r\n\r\n\t\tpublic float DMChance;\r\n\t\tpublic float GrannyChance;\r\n\t\tpublic bool SawDeal;\r\n\t\tpublic bool TookDeal;\r\n\t\tpublic bool TookDamageInRoom;\r\n\t\tpublic bool TookDamageInLastRoom;\r\n\t\tpublic bool TookDamageOnLevel;\r\n\t\tpublic bool UsedWeaponInRoom;\r\n\r\n\t\tpublic int HeartsPayed;\r\n\r\n\t\tpublic float Speed {\r\n\t\t\tget => speed;\r\n\t\t\tset => speed = MathUtils.Clamp(0.02f, 3f, value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic float Damage {\r\n\t\t\tget => damage;\r\n\t\t\tset => damage = MathUtils.Clamp(0.1f, 100f, value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic float FireRate {\r\n\t\t\tget => fireRate;\r\n\t\t\tset => fireRate = MathUtils.Clamp(0.1f, 3f, value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic float RangedRate {\r\n\t\t\tget => rangedRate;\r\n\t\t\tset => rangedRate = MathUtils.Clamp(0.1f, 3f, value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic float Accuracy {\r\n\t\t\tget => accuracy;\r\n\t\t\tset => accuracy = MathUtils.Clamp(0.1f, 10f, value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic float Range {\r\n\t\t\tget => range;\r\n\t\t\tset => range = MathUtils.Clamp(0.1f, 3f, value);\r\n\t\t}\r\n\r\n\t\tpublic float Knockback {\r\n\t\t\tget => knockback;\r\n\t\t\tset => knockback = MathUtils.Clamp(0f, 4f, value);\r\n\t\t}\r\n\r\n\t\tpublic override void RenderDebug() {\r\n\t\t\tbase.RenderDebug();\r\n\r\n\t\t\tImGui.InputFloat(\"Speed\", ref speed);\r\n\t\t\tImGui.InputFloat(\"Damage\", ref damage);\r\n\t\t\tImGui.InputFloat(\"Fire Rate\", ref fireRate);\r\n\t\t\tImGui.InputFloat(\"Ranged Rate\", ref rangedRate);\r\n\t\t\tImGui.InputFloat(\"Accuracy\", ref accuracy);\r\n\t\t\tImGui.InputFloat(\"Range\", ref range);\r\n\t\t\tImGui.InputFloat(\"Knockback\", ref knockback);\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tImGui.InputFloat(\"DM Chance\", ref DMChance);\r\n\t\t\tImGui.InputFloat(\"Granny Chance\", ref GrannyChance);\r\n\r\n\t\t\tImGui.Checkbox(\"Saw Deal\", ref SawDeal);\r\n\t\t\tImGui.Checkbox(\"Took Deal\", ref TookDeal);\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tImGui.Checkbox(\"Took Damage in Room\", ref TookDamageInRoom);\r\n\t\t\tImGui.Checkbox(\"Took Damage on Level\", ref TookDamageOnLevel);\r\n\t\t\tImGui.InputInt(\"Containers payed\", ref HeartsPayed);\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\t\r\n\t\t\tstream.WriteBoolean(SawDeal);\r\n\t\t\tstream.WriteBoolean(TookDeal);\r\n\t\t\tstream.WriteBoolean(TookDamageInRoom);\r\n\t\t\tstream.WriteBoolean(TookDamageOnLevel);\r\n\t\t\tstream.WriteInt32(HeartsPayed);\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\r\n\t\t\tSawDeal = stream.ReadBoolean();\r\n\t\t\tTookDeal = stream.ReadBoolean();\r\n\t\t\tTookDamageInRoom = stream.ReadBoolean();\r\n\t\t\tTookDamageOnLevel = stream.ReadBoolean();\r\n\t\t\tHeartsPayed = stream.ReadInt32();\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is PlayerHurtEvent) {\r\n\t\t\t\tif (!TookDamageOnLevel) {\r\n\t\t\t\t\tDMChance -= 0.5f;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar rm = Entity.GetComponent<RoomComponent>().Room;\r\n\t\t\t\t\r\n\t\t\t\tif (rm != null && !TookDamageInRoom && rm.Type == RoomType.Boss) {\r\n\t\t\t\t\tDMChance -= 0.25f;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tTookDamageInRoom = true;\r\n\t\t\t\tTookDamageOnLevel = true;\r\n\t\t\t} else if (e is RoomChangedEvent rce) {\r\n\t\t\t\tif (rce.JustDiscovered) {\r\n\t\t\t\t\tTookDamageInLastRoom = TookDamageInRoom;\r\n\t\t\t\t\tTookDamageInRoom = false;\r\n\t\t\t\t\tUsedWeaponInRoom = false;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is NewLevelStartedEvent) {\r\n\t\t\t\tTookDamageOnLevel = false;\r\n\t\t\t\tTookDamageInRoom = false;\r\n\t\t\t\tTookDamageInLastRoom = false;\r\n\r\n\t\t\t\tGrannyChance = 0.5f;\r\n\t\t\t\tDMChance = 1f;\r\n\t\t\t} else if (e is ProjectileCreatedEvent pce) {\r\n\t\t\t\tvar projectile = pce.Projectile;\r\n\t\t\t\t\r\n\t\t\t\tprojectile.Damage *= Damage;\r\n\r\n\t\t\t\t// Can turn out to be a disaster\r\n\t\t\t\tif (projectile.T > 0) {\r\n\t\t\t\t\tprojectile.T *= Range;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is MeleeArc.CreatedEvent mace) {\r\n\t\t\t\tvar arc = mace.Arc;\r\n\r\n\t\t\t\tarc.Damage *= Damage;\r\n\t\t\t\tarc.Width *= Math.Max(1, Range);\r\n\t\t\t} else if (e is RoomClearedEvent rr) {\r\n\t\t\t\tif (!UsedWeaponInRoom && rr.Room != null) {\r\n\t\t\t\t\tvar t = rr.Room.Type;\r\n\r\n\t\t\t\t\tif (t == RoomType.Regular || t == RoomType.Challenge || t == RoomType.Boss) {\r\n\t\t\t\t\t\tAchievements.Unlock(\"bk:white_flag\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/SupportableComponent.cs",
    "content": "using System.Collections.Generic;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.room.controllable;\r\nusing Lens.entity;\r\nusing Lens.entity.component;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class SupportableComponent : Component {\r\n\t\tpublic List<Support> Supports = new List<Support>();\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\tSupports.Clear();\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Support ss) {\r\n\t\t\t\tif (!Supports.Contains(ss) && (!(Entity is Player) || !(cse.Body is SensorBodyComponent))) {\r\n\t\t\t\t\tSupports.Add(ss);\r\n\t\t\t\t\tss.Supporting.Add(Entity);\r\n\r\n\t\t\t\t\tss.HandleEvent(new Support.StartedSupportingEvent {\r\n\t\t\t\t\t\tSupport = ss,\r\n\t\t\t\t\t\tEntity = Entity\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t} else if (e is CollisionEndedEvent cee && cee.Entity is Support se) {\r\n\t\t\t\tif (Supports.Contains(se)) {\r\n\t\t\t\t\tSupports.Remove(se);\r\n\t\t\t\t\tse.Supporting.Remove(Entity);\r\n\r\n\t\t\t\t\tse.HandleEvent(new Support.EndedSupportingEvent {\r\n\t\t\t\t\t\tSupport = se,\r\n\t\t\t\t\t\tEntity = Entity\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\t\t\t\r\n\t\t\tforeach (var s in Supports) {\r\n\t\t\t\ts.Apply(Entity, dt);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic bool HasAnotherSupportBesides(Support support) {\r\n\t\t\tforeach (var s in Supports) {\r\n\t\t\t\tif (s != support) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/TextGraphicsComponent.cs",
    "content": "using BurningKnight.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class TextGraphicsComponent : GraphicsComponent {\n\t\tprivate string text;\n\t\tpublic Color Color = Color.White;\n\t\tpublic float Scale = 1;\n\t\tpublic float Angle;\n\n\t\tpublic byte A {\n\t\t\tget => Color.A;\n\t\t\tset => Color.A = value;\n\t\t}\n\t\t\n\t\tpublic TextGraphicsComponent(string str) {\n\t\t\ttext = str;\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Print(text, Font.Medium, Entity.Position, 0, Vector2.Zero, Vector2.One, Graphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar origin = new Vector2(Entity.Width / 2f, Entity.Height / 2);\n\t\t\t\n\t\t\tGraphics.Color = Color;\n\t\t\tGraphics.Print(text, Font.Medium, Entity.Position + origin, Angle, origin, new Vector2(Scale));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/TileInteractionComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class TileInteractionComponent : Component {\n\t\tpublic bool[] LastTouching;\n\t\tpublic bool[] Touching;\n\n\t\tpublic bool[] LastFlags;\n\t\tpublic bool[] Flags;\n\n\t\tpublic bool HasNoSupport;\n\t\tpublic bool HadNoSupport;\n\t\tpublic bool HasNoTileSupport;\n\t\tpublic Vector2 LastSupportedPosition;\n\n\t\tpublic TileInteractionComponent() {\n\t\t\tTouching = new bool[(int) Tile.Total];\n\t\t\tLastTouching = new bool[(int) Tile.Total];\n\t\t\t\n\t\t\tLastFlags = new bool[8];\n\t\t\tFlags = new bool[8];\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Entity is Creature c && c.InAir()) {\n\t\t\t\tHasNoSupport = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int i = 0; i < Touching.Length; i++) {\n\t\t\t\tLastTouching[i] = Touching[i];\n\t\t\t\tTouching[i] = false;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int i = 0; i < Flags.Length; i++) {\n\t\t\t\tLastFlags[i] = Flags[i];\n\t\t\t\tFlags[i] = false;\n\t\t\t}\n\n\t\t\tHadNoSupport = HasNoSupport;\n\t\t\tHasNoTileSupport = true;\n\n\t\t\tvar h = Entity.TryGetComponent<SupportableComponent>(out var sp);\n\t\t\t\n\t\t\tHasNoSupport = !h || sp.Supports.Count == 0;\n\t\t\t\n\t\t\tif (h && sp.Supports.Count > 0) {\n\t\t\t\tLastSupportedPosition = Entity.Position;\n\t\t\t}\n\t\t\t\n\t\t\tApplyForAllTouching(InspectTile);\n\n\t\t\tfor (int i = 0; i < Touching.Length; i++) {\n\t\t\t\tCheckTile(i);\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < Flags.Length; i++) {\n\t\t\t\tCheckFlag(i);\n\t\t\t}\n\n\t\t\tCheckSupport();\n\t\t}\n\n\t\tprivate void InspectTile(int index, int x, int y) {\n\t\t\tvar level = Run.Level;\n\n\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar tile = level.Tiles[index];\n\t\t\tvar liquid = level.Liquid[index];\n\n\t\t\tif (tile > 0) {\n\t\t\t\tTouching[tile] = true;\n\n\t\t\t\tif (HasNoTileSupport) {\n\t\t\t\t\tvar t = (Tile) tile;\n\n\t\t\t\t\tif (t != Tile.Chasm && (!t.IsWall() || (level.IsInside(x, y + 1) && !level.Get(x, y + 1).IsWall() && level.Get(x, y + 1) != Tile.Chasm))) {\n\t\t\t\t\t\tHasNoSupport = false;\n\t\t\t\t\t\tHasNoTileSupport = false;\n\t\t\t\t\t\tLastSupportedPosition = new Vector2((int) x * 16, (int) y * 16);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\t\n\t\t\tif (liquid > 0) {\n\t\t\t\tTouching[liquid] = true;\n\t\t\t}\n\n\t\t\tif (level.CheckFlag(index, Flag.Burning)) {\n\t\t\t\tFlags[Flag.Burning] = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic void ApplyForAllTouching(Action<int, int, int> action) {\n\t\t\tvar ex = Entity.X + Entity.Width / 6f;\n\t\t\tvar ey = Entity.Y + Entity.Height / 2f;\n\t\t\tvar ew = Entity.Width / 6f * 4f;\n\t\t\tvar eh = Entity.Height / 2f;\n\t\t\tvar rect = new Rect((int) ex, (int) ey, (int) (ex + ew), (int) (ey + eh));\n\n\t\t\tvar startX = (int) Math.Floor(ex / 16f);\n\t\t\tvar startY = (int) Math.Floor(ey / 16f);\n\t\t\tvar endX = (int) Math.Floor((ex + ew) / 16f);\n\t\t\tvar endY = (int) Math.Floor((ey + eh) / 16f);\n\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tfor (int x = startX; x <= endX; x++) {\n\t\t\t\tfor (int y = startY; y <= endY; y++) {\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tif (!level.IsInside(index)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (new Rect(x * 16, y * 16, x * 16 + 16, y * 16 + 16).Intersects(rect)) {\n\t\t\t\t\t\taction(index, x, y);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void CheckSupport() {\n\t\t\tif (!HadNoSupport && HasNoSupport && !Engine.EditingLevel) {\n\t\t\t\tif (Send(new LostSupportEvent {\n\t\t\t\t\tWho = Entity\n\t\t\t\t})) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tEntity.Position = LastSupportedPosition;\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\n\t\t\t\t\tpart.Position = Entity.Center;\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\tEntity.Area.Add(part);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void CheckTile(int tile) {\n\t\t\tif (!LastTouching[tile] && Touching[tile]) {\n\t\t\t\tSend(new TileCollisionStartEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tTile = (Tile) tile\n\t\t\t\t});\n\t\t\t} else if (LastTouching[tile] && !Touching[tile]) {\n\t\t\t\tSend(new TileCollisionEndEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tTile = (Tile) tile\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void CheckFlag(int flag) {\n\t\t\tif (!LastFlags[flag] && Flags[flag]) {\n\t\t\t\tSend(new FlagCollisionStartEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tFlag = flag\n\t\t\t\t});\n\t\t\t} else if (LastFlags[flag] && !Flags[flag]) {\n\t\t\t\tSend(new FlagCollisionEndEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tFlag = flag\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/WallAnimationComponent.cs",
    "content": "using System;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class WallAnimationComponent : MobAnimationComponent {\n\t\tpublic float WallAngle;\n\t\t\n\t\tpublic WallAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\n\t\t}\n\n\t\tpublic WallAnimationComponent(string animationName, ColorSet set) : base(animationName, set) {\n\t\t}\n\n\t\tprotected override void CallRender(Vector2 pos, bool shadow) {\n\t\t\tvar region = Animation.GetCurrentTexture();\n\t\t\tvar origin = new Vector2(0, region.Height / 2);\n\t\t\tvar w = region.Width / 2f;\n\t\t\t\n\t\t\tGraphics.Render(region, pos + origin + new Vector2((float) (WallAngle / Math.PI * w * 2) - (WallAngle > Math.PI * 1.2f ? w * 2 : 0),  (float) -Math.Sin(WallAngle) * w), WallAngle, origin, Scale);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ZAnimationComponent.cs",
    "content": "using Lens.graphics;\r\nusing Lens.graphics.animation;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.component {\r\n\tpublic class ZAnimationComponent : MobAnimationComponent {\r\n\t\tpublic Vector2 Scale = Vector2.One;\r\n\t\t\r\n\t\tpublic ZAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\r\n\t\t}\r\n\r\n\t\tpublic ZAnimationComponent(string animationName, ColorSet set) : base(animationName, set) {\r\n\t\t}\r\n\r\n\t\tprotected override void CallRender(Vector2 pos, bool shadow) {\r\n\t\t\tvar component = GetComponent<ZComponent>();\r\n\t\t\t\r\n\t\t\tvar region = Animation.GetCurrentTexture();\r\n\t\t\tvar origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height);\r\n\r\n\t\t\tif (!shadow) {\r\n\t\t\t\tpos.Y -= component.Z;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tGraphics.Render(region, pos + origin, shadow ^ Flipped ? -Angle : Angle, origin, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/component/ZComponent.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing Lens.entity.component;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ZComponent : Component {\n\t\tpublic float Z;\n\t\tpublic float ZVelocity;\n\t\tpublic bool Float;\n\t\tpublic float Gravity = 1;\n\n\t\tprivate float t;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tt = Rnd.Float(5f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Float) {\n\t\t\t\tt += dt;\n\t\t\t\tZ = 2.5f + (float) Math.Sin(t * 5f) * 1.5f;\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tZ += ZVelocity * dt * 20 * (Entity.TryGetComponent<BuffsComponent>(out var buffs) && buffs.Has<SlowBuff>() ? 0.5f : 1f);\n\t\t\tZVelocity -= dt * 10 * Gravity;\n\n\t\t\tif (Z <= 0) {\n\t\t\t\tZ = 0;\n\t\t\t\tZVelocity = 0;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/component/ZSliceComponent.cs",
    "content": "using System;\nusing Lens.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.component {\n\tpublic class ZSliceComponent : GraphicsComponent {\n\t\tpublic TextureRegion Sprite;\n\t\tpublic Vector2 Scale = Vector2.One;\n\t\tpublic Vector2 Origin;\n\t\t\n\t\tpublic ZSliceComponent(TextureRegion region) {\n\t\t\tSprite = region;\n\t\t}\n\t\t\n\t\tpublic ZSliceComponent(string image, string slice) {\n\t\t\tSprite = Animations.Get(image).GetSlice(slice);\n\t\t}\n\n\t\tpublic ZSliceComponent(AnimationData image, string slice) {\n\t\t\tSprite = image.GetSlice(slice);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position + new Vector2(0, Sprite.Height), 0, Origin, Scale, Graphics.ParseEffect(Flipped, !FlippedVerticaly));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(Sprite, Entity.Position - new Vector2(0, Entity.GetComponent<ZComponent>().Z), 0, Origin, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t}\n\t\t\n\t\tpublic void Animate(Action callback = null) {\n\t\t\tTween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f);\n\t\t\tTween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\tTween.To(1, Scale.X, x => Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1, Scale.Y, x => Scale.Y = x, 0.4f);\n\n\t\t\t\tcallback?.Invoke();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/Creature.cs",
    "content": "using System;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature {\n\tpublic class Creature : SaveableEntity, CollisionFilterEntity, PlaceableEntity {\n\t\tpublic bool Flying;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddComponent(new BuffsComponent());\n\n\t\t\tAddComponent(new HealthComponent {\n\t\t\t\tRenderInvt = true,\n\t\t\t\tAutoKill = false\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new DropsComponent());\n\t\t\tAddComponent(new TileInteractionComponent());\n\t\t\tAddComponent(new SupportableComponent());\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\t\n\t\t\tAddDrops(new SingleDrop(\"bk:heart\", /*0.0015f*/ 0.0001f));\n\t\t\tAddDrops(new SingleDrop(\"bk:half_heart\", /*0.003f*/ 0.0002f));\n\t\t\tAddDrops(new SingleDrop(\"bk:shield\", 0.001f));\n\t\t\tAddDrops(new SingleDrop(\"bk:bomb\", 0.01f));\n\t\t\tAddDrops(new SingleDrop(\"bk:key\", 0.01f));\n\t\t}\n\n\t\tprotected virtual void Become<T>() {\n\t\t\tGetComponent<StateComponent>().Become<T>();\n\t\t}\n\t\t\n\t\tpublic virtual void Kill(Entity w, DamageType type = DamageType.Regular) {\n\t\t\tGetComponent<HealthComponent>().Kill(w, type);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is PostHealthModifiedEvent ev && ev.Amount < 0) {\n\t\t\t\tif (HasNoHealth(ev)) {\n\t\t\t\t\tKill(ev.From, ev.Type);\n\t\t\t\t} else if (!ev.PressedForBomb) {\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(GetHurtSfx());\n\t\t\t\t}\n\n\t\t\t\tif (ev.From != null && !ev.Handled && !ev.PressedForBomb) {\n\t\t\t\t\tvar b = GetAnyComponent<BodyComponent>();\n\n\t\t\t\t\tif (b != null && ev.Amount < 0) {\n\t\t\t\t\t\tb.KnockbackFrom(ev.From);\n\n\t\t\t\t\t\tif (Settings.Blood && !Settings.LowQuality) {\n\t\t\t\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\t\t\t\tvar p = Particles.Wrap(new Particle(Controllers.Blood, Particles.BloodRenderer), Area,\n\t\t\t\t\t\t\t\t\tCenter + Rnd.Vector(-4, 4));\n\n\t\t\t\t\t\t\t\tvar a = ev.From.AngleTo(this);\n\n\t\t\t\t\t\t\t\tp.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.5f, 0.5f), Rnd.Float(80, 120));\n\t\t\t\t\t\t\t\tp.Particle.Velocity.Y -= 8f;\n\t\t\t\t\t\t\t\tp.Particle.Velocity += b.Velocity * 0.5f;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent d) {\n\t\t\t\tif (!e.Handled) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (HandleDeath(d)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\tLog.Error(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is LostSupportEvent) {\n\t\t\t\tif (!(this is Player)) {\n\t\t\t\t\tDone = true;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else if (e is TileCollisionStartEvent tce) {\n\t\t\t\tif (tce.Tile == Tile.Lava) {\n\t\t\t\t\tif (GetComponent<HealthComponent>().ModifyHealth(-1, Run.Level)) {\n\t\t\t\t\t\t// GetComponent<BuffsComponent>().Add(BurningBuff.Id);\n\n\t\t\t\t\t\tvar set = false;\n\t\t\t\t\t\tvar center = Center;\n\t\t\t\t\t\tvar count = 0;\n\n\t\t\t\t\t\tGetComponent<TileInteractionComponent>().ApplyForAllTouching((i, x, y) => {\n\t\t\t\t\t\t\tif (Run.Level.Get(x, y, true) == Tile.Lava) {\n\t\t\t\t\t\t\t\tvar v = new Vector2(x * 16, y * 16);\n\t\t\t\t\t\t\t\tcount++;\n\n\t\t\t\t\t\t\t\tif (!set) {\n\t\t\t\t\t\t\t\t\tset = true;\n\t\t\t\t\t\t\t\t\tcenter = v;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcenter += v;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tGetAnyComponent<BodyComponent>()?.KnockbackFrom(center / count, 1.5f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected virtual bool HandleDeath(DiedEvent d) {\n\t\t\tAnimateDeath(d);\n\t\t\t\n\t\t\tif (d.From is Creature c) {\n\t\t\t\td.From.HandleEvent(new KilledEvent {\n\t\t\t\t\tWho = this,\n\t\t\t\t\tKilledBy = c\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic virtual void AnimateDeath(DiedEvent d) {\n\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomized(GetDeadSfx(), sz: 0.2f);\n\n\t\t\tif (!GetComponent<TileInteractionComponent>().HasNoSupport) {\n\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\t\t\t}\n\n\t\t\tDone = true;\n\t\t\t\n\t\t\tfor (var i = 0; i < 5; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Ash());\n\n\t\t\t\tpart.Position = Center;\n\t\t\t\tpart.Particle.Scale = Rnd.Float(1.5f, 2f);\n\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(20, 30) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(40, 66));\n\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\tpart.Depth = 1;\n\t\t\t}\n\n\t\t\tif (Settings.Blood) {\n\t\t\t\tfor (var i = 0; i < Rnd.Int(2, 8); i++) {\n\t\t\t\t\tArea.Add(new SplashParticle {\n\t\t\t\t\t\tPosition = Center - new Vector2(2.5f),\n\t\t\t\t\t\tColor = GetBloodColor()\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual TextureRegion GetDeathFrame() {\n\t\t\treturn GetAnyComponent<AnimationComponent>()?.Animation.GetFrame(\"dead\", 0);\n\t\t}\n\n\t\tprotected virtual void CreateGore(DiedEvent d) {\n\t\t\tEngine.Instance.Freeze = 0.5f;\n\t\t\tCamera.Instance.ShakeMax(5);\n\t\t\t\n\n\t\t\tif (!Settings.Blood) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar gore = new Gore();\n\t\t\tvar r = GetDeathFrame();\n\n\t\t\tif (r == null) {\n\t\t\t\tLog.Error($\"Failed to find dead frame for {GetType().Name}\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tArea.Add(gore);\n\t\t\t\n\t\t\tgore.Position = Position;\n\t\t\tgore.AddComponent(new ZSliceComponent(r));\n\n\t\t\tgore.Width = r.Width;\n\t\t\tgore.Height = r.Height;\n\n\t\t\tvar b = new RectBodyComponent(0, 0, gore.Width, gore.Height);\n\t\t\t\n\t\t\tgore.AddComponent(b);\n\t\t\t\n\t\t\tb.Body.LinearDamping = 2f;\n\t\t\tb.Body.Restitution = 1;\n\t\t\tb.Body.Friction = 0;\n\n\t\t\tif (d != null) {\n\t\t\t\tvar v = MathUtils.CreateVector(d.From is Player ? AngleTo(d.From) - Math.PI : Rnd.AnglePI(), 64);\n\n\t\t\t\tb.Body.LinearVelocity = v;\n\n\t\t\t\tif (v.X > 0) {\n\t\t\t\t\tgore.GetComponent<ZSliceComponent>().Flipped = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected void AddDrops(params Drop[] drops) {\n\t\t\tGetComponent<DropsComponent>().Add(drops);\n\t\t}\n\n\t\tpublic virtual bool HasNoHealth(HealthModifiedEvent e = null) {\n\t\t\treturn GetComponent<HealthComponent>().HasNoHealth || Math.Abs(GetComponent<HealthComponent>().Health - (-e?.Amount ?? 0)) < 0.01f;\n\t\t}\n\n\t\tpublic virtual bool HasNoHealth(PostHealthModifiedEvent e = null) {\n\t\t\treturn GetComponent<HealthComponent>().HasNoHealth;\n\t\t}\n\t\t\n\t\tpublic virtual bool InAir() {\n\t\t\treturn Flying;\n\t\t}\n\n\t\tpublic virtual bool IgnoresProjectiles() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic virtual bool ShouldCollideWithDestroyableInAir() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\treturn !((entity is Creature && !(entity is DungeonShopNpc || entity is Mimic)) || (InAir() && (entity is Chasm || entity is Item || entity is Bomb || (!ShouldCollideWithDestroyableInAir() && entity is HalfWall))));\n\t\t}\n\n\t\tpublic virtual bool IsFriendly() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual void RenderShadow() {\n\t\t\tGraphicsComponent?.Render(true);\n\t\t}\n\n\t\tprotected virtual Color GetBloodColor() {\n\t\t\treturn Color.Red;\n\t\t}\n\n\t\tprotected virtual string GetHurtSfx() {\n\t\t\treturn $\"hurt{Rnd.Int(1, 3)}\";\n\t\t}\n\n\t\tprotected virtual string GetDeadSfx() {\n\t\t\treturn $\"dead{Rnd.Int(1, 4)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/Decoy.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\n\nnamespace BurningKnight.entity.creature {\n\tpublic class Decoy : Creature {\n\t\tpublic Action OnDeath;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 11;\n\t\t\tHeight = 10;\n\t\t\t\n\t\t\tAddTag(Tags.PlayerTarget);\n\t\t\tRemoveTag(Tags.LevelSave);\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, 11, 10));\n\t\t\tAddComponent(new RectBodyComponent(0, 9, 11, 1));\n\n\t\t\tGetComponent<RectBodyComponent>().KnockbackModifier = 0.1f;\n\t\t\t\n\t\t\tAddComponent(new SliceComponent(\"items\", \"bk:decoy\"));\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tvar h = GetComponent<HealthComponent>();\n\n\t\t\th.InitMaxHealth = 6;\n\t\t\th.RenderInvt = true;\n\n\t\t\tGetComponent<DropsComponent>().Drops.Clear();\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (r != null && r.Tagged[Tags.MustBeKilled].Count == 0) {\n\t\t\t\tKill(this);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tt += dt;\n\n\t\t\tif (t >= 20f) {\n\t\t\t\tKill(this);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void AnimateDeath(DiedEvent d) {\n\t\t\tbase.AnimateDeath(d);\n\t\t\tExplosionMaker.Make(this);\n\t\t\tOnDeath?.Invoke();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/Gore.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.level;\r\nusing BurningKnight.physics;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature {\r\n\tpublic class Gore : Entity, CollisionFilterEntity {\r\n\t\tpublic bool ShouldCollide(Entity entity) {\r\n\t\t\treturn entity is Level || entity is Chasm || entity is Door;\r\n\t\t}\r\n\r\n\t\tprivate float vz;\r\n\t\tprivate float t;\r\n\t\tprivate float a = 1;\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tAddComponent(new ZComponent());\r\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\r\n\r\n\t\t\tvz = 1;\r\n\t\t\tAlwaysActive = true;\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tGraphics.Color = new Color(0.5f, 0.5f, 0.5f, a);\r\n\t\t\tbase.Render();\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t}\r\n\r\n\t\tprivate void RenderShadow() {\r\n\t\t\tGraphics.Color.A = (byte) (a * 255f);\r\n\t\t\tGraphicsComponent.Render(true);\r\n\t\t\tGraphics.Color.A = 255;\r\n\t\t}\r\n\r\n\t\tprivate bool did;\r\n\t\tprivate bool zdid;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tt += dt;\r\n\r\n\t\t\tif (t >= 20f) {\r\n\t\t\t\ta -= dt * 0.5f;\r\n\r\n\t\t\t\tif (a <= 0) {\r\n\t\t\t\t\tDone = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!Settings.Blood) {\r\n\t\t\t\tDone = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (!zdid) {\r\n\t\t\t\tvar z = GetComponent<ZComponent>();\r\n\r\n\t\t\t\tvz -= dt * 4;\r\n\t\t\t\tz.Z = Math.Max(z.Z + vz, 0);\r\n\r\n\t\t\t\tif (z.Z <= 0) {\r\n\t\t\t\t\tzdid = true;\r\n\r\n\t\t\t\t\tif (TryGetComponent<RectBodyComponent>(out var bd)) {\r\n\t\t\t\t\t\tbd.Body.LinearVelocity *= 0.5f;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (did) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar b = GetComponent<RectBodyComponent>().Body;\r\n\r\n\t\t\tif (b.LinearVelocity.Length() < 4) {\r\n\t\t\t\tb.LinearVelocity = Vector2.Zero;\r\n\t\t\t\tRemoveComponent<RectBodyComponent>();\r\n\t\t\t\tdid = true;\r\n\t\t\t} else {\r\n\t\t\t\tPosition += b.LinearVelocity * (dt * 1.5f);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/SmartState.cs",
    "content": "﻿using Lens.entity;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.creature {\n\tpublic class SmartState<T> : EntityState where T: Entity {\n\t\tpublic new T Self;\n\n\t\tpublic override void Assign(Entity self) {\n\t\t\tbase.Assign(self);\n\t\t\tSelf = (T) self;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/bk/BkGraphicsComponent.cs",
    "content": "﻿using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.bk {\n\tpublic class BkGraphicsComponent : AnimationComponent {\n\t\tprivate float t;\n\t\tpublic float Alpha = 1f;\n\t\n\t\tpublic BkGraphicsComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar pos = Entity.Position + Offset;\n\n\t\t\tif (shadow) {\n\t\t\t\tFlippedVerticaly = !FlippedVerticaly;\n\t\t\t\tpos.Y += Animation.GetCurrentTexture().Height - ShadowOffset * 2 + 4;\n\t\t\t\tGraphics.Color.A = (byte) (Alpha * 255);\n\t\t\t} else {\n\t\t\t\tvar shader = Shaders.Bk;\n\t\t\t\tvar region = Animation.GetCurrentTexture();\n\n\t\t\t\tshader.Parameters[\"pos\"].SetValue(new Vector2(region.Source.X / (float) region.Texture.Width,\n\t\t\t\t\tregion.Source.Y / (float) region.Texture.Height));\n\t\t\t\tshader.Parameters[\"size\"].SetValue(new Vector2(region.Width / (float) region.Texture.Width,\n\t\t\t\t\tregion.Height / (float) region.Texture.Height));\n\t\t\t\tshader.Parameters[\"time\"].SetValue(t);\n\t\t\t\tshader.Parameters[\"a\"].SetValue(Alpha);\n\t\t\t\t\n\t\t\t\tShaders.Begin(shader);\n\t\t\t}\n\n\t\t\tCallRender(pos, shadow);\n\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Color.A = 255;\n\t\t\t\tFlippedVerticaly = !FlippedVerticaly;\n\t\t\t} else {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/bk/BkOrbital.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.desert;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.level;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.bk {\n\tpublic class BkOrbital : Mob {\n\t\tprotected const float DefaultZ = 2;\n\t\tpublic int Id;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tSetMaxHp(50);\n\t\t\tRemoveTag(Tags.LevelSave);\n\n\t\t\tWidth = 12;\n\t\t\tHeight = 13;\n\t\t\tTouchDamage = 2;\n\t\t\t\n\t\t\tvar body = new SensorBodyComponent(1, 2, 10, 10);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 4;\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"bk_orbital\"));\n\t\t\tAddComponent(new ZComponent());\n\t\t\tAddComponent(new OrbitalComponent());\n\t\t\t\n\t\t\tAddComponent(new OrbitalComponent {\n\t\t\t\tRadius = 24,\n\t\t\t\tLerp = true\n\t\t\t});\n\n\t\t\tDepth = Layers.Wall;\n\t\t\tBecome<OrbitingState>();\n\t\t}\n\n\t\tpublic override bool InAir() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void Fire() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\tvar a = GetComponent<ZAnimationComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\t\t\t\t\n\t\t\t\t\tvar an = AngleTo(Target);\n\t\t\t\t\tvar builder = new ProjectileBuilder(this, \"big\") {\n\t\t\t\t\t\tScale = 0.8f,\n\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\tColor = ProjectileColor.Orange,\n\t\t\t\t\t\tDamage = 2\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\tbuilder.Shoot(an, 8f);\n\n\t\t\t\t\tvar projectile = builder.Build();\n\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(an, 4f);\n\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, TargetProjectileController.Make(Target, 0.2f));\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\t#region Fly States\n\t\tpublic class OrbitingState : SmartState<BkOrbital> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tT = Self.Id * 1f;\n\t\t\t\t\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\n\t\t\t\tTween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 10f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\n\t\t\t\tvar o = Self.GetComponent<OrbitalComponent>().Orbiting;\n\n\t\t\t\tif (o == null || o.Done) {\n\t\t\t\t\tSelf.Kill(Self);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Level) && base.ShouldCollide(entity);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_fly_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/bk/BurningKnight.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.cutscene.entity;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.entity.projectile.pattern;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing VelcroPhysics.Dynamics;\nusing Color = Microsoft.Xna.Framework.Color;\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\n\nnamespace BurningKnight.entity.creature.bk {\n\tpublic class BurningKnight : Boss {\n\t\tprivate static Color tint = new Color(234, 50, 60, 200);\n\t\tprivate Boss captured;\n\t\tprivate bool raging;\n\t\tprivate int timesRaged;\n\n\t\tpublic bool Passive;\n\t\tpublic bool Hidden => GetComponent<StateComponent>().StateInstance is HiddenState;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddTag(Tags.BurningKnight);\n\t\t\tAddTag(Tags.PlayerSave);\n\n\t\t\tRemoveTag(Tags.Boss);\n\t\t\tRemoveTag(Tags.Mob);\n\t\t\tRemoveTag(Tags.LevelSave);\n\t\t\tRemoveTag(Tags.MustBeKilled);\n\n\t\t\tWidth = 22;\n\t\t\tHeight = 27;\n\t\t\tFlying = true;\n\t\t\tTargetEverywhere = true;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t\tHasHealthbar = false;\n\t\t\tDepth = Layers.Bk;\n\t\t\tTouchDamage = 0;\n\t\t\t\n\t\t\tvar b = new RectBodyComponent(6, 8, 10, 15, BodyType.Dynamic, true) {\n\t\t\t\tKnockbackModifier = 0\n\t\t\t};\n\n\t\t\tAddComponent(b);\n\t\t\tb.Body.LinearDamping = 3;\n\n\t\t\tAddComponent(new BkGraphicsComponent(\"old_burning_knight\"));\n\n\t\t\tvar health = GetComponent<HealthComponent>();\n\t\t\thealth.Unhittable = true;\n\t\t\tSetMaxHp(300);\n\t\t\t// health.AutoKill = false;\n\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\tAddComponent(new OrbitGiverComponent());\n\n\t\t\tAddComponent(new LightComponent(this, 64, new Color(1f, 0.2f, 0.1f, 0.5f)));\n\n\t\t\tvar buffs = GetComponent<BuffsComponent>();\n\n\t\t\tbuffs.AddImmunity<FrozenBuff>();\n\t\t\tbuffs.AddImmunity<BurningBuff>();\n\t\t\tbuffs.AddImmunity<BleedingBuff>();\n\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\tSubscribe<ItemTakenEvent>();\n\t\t\tSubscribe<Dialog.EndedEvent>();\n\t\t\tSubscribe<ShopNpc.SavedEvent>();\n\t\t\tSubscribe<ShopKeeper.EnragedEvent>();\n\t\t\tSubscribe<DiedEvent>();\n\t\t\tSubscribe<SecretRoomFoundEvent>();\n\t\t\tSubscribe<DefeatedEvent>();\n\t\t\tSubscribe<NewLevelStartedEvent>();\n\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 25;\n\t\t\tAddComponent(new AimComponent(AimComponent.AimType.Target));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tTimer.Add(() => {\n\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"mob_bk_hovering_loop\", 0.3f, looped: true, tween: true);\n\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(Run.Depth == 10 ? \"mob_bk_fight_loop\" : \"mob_bk_flame_loop\",  0.3f, looped: true, tween: true);\n\t\t\t}, 2f);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tGetComponent<AudioEmitterComponent>().StopAll();\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!Awoken && target != null) {\n\t\t\t\tAwoken = true;\n\t\t\t\tBecome<FollowState>();\n\t\t\t} else if (target == null) {\n\t\t\t\tBecome<IdleState>();\n\t\t\t\tAwoken = false;\n\t\t\t}\n\n\t\t\tbase.OnTargetChange(target);\n\t\t}\n\n\t\tprivate void FreeSelf() {\n\t\t\tif (!Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar graphics = GetComponent<BkGraphicsComponent>();\n\t\t\tgraphics.Alpha = 0;\n\n\t\t\tCenter = captured.Center;\n\t\t\tGetComponent<HealthComponent>().Unhittable = true;\n\n\t\t\tTween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f).OnEnd = () => {\n\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"mob_bk_roar_4\", 0.8f);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tif (captured.Done) {\n\t\t\t\t\t\tBecome<ChaseState>();\n\n\t\t\t\t\t\t// YOU CAN'T DEFEAT THE BURNING KNIGHT!!!\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_2\", 5);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcaptured = null;\n\t\t\t\t\t\tBecome<FollowState>();\n\t\t\t\t\t\tCheckForScourgeRage();\n\t\t\t\t\t}\n\t\t\t\t}, 1f);\n\t\t\t};\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DefeatedEvent bde) {\n\t\t\t\tif (bde.Boss == captured) {\n\t\t\t\t\tFreeSelf();\n\t\t\t\t}\n\n\t\t\t\tif (bde.Boss == this) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Hidden) {\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tif (!InFight) {\n\t\t\t\t\tvar p = rce.Who is Player;\n\t\t\t\t\tvar bs = rce.Who is BurningKnight;\n\n\t\t\t\t\tif ((p || bs) && rce.New != null) {\n\t\t\t\t\t\tvar t = rce.New.Type;\n\n\t\t\t\t\t\tif (t == RoomType.Boss) {\n\t\t\t\t\t\t\tCheckCapture();\n\t\t\t\t\t\t} else if (p) {\n\t\t\t\t\t\t\tif (t == RoomType.Treasure) {\n\t\t\t\t\t\t\t\tforeach (var item in rce.New.Tagged[Tags.Item]) {\n\t\t\t\t\t\t\t\t\tif (item is SingleChoiceStand stand && stand.Item != null) {\n\t\t\t\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_0\", 5);\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (t == RoomType.Granny) {\n\t\t\t\t\t\t\t\t// GRANNY, CAN YOU JUST DIE, PLEASE??\n\t\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_9\", 3);\n\t\t\t\t\t\t\t} else if (t == RoomType.OldMan) {\n\t\t\t\t\t\t\t\t// MY MASTER, I BROUGHT THE GOBLIN\n\t\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_10\", 5);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is ItemTakenEvent ite) {\n\t\t\t\tif (!InFight && ite.Stand is SingleChoiceStand && ite.Who is Player) {\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_1\", 5);\n\t\t\t\t\tvar state = GetComponent<StateComponent>();\n\n\t\t\t\t\tif (!(state.StateInstance is HiddenState)) {\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\ttimesRaged++;\n\t\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"mob_bk_roar_1\", 0.8f);\n\t\t\t\t\t\t\tstate.Become<AttackState>();\n\t\t\t\t\t\t}, 3);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is Dialog.EndedEvent dse) {\n\t\t\t\tif (!InFight && dse.Owner is ShopKeeper && dse.Dialog.Id == \"shopkeeper_18\") {\n\t\t\t\t\t// What a joke\n\t\t\t\t\tTimer.Add(() => { GetComponent<DialogComponent>().StartAndClose(\"bk_4\", 5); }, 1);\n\t\t\t\t}\n\t\t\t} else if (e is ShopNpc.SavedEvent) {\n\t\t\t\t// I WOULDN'T BOTHER EVEN TALKING TO THEM\n\t\t\t\tTimer.Add(() => { GetComponent<DialogComponent>().StartAndClose(\"bk_5\", 5); }, 2f);\n\t\t\t} else if (e is ShopKeeper.EnragedEvent skee) {\n\t\t\t\tif (skee.ShopKeeper.GetComponent<RoomComponent>().Room.Explored) {\n\t\t\t\t\t// KILL HIM, EDWARD!\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_6\", 5);\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent de) {\n\t\t\t\tif (de.Who is ShopKeeper) {\n\t\t\t\t\t// EDWARD, NOOOOOO!\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_7\", 5);\n\t\t\t\t\treturn false;\n\t\t\t\t} else if (de.Who == this) {\n\t\t\t\t\tdied = true;\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t} else {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else if (e is SecretRoomFoundEvent) {\n\t\t\t\t// OH COMON, STOP EXPLODING MY CASTLE!\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_8\", 5);\n\t\t\t} else if (e is NewLevelStartedEvent) {\n\t\t\t\tif (!InFight) {\n\t\t\t\t\tCheckForScourgeRage();\n\t\t\t\t\tvar state = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (raging && !(state is AttackState || state is ChaseState || state is FlyAwayAttackingState)) {\n\t\t\t\t\t\traging = false;\n\t\t\t\t\t\tsayNoRage = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool died;\n\t\t\n\t\tprivate bool sayNoRage;\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\traging = stream.ReadBoolean();\n\t\t\ttimesRaged = stream.ReadInt32();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(raging);\n\t\t\tstream.WriteInt32(timesRaged);\n\t\t}\n\n\t\tprivate float lastFadingParticle;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!Placed) {\n\t\t\t\tDone = false;\n\t\t\t}\n\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (lasers.Count > 0) {\n\t\t\t\tspinV += dt;\n\n\t\t\t\tforeach (var l in lasers) {\n\t\t\t\t\tif (l.Done) {\n\t\t\t\t\t\tlasers.Clear();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tl.Angle += spinV * dt * 0.2f * spinDir;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastFadingParticle -= dt;\n\n\t\t\tif (lastFadingParticle <= 0 && !(GetComponent<StateComponent>().StateInstance is FlameAttack)) {\n\t\t\t\tlastFadingParticle = 0.2f;\n\n\t\t\t\tvar particle = new FadingParticle(GetComponent<BkGraphicsComponent>().Animation.GetCurrentTexture(), tint);\n\t\t\t\tArea.Add(particle);\n\n\t\t\t\tparticle.Depth = Depth - 1;\n\t\t\t\tparticle.Center = Center;\n\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room != null && room.Type == RoomType.Boss) {\n\t\t\t\t\tCheckCapture();\n\t\t\t\t} else if (Target != null) {\n\t\t\t\t\troom = Target.GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room != null && room.Type == RoomType.Boss) {\n\t\t\t\t\t\tCheckCapture();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool ForcedRage;\n\n\t\tpublic void CheckForScourgeRage() {\n\t\t\tif (InFight) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\tif (s is ChaseState || s is AttackState || s is HiddenState) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (ForcedRage || Run.Scourge >= 10) {\n\t\t\t\tBecome<ChaseState>();\n\t\t\t}\n\t\t}\n\n\t\tprivate void CheckForScourgeRageFree() {\n\t\t\tif (InFight) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Target == null) {\n\t\t\t\tBecome<IdleState>();\n\t\t\t}\n\t\t\t\n\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\tif (s is IdleState || s is ChaseState || s is FollowState || s is HiddenState || s is FlyAwayAttackingState || s is AttackState) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!ForcedRage && Run.Scourge < 10) {\n\t\t\t\tBecome<FollowState>();\n\t\t\t}\n\t\t}\n\n\t\t#region Buring Knight States while calm\n\t\tpublic class IdleState : SmartState<BurningKnight> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\tSelf.CheckForScourgeRage();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class FollowState : SmartState<BurningKnight> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.CheckForScourgeRage();\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\t\t\t\tvar force = 200f * dt;\n\n\t\t\t\tif (d < 48f) {\n\t\t\t\t\tSelf.Become<FlyAwayState>();\n\t\t\t\t} else if (d <= 72f) {\n\t\t\t\t\treturn;\n\t\t\t\t} else if (d >= 300) {\n\t\t\t\t\tSelf.Become<TeleportState>();\n\t\t\t\t}\n\n\t\t\t\tvar room = Self.Target.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (Self.OnScreen && room != null && room.Type == RoomType.Regular &&\n\t\t\t\t    room.Tagged[Tags.MustBeKilled].Count > 0 && room.Contains(Self, 16f)) {\n\t\t\t\t\tvar aa = Self.AngleTo(room);\n\t\t\t\t\tforce = 400f * dt;\n\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity -=\n\t\t\t\t\t\tnew Vector2((float) Math.Cos(aa) * force, (float) Math.Sin(aa) * force);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tpublic class FlyAwayState : SmartState<BurningKnight> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tSelf.CheckForScourgeRage();\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\t\t\t\tvar force = -300f * dt;\n\n\t\t\t\tif (d > 80f) {\n\t\t\t\t\tSelf.Become<FollowState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tprivate void CheckCapture() {\n\t\t\tif (InFight) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar room = Target?.GetComponent<RoomComponent>()?.Room;\n\n\t\t\tif (room != null && room.Type == RoomType.Boss) {\n\t\t\t\tforeach (var p in room.Tagged[Tags.Player]) {\n\t\t\t\t\tif (!((Player) p).Teleported) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (Run.Level.Biome is LibraryBiome) {\n\t\t\t\t\tBeginFight();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tforeach (var mob in room.Tagged[Tags.Boss]) {\n\t\t\t\t\tif (mob != this && mob is Boss b && !(b is bk.BurningKnight)) {\n\t\t\t\t\t\tcaptured = b;\n\t\t\t\t\t\tBecome<CaptureState>();\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class CutsceneState : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tvar bkDialog = Self.GetComponent<DialogComponent>();\n\t\t\t\tvar playerDialog = Self.Target.GetComponent<DialogComponent>();\n\t\t\t\t\n\t\t\t\tStart(bkDialog, \"bkw_0\", Self.Target, () => {\n\t\t\t\t\tStart(bkDialog, \"bkw_1\", Self.Target, () => {\n\t\t\t\t\t\tbkDialog.Close();\n\t\t\t\t\t\t\n\t\t\t\t\t\tStart(playerDialog, \"bkw_2\", Self.Target, () => {\n\t\t\t\t\t\t\tplayerDialog.Close();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tStart(bkDialog, \"bkw_3\", Self.Target, () => {\n\t\t\t\t\t\t\t\tBecome<FollowState>();\n\t\t\t\t\t\t\t\tbkDialog.OnEnd();\n\t\t\t\t\t\t\t\tGlobalSave.Put(\"bk_who\", true);\n\n\t\t\t\t\t\t\t\tSelf.Target.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t\t\t\t\t});\t\n\t\t\t\t\t\t});\t\n\t\t\t\t\t});\t\n\t\t\t\t});\n\t\t\t}\n\t\t\n\t\t\tprivate void Start(DialogComponent d, string id, Entity to, Action callback = null) {\n\t\t\t\td.Start(id, to);\n\n\t\t\t\tif (callback != null) {\n\t\t\t\t\td.Dialog.ShowArrow = true;\n\t\t\t\t\td.Dialog.OnEnd = () => {\n\t\t\t\t\t\tTimer.Add(callback, 0.1f);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class TeleportState : SmartState<BurningKnight> {\n\t\t\tprivate bool did;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (did) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdid = true;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<DialogComponent>().Close();\n\t\t\t\tvar graphics = Self.GetComponent<BkGraphicsComponent>();\n\n\t\t\t\tTween.To(0, graphics.Alpha, x => graphics.Alpha = x, 0.3f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\t\tSelf.Center = Self.Target.Center + MathUtils.CreateVector(Rnd.AnglePI(), 64f);\n\t\t\t\t\t}\n\n\t\t\t\t\tTween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f).OnEnd = () => {\n\t\t\t\t\t\tif (Run.Depth == 1 && GlobalSave.IsFalse(\"bk_who\")) {\n\t\t\t\t\t\t\tSelf.Become<CutsceneState>();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (Self.sayNoRage) {\n\t\t\t\t\t\t\tSelf.sayNoRage = false;\n\t\t\t\t\t\t\tSelf.GetComponent<DialogComponent>().StartAndClose(\"bk_11\", 5);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\t\t\tSelf.Become<FollowState>();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.CheckCapture();\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\t#region Burning Knight States while chasing\n\t\tpublic class FlyAwayAttackingState : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.raging = true;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tSelf.CheckForScourgeRageFree();\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\t\t\t\tvar force = -300f * dt;\n\n\t\t\t\tif (d > 96f) {\n\t\t\t\t\tSelf.Become<ChaseState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tpublic class ChaseState : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.raging = true;\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tSelf.CheckForScourgeRageFree();\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\t\t\t\tvar force = 300f * dt;\n\n\t\t\t\tif (d < 64f) {\n\t\t\t\t\tSelf.Become<FlyAwayAttackingState>();\n\t\t\t\t} else if (d <= 128f) {\n\t\t\t\t\tvar r = Self.Target.GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (r.Type == RoomType.Shop || r.Type == RoomType.SubShop || r.Type == RoomType.OldMan) {\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSelf.Become<AttackState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar room = Self.Target.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (Self.OnScreen && room != null && room.Type == RoomType.Regular &&\n\t\t\t\t    room.Tagged[Tags.MustBeKilled].Count > 0 && room.Contains(Self, 16f)) {\n\t\t\t\t\tvar aa = Self.AngleTo(room);\n\t\t\t\t\tforce = 400f * dt;\n\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity -=\n\t\t\t\t\t\tnew Vector2((float) Math.Cos(aa) * force, (float) Math.Sin(aa) * force);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tpublic class AttackState : SmartState<BurningKnight> {\n\t\t\tprivate int count;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.raging = true;\n\t\t\t\tcount = Math.Min(1, Self.timesRaged);\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tSelf.CheckForScourgeRageFree();\n\n\t\t\t\tif (Self.DistanceTo(Self.Target) < 64f) {\n\t\t\t\t\tSelf.Become<FlyAwayAttackingState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar r = Self.Target.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r.Type == RoomType.Shop || r.Type == RoomType.SubShop || r.Type == RoomType.OldMan) {\n\t\t\t\t\tSelf.Become<ChaseState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (T >= 1f) {\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_bk_fire\");\n\n\t\t\t\t\tvar c = 1;\n\n\t\t\t\t\tif (Self.timesRaged > 2 && Self.timesRaged < 5) {\n\t\t\t\t\t\tc = 3;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\tScale = Rnd.Float(1f, 1f + Self.timesRaged * 0.1f),\n\t\t\t\t\t\tColor = ProjectileColor.BkRed,\n\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverWalls);\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\t\tvar p = builder.Shoot(Self.AngleTo(Self.Target) + Rnd.Float(-0.4f, 0.4f) + (c == 1 ? 0 : (i - 1) * Math.PI * 0.2f),\n\t\t\t\t\t\t\t8 + Self.timesRaged * 0.3f).Build();\n\n\t\t\t\t\t\tp.Center = Self.Center;\n\t\t\t\t\t\tp.Depth = Self.Depth;\n\n\t\t\t\t\t\tif (Self.timesRaged > 4) {\n\t\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.Make(Self.Target, 0.5f));\n\t\t\t\t\t\t\tp.T = 5f + Rnd.Float(1f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcount--;\n\t\t\t\t\tT -= 0.25f + (Self.timesRaged - 1) * 0.1f;\n\n\t\t\t\t\tif (count <= 0) {\n\t\t\t\t\t\tBecome<ChaseState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic class CaptureState : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\tCamera.Instance.Follow(Self, 0.3f);\n\n\t\t\t\tTimer.Add(() => { Camera.Instance.Follow(Self.captured, 0.3f); }, 0.5f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar d = Self.DistanceTo(Self.captured);\n\n\t\t\t\tif (d <= 8) {\n\t\t\t\t\tAudio.PlayMusic(\"Fatiga\", true);\n\n\t\t\t\t\t// PREPARE TO DIE!\n\t\t\t\t\tSelf.captured.GetComponent<DialogComponent>().StartAndClose(Self.captured.GetScream(), 5);\n\t\t\t\t\tSelf.captured.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_bk_capture\");\n\t\t\t\t\tCamera.Instance.Unfollow(Self);\n\n\t\t\t\t\tBecome<HiddenState>();\n\t\t\t\t\tSelf.captured.SelectAttack();\n\t\t\t\t} else if (d >= 400f &&\n\t\t\t\t           Self.GetComponent<RoomComponent>().Room != Self.captured.GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tBecome<TeleportState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(Self.captured);\n\t\t\t\tvar force = 500f * dt;\n\n\t\t\t\tif (d <= 64f) {\n\t\t\t\t\tforce *= 2;\n\t\t\t\t}\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tpublic class HiddenState : SmartState<BurningKnight> {\n\t\t\tprivate bool teleported;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tCamera.Instance.Shake(20);\n\t\t\t\tSelf.Position = Vector2.Zero;\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\t\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t\t}, 1);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!teleported && (Self.captured.Done || Self.captured.GetComponent<StateComponent>().StateInstance is FriendlyState)) {\n\t\t\t\t\tteleported = true;\n\t\t\t\t\tSelf.FreeSelf();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (ImGui.Checkbox(\"Raging\", ref raging)) {\n\t\t\t\tif (raging) {\n\t\t\t\t\tBecome<AttackState>();\n\t\t\t\t} else {\n\t\t\t\t\tBecome<FollowState>();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.InputInt(\"Times Raged\", ref timesRaged);\n\t\t}\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tvar head = new BkHead();\n\t\t\tArea.Add(head);\n\t\t\thead.Center = Center;\n\t\t\tAudio.PlayMusic(\"Last chance\");\n\t\t}\n\n\t\tprotected override void CreateGore(DiedEvent d) {\n\t\t\t\n\t\t}\n\n\t\tpublic bool InFight;\n\n\t\tprivate void AddOrbitals(int count) {\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar orbital = new BkOrbital {\n\t\t\t\t\tId = i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tArea.Add(orbital);\n\t\t\t\torbital.Center = Center;\n\t\t\t\tGetComponent<OrbitGiverComponent>().AddOrbiter(orbital);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void BeginFight() {\n\t\t\tif (InFight || Passive) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (r == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().StartAndClose(\"bk_12\", 3);\n\t\t\tAddOrbitals(6);\n\n\t\t\tInFight = true;\n\t\t\tHasHealthbar = true;\n\n\t\t\tif (HealthBar == null) {\n\t\t\t\tHealthBar = new HealthBar(this);\n\t\t\t\tEngine.Instance.State.Ui.Add(HealthBar);\n\t\t\t\tAddPhases();\n\t\t\t}\n\t\t\t\n\t\t\tAddTag(Tags.Boss);\n\t\t\tAddTag(Tags.Mob);\n\t\t\tAddTag(Tags.MustBeKilled);\n\n\t\t\tvar a = r.Tagged[Tags.MustBeKilled];\n\n\t\t\tif (!a.Contains(this)) {\n\t\t\t\ta.Add(this);\n\t\t\t}\n\t\t\t\n\t\t\ta = r.Tagged[Tags.Mob];\n\n\t\t\tif (!a.Contains(this)) {\n\t\t\t\ta.Add(this);\n\t\t\t}\n\t\t\t\n\t\t\ta = r.Tagged[Tags.Boss];\n\n\t\t\tif (!a.Contains(this)) {\n\t\t\t\ta.Add(this);\n\t\t\t}\n\n\t\t\tBecome<FightState>();\n\n\t\t\tGetComponent<HealthComponent>().Unhittable = false;\n\t\t\tTouchDamage = 2;\n\t\t\tCenter = Target.GetComponent<RoomComponent>().Room.Center;\n\t\t}\n\n\t\tprotected override void Become<T>() {\n\t\t\tif (!Passive || typeof(T) == typeof(IdleState)) {\n\t\t\t\tbase.Become<T>();\n\t\t\t}\n\t\t}\n\n\t\tprotected override void AddPhases() {\n\t\t\tHealthBar.AddPhase(0.5f);\n\t\t}\n\t\t\n\t\t/*\n\t\t * The actual boss battle\n\t\t */\n\n\t\tprivate int count;\n\n\t\tpublic class FightState : SmartState<BurningKnight> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 1f) {\n\t\t\t\t\tswitch (Self.count) {\n\t\t\t\t\t\tcase 0: {\n\t\t\t\t\t\t\tBecome<LaserSwingAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 1: {\n\t\t\t\t\t\t\tBecome<SpawnAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 2: {\n\t\t\t\t\t\t\tBecome<LaserRotateAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 3: {\n\t\t\t\t\t\t\tBecome<FlameAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 4: {\n\t\t\t\t\t\t\tBecome<SwordAttackState>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 5: {\n\t\t\t\t\t\t\tBecome<SkullAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 6: {\n\t\t\t\t\t\t\tBecome<LaserCageAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tSelf.count = (Self.count + 1) % (Self.Raging ? 7 : 6);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic bool Raging => GetComponent<HealthComponent>().Percent <= 0.5f;\n\n\t\tpublic class LaserSwingAttack : SmartState<BurningKnight> {\n\t\t\tprivate Laser laser;\n\t\t\tprivate float vy;\n\t\t\tprivate float angle;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tangle = Self.AngleTo(Self.Target) - (Rnd.Chance() ? -1 : 1) * 1.2f;\n\t\t\t\tSelf.WarnLaser(angle);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (laser == null) {\n\t\t\t\t\tif (T < 1f) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Self.Raging) {\n\t\t\t\t\t\tSelf.StartLasers();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlaser = Laser.Make(Self, 0, 0, damage: 2, scale: 3, range: 64);\n\t\t\t\t\tlaser.LifeTime = 10f;\n\t\t\t\t\tlaser.Position = Self.Center;\n\t\t\t\t\tlaser.Angle = angle;\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\t\t\t\t}\n\n\t\t\t\tif (laser.Done) {\n\t\t\t\t\tBecome<FightState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlaser.Position = Self.Center;\n\n\t\t\t\tvar aa = laser.Angle;\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\t\t\t\t\n\t\t\t\tvy += (float) MathUtils.ShortAngleDistance(aa, a) * dt * 4;\n\n\t\t\t\tlaser.Angle += vy * dt * 0.5f;\n\t\t\t}\n\t\t}\n\n\t\tprivate List<Laser> lasers = new List<Laser>();\n\t\tprivate float spinV;\n\t\tprivate int spinDir;\n\n\t\tprivate void WarnLaser(float angle, Vector2? offset = null) {\n\t\t\tvar builder = new ProjectileBuilder(this, Raging ? \"big\" : \"circle\") {\n\t\t\t\tLightRadius = 32f,\n\t\t\t\tColor = ProjectileColor.Red\n\t\t\t};\n\n\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar projectile = builder.Shoot(angle, Raging ? 15f : 10f).Build();\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\n\t\t\t\t\tif (offset != null) {\n\t\t\t\t\t\tprojectile.Center += offset.Value;\n\t\t\t\t\t}\n\t\t\t\t}, i * 0.3f);\n\t\t\t}\t\t\n\t\t}\n\n\t\tprivate void StartLasers() {\n\t\t\tlasers.Clear();\n\t\t\tspinV = 0;\n\t\t\tspinDir = Rnd.Chance() ? 1 : -1;\n\n\t\t\tTimer.Add(() => { \n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\t\t\t}, 1f);\n\n\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\tvar angle = AngleTo(Target) + (i / 4f + 1 / 8f) * (float) Math.PI * 2f;\n\n\t\t\t\tWarnLaser(angle);\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar laser = Laser.Make(this, 0, 0, damage: 2, scale: 3, range: 64);\n\t\t\t\t\tlaser.LifeTime = 10f;\n\t\t\t\t\tlaser.Position = Center;\n\t\t\t\t\tlaser.Angle = angle;\n\n\t\t\t\t\tlasers.Add(laser);\n\t\t\t\t}, 1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic class LaserRotateAttack : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.StartLasers();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 3f && Self.lasers.Count == 0) {\n\t\t\t\t\tBecome<FightState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class SkullAttack : SmartState<BurningKnight> {\n\t\t\tprivate int count;\n\t\t\tprivate bool explode;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\texplode = Rnd.Chance();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif ((count + 1) * (Self.Raging ? 0.7f : 1f) <= T) {\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (Self.Target == null || Self.Died) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar a = Self.GetComponent<BkGraphicsComponent>();\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_oldking_shoot\");\n\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\n\t\t\t\t\t\tif (Self.Target == null || Self.Died) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, explode ? \"skull\" : \"skup\") {\n\t\t\t\t\t\t\tRange = 5\n\t\t\t\t\t\t}.Shoot(Rnd.AnglePI(), explode ? Rnd.Float(5, 12) : 14);\n\n\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tvar skull = builder.Build();\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(Self.Target, 0.5f));\n\n\t\t\t\t\t\tif (explode) {\n\t\t\t\t\t\t\t/*skull.NearDeath += p => {\n\t\t\t\t\t\t\t\tvar c = new AudioEmitterComponent {\n\t\t\t\t\t\t\t\t\tDestroySounds = false\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tp.AddComponent(c);\n\t\t\t\t\t\t\t\tc.Emit(\"mob_oldking_explode\");\n\t\t\t\t\t\t\t};*/\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => {\n\t\t\t\t\t\t\t\tif (!t) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tvar b = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\t\t\t\t\tb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (var i = 0; i < 16; i++) {\n\t\t\t\t\t\t\t\t\tvar bullet = b.Shoot(((float) i) / 8 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build();\n\t\t\t\t\t\t\t\t\tbullet.Center = p.Center;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tskull.GetComponent<ProjectileGraphicsComponent>().IgnoreRotation = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (count == (Self.Raging ? 6 : 4)) {\n\t\t\t\t\t\t\tSelf.Become<FightState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate static string[] swordData = {\n\t\t\t\" x     \",\n\t\t\t\"xxxxxxx\",\n\t\t\t\" x     \",\n\t\t};\n\n\t\tpublic class SwordAttackState : SmartState<BurningKnight> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_static\");\n\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\t\t\t\t\t\n\t\t\t\t\tvar p = new ProjectilePattern(KeepShapePattern.Make(0)) {\n\t\t\t\t\t\tPosition = Self.Center\n\t\t\t\t\t};\n\n\t\t\t\t\tSelf.Area.Add(p);\n\t\t\t\t\t\n\t\t\t\t\tProjectileTemplate.MakeFast(Self, \"small\", Self.Center, a, (pr) => {\n\t\t\t\t\t\tpr.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tp.Add(pr);\n\t\t\t\t\t\tpr.Color = ProjectileColor.Red;\n\t\t\t\t\t}, swordData, () => {\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tp.Launch(a, 30);\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_static\");\n\n\t\t\t\t\t\t\tBecome<FightState>();\n\t\t\t\t\t\t}, 0.2f);\n\t\t\t\t\t});\n\t\t\t\t}, 1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic class LaserCageAttack : SmartState<BurningKnight> {\n\t\t\tprivate Laser[] lasers = new Laser[8];\n\t\t\tprivate Vector2 spot;\n\n\t\t\tprivate const float boxHalfSize = 32;\n\n\t\t\tprivate static Vector2[] laserOffsets = {\n\t\t\t\tnew Vector2(-boxHalfSize, 0), \n\t\t\t\tnew Vector2(-boxHalfSize, 0), \n\t\t\t\tnew Vector2(boxHalfSize, 0),\n\t\t\t\tnew Vector2(boxHalfSize, 0),\n\t\t\t\tnew Vector2(0, -boxHalfSize),\n\t\t\t\tnew Vector2(0, -boxHalfSize),\n\t\t\t\tnew Vector2(0, boxHalfSize),\n\t\t\t\tnew Vector2(0, boxHalfSize),\n\t\t\t};\n\n\t\t\tprivate static double[] laserAngles = {\n\t\t\t\tMath.PI * 0.5f,\n\t\t\t\tMath.PI * 1.5f,\n\t\t\t\tMath.PI * 0.5f,\n\t\t\t\tMath.PI * 1.5f,\n\t\t\t\tMath.PI,\n\t\t\t\t0,\n\t\t\t\tMath.PI,\n\t\t\t\t0\n\t\t\t};\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tspot = Self.Center;\n\n\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\tSelf.WarnLaser((float) laserAngles[i], laserOffsets[i]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\t\tvar laser = Laser.Make(Self, 0, (float) laserAngles[i], damage: 2, scale: 3, range: 64);\n\n\t\t\t\t\t\tlaser.LifeTime = 10f;\n\t\t\t\t\t\tlaser.Position = spot + laserOffsets[i];\n\n\t\t\t\t\t\tlasers[i] = laser;\n\t\t\t\t\t}\n\t\t\t\t}, 1);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T < 1f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspot = spot.Lerp(Self.Target.Center, dt * 0.5f);\n\n\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\tvar laser = lasers[i];\n\n\t\t\t\t\tif (laser == null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (laser.Done) {\n\t\t\t\t\t\tforeach (var l in lasers) {\n\t\t\t\t\t\t\tif (l != null) {\n\t\t\t\t\t\t\t\tl.Done = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tBecome<FightState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlaser.Position = spot + laserOffsets[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class FlameAttack : SmartState<BurningKnight> {\n\t\t\tprivate float r;\n\t\t\tprivate List<int> last = new List<int>();\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar graphics = Self.GetComponent<BkGraphicsComponent>();\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\tTween.To(0, graphics.Alpha, x => graphics.Alpha = x, 0.3f);\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\t\n\t\t\t\tvar graphics = Self.GetComponent<BkGraphicsComponent>();\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t\tSelf.TouchDamage = 2;\n\t\t\t\tTween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f);\n\n\t\t\t\tforeach (var l in last) {\n\t\t\t\t\tRun.Level.SetFlag(l, Flag.Burning, false);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 10f) {\n\t\t\t\t\tBecome<FightState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tr = Math.Min(1.5f, r + dt * 60);\n\t\t\t\t\n\t\t\t\tvar x = (int) Math.Floor(Self.CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(Self.CenterY / 16);\n\n\t\t\t\tfor (var xx = (int) -r; xx <= r; xx++) {\n\t\t\t\t\tfor (var yy = (int) -r; yy <= r; yy++) {\n\t\t\t\t\t\tif (Math.Sqrt(xx * xx + yy * yy) <= r) {\n\t\t\t\t\t\t\tvar i = Run.Level.ToIndex(x + xx, y + yy);\n\n\t\t\t\t\t\t\tif (!Run.Level.CheckFlag(i, Flag.Burning)) {\n\t\t\t\t\t\t\t\tRun.Level.SetFlag(i, Flag.Burning, true);\n\t\t\t\t\t\t\t\tlast.Add(i);\n\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tlast.Remove(i);\n\t\t\t\t\t\t\t\t\tRun.Level.SetFlag(i, Flag.Burning, false);\n\t\t\t\t\t\t\t\t}, Rnd.Float(1.5f, 2.5f));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar force = 250f * dt;\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class SpawnAttack : SmartState<BurningKnight> {\n\t\t\tprivate int count;\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tcount = Rnd.Int(4, 10);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tdelay -= dt;\n\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tdelay = 0.3f;\n\t\t\t\t\tSelf.GetComponent<BkGraphicsComponent>().Animate();\n\n\t\t\t\t\tvar angle = Rnd.AnglePI() * 0.5f + count * (float) Math.PI;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"big\") {\n\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\tColor = ProjectileColor.Orange\n\t\t\t\t\t}.Shoot(angle, 15f);\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\t\t\tvar projectile = builder.Build();\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => {\n\t\t\t\t\t\tvar x = (int) Math.Floor(p.CenterX / 16);\n\t\t\t\t\t\tvar y = (int) Math.Floor(p.CenterY / 16);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar mob = new WallCrawler();\n\t\t\t\t\t\tSelf.Area.Add(mob);\n\t\t\t\t\t\tmob.X = x * 16;\n\t\t\t\t\t\tmob.Y = y * 16 - 8;\n\t\t\t\t\t\tmob.GeneratePrefix();\n\t\t\t\t\t\tAnimationUtil.Poof(mob.Center, 1);\n\t\t\t\t\t});\n\n\t\t\t\t\tcount--;\n\n\t\t\t\t\tif (count <= 0) {\n\t\t\t\t\t\tBecome<FightState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/bk/SpawnTrigger.cs",
    "content": "using System;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.level;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.bk {\n\tpublic class SpawnTrigger : SaveableEntity {\n\t\tpublic byte[] Tiles;\n\t\tpublic byte[] Liquid;\n\t\tpublic ushort RoomX;\n\t\tpublic ushort RoomY;\n\t\tpublic byte RoomWidth;\n\t\tpublic byte RoomHeight;\n\n\t\tpublic bool Triggered;\n\t\tpublic bool Interrupted;\n\t\tpublic bool ReadyToSpawn;\n\t\t\n\t\tprivate float t;\n\t\tprivate bool did;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!did && Triggered) {\n\t\t\t\tCamera.Instance.Shake(0.5f);\n\t\t\t\tt += dt;\n\n\t\t\t\tif (t >= 1f) {\n\t\t\t\t\tdid = true;\n\t\t\t\t\tvar r = (int) Math.Ceiling(Math.Sqrt((RoomWidth + 1) * (RoomWidth + 1) + (RoomHeight + 1) * (RoomHeight + 1)));\n\n\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\tCamera.Instance.Follow(this, 3f);\n\t\t\t\t\tTween.To(0.5f, Camera.Instance.Zoom, x => Camera.Instance.Zoom = x, 0.3f);\n\n\t\t\t\t\tfor (var j = 1; j < r; j++) {\n\t\t\t\t\t\tvar level = Run.Level;\n\t\t\t\t\t\tvar j1 = j;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tif (Interrupted) {\n\t\t\t\t\t\t\t\tlevel.CreateBody();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (var y = 0; y < RoomHeight; y++) {\n\t\t\t\t\t\t\t\tfor (var x = 0; x < RoomWidth; x++) {\n\t\t\t\t\t\t\t\t\tvar dx = x - RoomWidth / 2f;\n\t\t\t\t\t\t\t\t\tvar dy = y - RoomHeight / 2f;\n\n\t\t\t\t\t\t\t\t\tif (Math.Sqrt(dx * dx + dy * dy) > j1) {\n\t\t\t\t\t\t\t\t\t\tcontinue;\t\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tvar i = x + y * RoomWidth;\n\n\t\t\t\t\t\t\t\t\tif (Tiles[i] == 255) {\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tvar li = level.ToIndex(RoomX + x, RoomY + y);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (level.Get(li).IsWall()) {\n\t\t\t\t\t\t\t\t\t\tlevel.Variants[li] = 0;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// tmp\n\t\t\t\t\t\t\t\t\tArea.Add(new TileFx {\n\t\t\t\t\t\t\t\t\t\tX = (RoomX + x) * 16,\n\t\t\t\t\t\t\t\t\t\tY = (RoomY + y) * 16 - 8\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tlevel.ReCreateBodyChunk(RoomX + x, RoomY + y);\n\n\t\t\t\t\t\t\t\t\tlevel.Tiles[li] = Tiles[i];\n\t\t\t\t\t\t\t\t\tlevel.Liquid[li] = Liquid[i];\n\n\t\t\t\t\t\t\t\t\tTiles[i] = 255; // Mark as already checked;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (var y = -1; y < RoomHeight + 1; y++) {\n\t\t\t\t\t\t\t\tfor (var x = -1; x < RoomWidth + 1; x++) {\n\t\t\t\t\t\t\t\t\tLevelTiler.TileUp(level, level.ToIndex(RoomX + x, RoomY + y));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\t\tCamera.Instance.Shake(2);\n\t\t\t\t\t\t}, j * 0.05f);\n\t\t\t\t\t}\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tif (Interrupted) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tTween.To(1f, Camera.Instance.Zoom, x => Camera.Instance.Zoom = x, 0.3f);\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tif (Interrupted) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tDone = true;\n\t\t\t\t\t\t\tReadyToSpawn = true;\n\t\t\t\t\t\t}, 1f);\n\t\t\t\t\t}, r * 0.05f + 1f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte((byte) Width);\n\t\t\tstream.WriteByte((byte) Height);\n\t\t\t\n\t\t\tstream.WriteUInt16(RoomX);\n\t\t\tstream.WriteUInt16(RoomY);\n\t\t\t\n\t\t\tstream.WriteByte(RoomWidth);\n\t\t\tstream.WriteByte(RoomHeight);\n\n\t\t\tfor (var i = 0; i < RoomWidth * RoomHeight; i++) {\n\t\t\t\tstream.WriteByte(Tiles[i]);\n\t\t\t\tstream.WriteByte(Liquid[i]);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tWidth = stream.ReadByte();\n\t\t\tHeight = stream.ReadByte();\n\n\t\t\tRoomX = stream.ReadUInt16();\n\t\t\tRoomY = stream.ReadUInt16();\n\n\t\t\tRoomWidth = stream.ReadByte();\n\t\t\tRoomHeight = stream.ReadByte();\n\n\t\t\tvar s = RoomWidth * RoomHeight;\n\n\t\t\tTiles = new byte[s];\n\t\t\tLiquid = new byte[s];\n\t\t\t\n\t\t\tfor (var i = 0; i < s; i++) {\n\t\t\t\tTiles[i] = stream.ReadByte();\n\t\t\t\tLiquid[i] = stream.ReadByte();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tSubscribe<BurningStatue.BrokenEvent>();\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new RectBodyComponent(8, 8, Width - 16, Height - 16, BodyType.Static, true));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BurningStatue.BrokenEvent) {\n\t\t\t\tInterrupted = true;\n\t\t\t\tDone = true;\n\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (Triggered) {\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Player p) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tTriggered = true;\n\t\t\t\t\t}, 1f);\n\t\t\t\t\t\n\t\t\t\t\tvar xx = (int) Math.Floor(CenterX / 16);\n\t\t\t\t\tvar xy = (int) Math.Floor(CenterY / 16);\n\n\t\t\t\t\tPainter.Rect(Run.Level, xx - 3, xy - 3, 6, 6, Tile.Chasm);\n\n\t\t\t\t\t/*var torches = GetComponent<RoomComponent>().Room.Tagged[Tags.Torch];\n\n\t\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t\t((Torch) t).On = false;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tif (Interrupted) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t\t\tvar tr = (Torch) t;\n\t\t\t\t\t\t\ttr.On = true;\n\t\t\t\t\t\t\ttr.XSpread = 0.1f;\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 3f);*/\n\t\t\t\t\t\n\t\t\t\t\tHandleEvent(new TriggeredEvent {\n\t\t\t\t\t\tTrigger = this,\n\t\t\t\t\t\tWho = p\n\t\t\t\t\t});\n\n\t\t\t\t\tfor (var x = X - 16; x < X + Width + 16; x += 16) {\n\t\t\t\t\t\tfor (var i = 0; i < Rnd.Int(3, 9); i++) {\n\t\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x + Rnd.Float(-2, 18), Y - 16 + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x + Rnd.Float(-2, 18), Y + Height + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new TileFx {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x, Y - 16)\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new TileFx {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x, Y + Height)\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var y = Y; y < Y + Height; y += 16) {\n\t\t\t\t\t\tfor (var i = 0; i < Rnd.Int(3, 9); i++) {\n\t\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(X + Rnd.Float(-2, 18) - 16, y + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(X + Width + Rnd.Float(-2, 18), y + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new TileFx {\n\t\t\t\t\t\t\t\tPosition = new Vector2(X - 16, y)\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tArea.Add(new TileFx {\n\t\t\t\t\t\t\t\tPosition = new Vector2(X + Width, y)\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic class TriggeredEvent : Event {\n\t\t\tpublic SpawnTrigger Trigger;\n\t\t\tpublic Player Who;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/AnyDrop.cs",
    "content": "using System.Collections.Generic;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class AnyDrop : OneOfDrop {\n\t\tpublic AnyDrop() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic AnyDrop(params Drop[] drops) : base(drops) {\n\t\t\t\n\t\t}\n\n\t\tpublic override List<string> GetItems() {\n\t\t\tvar items = new List<string>();\n\n\t\t\tforeach (var d in Drops) {\n\t\t\t\tvar i = d.GetItems();\n\n\t\t\t\tif (i != null) {\n\t\t\t\t\titems.AddRange(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn items;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"any\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/Drop.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.loot;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic abstract class Drop {\n\t\t// From 0 to 1\n\t\tpublic float Chance = 1f;\n\t\t\n\t\tpublic virtual List<string> GetItems() { \n\t\t\treturn new List<string>();\n\t\t}\n\n\t\tpublic abstract string GetId();\n\n\t\tpublic virtual void Load(JsonValue root) {\n\t\t\tChance = root[\"chance\"].Number(1);\n\t\t}\n\n\t\tpublic virtual void Save(JsonValue root) {\n\t\t\troot[\"chance\"] = Chance;\n\t\t}\n\n\t\tpublic static void Create(string id, Entity entity, Area area = null, Dot where = null) {\n\t\t\tvar drop = Drops.Get(id);\n\n\t\t\tif (drop == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tCreate(new List<Drop> { drop }, entity, area, where);\n\t\t}\n\n\t\tpublic static void Create(List<Drop> dr, Entity entity, Area area = null, Dot where = null) {\n\t\t\tvar drops = new List<Item>();\n\t\t\tvar ar = entity?.Area ?? area;\n\t\t\tvar wh = entity?.BottomCenter ?? where;\n\t\t\t\n\t\t\tforeach (var drop in dr) {\n\t\t\t\tif (Rnd.Float() > drop.Chance) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar ids = drop.GetItems();\n\n\t\t\t\tforeach (var id in ids) {\n\t\t\t\t\tif (id != null) {\n\t\t\t\t\t\tif (id == \"bk:troll_bomb\") {\n\t\t\t\t\t\t\tvar bomb = new Bomb(entity);\n\t\t\t\t\t\t\tar.Add(bomb);\n\t\t\t\t\t\t\tbomb.Center = wh;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar item = Items.Create(id);\n\n\t\t\t\t\t\tif (item != null) {\n\t\t\t\t\t\t\tdrops.Add(item);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (entity is DropModifier d) {\n\t\t\t\td.ModifyDrops(drops);\n\t\t\t}\n\n\t\t\tforeach (var item in drops) {\n\t\t\t\titem.CenterX = wh.X;\n\t\t\t\titem.CenterY = wh.Y + 4;\n\t\t\t\tar.Add(item);\n\t\t\t\titem.AddDroppedComponents();\n\t\t\t\titem.RandomizeVelocity(1f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/DropInfo.cs",
    "content": "using System;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic struct DropInfo {\n\t\tpublic string Id;\n\t\tpublic Type Type;\n\t\tpublic Action<JsonValue> Render;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/DropRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic static class DropRegistry {\n\t\tpublic static Dictionary<string, DropInfo> Defined = new Dictionary<string, DropInfo>();\n\n\t\tstatic DropRegistry() {\n\t\t\tDefine<AnyDrop>(\"any\", AnyDrop.RenderDebug);\n\t\t\tDefine<EmptyDrop>(\"empty\", EmptyDrop.RenderDebug);\n\t\t\tDefine<OneOfDrop>(\"one\", OneOfDrop.RenderDebug);\n\t\t\tDefine<PoolDrop>(\"pool\", PoolDrop.RenderDebug);\n\t\t\tDefine<SimpleDrop>(\"simple\", SimpleDrop.RenderDebug);\n\t\t\tDefine<SingleDrop>(\"single\", SingleDrop.RenderDebug);\n\t\t}\n\t\t\n\t\tpublic static void Define<T>(string id, Action<JsonValue> render) where T : Drop {\n\t\t\tDefined[id] = new DropInfo {\n\t\t\t\tRender = render,\n\t\t\t\tId = id,\n\t\t\t\tType = typeof(T)\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/EmptyDrop.cs",
    "content": "using System.Collections.Generic;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class EmptyDrop : Drop {\n\t\tpublic EmptyDrop(float chance = 1) {\n\t\t\tChance = chance;\n\t\t}\n\t\t\n\t\tpublic override List<string> GetItems() {\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"empty\";\n\t\t}\n\n\t\tpublic override void Load(JsonValue root) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Save(JsonValue root) {\n\t\t\t\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/OneOfDrop.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.loot;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class OneOfDrop : Drop {\n\t\tpublic static string[] DropNames;\n\t\tpublic static int CurrentDrop;\n\t\t\n\t\tpublic Drop[] Drops;\n\n\t\tpublic OneOfDrop(params Drop[] drops) {\n\t\t\tDrops = drops;\n\t\t}\n\t\t\n\t\tpublic override List<string> GetItems() {\n\t\t\tvar items = base.GetItems();\n\n\t\t\tif (Drops != null) {\n\t\t\t\tvar sum = 0f;\n\t\t\t\tvar dropResults = new List<string>[Drops.Length];\n\t\t\t\tvar i = 0;\n\n\t\t\t\tforeach (var drop in Drops) {\n\t\t\t\t\tvar results = drop.GetItems();\n\t\t\t\t\tdropResults[i++] = results;\n\n\t\t\t\t\tif (results == null || results.Count > 0) {\n\t\t\t\t\t\tsum += drop.Chance;\n\t\t\t\t\t}\n\t\t\t\t}\t\t\t\n\t\t\t\t\n\t\t\t\tvar value = Rnd.Float(sum);\n\t\t\t\tsum = 0;\n\t\t\t\ti = 0;\n\t\t\t\t\n\t\t\t\tforeach (var drop in Drops) {\n\t\t\t\t\tvar d = dropResults[i++];\n\t\t\t\t\t\n\t\t\t\t\tif (d != null && d.Count == 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\t\n\t\t\t\t\t\n\t\t\t\t\tsum += drop.Chance;\n\n\t\t\t\t\tif (value <= sum) {\n\t\t\t\t\t\tif (d != null) {\n\t\t\t\t\t\t\titems.AddRange(d);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn items;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"one\";\n\t\t}\n\n\t\tpublic override void Load(JsonValue root) {\n\t\t\tbase.Load(root);\n\t\t\t\n\t\t\tif (root[\"drops\"].IsJsonArray) {\n\t\t\t\tvar drops = root[\"drops\"].AsJsonArray;\n\t\t\t\tDrops = new Drop[drops.Count];\n\n\t\t\t\tfor (var i = 0; i < Drops.Length; i++) {\n\t\t\t\t\tDrops[i] = LootTables.ParseDrop(drops[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(JsonValue root) {\n\t\t\tbase.Save(root);\n\t\t\tvar drops = new JsonArray();\n\n\t\t\tforeach (var d in Drops) {\n\t\t\t\tdrops.Add(LootTables.WriteDrop(d));\n\t\t\t}\n\t\t\n\t\t\troot[\"drops\"] = drops;\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Chance\", \"chance\");\n\t\t\t\n\t\t\tif (!root[\"drops\"].IsJsonArray) {\n\t\t\t\troot[\"drops\"] = new JsonArray();\n\t\t\t}\n\n\t\t\tvar drops = root[\"drops\"].AsJsonArray;\n\t\t\tvar toRemove = -1;\n\t\t\t\n\t\t\tfor (var i = 0; i < drops.Count; i++) {\n\t\t\t\tif (LootTables.RenderDrop(drops[i]) && ImGui.Button(\"Remove drop\")) {\n\t\t\t\t\ttoRemove = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (toRemove > -1) {\n\t\t\t\tdrops.Remove(toRemove);\n\t\t\t}\n\n\t\t\tif (DropNames == null) {\n\t\t\t\tDropNames = new string[DropRegistry.Defined.Count];\n\t\t\t\tvar i = 0;\n\n\t\t\t\tforeach (var v in DropRegistry.Defined.Values) {\n\t\t\t\t\tDropNames[i++] = v.Id;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tImGui.Combo(\"##tp\", ref CurrentDrop, DropNames, DropNames.Length);\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Add drop\")) {\n\t\t\t\tdrops.Add(new JsonObject {\n\t\t\t\t\t[\"type\"] = DropNames[CurrentDrop]\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/PoolDrop.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.debug;\nusing BurningKnight.entity.item;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class PoolDrop : Drop {\n\t\tpublic ItemPool Pool;\n\t\tpublic int Min;\n\t\tpublic int Max;\n\n\t\tpublic PoolDrop() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic PoolDrop(ItemPool pool, float chance = 1f, int min = 1, int max = 1) {\n\t\t\tPool = pool;\n\t\t\tChance = chance;\n\t\t\tMin = min;\n\t\t\tMax = max;\n\t\t}\n\n\t\tpublic override List<string> GetItems() {\n\t\t\tvar list = new List<string>();\n\n\t\t\tfor (var i = 0; i < Rnd.Int(Min, Max + 1); i++) {\n\t\t\t\tlist.Add(Items.Generate(Pool));\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"pool\";\n\t\t}\n\n\t\tpublic override void Load(JsonValue root) {\n\t\t\tbase.Load(root);\n\n\t\t\tMin = root[\"min\"].Int(1);\n\t\t\tMax = root[\"max\"].Int(1);\n\t\t\tPool = ItemPool.ById[root[\"pool\"].Int(0)];\n\t\t}\n\n\t\tpublic override void Save(JsonValue root) {\n\t\t\tbase.Save(root);\n\n\t\t\troot[\"min\"] = Min;\n\t\t\troot[\"max\"] = Max;\n\t\t\troot[\"pool\"] = Pool.Id;\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Chance\", \"chance\");\n\n\t\t\troot.InputInt(\"Min Count\", \"min\");\n\t\t\troot.InputInt(\"Max Count\", \"max\");\n\t\t\t\n\t\t\tvar pool = root[\"pool\"].Int(0);\n\n\t\t\tif (ImGui.Combo(\"Pool##p\", ref pool, ItemPool.Names, ItemPool.Count)) {\n\t\t\t\troot[\"pool\"] = pool;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"View pool\")) {\n\t\t\t\tWindowManager.PoolEditor = true;\n\t\t\t\tPoolEditor.Pool = pool;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/SimpleDrop.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.state;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class SimpleDrop : Drop {\n\t\tprivate static System.Numerics.Vector2 popupSize = new System.Numerics.Vector2(400, 400);\n\t\tprivate static unsafe ImGuiTextFilterPtr popupFilter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static string selectedItem;\n\t\tprivate static int id;\n\t\t\n\t\tpublic string[] Items;\n\t\tpublic int Min = 1;\n\t\tpublic int Max = 1;\n\n\t\tpublic SimpleDrop(float chance, int min, int max, params string[] items) {\n\t\t\tChance = chance;\n\t\t\tMin = min;\n\t\t\tMax = max;\n\t\t\tItems = items;\n\t\t}\n\t\t\n\t\tpublic SimpleDrop() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override List<string> GetItems() {\n\t\t\tvar items = new List<string>();\n\n\t\t\tif (Items != null) {\n\t\t\t\tfor (var i = 0; i < Rnd.Int(Min, Max + 1); i++) {\n\t\t\t\t\tforeach (var item in Items) {\n\t\t\t\t\t\tif (assets.items.Items.ShouldAppear(item)) {\n\t\t\t\t\t\t\titems.Add(item);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn items;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"simple\";\n\t\t}\n\n\t\tpublic override void Load(JsonValue root) {\n\t\t\tbase.Load(root);\n\t\t\t\n\t\t\tMin = root[\"min\"].Int(1);\n\t\t\tMax = root[\"max\"].Int(1);\n\n\t\t\tif (root[\"items\"].IsJsonArray) {\n\t\t\t\tvar items = root[\"items\"].AsJsonArray;\n\t\t\t\tItems = new string[items.Count];\n\n\t\t\t\tfor (var i = 0; i < Items.Length; i++) {\n\t\t\t\t\tItems[i] = items[i].AsString;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(JsonValue root) {\n\t\t\tbase.Save(root);\n\n\t\t\tvar items = new JsonArray();\n\n\t\t\tforeach (var item in Items) {\n\t\t\t\titems.Add(item);\n\t\t\t}\n\t\t\t\n\t\t\troot[\"min\"] = Min;\n\t\t\troot[\"max\"] = Max;\n\t\t\troot[\"items\"] = items;\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Chance\", \"chance\");\n\t\t\t\n\t\t\troot.InputInt(\"Min\", \"min\");\n\t\t\troot.InputInt(\"Max\", \"max\");\n\t\t\t\n\t\t\tif (!root[\"items\"].IsJsonArray) {\n\t\t\t\troot[\"items\"] = new JsonArray();\n\t\t\t}\n\n\t\t\tvar toRemove = -1;\n\t\t\tvar items = root[\"items\"].AsJsonArray;\n\n\t\t\tfor (var i = 0; i < items.Count; i++) {\n\t\t\t\tif (ImGui.SmallButton($\"{items[i]}##s\")) {\n\t\t\t\t\tWindowManager.ItemEditor = true;\n\t\t\t\t\tItemEditor.Selected = assets.items.Items.Datas[items[i]];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.SmallButton(\"-\")) {\n\t\t\t\t\ttoRemove = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (toRemove != -1) {\n\t\t\t\titems.Remove(toRemove);\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"Add\")) {\n\t\t\t\tImGui.OpenPopup(\"Add Item##p\");\t\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tif (ImGui.BeginPopupModal(\"Add Item##p\")) {\n\t\t\t\tImGui.SetWindowSize(popupSize);\n\t\t\t\t\n\t\t\t\tpopupFilter.Draw(\"\");\n\t\t\t\tImGui.BeginChild(\"ScrollinegionUses##reee\", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), \n\t\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\t\t\t\t\n\t\t\t\tImGui.Separator();\n\n\t\t\t\tforeach (var i in assets.items.Items.Datas) {\n\t\t\t\t\tImGui.PushID($\"{id}__itm\");\n\t\t\t\t\n\t\t\t\t\tif (popupFilter.PassFilter(i.Key) && !items.Contains(i.Key) && ImGui.Selectable($\"{i.Key}##dd\", selectedItem == i.Key)) {\n\t\t\t\t\t\tselectedItem = i.Key;\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.PopID();\n\t\t\t\t\tid++;\n\t\t\t\t}\n\n\t\t\t\tid = 0;\n\n\t\t\t\tImGui.EndChild();\n\t\t\t\tImGui.Separator();\n\n\t\t\t\tif (selectedItem != null && (ImGui.Button(\"Add\") || Input.Keyboard.WasPressed(Keys.Enter, true))) {\n\t\t\t\t\titems.Add(selectedItem);\n\t\t\t\t\tselectedItem = null;\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.EndPopup();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/drop/SingleDrop.cs",
    "content": "using System.Collections.Generic;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.drop {\n\tpublic class SingleDrop : Drop {\n\t\tpublic string Item;\n\n\t\tpublic SingleDrop() {\n\t\t\t\n\t\t}\n\n\t\tpublic SingleDrop(string id, float chance = 1f) {\n\t\t\tItem = id;\n\t\t\tChance = chance;\n\t\t}\n\n\t\tpublic override List<string> GetItems() {\n\t\t\tvar items = new List<string>();\n\t\t\t\n\t\t\tif (assets.items.Items.ShouldAppear(Item)) {\n\t\t\t\titems.Add(Item);\n\t\t\t} else {\n\t\t\t\tLog.Error($\"Blocked {Item}\");\n\t\t\t}\n\n\t\t\treturn items;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn \"single\";\n\t\t}\n\n\t\tpublic override void Load(JsonValue root) {\n\t\t\tbase.Load(root);\n\t\t\tItem = root[\"item\"].String(\"\");\n\t\t}\n\n\t\tpublic override void Save(JsonValue root) {\n\t\t\tbase.Save(root);\n\t\t\troot[\"item\"] = Item;\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/Dummy.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic class Dummy : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(4, 2, 8, 14, BodyType.Static));\n\t\t\tAddComponent(new DialogComponent());\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 2;\n\t\t\tAddAnimation(\"dummy\");\n\t\t\t\n\t\t\tSetMaxHp(1);\n\t\t\tRemoveTag(Tags.MustBeKilled);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar health = GetComponent<HealthComponent>();\n\n\t\t\thealth.InvincibilityTimerMax = 0;\n\t\t\thealth.RenderInvt = false;\n\n\t\t\tTouchDamage = 0;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent ev && ev.Amount < 0) {\n\t\t\t\tBecome<HurtState>();\n\t\t\t\tGraphicsComponent.Flipped = ev.From.CenterX > CenterX;\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(GetHurtSfx());\n\n\t\t\t\tif (Run.Depth < 1 && Rnd.Chance(30)) {\n\t\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\n\t\t\t\t\tif (dialog.Current == null) {\n\t\t\t\t\t\tdialog.StartAndClose($\"npc_hurt_{Rnd.Int(3)}\", 2);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\t#region Dummy States\n\t\tpublic class IdleState : EntityState {\n\t\t\t\n\t\t}\n\n\t\tpublic class HurtState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (Self.GetComponent<MobAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>(true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_dummy\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/LoopChance.cs",
    "content": "namespace BurningKnight.entity.creature.mob {\n\tpublic class LoopChance : SpawnChance {\n\t\tpublic LoopChance(float chance, params string[] areas) : base(chance, areas) {\n\t\t\tLoopOnly = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/Mimic.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic class Mimic : Slime {\n\t\tpublic string Kind;\n\t\tpublic string Pool = \"bk:wooden_chest\";\n\t\tprivate bool invoked;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 16;\n\t\t\tHeight = 13;\n\t\t\t\n\t\t\tSetMaxHp(40 + Run.Depth * 7);\n\n\t\t\tvar body = CreateBodyComponent();\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.5f;\n\n\t\t\tAddComponent(CreateSensorBodyComponent());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Kind == null) {\n\t\t\t\tKind = \"wooden_chest\";\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", Kind));\n\t\t\tGetComponent<DropsComponent>().Add(Pool);\n\n\t\t\tif (!invoked) {\n\t\t\t\tRemoveTag(Tags.MustBeKilled);\n\t\t\t\tRemoveTag(Tags.Mob);\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t\tTouchDamage = 0;\n\t\t\t\t\n\t\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\t\tCanInteract = e => !invoked\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tif (invoked) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\te.GetComponent<HealthComponent>().ModifyHealth(-2, this, DamageType.Custom);\n\t\t\tTarget = e;\n\t\t\tBecome<JumpState>();\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (!invoked && e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tBecome<JumpState>();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override TextureRegion GetDeathFrame() {\n\t\t\treturn CommonAse.Props.GetSlice($\"{Kind}_open\");\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateBodyComponent() {\n\t\t\treturn new RectBodyComponent(0, 12, 16, 1);\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateSensorBodyComponent() {\n\t\t\treturn new SensorBodyComponent(0, 0, 16, 13);\n\t\t}\n\n\t\tprotected override void OnJump() {\n\t\t\tbase.OnJump();\n\n\t\t\tvar builder = new ProjectileBuilder(this, \"circle\") {\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tif (Target == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\t\t\tvar a = AngleTo(Target) + Rnd.Float(-0.1f, 0.1f);\n\t\t\t\t\tvar projectile = builder.Shoot(a, 9f).Build();\n\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(a, 5f) - new Vector2(0, GetComponent<ZComponent>().Z);\n\t\t\t\t}, i * 0.3f);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnLand() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar am = 16;\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am);\n\t\t\t\tvar fast = i % 2 == 0;\n\n\t\t\t\tbuilder.Slice = fast ? \"small\" : \"circle\";\n\t\t\t\tvar projectile = builder.Shoot(a, fast ? 7f : 4f).Build();\n\t\t\t\t\t\n\t\t\t\tprojectile.Center = BottomCenter;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override void AnimateJump(Action callback) {\n\t\t\tvar anim = GetComponent<InteractableSliceComponent>();\n\t\t\t\t\n\t\t\tTween.To(2f, anim.Scale.X, x => anim.Scale.X = x, 0.2f);\n\t\t\tTween.To(0.3f, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tTween.To(0.5f, anim.Scale.X, x => anim.Scale.X = x, 0.3f);\n\n\t\t\t\tTween.To(2f, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f).OnEnd = () => {\n\t\t\t\t\tTween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f);\n\t\t\t\t};\n\n\t\t\t\tcallback();\n\t\t\t};\n\t\t}\n\n\t\tprotected override void AnimateLand() {\n\t\t\tvar anim = GetComponent<InteractableSliceComponent>();\n\n\t\t\tanim.Scale.X = 2f;\n\t\t\tanim.Scale.Y = 0.3f;\n\t\t\tTween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.3f);\n\t\t\tTween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tKind = stream.ReadString();\n\t\t\tinvoked = stream.ReadBoolean();\n\t\t\tPool = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteString(Kind);\n\t\t\tstream.WriteBoolean(invoked);\n\t\t\tstream.WriteString(Pool);\n\t\t}\n\n\t\tprivate class FriendlyState : SmartState<Mimic> {\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tSelf.invoked = true;\n\t\t\t\tSelf.AddTag(Tags.MustBeKilled);\n\t\t\t\tSelf.AddTag(Tags.Mob);\n\t\t\t\tSelf.TouchDamage = 1;\n\n\t\t\t\tAchievements.Unlock(\"bk:mimic\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/Mob.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.prefix;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.paintings;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.variant;\nusing BurningKnight.physics;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic class Mob : Creature, DropModifier {\n\t\tpublic Entity Target;\n\t\tpublic bool HasPrefix => prefix != null;\n\t\tpublic Prefix Prefix => prefix;\n\t\t\n\t\tprotected List<Entity> CollidingToHurt = new List<Entity>();\n\t\tprotected int TouchDamage = 1;\n\t\tprotected bool TargetEverywhere;\n\t\t\n\t\tprivate Prefix prefix;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new AimComponent(AimComponent.AimType.Target));\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddTag(Tags.Mob);\n\t\t\tAddTag(Tags.MustBeKilled);\n\t\t\t\n\t\t\tSetStats();\n\t\t\t\n\t\t\tAddDrops(new SingleDrop(\"bk:coin\", LevelSave.GenerateShops ? 0.2f : 0.12f));\n\t\t\tAddDrops(new SingleDrop(\"bk:bomb\", 0.03f));\n\n\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\th.InvincibilityTimerMax = 0.3f;\n\t\t\th.PreventDamageInInvincibility = false;\n\n\t\t\tif (!(this is Boss)) {\n\t\t\t\tGetComponent<StateComponent>().Pause++;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Run.Level?.Variant is SnowLevelVariant || Run.Level?.Biome is IceBiome) {\n\t\t\t\tGetComponent<BuffsComponent>().AddImmunity<FrozenBuff>();\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void SetStats() {\n\t\t\t\n\t\t}\n\n\t\tprotected void AddAnimation(string name, string layer = null) {\n\t\t\tAddComponent(new MobAnimationComponent(name, layer));\n\t\t}\n\t\t\n\t\tprotected virtual void SetMaxHp(int hp) {\n\t\t\tif (Run.Loop > 0 && !(this is DM)) {\n\t\t\t\thp *= (this is Boss ? 4 : 1) * (Run.Loop + 1);\n\t\t\t}\n\t\t\n\t\t\tvar health = GetComponent<HealthComponent>();\n\t\t\thealth.InitMaxHealth = hp;\n\t\t}\n\n\t\tprotected virtual void OnTargetChange(Entity target) {\n\t\t\tif (target == null) {\n\t\t\t\tGetComponent<StateComponent>().PauseOnChange = true;\n\t\t\t} else {\n\t\t\t\tGetComponent<StateComponent>().PauseOnChange = false;\n\t\t\t\tGetComponent<StateComponent>().Pause = 0;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate float lastParticle;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (prefix != null) {\n\t\t\t\tprefix.Update(dt);\n\n\t\t\t\tlastParticle -= dt;\n\n\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\tlastParticle = Rnd.Float(0.05f, 0.3f);\n\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(0, 3); i++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Scourge());\n\n\t\t\t\t\t\tpart.Position = Center + Rnd.Vector(-4, 4);\n\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.5f, 1.2f);\n\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Target == null) {\n\t\t\t\tFindTarget();\n\t\t\t} else if (Target.Done || Target.GetComponent<RoomComponent>().Room != GetComponent<RoomComponent>().Room ||\n\t\t\t           (Target is Creature c && c.IsFriendly() == IsFriendly()) || \n\t\t\t           (Target.TryGetComponent<BuffsComponent>(out var b) && b.Has<InvisibleBuff>())) {\n\n\t\t\t\tvar old = Target;\n\n\t\t\t\tHandleEvent(new MobTargetChange {\n\t\t\t\t\tMob = this,\n\t\t\t\t\tNew = null,\n\t\t\t\t\tOld = old \n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tFindTarget();\n\t\t\t}\n\n\t\t\tif (TouchDamage == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar raging = GetComponent<BuffsComponent>().Has<RageBuff>();\n\t\t\t\n\t\t\tfor (var i = CollidingToHurt.Count - 1; i >= 0; i--) {\n\t\t\t\tvar entity = CollidingToHurt[i];\n\n\t\t\t\tif (entity.Done) {\n\t\t\t\t\tCollidingToHurt.RemoveAt(i);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ((!(entity is Creature c) || c.IsFriendly() != IsFriendly())) {\n\t\t\t\t\tif (entity.GetComponent<HealthComponent>().ModifyHealth(-TouchDamage * (raging ? 2 : 1), this, DamageType.Contact)) {\n\t\t\t\t\t\tOnHit(entity);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (GetComponent<RoomComponent>().Room == null) {\n\t\t\t\tKill(null);\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void OnHit(Entity e) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (prefix != null && prefix.HandleEvent(e)) {\n\t\t\t\te.Handled = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (e is BuffAddedEvent add && add.Buff is CharmedBuff || e is BuffRemovedEvent del && del.Buff is CharmedBuff) {\n\t\t\t\t// If old target even was a thing, it was from wrong category\n\t\t\t\tFindTarget();\n\t\t\t} else if (e is CollisionStartedEvent collisionStart) {\n\t\t\t\tif (collisionStart.Entity.HasComponent<HealthComponent>() && CanHurt(collisionStart.Entity)) {\n\t\t\t\t\tCollidingToHurt.Add(collisionStart.Entity);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent collisionEnd) {\n\t\t\t\tif (collisionEnd.Entity.HasComponent<HealthComponent>()) {\n\t\t\t\t\tCollidingToHurt.Remove(collisionEnd.Entity);\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent de) {\n\t\t\t\tvar who = de.From;\n\t\t\t\t\n\t\t\t\tif (de.From != null) {\n\t\t\t\t\tif (de.From.TryGetComponent<OwnerComponent>(out var o)) {\n\t\t\t\t\t\twho = o.Owner;\n\t\t\t\t\t} else if (who is Projectile p) {\n\t\t\t\t\t\twho = p.Owner;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (who is Player && who.GetComponent<LampComponent>().Item?.Id == \"bk:explosive_lamp\") {\n\t\t\t\t\tAddDrops(new SimpleDrop(1f, 1, 1, \"bk:bomb\"));\n\t\t\t\t}\n\n\t\t\t\tif (!de.BlockClear) {\n\t\t\t\t\tGetComponent<RoomComponent>().Room?.CheckCleared(who);\n\t\t\t\t}\n\t\t\t} else if (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tif (!(this is bk.BurningKnight) && TryGetComponent<RoomComponent>(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (!rotationApplied) {\n\t\t\t\t\trotationApplied = true;\n\t\t\t\t\tvar a = GetAnyComponent<AnimationComponent>();\n\t\t\t\t\n\t\t\t\t\tif (a != null) {\n\t\t\t\t\t\tvar w = a.Angle;\n\t\t\t\t\t\ta.Angle += 0.5f;\n\n\t\t\t\t\t\tvar t = Tween.To(w, a.Angle, x => a.Angle = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tt.Delay = 0.2f;\n\t\t\t\t\t\tt.OnEnd = () => {\n\t\t\t\t\t\t\trotationApplied = false;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is TileCollisionStartEvent tce) {\n\t\t\t\tif (tce.Tile == Tile.Cobweb) {\n\t\t\t\t\tvar body = GetAnyComponent<BodyComponent>();\n\t\t\t\t\twasSlow = body.Slow;\n\t\t\t\t\tbody.Slow = true;\n\t\t\t\t}\n\t\t\t} else if (e is TileCollisionEndEvent tee) {\n\t\t\t\tif (tee.Tile == Tile.Cobweb) {\n\t\t\t\t\tvar body = GetAnyComponent<BodyComponent>();\n\n\t\t\t\t\tif (!wasSlow && body.Slow && !GetComponent<BuffsComponent>().Has<SlowBuff>()) {\n\t\t\t\t\t\tbody.Slow = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}  \n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool wasSlow;\n\n\t\tprotected virtual bool CanHurt(Entity entity) {\n\t\t\treturn !(entity is BreakableProp || entity is Painting || entity is Prop);\n\t\t}\n\n\t\tprotected void FindTarget() {\n\t\t\tList<Entity> targets;\n\n\t\t\tif (TargetEverywhere) {\n\t\t\t\ttargets = Area.Tagged[IsFriendly() ? Tags.Mob : Tags.PlayerTarget];\n\t\t\t} else {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\n\t\t\t\ttargets = room.Tagged[IsFriendly() ? Tags.Mob : Tags.PlayerTarget];\n\t\t\t}\n\t\t\t\n\t\t\tvar closestDistance = float.MaxValue;\n\t\t\tvar friendly = IsFriendly();\n\t\t\t\n\t\t\tEntity closest = null;\n\t\t\t\n\t\t\tforeach (var target in targets) {\n\t\t\t\tif (target == this || target is bk.BurningKnight || ((Creature) target).IsFriendly() == friendly || \n\t\t\t\t    (target.TryGetComponent<BuffsComponent>(out var b) && b.Has<InvisibleBuff>())) {\n\t\t\t\t\t\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar d = target.DistanceToSquared(this);\n\n\t\t\t\tif (d < closestDistance) {\n\t\t\t\t\tclosestDistance = d;\n\t\t\t\t\tclosest = target;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Target != closest) {\n\t\t\t\tHandleEvent(new MobTargetChange {\n\t\t\t\t\tMob = this,\n\t\t\t\t\tNew = closest,\n\t\t\t\t\tOld = Target \n\t\t\t\t});\n\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Might be null, thats ok\n\t\t\tTarget = closest;\n\t\t\tOnTargetChange(closest);\n\t\t}\n\n\t\tpublic override bool IsFriendly() {\n\t\t\treturn GetComponent<BuffsComponent>().Has<CharmedBuff>();\n\t\t}\n\n\t\tprivate bool rotationApplied;\n\n\t\tpublic override void AnimateDeath(DiedEvent d) {\n\t\t\tbase.AnimateDeath(d);\n\t\t\tCreateGore(d);\n\t\t}\n\n\t\t#region Path finding\n\t\tprotected Vec2 NextPathPoint;\n\t\tprivate int lastStepBack;\n\t\tprivate int prevStepBack;\n\n\t\tprivate void BuildPath(Vector2 to, bool back = false) {\n\t\t\tvar level = Run.Level;\n\t\t\tvar fp = level.ToIndex((int) Math.Floor(CenterX / 16f), (int) Math.Floor(Bottom / 16f));\n\t\t\tvar tp = level.ToIndex((int) Math.Floor(to.X / 16f), (int) Math.Floor(to.Y / 16f));\n\n\t\t\tvar p = back ? PathFinder.GetStepBack(fp, tp, level.Passable, prevStepBack) : PathFinder.GetStep(fp, tp, level.Passable);\n\n\t\t\tif (back) {\n\t\t\t\tprevStepBack = lastStepBack;\n\t\t\t\tlastStepBack = p;\n\t\t\t}\n\t\t\t\n\t\t\tif (p == -1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tNextPathPoint = new Vec2 {\n\t\t\t\tX = level.FromIndexX(p) * 16 + 8, \n\t\t\t\tY = level.FromIndexY(p) * 16 + 8\n\t\t\t};\n\t\t}\n\t\t\n\t\tpublic bool MoveTo(Vector2 point, float speed, float distance = 8f, bool back = false) {\n\t\t\tif (!back) {\n\t\t\t\tvar ds = DistanceToFromBottom(point);\n\n\t\t\t\tif (ds <= distance) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar ds = DistanceToFromBottom(point);\n\n\t\t\t\tif (ds >= distance) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (NextPathPoint == null) {\n\t\t\t\tBuildPath(point, back);\n\n\t\t\t\tif (NextPathPoint == null) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar dx = NextPathPoint.X - CenterX;\n\t\t\tvar dy = NextPathPoint.Y - Bottom;\n\t\t\tvar d = (float) Math.Sqrt(dx * dx + dy * dy);\n\n\t\t\tif (d <= 2f) {\n\t\t\t\tNextPathPoint = null;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tspeed *= Engine.Delta * 60;\n\t\t\tGetAnyComponent<BodyComponent>().Velocity = new Vector2(dx / d * speed, dy / d * speed);\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool FlyTo(Vector2 point, float speed, float distance = 8f) {\n\t\t\tvar dx = DxTo(point);\n\t\t\tvar dy = DyTo(point);\n\t\t\tvar d = (float) Math.Sqrt(dx * dx + dy * dy);\n\n\t\t\tif (d <= distance) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tGetAnyComponent<BodyComponent>().Velocity = new Vector2(dx / d * speed, dy / d * speed);\n\n\t\t\treturn false;\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tvar str = stream.ReadString();\n\n\t\t\tif (str != null) {\n\t\t\t\tSetPrefix(str);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(prefix?.Id);\n\t\t}\n\n\t\tpublic void GeneratePrefix() {\n\t\t\tif (!Rnd.Chance(Run.Scourge * 10 + 0.5f)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar all = PrefixRegistry.Defined.Keys.ToArray();\n\t\t\tSetPrefix(all[Rnd.Int(all.Length)]);\n\t\t}\n\n\t\tpublic void SetPrefix(string id) {\n\t\t\tif (!PrefixRegistry.Defined.TryGetValue(id, out var t)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tvar p = (Prefix) Activator.CreateInstance(t);\n\n\t\t\t\tprefix = p;\n\t\t\t\t\n\t\t\t\tp.Id = id;\n\t\t\t\tp.Mob = this;\n\t\t\t\tp.Init();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\t\n\t\t\tImGui.Text($\"Target: {(Target == null ? \"null\" : Target.GetType().Name)}\");\n\n\t\t\tif (Target != null) {\n\t\t\t\tif (ImGui.Button(\"Jump\")) {\n\t\t\t\t\tWindowManager.Entities = true;\n\t\t\t\t\tAreaDebug.ToFocus = Target;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Text($\"Prefix: {(Prefix == null ? \"null\" : Prefix.Id)}\");\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tbase.RenderDebug();\n\n\t\t\tif (NextPathPoint != null) {\n\t\t\t\tGraphics.Batch.DrawLine(CenterX, Bottom, NextPathPoint.X, NextPathPoint.Y, Color.Red);\n\t\t\t\tGraphics.Batch.DrawLine(CenterX, Bottom, Run.Level.FromIndexX(prevStepBack) * 16 + 8, Run.Level.FromIndexY(prevStepBack) * 16 + 8, Color.Blue);\n\t\t\t}\n\t\t}\n\n\t\tprivate static bool RayShouldCollide(Entity entity) {\n\t\t\treturn entity is ProjectileLevelBody;\n\t\t}\n\n\t\tprotected bool CanSeeTarget() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tvar min = 1f;\n\t\t\tvar found = false;\n\t\t\t\n\t\t\tPhysics.World.RayCast((fixture, point, normal, fraction) => {\n\t\t\t\tif (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) {\n\t\t\t\t\tmin = fraction;\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn min;\n\t\t\t}, Center, Target.Center);\n\n\t\t\treturn !found;\n\t\t}\n\t\t\n\t\tprotected void TurnToTarget() {\n\t\t\tif (Target != null) {\n\t\t\t\tGraphicsComponent.Flipped = Target.CenterX < CenterX;\n\t\t\t}\n\t\t}\n\n\t\tprotected void PushFromOtherEnemies(float dt, Func<Creature, bool> filter = null) {\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\t\t\tvar body = GetAnyComponent<BodyComponent>();\n\n\t\t\tif (room == null || body == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var m in room.Tagged[Tags.Mob]) {\n\t\t\t\tif (m == this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar mob = (Creature) m;\n\t\t\t\t\n\t\t\t\tif (filter != null && !filter(mob)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = DxTo(mob);\n\t\t\t\tvar dy = DyTo(mob);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\tvar force = dt * 800;\n\t\t\t\t\n\t\t\t\tif (d <= 8) {\n\t\t\t\t\tvar a = MathUtils.Angle(dx, dy) - (float) Math.PI;\n\t\t\t\t\tbody.Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected void PushOthersFromMe(float dt, Func<Creature, bool> filter = null) {\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var m in room.Tagged[Tags.Mob]) {\n\t\t\t\tif (m == this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar mob = (Creature) m;\n\n\t\t\t\tif (filter != null && !filter(mob)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = DxTo(mob);\n\t\t\t\tvar dy = DyTo(mob);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\tvar force = dt * 800;\n\n\t\t\t\tif (d <= 12) {\n\t\t\t\t\tvar a = MathUtils.Angle(dx, dy) - (float) Math.PI;\n\t\t\t\t\tvar b = mob.GetAnyComponent<BodyComponent>();\n\n\t\t\t\t\tif (b != null) {\n\t\t\t\t\t\tb.Velocity -= new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void ModifyDrops(List<Item> drops) {\n\t\t\tif (Rnd.Chance(Run.Scourge * 0.5f)) {\n\t\t\t\tvar c = Rnd.Int(0, 3);\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\tdrops.Add(Items.Create(\"bk:copper_coin\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tif (p.GetComponent<LampComponent>().Item?.Id == \"bk:explosive_lamp\") {\n\t\t\t\t\tdrops.Add(Items.Create(\"bk:bomb\"));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/MobInfo.cs",
    "content": "﻿using System;\nusing BurningKnight.state;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic class MobInfo {\n\t\tpublic Type Type;\n\t\tpublic SpawnChance[] Spawns;\n\t\tpublic bool SpawnsOnFirst = true;\n\t\tpublic bool NearWall;\n\t\tpublic bool Single;\n\t\tpublic bool AwayFromWall;\n\t\tpublic float Weight = 1;\n\t\tpublic float Chance = 1;\n\n\t\tpublic static MobInfo New<T>(params SpawnChance[] spawns) where T : Mob {\n\t\t\treturn new MobInfo {\n\t\t\t\tType = typeof(T),\n\t\t\t\tSpawns = spawns\n\t\t\t};\n\t\t}\n\t\t\n\t\tpublic MobInfo MarkSingle() {\n      Single = true;\n      return this;\n\t\t}\n\t\t\n\t\tpublic MobInfo SetWeight(float weight) {\n\t    Weight = weight;\n\t    return this;\n\t\t}\n\t\t\n\t\tpublic MobInfo SetSpawnChance(float chance) {\n\t\t\tChance = chance;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic MobInfo RequiresNearWall() {\n\t\t\tNearWall = true;\n\t\t\tAwayFromWall = false;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic MobInfo HatesWall() {\n\t\t\tNearWall = false;\n\t\t\tAwayFromWall = true;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic MobInfo DisableFirstSpawn() {\n\t\t\tSpawnsOnFirst = false;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic bool SpawnsIn(string biome) {\n\t\t\treturn GetChanceFor(biome) != null;\n\t\t}\n\n\t\tpublic SpawnChance GetChanceFor(string biome) {\n\t\t\tforeach (var b in Spawns) {\n\t\t\t\tforeach (var a in b.Areas) {\n\t\t\t\t\tif (a == biome && (!b.LoopOnly || Run.Loop > 0)) {\n\t\t\t\t\t\treturn b;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/MobPair.cs",
    "content": "namespace BurningKnight.entity.creature.mob {\n\tpublic class MobPair {\n\t\tpublic int Count;\n\t\tpublic string Id;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/MobRegistry.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.creature.mob.cave;\nusing BurningKnight.entity.creature.mob.desert;\nusing BurningKnight.entity.creature.mob.ice;\nusing BurningKnight.entity.creature.mob.jungle;\nusing BurningKnight.entity.creature.mob.library;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing Lens.util.math;\nusing Buffer = BurningKnight.entity.creature.mob.library.Buffer;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic static class MobRegistry {\n\t\tpublic static List<MobInfo> All = new List<MobInfo>();\n\t\tpublic static List<MobInfo> Current = new List<MobInfo>();\n\t\t\n\t\tstatic MobRegistry() {\n\t\t\tMobInfo[] infos = {\n\t\t\t\t// XD\n\t\t\t\tMobInfo.New<Dummy>(new SpawnChance(0.1f, Biome.Castle)).SetSpawnChance(0.5f),\n\t\t\t\t// Castle\n\t\t\t\tMobInfo.New<Ghost>(new SpawnChance(1f, Biome.Castle)),\n\t\t\t\tMobInfo.New<Rat>(new SpawnChance(0.5f, Biome.Castle)),\n\t\t\t\tMobInfo.New<Crab>(new SpawnChance(0.7f, Biome.Castle)),\n\t\t\t\tMobInfo.New<WallCrawler>(new SpawnChance(0.5f + 3f, Biome.Castle)).RequiresNearWall(),\n\t\t\t\tMobInfo.New<SimpleSlime>(new SpawnChance(1f, Biome.Castle), new SpawnChance(0.5f, Biome.Cave)),\n\t\t\t\tMobInfo.New<MotherSlime>(new SpawnChance(0.5f, Biome.Castle)).MarkSingle(),\n\t\t\t\tMobInfo.New<BigSlime>(new SpawnChance(0.1f, Biome.Castle)),\n\n\t\t\t\tMobInfo.New<Bandit>(new SpawnChance(1f, Biome.Castle)).DisableFirstSpawn(),\n\t\t\t\tMobInfo.New<Gunner>(new SpawnChance(0.1f, Biome.Castle)).DisableFirstSpawn().SetWeight(3f),\n\t\t\t\tMobInfo.New<BulletSlime>(new SpawnChance(2f, Biome.Castle)).DisableFirstSpawn(),\n\t\t\t\tMobInfo.New<BlueBulletSlime>(new SpawnChance(0.1f, Biome.Castle)).DisableFirstSpawn().SetWeight(2f),\n\t\t\t\tMobInfo.New<Clown>(new SpawnChance(2f, Biome.Castle)).DisableFirstSpawn(),\n\n\t\t\t\t// Desert\n\t\t\t\tMobInfo.New<Bandit>(new SpawnChance(1f, Biome.Desert, Biome.Jungle)).SetWeight(0.5f),\n\t\t\t\tMobInfo.New<Gunner>(new SpawnChance(0.8f, Biome.Desert)).SetWeight(2f),\n\t\t\t\tMobInfo.New<DesertSlime>(new SpawnChance(0.7f, Biome.Desert)).SetWeight(1.5f),\n\t\t\t\tMobInfo.New<Maggot>(new SpawnChance(1f, Biome.Desert)).RequiresNearWall(),\n\t\t\t\tMobInfo.New<Mummy>(new SpawnChance(1f, Biome.Desert)),\n\t\t\t\tMobInfo.New<Worm>(new SpawnChance(1f, Biome.Desert)),\n\t\t\t\tMobInfo.New<Crab>(new SpawnChance(0.5f, Biome.Desert)),\n\t\t\t\tMobInfo.New<Spelunker>(new SpawnChance(1f, Biome.Desert), new LoopChance(1f, Biome.Castle)),\n\t\t\t\tMobInfo.New<Fly>(new SpawnChance(1f, Biome.Desert), new LoopChance(1f, Biome.Castle)),\n\t\t\t\t\n\t\t\t\tMobInfo.New<DesertBulletSlime>(new SpawnChance(1f, Biome.Desert)).DisableFirstSpawn().SetWeight(2f).MarkSingle(),\n\t\t\t\tMobInfo.New<MegaSlime>(new SpawnChance(1f, Biome.Desert)).DisableFirstSpawn().SetWeight(2f).MarkSingle(),\n\t\t\t\t// MobInfo.New<Cactus>(new SpawnChance(0f, Biome.Desert)).DisableFirstSpawn(),\n\t\t\t\t\n\t\t\t\t// Jungle\n\t\t\t\tMobInfo.New<Sniper>(new SpawnChance(1f, Biome.Jungle), new LoopChance(1f, Biome.Desert)),\n\t\t\t\tMobInfo.New<BeeHive>(new SpawnChance(100.5f, Biome.Jungle)).MarkSingle().SetWeight(3f).HatesWall(),\n\t\t\t\tMobInfo.New<Bee>(new SpawnChance(0.3f, Biome.Jungle)),\n\t\t\t\tMobInfo.New<Explobee>(new SpawnChance(0.15f, Biome.Jungle)),\n\t\t\t\tMobInfo.New<Wombat>(new SpawnChance(0.7f, Biome.Jungle), new LoopChance(1f, Biome.Desert)).SetWeight(2f).MarkSingle(),\n\t\t\t\tMobInfo.New<Flower>(new SpawnChance(1f, Biome.Jungle)).SetWeight(2f).HatesWall(),\n\t\t\t\t\n\t\t\t\tMobInfo.New<BuffedFlower>(new SpawnChance(1f, Biome.Jungle)).SetWeight(2f).DisableFirstSpawn().HatesWall(),\n\t\t\t\t\n\t\t\t\t// Ice\n\t\t\t\tMobInfo.New<CupGuy>(new SpawnChance(1f, Biome.Ice), new LoopChance(1f, Biome.Jungle)),\n\t\t\t\tMobInfo.New<Snowman>(new SpawnChance(1f, Biome.Ice)).SetSpawnChance(0.5f).HatesWall(),\n\t\t\t\tMobInfo.New<Snowball>(new SpawnChance(1f, Biome.Ice)).SetWeight(0.5f),\n\t\t\t\tMobInfo.New<IceCrawler>(new SpawnChance(1f, Biome.Ice)).RequiresNearWall(),\n\t\t\t\tMobInfo.New<Snowflake>(new SpawnChance(0.5f, Biome.Ice)).SetSpawnChance(0.5f),\n\t\t\t\tMobInfo.New<BigSnowball>(new SpawnChance(1f, Biome.Ice)),\n\t\t\t\t\n\t\t\t\tMobInfo.New<Sponge>(new SpawnChance(1f, Biome.Ice)).MarkSingle().HatesWall().DisableFirstSpawn(),\n\t\t\t\tMobInfo.New<Dino>(new SpawnChance(1f, Biome.Ice)).SetWeight(3f).DisableFirstSpawn(),\n\t\t\t\t\n\t\t\t\t// Library\n\t\t\t\tMobInfo.New<Book>(new SpawnChance(1f, Biome.Library)).HatesWall().SetWeight(2.5f),\n\t\t\t\tMobInfo.New<TeleportingMage>(new SpawnChance(1f, Biome.Library)).HatesWall(),\n\t\t\t\tMobInfo.New<Skeleton>(new SpawnChance(1f, Biome.Library)).SetSpawnChance(0.5f),\n\t\t\t\tMobInfo.New<Buffer>(new SpawnChance(1f, Biome.Library), new LoopChance(1f, Biome.Jungle), new LoopChance(1f, Biome.Ice)).MarkSingle(),\n\t\t\t\tMobInfo.New<DesertSlime>(new SpawnChance(1f, Biome.Library)),\n\t\t\t\tMobInfo.New<DesertBulletSlime>(new SpawnChance(1f, Biome.Library)),\n\t\t\t\t\n\t\t\t\t// Tech for dm fight\n\t\t\t\tMobInfo.New<DesertBulletSlime>(new SpawnChance(1f, Biome.Tech)),\n\t\t\t\tMobInfo.New<Book>(new SpawnChance(1f, Biome.Tech)).HatesWall(),\n\t\t\t\tMobInfo.New<IceCrawler>(new SpawnChance(1f, Biome.Tech)).RequiresNearWall(),\n\t\t\t\tMobInfo.New<Dino>(new SpawnChance(1f, Biome.Tech)),\n\t\t\t\tMobInfo.New<Gunner>(new SpawnChance(2f, Biome.Tech)),\n\t\t\t\t\n\t\t\t\t// Caves\n\t\t\t\tMobInfo.New<Thief>(new SpawnChance(1f, Biome.Cave)),\n\t\t\t\tMobInfo.New<EmeraldGunner>(new SpawnChance(1f, Biome.Cave)).SetWeight(2f),\n\t\t\t\tMobInfo.New<Broco>(new SpawnChance(1f, Biome.Cave)),\n\t\t\t};\n\t\t\t\n\t\t\tAll.AddRange(infos);\n\t\t}\n\n\t\tpublic static MobInfo FindFor(Type type) {\n\t\t\tforeach (var info in All) {\n\t\t\t\tif (info.Type == type) {\n\t\t\t\t\treturn info;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic static Mob Generate() {\n\t\t\tvar chances = new float[Current.Count];\n\n\t\t\tfor (var i = 0; i < Current.Count; i++) {\n\t\t\t\tif (Current[i].Type == typeof(BeeHive)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tchances[i] = Current[i].GetChanceFor(Run.Level.Biome.Id).Chance;\n\t\t\t}\n\n\t\t\tvar types = new List<MobInfo>();\n\t\t\tvar spawnChances = new List<float>();\n\n\t\t\tfor (int i = 0; i < Rnd.Int(2, 6); i++) {\n\t\t\t\tvar type = Current[Rnd.Chances(chances)];\n\t\t\t\tvar found = false;\n\t\t\t\t\n\t\t\t\tforeach (var t in types) {\n\t\t\t\t\tif (t == type) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (found) {\n\t\t\t\t\ti--;\n\t\t\t\t} else {\n\t\t\t\t\ttypes.Add(type);\n\t\t\t\t\tspawnChances.Add(type.Chance);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (types.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn (Mob) Activator.CreateInstance(types[Rnd.Chances(spawnChances)].Type);\n\t\t}\n\n\t\tpublic static void SetupForBiome(string biome) {\n\t\t\tCurrent.Clear();\n\n\t\t\tforeach (var info in All) {\n\t\t\t\tif (info.SpawnsIn(biome) && (info.SpawnsOnFirst || Run.Depth % 2 == 0)) {\n\t\t\t\t\tCurrent.Add(info);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Remove<T>() where T : Mob {\n\t\t\tvar type = typeof(T);\n\t\t\tMobInfo i = null; \n\t\t\t\n\t\t\tforeach (var info in All) {\n\t\t\t\tif (info.Type == type) {\n\t\t\t\t\ti = info;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (i != null) {\n\t\t\t\tAll.Remove(i);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/MobSpawnInfo.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob {\n\tpublic struct MobSpawnInfo {\n\t\tpublic Vector2 Position;\n\t\tpublic Type Type;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/SpawnChance.cs",
    "content": "﻿namespace BurningKnight.entity.creature.mob {\n\tpublic class SpawnChance {\n\t\tpublic float Chance;\n\t\tpublic string[] Areas;\n\t\tpublic bool LoopOnly;\n\n\t\tpublic SpawnChance(float chance, params string[] areas) {\n\t\t\tChance = chance;\n\t\t\tAreas = areas;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/BkHead.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.creature.mob.desert;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.cutscene.entity;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.pattern;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class BkHead : Boss {\n\t\tpublic bool CanBeSaved => GetComponent<HealthComponent>().Percent <= 0.2f;\n\t\t\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\tHealthBar.AddPhase(0.2f);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new BkGraphicsComponent(\"demon\"));\n\t\t\tAddComponent(new RectBodyComponent(2, 4, 12, 15, BodyType.Dynamic, true));\n\t\t\tAddComponent(new AimComponent(AimComponent.AimType.Target));\n\n\t\t\tvar b = GetComponent<RectBodyComponent>();\n\t\t\tb.Body.LinearDamping = 2;\n\t\t\tb.KnockbackModifier = 0;\n\t\t\t\n\t\t\tSetMaxHp(600);\n\n\t\t\tDepth = Layers.FlyingMob;\n\t\t\tAwoken = true;\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target != null) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"head_0\", 2f);\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}, 1);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\t\t\t\n\t\t\tif (Target != null && !Died) {\n\t\t\t\tvar force = 40f * dt;\n\t\t\t\tvar a = AngleTo(Target);\n\n\t\t\t\tGetComponent<RectBodyComponent>().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\n\t\tprivate int counter;\n\n\t\tprivate void WarnLaser(float angle, Vector2? offset = null) {\n\t\t\tvar builder = new ProjectileBuilder(this, \"circle\") {\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\tvar projectile = builder.Shoot(angle, 20f).Build();\n\n\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\n\t\t\tif (offset != null) {\n\t\t\t\tprojectile.Center += offset.Value;\n\t\t\t}\n\t\t}\n\n\t\t#region Demon States\n\t\tprivate class IdleState : SmartState<BkHead> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.TouchDamage = 2;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T <= 1f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (Self.counter) {\n\t\t\t\t\tcase 0: {\n\t\t\t\t\t\tBecome<LaserSnipeState>();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 1: {\n\t\t\t\t\t\tBecome<LaserSwingAttack>();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 2: {\n\t\t\t\t\t\tBecome<BulletHellState>();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 3: {\n\t\t\t\t\t\tBecome<SpawnAttack>();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 4: {\n\t\t\t\t\t\tBecome<MissileState>();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSelf.counter = (Self.counter + 1) % 5;\n\t\t\t}\n\t\t}\n\n\t\tprivate class LaserSnipeState : SmartState<BkHead> {\n\t\t\tprivate float delay;\n\t\t\tprivate int count;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tdelay -= dt;\n\t\t\t\t\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tif (count >= 3) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdelay = 0.5f;\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\t\t\t\t\tSelf.WarnLaser(a);\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\t\t\t\t\t\tvar laser = Laser.Make(Self, a, 0, damage: 2, scale: 3, range: 64);\n\t\t\t\t\t\tlaser.LifeTime = 1f;\n\t\t\t\t\t\tlaser.Position = Self.Center;\n\t\t\t\t\t\tSelf.GetComponent<BkGraphicsComponent>().Animate();\n\t\t\t\t\t}, 0.2f);\n\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate class BulletHellState : SmartState<BkHead> {\n\t\t\tprivate float sinceLast;\n\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tsinceLast -= dt;\n\n\t\t\t\tif (sinceLast <= 0) {\n\t\t\t\t\tsinceLast = 0.5f; // Self.InFirstPhase ? 0.5f : 0.3f;\n\t\t\t\t\tvar amount = 8;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tvar a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 2f) * Math.PI) * (i % 2 == 0 ? -1 : 1);\n\t\t\t\t\t\tvar projectile = builder.Shoot(a, 8f + (float) Math.Cos(Self.t * 2f) * 3f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tprojectile.Color = ProjectileColor.DesertRainbow[Rnd.Int(ProjectileColor.DesertRainbow.Length)];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tSelf.GetComponent<BkGraphicsComponent>().Animate();\n\t\t\t\t}\n\n\t\t\t\tif (T >= 5f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate class MissileState : SmartState<BkHead> {\n\t\t\tprivate const int SmallCount = 8;\n\t\t\tprivate const int InnerCount = 8;\n\t\t\t\n\t\t\tprivate float delay;\n\t\t\tprivate int count;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tdelay -= dt;\n\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tif (count >= 5f) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdelay = 3f;\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tSelf.GetComponent<BkGraphicsComponent>().Animate();\n\n\t\t\t\t\tvar m = new Missile(Self, Self.Target);\n\t\t\t\t\tSelf.Area.Add(m);\n\n\t\t\t\t\tm.HurtOwner = false;\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(m, (p, e, t) => {\n\t\t\t\t\t\tvar bb = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\t\t\tbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tfor (var i = 0; i < SmallCount; i++) {\n\t\t\t\t\t\t\tvar an = (float) (((float) i) / SmallCount * Math.PI * 2);\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar pp = new ProjectilePattern(CircleProjectilePattern.Make(6.5f, 10 * (i % 2 == 0 ? 1 : -1))) {\n\t\t\t\t\t\t\t\tPosition = p.Center\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tfor (var j = 0; j < 5; j++) {\n\t\t\t\t\t\t\t\tpp.Add(bb.Build());\n\t\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\t\tpp.Launch(an, 40);\n\t\t\t\t\t\t\tSelf.Area.Add(pp);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar aa = Self.AngleTo(Self.Target);\n\t\t\t\t\t\tvar bbb = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\tColor = ProjectileColor.Orange\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tfor (var i = 0; i < InnerCount; i++) {\n\t\t\t\t\t\t\tbbb.Scale = Rnd.Float(0.5f, 1f);\n\t\t\t\t\t\t\tvar b = bbb.Shoot(aa + Rnd.Float(-0.3f, 0.3f), Rnd.Float(2, 12)).Build();\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tb.Center = p.Center;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class SpawnAttack : SmartState<BkHead> {\n\t\t\tprivate int count;\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tcount = Rnd.Int(4, 10);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tdelay -= dt;\n\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tdelay = 0.3f;\n\t\t\t\t\tSelf.GetComponent<BkGraphicsComponent>().Animate();\n\n\t\t\t\t\tvar angle = Rnd.AnglePI() * 0.5f + count * (float) Math.PI;\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"big\") {\n\t\t\t\t\t\tColor = ProjectileColor.Orange,\n\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tvar projectile = builder.Shoot(angle, 15f).Build();\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => {\n\t\t\t\t\t\tvar x = (int) Math.Floor(p.CenterX / 16);\n\t\t\t\t\t\tvar y = (int) Math.Floor(p.CenterY / 16);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar mob = Rnd.Chance(40) ? (Mob) new DesertBulletSlime() : new Gunner();\n\t\t\t\t\t\tSelf.Area.Add(mob);\n\t\t\t\t\t\tmob.X = x * 16;\n\t\t\t\t\t\tmob.Y = y * 16 - 8;\n\t\t\t\t\t\tmob.GeneratePrefix();\n\t\t\t\t\t\tAnimationUtil.Poof(mob.Center, 1);\n\t\t\t\t\t});\n\n\t\t\t\t\tcount--;\n\n\t\t\t\t\tif (count <= 0) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class LaserSwingAttack : SmartState<BkHead> {\n\t\t\tprivate class Data {\n\t\t\t\tpublic Laser Laser;\n\t\t\t\tpublic float Vy;\n\t\t\t\tpublic float Angle;\n\t\t\t}\n\n\t\t\tprivate Data[] data = new Data[2];\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\t\tvar angle = a - (i == 0 ? -1 : 1) * 1.2f;\n\t\t\t\t\tSelf.WarnLaser(angle);\n\n\t\t\t\t\tdata[i] = new Data();\n\t\t\t\t\tdata[i].Angle = angle;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T < 0.4f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar made = false;\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\t\tvar info = data[i];\n\t\t\t\t\t\n\t\t\t\t\tif (info.Laser == null) {\n\t\t\t\t\t\tinfo.Laser = Laser.Make(Self, 0, 0, damage: 2, scale: 3, range: 64);\n\t\t\t\t\t\tinfo.Laser.LifeTime = 10f;\n\t\t\t\t\t\tinfo.Laser.Angle = info.Angle;\n\n\t\t\t\t\t\tif (!made) {\n\t\t\t\t\t\t\tmade = true;\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tLog.Info(\"made laser\");\n\t\t\t\t\t} else if (info.Laser.Done) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tinfo.Laser.Position = Self.Center;\n\n\t\t\t\t\tvar aa = info.Laser.Angle;\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\n\t\t\t\t\tinfo.Vy += (float) MathUtils.ShortAngleDistance(aa, a) * dt * 4;\n\t\t\t\t\tinfo.Laser.Angle += info.Vy * dt * 0.5f;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class TeleportState : SmartState<BkHead> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tTween.To(0, 255, x => Self.GetComponent<BkGraphicsComponent>().Tint.A = (byte) x, 0.5f).OnEnd = () => {\n\t\t\t\t\tvar tile = Self.GetComponent<RoomComponent>().Room.GetRandomFreeTile() * 16;\n\n\t\t\t\t\tSelf.BottomCenter = tile + new Vector2(8, 8); \n\n\t\t\t\t\tTween.To(255, 0, x => Self.GetComponent<BkGraphicsComponent>().Tint.A = (byte) x, 0.5f).OnEnd = () => {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tif (saved) {\n\t\t\t\tbase.PlaceRewards();\n\t\t\t} else {\n\t\t\t\tResetCam = false;\n\t\t\t}\n\t\t\t\n\t\t\tAchievements.Unlock(\"bk:bk_no_more\");\n\t\t}\n\n\t\tprotected override TextureRegion GetDeathFrame() {\n\t\t\treturn CommonAse.Particles.GetSlice(\"old_gobbo\");\n\t\t}\n\n\t\tprivate bool saved;\n\n\t\tpublic void Save() {\n\t\t\tif (saved || Died) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsaved = true;\n\t\t\tGetComponent<HealthComponent>().Kill(this);\n\n\t\t\tTimer.Add(() => PlaceRewards(), 1f);\n\t\t}\n\t\t\n\t\tprotected override void CreateGore(DiedEvent d) {\n\t\t\tbase.CreateGore(d);\n\n\t\t\tif (saved) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar heinur = new Heinur();\n\t\t\tArea.Add(heinur);\n\t\t\theinur.Center = Center - new Vector2(0, 32);\n\n\t\t\tvar g = heinur.GetComponent<BkGraphicsComponent>();\n\t\t\t\n\t\t\tg.Scale = Vector2.Zero;\n\t\t\t\n\t\t\tTimer.Add(() => {\n\t\t\t\tTween.To(1, 0, x => g.Scale.X = x, 3f);\n\t\t\t\tTween.To(1, 0, x => g.Scale.Y = x, 3f);\n\t\t\t}, 1f);\n\n\t\t\tvar dm = new DarkMage();\n\t\t\tArea.Add(dm);\n\n\t\t\tdm.Center = Center + new Vector2(0, 32);\n\t\t\tdm.GetComponent<AnimationComponent>().Animate();\n\n\t\t\tAnimationUtil.Poof(dm.Center);\n\t\t\t\n\t\t\tvar dmDialog = dm.GetComponent<DialogComponent>();\n\t\t\tvar heinurDialog = heinur.GetComponent<DialogComponent>();\n\t\t\t\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tp.RemoveComponent<PlayerInputComponent>();\n\t\t\t}\n\t\t\t\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tCamera.Instance.Follow(dm, 1f);\n\t\t\tCamera.Instance.Follow(heinur, 1f);\n\t\t\t\n\t\t\tdmDialog.Start(\"dm_5\", null, () => Timer.Add(() => {\n\t\t\t\tdmDialog.Close();\n\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\tCamera.Instance.Follow(dm, 1f);\n\t\t\t\tCamera.Instance.Follow(heinur, 1f);\n\t\t\t\t\n\t\t\t\theinurDialog.Start(\"heinur_0\", null, () => Timer.Add(() => {\n\t\t\t\t\theinurDialog.Close();\n\t\t\t\t\theinur.Attract = true;\n\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\tCamera.Instance.Follow(dm, 1f);\n\t\t\t\t\tCamera.Instance.Follow(heinur, 1f);\n\n\t\t\t\t\theinur.Callback = () => {\n\t\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\t\tCamera.Instance.Follow(dm, 1f);\n\t\t\t\t\t\tCamera.Instance.MainTarget = dm;\n\n\t\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tp.GetComponent<PlayerGraphicsComponent>().Hidden = true;\n\t\t\t\t\t\t\tp.RemoveComponent<RectBodyComponent>();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar bk = new bk.BurningKnight() {\n\t\t\t\t\t\t\tPassive = true\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\n\t\t\t\t\t\tArea.Add(bk);\n\t\t\t\t\t\tbk.Center = Center;\n\n\t\t\t\t\t\tbk.GetComponent<BkGraphicsComponent>().Animate();\n\t\t\t\t\t\tCamera.Instance.Follow(bk, 1f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tdmDialog.Start(\"dm_6\", null, () => Timer.Add(() => {\n\t\t\t\t\t\t\tdmDialog.Close();\n\t\t\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\t\t\tCamera.Instance.Follow(bk, 1f);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar nbkDialog = bk.GetComponent<DialogComponent>();\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tnbkDialog.Start(\"nbk_0\", null, () => Timer.Add(() => {\n\t\t\t\t\t\t\t\tnbkDialog.Close();\n\t\t\t\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\t\t\t\tCamera.Instance.Follow(bk, 1f);\n\t\t\t\t\t\t\t\tRun.Win();\n\t\t\t\t\t\t\t}, 2f));\n\t\t\t\t\t\t}, 2f));\n\t\t\t\t\t};\n\t\t\t\t}, 1f));\n\t\t\t}, 1f));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/Boss.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.ui;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class Boss : Mob {\n\t\t// Dirty hack, I'm running out of time, don't kill me\n\t\tpublic static bool Exploding;\n\t\tpublic bool Awoken;\n\t\t\n\t\tprotected bool HasHealthbar = true;\n\t\tprotected HealthBar HealthBar;\n\n\t\tprotected bool Died;\n\t\tprivate float deathTimer;\n\t\tprivate float lastExplosion;\n\n\t\tpublic bool ResetCam = true;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddComponent(new DialogComponent());\n\n\t\t\tvar b = GetComponent<BuffsComponent>();\n\t\t\tb.AddImmunity<CharmedBuff>();\n\t\t\tb.AddImmunity<FrozenBuff>();\n\n\t\t\tif (!(this is BkHead || this is DM)) {\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t}\n\n\t\t\tGetComponent<HealthComponent>().AutoKill = true;\n\t\t\t\n\t\t\tAddTag(Tags.Boss);\n\t\t}\n\t\t\n\t\tprivate bool cleared;\n\t\tprotected bool Placed;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (Died) {\n\t\t\t\tif (!cleared) {\n\t\t\t\t\tcleared = true;\n\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t\t\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Projectile]) {\n\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\t\t\t\t\t\t((Projectile) p).Break(null);\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar a = GetComponent<RoomComponent>().Room.Tagged[Tags.MustBeKilled].ToArray();\n\n\t\t\t\t\t\tforeach (var p in a) {\n\t\t\t\t\t\t\tif (!(p is Boss)) {\n\t\t\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\t\t\t\t\t\t\t\t((Creature) p).Kill(this);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (deathTimer >= 3f && !Placed) {\n\t\t\t\t\tPlaced = true;\n\t\t\t\t\tCreateGore(null);\n\n\t\t\t\t\tif (this is bk.BurningKnight) {\n\t\t\t\t\t} else {\n\t\t\t\t\t\tHandleEvent(new DefeatedEvent {\n\t\t\t\t\t\t\tBoss = this\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tvar player = LocalPlayer.Locate(Area);\n\t\t\t\t\tvar doors = new List<DoorTile>();\n\t\t\t\t\t\n\t\t\t\t\tif (player != null) {\n\t\t\t\t\t\tvar stats = player.GetComponent<StatsComponent>();\n\t\t\t\t\t\tvar e = new DealChanceCalculateEvent();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!stats.TookDamageInRoom) {\n\t\t\t\t\t\t\tAchievements.Unlock(\"bk:dodge_master\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\te.GrannyStartChance = stats.SawDeal && !stats.TookDeal ? stats.GrannyChance : 0;\n\t\t\t\t\t\te.GrannyChance = e.GrannyStartChance;\n\t\t\t\t\t\te.DmStartChance = stats.DMChance;\n\t\t\t\t\t\te.DmChance = e.DmStartChance;\n\n\t\t\t\t\t\tplayer.HandleEvent(e);\n\n\t\t\t\t\t\tvar gr = Rnd.Chance(e.GrannyChance * 100);\n\t\t\t\t\t\tvar dm = Rnd.Chance(e.DmChance * 100);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (gr || (dm && e.OpenBoth)) {\n\t\t\t\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\t\t\t\t\tvar room = (Room) r;\n\n\t\t\t\t\t\t\t\tif (room.Type == RoomType.Granny) {\n\t\t\t\t\t\t\t\t\troom.OpenHiddenDoors();\n\n\t\t\t\t\t\t\t\t\tforeach (var d in room.Doors) {\n\t\t\t\t\t\t\t\t\t\tdoors.Add(new DoorTile {\n\t\t\t\t\t\t\t\t\t\t\tDoor = d,\n\t\t\t\t\t\t\t\t\t\t\tTile = Tile.GrannyFloor\n\t\t\t\t\t\t\t\t\t\t});\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (dm || (gr && e.OpenBoth)) {\n\t\t\t\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\t\t\t\t\tvar room = (Room) r;\n\n\t\t\t\t\t\t\t\tif (room.Type == RoomType.OldMan) {\n\t\t\t\t\t\t\t\t\troom.OpenHiddenDoors();\n\n\t\t\t\t\t\t\t\t\tforeach (var d in room.Doors) {\n\t\t\t\t\t\t\t\t\t\tdoors.Add(new DoorTile {\n\t\t\t\t\t\t\t\t\t\t\tDoor = d,\n\t\t\t\t\t\t\t\t\t\t\tTile = Tile.EvilFloor\n\t\t\t\t\t\t\t\t\t\t});\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (doors.Count > 0) {\n\t\t\t\t\t\tvar rm = GetComponent<RoomComponent>().Room;\n\t\t\t\t\t\tvar level = Run.Level;\n\t\t\t\t\t\tvar cx = rm.MapX + rm.MapW / 2f;\n\t\t\t\t\t\tvar cy = rm.MapY + rm.MapH / 2f;\n\t\t\t\t\t\tvar grannyDoors = new List<Door>();\n\t\t\t\t\t\tvar evilDoors = new List<Door>();\n\n\t\t\t\t\t\tforeach (var d in doors) {\n\t\t\t\t\t\t\tif (d.Tile == Tile.GrannyFloor) {\n\t\t\t\t\t\t\t\tgrannyDoors.Add(d.Door);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tevilDoors.Add(d.Door);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\trm.PaintTunnel(grannyDoors, Tile.GrannyFloor);\n\t\t\t\t\t\trm.PaintTunnel(evilDoors, Tile.EvilFloor);\n\n\t\t\t\t\t\trm.ApplyToEachTile((x, y) => {\n\t\t\t\t\t\t\tvar t = level.Get(x, y);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (t == Tile.GrannyFloor || t == Tile.EvilFloor) {\n\t\t\t\t\t\t\t\tlevel.Set(x, y, Tile.FloorA);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tvar part = new TileParticle();\n\n\t\t\t\t\t\t\t\t\tpart.Top = t == Tile.GrannyFloor ? Tilesets.Biome.GrannyFloor[0] : Tilesets.Biome.EvilFloor[0];\n\t\t\t\t\t\t\t\t\tpart.TopTarget = Run.Level.Tileset.WallTopADecor;\n\t\t\t\t\t\t\t\t\tpart.Side = Run.Level.Tileset.FloorSidesD[0];\n\t\t\t\t\t\t\t\t\tpart.Sides = Run.Level.Tileset.WallSidesA[2];\n\t\t\t\t\t\t\t\t\tpart.Tile = t;\n\n\t\t\t\t\t\t\t\t\tpart.X = x * 16;\n\t\t\t\t\t\t\t\t\tpart.Y = y * 16;\n\t\t\t\t\t\t\t\t\tpart.Target.X = x * 16;\n\t\t\t\t\t\t\t\t\tpart.Target.Y = y * 16;\n\t\t\t\t\t\t\t\t\tpart.TargetZ = -8f;\n\n\t\t\t\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t\t\t\t}, 1f + Rnd.Float(0.2f) + MathUtils.Distance(x - cx, y - cy) / 6f);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, -1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tlevel.TileUp();\n\t\t\t\t\t\tlevel.CreateBody();\n\t\t\t\t\t}\n\n\t\t\t\t\tDone = true;\n\t\t\t\t\tPlaceRewards();\n\n\t\t\t\t\tif (ResetCam) {\n\t\t\t\t\t\tTimer.Add(() => { ((InGameState) Engine.Instance.State).ResetFollowing(); }, 0.5f);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdeathTimer += dt;\n\t\t\t\t\tlastExplosion -= dt;\n\t\t\t\t\n\t\t\t\t\tif (lastExplosion <= 0) {\n\t\t\t\t\t\tlastExplosion = 0.3f;\n\t\t\t\t\t\tAnimationUtil.Explosion(Center + new Vector2(Rnd.Float(-16, 16), Rnd.Float(-16, 16)));\n\t\t\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t\t\t\tAudio.PlaySfx($\"level_explosion_{Rnd.Int(1, 4)}\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (deathTimer > 2.5f) {\n\t\t\t\t\t\tEngine.Instance.FlashColor = new Color(1f, 1f, 1f, (deathTimer - 2.5f) * 2f);\n\t\t\t\t\t\tEngine.Instance.Flash = 0.01f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!(GetComponent<StateComponent>().StateInstance is FriendlyState) && HasHealthbar && HealthBar == null) {\n\t\t\t\tHealthBar = new HealthBar(this);\n\t\t\t\tEngine.Instance.State.Ui.Add(HealthBar);\n\t\t\t\tAddPhases();\n\t\t\t\t\n\t\t\t\tEngine.Instance.State.Ui.Add(new UiBanner(Locale.Get(GetId())));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic string GetId() {\n\t\t\treturn $\"boss_{(this is BkHead ? \"burningknight\" : GetType().Name.ToLower())}\";\n\t\t}\n\n\t\tprivate struct DoorTile {\n\t\t\tpublic Door Door;\n\t\t\tpublic Tile Tile;\n\t\t}\n\n\t\tprotected virtual void AddPhases() {\n\t\t\t\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tif (target == null) {\n\t\t\t\t// Awoken = false;\n\t\t\t\tvar c = GetAnyComponent<AnimationComponent>();\n\n\t\t\t\tif (c != null) {\n\t\t\t\t\tc.Animation.Tag = \"idle\";\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tAwoken = true;\n\t\t\t}\n\t\t\t\n\t\t\tbase.OnTargetChange(target);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DiedEvent de) {\n\t\t\t\tif (de.Who == this) {\n\t\t\t\t\tif (!Died) {\n\t\t\t\t\t\tExploding = true;\n\t\t\t\t\t\tDied = true;\n\t\t\t\t\t\tHealthBar?.Remove();\n\n\t\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\t\tCamera.Instance.Follow(this, 1f);\n\t\t\t\t\t\tBecome<DefeatedState>();\n\n\t\t\t\t\t\tAudio.Stop();\n\t\t\t\t\t}\n\n\t\t\t\t\tDone = false;\n\t\t\t\t\te.Handled = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic virtual void PlaceRewards() {\n\t\t\tvar exit = new Exit();\n\n\t\t\tExploding = false;\n\t\t\tArea.Add(exit);\n\n\t\t\texit.To = Run.Depth + 1;\n\n\t\t\tvar center = GetComponent<RoomComponent>().Room.Center;\n\n\t\t\tvar x = (int) Math.Floor(center.X / 16);\n\t\t\tvar y = (int) Math.Floor(center.Y / 16);\n\t\t\tvar p = new Vector2(x * 16 + 8, y * 16 + 8);\n\n\t\t\texit.Center = p;\n\n\t\t\tPainter.Fill(Run.Level, x - 1, y - 1, 3, 3, Tiles.RandomFloor());\n\t\t\tPainter.Fill(Run.Level, x - 1, y - 3, 3, 3, Tiles.RandomFloor());\n\n\t\t\tRun.Level.ReTileAndCreateBodyChunks(x - 1, y - 1, 3, 7);\n\t\t\tvar w = p - new Vector2(0, 32f);\n\n\t\t\tif (!(this is DM || this is BkHead || Run.Type == RunType.BossRush)) {\n\t\t\t\tvar stand = new BossStand();\n\t\t\t\tArea.Add(stand);\n\t\t\t\tstand.Center = w;\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Boss), Area), null);\n\t\t\t}\n\n\t\t\tvar rewards = new List<string>();\n\t\t\tvar c = Run.Type == RunType.BossRush ? 2 : Rnd.Int(2, 10);\n\n\t\t\tif (Run.Type != RunType.BossRush && !(this is DM || this is BkHead)) {\n\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\trewards.Add(\"bk:emerald\");\n\t\t\t\t}\n\n\t\t\t\tvar q = Rnd.Int(4, 10);\n\n\t\t\t\tfor (var i = 0; i < q; i++) {\n\t\t\t\t\trewards.Add(\"bk:copper_coin\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Run.Type != RunType.BossRush) {\n\t\t\t\tvar cn = Rnd.Int(0, 3);\n\n\t\t\t\tfor (var i = 0; i < cn; i++) {\n\t\t\t\t\trewards.Add(\"bk:heart\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar cn = Rnd.Int(20, 30);\n\n\t\t\t\tfor (var i = 0; i < cn; i++) {\n\t\t\t\t\trewards.Add(\"bk:coin\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar j = 0;\n\n\t\t\tforeach (var reward in rewards) {\n\t\t\t\tvar item = Items.CreateAndAdd(reward, Area);\n\t\t\t\titem.Center = w + MathUtils.CreateVector(j / ((float) rewards.Count) * Math.PI * 2 + Rnd.Float(-0.1f, 0.1f), Rnd.Float(12, 18));\n\t\t\t\tj++;\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void SelectAttack() {\n\t\t\t\n\t\t}\n\n\t\tpublic class DefeatedState : SmartState<Boss> {\n\t\t\t\n\t\t}\n\n\t\tpublic class FriendlyState : SmartState<Boss> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tExploding = false;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = true;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tExploding = false;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool IsFriendly() {\n\t\t\treturn GetComponent<StateComponent>().StateInstance is FriendlyState;\n\t\t}\n\n\t\tpublic class DefeatedEvent : Event {\n\t\t\tpublic Boss Boss;\n\t\t}\n\t\t\n\t\tpublic override void Kill(Entity w, DamageType type = DamageType.Regular) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual string GetScream() {\n\t\t\treturn \"bk_3\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/BossAttack.cs",
    "content": "namespace BurningKnight.entity.creature.mob.boss {\n\tpublic class BossAttack<T> : SmartState<T> where T : Boss {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/BossInfo.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class BossInfo {\n\t\tpublic Type Type;\n\t\tpublic SpawnChance[] Spawns;\n\n\t\tpublic static BossInfo New<T>(params SpawnChance[] spawns) where T : Mob {\n\t\t\treturn new BossInfo {\n\t\t\t\tType = typeof(T),\n\t\t\t\tSpawns = spawns\n\t\t\t};\n\t\t}\n\n\t\tpublic bool SpawnsIn(string biome) {\n\t\t\treturn GetChanceFor(biome) != null;\n\t\t}\n\n\t\tpublic SpawnChance GetChanceFor(string biome) {\n\t\t\tforeach (var b in Spawns) {\n\t\t\t\tforeach (var a in b.Areas) {\n\t\t\t\t\tif (a == biome) {\n\t\t\t\t\t\treturn b;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/BossRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic static class BossRegistry {\n\t\tpublic static List<BossInfo> All = new List<BossInfo>();\n\t\t\n\t\tstatic BossRegistry() {\n\t\t\tBossInfo[] infos = {\n\t\t\t\tBossInfo.New<OldKing>(new SpawnChance(1f, Biome.Castle)),\n\t\t\t\tBossInfo.New<Pharaoh>(new SpawnChance(1f, Biome.Desert)),\n\t\t\t\tBossInfo.New<QueenBee>(new SpawnChance(1f, Biome.Jungle)),\n\t\t\t\tBossInfo.New<IceQueen>(new SpawnChance(1f, Biome.Ice)),\n\t\t\t\tBossInfo.New<DM>(new SpawnChance(1f, Biome.Tech))\n\t\t\t};\n\t\t\t\n\t\t\tAll.AddRange(infos);\n\t\t}\n\t\t\n\t\tpublic static Boss Generate() {\n\t\t\tvar current = new List<BossInfo>();\n\t\t\t\n\t\t\tforeach (var info in All) {\n\t\t\t\tif (info.SpawnsIn(Run.Level.Biome.Id)) {\n\t\t\t\t\tcurrent.Add(info);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar chances = new float[current.Count];\n\n\t\t\tfor (var i = 0; i < current.Count; i++) {\n\t\t\t\tchances[i] = current[i].GetChanceFor(Run.Level.Biome.Id).Chance;\n\t\t\t}\n\n\t\t\tvar index = Rnd.Chances(chances);\n\n\t\t\tif (index == -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn (Boss) Activator.CreateInstance(current[index].Type);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/DM.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss.rooms;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.entity.room.controller;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class DM : Boss {\n\t\tprivate const int Hp = 5;\n\t\tprivate List<Type> did = new List<Type>();\n\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\t\n\t\t\tfor (var i = 1; i < Hp; i++) {\n\t\t\t\tHealthBar.AddPhase(i / (float) Hp);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 14;\n\t\t\tHeight = 17;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 1, 12, 16));\n\n\t\t\tvar body = new RectBodyComponent(1, 16, 12, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\tbody.Body.LinearDamping = 3;\n\n\t\t\tAddComponent(new ZComponent());\n\t\t\tAddComponent(new ZAnimationComponent(\"dark_mage\"));\n\t\t\t\n\t\t\tSetMaxHp(Hp);\n\n\t\t\tFlying = true;\n\n\t\t\tvar b = GetComponent<BuffsComponent>();\n\t\t\t\n\t\t\tb.AddImmunity<BurningBuff>();\n\t\t\tb.AddImmunity<PoisonBuff>();\n\t\t\tb.AddImmunity<FrozenBuff>();\n\t\t\tb.AddImmunity<BrokenArmorBuff>();\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target != null) {\n\t\t\t\tif (GetComponent<HealthComponent>().Health > 1) {\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"dm_7\", 2f);\n\t\t\t\t}\n\n\t\t\t\tSelectAttack();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t\t\n\t\t\tTimer.Add(() => {\n\t\t\t\tChangeupRoom();\n\t\t\t}, 1f);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\thme.Amount = Math.Max(-1, hme.Amount);\n\t\t\t\tChangeupRoom();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate void ChangeupRoom() {\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tAnimationUtil.TeleportAway(p, () => { });\n\t\t\t\t}, 0.5f);\n\t\t\t}\n\n\t\t\tCamera.Instance.Shake(6);\n\n\t\t\tAnimationUtil.TeleportAway(this, () => {\n\t\t\t\tGetComponent<RoomComponent>().Room.Hide();\n\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\t\t\tvar room = (Room) r;\n\n\t\t\t\t\t\tif (room.Type != RoomType.Boss) {\n\t\t\t\t\t\t\troom.Done = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tforeach (var d in Area.Tagged[Tags.Door]) {\n\t\t\t\t\t\td.Done = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tforeach (var e in Area.Entities.Entities) {\n\t\t\t\t\t\tif (e is WallTorch || e is Torch || e is Prop || e is Entrance || (e is Creature && !(e is Player || e is Boss)) \n\t\t\t\t\t\t    || e is Turret || e is SpawnPoint || e is Projectile || e is MovingPlatform || e is RoomControllable || e is Gore) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\te.Done = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar rm = GetComponent<RoomComponent>().Room;\n\t\t\t\t\tvar level = Run.Level;\n\t\t\t\t\tType type;\n\n\t\t\t\t\tif (GetComponent<HealthComponent>().Health <= 0) {\n\t\t\t\t\t\ttype = typeof(DmEndRoom);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar arr = DmRoomRegistry.Rooms.ToList();\n\n\t\t\t\t\t\tforeach (var t in did) {\n\t\t\t\t\t\t\tarr.Remove(t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\ttype = arr[Rnd.Int(arr.Count)];\n\t\t\t\t\t\tdid.Add(type);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var i = rm.Controllers.Count - 1; i >= 0; i--) {\n\t\t\t\t\t\tif (!(rm.Controllers[i] is BossRoomController)) {\n\t\t\t\t\t\t\trm.Controllers.RemoveAt(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar rmdef = (DmRoom) Activator.CreateInstance(type);\n\n\t\t\t\t\trm.Parent = rmdef;\n\t\t\t\t\trm.MapW = Math.Min(Rnd.Int(rmdef.GetMinWidth(), rmdef.GetMaxWidth()), level.Width - 2);\n\t\t\t\t\trm.MapH = Math.Min(Rnd.Int(rmdef.GetMinHeight(), rmdef.GetMaxHeight()), level.Height - 2);\n\t\t\t\t\trm.MapX = (int) Math.Ceiling((level.Width - rm.MapW) / 2f);\n\t\t\t\t\trm.MapY = (int) Math.Ceiling((level.Height - rm.MapH) / 2f);\n\t\t\t\t\trm.UpdateSize();\n\n\t\t\t\t\trmdef.Set(rm.MapX, rm.MapY, rm.MapX + rm.MapW - 1, rm.MapY + rm.MapH - 1);\n\t\t\t\t\t\n\t\t\t\t\tPainter.Fill(level, new Rect(0, 0, level.Width, level.Height), Tile.WallA);\n\t\t\t\t\tPainter.Fill(level, rmdef, 1, Tile.FloorA);\n\t\t\t\t\trmdef.PaintFloor(level);\n\t\t\t\t\trmdef.Paint(level, rm);\n\t\t\t\t\t\n\t\t\t\t\trmdef.PlaceMage(rm, this);\n\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\tvar s = new SpawnPoint();\n\t\t\t\t\t\tArea.Add(s);\n\n\t\t\t\t\t\trmdef.PlacePlayer(rm, (Player) p);\n\t\t\t\t\t\ts.Center = p.Center;\n\t\t\t\t\t\t\n\t\t\t\t\t\tAnimationUtil.TeleportIn(p);\n\t\t\t\t\t}\n\n\t\t\t\t\tPainter.ReplaceTiles(level, rmdef);\n\t\t\t\t\tPainter.UpdateTransition(level);\n\t\t\t\t\tlevel.TileUp();\n\t\t\t\t\tlevel.RecreateBody();\n\n\t\t\t\t\tEngine.Instance.Flash = 2f;\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = 0; i < level.Size; i++) {\n\t\t\t\t\t\tlevel.Light[i] = 1f;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tAnimationUtil.TeleportIn(this);\n\t\t\t\t}, 1f);\n\t\t\t});\n\t\t}\n\n\t\tprivate int counter;\n\t\t\n\t\t#region DM States\n\t\tpublic class IdleState : SmartState<DM> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Mob].Count > 1) {\n\t\t\t\t\tBecome<FlyingState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class FlyingState : SmartState<DM> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = true;\n\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().Tint.A = 140;\n\t\t\t\tSelf.GetComponent<ZComponent>().Float = true;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().Tint.A = 255;\n\t\t\t\tSelf.GetComponent<ZComponent>().Float = false;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\t\n\t\t\t\tif (Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Mob].Count <= 1) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tbase.PlaceRewards();\n\t\t\tAchievements.Unlock(\"bk:dm_no_more\");\n\t\t\tDone = false;\n\t\t\tDied = false;\n\t\t\t\n\t\t\tTarget.RemoveComponent<PlayerInputComponent>();\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Start(\"lp_0\", Target, () => {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tRun.ActualDepth = -1;\n\t\t\t\t\tRun.Depth = 1;\n\t\t\t\t\tRun.Loop++;\n\n\t\t\t\t\tAchievements.Unlock(\"bk:loop\");\n\t\t\t\t}, 1f);\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/IceQueen.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.entity.projectile.pattern;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class IceQueen : Boss {\n\t\tprivate static Color tint = new Color(50, 60, 234, 200);\n\t\t\n\t\tpublic bool InSecondPhase {\n\t\t\tget {\n\t\t\t\tvar p = GetComponent<HealthComponent>().Percent;\n\t\t\t\treturn p > 0.33f && p <= 0.66f;\n\t\t\t}\n\t\t}\n\n\t\tpublic bool InThirdPhase => GetComponent<HealthComponent>().Percent <= 0.33f;\n\t\tpublic bool InFirstPhase => GetComponent<HealthComponent>().Percent > 0.66f;\n\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\t\n\t\t\tHealthBar.AddPhase(0.33f);\n\t\t\tHealthBar.AddPhase(0.66f);\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 10;\n\t\t\tHeight = 19;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 2, 8, 17));\n\n\t\t\tvar body = new RectBodyComponent(1, 18, 8, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\tbody.Body.LinearDamping = 3;\n\n\t\t\tAddAnimation(\"ice_queen\");\n\t\t\tSetMaxHp(550);\n\t\t}\n\n\t\tpublic void ModifyBuilder(ProjectileBuilder builder) {\n\t\t\tif (InThirdPhase) {\n\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Animate() {\n\t\t\tGetComponent<MobAnimationComponent>().Animate();\n\t\t}\n\t\t\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target == null) {\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t}\n\t\t}\n\n\t\tprivate float lastFadingParticle;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Target != null) {\n\t\t\t\tGraphicsComponent.Flipped = Target.CenterX < CenterX;\n\t\t\t}\n\t\t\t\n\t\t\tlastFadingParticle -= dt;\n\n\t\t\tif (lastFadingParticle <= 0) {\n\t\t\t\tlastFadingParticle = 0.2f;\n\n\t\t\t\tvar particle = new FadingParticle(GetComponent<MobAnimationComponent>().Animation.GetCurrentTexture(), tint);\n\t\t\t\tArea.Add(particle);\n\n\t\t\t\tparticle.Depth = Depth - 1;\n\t\t\t\tparticle.Center = Center;\n\t\t\t}\n\t\t}\n\n\t\tprivate int counter;\n\t\t\n\t\t#region Ice Queen States\n\t\tprotected class IdleState : SmartState<IceQueen> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= (Self.InThirdPhase ? 1f : 3f)) {\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tswitch (Self.counter) {\n\t\t\t\t\t\tcase 0: {\n\t\t\t\t\t\t\tBecome<ExplosiveBulletsState>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 1: {\n\t\t\t\t\t\t\tBecome<SpamBulletsState>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 3: {\n\t\t\t\t\t\t\tif (Self.InThirdPhase) {\n\t\t\t\t\t\t\t\tBecome<SpinCircleAttack>();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tBecome<MoveState>();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 2: case 4: {\n\t\t\t\t\t\t\tBecome<MoveState>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 5: {\n\t\t\t\t\t\t\tBecome<BulletCircleAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase 6: {\n\t\t\t\t\t\t\tBecome<SpinCircleAttack>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 7: {\n\t\t\t\t\t\t\tBecome<MoveState>();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.counter = (Self.counter + 1) % (Self.InSecondPhase ? 7 : (Self.InThirdPhase ? 8 : 5));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class SpinCircleAttack : SmartState<IceQueen> {\n\t\t\tprivate float t;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tt += dt;\n\n\t\t\t\tif (T >= 0.15f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\t\n\t\t\t\t\tvar amount = 4;\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tvar a = Math.PI * 2 * ((float) i / amount) + Math.Cos(t * 0.8f) * Math.PI;\n\t\t\t\t\t\tbuilder.Slice = (t % 0.5f < 0.25f) ^ (i % 2 == 0) ? \"small\" : \"big\";\n\t\t\t\t\t\tbuilder.Color = t % 1f < 0.5f ? ProjectileColor.Blue : ProjectileColor.Purple;\n\n\t\t\t\t\t\tbuilder.Shoot(a, 6f + t * 2).Build();\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.Animate();\n\t\t\t\t}\n\n\t\t\t\tif (t >= 3f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class BulletCircleAttack : SmartState<IceQueen> {\n\t\t\tprivate List<Projectile> projectiles = new List<Projectile>();\n\t\t\tprivate bool second;\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tforeach (var p in projectiles) {\n\t\t\t\t\tp.Break();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T >= 0.15f) {\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tif (second) {\n\t\t\t\t\t\tvar p = projectiles[0];\n\t\t\t\t\t\tprojectiles.RemoveAt(0);\n\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_fire_static\", pitch: (projectiles.Count / 16f - 0.5f) * 2);\n\n\t\t\t\t\t\tif (!p.Done) {\n\t\t\t\t\t\t\tp.BodyComponent.Velocity = MathUtils.CreateVector(p.AngleTo(Self.Target), 200f);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tp.Break();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (projectiles.Count == 0) {\n\t\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, projectiles.Count % 2 == 0 ? \"circle\" : \"small\");\n\t\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\t\tvar p = builder.Shoot(Self.AngleTo(Self.Target), 0).Build();\n\n\t\t\t\t\t\tp.Color = projectiles.Count % 2 == 0 ? ProjectileColor.Blue : ProjectileColor.Cyan;\n\t\t\t\t\t\tp.Center = Self.Center + MathUtils.CreateVector(projectiles.Count / 4f * Math.PI, 20 + projectiles.Count * 2);\n\t\t\t\t\t\tp.Depth = 1;\n\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_flower_charging\", pitch: projectiles.Count / 8f);\n\t\t\t\t\t\tprojectiles.Add(p);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (projectiles.Count == 16) {\n\t\t\t\t\t\t\tsecond = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.Animate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected class ExplosiveBulletsState : SmartState<IceQueen> {\n\t\t\tprivate const int SmallCount = 4;\n\t\t\tprivate const int InnerCount = 8;\n\t\t\t\n\t\t\tprivate int count;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = 10f;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 1f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f) + (count == 1 ? 0 : Math.PI);\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"square\") {\n\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\tRange = 5\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\t\t\tvar projectile = builder.Shoot(a, 15f).Build();\n\t\t\t\t\tSelf.Animate();\n\n\t\t\t\t\tprojectile.Color = ProjectileColor.Red;\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(a, 8);\n\n\t\t\t\t\tvar tt = 0f;\n\n\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, (p, dtt) => {\n\t\t\t\t\t\ttt += dtt;\n\n\t\t\t\t\t\tif (tt >= 0.3f) {\n\t\t\t\t\t\t\ttt = 0;\n\n\t\t\t\t\t\t\tvar s = projectile.BodyComponent.Velocity.Length();\n\n\t\t\t\t\t\t\tif (s < 3f) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar bb = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\t\t\tScale = Rnd.Float(0.8f, 1.2f)\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tSelf.ModifyBuilder(builder);\n\t\t\t\t\t\t\tvar z = bb.Shoot(a - Math.PI + Rnd.Float(-0.1f, 0.1f), s).Build();\n\t\t\t\t\t\t\tz.Center = projectile.Center;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, SlowdownProjectileController.Make());\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => {\n\t\t\t\t\t\tfor (var i = 0; i < SmallCount; i++) {\n\t\t\t\t\t\t\tvar an = (float) (((float) i) / SmallCount * Math.PI * 2);\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar pp = new ProjectilePattern(CircleProjectilePattern.Make(4.5f, 10 * (i % 2 == 0 ? 1 : -1))) {\n\t\t\t\t\t\t\t\tPosition = p.Center\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tvar bb = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\t\tfor (var j = 0; j < 4; j++) {\n\t\t\t\t\t\t\t\tvar b = bb.Build();\n\t\t\t\t\t\t\t\tpp.Add(b);\n\t\t\t\t\t\t\t\tb.Color = ProjectileColor.Red;\n\t\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\t\tpp.Launch(an, 40);\n\t\t\t\t\t\t\tSelf.Area.Add(pp);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar bbb = new ProjectileBuilder(Self, \"snowflake\") {\n\t\t\t\t\t\t\tColor = ProjectileColor.Cyan\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tfor (var i = 0; i < InnerCount; i++) {\n\t\t\t\t\t\t\tbbb.Scale = Rnd.Float(0.5f, 1f);\n\t\t\t\t\t\t\tvar b = bbb.Shoot(Rnd.AnglePI(), Rnd.Float(10, 40)).Build();\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tb.Center = p.Center;\n\t\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(b,  SlowdownProjectileController.Make(Rnd.Float(0.5f, 4f)));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tif (count == 2) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected class SpamBulletsState : SmartState<IceQueen> {\n\t\t\tprivate const int InnerCount = 32;\n\t\t\t\n\t\t\tprivate int count;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = 10f;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 4f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f) + (count == 1 ? 0 : Math.PI);\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"big\") {\n\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\t\t\tvar projectile = builder.Shoot(a, 7).Build();\n\t\t\t\t\tSelf.Animate();\n\n\t\t\t\t\tprojectile.Color = ProjectileColor.Blue;\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(a, 8);\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => {\n\t\t\t\t\t\tvar bb = new ProjectileBuilder(Self, \"snowflake\") {\n\t\t\t\t\t\t\tColor = ProjectileColor.Blue,\n\t\t\t\t\t\t\tLightRadius = 32\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\tbb.AddFlags(ProjectileFlags.AutomaticRotation);\n\n\t\t\t\t\t\tfor (var i = 0; i < InnerCount; i++) {\n\t\t\t\t\t\t\tvar b = bb.Shoot((float) i / InnerCount * Math.PI * 2, i % 2 == 0 ? 6 : 12).Build();\n\t\t\t\t\t\t\tb.Center = p.Center;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tif (count == 1) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected class MoveState : SmartState<IceQueen> {\n\t\t\tprivate Vector2 to; \n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tto = Self.Target.Center;\n\t\t\t\tSelf.Animate();\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tvar aa = Self.AngleTo(Self.Target);\n\t\t\t\tSelf.Animate();\n\n\t\t\t\tvar builder = new ProjectileBuilder(Self, \"donut\") {\n\t\t\t\t\tScale = 1.5f,\n\t\t\t\t\tColor = ProjectileColor.Green,\n\t\t\t\t\tLightRadius = 32f\n\t\t\t\t};\n\n\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\tfor (var j = 0; j < 2; j++) {\n\t\t\t\t\tvar projectile = builder.Shoot(aa + (j % 2 == 0 ? -1 : 1) * 0.3f, 14f).Build();\n\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(aa, 8);\n\n\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => {\n\t\t\t\t\t\tvar v = p.GetAnyComponent<BodyComponent>().Velocity;\n\t\t\t\t\t\tvar a = v.ToAngle() - (float) Math.PI;\n\t\t\t\t\t\tvar s = v.Length();\n\t\t\t\t\t\tvar c = p.HasComponent<CircleBodyComponent>();\n\n\t\t\t\t\t\tvar b = new ProjectileBuilder(Self, p.Slice) {\n\t\t\t\t\t\t\tParent = p,\n\t\t\t\t\t\t\tScale = p.Scale * Rnd.Float(0.4f, 1.5f)\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tSelf.ModifyBuilder(b);\n\t\t\t\t\t\tfor (var i = 0; i < Rnd.Int(3, 5); i++) {\n\t\t\t\t\t\t\tb.Shoot(a + Rnd.Float(-1.4f, 1.4f), s * Rnd.Float(0.3f, 1.5f)).Build().Center = p.Center;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar dx = Self.DxTo(to);\n\t\t\t\tvar dy = Self.DyTo(to);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tif (d <= 16f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tvar s = 120 * dt / d;\n\t\t\t\t\tSelf.Position += new Vector2(dx * s, dy * s);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tbase.PlaceRewards();\n\t\t\tAchievements.Unlock(\"bk:ice_boss\");\n\t\t}\n\n\t\tpublic override string GetScream() {\n\t\t\treturn \"ice_queen_scream\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/OldKing.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.entity.projectile.pattern;\nusing BurningKnight.level;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class OldKing : Boss {\n\t\tpublic bool Raging => GetComponent<HealthComponent>().Percent <= 0.25f;\n\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\tHealthBar.AddPhase(0.25f);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 19;\n\t\t\tHeight = 27;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 10, 14, 17));\n\n\t\t\tvar body = new RectBodyComponent(2, 26, 14, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.05f;\n\t\t\tbody.Body.LinearDamping = 1;\n\n\t\t\tAddComponent(new ZComponent {\n\t\t\t\tGravity = 2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"old_king\"));\n\t\t\tSetMaxHp(100);\n\t\t}\n\n\t\tprivate float lastParticle;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle -= dt;\n\n\t\t\tif (lastParticle <= 0) {\n\t\t\t\tlastParticle = 0.1f;\n\n\t\t\t\tif (!IsFriendly()) {\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(-2, -13),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(2, -13),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is Chasm) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.ShouldCollide(entity);\n\t\t}\n\n\t\tpublic override bool InAir() {\n\t\t\tvar state = GetComponent<StateComponent>().StateInstance;\n\t\t\t\n\t\t\treturn state is UpState || state is DownState;\n\t\t}\n\t\t\n\t\t#region Old King States\n\t\tprivate int lastAttack;\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target == null) {\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t}\n\t\t}\n\n\t\tpublic class IdleState : SmartState<OldKing> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= (Self.Raging ? 1f : 2f)) {\n\t\t\t\t\tif (Rnd.Chance(95)) {\n\t\t\t\t\t\tSelf.lastAttack = (Self.lastAttack + 1) % 2;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Self.lastAttack == 0) {\n\t\t\t\t\t\tBecome<SkullAttack>();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tBecome<JumpState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class SkullAttack : SmartState<OldKing> {\n\t\t\tprivate int count;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif ((count + 1) * (Self.Raging ? 0.7f : 1.5f) <= T) {\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (Self.Target == null || Self.Died) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar a = Self.GetComponent<ZAnimationComponent>();\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_oldking_shoot\");\n\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\n\t\t\t\t\t\tif (Self.Target == null || Self.Died) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"skull\") {\n\t\t\t\t\t\t\tRange = 5f\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\tvar skull = builder.Shoot(Self.AngleTo(Self.Target), 8).Build();\n\n\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => {\n\t\t\t\t\t\t\tif (!t) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tCamera.Instance.ShakeMax(8);\n\n\t\t\t\t\t\t\tvar b = new ProjectileBuilder(Self, \"small\");\n\t\t\t\t\t\t\tb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\n\t\t\t\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\t\t\t\tvar bullet = b.Shoot(((float) i) / 4 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build();\n\t\t\t\t\t\t\t\tbullet.Center = p.Center;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(Self.Target, 0.5f));\n\t\t\t\t\t\tskull.GetComponent<ProjectileGraphicsComponent>().IgnoreRotation = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (count == (Self.Raging ? 6 : 4)) {\n\t\t\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class JumpState : SmartState<OldKing> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<ZAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tBecome<UpState>();\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_oldking_jump\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class UpState : SmartState<OldKing> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar a = Self.Target == null || (!Self.Raging && Rnd.Chance()) ? Rnd.AnglePI() : Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f);\n\t\t\t\tvar force = Rnd.Float(20f) + (Self.Raging ? 240 : 120);\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\tSelf.GetComponent<ZComponent>().ZVelocity = 10;\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t\tSelf.Depth = Layers.FlyingMob;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<ZComponent>().ZVelocity <= 0) {\n\t\t\t\t\tBecome<DownState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class DownState : SmartState<OldKing> {\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\t\t\t\t\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 1;\t\t\t\t\n\t\t\t\tSelf.Depth = Layers.Creature;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<ZComponent>().Z <= 0) {\n\t\t\t\t\tBecome<LandState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate int jumpCounter;\n\t\t\n\t\tpublic class LandState : SmartState<OldKing> {\n\t\t\tprivate const int SmallCount = 8;\n\t\t\tprivate const int InnerCount = 8;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar a = Self.GetComponent<ZAnimationComponent>();\n\t\t\t\ta.SetAutoStop(true);\n\n\t\t\t\tCamera.Instance.ShakeMax(12);\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_oldking_land\");\n\t\t\t\t\n\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t\tvar bb = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\tbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\tfor (var i = 0; i < SmallCount; i++) {\n\t\t\t\t\tvar an = (float) (((float) i) / SmallCount * Math.PI * 2);\n\t\t\t\t\t\t\n\t\t\t\t\tvar pp = new ProjectilePattern(CircleProjectilePattern.Make(4.5f, 10 * (i % 2 == 0 ? 1 : -1))) {\n\t\t\t\t\t\tPosition = Self.BottomCenter\n\t\t\t\t\t};\n\n\t\t\t\t\tfor (var j = 0; j < 2; j++) {\n\t\t\t\t\t\tpp.Add(bb.Build());\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\tpp.Launch(an, 40);\n\t\t\t\t\tSelf.Area.Add(pp);\n\t\t\t\t}\n\n\t\t\t\tvar aa = Self.AngleTo(Self.Target);\n\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\tColor = ProjectileColor.Green,\n\t\t\t\t\tBounce = 2\n\t\t\t\t};\n\n\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\n\t\t\t\tfor (var i = 0; i < InnerCount; i++) {\n\t\t\t\t\tbuilder.Scale = Rnd.Float(0.5f, 1f);\n\t\t\t\t\tvar b = builder.Shoot(aa + Rnd.Float(-0.3f, 0.3f), Rnd.Float(2, 12)).Build();\n\t\t\t\t\t\t\n\t\t\t\t\tb.Center = Self.BottomCenter;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar animation = Self.GetComponent<ZAnimationComponent>().Animation;\n\n\t\t\t\tif (animation.Paused) {\n\t\t\t\t\tif (Self.Raging) {\n\t\t\t\t\t\tif (Self.jumpCounter < 2) {\n\t\t\t\t\t\t\tBecome<JumpState>();\n\t\t\t\t\t\t\tSelf.jumpCounter++;\n\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tSelf.jumpCounter = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tbase.PlaceRewards();\n\t\t\tAchievements.Unlock(\"bk:democracy\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/Pharaoh.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.desert;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Audio;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class Pharaoh : Boss {\n\t\tpublic bool InSecondPhase {\n\t\t\tget {\n\t\t\t\tvar p = GetComponent<HealthComponent>().Percent;\n\t\t\t\treturn p > 0.33f && p <= 0.66f;\n\t\t\t}\n\t\t}\n\n\t\tpublic bool InThirdPhase => GetComponent<HealthComponent>().Percent <= 0.33f;\n\t\tpublic bool InFirstPhase => GetComponent<HealthComponent>().Percent > 0.66f;\n\t\t\n\t\tpublic int Phase => (InThirdPhase ? 3 : (InSecondPhase ? 2 : 1));\n\n\t\tprivate int lastPhase = 1;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 15;\n\t\t\tHeight = 18;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 1, 13, 17));\n\n\t\t\tvar body = new RectBodyComponent(2, 17, 11, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.1f;\n\t\t\tbody.Body.LinearDamping = 4;\n\n\t\t\tAddAnimation(\"pharaoh\");\n\t\t\tSetMaxHp(250);\n\t\t}\n\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\t\n\t\t\tHealthBar.AddPhase(0.33f);\n\t\t\tHealthBar.AddPhase(0.66f);\n\t\t}\n\n\t\tprivate float lastParticle;\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle -= dt;\n\t\t\tt += dt;\n\n\t\t\tif (lastParticle <= 0) {\n\t\t\t\tlastParticle = 0.1f;\n\n\t\t\t\tif (!IsFriendly()) {\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(-2, -11),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(2, -11),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\n\t\t\t\t\tif (Died) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar p = Phase;\n\n\t\t\t\t\tif (lastPhase != p) {\n\t\t\t\t\t\tlastPhase = p;\n\t\t\t\t\t\tBecome<SwitchPhaseState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprivate int counter;\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target == null) {\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t}\n\t\t}\n\n\t\t#region Pharaoh States\n\t\tpublic class IdleState : SmartState<Pharaoh> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (T >= (Self.InThirdPhase ? 0.01f : 0.3f)) {\n\t\t\t\t\tvar v = Self.counter;\n\n\t\t\t\t\tif (v == 0) {\n\t\t\t\t\t\tBecome<SimpleSpiralState>();\n\t\t\t\t\t} else if (v == 1) {\n\t\t\t\t\t\tif (Self.InThirdPhase) {\n\t\t\t\t\t\t\tBecome<BulletHellState>();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tBecome<TileMoveState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (v == 2) {\n\t\t\t\t\t\tBecome<TeleportState>();\n\t\t\t\t\t} else if (v == 3) {\n\t\t\t\t\t\tBecome<BulletHellState>();\n\t\t\t\t\t} else if (v == 4) {\n\t\t\t\t\t\tBecome<TeleportState>();\n\t\t\t\t\t} else if (v == 5) {\n\t\t\t\t\t\tBecome<AdvancedSpiralState>();\n\t\t\t\t\t} else if (v == 6) {\n\t\t\t\t\t\tif (Self.InThirdPhase) {\n\t\t\t\t\t\t\tBecome<TeleportState>();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tBecome<TileMoveState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.counter = (v + 1) % 7;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class SimpleSpiralState : SmartState<Pharaoh> {\n\t\t\tprivate float sinceLast;\n\t\t\tprivate int count;\n\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tsinceLast -= dt;\n\n\t\t\t\tif (sinceLast <= 0) {\n\t\t\t\t\tsinceLast = 0.2f;\n\t\t\t\t\tvar amount = 2 + (Self.Phase - 1);\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\");\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tvar a = Math.PI * 2 * ((float) i / amount) + Math.Cos(Self.t * 0.8f) * Math.PI;\n\n\t\t\t\t\t\tbuilder.Color = count % 4 == 0 ? ProjectileColor.Orange : ProjectileColor.Red;\n\t\t\t\t\t\tbuilder.Scale = count % 2 == 0 ? 1.5f : 2f;\n\t\t\t\t\t\tbuilder.Shoot(a, 8f).Build();\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_shot\");\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\n\t\t\t\tif (T >= 8f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class AdvancedSpiralState : SmartState<Pharaoh> {\n\t\t\tprivate float sinceLast;\n\t\t\tprivate int count;\n\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tsinceLast -= dt;\n\n\t\t\t\tif (sinceLast <= 0) {\n\t\t\t\t\tsinceLast = Self.InFirstPhase ? 0.6f : 0.4f;\n\t\t\t\t\tvar amount = 8;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\tScale = 1.5f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tvar a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 1) * Math.PI * 0.25f) * (i % 2 == 1 ? -1 : 1);\n\n\t\t\t\t\t\tbuilder.Color = ProjectileColor.DesertRainbow[count % ProjectileColor.DesertRainbow.Length];\n\n\t\t\t\t\t\tbuilder.Shoot(a, 6f + (float) Math.Cos(Self.t * 1) * 2f).Build();\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_shot_wave\");\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t\t\n\n\t\t\t\tif (T >= 10f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class BulletHellState : SmartState<Pharaoh> {\n\t\t\tprivate float sinceLast;\n\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tsinceLast -= dt;\n\n\t\t\t\tif (sinceLast <= 0) {\n\t\t\t\t\tsinceLast = Self.InFirstPhase ? 0.4f : 0.2f;\n\n\t\t\t\t\tvar amount = 4;\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\tScale = 1.5f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tbuilder.Color = ProjectileColor.DesertRainbow[Rnd.Int(ProjectileColor.DesertRainbow.Length)];\n\n\t\t\t\t\t\tvar a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 2f) * Math.PI) * (i % 2 == 0 ? -1 : 1);\n\t\t\t\t\t\tbuilder.Shoot(a, 7f + (float) Math.Cos(Self.t * 2f) * 2f).Build();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (T >= 10f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class TileMoveState : SmartState<Pharaoh> {\n\t\t\tprivate Dot PickDot() {\n\t\t\t\tvar room = Self.GetComponent<RoomComponent>().Room;\n\t\t\t\tvar attempt = 0;\n\t\t\t\tvar toCheck = new List<Entity>();\n\n\t\t\t\ttoCheck.Add(Self);\n\t\t\t\ttoCheck.AddRange(room.Tagged[Tags.Player]);\n\n\t\t\t\tDot spot;\n\n\t\t\t\tdo {\n\t\t\t\t\tspot = new Dot(Rnd.Int(room.MapX + 3, room.MapX + room.MapW - 3),\n\t\t\t\t\t\tRnd.Int(room.MapY + 3, room.MapY + room.MapH - 3));\n\n\t\t\t\t\tvar vector = spot * 16 + new Vector2(8, 8);\n\t\t\t\t\tvar found = false;\n\t\t\t\t\t\n\t\t\t\t\tforeach (var e in toCheck) {\n\t\t\t\t\t\tif (e.DistanceTo(vector) <= 48f) {\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!found) {\n\t\t\t\t\t\treturn spot;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (attempt++ > 30) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t} while (true);\n\n\t\t\t\treturn spot;\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar spot = PickDot();\n\t\t\t\tvar to = PickDot();\n\n\t\t\t\tif (spot == null || to == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar sx = Rnd.Int(1, 4);\n\t\t\t\tvar sy = Rnd.Int(1, 4);\n\n\t\t\t\tfor (var x = sx > 2 ? -1 : 0; x < sx; x++) {\n\t\t\t\t\tfor (var y = sy > 2 ? -1 : 0; y < sy; y++) {\n\t\t\t\t\t\tvar x1 = x;\n\t\t\t\t\t\tvar y1 = y;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tvar part = new TileParticle();\n\n\t\t\t\t\t\t\tpart.FromBottom = true;\n\t\t\t\t\t\t\tpart.Top = Run.Level.Tileset.FloorA[0];\n\t\t\t\t\t\t\tpart.TopTarget = Run.Level.Tileset.WallTopADecor;\n\t\t\t\t\t\t\tpart.Side = Run.Level.Tileset.WallA[0];\n\t\t\t\t\t\t\tpart.Sides = Run.Level.Tileset.WallSidesA[2];\n\t\t\t\t\t\t\tpart.Tile = Tile.WallA;\n\n\t\t\t\t\t\t\tpart.X = (spot.X + x1) * 16;\n\t\t\t\t\t\t\tpart.Y = (spot.Y + y1) * 16 + 8;\n\t\t\t\t\t\t\tpart.Target.X = (to.X + x1) * 16;\n\t\t\t\t\t\t\tpart.Target.Y = (to.Y + y1) * 16 + 8;\n\n\t\t\t\t\t\t\tSelf.Area.Add(part);\n\t\t\t\t\t\t}, Rnd.Float(1f));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 4f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class SwitchPhaseState : SmartState<Pharaoh> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tvar am = 24;\n\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\");\n\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\tfor (var j = 0; j < 2; j++) {\n\t\t\t\t\tvar j1 = j;\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar z = (j1 == 0 ? am : am / 2);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (var i = 0; i < z; i++) {\n\t\t\t\t\t\t\tvar a = Math.PI * 2 * ((i + j1 * 0.5f) / z);\n\n\t\t\t\t\t\t\tbuilder.Scale = j1 == 0 ? 1f : 2f;\n\t\t\t\t\t\t\tbuilder.Shoot(a, 7f + j1 * 2).Build();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_shot\");\n\t\t\t\t\t}, j);\n\t\t\t\t}\n\n\t\t\t\tBecome<IdleState>();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\t\n\t\t\t\tif (T >= 2f) {\n\t\t\t\t\tBecome<SummoningState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class SummoningState : SmartState<Pharaoh> {\n\t\t\tprivate bool summoned;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!summoned && T >= 1f) {\n\t\t\t\t\tsummoned = true;\n\t\t\t\t\t\n\t\t\t\t\tvar amount = Self.InThirdPhase ? 4 : 2;\n\t\t\t\t\tvar d = 16;\n\n\t\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\t\tvar i1 = i;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_summon\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar mummy = new Mummy();\n\t\t\t\t\t\t\tSelf.Area.Add(mummy);\n\t\t\t\t\t\t\tmummy.BottomCenter = Self.BottomCenter + MathUtils.CreateVector(i1 / (float) amount * Math.PI * 2, d);\n\t\t\t\t\t\t\tmummy.GetComponent<StateComponent>().Become<Mummy.SummonedState>();\n\t\t\t\t\t\t}, i * 0.5f);\n\t\t\t\t\t}\n\t\t\t\t} else if (summoned && T >= 2f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class TeleportState : SmartState<Pharaoh> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_adidos\");\n\n\t\t\t\tTween.To(0, 255, x => Self.GetComponent<MobAnimationComponent>().Tint.A = (byte) x, 0.5f).OnEnd = () => {\n\t\t\t\t\tvar tile = Self.GetComponent<RoomComponent>().Room.GetRandomWallFreeTile() * 16;\n\n\t\t\t\t\tSelf.BottomCenter = tile + new Vector2(8, 8); \n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_pharaoh_appear\");\n\n\t\t\t\t\tTween.To(255, 0, x => Self.GetComponent<MobAnimationComponent>().Tint.A = (byte) x, 0.5f).OnEnd = () => {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tbase.PlaceRewards();\n\t\t\tAchievements.Unlock(\"bk:mummified\");\n\t\t}\n\n\t\tpublic override string GetScream() {\n\t\t\treturn \"pharaoh_scream\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/QueenBee.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.jungle;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.entity.projectile.pattern;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss {\n\tpublic class QueenBee : Boss {\n\t\tpublic bool InSecondPhase {\n\t\t\tget {\n\t\t\t\tvar p = GetComponent<HealthComponent>().Percent;\n\t\t\t\treturn p > 0.33f && p <= 0.66f;\n\t\t\t}\n\t\t}\n\n\t\tpublic bool InThirdPhase => GetComponent<HealthComponent>().Percent <= 0.33f;\n\t\tpublic bool InFirstPhase => GetComponent<HealthComponent>().Percent > 0.66f;\n\t\tpublic int Phase => (InThirdPhase ? 3 : (InSecondPhase ? 2 : 1));\n\n\t\tprivate int lastPhase = 1;\n\t\tprivate float lastParticle;\n\t\tprivate int penetrateCount;\n\t\tprivate int attack;\n\t\tprivate bool changingPhase;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 23;\n\t\t\tHeight = 19;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 4, 21, 14));\n\n\t\t\tvar body = new RectBodyComponent(2, 17, 19, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 3;\n\n\t\t\tAddAnimation(\"bigbee\");\n\t\t\tSetMaxHp(340);\n\n\t\t\tFlying = true;\n\t\t\tDepth = Layers.FlyingMob;\n\t\t}\n\n\t\tprotected override void AddPhases() {\n\t\t\tbase.AddPhases();\n\t\t\t\n\t\t\tHealthBar.AddPhase(0.33f);\n\t\t\tHealthBar.AddPhase(0.66f);\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastParticle -= dt;\n\n\t\t\tif (lastParticle <= 0) {\n\t\t\t\tlastParticle = 0.1f;\n\n\t\t\t\tif (!IsFriendly()) {\n\t\t\t\t\tvar s = GraphicsComponent.Flipped ? -1 : 1;\n\t\t\t\t\t\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(6 * s, -5.5f),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tOffset = new Vector2(9 * s, -5.5f),\n\t\t\t\t\t\tOwner = this,\n\t\t\t\t\t\tSize = 0.5f,\n\t\t\t\t\t\tDepth = Depth + 1\n\t\t\t\t\t});\n\n\t\t\t\t\tif (Died) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar p = Phase;\n\n\t\t\t\t\tif (lastPhase != p) {\n\t\t\t\t\t\tlastPhase = p;\n\t\t\t\t\t\tchangingPhase = true;\n\t\t\t\t\t\tBecome<ToCenterState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void ModifyBuilder(ProjectileBuilder builder) {\n\t\t\tif (InThirdPhase) {\n\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t}\n\t\t}\n\t\t\n\t\t#region Queen Bee States\n\t\tpublic override void SelectAttack() {\n\t\t\tbase.SelectAttack();\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target == null) {\n\t\t\t\tBecome<FriendlyState>();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class IdleState : SmartState<QueenBee> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\tif (Self.penetrateCount != 0) {\n\t\t\t\t\t\tBecome<PrepareToPenetrateState>();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar a = Self.attack = (Self.attack + 1) % (Self.InFirstPhase ? 3 : 4);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (a == 1) {\n\t\t\t\t\t\t\tSelf.penetrateCount++;\n\t\t\t\t\t\t} else if (a == 2) {\n\t\t\t\t\t\t\tBecome<ToCenterState>();\n\t\t\t\t\t\t} else if (a == 3) {\n\t\t\t\t\t\t\tBecome<MachineGunState>();\n\t\t\t\t\t\t} else if (a == 0) {\n\t\t\t\t\t\t\tif (Self.InSecondPhase || (Self.InThirdPhase && Rnd.Chance())) {\n\t\t\t\t\t\t\t\tBecome<CircleState>();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tBecome<SpamBeesState>();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class MachineGunState : SmartState<QueenBee> {\n\t\t\tprivate float sinceLast;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tsinceLast += dt;\n\n\t\t\t\tif (sinceLast >= 0.5f) {\n\t\t\t\t\tsinceLast = 0;\n\t\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\t\t\t\t\tvar second = Self.InThirdPhase;\n\n\t\t\t\t\tfor (var i = 0; i < (second ? 1 : 3); i++) {\n\t\t\t\t\t\tvar i1 = i;\n\t\t\t\t\t\t\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tif (second) {\n\t\t\t\t\t\t\t\tvar pp = new ProjectilePattern(CircleProjectilePattern.Make(9f, i1 % 2 == 0 ? -10 : 10)) {\n\t\t\t\t\t\t\t\t\tPosition = Self.Center\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\t\t\t\tfor (var j = 0; j < 4; j++) {\n\t\t\t\t\t\t\t\t\tbuilder.Slice = j % 2 == 0 ? \"circle\" : \"small\";\n\t\t\t\t\t\t\t\t\tbuilder.Color = j % 2 == 0 ? ProjectileColor.Orange : ProjectileColor.Red;\n\n\t\t\t\t\t\t\t\t\tpp.Add(builder.Build());\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tpp.Launch(a, 80);\n\t\t\t\t\t\t\t\tSelf.Area.Add(pp);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\t\t\tScale = Rnd.Float(0.8f, 1f),\n\t\t\t\t\t\t\t\t\tColor = Rnd.Chance() ? ProjectileColor.Yellow : ProjectileColor.Orange,\n\t\t\t\t\t\t\t\t\tLightRadius = 64\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\t\t\t\tbuilder.Shoot(a + Rnd.Float(-0.1f, 0.1f), 30f).Build();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_bee_shot\");\n\t\t\t\t\t\t}, i * 0.15f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar t = T + Math.PI * 0.5f;\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tvar x = r.CenterX + (float) Math.Cos(t) * (r.Width * 0.4f);\n\t\t\t\tvar y = r.CenterY - r.Height * 0.2f + (float) Math.Sin(t * 2) * (r.Height * 0.2f);\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tvar dx = x - Self.CenterX;\n\t\t\t\tvar dy = y - Self.CenterY;\n\t\t\t\t\n\t\t\t\tvar s = (dt * 10);\n\t\t\t\t\n\t\t\t\tSelf.CenterX += dx * s;\n\t\t\t\tSelf.CenterY += dy * s;\n\t\t\t\tSelf.GraphicsComponent.Flipped = dx < 0;\n\t\t\t\t\n\n\t\t\t\tif (t >= Math.PI * 4.5f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class PrepareToPenetrateState : SmartState<QueenBee> {\n\t\t\tprivate float x;\n\t\t\tprivate bool locked;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.penetrateCount++;\n\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r.CenterX > Self.CenterX) {\n\t\t\t\t\tx = r.X + 32;\n\t\t\t\t} else {\n\t\t\t\t\tx = r.Right - 32;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (locked) {\n\t\t\t\t\tif (T >= 0.3f) {\n\t\t\t\t\t\tBecome<PenetrateState>();\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\t\t\t\tbody.Velocity += new Vector2((x > Self.CenterX ? 1 : -1) * dt * 360, 0);\n\n\t\t\t\tvar py = Self.Target.CenterY;\n\t\t\t\tvar sy = Self.CenterY;\n\t\t\t\t\n\t\t\t\tbody.Velocity += new Vector2(0, (py > sy ? 1 : -1) * dt * 360);\n\n\t\t\t\tif (Math.Abs(py - sy) < 6 && Math.Abs(x - Self.CenterX) < 16) {\n\t\t\t\t\tSelf.GraphicsComponent.Flipped = !Self.GraphicsComponent.Flipped;\n\t\t\t\t\tlocked = true;\n\t\t\t\t\tT = 0;\n\t\t\t\t\tbody.Velocity = Vector2.Zero;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\tpublic class CircleState : SmartState<QueenBee> {\n\t\t\tprivate float sinceLast;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tsinceLast += dt;\n\t\t\t\tvar t = T * (Self.InSecondPhase ? 1.5f : 2f);\n\n\t\t\t\tif (sinceLast >= 0.15f) {\n\t\t\t\t\tsinceLast = 0;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\tScale = Rnd.Float(0.5f, 1f),\n\t\t\t\t\t\tLightRadius = 64\n\t\t\t\t\t};\n\n\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\tbuilder.Shoot(t + Math.PI + Rnd.Float(-0.1f, 0.1f), Rnd.Float(4f, 10f)).Build();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tvar x = Self.Target.CenterX + (float) Math.Cos(t) * (r.Width * 0.3f);\n\t\t\t\tvar y = Self.Target.CenterY + (float) Math.Sin(t) * (r.Height * 0.3f);\n\t\t\t\t\n\t\t\t\tvar dx = x - Self.CenterX;\n\t\t\t\tvar dy = y - Self.CenterY;\n\t\t\t\t\n\t\t\t\tvar s = (dt * 4);\n\t\t\t\t\n\t\t\t\tSelf.CenterX += dx * s;\n\t\t\t\tSelf.CenterY += dy * s;\n\t\t\t\tSelf.GraphicsComponent.Flipped = dx < 0;\n\n\t\t\t\tif (t >= Math.PI * 6f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class PenetrateState : SmartState<QueenBee> {\n\t\t\tprivate float x;\n\t\t\tprivate float sign;\n\t\t\tprivate float delay = 1;\n\t\t\tprivate float lastBullet;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r.CenterX < Self.CenterX) {\n\t\t\t\t\tx = r.X + 32;\n\t\t\t\t\tsign = -1;\n\t\t\t\t} else {\n\t\t\t\t\tx = r.Right - 32;\n\t\t\t\t\tsign = 1;\n\t\t\t\t}\n\n\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tvar v = Self.penetrateCount;\n\t\t\t\tvar max = 2 + Self.Phase * 2;\n\n\t\t\t\tif (v == max) {\n\t\t\t\t\tSelf.penetrateCount = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\n\t\t\t\tif ((Self.CenterX - x) * sign >= -16) {\n\t\t\t\t\tbody.Velocity -= body.Velocity * (dt * 2);\n\t\t\t\t\tdelay -= dt;\n\n\t\t\t\t\tif (delay <= 0) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!Self.InFirstPhase) {\n\t\t\t\t\tlastBullet -= dt;\n\n\t\t\t\t\tif (lastBullet <= 0) {\n\t\t\t\t\t\tlastBullet = 0.2f;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar a = (sign < 0 ? Math.PI : 0) + Rnd.Float(-1f, 1f);\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\tBounce = 5,\n\t\t\t\t\t\t\tColor = ProjectileColor.Orange,\n\t\t\t\t\t\t\tLightRadius = 64,\n\t\t\t\t\t\t\tScale = Rnd.Float(0.6f, 2f)\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\t\tvar p = builder.Shoot(a, Rnd.Float(3f, 10f)).Build();\n\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.25f));\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_bee_shot\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSelf.X += sign * dt * 360;\n\t\t\t\tbody.Velocity += new Vector2(sign * dt * 3600, 0);\n\t\t\t}\n\t\t}\n\n\t\tpublic class ToCenterState : SmartState<QueenBee> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\t\t\t\tvar dx = r.CenterX - Self.CenterX;\n\t\t\t\tvar dy = r.CenterY - Self.CenterY;\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tif (d <= 32f) {\n\t\t\t\t\tif (Self.changingPhase) {\n\t\t\t\t\t\tSelf.changingPhase = false;\n\t\t\t\t\t\tBecome<RageState>();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar s = (dt * 3600 / d) * (d > 48 ? 1 : d / 48);\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity += new Vector2(dx * s, dy * s);\n\t\t\t}\n\t\t}\n\n\t\tpublic class SpamBeesState : SmartState<QueenBee> {\n\t\t\tprivate float sinceLast;\n\t\t\tprivate int count;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (count < 5) {\n\t\t\t\t\tsinceLast += dt;\n\n\t\t\t\t\tif (sinceLast >= 1f - Self.Phase * 0.25f) {\n\t\t\t\t\t\tsinceLast = 0;\n\t\t\t\t\t\tcount++;\n\n\t\t\t\t\t\tvar bee = BeeHive.GenerateBee();\n\t\t\t\t\t\tSelf.Area.Add(bee);\n\t\t\t\t\t\tbee.Center = Self.Center;\n\t\t\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animate();\n\t\t\t\t\t}\n\n\t\t\t\t\tT = 0;\n\t\t\t\t}\n\n\t\t\t\tif (T >= 1) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class RageState : SmartState<QueenBee> {\n\t\t\tprivate int count;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 0.1f) {\n\t\t\t\t\tcount++;\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tif (count == 32) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\tvar a = (count * 3 / 8f * Math.PI) + Rnd.Float(-0.5f, 0.5f);\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\tScale = Rnd.Float(1f, 2f),\n\t\t\t\t\t\tColor = Rnd.Chance() ? ProjectileColor.Yellow : ProjectileColor.Orange,\n\t\t\t\t\t\tLightRadius = 64\n\t\t\t\t\t};\n\n\t\t\t\t\tSelf.ModifyBuilder(builder);\n\n\t\t\t\t\tbuilder.Shoot(a, 30f).Build();\n\n\t\t\t\t\tCamera.Instance.Shake(2);\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_bee_swirly_shot\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is Prop) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.ShouldCollide(entity) && !(entity is Level);\n\t\t}\n\n\t\tpublic override void PlaceRewards() {\n\t\t\tbase.PlaceRewards();\n\t\t\tAchievements.Unlock(\"bk:sting_operation\");\n\t\t}\n\n\t\tpublic override string GetScream() {\n\t\t\treturn \"queen_bee_scream\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmBulletDodgeRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmBulletDodgeRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.BottomCenter = new Vector2((Right - 1) * 16 - 8, GetTileCenter().Y * 16 + 8);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.BottomCenter = new Vector2((Left + 1) * 16 + 8, GetTileCenter().Y * 16 + 8);\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tvar x = (Right - 2) * 16 - 8;\n\t\t\tvar wall = Tiles.Pick(Tile.WallA, Tile.EvilWall);\n\t\t\t\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Top + 1), new Dot(Right - 7, Top + 1), wall);\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Bottom - 1), new Dot(Right - 7, Bottom - 1), wall);\n\t\t\t\n\t\t\tfor (var y = Top + 2; y < Bottom - 1; y++) {\n\t\t\t\tvar turret = new Turret {\n\t\t\t\t\tStartingAngle = 4\n\t\t\t\t};\n\n\t\t\t\tlevel.Area.Add(turret);\n\t\t\t\tturret.BottomCenter = new Vector2(x, y * 16 + 12);\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 30;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 40;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 13;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmEndRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmEndRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.Center = room.Center;\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.Center = room.Center + new Vector2(0, 32);\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmEnemyRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmEnemyRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.Center = GetTileCenter() * 16 - new Vector2(0, 64);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.Center = GetTileCenter() * 16;\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tvar c = GetCenter();\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect().Setup(c.X - 2, c.Y - 2, 5, 5), Tile.WallA);\n\t\t\tPainter.Fill(level, new Rect().Setup(c.X - 1, c.Y - 1, 3, 3), Tiles.RandomFloor());\n\n\t\t\tvar placed = false;\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tplaced = true;\n\t\t\t\tPainter.Set(level, new Dot(c.X, c.Y - 2), Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tplaced = true;\n\t\t\t\tPainter.Set(level, new Dot(c.X, c.Y + 2), Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tplaced = true;\n\t\t\t\tPainter.Set(level, new Dot(c.X - 2, c.Y), Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tif (!placed || Rnd.Chance()) {\n\t\t\t\tPainter.Set(level, new Dot(c.X + 2, c.Y), Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, new Dot(c.X, c.Y), Tile.FloorD); // Tiles.RandomFloor());\n\t\t\t\n\t\t\tMobRegistry.SetupForBiome(Biome.Tech);\n\t\t\tPainter.PlaceMobs(level, room);\n\t\t}\n\n\t\tpublic override float GetWeightModifier() {\n\t\t\treturn 0.25f;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 30;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 30;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmMazeRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmMazeRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.BottomCenter = room.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.BottomCenter = room.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tvar maze = Maze.Generate(this);\n\t\t\tvar wall = Tile.WallA;\n\n\t\t\tfor (int x = 1; x < maze.Length - 1; x++) {\n\t\t\t\tfor (int y = 1; y < maze[0].Length - 1; y++) {\n\t\t\t\t\tif (maze[x][y]) {\n\t\t\t\t\t\tPainter.Set(level, x + Left, y + Top, wall);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 30;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 30;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 20;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmPadsRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmPadsRoom : DmRoom {\n\t\tprivate Dot magePos;\n\t\tprivate Dot playerPos;\n\t\t\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.BottomCenter = magePos * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.BottomCenter = playerPos * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\n\t\t\tvar gap = 2;\n\t\t\t\n\t\t\tvar xcollumn = Rnd.Int(2, 5);\n\t\t\tvar ycollumn = Rnd.Chance(20) ? Rnd.Int(2, 5) : xcollumn;\n\t\t\tvar w = GetWidth();\n\t\t\tvar h = GetHeight();\n\t\t\tvar gx = (gap + xcollumn);\n\t\t\tvar gy = (gap + ycollumn);\n\n\t\t\tvar xcount = (int) Math.Ceiling((w - (float) xcollumn) / gx);\n\t\t\tvar ycount = (int) Math.Ceiling((h - (float) ycollumn) / gy);\n\n\t\t\tvar xw = xcount * gx - xcollumn;\n\t\t\tvar yw = ycount * gy - ycollumn;\n\n\t\t\tvar xo = (int) Math.Min(Math.Floor((w - xw) / 2f), 2);\n\t\t\tvar yo = (int) Math.Min(Math.Floor((h - yw) / 2f), 2);\n\n\t\t\tvar spots = new List<Dot>();\n\t\t\t\n\t\t\tfor (var x = 0; x < xcount; x++) {\n\t\t\t\tfor (var y = 0; y < ycount; y++) {\n\t\t\t\t\tspots.Add(new Dot(Left + xo + x * gx, Top + yo + y * gy));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar i = Rnd.Int(spots.Count);\n\t\t\tmagePos = spots[i] + new Dot(1);\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect(magePos.X - 1, magePos.Y - 1).Resize(Math.Max(3, xcollumn), Math.Max(3, ycollumn)), Tiles.RandomFloor());\n\t\t\tPainter.Set(level, magePos.X - 1, magePos.Y - 1, Tile.WallA);\n\t\t\tPainter.Set(level, magePos.X + 1, magePos.Y - 1, Tile.WallA);\n\t\t\tPainter.Set(level, magePos.X - 1, magePos.Y + 1, Tile.WallA);\n\t\t\tPainter.Set(level, magePos.X + 1, magePos.Y + 1, Tile.WallA);\n\t\t\t\n\t\t\tspots.RemoveAt(i);\n\t\t\t\n\t\t\ti = Rnd.Int(spots.Count);\n\t\t\tplayerPos = spots[i] + new Dot(1);\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect(playerPos.X - 1, playerPos.Y - 1).Resize(xcollumn, ycollumn), Tiles.RandomFloor());\n\t\t\tspots.RemoveAt(i);\n\n\t\t\tforeach (var s in spots) {\n\t\t\t\tPainter.Fill(level, new Rect(s.X, s.Y).Resize(xcollumn, ycollumn), Rnd.Chance(5) ? Tiles.RandomFloor() : Tile.SensingSpikeTmp);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 28;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 28;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmPlatformRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmPlatformRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tmage.BottomCenter = new Dot(Right - 2, Bottom - 2) * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tplayer.BottomCenter = new Dot(Left + 2, Top + 2) * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect().Setup(Left + 1, Top + 1, 2, 2), Tiles.RandomFloor());\n\t\t\tPainter.Fill(level, new Rect().Setup(Left + 1, Top + GetHeight() / 2, 2, 2), Tiles.RandomFloor());\n\t\t\tPainter.Fill(level, new Rect().Setup(Left + 1, Bottom - 2, 2, 2), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect().Setup(Right - 2, Top + 1, 2, 2), Tiles.RandomFloor());\n\t\t\tPainter.Fill(level, new Rect().Setup(Right - 2, Top + GetHeight() / 2, 2, 2), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect().Setup(Right - 3, Bottom - 3, 3, 3), Tiles.RandomFloor());\n\t\t\tPainter.Fill(level, new Rect().Setup(Right - 3, Bottom - 3, 2, 2), Tile.WallA);\n\t\t\tPainter.Fill(level, new Rect().Setup(Right - 2, Bottom - 2, 2, 2), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPlatform(level, Left + 3, Top + 1);\n\t\t\tPlatform(level, Right - 4, Top + GetHeight() / 2);\n\t\t\tPlatform(level, Left + 3, Bottom - 2);\n\t\t\t\n\t\t\tPlatform(level, Right - 2, Top + GetHeight() / 2 - 3, true);\n\t\t\tPlatform(level, Left + 1, Top + GetHeight() / 2 + 5, true);\n\t\t}\n\n\t\tprivate void Platform(Level level, int x, int y, bool vertical = false) {\n\t\t\tlevel.Area.Add(new MovingPlatform {\n\t\t\t\tController = vertical ? PlatformController.UpDown : PlatformController.LeftRight,\n\t\t\t\tPosition = new Vector2(x, y) * 16\n\t\t\t});\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 17;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 21;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.rooms.regular;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic abstract class DmRoom : RegularRoom {\n\t\tpublic abstract void PlaceMage(Room room, DM mage);\n\t\tpublic abstract void PlacePlayer(Room room, Player player);\n\t\tpublic abstract void Paint(Level level, Room room);\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmRoomRegistry.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic static class DmRoomRegistry {\n\t\tpublic static Type[] Rooms = {\n\t\t\ttypeof(DmEnemyRoom),\n\t\t\ttypeof(DmMazeRoom),\n\t\t\ttypeof(DmBulletDodgeRoom),\n\t\t\ttypeof(DmPlatformRoom),\n\t\t\ttypeof(DmPadsRoom),\n\t\t\ttypeof(DmSpikeRoom)\n\t\t};\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/boss/rooms/DmSpikeRoom.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.boss.rooms {\n\tpublic class DmSpikeRoom : DmRoom {\n\t\tpublic override void PlaceMage(Room room, DM mage) {\n\t\t\tvar w = new Dot(Rnd.Int(Left + 1, Right), Top + 2);\n\t\t\t\n\t\t\tPainter.Fill(Run.Level, new Rect().Setup(w.X - 1, w.Y - 1, 3, 2), Tile.FloorA);\n\t\t\t\n\t\t\tmage.BottomCenter = w * 16 + new Vector2(8, -8);\n\t\t\tPainter.DrawLine(Run.Level, new Dot(w.X - 1, w.Y), new Dot(w.X + 1, w.Y), Tile.WallA);\n\t\t}\n\n\t\tpublic override void PlacePlayer(Room room, Player player) {\n\t\t\tvar w = new Dot(Rnd.Int(Left + 1, Right), Bottom - 1);\n\t\t\t\n\t\t\tPainter.Fill(Run.Level, new Rect().Setup(w.X - 1, w.Y - 1, 3, 2), Tile.FloorA);\n\t\t\tplayer.BottomCenter = w * 16 + new Vector2(8);\n\t\t}\n\n\t\tpublic override void Paint(Level level, Room room) {\n\t\t\tPainter.Fill(level, this, 1, Tile.SpikeOffTmp);\n\t\t\t\n\t\t\troom.AddController(\"bk:spike_field\");\n\t\t\troom.Generate();\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 15;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 17;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 23;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/BabySlime.cs",
    "content": "using BurningKnight.assets.lighting;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob.prefabs;\r\nusing Lens.graphics;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature.mob.castle {\r\n\tpublic class BabySlime : Slime {\r\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#0069aa\");\r\n\t\t\r\n\t\tprotected override Color GetBloodColor() {\r\n\t\t\treturn color;\r\n\t\t}\r\n\r\n\t\tprotected override float GetJumpDelay() {\r\n\t\t\treturn Rnd.Float(0.5f, 1.2f) - 0.2f;\r\n\t\t}\r\n\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddComponent(new ZAnimationComponent(\"baby_slime\"));\r\n\t\t\tSetMaxHp(1);\r\n\r\n\t\t\tvar body = new RectBodyComponent(4, 9, 8, 7);\r\n\t\t\tAddComponent(body);\r\n\r\n\t\t\tbody.Body.LinearDamping = 2;\r\n\t\t\tbody.KnockbackModifier = 0.5f;\r\n\t\t\t\r\n\t\t\tAddComponent(new SensorBodyComponent(4, 15, 8, 1));\r\n\t\t\t\r\n\t\t\tAddComponent(new LightComponent(this, 32, MotherSlime.LightColor));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Bandit.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.projectile;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.entity.component.logic;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature.mob.castle {\r\n\tpublic class Bandit : Mob {\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddAnimation(\"bandit\");\r\n\t\t\tSetMaxHp(Run.Depth);\r\n\t\t\t\r\n\t\t\tBecome<IdleState>();\r\n\r\n\t\t\tvar body = new RectBodyComponent(3, 13, 10, 1);\r\n\t\t\tAddComponent(body);\r\n\t\t\tbody.Body.LinearDamping = 10;\r\n\r\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 12, 12));\r\n\r\n\t\t\tmoveId = Rnd.Int(0, 2);\r\n\t\t}\r\n\r\n\t\tprivate int moveId;\r\n\t\t\r\n\t\t#region Bandit States\r\n\t\tpublic class IdleState : SmartState<Bandit> {\r\n\t\t\tprivate float delay;\r\n\t\t\tprivate float fireDelay;\r\n\t\t\tprivate bool fired;\r\n\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\tdelay = Rnd.Float(1, 2.5f);\r\n\t\t\t\tfireDelay = Self.moveId % 2 == 0 ? 3 : Rnd.Float(0.5f, delay - 0.5f);\r\n\t\t\t\tSelf.moveId++;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (T >= delay) {\r\n\t\t\t\t\tBecome<RunState>();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!fired && T >= fireDelay) {\r\n\t\t\t\t\tfired = true;\r\n\r\n\t\t\t\t\tif (!Self.CanSeeTarget()) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\r\n\t\t\t\t\t\r\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\r\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\r\n\r\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\r\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\r\n\r\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\r\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\r\n\r\n\t\t\t\t\t\t\tif (Self.Target == null) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tvar ac = 0.1f;\r\n\t\t\t\t\t\t\tvar angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\r\n\r\n\t\t\t\t\t\t\tvar p = new ProjectileBuilder(Self, \"small\") {\r\n\t\t\t\t\t\t\t\tPoof = true,\r\n\t\t\t\t\t\t\t\tLightRadius = 32f\r\n\t\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\t\tp.AddFlags(ProjectileFlags.FlyOverStones);\r\n\r\n\t\t\t\t\t\t\tp.Shoot(angle, 8f);\r\n\t\t\t\t\t\t\tp.Move(angle, 8f);\r\n\t\t\t\t\t\t\tp.Build();\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic class RunState : SmartState<Bandit> {\r\n\t\t\tprivate Vector2 velocity;\r\n\t\t\tprivate float timer;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\ttimer = Rnd.Float(0.4f, 1f);\r\n\t\t\t\t\r\n\t\t\t\tvar angle = Rnd.AnglePI();\r\n\t\t\t\tvar force = 120f + Rnd.Float(50f);\r\n\t\t\t\t\r\n\t\t\t\tif (Rnd.Chance() && Self.Target != null) {\r\n\t\t\t\t\tvar ac = 0.1f;\r\n\t\t\t\t\tangle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\r\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\r\n\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Destroy() {\r\n\t\t\t\tbase.Destroy();\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\tif (timer <= T) {\r\n\t\t\t\t\tBecome<IdleState>();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity * Math.Min(1, timer - T * 0.4f);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent ev) {\r\n\t\t\t\tif (ev.Entity is Door) {\r\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\r\n\r\n\t\t\t\t\tif (s is RunState) {\r\n\t\t\t\t\t\tBecome<IdleState>();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tprotected override string GetDeadSfx() {\r\n\t\t\treturn \"mob_bandit_death\";\r\n\t\t}\r\n\r\n\t\tprotected override string GetHurtSfx() {\r\n\t\t\treturn \"mob_bandit_damage\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/BigSlime.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.events;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class BigSlime : Slime {\n\t\tprotected override float GetJumpDelay() {\n\t\t\treturn 1 + Rnd.Float(0.7f, 1.6f);\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(GetSprite()));\n\t\t\tSetMaxHp(4);\n\n\t\t\tvar body = new RectBodyComponent(1, 15, 14, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 7, 12, 9));\n\t\t}\n\n\t\tprotected virtual string GetSprite() {\n\t\t\treturn Events.Halloween ? \"spooky_big_slime\" : \"big_slime\";\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\tvar slime = new SimpleSlime();\n\t\t\t\tArea.Add(slime);\n\t\t\t\tslime.BottomCenter = BottomCenter;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleDeath(d);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/BlueBulletSlime.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class BlueBulletSlime : BulletSlime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#00cdf9\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\tSetMaxHp(4);\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"blue_bullet_slime\";\n\t\t}\n\n\t\tprotected override void DoSpit() {\n\t\t\tvar am = 8;\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tColor = ProjectileColor.Cyan,\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am);\n\t\t\t\tvar projectile = builder.Shoot(a + Rnd.Float(-0.1f, 0.1f), 5f).Build();\n\t\t\t\t\t\n\t\t\t\tprojectile.Center = BottomCenter;\n\t\t\t}\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tif (GetComponent<HealthComponent>().Dead) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\t\tGetComponent<ZAnimationComponent>().Animate();\n\n\t\t\t\tvar b = new ProjectileBuilder(this, \"small\") {\n\t\t\t\t\tColor = ProjectileColor.Blue,\n\t\t\t\t\tLightRadius = 48f\n\t\t\t\t};\n\n\t\t\t\tb.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\tb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am + 0.5f);\n\t\t\t\t\tvar projectile = b.Shoot(a + Rnd.Float(-0.1f, 0.1f), 8f).Build();\n\t\t\t\t\t\n\t\t\t\t\tprojectile.Center = BottomCenter;\n\t\t\t\t\tprojectile.Color = ProjectileColor.Blue;\n\t\t\t\t}\n\t\t\t}, 1f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/BulletSlime.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class BulletSlime : Slime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#ff0000\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\n\t\tprotected override float GetJumpDelay() {\n\t\t\treturn 1 + Rnd.Float(0.5f, 1.2f);\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(GetSprite()));\n\t\t\tSetMaxHp(5);\n\n\t\t\tvar body = new RectBodyComponent(1, 15, 14, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 7, 12, 9));\n\t\t}\n\n\t\tprotected virtual string GetSprite() {\n\t\t\treturn \"bullet_slime\";\n\t\t}\n\n\t\tprotected override void OnLand() {\n\t\t\tbase.OnLand();\n\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDoSpit();\n\t\t}\n\n\t\tprotected virtual void DoSpit() {\n\t\t\tvar am = 8;\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am);\n\t\t\t\tvar projectile = builder.Shoot(a, 5f).Build();\n\t\t\t\tprojectile.Center = BottomCenter;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Caster.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Caster : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"caster\");\n\t\t\tSetMaxHp(4);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(8, 3, 8, 13);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\tbody.Body.LinearDamping = 0;\n\n\t\t\tWidth = 22;\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 50f, new Color(1f, 1f, 0.7f, 1f)));\n\t\t}\n\n\t\t#region Caster States\n\t\tpublic class IdleState : SmartState<Caster> {\n\t\t\tprivate float delay;\n\t\t\tprivate float lastBullet;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(0.5f, 2f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T < delay) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlastBullet -= dt;\n\n\t\t\t\tif (lastBullet <= 0f) {\n\t\t\t\t\tlastBullet = 1f;\n\n\t\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\t\tvar an = Self.AngleTo(Self.Target);\n\t\t\t\t\t\tvar a = Self.GetComponent<AnimationComponent>();\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"caster\") {\n\t\t\t\t\t\t\t\tColor = ProjectileColor.Blue,\n\t\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\t\tPoof = true\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbuilder.Move(an, 8);\n\t\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.AutomaticRotation, ProjectileFlags.FlyOverStones, ProjectileFlags.FlyOverWalls);\n\n\t\t\t\t\t\t\tvar projectile = builder.Shoot(an, 7f).Build();\n\t\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, MakeController());\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T - delay >= 3f) {\n\t\t\t\t\tBecome<DissappearState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate static ProjectileCallbacks.UpdateCallback MakeController() {\n\t\t\tvar lastPart = 0f;\n\t\t\t\n\t\t\treturn (pr, dt) => {\n\t\t\t\tlastPart += dt;\n\n\t\t\t\tif (lastPart >= 0.1f) {\n\t\t\t\t\tlastPart = 0;\n\n\t\t\t\t\tvar p = new ProjectileParticle();\n\t\t\t\t\tpr.Area.Add(p);\n\t\t\t\t\tp.Center = pr.Center; // + Random.Vector(3, 3);\n\t\t\t\t\t// give some velocity too??\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\t\n\t\t/*\n\t\t * todo:\n\t\t * projectile particles\n\t\t * tween light radius when tp\n\t\t * delay between appear and dissappear\n\t\t *\n\t\t * dont collide when appearing/dissappearing\n\t\t */\n\t\tpublic class DissappearState : SmartState<Caster> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"door_close\");\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<AppearState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class AppearState : SmartState<Caster> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.Center = Self.GetComponent<RoomComponent>().Room.GetRandomFreeTile() * 16;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"door_close\");\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Clown.cs",
    "content": "using BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Clown : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"clown\");\n\t\t\tSetMaxHp(3);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(2, 15, 12, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 2;\n\t\t\tbody.Body.LinearDamping = 0;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 12, 12));\n\t\t\t\n\t\t\tAddDrops(new SingleDrop(\"bk:bomb\", 0.1f));\n\n\t\t\tTouchDamage = 0;\n\t\t}\n\n\t\t#region Clown States\n\t\tpublic class IdleState : SmartState<Clown> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Clown> {\n\t\t\tprivate Vector2 target;\n\t\t\tprivate float delay;\n\t\t\tprivate bool away;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = 0;\n\t\t\t\t\n\t\t\t\tif (away) {\n\t\t\t\t\ttarget = Self.Center + MathUtils.CreateVector(Self.Target.AngleTo(Self) + Rnd.Float(-1, 1), 96f);\n\t\t\t\t\tdelay = Rnd.Float(1f, 2f);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdelay = Rnd.Float(0.3f, 1f);\n\t\t\t\tvar toTarget = Self.Target != null && Rnd.Chance();\n\n\t\t\t\tif (toTarget) {\n\t\t\t\t\ttarget = Self.Target.Center;\n\t\t\t\t} else {\n\t\t\t\t\ttarget = Self.GetComponent<RoomComponent>().Room.GetRandomFreeTile();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tvar dx = Self.DxTo(target);\n\t\t\t\tvar dy = Self.DyTo(target);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\tvar s = dt * 150;\n\n\t\t\t\tvar b = Self.GetComponent<RectBodyComponent>();\n\t\t\t\tb.Velocity += new Vector2(dx / d * s, dy / d * s);\n\n\t\t\t\tif (d <= 8 || T >= delay) {\n\t\t\t\t\tif (away) {\n\t\t\t\t\t\taway = false;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tInit();\n\t\t\t\t}\n\n\t\t\t\tif (!away && Self.Target != null && Self.DistanceTo(Self.Target) < 32) {\n\t\t\t\t\tvar bomb = new Bomb(Self, 1);\n\t\t\t\t\tSelf.Area.Add(bomb);\n\t\t\t\t\tbomb.Center = Self.Center;\n\t\t\t\t\tbomb.VelocityTo(Self.AngleTo(Self.Target));\n\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"mob_clown_bomb\", 2);\n\n\t\t\t\t\taway = true;\n\t\t\t\t\tInit();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent ee) {\n\t\t\t\tif (ee.Who is Mob) {\n\t\t\t\t\t// GetComponent<HealthComponent>().ModifyHealth(2, null);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else if (e is MobTargetChange ev) {\n\t\t\t\tif (ev.New == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_clown_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_clown_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Crab.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Crab : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tvertical = Rnd.Chance();\n\t\t\t\n\t\t\tWidth = 18;\n\t\t\tHeight = 14;\n\t\t\t\n\t\t\tAddAnimation(\"crab\");\n\t\t\tSetMaxHp(3);\n\t\t\t\n\t\t\tBecome<WaitState>();\n\n\t\t\tvar body = new RectBodyComponent(3, 13, 12, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(3, 2, 12, 12));\n\t\t\tAddDrops(new SingleDrop(\"bk:crabs_claw\", 0.01f));\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tbase.OnTargetChange(target);\n\n\t\t\tif (target != null) {\n\t\t\t\tBecome<IdleState>();\n\t\t\t} else {\n\t\t\t\tBecome<WaitState>();\n\t\t\t}\n\t\t}\n\n\t\tprivate bool vertical;\n\t\t\n\t\t#region Bandit States\n\t\tpublic class WaitState : SmartState<Crab> {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic class IdleState : SmartState<Crab> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate bool a;\n\t\t\tprivate float timer;\n\n\t\t\tpublic void Flip(bool force = false) {\n\t\t\t\ta = !a;\n\n\t\t\t\ttimer = Rnd.Float(1f, 10f);\n\n\t\t\t\tif (force || Rnd.Chance(25)) {\n\t\t\t\t\tSelf.vertical = !Self.vertical;\n\t\t\t\t\ta = Rnd.Chance();\n\t\t\t\t}\n\n\t\t\t\tvar f = 40;\n\t\t\t\tvelocity = new Vector2(Self.vertical ? 0 : (a ? -f : f), Self.vertical ? (a ? -f : f) : 0);\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\n\t\t\t\tvar an = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\tan.Animation.Frame = (uint) Rnd.Int(4);\n\t\t\t\tan.Animate();\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\ta = Rnd.Chance();\n\t\t\t\tFlip();\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tvar b = Self.GetComponent<RectBodyComponent>();\n\n\t\t\t\tif (T >= timer || b.Velocity.Length() < 20) {\n\t\t\t\t\tFlip(T >= timer);\n\t\t\t\t\tT = 0;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tb.Velocity = velocity;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door || ev.Entity is Level || ev.Entity is Chasm || (ev.Entity is SolidProp && !(ev.Entity is BreakableProp))) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is IdleState i) {\n\t\t\t\t\t\ti.Flip();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Ghost.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Ghost : Mob {\n\t\tpublic const float TargetRadius = 128f;\n\t\tpublic const byte Alpha = 50;\n\t\t\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#5ac54f\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"ghost\");\n\t\t\tSetMaxHp(2);\n\t\t\t\n\t\t\tFlying = true;\n\t\t\tDepth = Layers.FlyingMob;\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new SensorBodyComponent(2, 2, 12, 12);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 3;\n\t\t\t\n\t\t\tGetComponent<MobAnimationComponent>().Tint.A = Alpha;\n\t\t}\n\n\t\tprivate bool rage;\n\t\t\n\t\t#region Ghost States\n\t\tpublic class IdleState : SmartState<Ghost> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tvar color = Self.GetComponent<MobAnimationComponent>().Tint;\n\t\t\t\tTween.To(Alpha, color.A, x => Self.GetComponent<MobAnimationComponent>().Tint.A = (byte) x, 0.3f);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\t\n\t\t\t\t\n\t\t\t\tvar color = Self.GetComponent<MobAnimationComponent>().Tint;\n\t\t\t\tTween.To(255f, color.A, x => Self.GetComponent<MobAnimationComponent>().Tint.A = (byte) x, 0.3f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null && Self.Target.DistanceTo(Self) < TargetRadius) {\n\t\t\t\t\tBecome<ChaseState>();\n\t\t\t\t}\n\n\t\t\t\tSelf.CheckRage();\n\t\t\t}\n\t\t}\n\n\t\tpublic class ChaseState : SmartState<Ghost> {\n\t\t\tprivate bool rage;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\trage = Self.rage;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Fixme: this target stuff is bad for multiplayer, it will chase only random player, not closest\n\t\t\t\tfloat d = Self.Target.DistanceTo(Self);\n\n\t\t\t\tif (!rage) {\n\t\t\t\t\tSelf.CheckRage();\n\n\t\t\t\t\tif (Self.rage) {\n\t\t\t\t\t\trage = true;\n\t\t\t\t\t} else if (d > TargetRadius + 10f) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfloat a = Self.AngleTo(Self.Target);\n\t\t\t\tfloat force = (rage ? 200f : 100f) * dt;\n\n\t\t\t\tif (T < 0.5f) {\n\t\t\t\t\tforce *= 0.1f;\n\t\t\t\t}\n\n\t\t\t\tSelf.GetComponent<SensorBodyComponent>().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\tSelf.PushFromOtherEnemies(dt);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t\t\n\t\tprotected void CheckRage() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var m in room.Tagged[Tags.MustBeKilled]) {\n\t\t\t\tif (!(m is Ghost)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\n\t\t\t// RAAAAAAGE MOOOOOOOOOOOODE\n\t\t\trage = true;\n\t\t\t\n\t\t\tBecome<ChaseState>();\n\t\t\tGetComponent<HealthComponent>().InitMaxHealth = 4;\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is Prop) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.ShouldCollide(entity) && !(entity is Level);\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn $\"mob_ghost_hurt_{Rnd.Int(1, 3)}\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn $\"mob_ghost_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Gunner.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.projectile;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.entity.component.logic;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature.mob.castle {\r\n\tpublic class Gunner : Mob {\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddAnimation(\"gunner\");\r\n\t\t\tSetMaxHp(5);\r\n\t\t\t\r\n\t\t\tBecome<IdleState>();\r\n\t\t\t\r\n\t\t\tvar body = new RectBodyComponent(1, 15, 15, 1);\r\n\t\t\tAddComponent(body);\r\n\r\n\t\t\tbody.Body.LinearDamping = 6;\r\n\t\t\t\r\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 12, 12));\r\n\r\n\t\t\tmoveId = Rnd.Int(3);\r\n\t\t\tGetComponent<AudioEmitterComponent>().PitchMod = -0.3f;\r\n\t\t}\r\n\r\n\t\t#region Gunner States\r\n\t\tpublic class IdleState : SmartState<Gunner> {\r\n\t\t\tprivate float delay;\r\n\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\tdelay = Rnd.Float(0.4f, 1f);\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (T >= delay) {\r\n\t\t\t\t\tBecome<RunState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate int moveId;\r\n\t\t\r\n\t\tpublic class RunState : SmartState<Gunner> {\r\n\t\t\tprivate const float Accuracy = 0.2f;\r\n\t\t\t\r\n\t\t\tprivate Vector2 velocity;\r\n\t\t\tprivate float timer;\r\n\t\t\tprivate float lastBullet;\r\n\t\t\tprivate float angle;\r\n\t\t\tprivate bool fire;\r\n\t\t\tprivate float start;\r\n\t\t\tprivate bool saw;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\tfire = Self.Target != null && Self.moveId % 2 == 0;\r\n\t\t\t\tangle = !fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target);\r\n\t\t\t\ttimer = fire ? 0.9f : Rnd.Float(0.8f, 2f);\r\n\t\t\t\tstart = Rnd.Float(0f, 10f);\r\n\t\t\t\t\r\n\t\t\t\tvar a = angle + Rnd.Float(-Accuracy, Accuracy);\r\n\t\t\t\tvar force = fire ? 60 : 120;\r\n\t\t\t\t\r\n\t\t\t\tvelocity.X = (float) Math.Cos(a) * force;\r\n\t\t\t\tvelocity.Y = (float) Math.Sin(a) * force;\r\n\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t\tSelf.moveId++;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Destroy() {\r\n\t\t\t\tbase.Destroy();\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\tif (timer <= T) {\r\n\t\t\t\t\tBecome<IdleState>();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar v = velocity * Math.Min(1, timer - T * 0.4f);\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = v;\r\n\r\n\t\t\t\tif (!fire) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlastBullet -= dt;\r\n\t\t\t\t\r\n\t\t\t\tif (lastBullet <= 0) {\r\n\t\t\t\t\tlastBullet = 0.3f;\r\n\r\n\t\t\t\t\tif (!saw && !Self.CanSeeTarget()) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tsaw = true;\r\n\t\t\t\t\t\r\n\t\t\t\t\tvar an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * (float) Math.PI * 0.1f;\r\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\r\n\t\t\t\t\t\r\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\r\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\r\n\r\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f);\r\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\", sz: 0.2f);\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\r\n\t\t\t\t\t\t\tLightRadius = 32f\r\n\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\tbuilder.Move(angle, 8);\r\n\t\t\t\t\t\tbuilder.Shoot(an, 7f).Build();\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent ev) {\r\n\t\t\t\tif (ev.Entity is Door) {\r\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\r\n\r\n\t\t\t\t\tif (s is RunState) {\r\n\t\t\t\t\t\tBecome<IdleState>();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tprotected override string GetDeadSfx() {\r\n\t\t\treturn \"mob_gunner_death\";\r\n\t\t}\r\n\r\n\t\tprotected override string GetHurtSfx() {\r\n\t\t\treturn \"mob_gunner_hurt\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/King.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class King : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"king\");\n\t\t\tSetMaxHp(3);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(2, 2, 12, 12);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 4;\n\t\t}\n\t\t\n\t\t#region King States\n\t\tpublic class IdleState : SmartState<King> {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Knight.cs",
    "content": "﻿using Lens.entity;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Knight : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"knight\");\n\t\t\tSetMaxHp(10);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprotected override void OnTargetChange(Entity target) {\n\t\t\tif (target == null) {\n\t\t\t\tBecome<IdleState>();\n\t\t\t} else {\n\t\t\t\tBecome<ChaseState>();\n\t\t\t}\n\t\t}\n\n\t\t#region Knight States\n\t\tpublic class IdleState : EntityState {\n\t\t\t\n\t\t}\n\n\t\tpublic class ChaseState : EntityState {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/MotherSlime.cs",
    "content": "using BurningKnight.assets.lighting;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.events;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature.mob.castle {\r\n\tpublic class MotherSlime : SimpleSlime {\r\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#0069aa\");\r\n\t\tpublic static Color LightColor = new Color(0.5f, 0.5f, 1f, 1f);\r\n\t\t\r\n\t\tprotected override Color GetBloodColor() {\r\n\t\t\treturn color;\r\n\t\t}\r\n\t\t\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddComponent(new ZAnimationComponent(\"mother_slime\"));\r\n\t\t\tSetMaxHp(1);\r\n\r\n\t\t\tAddComponent(new LightComponent(this, 64, LightColor));\r\n\t\t}\r\n\r\n\t\tprotected override BodyComponent CreateBodyComponent() {\r\n\t\t\treturn new RectBodyComponent(2, 7, 12, 9);\r\n\t\t}\r\n\r\n\t\tprotected override BodyComponent CreateSensorBodyComponent() {\r\n\t\t\treturn new SensorBodyComponent(2, 7, 12, 9);\r\n\t\t}\r\n\r\n\t\tprotected override bool HandleDeath(DiedEvent d) {\r\n\t\t\tfor (var i = 0; i < 2; i++) {\r\n\t\t\t\tvar slime = new BabySlime();\r\n\t\t\t\tArea.Add(slime);\r\n\t\t\t\tslime.Center = Center + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\r\n\t\t\t\tslime.GetComponent<HealthComponent>().InvincibilityTimer = 0.1f;\r\n\r\n\t\t\t\tslime.GetAnyComponent<BodyComponent>().KnockbackFrom(d.From, Rnd.Float(1f, 2f), 2);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleDeath(d);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/Rat.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class Rat : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 14;\n\t\t\tHeight = 15;\n\t\t\t\n\t\t\tAddAnimation(\"rat\");\n\t\t\tSetMaxHp(2);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(2, 14, 10, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(2, 1, 10, 14));\n\t\t}\n\t\t\n\t\t#region Bandit States\n\t\tpublic class IdleState : SmartState<Rat> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(1, 2.5f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Rat> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\ttimer = Rnd.Float(0.4f, 1f);\n\t\t\t\t\n\t\t\t\tvar angle = Rnd.AnglePI();\n\t\t\t\tvar force = 120f + Rnd.Float(50f);\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance() && Self.Target != null) {\n\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\tangle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_bandit_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_bandit_damage\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/SimpleSlime.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.castle {\n\tpublic class SimpleSlime : Slime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#33984b\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(Events.Halloween ? \"spooky_slime\" : \"slime\"));\n\t\t\tSetMaxHp((Run.Level != null && Run.Level.Biome is CaveBiome) ? 4 : 1 + Run.Depth / 2);\n\n\t\t\tvar body = CreateBodyComponent();\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\t\n\t\t\tAddComponent(CreateSensorBodyComponent());\n\t\t\tAddComponent(new LightComponent(this, 24, new Color(0.5f, 1f, 0.4f)));\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateBodyComponent() {\n\t\t\treturn new RectBodyComponent(2, 12, 10, 1);\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateSensorBodyComponent() {\n\t\t\treturn new SensorBodyComponent(2, 5, 12, 9);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/castle/WallCrawler.cs",
    "content": "using System;\r\nusing BurningKnight.entity.buff;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob.prefabs;\r\nusing BurningKnight.entity.projectile;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens.entity.component.logic;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.creature.mob.castle {\r\n\tpublic class WallCrawler : WallWalker {\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddComponent(new WallAnimationComponent(\"crawler\"));\r\n\t\t\tSetMaxHp(2);\r\n\t\t}\t\r\n\t\t\r\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#ffeb57\");\r\n\t\t\r\n\t\tprotected override Color GetBloodColor() {\r\n\t\t\treturn color;\r\n\t\t}\r\n\r\n\t\t#region Crawler States\r\n\t\tpublic class IdleState : WallWalker.IdleState {\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\tif (T >= 3f) {\r\n\t\t\t\t\tBecome<FireState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tpublic override void Flip() {\r\n\t\t\t\tSelf.Left = !Self.Left;\r\n\r\n\t\t\t\tif (Self.T >= 3f) {\r\n\t\t\t\t\tBecome<FireState>();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvelocity *= -1;\r\n\t\t\t\tvx *= -1;\r\n\t\t\t\tvy *= -1;\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t\tT = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic class FireState : SmartState<WallCrawler> {\r\n\t\t\tprivate bool fired;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\tSelf.T = 0;\r\n\t\t\t\t\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\r\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(true);\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Destroy() {\r\n\t\t\t\tbase.Destroy();\r\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(false);\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (!fired && Self.GetComponent<WallAnimationComponent>().Animation.Paused) {\r\n\t\t\t\t\tfired = true;\r\n\t\t\t\t\tT = 0;\r\n\r\n\t\t\t\t\tif (Self.Target == null) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tvar a = Self.GetComponent<WallAnimationComponent>();\r\n\r\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\r\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\r\n\r\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\r\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\r\n\r\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\r\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\r\n\r\n\t\t\t\t\t\t\tif (Self.Target == null) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_wall\");\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tvar angle = Self.Direction.ToAngle();\r\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\r\n\t\t\t\t\t\t\t\tLightRadius = 32f\r\n\t\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\r\n\t\t\t\t\t\t\tbuilder.Move(angle, 8);\r\n\r\n\t\t\t\t\t\t\tif (Run.Depth > 2 || Run.Loop > 0) {\r\n\t\t\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\r\n\t\t\t\t\t\t\t\tbuilder.Scale *= 1.5f;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tbuilder.Shoot(angle, 5f).Build();\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t};\r\n\t\t\t\t} else if (fired && T > 1f) {\r\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tprotected override Type GetIdleState() {\r\n\t\t\treturn typeof(IdleState);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\t\t\tT += dt;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/cave/Broco.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.cave {\n\tpublic class Broco : Mob {\n\t\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 12;\n\t\t\tHeight = 11;\n\t\t\t\n\t\t\tAddAnimation(\"broco\");\n\t\t\tSetMaxHp(2);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(2, 10, 8, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 8, 9));\n\n\t\t\tmoveId = Rnd.Int(0, 2);\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 20, new Color(0.5f, 1f, 0.4f)));\n\t\t\tAddDrops(new SingleDrop(\"bk:emerald\", 0.001f));\n\t\t}\n\n\t\tprivate int moveId;\n\t\t\n\t\t#region Bandit States\n\t\tpublic class IdleState : SmartState<Broco> {\n\t\t\tprivate float delay;\n\t\t\tprivate float fireDelay;\n\t\t\tprivate bool fired;\n\t\t\tprivate bool firedLaser;\n\t\t\tprivate Laser laser;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tdelay = Rnd.Float(1.5f, 2.5f);\n\t\t\t\tfireDelay = (firedLaser = (Self.moveId % 2 == 0)) ? 3 : Rnd.Float(0.5f, delay - 0.5f);\n\t\t\t\tSelf.moveId++;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (laser != null) {\n\t\t\t\t\tlaser.Position = Self.Center;\n\t\t\t\t}\n\n\t\t\t\tif (firedLaser && T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!firedLaser && !fired && T >= fireDelay) {\n\t\t\t\t\tfired = true;\n\n\t\t\t\t\tif (!Self.CanSeeTarget()) {\n\t\t\t\t\t\tfiredLaser = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\t\t\tfiredLaser = true;\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\t\t\tvar angle = Self.AngleTo(Self.Target);\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\t\tColor = ProjectileColor.White,\n\t\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\t\t\t\tbuilder.Move(angle, 8);\n\t\t\t\t\t\t\tbuilder.Shoot(angle + Rnd.Float(-ac, ac), 9f);\n\n\t\t\t\t\t\t\tbuilder.Build();\n\n\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\tif (Self.Done) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tlaser = Laser.Make(Self, 0, angle + Rnd.Float(-ac * 3f, ac * 3f), scale: 2, range: 16);\n\n\t\t\t\t\t\t\t\tlaser.LifeTime = 2f;\n\t\t\t\t\t\t\t\tlaser.Color = ProjectileColor.Green;\n\t\t\t\t\t\t\t\tlaser.Position = Self.Center;\n\n\t\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_laser\", 4);\n\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tfiredLaser = true;\n\t\t\t\t\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\t\t\t\t}, 2f);\n\t\t\t\t\t\t\t}, 0.8f);\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Broco> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\ttimer = Rnd.Float(0.4f, 1f);\n\t\t\t\t\n\t\t\t\tvar angle = Rnd.AnglePI();\n\t\t\t\tvar force = 120f + Rnd.Float(50f);\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance() && Self.Target != null) {\n\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\tangle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_bandit_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_bandit_damage\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/cave/EmeraldGunner.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.cave {\n\tpublic class EmeraldGunner : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 17;\n\t\t\tHeight = 15;\n\t\t\t\n\t\t\tAddAnimation(\"emerald_gunner\");\n\t\t\tSetMaxHp(4);\n\t\t\t\n\t\t\tAddDrops(new SingleDrop(\"bk:emerald\", 0.001f));\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(1, 13, 15, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 6;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 2, 15, 12));\n\n\t\t\tmoveId = Rnd.Int(3);\n\t\t\tGetComponent<AudioEmitterComponent>().PitchMod = -0.4f;\n\t\t\tAddComponent(new LightComponent(this, 32, new Color(0.5f, 1f, 0.4f)));\n\t\t}\n\n\t\t#region Gunner States\n\t\tpublic class IdleState : SmartState<EmeraldGunner> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(0.4f, 1f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate int moveId;\n\t\t\n\t\tpublic class RunState : SmartState<EmeraldGunner> {\n\t\t\tprivate const float Accuracy = 0.2f;\n\t\t\t\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\tprivate float lastBullet;\n\t\t\tprivate float angle;\n\t\t\tprivate bool fire;\n\t\t\tprivate float start;\n\t\t\tprivate bool saw;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tfire = Self.Target != null && Self.moveId % 2 == 0;\n\t\t\t\tangle = !fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target);\n\t\t\t\ttimer = fire ? 0.9f : Rnd.Float(0.8f, 2f);\n\t\t\t\tstart = Rnd.Float(0f, 10f);\n\t\t\t\t\n\t\t\t\tvar a = angle + Rnd.Float(-Accuracy, Accuracy);\n\t\t\t\tvar force = fire ? 60 : 120;\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(a) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(a) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t\tSelf.moveId++;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar v = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = v;\n\n\t\t\t\tif (!fire) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlastBullet -= dt;\n\t\t\t\t\n\t\t\t\tif (lastBullet <= 0) {\n\t\t\t\t\tlastBullet = 0.3f;\n\n\t\t\t\t\tif (!saw && !Self.CanSeeTarget()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tsaw = true;\n\t\t\t\t\t\n\t\t\t\t\tvar an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * (float) Math.PI * 0.1f;\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\", sz: 0.2f);\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\tColor = ProjectileColor.Green\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.Shoot(an, 7f);\n\t\t\t\t\t\tbuilder.Move(angle, 8);\n\n\t\t\t\t\t\tbuilder.Build();\n\n\t\t\t\t\t\tvar b = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\tColor = ProjectileColor.DarkGreen,\n\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tb.Move(angle, 8);\n\n\t\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\t\tbuilder.Scale = Rnd.Float(0.4f, 0.7f);\n\n\t\t\t\t\t\t\tbuilder.Shoot(an + Rnd.Float(-Accuracy * 3, Accuracy * 3), Rnd.Float(7, 10f));\n\t\t\t\t\t\t\tbuilder.Build();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_gunner_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_gunner_hurt\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/cave/Thief.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.cave {\n\tpublic class Thief : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 16;\n\t\t\tHeight = 16;\n\t\t\t\n\t\t\tAddAnimation(\"thief\");\n\t\t\tSetMaxHp(3);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(2, 15, 12, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 12, 14));\n\t\t\tAddComponent(new LightComponent(this, 20, new Color(0.5f, 1f, 0.4f)));\n\t\t\tAddDrops(new SingleDrop(\"bk:emerald\", 0.001f));\n\t\t}\n\t\t\n\t\t#region Bandit States\n\t\tpublic class IdleState : SmartState<Thief> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(0.8f, 1.3f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Thief> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\ttimer = Rnd.Float(0.3f, 0.6f);\n\t\t\t\t\n\t\t\t\tvar angle = Rnd.AnglePI();\n\t\t\t\tvar force = 160f + Rnd.Float(90f);\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance() && Self.Target != null) {\n\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\tangle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_bandit_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_bandit_damage\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Cactus.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\t/*public class Cactus : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(4, 2, 8, 14, BodyType.Static, true);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0;\n\t\t\tSetMaxHp(10);\n\t\t\t\n\t\t\tAddAnimation(\"cactus\");\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tcounter = Rnd.Int(4);\n\t\t}\n\n\t\tprivate int counter;\n\t\t\n\t\t#region Cactus states\n\t\tpublic class IdleState : SmartState<Cactus> {\n\t\t\tprivate bool tweened;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.counter++;\n\n\t\t\t\tif (Self.counter > 2) {\n\t\t\t\t\tSelf.counter = 0;\n\n\t\t\t\t\tfor (var i = 0; i < 10; i++) {\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tvar projectile = Projectile.Make(Self, \"small\", Rnd.AnglePI(), Rnd.Float(1, 9));\n\t\t\t\t\n\t\t\t\t\t\t\tprojectile.Color = ProjectileColor.Green;\n\t\t\t\t\t\t\tprojectile.Center = Self.Center;\n\t\t\t\t\t\t\tprojectile.Spectral = true;\n\t\t\t\t\t\t\tprojectile.BreaksFromWalls = false;\n\t\t\t\t\t\t\tprojectile.Depth = Layers.Wall + 1;\n\t\t\t\t\t\t\tprojectile.Controller += SlowdownProjectileController.Make(Rnd.Float(1f, 2f));\n\t\t\t\t\t\t\tprojectile.AddLight(32f, ProjectileColor.Green);\n\t\t\t\t\t\t}, i * 0.1f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!tweened && T >= 1f) {\n\t\t\t\t\ttweened = true;\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\n\t\t\t\t\t\tBecome<OppositeState>();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class OppositeState : SmartState<Cactus> {\n\t\t\tprivate bool tweened;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!tweened && T >= 1f) {\n\t\t\t\t\ttweened = true;\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}*/\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/DesertBulletSlime.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.projectile;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class DesertBulletSlime : BulletSlime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#ffeb57\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\tSetMaxHp(8);\n\t\t}\n\n\t\tprotected override void OnJump() {\n\t\t\tbase.OnJump();\n\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tLightRadius = 32f\n\t\t\t};\n\n\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tif (Target == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\t\t\tvar a = AngleTo(Target) + Rnd.Float(-0.1f, 0.1f);\n\t\t\t\t\tvar projectile = builder.Shoot(a, 9f).Build();\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(a, 5f) - new Vector2(0, GetComponent<ZComponent>().Z);\n\t\t\t\t}, i * 0.3f);\n\t\t\t}\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"desert_bullet_slime\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/DesertSlime.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing Lens.graphics;\nusing Lens.util;\nusing Color = Microsoft.Xna.Framework.Color;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class DesertSlime : Slime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#ffeb57\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"desert_slime\"));\n\t\t\tSetMaxHp(1 + (int) Math.Round(Run.Depth * 1.5f));\n\n\t\t\tvar body = new RectBodyComponent(2, 12, 12, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.5f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 7, 12, 9));\n\t\t}\n\t\t\n\t\tprotected override void OnLand() {\n\t\t\tbase.OnLand();\n\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar a = AngleTo(Target);\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tLightRadius = 48\n\t\t\t};\n\n\t\t\tbuilder.Shoot(a, 5f);\n\t\t\tbuilder.Build().Center = Center + MathUtils.CreateVector(a, 5f);\n\n\t\t\tGetComponent<RectBodyComponent>().KnockbackFrom(a - (float) Math.PI, 0.3f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Fly.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class Fly : Mob {\n\t\tprotected const float DefaultZ = 2;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tSetMaxHp(3);\n\t\t\t\n\t\t\tvar body = new SensorBodyComponent(1, 1, 10, 8);\n\t\t\tAddComponent(body);\n\n\t\t\tTouchDamage = 0;\n\t\t\tbody.Body.LinearDamping = 4;\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"fly\"));\n\t\t\tAddComponent(new ZComponent());\n\t\t\t\n\t\t\tAddComponent(new OrbitalComponent {\n\t\t\t\tRadius = 12,\n\t\t\t\tLerp = true\n\t\t\t});\n\n\t\t\tDepth = Layers.Wall;\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tpublic override bool InAir() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void Fire() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\tvar a = GetComponent<ZAnimationComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\t\t\t\t\n\t\t\t\t\tvar an = AngleTo(Target);\n\t\t\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\t\t\tScale = 0.8f,\n\t\t\t\t\t\tLightRadius = 24\n\t\t\t\t\t};\n\n\t\t\t\t\tvar projectile = builder.Shoot(an, 8).Build();\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(an, 2f);\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\t#region Fly States\n\t\tpublic class IdleState : SmartState<Fly> {\n\t\t\tprivate bool searched;\n\t\t\tprivate Entity target;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\n\t\t\t\tTween.To(0, component.Z, x => component.Z = x, 0.4f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!searched) {\n\t\t\t\t\tsearched = true;\n\t\t\t\t\ttarget = Self.GetComponent<RoomComponent>().Room?.FindClosest(Self.Center, Tags.Mob, e => !e.HasComponent<OrbitalComponent>() && !(e is WallWalker || e is Boss));\n\t\t\t\t}\n\n\t\t\t\tif (target != null) {\n\t\t\t\t\tif (!target.HasComponent<OrbitGiverComponent>()) {\n\t\t\t\t\t\ttarget.AddComponent(new OrbitGiverComponent());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttarget.GetComponent<OrbitGiverComponent>().AddOrbiter(Self);\n\t\t\t\t\tBecome<OrbitingState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar dx = Self.DxTo(Self.Target);\n\t\t\t\tvar dy = Self.DyTo(Self.Target);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tvar s = dt * 300;\n\n\t\t\t\tSelf.GetComponent<SensorBodyComponent>().Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t\tSelf.PushFromOtherEnemies(dt, e => e.InAir());\n\n\t\t\t\tif (T >= 3f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class OrbitingState : SmartState<Fly> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\n\t\t\t\tTween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar orbiting = Self.GetComponent<OrbitalComponent>().Orbiting;\n\t\t\t\t\n\t\t\t\tif (orbiting == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (orbiting.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\tSelf.GetComponent<ZComponent>().Z = z.Z + DefaultZ;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T >= 3f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Level) && base.ShouldCollide(entity);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_fly_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Maggot.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class Maggot : WallWalker {\n\t\tprivate const float TargetDistance = 4f;\n\t\tprivate const float Speed = 30f;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new WallAnimationComponent(\"maggot\"));\n\t\t\tSetMaxHp(1);\n\n\t\t\tDepth = Layers.Creature + 1;\n\t\t}\n        \t\n\t\t#region Maggot States\n\t\tpublic class IdleState : WallWalker.IdleState {\n\t\t\tprivate bool stop;\n\t\t\t\n\t\t\tpublic override void DoLogic(float dt) {\n\t\t\t\tbase.DoLogic(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tResetVelocity();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (mx == 0) {\n\t\t\t\t\tif (Math.Abs(Self.DxTo(Self.Target)) <= TargetDistance) {\n\t\t\t\t\t\tResetVelocity();\n\t\t\t\t\t\tBecome<FireState>();\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar left = Self.CenterX > Self.Target.CenterX;\n\n\t\t\t\t\tif (Self.Left != left) {\n\t\t\t\t\t\tInvertVelocity();\n\t\t\t\t\t\tstop = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvx = Self.Left ? -1 : 1;\n\t\t\t\t\t\tvy = 0;\t\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (Math.Abs(Self.DyTo(Self.Target)) <= TargetDistance) {\n\t\t\t\t\t\tResetVelocity();\n\t\t\t\t\t\tBecome<FireState>();\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar left = Self.CenterY > Self.Target.CenterY;\n\n\t\t\t\t\tif (Self.Left != left) {\n\t\t\t\t\t\tInvertVelocity();\n\t\t\t\t\t\tstop = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvx = 0;\n\t\t\t\t\t\tvy = Self.Left ? -1 : 1;\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (stop) {\n\t\t\t\t\tvx = 0;\n\t\t\t\t\tvy = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvelocity = new Vector2(vx * Speed, vy * Speed);\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Flip() {\n\t\t\t\tResetVelocity();\n\t\t\t\tstop = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic class FireState : SmartState<Maggot> {\n\t\t\tprivate bool shot; \n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.T = 0;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!shot && Self.GetComponent<WallAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tshot = true;\n\n\t\t\t\t\tvar a = Self.GetComponent<WallAnimationComponent>();\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_wall\");\n\t\t\t\t\t\t\n\t\t\t\t\tvar angle = Self.Direction.ToAngle();\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\tLightRadius = 30\n\t\t\t\t\t};\n\n\t\t\t\t\tif (Run.Depth > 4 || Run.Loop > 0) {\n\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\tbuilder.Scale *= 1.5f;\n\t\t\t\t\t}\n\n\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\t\tvar projectile = builder.Shoot(angle, 5f).Build();\n\n\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 4);\n\n\t\t\t\t\ta.Scale.X = 1.8f;\n\t\t\t\t\ta.Scale.Y = 0.2f;\n\t\t\t\t\t\n\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f).OnEnd = () => { Become<IdleState>(); };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override Type GetIdleState() {\n\t\t\treturn typeof(IdleState);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tT += dt;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/MegaSlime.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.events;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class MegaSlime : SimpleSlime {\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#0069aa\");\n\t\tpublic static Color LightColor = new Color(0.5f, 0.5f, 1f, 1f);\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"mega_slime\"));\n\t\t\tSetMaxHp(5);\n\n\t\t\tAddComponent(new LightComponent(this, 64, LightColor));\n\t\t}\n\n\t\tprotected override BodyComponent CreateBodyComponent() {\n\t\t\treturn new RectBodyComponent(2, 7, 12, 9);\n\t\t}\n\n\t\tprotected override BodyComponent CreateSensorBodyComponent() {\n\t\t\treturn new SensorBodyComponent(2, 7, 12, 9);\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\tvar slime = new MotherSlime();\n\t\t\t\tArea.Add(slime);\n\t\t\t\tslime.Center = Center + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\n\t\t\t\tslime.GetComponent<HealthComponent>().InvincibilityTimer = 0.1f;\n\n\t\t\t\tslime.GetAnyComponent<BodyComponent>().KnockbackFrom(d.From, Rnd.Float(1f, 2f), 2);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleDeath(d);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Mummy.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class Mummy : Mob {\n\t\tprivate const float DetectionRadius = 70f;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tSetMaxHp(4);\n\t\t\tAddAnimation(\"mummy\");\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(2, 15, 10, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 3;\n\t\t\tbody.Body.LinearDamping = 6;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(3, 3, 7, 13));\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t\tTouchDamage = 2;\n\t\t}\n\t\t\n\t\t#region Mummy States\n\t\tpublic class IdleState : SmartState<Mummy> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Int(1, 2);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<StateComponent>().StateInstance is SummonedState) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<WanderState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class WanderState : SmartState<Mummy> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\tprivate float angle;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tangle = Rnd.AnglePI();\n\t\t\t\ttimer = Rnd.Float(0.8f, 2f);\n\t\t\t\t\n\t\t\t\tvar force = Rnd.Float(40f, 60f);\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Tag = \"run\";\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar v = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = v;\n\t\t\t}\n\t\t}\n\n\t\tpublic class SummonedState : SmartState<Mummy> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\ta.Scale.X = 3f;\n\t\t\t\ta.Scale.Y = 0f;\n\n\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.5f, Ease.BackOut);\n\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.5f, Ease.BackOut).OnEnd = () => {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.TouchDamage = 1;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Mummy> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tSelf.Become<IdleState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\n\t\t\t\tif (d > 96f) {\n\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = Self.DxTo(Self.Target);\n\t\t\t\tvar dy = Self.DyTo(Self.Target);\n\n\t\t\t\tvar s = dt * 300;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t\tSelf.PushFromOtherEnemies(dt);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_mummy_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_mummy_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Spelunker.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class Spelunker : Mob {\n\t\tprivate const float DetectionRadius = 64f;\n\t\tprivate bool Exploded;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tSetMaxHp(7);\n\t\t\tAddAnimation(\"spelunker\");\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(3, 15, 10, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 2;\n\t\t\tbody.Body.LinearDamping = 6;\n\n\t\t\tAddComponent(new SensorBodyComponent(5, 4, 7, 11));\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\t\t\n\t\t#region Spelunker States\n\t\tpublic class IdleState : SmartState<Spelunker> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Int(1, 2);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<WanderState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class WanderState : SmartState<Spelunker> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\tprivate float angle;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tangle = Rnd.AnglePI();\n\t\t\t\ttimer = Rnd.Float(0.8f, 2f);\n\t\t\t\t\n\t\t\t\tvar force = Rnd.Float(60f, 80f);\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Tag = \"run\";\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar v = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = v;\n\t\t\t}\n\t\t}\n\n\t\tpublic class RunState : SmartState<Spelunker> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\n\t\t\t\tif (d <= 32f) {\n\t\t\t\t\tSelf.Become<ExplodeState>();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (d > 96f) {\n\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = Self.DxTo(Self.Target);\n\t\t\t\tvar dy = Self.DyTo(Self.Target);\n\n\t\t\t\tvar s = dt * 250;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t\tSelf.PushFromOtherEnemies(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic class ExplodeState : SmartState<Spelunker> {\n\t\t\tprivate bool lastFlash;\n\t\t\t\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Flash = false;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\t\t\t\t\n\t\t\t\tvar d = Self.DistanceTo(Self.Target);\n\n\t\t\t\tif (d > 48f) {\n\t\t\t\t\tSelf.Become<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (T >= 0.66f) {\n\t\t\t\t\tSelf.Done = true;\n\t\t\t\t\tSelf.Exploded = true;\n\t\t\t\t\tAudioEmitterComponent.Dummy(Self.Area, Self.Center).EmitRandomized(\"mob_archeolog_explosion\", sz: 0.2f);\n\t\t\t\t\tExplosionMaker.Make(Self, 48f);\n\t\t\t\t}\n\n\t\t\t\tvar flash = T % 0.33 < 0.15f;\n\n\t\t\t\tif (flash && !lastFlash) {\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_spelunker_beep\", 1f, T);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlastFlash = flash;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Flash = flash;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn Exploded ? null : \"mob_archeolog_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_archeolog_hurt\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/desert/Worm.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.desert {\n\tpublic class Worm : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tSetMaxHp(1);\n\t\t\tAddAnimation(\"worm\");\n\n\t\t\tGetComponent<MobAnimationComponent>().ShadowOffset = 1;\n\n\t\t\tvar body = new RectBodyComponent(3, 3, 4, 10);\n\t\t\tAddComponent(body);\n\t\t\tbody.KnockbackModifier = 0;\n\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\t#region Worm \n\t\tpublic class HiddenState : SmartState<Worm> {\n\t\t\tprivate float delay;\n\t\t\tprivate Vector2 target;\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tvar i = 0;\n\n\t\t\t\tdo {\n\t\t\t\t\tvar spot = Self.GetComponent<RoomComponent>().Room.GetRandomFreeTile() * 16;\n\n\t\t\t\t\tif (Self.Target == null || Self.Target.DistanceTo(spot) > 32f) {\n\t\t\t\t\t\ttarget = new Vector2(spot.X + 8, spot.Y);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\ti++;\n\n\t\t\t\t\tif (i > 99) {\n\t\t\t\t\t\tLog.Error(\"Failed to find a spot where to dig up\");\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} while (true);\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 0;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\tdelay = Rnd.Float(0.5f, 1.5f);\n\n\t\t\t\tSelf.Center = target;\n\t\t\t\t\n\t\t\t\tSelf.TouchDamage = 1;\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<ShowingState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class HidingState : SmartState<Worm> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<MobAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tBecome<HiddenState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class ShowingState : SmartState<Worm> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<MobAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\n\t\t\t\tSelf.TurnToTarget();\n\t\t\t}\n\t\t}\n\n\t\tpublic class IdleState : SmartState<Worm> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 3f) {\n\t\t\t\t\tif (Self.Target == null || Self.DistanceTo(Self.Target) > 96f) {\n\t\t\t\t\t\tBecome<HidingState>();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tBecome<FireState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSelf.TurnToTarget();\n\t\t\t}\n\t\t}\n\n\t\tpublic class FireState : SmartState<Worm> {\n\t\t\tprivate bool fired;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (!fired && T >= 0.1f) {\n\t\t\t\t\tfired = true;\n\n\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f).OnEnd = () => {\n\t\t\t\t\t\t\t\tBecome<HidingState>();\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\t\t\tvar angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbuilder.Shoot(angle, 8f);\n\t\t\t\t\t\t\tvar projectile = builder.Build();\n\n\t\t\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 2f);\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tSelf.TurnToTarget();\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override void RenderShadow() {\n\t\t\tif (GetComponent<StateComponent>().StateInstance is HiddenState) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.RenderShadow();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (GetComponent<StateComponent>().StateInstance is HiddenState) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Render();\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_worm_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/BigSnowball.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class BigSnowball : Mob {\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 20;\n\t\t\tHeight = 20;\n\n\t\t\tSetMaxHp(10);\n\t\t\tAddDrops(new SingleDrop(\"bk:ice_skates\", 0.01f));\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(3, 19, 10, 5);\n\t\t\tAddComponent(body);\n\t\t\t\n\t\t\tbody.Body.LinearDamping = 1f;\n\t\t\tbody.KnockbackModifier = 2f;\n\t\t\tbody.Body.Restitution = 1;\n\t\t\tbody.Body.Friction = 0;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 3, 16, 16));\n\t\t\tAddComponent(new MobAnimationComponent(\"big_snowball\") {\n\t\t\t\tShadowOffset = 3\n\t\t\t});\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\t#region Snowman States\n\t\tpublic class IdleState : SmartState<BigSnowball> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(1f, 5f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RollState>();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar v = Self.GetComponent<RectBodyComponent>().Body.LinearVelocity;\n\n\t\t\t\tif (v.LengthSquared() > 15f) {\n\t\t\t\t\tBecome<RollState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RollState : SmartState<BigSnowball> {\n\t\t\tprivate const float Accuracy = 0.2f;\n\t\t\t\n\t\t\tprivate float angle;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tif (Self.GetComponent<RectBodyComponent>().Body.LinearVelocity.LengthSquared() < 15f) {\n\t\t\t\t\tangle = Rnd.Chance() || Self.Target == null ? Rnd.AnglePI() : Self.AngleTo(Self.Target);\n\n\t\t\t\t\tvar a = angle + Rnd.Float(-Accuracy, Accuracy);\n\t\t\t\t\tvar force = 200;\n\n\t\t\t\t\tVector2 velocity;\n\n\t\t\t\t\tvelocity.X = (float) Math.Cos(a) * force;\n\t\t\t\t\tvelocity.Y = (float) Math.Sin(a) * force;\n\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Reverse = velocity.Y < 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Reverse = false;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar v = Self.GetComponent<RectBodyComponent>().Body.LinearVelocity;\n\n\t\t\t\tif (v.LengthSquared() < 15f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Body.LinearVelocity = Vector2.Zero;\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Reverse = v.Y < 0;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is BigSnowball) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.ShouldCollide(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/CupGuy.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class CupGuy : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 14;\n\t\t\tHeight = 15;\n\t\t\t\n\t\t\tAddAnimation(\"cup_guy\");\n\t\t\tSetMaxHp(10);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(3, 13, 9, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(3, 1, 9, 13));\n\n\t\t\tmoveId = Rnd.Int(0, 2);\n\t\t}\n\n\t\tprivate int moveId;\n\t\t\n\t\t#region CupGuy States\n\t\tpublic class IdleState : SmartState<CupGuy> {\n\t\t\tprivate float delay;\n\t\t\tprivate float fireDelay;\n\t\t\tprivate bool fired;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tdelay = Rnd.Float(1, 2.5f);\n\t\t\t\tfireDelay = Self.moveId % 2 == 0 ? 3 : Rnd.Float(0.5f, delay - 0.5f);\n\t\t\t\tSelf.moveId++;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!fired && T >= fireDelay) {\n\t\t\t\t\tfired = true;\n\n\t\t\t\t\tif (!Self.CanSeeTarget()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\t\t\t\t\tvar am = Rnd.Int(5, 10);\n\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\t\tRange = 2f\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\n\t\t\t\t\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\t\t\t\t\tvar angle = Rnd.Float(-0.1f, 0.1f) + (float) i / am * Math.PI * 2;\n\t\t\t\t\t\t\t\tvar projectile = builder.Shoot(angle, Rnd.Float(3, 6)).Build();\n\n\t\t\t\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8f);\n\t\t\t\t\t\t\t\tAnimationUtil.Poof(projectile.Center);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<CupGuy> {\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\ttimer = Rnd.Float(0.4f, 1f);\n\t\t\t\t\n\t\t\t\tvar angle = Rnd.AnglePI();\n\t\t\t\tvar force = 120f + Rnd.Float(50f);\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance() && Self.Target != null) {\n\t\t\t\t\tvar ac = 0.1f;\n\t\t\t\t\tangle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(angle) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(angle) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_bandit_death\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_bandit_damage\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/Dino.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class Dino : Mob {\n\t\tprivate const float FindTime = 3f;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\t// todo: make him bounce of walls?\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 17;\n\t\t\tHeight = 20;\n\t\t\t\n\t\t\tAddAnimation(\"dino\");\n\t\t\tSetMaxHp(20);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(2, 19, 13, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 6;\n\t\t\tbody.Body.Restitution = 1;\n\t\t\tbody.Body.Friction = 0;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 3, 15, 17));\n\t\t}\n\n\t\t#region Dino States\n\t\tpublic class IdleState : SmartState<Dino> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(0.4f, 1f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= delay) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t} else {\n\t\t\t\t\tif (Self.CanSeeTarget()) {\n\t\t\t\t\t\tSelf.sawTime += dt;\n\n\t\t\t\t\t\tif (Self.sawTime >= FindTime) {\n\t\t\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSelf.sawTime = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool fire;\n\t\tprivate float sawTime;\n\n\t\tpublic class RunState : SmartState<Dino> {\n\t\t\tprivate const float Accuracy = 0.2f;\n\t\t\t\n\t\t\tprivate Vector2 velocity;\n\t\t\tprivate float timer;\n\t\t\tprivate float lastBullet;\n\t\t\tprivate float angle;\n\t\t\tprivate float start;\n\t\t\tprivate bool saw;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tif (Self.fire = (Self.sawTime >= FindTime)) {\n\t\t\t\t\tSelf.sawTime = 0;\n\t\t\t\t}\n\n\t\t\t\tangle = !Self.fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target);\n\t\t\t\ttimer = Self.fire ? 0.9f * 5 : Rnd.Float(0.8f, 2f);\n\t\t\t\tstart = Rnd.Float(0f, 10f);\n\t\t\t\t\n\t\t\t\tvar a = angle + Rnd.Float(-Accuracy, Accuracy);\n\t\t\t\tvar force = Self.fire ? 30 : 60;\n\t\t\t\t\n\t\t\t\tvelocity.X = (float) Math.Cos(a) * force;\n\t\t\t\tvelocity.Y = (float) Math.Sin(a) * force;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (timer <= T) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar v = velocity * Math.Min(1, timer - T * 0.4f);\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = v;\n\n\t\t\t\tif (!Self.fire) {\n\t\t\t\t\tif (Self.CanSeeTarget()) {\n\t\t\t\t\t\tSelf.sawTime += dt;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSelf.sawTime = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlastBullet -= dt;\n\t\t\t\t\n\t\t\t\tif (lastBullet <= 0) {\n\t\t\t\t\tlastBullet = 0.2f;\n\n\t\t\t\t\tif (!saw && !Self.CanSeeTarget()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tsaw = true;\n\t\t\t\t\t\n\t\t\t\t\tvar an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * 0.1f;\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\t\tScale = Rnd.Float(0.5f, 1.5f),\n\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\tBounce = 1\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\t\tvar projectile = builder.Shoot(an, 15).Build();\n\n\t\t\t\t\t\tprojectile.Color = Rnd.Chance(70) ? ProjectileColor.Orange : ProjectileColor.Red;\n\t\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is Door) {\n\t\t\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\n\t\t\t\t\tif (s is RunState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_dino_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_dino_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/IceCrawler.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class IceCrawler : WallWalker {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new WallAnimationComponent(\"ice_crawler\"));\n\t\t\tSetMaxHp(4);\n\t\t\tAddDrops(new SingleDrop(\"bk:campfire_in_bottle\", 0.01f));\n\t\t}\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\n\t\t#region Crawler States\n\t\tpublic class IdleState : WallWalker.IdleState {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (T >= 1.5f) {\n\t\t\t\t\tBecome<FireState>();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Flip() {\n\t\t\t\tSelf.Left = !Self.Left;\n\n\t\t\t\tif (Self.T >= 3f) {\n\t\t\t\t\tBecome<FireState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvelocity *= -1;\n\t\t\t\tvx *= -1;\n\t\t\t\tvy *= -1;\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\n\t\t\t\tT = 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic class FireState : SmartState<IceCrawler> {\n\t\t\tprivate bool fired;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.T = 0;\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<WallAnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!fired && Self.GetComponent<WallAnimationComponent>().Animation.Paused) {\n\t\t\t\t\tfired = true;\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar a = Self.GetComponent<WallAnimationComponent>();\n\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_wall\");\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar angle = Self.Direction.ToAngle();\n\t\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\n\t\t\t\t\t\t\tfor (var i = 0; i < 5; i++) {\n\t\t\t\t\t\t\t\tbuilder.Slice = i == 0 ? \"circle\" : \"small\";\n\t\t\t\t\t\t\t\tbuilder.Scale = i == 0 ? 1 : Rnd.Float(0.7f, 1f);\n\n\t\t\t\t\t\t\t\tvar projectile = builder.Shoot(angle + (i == 0 ? 0 : Rnd.Float(-0.5f, 0.5f)), i == 0 ? 5f : Rnd.Float(6, 10f)).Build();\n\n\t\t\t\t\t\t\t\tprojectile.Color = i == 0 ? ProjectileColor.Cyan : ProjectileColor.Blue;\n\t\t\t\t\t\t\t\tprojectile.Center += MathUtils.CreateVector(angle, 8);\n\n\t\t\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\t\t\tProjectileCallbacks.AttachHurtCallback(projectile, (p, e) => {\n\t\t\t\t\t\t\t\t\t\tif (e.TryGetComponent<BuffsComponent>(out var b)) {\n\t\t\t\t\t\t\t\t\t\t\tb.Add(new FrozenBuff() {\n\t\t\t\t\t\t\t\t\t\t\t\tDuration = 1\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tAnimationUtil.Poof(projectile.Center);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t} else if (fired && T > 1f) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override Type GetIdleState() {\n\t\t\treturn typeof(IdleState);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tT += dt;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/Snowball.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class Snowball : Slime {\n\t\tpublic static readonly Color BloodColor = ColorUtils.FromHex(\"#92a1b9\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn BloodColor;\n\t\t}\n\n\t\tprotected override float GetJumpDelay() {\n\t\t\treturn Rnd.Float(0.6f, 1f);\n\t\t}\n\n\t\tprotected override float GetJumpAngle() {\n\t\t\treturn Target == null || Rnd.Chance(80) ? Rnd.AnglePI() : AngleTo(Target) + Rnd.Float(-0.1f, 0.1f);\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"snowball\") {\n\t\t\t\tShadowOffset = 2\n\t\t\t});\n\n\t\t\tSetMaxHp(4);\n\n\t\t\tvar body = CreateBodyComponent();\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.KnockbackModifier = 0.7f;\n\t\t\t\n\t\t\tAddComponent(CreateSensorBodyComponent());\n\n\t\t\tJumpForce = 40;\n\t\t\tZVelocity = 3;\n\n\t\t\tGetComponent<RectBodyComponent>().Body.LinearDamping = 1;\n\t\t\tGetComponent<AudioEmitterComponent>().PitchMod = 0.2f;\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateBodyComponent() {\n\t\t\treturn new RectBodyComponent(1, 11, 11, 1);\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateSensorBodyComponent() {\n\t\t\treturn new SensorBodyComponent(1, 2, 11, 10);\n\t\t}\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_snowball_hut\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_snowball_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/Snowflake.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.level;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class Snowflake : Mob {\n\t\tprotected const float DefaultZ = 2;\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tSetMaxHp(6);\n\t\t\tGetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\n\t\t\tvar body = new SensorBodyComponent(1, 1, 14, 15);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 0.3f;\n\t\t\t\n\t\t\tAddComponent(new ZAnimationComponent(\"snowflake\"));\n\t\t\tAddComponent(new ZComponent() {\n\t\t\t\tFloat = true\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new OrbitalComponent {\n\t\t\t\tRadius = 32,\n\t\t\t\tLerp = true\n\t\t\t});\n\n\t\t\tDepth = Layers.Wall;\n\t\t\tBecome<IdleState>();\n\t\t\t\n\t\t\tRemoveTag(Tags.MustBeKilled);\n\t\t}\n\n\t\tpublic override bool InAir() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tvar rm = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (rm == null || rm.Tagged[Tags.Player].Count == 0 || rm.Tagged[Tags.MustBeKilled].Count > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\th.Unhittable = false;\n\t\t\th.Kill(this);\n\t\t}\n\n\t\t#region Snowflake States\n\t\tpublic class IdleState : SmartState<Snowflake> {\n\t\t\tprivate bool searched;\n\t\t\tprivate Entity target;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\n\t\t\t\tTween.To(0, component.Z, x => component.Z = x, 0.4f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (target != null) {\n\t\t\t\t\tif (target.Done) {\n\t\t\t\t\t\ttarget = null;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar dx = Self.DxTo(target);\n\t\t\t\t\tvar dy = Self.DyTo(target);\n\t\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\t\tif (d <= 32) {\n\t\t\t\t\t\tif (!target.HasComponent<OrbitGiverComponent>()) {\n\t\t\t\t\t\t\ttarget.AddComponent(new OrbitGiverComponent());\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\ttarget.GetComponent<OrbitGiverComponent>().AddOrbiter(Self);\n\t\t\t\t\t\tBecome<OrbitingState>();\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar body = Self.GetComponent<SensorBodyComponent>();\n\t\t\t\t\tvar s = dt * 200;\n\t\t\t\t\t\n\t\t\t\t\tbody.Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!searched) {\n\t\t\t\t\tsearched = true;\n\t\t\t\t\ttarget = Self.GetComponent<RoomComponent>().Room?.FindClosest(Self.Center, Tags.Mob, e => !e.HasComponent<OrbitalComponent>() && !(e is WallWalker || e is Boss));\n\n\t\t\t\t\tif (target == null) {\n\t\t\t\t\t\tSelf.Kill(Self);\n\t\t\t\t\t\t// target = Self.GetComponent<RoomComponent>().Room?.FindClosest(Self.Center, Tags.Player);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (T >= 1f && searched) {\n\t\t\t\t\tsearched = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// fixme: pursue first, make unhittable but autodying (add tag for autodeath)\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class OrbitingState : SmartState<Snowflake> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\n\t\t\t\tTween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar orbiting = Self.GetComponent<OrbitalComponent>().Orbiting;\n\t\t\t\t\n\t\t\t\tif (orbiting == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (orbiting.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\tSelf.GetComponent<ZComponent>().Z = z.Z + DefaultZ;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Level) && base.ShouldCollide(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/Snowman.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class Snowman : Mob {\n\t\tprivate float t;\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 24;\n\t\t\tHeight = 22;\n\n\t\t\tt = Rnd.Float(4);\n\n\t\t\tSetMaxHp(30);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(5, 21, 15, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\t\t\tbody.KnockbackModifier = 0.1f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(6, 2, 13, 19));\n\t\t\tAddComponent(new MobAnimationComponent(\"snowman\") {\n\t\t\t\tShadowOffset = 3\n\t\t\t});\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tTouchDamage = 0;\n\t\t}\n\n\t\tprivate void Fire() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\tvar a = GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\tGetComponent<HealthComponent>().InvincibilityTimer = 1f;\n\t\t\t\t\n\t\t\t\t\tvar an = AngleTo(Target);\n\t\t\t\t\tvar builder = new ProjectileBuilder(this, \"carrot\") {\n\t\t\t\t\t\tColor = ProjectileColor.Orange,\n\t\t\t\t\t\tDamage = 10\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.HurtsEveryone);\n\n\t\t\t\t\tvar projectile = builder.Shoot(an, 8f).Build();\n\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(an, 4f);\n\n\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, TargetProjectileController.Make(Target));\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\t#region Snowman States\n\t\tpublic class IdleState : SmartState<Snowman> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = Self.t;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null || !Self.CanSeeTarget()) {\n\t\t\t\t\tT = Self.t;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T >= 5f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override void CreateGore(DiedEvent d) {\n\t\t\tvar head = new Snowball();\n\t\t\tArea.Add(head);\n\t\t\thead.TopCenter = TopCenter;\n\n\t\t\tvar body = new SnowmanBody();\n\t\t\tArea.Add(body);\n\t\t\tbody.BottomCenter = BottomCenter;\n\t\t}\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_snowman_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_snowman_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/SnowmanBody.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class SnowmanBody : Mob {\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t}\n\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 24;\n\t\t\tHeight = 15;\n\n\t\t\tSetMaxHp(20);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(4, 14, 17, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\t\t\tbody.KnockbackModifier = 0.1f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(5, 2, 15, 12));\n\t\t\tAddComponent(new MobAnimationComponent(\"snowman_body\") {\n\t\t\t\tShadowOffset = 3\n\t\t\t});\n\t\t\t\n\t\t\tGetComponent<AudioEmitterComponent>().PitchMod = -0.2f;\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tTouchDamage = 0;\n\t\t}\n\n\t\tprivate void Fire() {\n\t\t\tif (Target == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\tvar a = GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\t\t\t\n\t\t\t\tvar an = AngleTo(Target) + t * 0.3f;\n\t\t\t\tvar d = GetComponent<HealthComponent>().Percent <= 0.3f;\n\n\t\t\t\tvar builder = new ProjectileBuilder(this, \"carrot\");\n\n\t\t\t\tfor (var i = 0; i < (d ? 8 : 4); i++) {\n\t\t\t\t\tvar projectile = builder.Shoot(an + i * Math.PI * (d ? 0.25f : 0.5f), 4f).Build();\n\n\t\t\t\t\tprojectile.Color = d ? ProjectileColor.Red : ProjectileColor.Orange;\n\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(an, 4f);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t#region Snowman body States\n\t\tpublic class IdleState : SmartState<SnowmanBody> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (T >= 0.6f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_snowman_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_snowman_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/ice/Sponge.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.ice {\n\tpublic class Sponge : Mob {\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn Snowball.BloodColor;\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 32;\n\t\t\tHeight = 24;\n\n\t\t\tSetMaxHp(20);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(2, 22, 28, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.KnockbackModifier = 0f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(3, 3, 25, 19));\n\t\t\tAddComponent(new MobAnimationComponent(\"sponge\") {\n\t\t\t\tShadowOffset = 8\n\t\t\t});\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tprivate void Fire() {\n\t\t\tvar a = GetComponent<MobAnimationComponent>();\n\n\t\t\tTween.To(0.4f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\tTween.To(1.8f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\tif (Target != null) {\n\t\t\t\t\tArea.Add(new Missile(this, Target));\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t#region Snowman States\n\t\tpublic class IdleState : SmartState<Sponge> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (T >= 4f) {\n\t\t\t\t\tT = 0;\n\t\t\t\t\tSelf.Fire();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/Bee.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class Bee : Mob {\n\t\tprotected float Speed = 1f;\n\t\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#5ac54f\");\n\t\t\n\t\tprotected override Color GetBloodColor() {\n\t\t\treturn color;\n\t\t}\n\t\t\n\t\tprotected virtual string GetAnimation() {\n\t\t\treturn \"bee\";\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_bee_damage\";\n\t\t}\n\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tHeight = 12;\n\t\t\t\n\t\t\tAddAnimation(GetAnimation());\n\t\t\tSetMaxHp(5);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t\tFlying = true;\n\n\t\t\tGetComponent<MobAnimationComponent>().ShadowOffset = -2;\n\t\t\tAddBody();\n\t\t\t\n\t\t\tvar body = GetComponent<RectBodyComponent>();\n\t\t\t\n\t\t\tbody.Body.LinearDamping = 0.5f;\n\t\t\tbody.Body.Restitution = 1;\n\t\t\tbody.Body.Friction = 0;\n\t\t\tbody.KnockbackModifier = 2.5f;\n\t\t\t\n\t\t\tDepth = Layers.FlyingMob;\n\t\t}\n\n\t\tprotected virtual void AddBody() {\n\t\t\tAddComponent(new RectBodyComponent(2, 9, 12, 1));\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 3, 12, 8));\n\t\t}\n\n\t\tprotected override void OnHit(Entity e) {\n\t\t\tbase.OnHit(e);\n\n\t\t\tif (e is Player) {\n\t\t\t\te.GetComponent<BuffsComponent>().Add(new SlowBuff {\n\t\t\t\t\tDuration = 5\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t#region Bee States\n\t\tpublic class IdleState : SmartState<Bee> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.CanSeeTarget()) {\n\t\t\t\t\tBecome<ChaseState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class ChaseState : SmartState<Bee> {\n\t\t\tprivate Vector2 lastSeen;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tBecome<IdleState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar see = Self.CanSeeTarget();\n\n\t\t\t\tif (see) {\n\t\t\t\t\tlastSeen = Self.Target.Center;\n\t\t\t\t} else if (Self.DistanceTo(lastSeen) <= 16) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.AngleTo(lastSeen);\n\t\t\t\tvar force = 50f * dt * Self.Speed;\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity +=\n\t\t\t\t\tnew Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\n\t\t\t\tSelf.PushFromOtherEnemies(dt * 0.2f);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/BeeHive.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class BeeHive : Mob {\n\t\tprivate const float ZHeight = 8;\n\t\tprivate bool loaded;\n\t\tprivate Tree tree;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 13;\n\t\t\tDepth = 1;\n\t\t\t\n\t\t\tAddAnimation(\"beehive\");\n\t\t\tSetMaxHp(10);\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new SensorBodyComponent(2, 3, 9, 11);\n\t\t\tAddComponent(body);\n\t\t\tbody.KnockbackModifier = 0;\n\n\t\t\tGetComponent<MobAnimationComponent>().ShadowOffset = -ZHeight;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tloaded = true;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (!loaded) {\n\t\t\t\ttree = new Tree();\n\t\t\t\ttree.Id = 5;\n\t\t\t\ttree.AlwaysShow = true;\n\t\t\t\tArea.Add(tree);\n\t\t\t}\n\n\t\t\tTimer.Add(() => { \n\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"mob_hive_static\", 0.8f, looped: true, tween: true);\n\t\t\t}, 5f);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tGetComponent<AudioEmitterComponent>().StopAll();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (tree != null) {\n\t\t\t\ttree.Position = Position - new Vector2(15, 16);\n\t\t\t}\n\t\t}\n\n\t\t#region Bee Hive States\n\t\tpublic class IdleState : SmartState<BeeHive> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\tif (T >= 10f) {\n\t\t\t\t\t\tT = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar bee = GenerateBee();\n\t\t\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animate();\n\t\t\t\t\t\tSelf.Area.Add(bee);\n\t\t\t\t\t\tbee.BottomCenter = Self.BottomCenter;\n\t\t\t\t\t\tAnimationUtil.Ash(bee.Center);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_hive_pop\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tT = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class FallingState : SmartState<BeeHive> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_hive_breaking\");\n\t\t\t\tSelf.tree = null;\n\n\t\t\t\tvar y = Self.Y;\n\t\t\t\tvar c = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\n\t\t\t\tTween.To(0, c.ShadowOffset, x => c.ShadowOffset = x, 0.4f, Ease.QuadIn);\n\t\t\t\tTween.To(y + ZHeight, y, x => Self.Y = x, 0.4f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\tAudio.PlaySfx(\"mob_hive_release\");\n\t\t\t\t\t\n\t\t\t\t\tSelf.AnimateDeath(null);\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().StopAll();\n\t\t\t\t\t\n\t\t\t\t\tvar am = 16;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"circle\") {\n\t\t\t\t\t\tColor = ProjectileColor.Orange,\n\t\t\t\t\t\tBounce = 5\n\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am) + Rnd.Float(-1f, 1f);\n\n\t\t\t\t\t\tbuilder.Scale = Rnd.Float(0.4f, 1f);\n\t\t\t\t\t\tvar p = builder.Shoot(a, Rnd.Float(3f, 10f)).Build();\n\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.25f, 0.5f, 1f));\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(4, 10); i++) {\n\t\t\t\t\t\tvar bee = GenerateBee();\n\t\t\t\t\t\tSelf.Area.Add(bee);\n\t\t\t\t\t\tbee.Center = Self.Center;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic static Bee GenerateBee() {\n\t\t\tvar r = Rnd.Float();\n\n\t\t\tif (r < 0.2f) {\n\t\t\t\treturn new Explobee();\n\t\t\t}/* else if (r < 0.3f) {\n\t\t\t\treturn new BigBee();\n\t\t\t}*/\n\n\t\t\treturn new Bee();\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tBecome<FallingState>();\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_hive_hurt\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/BigBee.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class BigBee : Bee {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tSpeed = 0.25f;\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"bigbee\";\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tfor (var i = 0; i < Rnd.Int(2, 5); i++) {\n\t\t\t\tvar bee = new Bee();\n\t\t\t\tArea.Add(bee);\n\t\t\t\tbee.Center = Center;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleDeath(d);\n\t\t}\n\n\t\tprotected override void AddBody() {\n\t\t\tAddComponent(new RectBodyComponent(2, 17, 19, 1));\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 4, 19, 13));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/BuffedFlower.cs",
    "content": "namespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class BuffedFlower : Flower {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tShootAllAtOnce = true;\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"buffed_flower\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/Explobee.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class Explobee : Bee {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tSpeed = 0.5f;\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"explobee\";\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tGetAnyComponent<BodyComponent>().KnockbackFrom(d.From, 2f);\n\n\t\t\tif (d.DamageType != DamageType.Melee && d.DamageType != DamageType.Explosive) {\n\t\t\t\tExplosionMaker.Make(this, 16);\n\t\t\t}\n\n\t\t\treturn base.HandleDeath(d);\n\t\t}\n\n\t\tprotected override void OnHit(Entity e) {\n\t\t\t// No slowness debuffs\n\t\t}\n\n\t\tprotected override void AddBody() {\n\t\t\tAddComponent(new RectBodyComponent(2, 9, 12, 1));\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 3, 10, 10));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/Flower.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class Flower : Mob {\n\t\tprotected bool ShootAllAtOnce;\n\t\t\n\t\tprotected virtual string GetAnimation() {\n\t\t\treturn \"flower\";\n\t\t}\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 18;\n\t\t\tHeight = 21;\n\t\t\t\n\t\t\tAddAnimation(GetAnimation());\n\t\t\tSetMaxHp(7);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new SensorBodyComponent(1, 1, 16, 19);\n\t\t\tAddComponent(body);\n\t\t\tbody.KnockbackModifier = 0;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tforeach (var p in projectiles) {\n\t\t\t\tp.Break();\n\t\t\t}\n\n\t\t\tprojectiles.Clear();\n\t\t}\n\n\t\t#region Flower States\n\t\tpublic class IdleState : SmartState<Flower> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = Rnd.Float(1);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!Self.CanSeeTarget()) {\n\t\t\t\t\tT = 0;\n\t\t\t\t} else if (T >= 1.5f) {\n\t\t\t\t\tBecome<FireState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate List<Projectile> projectiles = new List<Projectile>();\n\n\t\tpublic class FireState : SmartState<Flower> {\n\t\t\tprivate bool second;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tif (second) {\n\t\t\t\t\t\tif (Self.ShootAllAtOnce) {\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_fire_static\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (var i = 0; i < (Self.ShootAllAtOnce ? 8 : 1); i++) {\n\t\t\t\t\t\t\tvar p = Self.projectiles[0];\n\t\t\t\t\t\t\tSelf.projectiles.RemoveAt(0);\n\n\t\t\t\t\t\t\tif (!Self.ShootAllAtOnce) {\n\t\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_fire_static\", pitch: (Self.projectiles.Count / 16f - 0.5f) * 2);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!p.Done) {\n\t\t\t\t\t\t\t\tp.BodyComponent.Velocity = MathUtils.CreateVector(p.AngleTo(Self.Target), 200f);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tp.Break();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (Self.projectiles.Count == 0) {\n\t\t\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, Self.projectiles.Count % 2 == 0 ? \"circle\" : \"small\");\n\t\t\t\t\t\tvar p = builder.Shoot(Self.AngleTo(Self.Target), 0).Build();\n\n\t\t\t\t\t\tp.Center = Self.Position + new Vector2(9) + MathUtils.CreateVector(Self.projectiles.Count / 4f * Math.PI, 10);\n\t\t\t\t\t\tp.Depth = 1;\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_flower_charging\", pitch: Self.projectiles.Count / 8f);\n\t\t\t\t\t\tSelf.projectiles.Add(p);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (Self.projectiles.Count == 8) {\n\t\t\t\t\t\t\tsecond = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_flower_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_flower_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/Sniper.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.castle;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class Sniper : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"sniper\");\n\t\t\tSetMaxHp(4);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tvar body = new RectBodyComponent(3, 13, 10, 1);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tAddComponent(new SensorBodyComponent(2, 2, 12, 12));\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tExplosionMaker.Make(this);\n\t\t\treturn base.HandleDeath(d);\n\t\t}\n\n\t\tprivate int moveId;\n\t\t\n\t\t#region Bandit States\n\t\tpublic class IdleState : SmartState<Sniper> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 3f && Self.CanSeeTarget()) {\n\t\t\t\t\tBecome<AimState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate float lastAngle;\n\n\t\tpublic class AimState : SmartState<Sniper> {\n\t\t\tprivate Vector2 lastSeen;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"mob_sniper_focus\");\n\t\t\t\tSelf.AlwaysVisible = true; // So that the line is visible\n\t\t\t\tSelf.lastAngle = Self.AngleTo(Self.Target);\n\t\t\t\tlastSeen = Self.Target.Center;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T < 1f) {\n\t\t\t\t\tif (Self.CanSeeTarget()) {\n\t\t\t\t\t\tSelf.GraphicsComponent.Flipped = Self.Target.CenterX < Self.CenterX;\n\t\t\t\t\t\tlastSeen = Self.Target.Center;\n\t\t\t\t\t}\n\n\t\t\t\t\tSelf.lastAngle = (float) MathUtils.LerpAngle(Self.lastAngle, Self.AngleTo(lastSeen), dt * 2f);\n\t\t\t\t} else if (T >= 1.5f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\n\t\t\t\tSelf.AlwaysVisible = false;\n\t\t\t\t\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\t\t\t\t\t\n\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_static\");\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"rect\") {\n\t\t\t\t\t\t\tRectHitbox = true,\n\t\t\t\t\t\t\tScale = 1.5f,\n\t\t\t\t\t\t\tDamage = 2\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\n\t\t\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\t\t\tvar angle = Self.lastAngle + (i - 1) * 0.1f;\n\t\t\t\t\t\t\tbuilder.Shoot(angle, 30f).Build();\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (GetComponent<StateComponent>().StateInstance is AimState) {\n\t\t\t\tGraphics.Batch.DrawLine(Center - new Vector2(0, 2), new Vector2((int) (Center.X + Math.Cos(lastAngle) * Display.UiWidth), \n\t\t\t\t\t(int) (Center.Y + Math.Sin(lastAngle) * Display.UiWidth)), PlayerGraphicsComponent.AimLineColor, 1);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_bandit_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/jungle/Wombat.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.mob.jungle {\n\tpublic class Wombat : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\t\t\t\n\t\t\tAddAnimation(\"wombat\");\n\t\t\tSetMaxHp(5);\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tFlying = true;\n\t\t\tHeight = 12;\n\n\t\t\tGetComponent<MobAnimationComponent>().ShadowOffset = -2;\n\n\t\t\tvar body = new RectBodyComponent(1, 9, 14, 1);\n\t\t\tAddComponent(body);\n\t\t\t\n\t\t\tbody.Body.LinearDamping = 2;\n\t\t\tbody.Body.Restitution = 1;\n\t\t\tbody.Body.Friction = 0;\n\n\t\t\tAddComponent(new SensorBodyComponent(1, 2, 14, 8));\n\t\t}\n\n\t\t#region Wombat States\n\t\tpublic class IdleState : SmartState<Wombat> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tT = Rnd.Float(1);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!Self.CanSeeTarget()) {\n\t\t\t\t\tT = 0;\n\t\t\t\t} else if (T >= 1.5f) {\n\t\t\t\t\tBecome<FireState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class FireState : SmartState<Wombat> {\n\t\t\tprivate float sinceLast;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\tBecome<FireState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_wombat_fly\");\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = MathUtils.CreateVector(Self.Target.AngleTo(Self), 10f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tsinceLast -= dt;\n\t\t\t\t\n\t\t\t\tif (sinceLast <= 0) {\n\t\t\t\t\tsinceLast = 0.2f;\n\t\t\t\t\t\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"square\") {\n\t\t\t\t\t\tScale = Rnd.Float(0.4f, 0.8f),\n\t\t\t\t\t\tRectHitbox = true\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.Shoot(Self.GetComponent<RectBodyComponent>().Velocity.ToAngle() - Math.PI + Rnd.Float(-0.2f, 0.2f), Rnd.Float(4, 7)).Build();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T < 5f) {\n\t\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\t\t\t\t\tbody.Velocity += body.Velocity * (dt * 40);\n\t\t\t\t} else {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/library/Book.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.pattern;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.mob.library {\n\tpublic class Book : Mob {\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 14;\n\n\t\t\tSetMaxHp(25);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(0, 15, 14, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0.1f;\n\t\t\tbody.Body.LinearDamping = 4f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, 14, 16));\n\t\t\tAddComponent(new ZAnimationComponent(\"book\"));\n\t\t\tAddComponent(new ZComponent {\n\t\t\t\tFloat = true\n\t\t\t});\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\t#region Snowman States\n\t\tpublic class IdleState : SmartState<Book> {\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(1f, 5f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\tif (T >= delay && Self.CanSeeTarget()) {\n\t\t\t\t\t\tBecome<ToRageState>();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tT = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class ToRageState : SmartState<Book> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().Animation.Tag = \"anim\";\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\tBecome<RageState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class ToIdleState : SmartState<Book> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<ZAnimationComponent>().Animation.Tag = \"anim\";\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate const string Chars = \"abcdefghijklmnopqrstuvwxyz\";\n\t\t\n\t\tpublic class RageState : SmartState<Book> {\n\t\t\tprivate bool fired;\n\t\t\tprivate float delay;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(1f, 2f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 0.2f && !fired) {\n\t\t\t\t\tfired = true;\n\t\t\t\t\t\n\t\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\t\tvar h = Self.Target.GetComponent<HealthComponent>();\n\t\t\t\t\t\tvar c = h.Health <= 1 ? 'f' : Chars[Rnd.Int(Chars.Length)];\n\t\t\t\t\t\tvar a = Self.AngleTo(Self.Target);\n\t\t\t\t\t\tvar color = ProjectileColor.Rainbow[Rnd.Int(ProjectileColor.Rainbow.Length)];\n\t\t\t\t\t\tvar sprite = Rnd.Chance(60) ? \"circle\" : \"square\";\n\n\t\t\t\t\t\tif (LetterTemplateData.Data.TryGetValue(c, out var data)) {\n\t\t\t\t\t\t\tvar p = new ProjectilePattern(KeepShapePattern.Make(0)) {\n\t\t\t\t\t\t\t\tPosition = Self.Center\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tSelf.Area.Add(p);\n\n\t\t\t\t\t\t\tProjectileTemplate.MakeFast(Self, sprite, Self.Center, a, (pr) => {\n\t\t\t\t\t\t\t\tp.Add(pr);\n\t\t\t\t\t\t\t\tpr.Color = color;\n\n\t\t\t\t\t\t\t\tpr.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\t\t\t\t\t\t\t\tpr.BodyComponent.Angle = a;\n\t\t\t\t\t\t\t}, data, () => {\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tp.Launch(a, Rnd.Float(30, 80));\n\t\t\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire_static\");\n\t\t\t\t\t\t\t\t}, 0.2f);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (T >= delay || Self.Target == null) {\n\t\t\t\t\tBecome<ToIdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/library/Buffer.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.library {\n\tpublic class Buffer : Mob {\n\t\tprivate const float SafeDistance = 128f;\n    \t\t\n    protected override void SetStats() {\n    \tbase.SetStats();\n\n    \tWidth = 11;\n    \tHeight = 15;\n      TouchDamage = 0;\n\n    \tSetMaxHp(32);\n    \t\n    \tvar body = new RectBodyComponent(3, 14, 6, 1);\n    \tAddComponent(body);\n\n    \tbody.Body.LinearDamping = 4f;\n    \t\n    \tAddComponent(new SensorBodyComponent(2, 1, 7, 14));\n    \tAddComponent(new MobAnimationComponent(\"buffer\"));\n    \t\n    \tBecome<RunState>();\n    }\n\n    public override void Destroy() {\n\t    base.Destroy();\n\t    mob?.GetComponent<BuffsComponent>().Remove<BuffedBuff>();\n    }\n\n    #region Buffer States\n    public class RunState : SmartState<Buffer> {\n\t    public override void Update(float dt) {\n    \t\tbase.Update(dt);\n\n    \t\tif (Self.Target != null) {\n\t        if (!Self.CanSeeTarget() || Self.MoveTo(Self.Target.Center, 60f, SafeDistance, true)) {\n    \t\t\t\tBecome<SummonState>();\n    \t\t\t}\n    \t\t}\n        \n        Self.PushOthersFromMe(dt);\n    \t}\n    }\n\n    private Mob mob;\n\n    public class SummonState : SmartState<Buffer> {\n\t    public override void Init() {\n\t\t    base.Init();\n\t\t    Self.GetComponent<MobAnimationComponent>().Animation.Tag = \"idle\";\n\t    }\n\n\t    public override void Update(float dt) {\n\t\t    base.Update(dt);\n\t      \n\t\t    if (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) {\n\t\t\t    Become<RunState>();\n\t\t\t    return;\n\t\t    }\n\n\t\t    if (T >= 3f) {\n\t\t\t    var list = Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Mob];\n\n\t\t\t    if (list.Count <= 1) {\n\t\t\t\t    return;\n\t\t\t    }\n\n\t\t\t    var attempt = 0;\n\n\t\t\t    do {\n\t\t\t\t    if (attempt >= 30) {\n\t\t\t\t\t    return;\n\t\t\t\t    }\n\t\t\t\t    \n\t\t\t\t    Self.mob = (Mob) list[Rnd.Int(list.Count)];\n\t\t\t\t    attempt++;\n\t\t\t    } while (Self.mob == Self);\n\n\t\t\t    Self.mob.GetComponent<BuffsComponent>().Add(new BuffedBuff() {\n\t\t\t\t    Infinite = true\n\t\t\t    });\n\t\t\t    \n\t\t\t    Become<BuffState>();\n\t\t    }\n\t    }\n    }\n\n    public class BuffState : SmartState<Buffer> {\n      public override void Destroy() {\n\t      base.Destroy();\n\t      Self.mob?.GetComponent<BuffsComponent>().Remove<BuffedBuff>();\n      }\n\n      public override void Update(float dt) {\n\t      base.Update(dt);\n\t      \n    \t\tif (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) {\n    \t\t\tBecome<RunState>();\n    \t\t\treturn;\n    \t\t}\n\n        if (Self.mob != null && Self.mob.Done) {\n\t        Self.mob = null;\n\t        Become<SummonState>();\n        }\n      }\n    }\n    #endregion\n\t\t\n    protected override string GetHurtSfx() {\n\t    return \"mob_wizard_hurt\";\n    }\n\n    protected override string GetDeadSfx() {\n\t    return \"mob_wizard_death\";\n    }\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/library/Skeleton.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.desert;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.library {\n\tpublic class Skeleton : Mob {\n\t\tprivate const float SafeDistance = 128f;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 15;\n\t\t\tHeight = 21;\n\n\t\t\tSetMaxHp(40);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(2, 20, 11, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 4f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(3, 3, 9, 18));\n\t\t\tAddComponent(new MobAnimationComponent(\"skeleton\"));\n\t\t\t\n\t\t\tBecome<SummonState>();\n\t\t}\n\n\t\t#region Skeleton States\n\t\tpublic class RunState : SmartState<Skeleton> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\tif (!Self.CanSeeTarget() || Self.MoveTo(Self.Target.Center, 50f, SafeDistance, true)) {\n\t\t\t\t\t\tBecome<SummonState>();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tBecome<SummonState>();\n\t\t\t\t}\n\n\t\t\t\tSelf.PushOthersFromMe(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic class SummonState : SmartState<Skeleton> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animation.Tag = \"idle\";\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) {\n\t\t\t\t\tBecome<RunState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.PushOthersFromMe(dt);\n\t\t\t\t\n\t\t\t\tif (T >= 5f) {\n\t\t\t\t\tT = -5;\n\n\t\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animate(() => {\n\t\t\t\t\t\tvar summon = new Mummy();\n\t\t\t\t\t\tSelf.Area.Add(summon);\n\t\t\t\t\t\n\t\t\t\t\t\tsummon.BottomCenter = Self.BottomCenter + new Vector2(0, 2);\n\t\t\t\t\t\tsummon.Target = Self.Target;\t\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_skeleton_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_skeleton_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/library/TeleportingMage.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.pattern;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Utilities;\nusing MathUtils = Lens.util.MathUtils;\n\nnamespace BurningKnight.entity.creature.mob.library {\n\tpublic class TeleportingMage : Mob {\n\t\tprivate Color color;\n\t\t\n\t\tprotected override void SetStats() {\n\t\t\tbase.SetStats();\n\n\t\t\tWidth = 10;\n\t\t\tHeight = 14;\n\n\t\t\tSetMaxHp(30);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(0, 13, 10, 1);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.KnockbackModifier = 0f;\n\t\t\tbody.Body.LinearDamping = 4f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(1, 1, 8, 13));\n\t\t\tAddComponent(new MobAnimationComponent(\"mage\"));\n\t\t\t\n\t\t\tBecome<IdleState>();\n\n\t\t\tcolor = ProjectileColor.Rainbow[Rnd.Int(ProjectileColor.Rainbow.Length)];\n\t\t}\n\n\t\t#region Snowman States\n\t\tpublic class IdleState : SmartState<TeleportingMage> {\n\t\t\tprivate float delay;\n\t\t\tprivate bool tweened;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tdelay = Rnd.Float(4, 10f);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.Target != null) {\n\t\t\t\t\tSelf.GraphicsComponent.Flipped = Self.Target.CenterX < Self.CenterX;\n\t\t\t\t}\n\n\t\t\t\tif (!tweened && T >= delay - 0.4f) {\n\t\t\t\t\ttweened = true;\n\t\t\t\t\tSelf.GetComponent<MobAnimationComponent>().Animate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (T >= delay && Self.CanSeeTarget()) {\n\t\t\t\t\tvar p = new ProjectilePattern(KeepShapePattern.Make(Rnd.Chance() ? -4 : 4)) {\n\t\t\t\t\t\tPosition = Self.Center\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tSelf.Area.Add(p);\n\t\t\t\t\tvar sa = Rnd.AnglePI();\n\t\t\t\t\tvar count = 5;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(Self, \"small\") {\n\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\tColor = Self.color\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\t\t\tvar i1 = i;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tvar a = (float) Math.PI * i1 / (count * 0.5f) + sa;\n\t\t\t\t\t\t\tvar pr = builder.Build();\n\n\t\t\t\t\t\t\tpr.BodyComponent.Angle = a;\n\t\t\t\t\t\t\tpr.Center = Self.Center + MathUtils.CreateVector(a, 12);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tp.Add(pr);\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"mob_fire\");\n\n\t\t\t\t\t\t\tif (i1 == count - 1) {\n\t\t\t\t\t\t\t\tp.Launch(Self.Target == null ? Rnd.AnglePI() : Self.AngleTo(Self.Target), 80);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, i * 0.1f);\n\t\t\t\t\t}\n\n\t\t\t\t\tBecome<TeleportState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class TeleportState : SmartState<TeleportingMage> {\n\t\t\tprivate bool teleported;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 1.5f && !teleported) {\n\t\t\t\t\tteleported = true;\n\n\t\t\t\t\tvar a = Self.GetComponent<MobAnimationComponent>();\n\n\t\t\t\t\tTween.To(0.2f, a.Scale.X, x => a.Scale.X = x, 0.5f, Ease.QuadIn);\n\t\t\t\t\tTween.To(2f, a.Scale.Y, x => a.Scale.Y = x, 0.5f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\n\t\t\t\t\t\tVector2 s;\n\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\ts = r.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t\t\t} while (Self.Target != null && Self.Target.DistanceTo(s) < 32);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSelf.Center = s;\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.5f);\n\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.5f).OnEnd = () => {\n\t\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t\t\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn \"mob_wizard_hurt\";\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn \"mob_wizard_death\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefabs/Slime.cs",
    "content": "using System;\r\nusing System.Numerics;\r\nusing BurningKnight.entity.buff;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.drop;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.fx;\r\nusing BurningKnight.level;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.entity.component.logic;\r\nusing Lens.graphics;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\r\n\r\nnamespace BurningKnight.entity.creature.mob.prefabs {\r\n\tpublic class Slime : Mob {\r\n\t\tprivate bool first;\r\n\t\tprivate float delay;\r\n\t\t\r\n\t\tprivate static readonly Color color = ColorUtils.FromHex(\"#5ac54f\");\r\n\t\t\r\n\t\tprotected override Color GetBloodColor() {\r\n\t\t\treturn color;\r\n\t\t}\r\n\r\n\t\tprotected override void OnTargetChange(Entity target) {\r\n\t\t\tbase.OnTargetChange(target);\r\n\r\n\t\t\tif (target != null) {\r\n\t\t\t\tdelay = Rnd.Float(0, 2f);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected virtual float GetJumpDelay() {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tprotected virtual float GetJumpAngle() {\r\n\t\t\treturn Target == null ? Rnd.AnglePI() : AngleTo(Target) + Rnd.Float(-0.1f, 0.1f);\r\n\t\t}\r\n\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tAddComponent(new ZComponent());\r\n\t\t\tBecome<IdleState>();\r\n\t\t\t\r\n\t\t\tAddDrops(new SingleDrop(\"bk:slime\", 0.01f));\r\n\t\t}\r\n\t\t\r\n\t\t#region Slime States\r\n\t\tpublic class IdleState : SmartState<Slime> {\r\n\t\t\tprivate float delay;\r\n\t\t\tprivate bool tweened;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\t\r\n\t\t\t\tdelay = Self.first ? Rnd.Float(1f) : Self.GetJumpDelay();\r\n\t\t\t\tSelf.first = false;\r\n\r\n\t\t\t\t// To avoid exceptions when loading old save due to component not being there\r\n\r\n\t\t\t\tif (Self.TryGetComponent<RectBodyComponent>(out var c)) {\r\n\t\t\t\t\tc.Velocity = Vector2.Zero;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tif (Self.delay > 0) {\r\n\t\t\t\t\tSelf.delay -= dt;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (!tweened && T >= delay) {\r\n\t\t\t\t\ttweened = true;\r\n\r\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"mob_slime_jump\", 2);\r\n\t\t\t\t\t\r\n\t\t\t\t\tSelf.AnimateJump(() => {\r\n\t\t\t\t\t\tBecome<JumpState>();\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected float JumpForce = 120;\r\n\t\tprotected float ZVelocity = 5;\r\n\t\t\r\n\t\tprotected virtual void AnimateJump(Action callback) {\r\n\t\t\tvar anim = GetComponent<ZAnimationComponent>();\r\n\t\t\t\t\r\n\t\t\tTween.To(2f, anim.Scale.X, x => anim.Scale.X = x, 0.2f);\r\n\t\t\tTween.To(0.3f, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f).OnEnd = () => {\r\n\t\t\t\tTween.To(0.5f, anim.Scale.X, x => anim.Scale.X = x, 0.3f);\r\n\r\n\t\t\t\tTween.To(2f, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f).OnEnd = () => {\r\n\t\t\t\t\tTween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.2f);\r\n\t\t\t\t\tTween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f);\r\n\t\t\t\t};\r\n\r\n\t\t\t\tcallback();\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tprotected virtual void AnimateLand() {\r\n\t\t\tvar anim = GetComponent<ZAnimationComponent>();\r\n\r\n\t\t\tanim.Scale.X = 2f;\r\n\t\t\tanim.Scale.Y = 0.3f;\r\n\t\t\tTween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.3f);\r\n\t\t\tTween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f);\r\n\t\t}\r\n\t\t\r\n\t\tpublic class JumpState : SmartState<Slime> {\r\n\t\t\tpublic bool InAir;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\tInAir = true;\r\n\t\t\t\tSelf.OnJump();\r\n\t\t\t\tvar a = Self.GetJumpAngle();\r\n\t\t\t\tvar force = Rnd.Float(20f) + Self.JumpForce;\r\n\t\t\t\t\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\r\n\r\n\t\t\t\tSelf.GetComponent<ZComponent>().ZVelocity = Self.ZVelocity;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Destroy() {\r\n\t\t\t\tbase.Destroy();\r\n\t\t\t\t\r\n\t\t\t\tSelf.AnimateLand();\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\r\n\t\t\t\tSelf.OnLand();\r\n\t\t\t\t\r\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"mob_slime_land\", 2);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tvar component = Self.GetComponent<ZComponent>();\r\n\r\n\t\t\t\tif (component.Z >= 4f) {\r\n\t\t\t\t\tSelf.Depth = Layers.FlyingMob;\r\n\t\t\t\t\tSelf.TouchDamage = 0;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tSelf.Depth = Layers.Creature;\r\n\t\t\t\t\tSelf.TouchDamage = 1;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (T >= 0.1f && component.Z <= 0) {\r\n\t\t\t\t\tcomponent.Z = 0;\r\n\t\t\t\t\tInAir = false;\r\n\t\t\t\t\tBecome<IdleState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tpublic override bool InAir() {\r\n\t\t\treturn (GetComponent<StateComponent>().StateInstance is JumpState j && j.InAir);\r\n\t\t}\r\n\r\n\t\tpublic override bool ShouldCollide(Entity entity) {\r\n\t\t\tif (entity is Chasm) {\r\n\t\t\t\treturn !InAir();\r\n\t\t\t}\r\n\r\n\t\t\treturn base.ShouldCollide(entity);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is HealthModifiedEvent ev && ev.Amount < 0 && InAir() && GetComponent<ZComponent>().Z > 4f) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic override bool ShouldCollideWithDestroyableInAir() {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tpublic override bool IgnoresProjectiles() {\r\n\t\t\treturn InAir();\r\n\t\t}\r\n\r\n\t\tprotected virtual void OnJump() {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tprotected virtual void OnLand() {\r\n\t\t\tif (Target == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tArea.Add(new SplashFx {\r\n\t\t\t\tPosition = Center,\r\n\t\t\t\tColor = ColorUtils.Mod(GetBloodColor())\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tprotected override string GetDeadSfx() {\r\n\t\t\treturn \"mob_slime_death\";\r\n\t\t}\r\n\r\n\t\tprotected override string GetHurtSfx() {\r\n\t\t\treturn \"slime_hurt\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefabs/WallWalker.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.entity.buff;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob.castle;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.level.rooms;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.entity.component.logic;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\nusing Microsoft.Xna.Framework;\r\nusing VelcroPhysics.Dynamics;\r\n\r\nnamespace BurningKnight.entity.creature.mob.prefabs {\r\n\tpublic class WallWalker : Mob {\r\n\t\tprotected internal Direction Direction;\r\n\t\tpublic bool Left;\r\n\t\tpublic float T;\r\n\t\tpublic bool Inited;\r\n\r\n\t\tpublic override bool InAir() {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tprotected override void SetStats() {\r\n\t\t\tbase.SetStats();\r\n\t\t\t\r\n\t\t\tWidth = 16;\r\n\t\t\tHeight = 16;\r\n\t\t\tLeft = Rnd.Chance();\r\n\t\t\t\r\n\t\t\tGetComponent<BuffsComponent>().AddImmunity<FrozenBuff>();\r\n\t\t}\r\n\r\n\t\tprivate bool locked;\r\n\t\t\r\n\t\tprivate void LockToWall() {\r\n\t\t\ttry {\r\n\t\t\t\tvar dirs = new List<Direction>();\r\n\r\n\t\t\t\tvar x = (int) Math.Round(X / 16f);\r\n\t\t\t\tvar y = (int) Math.Round((Y + 8) / 16f);\r\n\t\t\t\tvar level = Run.Level;\r\n\r\n\t\t\t\tif (level.Get(x + 1, y).IsWall()) {\r\n\t\t\t\t\tdirs.Add(Direction.Left);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (level.Get(x - 1, y).IsWall()) {\r\n\t\t\t\t\tdirs.Add(Direction.Right);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (level.Get(x, y + 1).IsWall()) {\r\n\t\t\t\t\tdirs.Add(Direction.Up);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (level.Get(x, y - 1).IsWall()) {\r\n\t\t\t\t\tdirs.Add(Direction.Down);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (dirs.Count == 0) {\r\n\t\t\t\t\tLog.Error(\"No walls to lock to!\");\r\n\r\n\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\tDone = true;\r\n\t\t\t\t\t}, 0.1f);\r\n\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tCenterX = x * 16 + 8;\r\n\t\t\t\tCenterY = y * 16;\r\n\r\n\t\t\t\tDirection = dirs[Rnd.Int(dirs.Count)];\r\n\t\t\t\tvar angle = Direction.ToAngle();\r\n\r\n\t\t\t\tvar v = Direction == Direction.Up || Direction == Direction.Down;\r\n\t\t\t\tvar body = new RectBodyComponent(Direction == Direction.Left ? 8 : 0, Direction == Direction.Up ? 8 : 0, v ? 16 : 8, v ? 8 : 16, BodyType.Dynamic, true);\r\n\r\n\t\t\t\tAddComponent(body);\r\n\t\t\t\tbody.KnockbackModifier = 0;\r\n\r\n\t\t\t\tGetComponent<WallAnimationComponent>().WallAngle = angle;\r\n\t\t\t\tGetComponent<StateComponent>().State = GetIdleState();\r\n\t\t\t} catch (Exception e) {\r\n\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\tDone = true;\r\n\t\t\t\t}, 0.1f);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tvar y = Y;\r\n\t\t\t\t\r\n\t\t\tX = (int) Math.Floor(X / 16f) * 16;\r\n\t\t\tY = (int) Math.Floor(y / 16f) * 16 + 8;\r\n\t\t\t\r\n\t\t\tbase.Save(stream);\r\n\r\n\t\t\tY = y;\r\n\t\t}\r\n\r\n\t\tprotected virtual float GetSpeed() {\r\n\t\t\treturn 30f;\r\n\t\t}\r\n\t\t\r\n\t\t#region Walker States\r\n\t\tpublic class IdleState : SmartState<WallWalker> {\r\n\t\t\tprotected Vector2 velocity;\r\n\t\t\tprotected float vx;\r\n\t\t\tprotected float vy;\r\n\t\t\tprotected int mx;\r\n\t\t\tprotected int my;\r\n\r\n\t\t\tpublic void ResetVelocity() {\r\n\t\t\t\tvelocity = Vector2.Zero;\r\n\t\t\t\tvx = 0;\r\n\t\t\t\tvy = 0;\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t}\r\n\r\n\t\t\tpublic void InvertVelocity() {\r\n\t\t\t\tSelf.Left = !Self.Left;\r\n\t\t\t\tvelocity *= -1;\r\n\t\t\t\tvx *= -1;\r\n\t\t\t\tvy *= -1;\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t\tT = 0;\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\t\r\n\t\t\t\tif (!Self.Inited) {\r\n\t\t\t\t\tSelf.Inited = true;\r\n\t\t\t\t\tT = Rnd.Float(1f);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar f = Self.GetSpeed();\r\n\t\t\t\tvar a = Self.Direction.ToAngle();\r\n\r\n\t\t\t\tif (Self.Left) {\r\n\t\t\t\t\ta += (float) Math.PI;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvx = (float) Math.Sin(a);\r\n\t\t\t\tvy = (float) Math.Cos(a);\r\n\t\t\t\t\r\n\t\t\t\tvelocity.X = vx * f;\r\n\t\t\t\tvelocity.Y = vy * f;\r\n\t\t\t\t\r\n\t\t\t\tmx = Self.Direction.GetMx();\r\n\t\t\t\tmy = Self.Direction.GetMy();\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\t/*var mx = Self.CenterX;\r\n\t\t\t\tvar my = Self.CenterY;\r\n\r\n\t\t\t\tvar x = (int) Math.Round(mx / 16f);\r\n\t\t\t\tvar y = (int) Math.Round(my / 16f);\r\n\r\n\t\t\t\tif (Run.Level.IsInside(x, y) && Run.Level.Get(x, y).IsWall()) {\r\n\t\t\t\t\tLog.Debug(\"Killing walker\");\r\n\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\tSelf.Done = true;\r\n\t\t\t\t\t}, 0.1f);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}*/\r\n\t\t\t\t\r\n\t\t\t\tvar mx = Self.X + (this.mx) * 16;\r\n\t\t\t\tvar my = Self.CenterY + (this.my) * 16;\r\n\r\n\t\t\t\tif (!Run.Level.Get((int) Math.Round(mx / 16f), (int) Math.Round(my / 16f)).IsWall()) {\r\n\t\t\t\t\tSelf.GetComponent<HealthComponent>().Kill(Self);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tmx = Self.X + (this.mx + vx * 0.5f) * 16;\r\n\t\t\t\tmy = Self.CenterY + (this.my + vy * 0.5f) * 16;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\tvar tx = (int) Math.Round(mx / 16f);\r\n\t\t\t\tvar ty = (int) Math.Round(my / 16f);\r\n\r\n\t\t\t\tif (!Run.Level.Get(tx, ty).IsWall()) {\r\n\t\t\t\t\tFlip();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tmx = Self.X + (vx) * 12;\r\n\t\t\t\tmy = Self.CenterY + (vy) * 12;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\ttx = (int) Math.Round(mx / 16f);\r\n\t\t\t\tty = (int) Math.Round(my / 16f);\r\n\t\t\t\t\r\n\t\t\t\tif (Run.Level.Get(tx, ty).IsWall()) {\r\n\t\t\t\t\tFlip();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tDoLogic(dt);\r\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = velocity;\r\n\t\t\t}\r\n\r\n\t\t\tpublic virtual void DoLogic(float dt) {\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tpublic virtual void Flip() {\r\n\t\t\t\tInvertVelocity();\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tprotected virtual Type GetIdleState() {\r\n\t\t\treturn typeof(IdleState);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent ev) {\r\n\t\t\t\tvar en = ev.Entity;\r\n\r\n\t\t\t\tif (en is Door || (en is SolidProp && !(en is BreakableProp))) {\r\n\t\t\t\t\tvar state = GetComponent<StateComponent>().StateInstance;\r\n\r\n\t\t\t\t\tif (state is IdleState s) {\r\n\t\t\t\t\t\ts.Flip();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tif (Done) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (!locked) {\r\n\t\t\t\tlocked = true;\r\n\t\t\t\tLockToWall();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tbase.Update(dt);\r\n\t\t\tT += dt;\r\n\r\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (room == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (room.Type != RoomType.Regular && room.Type != RoomType.Boss) {\r\n\t\t\t\t\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\tDone = true;\r\n\t\t\t\t}, 0.1f);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t/*if (room.Tagged[Tags.Player].Count == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tforeach (var m in room.Tagged[Tags.MustBeKilled]) {\r\n\t\t\t\tif (m is Mob && !(m is WallWalker || m is bk.BurningKnight)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tKill(this);*/\r\n\t\t}\r\n\r\n\t\tprotected override string GetDeadSfx() {\r\n\t\t\treturn \"mob_hugger_death\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/DeathShotPrefix.cs",
    "content": "using System;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class DeathShotPrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(245 / 255f, 85 / 255f, 93 / 255f, 1);\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DiedEvent) {\n\t\t\t\tvar am = 8;\n\n\t\t\t\tvar builder = new ProjectileBuilder(Mob, \"small\") {\n\t\t\t\t\tLightRadius = 32\n\t\t\t\t};\n\t\t\t\n\t\t\t\tfor (var i = 0; i < am; i++) {\n\t\t\t\t\tvar a = Math.PI * 2 * (((float) i) / am) + Rnd.Float(-0.1f, 0.1f);\n\t\t\t\t\tbuilder.Shoot(a, 3f).Build();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/EmeraldPrefix.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class EmeraldPrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(0, 220 / 255f, 152 / 255f, 1);\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tMob.GetComponent<DropsComponent>().Add(new SimpleDrop(1f, 2, 5, \"bk:emerald\"));\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/ExplosivePrefix.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class ExplosivePrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(138 / 255f, 72 / 255f, 54 / 255f, 1);\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DiedEvent) {\n\t\t\t\tvar bomb = new Bomb(Mob);\n\t\t\t\tMob.Area.Add(bomb);\n\t\t\t\tbomb.Center = Mob.Center;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/FragilePrefix.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class FragilePrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(146 / 255f, 161 / 255f, 185 / 255f, 1);\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme) {\n\t\t\t\tif (hme.Amount < 0) {\n\t\t\t\t\tAnimationUtil.Poof(Mob.Center, 1);\n\t\t\t\t\tvar room = Mob.GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room == null) {\n\t\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tMob.Center = room.GetRandomFreeTile() * 16 + new Vector2(8, 8);\n\t\t\t\t\tAnimationUtil.Poof(Mob.Center, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/GoldPrefix.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class GoldPrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(1f, 200 / 255f, 37 / 255f, 1);\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tMob.GetComponent<DropsComponent>().Add(new SimpleDrop(1f, 1, 3, \"bk:copper_coin\"));\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/HealthyPrefix.cs",
    "content": "using BurningKnight.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class HealthyPrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(255 / 255f, 0, 64 / 255f, 1);\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tvar health = Mob.GetComponent<HealthComponent>();\n\t\t\thealth.InitMaxHealth = health.MaxHealth * 2;\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/Prefix.cs",
    "content": "using Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic abstract class Prefix {\n\t\tpublic Mob Mob;\n\t\tpublic string Id;\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool HandleEvent(Event e) {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic abstract Vector4 GetColor();\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/PrefixRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.mod;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic static class PrefixRegistry {\n\t\tpublic static Dictionary<string, Type> Defined = new Dictionary<string, Type>();\n\n\t\tstatic PrefixRegistry() {\n\t\t\tDefine<ExplosivePrefix>(\"explosive\");\n\t\t\tDefine<DeathShotPrefix>(\"death_shot\");\n\t\t\tDefine<HealthyPrefix>(\"healthy_shot\");\n\t\t\t// Define<EmeraldPrefix>(\"emerald\");\n\t\t\tDefine<FragilePrefix>(\"fragile\");\n\t\t\tDefine<GoldPrefix>(\"gold\");\n\t\t}\n\n\t\tpublic static void Define<T>(string id, Mod mod = null) where T : Prefix {\n\t\t\tDefined[$\"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}\"] = typeof(T);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/mob/prefix/RegenerativePrefix.cs",
    "content": "using BurningKnight.entity.component;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.mob.prefix {\n\tpublic class RegenerativePrefix : Prefix {\n\t\tprivate static Vector4 color = new Vector4(237f / 255f, 118 / 255f, 20 / 255f, 1);\n\n\t\tprivate float sinceLast;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tsinceLast -= dt;\n\t\t\t\n\t\t\tif (sinceLast < 0) {\n\t\t\t\tsinceLast = 1;\n\n\t\t\t\tvar health = Mob.GetComponent<HealthComponent>();\n\n\t\t\t\tif (!health.IsFull()) {\n\t\t\t\t\thealth.ModifyHealth(1f, Mob);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override Vector4 GetColor() {\n\t\t\treturn color;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/AccessoryTrader.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.save;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class AccessoryTrader : ShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 12;\n\t\t\tHeight = 15;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"accessory_trader\"));\n\n\t\t\tvar b = new RectBodyComponent(2, 6, Width - 4, Height - 6);\n\t\t\tAddComponent(b);\n\t\t\tb.KnockbackModifier = 0;\n\t\t}\n\n\t\tprotected override string GetDialog() {\n\t\t\treturn $\"accessorytrader_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn AccessoryTrader;\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is ArtifactStand;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/ActiveTrader.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class ActiveTrader : ShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 17;\n\t\t\tHeight = 22;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"active_trader\"));\n\n\t\t\tvar b = new RectBodyComponent(2, 6, Width - 4, Height - 6);\n\t\t\tAddComponent(b);\n\t\t\tb.KnockbackModifier = 0;\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 1;\n\t\t}\n\n\t\tprotected override string GetDialog() {\n\t\t\treturn $\"activetrader_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ActiveTrader;\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is ActiveStand;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Beet.cs",
    "content": "using System;\nusing System.Text;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Beet : Npc {\n\t\tprivate Entity interactingWith;\n\n\t\tstatic Beet() {\n\t\t\tDialogs.RegisterCallback(\"beet_0\", (d, c) => {\n\t\t\t\tc.Dialog.Str.SetVariable(\"seed\", Run.NextSeed);\n\t\t\t\treturn Dialogs.Get($\"beet_{(Run.IgnoreSeed ? 4 : 1)}\");\n\t\t\t});\n\t\t\t\n\t\t\tDialogs.RegisterCallback(\"beet_2\", (d, c) => {\n\t\t\t\tvar a = ((AnswerDialog) d).Answer;\n\n\t\t\t\tLog.Info($\"Beet set the seed to {a}\");\n\t\t\t\t\n\t\t\t\tRnd.Seed = a;\n\t\t\t\tRun.NextSeed = a;\n\t\t\t\tRun.IgnoreSeed = true;\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\t\n\t\t\tDialogs.RegisterCallback(\"beet_4\", (d, c) => {\n\t\t\t\tif (((ChoiceDialog) d).Choice == 2) {\n\t\t\t\t\tRun.NextSeed = Rnd.GenerateSeed();\n\t\t\t\t\tRun.IgnoreSeed = false;\n\n\t\t\t\t\tc.Dialog.Str.SetVariable(\"seed\", Run.NextSeed);\n\t\t\t\t\tLog.Info($\"Beet randomly set the seed to {Run.NextSeed}\");\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 18;\n\t\t\tHeight = 19;\n\n\t\t\tAddComponent(new AnimationComponent(\"beet\"));\n\t\t\tAddComponent(new RectBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2) {\n\t\t\t\tKnockbackModifier = 0\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\t\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\n\t\t\tvar dialog = GetComponent<DialogComponent>();\n\t\t\t\n\t\t\tdialog.Dialog.Voice = 1;\n\t\t\tdialog.OnNext += (c) => {\n\t\t\t\tif (c.Current == null && !Run.IgnoreSeed) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<HideState>();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (GetComponent<DialogComponent>().Current?.Id == \"beet_2\" && Input.Keyboard.WasPressed(Keys.V) && (Input.Keyboard.IsDown(Keys.LeftControl) || Input.Keyboard.IsDown(Keys.RightControl))) {\n\t\t\t\tLog.Info(\"Pasting the seed\");\n\t\t\t\tvar seed = \"ERROR\";\n\n\t\t\t\ttry {\n\t\t\t\t\t// Needs xclip on linux\n\t\t\t\t\tseed = TextCopy.Clipboard.GetText().ToUpper();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\n\t\t\t\tif (seed.Length == 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (seed.Length > 8) {\n\t\t\t\t\tseed = seed.Substring(0, 8);\n\t\t\t\t}\n\n\t\t\t\tvar builder = new StringBuilder();\n\n\t\t\t\tfor (var i = 0; i < seed.Length; i++) {\n\t\t\t\t\tvar c = seed[i];\n\t\t\t\t\tbuilder.Append(Rnd.SeedChars.IndexOf(c) != -1 && c != '_' ? c : 'X');\n\t\t\t\t}\n\n\t\t\t\tvar result = builder.ToString();\n\t\t\t\tLog.Info($\"Initial seed {seed} converted to {result}\");\n\n\t\t\t\t((AnswerDialog) GetComponent<DialogComponent>().Current).Answer = result;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tvar state = GetComponent<StateComponent>();\n\n\t\t\tif (state.StateInstance is IdleState) {\n\t\t\t\tinteractingWith = e;\n\t\t\t\tstate.Become<PopState>();\n\t\t\t} else {\n\t\t\t\tGetComponent<DialogComponent>().Start(\"beet_0\", e);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\t#region Beet States\n\t\tpublic class IdleState : SmartState<Beet> {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic class PopState : SmartState<Beet> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"npc_beet_show\");\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<PoppedState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class HideState : SmartState<Beet> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"npc_beet_hide\");\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class PoppedState : SmartState<Beet> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<DialogComponent>().Start(\"beet_0\", Self.interactingWith);\n\t\t\t\tSelf.interactingWith = null;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Bird.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Bird : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tHeight = 14;\n\n\t\t\tAddComponent(new AnimationComponent(\"bird\"));\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\t\n\t\t\tAddComponent(new QuackInteractionComponent(p => {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar d = GetComponent<DialogComponent>();\n\n\t\t\t\t\tif (d.Current != null && d.Current.Id != \"quack\") {\n\t\t\t\t\t\td.StartAndClose(\"quack\", 3);\n\t\t\t\t\t}\n\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"quck\");\n\t\t\t\t}, 0.5f);\n\t\t\t}));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce && rce.Who is Player) {\n\t\t\t\tif (rce.New == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tGetComponent<DialogComponent>().Start(\"^^Spanish^^ or [cl red]##vanish##[cl]!\");\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Brastin.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Brastin : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 13;\n\t\t\tHeight = 18;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"brastin\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"brastin_0\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 3;\n\n\t\t\tif (Achievements.Get(\"bk:cat_without_a_hat\").Unlocked) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Builder.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.util.timer;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Builder : Npc {\n\t\tprivate int cost;\n\t\tprivate int paid;\n\t\tprivate bool shouldDissappear;\n\n\t\tprivate int GetPrice() {\n\t\t\treturn Math.Max(3, cost - paid);\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 7;\n\t\t\tHeight = 17;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\n\t\t\tcost = Math.Min(99, Run.Depth * 15);\n\t\t\tpaid = GlobalSave.GetInt(\"builder_paid\", 0);\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"builder\"));\n\t\t\t// GetComponent<DialogComponent>().Dialog.Voice = 15;\n\n\t\t\tvar dl = GetComponent<DialogComponent>();\n\n\t\t\tdl.InitCallback = () => {\n\t\t\t\tdl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(\"coin\"));\n\t\t\t\tdl.Dialog.Str.SetVariable(\"need\", GetPrice());\n\t\t\t};\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(e => {\n\t\t\t\tdl.Start(\"builder_0\", e);\n\t\t\t\treturn true;\n\t\t\t}) {\n\t\t\t\tCanInteract = e => !shouldDissappear\n\t\t\t});\n\n\t\t\tDialogs.RegisterCallback(\"builder_0\", (d, c) => {\n\t\t\t\tif (((ChoiceDialog) d).Choice == 0) {\n\t\t\t\t\tif (!c.To.TryGetComponent<ConsumablesComponent>(out var component) || component.Coins == 0) {\n\t\t\t\t\t\t// Bro, you have no money!\n\t\t\t\t\t\treturn Dialogs.Get(\"builder_1\");\n\t\t\t\t\t}\n\n\t\t\t\t\tvar amount = Math.Min(GetPrice(), component.Coins);\n\n\t\t\t\t\tpaid += amount;\n\t\t\t\t\tcomponent.Coins -= amount;\n\t\t\t\t\tdl.Dialog.Str.SetVariable(\"need\", GetPrice());\n\n\t\t\t\t\tif (paid >= cost) {\n\t\t\t\t\t\tGlobalSave.Put(\"builder_paid\", 0);\n\t\t\t\t\t\tGlobalSave.Put($\"shortcut_{Run.Depth}\", true);\n\n\t\t\t\t\t\treturn Dialogs.Get(\"builder_3\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tGlobalSave.Put(\"builder_paid\", paid);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn Dialogs.Get(\"builder_2\");\n\t\t\t\t}\n\n\t\t\t\treturn Dialogs.Get(\"builder_4\");\n\t\t\t});\n\n\t\t\tDialogs.RegisterCallback(\"builder_3\", (d, c) => {\n\t\t\t\tshouldDissappear = true;\n\n\t\t\t\tCheckShortcutUnlocks();\n\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\tDone = true;\n\t\t\t\t}, 5f);\n\t\t\t\t\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tpublic static void CheckShortcutUnlocks() {\n\t\t\tif (GlobalSave.IsTrue(\"shortcut_3\")) {\n\t\t\t\tAchievements.Unlock(\"bk:desert_shortcut\");\n\t\t\t}\n\t\t\t\n\t\t\tif (GlobalSave.IsTrue(\"shortcut_5\")) {\n\t\t\t\tAchievements.Unlock(\"bk:jungle_shortcut\");\n\t\t\t}\n\t\t\t\n\t\t\tif (GlobalSave.IsTrue(\"shortcut_7\")) {\n\t\t\t\tAchievements.Unlock(\"bk:ice_shortcut\");\n\t\t\t}\n\t\t\t\n\t\t\tif (GlobalSave.IsTrue(\"shortcut_9\")) {\n\t\t\t\tAchievements.Unlock(\"bk:library_shortcut\");\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (GlobalSave.IsTrue($\"shortcut_{Run.Depth}\")) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tGameSave.Put(\"seen_builder\", true);\n\t\t\t}\n\t\t}\n\n\t\tpublic static bool ShouldAppear() {\n\t\t\tif (Run.Type != RunType.Regular || GameSave.IsTrue(\"seen_builder\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Run.Depth == 5 && LevelSave.GenerateMarket && Run.Loop == 0) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Run.Depth == 3 || Run.Depth == 5 || Run.Depth == 7 || Run.Depth == 9) {\n\t\t\t\treturn GlobalSave.IsFalse($\"shortcut_{Run.Depth}\");\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/DarkMage.cs",
    "content": "using System.Timers;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.math;\nusing Timer = Lens.util.timer.Timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class DarkMage : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 14;\n\t\t\tHeight = 17;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"dark_mage\"));\n\n\t\t\tif (!(Run.Level?.Biome is LibraryBiome)) {\n\t\t\t\tAddComponent(new CloseDialogComponent(\"dm_0\"));\n\t\t\t}\n\n\t\t\tSubscribe<Dialog.EndedEvent>();\n\t\t\tSubscribe<ItemTakenEvent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is Dialog.EndedEvent dee) {\n\t\t\t\tif (dee.Dialog.Id == \"bk_10\") {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t// Really, well, thank you, Limpor\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"dm_1\", 5);\n\t\t\t\t\t}, 1f);\n\t\t\t\t}\n\t\t\t} else if (e is ItemTakenEvent ite) {\n\t\t\t\tif (ite.Stand is DarkMageStand) {\n\t\t\t\t\t// Yes, yes, I need more power!\n\t\t\t\t\t// MORE POWER!!!\n\t\t\t\t\t// I can feel the energy growing in me!\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"dm_{Rnd.Int(2, 4)}\", 5);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Discord.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Discord : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 10;\n\t\t\tHeight = 12;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"discord\"));\n\t\t\t\n\t\t\t// todo: connect discordIntegration CurrentPlayer here\n\t\t\tAddComponent(new CloseDialogComponent(\"discord_0\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 2;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Duck.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.input;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.dialog;\r\nusing Lens;\r\nusing Lens.util.file;\r\nusing Lens.util.math;\r\nusing VelcroPhysics.Utilities;\r\n\r\nnamespace BurningKnight.entity.creature.npc {\r\n\tpublic class Duck : Npc {\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tWidth = 12;\r\n\t\t\tHeight = 10;\r\n\t\t\t\r\n\t\t\tAddComponent(new AnimationComponent(\"duck\"));\r\n\r\n\t\t\tvar b = new RectBodyComponent(0, 0, Width, Height);\r\n\t\t\tAddComponent(b);\r\n\t\t\tb.KnockbackModifier = 0;\r\n\r\n\t\t\tquantom = Rnd.Chance(1);\r\n\t\t\t\r\n\t\t\tif (Run.Depth == -2) {\r\n\t\t\t\tAddComponent(new CloseDialogComponent(\"control_4\"));\r\n\t\t\t} else {\r\n\t\t\t\tAddComponent(new CloseDialogComponent($\"duck_{(quantom ? 20 : 19)}\"));\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tBecome<IdleState>();\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 4;\r\n\t\t}\r\n\r\n\t\tprivate bool set;\r\n\t\tprivate float x;\r\n\t\tprivate bool quantom;\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\t\t\tx = X;\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tif (Engine.Instance.State is EditorState) {\r\n\t\t\t\tx = X;\r\n\t\t\t} else {\r\n\t\t\t\tX = x;\r\n\t\t\t}\r\n\r\n\t\t\tbase.Save(stream);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!set) {\r\n\t\t\t\tset = true;\r\n\t\t\t\t\r\n\t\t\t\tvar dialog = GetComponent<DialogComponent>();\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\tdialog.Dialog.Str.ClearIcons();\r\n\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Duck, false)));\r\n\r\n\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\r\n\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Duck, true)));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t#region Duck States\r\n\r\n\t\tprivate class IdleState : SmartState<Duck> {\r\n\t\t\tprivate bool toLeft;\r\n\t\t\tprivate float vx;\r\n\t\t\tprivate float pauseTimer;\r\n\t\t\tprivate float tillPause;\r\n\t\t\t\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tSelf.GraphicsComponent.Flipped = toLeft;\r\n\r\n\t\t\t\tif (pauseTimer > 0) {\r\n\t\t\t\t\tpauseTimer -= dt;\r\n\r\n\t\t\t\t\tif (pauseTimer <= 0) {\r\n\t\t\t\t\t\ttillPause = Rnd.Float(0.5f, 2f);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (tillPause >= 0) {\r\n\t\t\t\t\ttillPause -= dt;\r\n\r\n\t\t\t\t\tif (tillPause < 0) {\r\n\t\t\t\t\t\ttillPause = 0;\r\n\t\t\t\t\t\tpauseTimer = Rnd.Float(0.5f, 2f);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tvx += (toLeft ? -1 : 1) * (dt * 10);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvx -= vx * (dt * 3);\r\n\t\t\t\tvar n = Self.X + vx * (10 * dt);\r\n\r\n\t\t\t\tif (Self.quantom) {\r\n\t\t\t\t\tSelf.X = MathUtils.Clamp(n, Self.x - 16, Self.x + 16);\r\n\r\n\t\t\t\t\tif (Math.Abs(Self.X - Self.x) >= 16) {\r\n\t\t\t\t\t\ttoLeft = !toLeft;\r\n\t\t\t\t\t\tSelf.X = Self.x + (toLeft ? -16 : 16);\r\n\t\t\t\t\t\tvx *= -1;\r\n\r\n\t\t\t\t\t\tif (Rnd.Chance(10)) {\r\n\t\t\t\t\t\t\tSelf.X = Self.x;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tSelf.X = MathUtils.Clamp(n, Self.x - 16, Self.x + 16);\r\n\r\n\t\t\t\t\tif (Math.Abs(Self.X - Self.x) >= 16) {\r\n\t\t\t\t\t\ttoLeft = !toLeft;\r\n\t\t\t\t\t\tvx *= -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Elon.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Elon : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 17;\n\t\t\tHeight = 19;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"elon\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"elon_0\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 15;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/EmeraldGolem.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class EmeraldGolem : Npc {\n\t\tprivate const int Amount = 20;\n\t\tprivate bool broken;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 31;\n\t\t\tHeight = 33;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"emerald_golem\"));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding, BodyType.Static));\n\t\t\tAddComponent(new RectBodyComponent(2, 17, 27, 16, BodyType.Static));\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => !broken\n\t\t\t});\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 15;\n\t\t\t\n\t\t\tDialogs.RegisterCallback(\"eg_0\", (d, c) => {\n\t\t\t\tif (broken) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (((ChoiceDialog) d).Choice == 0) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(Locale.Get(\"eg_1\"), 3);\n\t\t\t\t\t}, 0.2f);\n\n\t\t\t\t\tvar inv = c.To.GetComponent<InventoryComponent>();\n\t\t\t\t\tvar a = c.To.Area;\n\t\t\t\n\t\t\t\t\tfor (var i = 0; i < Amount; i++) {\n\t\t\t\t\t\tinv.Pickup(Items.CreateAndAdd(\"bk:emerald\", a));\n\t\t\t\t\t}\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tinv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a));\n\t\t\t\t\t}, 1f);\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\t\t\t\tDone = true;\n\t\t\t\t\t\t\tEngine.Instance.Flash = 1f;\n\t\t\t\t\t\t\tCamera.Instance.Shake(8);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tpart.Position = Center + Rnd.Vector(-16, 16);\n\t\t\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 2f);\n\t\t\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}, 4f);\n\n\t\t\t\t\tbroken = true;\n\t\t\t\t\treturn null;\n\t\t\t\t} else if (GlobalSave.IsTrue(\"bk:emerald_gun\")) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(Locale.Get(\"eg_1\"), 3);\n\t\t\t\t\t}, 0.2f);\n\n\t\t\t\t\tvar inv = c.To.GetComponent<InventoryComponent>();\n\t\t\t\t\tvar a = c.To.Area;\n\t\t\t\n\t\t\t\t\tinv.Pickup(Items.CreateAndAdd(\"bk:emerald_gun\", a));\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tinv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a));\n\t\t\t\t\t}, 1f);\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\t\t\t\tDone = true;\n\t\t\t\t\t\t\tEngine.Instance.Flash = 1f;\n\t\t\t\t\t\t\tCamera.Instance.Shake(8);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tpart.Position = Center + Rnd.Vector(-16, 16);\n\t\t\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 2f);\n\t\t\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}, 4f);\n\n\t\t\t\t\tbroken = true;\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\t\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce && rce.Who is Player) {\n\t\t\t\tif (rce.New == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"eg_3\", 3);\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tGetComponent<DialogComponent>().Start(\"eg_0\", e);\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tbroken = stream.ReadBoolean();\n\t\t\t// todo: update the sprite\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(broken);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Granny.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.rooms;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Granny : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 15;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"grandma\"));\n\n\t\t\tvar b = new RectBodyComponent(2, 6, Width - 4, Height - 6);\n\t\t\tAddComponent(b);\n\t\t\tb.KnockbackModifier = 0;\n\t\t\t\n\t\t\tSubscribe<Dialog.EndedEvent>();\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\tSubscribe<ItemTakenEvent>();\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 19;\n\t\t}\n\n\t\tprivate float delay;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tdelay -= dt;\n\n\t\t\tif (delay <= 0) {\n\t\t\t\tdelay = Rnd.Float(1, 4);\n\t\t\t\tGraphicsComponent.Flipped = !GraphicsComponent.Flipped;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\t\t\t\t\n\t\t\t\tif (rce.Who is Player && rce.New == room) {\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"hi\");\n\t\t\t\t\t\n\t\t\t\t\t// Welcome, gobbo!\n\t\t\t\t\tGetComponent<DialogComponent>().Dialog.Str.SetVariable(\"id\", MathUtils.ToRoman((int) GlobalSave.RunId));\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(room.Type == RoomType.Granny ? \"granny_4\" : GetDialog(), 3);\n\t\t\t\t\t\n\t\t\t\t\tif (rce.New.Type != RoomType.Granny) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:tea_party\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is Dialog.EndedEvent dee) {\n\t\t\t\tif (dee.Dialog.Id == \"bk_9\") {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t// You will die first, Limpor!\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"granny_3\", 5);\n\t\t\t\t\t}, 1f);\n\t\t\t\t}\n\t\t\t} else if (e is ItemTakenEvent ite) {\n\t\t\t\tif (ite.Stand is GrannyStand) {\n\t\t\t\t\t// Good luck on your sad quest!\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"granny_5\", 10);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate string GetDialog() {\n\t\t\treturn $\"granny_{Rnd.Int(3)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/HatTrader.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.ui.dialog;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.entity.creature.npc {\r\n\tpublic class HatTrader : ShopNpc {\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tWidth = 13;\r\n\t\t\tHeight = 20;\r\n\t\t\t\r\n\t\t\tAddComponent(new AnimationComponent(\"hat_trader\"));\r\n\r\n\t\t\tvar b = new RectBodyComponent(2, 6, Width - 4, Height - 6);\r\n\t\t\tAddComponent(b);\r\n\t\t\tb.KnockbackModifier = 0;\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 6;\r\n\t\t}\r\n\r\n\t\tprotected override string GetDialog() {\r\n\t\t\treturn $\"hattrader_{Rnd.Int(3)}\";\r\n\t\t}\r\n\r\n\t\tpublic override string GetId() {\r\n\t\t\treturn HatTrader;\r\n\t\t}\r\n\r\n\t\tprotected override bool OwnsStand(ItemStand stand) {\r\n\t\t\treturn stand is HatStand;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Isaac.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Isaac : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 12;\n\t\t\tHeight = 11;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"isaac\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"isaac_0\", \"isaac_1\", \"isaac_2\"));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/MaPuzzle.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class MaPuzzle : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 10;\n\t\t\tHeight = 8;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"mapuzzle\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"mapuzzle_0\"));\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 17;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Maanex.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Maanex : Npc {\n\t\tprivate bool interacted;\n\t\tprivate bool played;\n\t\tprivate byte cost;\n\t\tprivate float t;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 12;\n\t\t\tHeight = 15;\n\n\t\t\tvar min = Run.Depth * 2;\n\t\t\tcost = (byte) Rnd.Int(min, min + 5);\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"maanex\"));\n\t\t\tGetComponent<DropsComponent>().Add(new SingleDrop(\"bk:maanex_head\"));\n\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tAddComponent(new CloseDialogComponent(\"maanex_0\", \"maanex_1\", \"maanex_2\", \"maanex_3\", \"maanex_4\"));\n\t\t\t} else {\n\t\t\t\tif (!interacted) {\n\t\t\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\t\t\tCanInteract = e => !interacted\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tAddComponent(new SensorBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tDialogs.RegisterCallback(\"maanex_6\", (d, c) => {\n\t\t\t\tif (((ChoiceDialog) d).Choice == 0) {\n\t\t\t\t\tif (!c.To.TryGetComponent<ConsumablesComponent>(out var component) || component.Coins < cost) {\n\t\t\t\t\t\treturn Dialogs.Get(\"maanex_11\");\n\t\t\t\t\t}\n\n\t\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room == null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\tcomponent.Coins -= cost;\n\t\t\t\t\tinteracted = true;\n\n\t\t\t\t\tforeach (var chest in room.Tagged[Tags.Chest]) {\n\t\t\t\t\t\t((Chest) chest).CanOpen = true;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Dialogs.Get(\"maanex_8\");\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\t\n\t\t\tSubscribe<Chest.OpenedEvent>();\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\th.Unhittable = false;\n\t\t\th.InitMaxHealth = 50;\n\t\t\th.SetHealth(50, this);\n\t\t}\n\n\t\tprivate string GetDialog(Entity e) {\n\t\t\tvar hat = e.GetComponent<HatComponent>().Item;\n\n\t\t\tif (hat != null && hat.Id == \"bk:maanex_head\") {\n\t\t\t\treturn \"maanex_12\";\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(0.01f)) {\n\t\t\t\treturn \"spanish_inquisition\";\n\t\t\t}\n\n\t\t\treturn $\"maanex_{(played ? 7 : 5)}\";\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is Chest.OpenedEvent coe) {\n\t\t\t\tif (coe.Chest.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tif (coe.Chest.Empty) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"maanex_9\", 5f);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"maanex_10\", 5f);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tplayed = true;\n\t\t\t\t\tforeach (var chest in GetComponent<RoomComponent>().Room.Tagged[Tags.Chest]) {\n\t\t\t\t\t\tvar c = (Chest) chest;\n\n\t\t\t\t\t\tif (c.Scale > 0.9f) {\n\t\t\t\t\t\t\tc.CanOpen = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is RoomChangedEvent rce) {\n\t\t\t\tif (rce.Who is Player) {\n\t\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\t\t\t\t\t\n\t\t\t\t\tif (rce.New == r) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().Start(GetDialog(rce.Who));\n\t\t\t\t\t} else if (rce.Old == r) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent de) {\n\t\t\t\tItems.Unlock(\"bk:maanex_head\");\n\t\t\t\tExplosionMaker.Make(this);\n\n\t\t\t\tif (de.From is Player p && p.GetComponent<HatComponent>().Item?.Id == \"bk:maanex_head\") {\n\t\t\t\t\tAchievements.Unlock(\"bk:maanex\");\n\t\t\t\t}\n\t\t\t} else if (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(Bruh[Rnd.Int(Bruh.Length)], 2);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic static string[] Bruh = {\n\t\t\t\"bruh\", \"bruuh\", \"BRUH\"\n\t\t};\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t\t\n\t\t\tif ((!interacted || played) && t >= 0.1f) {\n\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tforeach (var chest in r.Tagged[Tags.Chest]) {\n\t\t\t\t\t((Chest) chest).CanOpen = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool Interact(Entity e) {\n\t\t\tvar d = GetComponent<DialogComponent>();\n\t\t\t\n\t\t\td.Dialog.Str.SetVariable(\"cost\", cost);\n\t\t\td.Start(\"maanex_6\", e);\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tinteracted = stream.ReadBoolean();\n\t\t\tcost = stream.ReadByte();\n\t\t\tplayed = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteBoolean(interacted);\n\t\t\tstream.WriteByte(cost);\n\t\t\tstream.WriteBoolean(played);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Maanex2.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Maanex2 : Npc {\n\t\tprivate const int Cost = 8;\n\t\tinternal ClawControll clawControll;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 12;\n\t\t\tHeight = 15;\n\n\t\t\tAddComponent(new AnimationComponent(\"maanex\"));\n\t\t\tGetComponent<DropsComponent>().Add(new SingleDrop(\"bk:maanex_head\"));\n\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => !clawControll.Payed\n\t\t\t});\n\t\t\tAddComponent(new SensorBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2));\n\t\t\t\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\t\n\t\t\tDialogs.RegisterCallback(\"maanex2_0\", (d, c) => {\n\t\t\t\tif (((ChoiceDialog) d).Choice == 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!c.To.TryGetComponent<ConsumablesComponent>(out var component) || component.Coins < Cost) {\n\t\t\t\t\t\t\treturn Dialogs.Get(\"maanex_11\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcomponent.Coins -= Cost;\n\t\t\t\t\t\tclawControll.Payed = true;\n\n\t\t\t\t\t\tTimer.Add(() => { GetComponent<DialogComponent>().StartAndClose(Locale.Get(\"m2_3\"), 1); }, 0.2f);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(e.Message, 10);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\th.Unhittable = false;\n\t\t\th.InitMaxHealth = 50;\n\t\t\th.SetHealth(50, this);\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tvar d = GetComponent<DialogComponent>();\n\t\t\t\n\t\t\td.Dialog.Str.SetVariable(\"cost\", Cost);\n\t\t\td.Start(\"maanex2_0\", e);\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tif (rce.Who is Player) {\n\t\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\t\t\t\t\t\n\t\t\t\t\tif (rce.New == r) {\n\t\t\t\t\t\t// Wanna try out your skill?\n\t\t\t\t\t\tGetComponent<DialogComponent>().Start(\"m2_2\");\n\t\t\t\t\t} else if (rce.Old == r) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent de) {\n\t\t\t\tItems.Unlock(\"bk:maanex_head\");\n\t\t\t\tExplosionMaker.Make(this);\n\n\t\t\t\tif (de.From is Player p && p.GetComponent<HatComponent>().Item?.Id == \"bk:maanex_head\") {\n\t\t\t\t\tAchievements.Unlock(\"bk:maanex\");\n\t\t\t\t}\n\t\t\t} else if (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(Maanex.Bruh[Rnd.Int(Maanex.Bruh.Length)], 2);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Mike.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.save;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Mike : ShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 11;\n\t\t\tHeight = 13;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"mike\"));\n\t\t\t// GetComponent<DialogComponent>().Dialog.Voice = 15;\n\t\t}\n\n\t\tprotected override string GetDialog() {\n\t\t\treturn \"mike_1\";\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn Mike;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Milt.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Milt : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 10;\n\t\t\tHeight = 8;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"milt\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"milt_1\"));\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 21;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Npc.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.tween;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class Npc : Creature {\n\t\tpublic const int Padding = 4;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new DialogComponent());\n\t\t\tGetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\n\t\t\tAddTag(Tags.Npc);\n\t\t}\n\n\t\tprivate bool rotationApplied;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tif (!rotationApplied) {\n\t\t\t\t\trotationApplied = true;\n\t\t\t\t\tvar a = GetAnyComponent<AnimationComponent>();\n\t\t\t\t\n\t\t\t\t\tif (a != null) {\n\t\t\t\t\t\tvar w = a.Angle;\n\t\t\t\t\t\ta.Angle += 0.5f;\n\n\t\t\t\t\t\tvar t = Tween.To(w, a.Angle, x => a.Angle = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tt.Delay = 0.2f;\n\t\t\t\t\t\tt.OnEnd = () => {\n\t\t\t\t\t\t\trotationApplied = false;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tpublic override void AnimateDeath(DiedEvent d) {\n\t\t\tbase.AnimateDeath(d);\n\t\t\tCreateGore(d);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/NullPtr.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class NullPtr : Npc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 10;\n\t\t\tHeight = 8;\n\n\t\t\tAddComponent(new AnimationComponent(\"nullptr\"));\n\t\t\tAddComponent(new CloseDialogComponent(\"nullptr_0\"));\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 18;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/OldMan.cs",
    "content": "using System.Linq;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.biome;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class OldMan : Npc {\n\t\tpublic bool RickRoll;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 20;\n\t\t\tHeight = 18;\n\n\t\t\tAddComponent(new AnimationComponent(\"old_man\"));\n\t\t\tAddComponent(new RectBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2));\n\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tAddComponent(new CloseDialogComponent(\"old_man_0\"));\n\t\t\t\t\n\t\t\t\t// AddComponent(new InteractDialogComponent(\"old_man_1\"));\n\t\t\t} else if (Run.Depth == Run.ContentEndDepth) {\n\t\t\t\tGetComponent<DialogComponent>().Start(\"old_man_4\");\n\t\t\t\t// cycle = !BK.Version.Dev;;\n\t\t\t} else if (Run.Depth == -2) {\n\t\t\t\tset = false;\n\t\t\t\tAddComponent(new CloseDialogComponent(\"control_1\") {\n\t\t\t\t\t\tRadius = 64 * 64,\n\t\t\t\t\t\tRadiusMax = 72 * 72\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tSubscribe<ItemTakenEvent>();\n\t\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\t\t\n\t\t\t\tinSecret = true;\n\t\t\t}\n\n\t\t\tAlwaysActive = true;\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 28;\n\t\t}\n\n\t\tprivate string[] song = {\n\t\t\t\"Never gonna give you up\",\n\t\t\t\"Never gonna let you down\",\n\t\t\t\"Never gonna run around and desert you\",\n\t\t\t\"Never gonna make you cry\",\n\t\t\t\"Never gonna say goodbye\",\n\t\t\t\"Never gonna tell a lie and hurt you\"\n\t\t};\n\n\t\tprivate int index;\n\n\t\tprivate void StartSong() {\n\t\t\tif (index >= song.Length) {\n\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Start(song[index], null, () => {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tStartSong();\n\t\t\t\t}, 2);\n\n\t\t\t\tif (RickRoll) {\n\t\t\t\t\tforeach (var item in GetComponent<RoomComponent>().Room.Tagged[Tags.Item]) {\n\t\t\t\t\t\titem.Done = true;\n\t\t\t\t\t\tAnimationUtil.Poof(item.Center);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tindex++;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (inSecret) {\n\t\t\t\tif (e is RoomChangedEvent rce && rce.Who is Player) {\n\t\t\t\t\tif (rce.New == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\t\tif (RickRoll) {\n\t\t\t\t\t\t\tStartSong();\n\t\t\t\t\t\t\tindex = 0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tGetComponent<DialogComponent>().Start(\"old_man_6\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t\t}\n\t\t\t\t} else if (e is ItemTakenEvent ite && ite.Stand.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\t\t\tDone = true;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool inSecret;\n\t\tprivate bool set = true;\n\t\tprivate bool cycle;\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (cycle) {\n\t\t\t\tt += dt;\n\n\t\t\t\tif (t >= 1f) {\n\t\t\t\t\tt = 0;\n\n\t\t\t\t\tvar all = BiomeRegistry.Defined.Values.ToArray();\n\t\t\t\t\tRun.Level.SetBiome(all[Rnd.Int(all.Length)]);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!set) {\n\t\t\t\tset = true;\n\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\t\t\t\t\t\t\t\t\n\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Roll, false)));\n\n\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\n\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Roll, true)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tRickRoll = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(RickRoll);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/Ord.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.ui.dialog;\r\n\r\nnamespace BurningKnight.entity.creature.npc {\r\n\tpublic class Ord : Npc {\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tWidth = 16;\r\n\t\t\tHeight = 20;\r\n\r\n\t\t\tvar anim = new AnimationComponent(\"ord\");\r\n\t\t\tAddComponent(anim);\r\n\r\n\t\t\tanim.Animation.AutoStop = true;\r\n\t\t\tanim.Animation.OnEnd += OnAnimationEnd;\r\n\r\n\t\t\tAddComponent(new RectBodyComponent(-4, -4, Width + 8, Height + 8));\r\n\t\t\t\r\n\t\t\tAddComponent(new InteractableComponent(e => {\r\n\t\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"turnon\";\r\n\t\t\t\treturn true;\r\n\t\t\t}));\r\n\t\t}\r\n\r\n\t\tprivate void OnAnimationEnd() {\r\n\t\t\tvar anim = GetComponent<AnimationComponent>().Animation;\r\n\r\n\t\t\tif (anim.Tag == \"turnon\") {\r\n\t\t\t\tanim.Tag = \"choice\";\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/ShopKeeper.cs",
    "content": "using System;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.entity.buff;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.drop;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.level.entities.machine;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.dialog;\r\nusing Lens;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\r\n\r\nnamespace BurningKnight.entity.creature.npc {\r\n\tpublic class ShopKeeper : Npc {\r\n\t\tprivate sbyte _mood = 3;\r\n\t\tprivate Item shotgun;\r\n\r\n\t\tpublic sbyte Mood {\r\n\t\t\tget => _mood;\r\n\r\n\t\t\tset {\r\n\t\t\t\tif (_mood == value || (TryGetComponent<RoomComponent>(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar r = raging;\r\n\t\t\t\t\r\n\t\t\t\tif (_mood < 0 && value > 0) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar old = _mood;\r\n\t\t\t\t_mood = value;\r\n\r\n\t\t\t\tif (_mood < old && _mood < 3 && _mood > -1) {\r\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{_mood}\", 1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (raging) {\r\n\t\t\t\t\tGameSave.Put(\"sk_enraged\", true);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!r && raging) {\r\n\t\t\t\t\tAddTag(Tags.Mob);\r\n\t\t\t\t\tAddTag(Tags.MustBeKilled);\r\n\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tvar rm = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\t\t\t// Hacky solution tbh\r\n\t\t\t\t\t\trm.Tagged[Tags.Mob].Add(this);\r\n\t\t\t\t\t\trm.Tagged[Tags.MustBeKilled].Add(this);\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tBecome<RunState>();\r\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{Rnd.Int(3, 5)}\", 1);\r\n\r\n\t\t\t\t\tSetItemsFree();\r\n\r\n\t\t\t\t\tHandleEvent(new EnragedEvent {\r\n\t\t\t\t\t\tShopKeeper = this\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t\tRecalc();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate bool raging => Mood < 0;\r\n\t\t\r\n\t\tprivate void Recalc() {\r\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (r == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tforeach (var s in r.Tagged[Tags.Item]) {\r\n\t\t\t\tif (s is ShopStand ss) {\r\n\t\t\t\t\tss.Recalculate();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\tAlwaysActive = true;\r\n\r\n\t\t\tAddComponent(new QuackInteractionComponent(p => {\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\tvar d = GetComponent<DialogComponent>();\r\n\r\n\t\t\t\t\tif (d.Current != null && d.Current.Id != \"quack\") {\r\n\t\t\t\t\t\td.StartAndClose(\"quack\", 3);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"quck\");\r\n\t\t\t\t}, 0.5f);\r\n\t\t\t}));\r\n\t\t\t\r\n\t\t\tAddComponent(new AimComponent(AimComponent.AimType.AnyPlayer));\r\n\t\t\tAddComponent(new AnimationComponent(\"shopkeeper\"));\r\n\r\n\t\t\tAddDrops(new SingleDrop(\"bk:shotgun\", 1f));\r\n\t\t\t\r\n\t\t\tvar h = GetComponent<HealthComponent>();\r\n\r\n\t\t\th.InitMaxHealth = 10 + Run.Depth * 10;\r\n\t\t\th.Unhittable = false;\r\n\r\n\t\t\tvar b = new RectBodyComponent(4, 2, 10, 14);\r\n\t\t\tAddComponent(b);\r\n\t\t\tb.Body.LinearDamping = 5;\r\n\t\t\t\r\n\t\t\tSubscribe<BombPlacedEvent>();\r\n\t\t\tSubscribe<GramophoneBrokenEvent>();\r\n\t\t\tSubscribe<RerollMachine.BrokenEvent>();\r\n\t\t\tSubscribe<VendingMachine.BrokenEvent>();\r\n\t\t\tSubscribe<RoomChangedEvent>();\r\n\t\t\tSubscribe<ItemBoughtEvent>();\r\n\t\t\t\r\n\t\t\tAddTag(Tags.ShopKeeper);\r\n\t\t\t\r\n\t\t\tBecome<IdleState>();\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 3;\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\tMood = stream.ReadSbyte();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\tstream.WriteSbyte(Mood);\r\n\t\t}\r\n\r\n\t\tpublic void Enrage() {\r\n\t\t\tif (raging) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tMood = -1;\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is BombPlacedEvent bpe) {\r\n\t\t\t\tif (bpe.Bomb.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tEnrage();\r\n\t\t\t\t}\r\n\t\t\t} else if (e is GramophoneBrokenEvent gbe) {\r\n\t\t\t\tif (gbe.Gramophone.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tMood--;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is RerollMachine.BrokenEvent rme) {\r\n\t\t\t\tif (rme.Machine.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tMood--;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is VendingMachine.BrokenEvent vme) {\r\n\t\t\t\tif (vme.Machine.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tMood--;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is HealthModifiedEvent hme && hme.Amount < 0) {\r\n\t\t\t\tif (hme.Amount < 0 && Mood > -2) {\r\n\t\t\t\t\tMood = (sbyte) Math.Min(2, Mood - 1);\r\n\t\t\t\t\thme.Amount = -1;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is RoomChangedEvent rce) {\r\n\t\t\t\tif (rce.Who is Player && rce.New == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tif (GameSave.IsTrue(\"sk_enraged\")) {\r\n\t\t\t\t\t\tEnrage();\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tRecalc();\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (Mood > -1) {\r\n\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"hi\");\r\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{Rnd.Int(6, 9)}\", 3);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (e is ItemBoughtEvent ibe) {\r\n\t\t\t\tif (ibe.Stand.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\tMood++;\r\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{Rnd.Int(9, 12)}\", 3);\r\n\t\t\t\t}\r\n\t\t\t} else if (e is DiedEvent) {\r\n\t\t\t\tAchievements.Unlock(\"bk:marauder\");\r\n\r\n\t\t\t\tfor (var i = 0; i < 3; i++) {\r\n\t\t\t\t\tRun.AddScourge(true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tprivate void SetItemsFree() {\r\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (r != null) {\r\n\t\t\t\tforeach (var s in r.Tagged[Tags.Item]) {\r\n\t\t\t\t\tif (s is ShopStand ss) {\r\n\t\t\t\t\t\tss.Free = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected override bool HandleDeath(DiedEvent d) {\r\n\t\t\tItems.Unlock(\"bk:shotgun\");\r\n\t\t\tSetItemsFree();\r\n\t\t\t\r\n\t\t\treturn base.HandleDeath(d);\r\n\t\t}\r\n\r\n\t\tprotected override string GetDeadSfx() {\r\n\t\t\treturn \"villager6\";\r\n\t\t}\r\n\r\n\t\tprotected override string GetHurtSfx() {\r\n\t\t\treturn \"villager5\";\r\n\t\t}\r\n\r\n\t\tpublic override bool IsFriendly() {\r\n\t\t\treturn !raging || GetComponent<BuffsComponent>().Has<CharmedBuff>();\r\n\t\t}\r\n\t\t\r\n\t\tprivate float delay;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!raging) {\r\n\t\t\t\tdelay -= dt;\r\n\r\n\t\t\t\tif (delay <= 0) {\r\n\t\t\t\t\tdelay = Rnd.Float(3, 9f);\r\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized($\"villager{Rnd.Int(1, 5)}\", 0.5f);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tshotgun?.Update(dt);\r\n\t\t}\r\n\r\n\t\t#region Shopkeeper States\r\n\t\t/*\r\n\t\t * Peacefull\r\n\t\t */\r\n\t\tprivate class IdleState : SmartState<ShopKeeper> {\r\n\t\t\tprivate float actionDelay;\r\n\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\tactionDelay = Rnd.Float(2, 6);\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (Self.GetComponent<DialogComponent>().Dialog.Saying) {\r\n\t\t\t\t\tT = 0;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (T >= actionDelay) {\r\n\t\t\t\t\tSelf.Become<MoveToState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate class MoveToState : SmartState<ShopKeeper> {\r\n\t\t\tprivate Vector2 target;\r\n\t\t\tprivate bool toPlayer;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\t\r\n\t\t\t\tSelf.GetComponent<AnimationComponent>().Animation.Tag = \"run\";\r\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\ttoPlayer = r.Tagged[Tags.Player].Count > 0 && Rnd.Chance(40);\r\n\r\n\t\t\t\tif (toPlayer) {\r\n\t\t\t\t\tif (Self.DistanceTo(r.Tagged[Tags.Player][0]) < 64f) {\r\n\t\t\t\t\t\ttoPlayer = false;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar p = r.GetRandomFreeTile();\r\n\t\t\t\ttarget = new Vector2(p.X * 16, p.Y * 16);\r\n\t\t\t}\r\n\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tvar t = target;\r\n\r\n\t\t\t\tif (toPlayer) {\r\n\t\t\t\t\tvar a = Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Player];\r\n\r\n\t\t\t\t\tif (a.Count > 0) {\r\n\t\t\t\t\t\ttarget = a[0].Center;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar dx = Self.DxTo(t);\r\n\t\t\t\tvar dy = Self.DyTo(t);\r\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\r\n\t\t\t\tvar s = dt * 300;\r\n\r\n\t\t\t\tvar b = Self.GetComponent<RectBodyComponent>();\r\n\t\t\t\tb.Velocity += new Vector2(dx / d * s, dy / d * s);\r\n\r\n\t\t\t\tif (d <= 24 || T >= 4f) {\r\n\t\t\t\t\tif ((toPlayer && Rnd.Chance(80)) || Rnd.Chance(30)) {\r\n\t\t\t\t\t\tif (Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Player].Count > 0) {\r\n\t\t\t\t\t\t\tSelf.GetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{(Rnd.Chance(30) ? 18 : Rnd.Int(12, 15))}\", 3);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tSelf.Become<IdleState>();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tbase.Render();\r\n\t\t\tshotgun?.Renderer.Render(false, Engine.Instance.State.Paused, Engine.Delta, false, 0);\r\n\t\t}\r\n\r\n\t\tprotected override void RenderShadow() {\r\n\t\t\tbase.RenderShadow();\r\n\t\t\tshotgun?.Renderer.Render(false, Engine.Instance.State.Paused, Engine.Delta, true, 0);\r\n\t\t}\r\n\r\n\t\t/*\r\n\t\t * Raging\r\n\t\t */\r\n\t\tprivate class RunState : SmartState<ShopKeeper> {\r\n\t\t\tprivate Vector2 target;\r\n\t\t\tprivate float delay;\r\n\t\t\tprivate bool set;\r\n\t\t\t\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\r\n\t\t\t\tdelay = Rnd.Float(0.2f, 0.8f);\r\n\t\t\t\t\r\n\t\t\t\tSelf.GetComponent<AnimationComponent>().Animation.Tag = \"run\";\r\n\t\t\t\tvar r = Self.GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\tif (r != null) {\r\n\t\t\t\t\tset = true;\r\n\t\t\t\t\tvar p = r.GetRandomFreeTile();\r\n\t\t\t\t\ttarget = new Vector2(p.X * 16, p.Y * 16);\r\n\r\n\t\t\t\t\tif (Self.shotgun == null) {\r\n\t\t\t\t\t\tSelf.shotgun = Items.CreateAndAdd(\"bk:shotgun\", Self.Area);\r\n\t\t\t\t\t\tSelf.shotgun.RemoveDroppedComponents();\r\n\t\t\t\t\t\tSelf.shotgun.AddComponent(new OwnerComponent(Self));\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\r\n\t\t\t\tif (!set) {\r\n\t\t\t\t\tInit();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (Self.shotgun != null && Self.GetComponent<RoomComponent>().Room.Tagged[Tags.Player].Count > 0) {\r\n\t\t\t\t\tSelf.shotgun.Use(Self);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar dx = Self.DxTo(target);\r\n\t\t\t\tvar dy = Self.DyTo(target);\r\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\r\n\t\t\t\tvar s = Math.Min(T * 3, 1f) * dt * 36000;\r\n\r\n\t\t\t\tvar b = Self.GetComponent<RectBodyComponent>();\r\n\t\t\t\tb.Velocity = new Vector2(dx / d * s, dy / d * s);\r\n\r\n\t\t\t\tif (d <= 8 || T >= delay) {\r\n\t\t\t\t\tT = 0;\r\n\t\t\t\t\tInit();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t#endregion\r\n\r\n\t\tpublic override bool ShouldCollide(Entity entity) {\r\n\t\t\treturn !(entity is ItemStand) && base.ShouldCollide(entity);\r\n\t\t}\r\n\r\n\t\tpublic class EnragedEvent : Event {\r\n\t\t\tpublic ShopKeeper ShopKeeper;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/ShopNpc.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class ShopNpc : Npc {\n\t\tpublic const string AccessoryTrader = \"accessory_trader\";\n\t\tpublic const string ActiveTrader = \"active_trader\";\n\t\tpublic const string WeaponTrader = \"weapon_trader\";\n\t\tpublic const string HatTrader = \"hat_trader\";\n\t\tpublic const string Mike = \"mike\";\n\t\t\n\t\tpublic const string Snek = \"snek\";\n\t\tpublic const string Boxy = \"boxy\";\n\t\tpublic const string Roger = \"roger\";\n\t\tpublic const string Gobetta = \"gobetta\";\n\t\tpublic const string Vampire = \"vampire\";\n\t\tpublic const string TrashGoblin = \"trash_goblin\";\n\t\tpublic const string Duck = \"duck\";\n\t\tpublic const string Nurse = \"nurse\";\n\t\tpublic const string Elon = \"elon\";\n\n\t\tpublic static string[] AllNpc = {\n\t\t\tAccessoryTrader, ActiveTrader, WeaponTrader, HatTrader, Mike, Snek,\n\t\t\tBoxy, Roger, Gobetta, Vampire, TrashGoblin, Duck, Nurse, Elon\n\t\t};\n\t\n\t\tprivate float delay;\n\t\tinternal bool Hidden;\n\t\tprivate bool saved;\n\t\tprivate bool hided;\n\t\t\n\t\tprotected bool Remove;\n\t\tprotected bool Flips = true;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t\tSubscribe<ItemBoughtEvent>();\n\n\t\t\tvar id = GetId();\n\n\t\t\tsaved = id == TrashGoblin || GlobalSave.IsTrue(id);\n\t\t\tAlwaysActive = true;\n\t\t\tHidden = Run.Depth == 0 && !saved;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\t\th.Unhittable = false;\n\t\t\t\th.InitMaxHealth = 50;\n\t\t\t\th.SetHealth(50, this);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tAddComponent(new CloseDialogComponent(GetDialog()) {\n\t\t\t\t\tDecideVariant = e => GetDialog(),\n\t\t\t\t\tRadius = 72 * 72,\n\t\t\t\t\tRadiusMax = 96 * 96\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tAddComponent(new QuackInteractionComponent(p => {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar d = GetComponent<DialogComponent>();\n\n\t\t\t\t\t\tif (d.Current != null && d.Current.Id != \"quack\") {\n\t\t\t\t\t\t\td.StartAndClose(\"quack\", 3);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"quck\");\n\t\t\t\t\t}, 0.5f);\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tif (Hidden) {\n\t\t\t\tif (!hided) {\n\t\t\t\t\thided = true;\n\n\t\t\t\t\tforeach (var item in Area.Tagged[Tags.Item]) {\n\t\t\t\t\t\tif (item is ItemStand stand && OwnsStand(stand)) {\n\t\t\t\t\t\t\tstand.Done = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (saved && Remove && !OnScreen) {\n\t\t\t\tDone = true;\n\t\t\t\tHidden = true;\n\n\t\t\t\tvar stand = new ItemStand();\n\t\t\t\tArea.Add(stand);\n\t\t\t\tstand.Center = Center;\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(\"bk:emerald\", Area), null);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!Flips) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tdelay -= dt;\n\n\t\t\tif (delay <= 0) {\n\t\t\t\tdelay = Rnd.Float(1, 10);\n\t\t\t\tGraphicsComponent.Flipped = !GraphicsComponent.Flipped;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Render();\n\t\t}\n\n\t\tprotected override void RenderShadow() {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\tbase.RenderShadow();\n\t\t}\n\n\t\tprotected virtual bool OwnsStand(ItemStand stand) {\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected virtual string GetHiDialog() {\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (Hidden || Done) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tif (rce.Who is Player && rce.New == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tif (Run.Depth > 0 && !saved) {\n\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"hi\");\n\n\t\t\t\t\t\tif ((rce.Who.TryGetComponent<ActiveWeaponComponent>(out var a) && a.Item != null && a.Item.Id == \"bk:cage_key\") ||\n\t\t\t\t\t\t    (rce.Who.TryGetComponent<WeaponComponent>(out var w) && w.Item != null && w.Item.Id == \"bk:cage_key\")) {\n\n\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"npc_2\", 3);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"npc_0\", 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar s = GetHiDialog();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (s != null) {\n\t\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(s, 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is ItemBoughtEvent ibe) {\n\t\t\t\tif (OwnsStand(ibe.Stand) && ibe.Stand.GetComponent<RoomComponent>().Room == GetComponent<RoomComponent>().Room) {\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(GetDealDialog(), 3);\n\t\t\t\t\tOnItemBought(ibe);\n\t\t\t\t}\n\t\t\t} else if (e is DiedEvent) {\n\t\t\t\tGlobalSave.Put(GetId(), false);\n\t\t\t\tExplosionMaker.Make(this);\n\t\t\t} else if (e is HealthModifiedEvent hme && hme.Amount < 0) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"npc_hurt_{Rnd.Int(3)}\", 2);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected virtual void OnItemBought(ItemBoughtEvent ibe) {\n\t\t\t\n\t\t}\n\n\t\tprotected virtual string GetDealDialog() {\n\t\t\treturn $\"shopkeeper_{Rnd.Int(9, 12)}\";\n\t\t}\n\n\t\tpublic void Save() {\n\t\t\tif (Run.Depth > 0 && !saved) {\n\t\t\t\tsaved = true;\n\t\t\t\tRemove = true;\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"npc_1\", 6);\n\t\t\t\t\n\t\t\t\tGlobalSave.Put(GetId(), true);\n\t\t\t\tGlobalSave.Put(\"saved_npc\", true);\n\t\t\t\t\n\t\t\t\tRemoveComponent<InteractableComponent>();\n\n\t\t\t\tHandleEvent(new SavedEvent {\n\t\t\t\t\tNpc = this\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tAchievements.Unlock(\"bk:rescue_operation\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected virtual string GetDialog() {\n\t\t\treturn $\"shopkeeper_{Rnd.Int(6, 9)}\";\n\t\t}\n\n\t\tpublic virtual string GetFailDialog() {\n\t\t\treturn $\"shopkeeper_{Rnd.Int(15, 18)}\";\n\t\t}\n\t\t\n\t\tpublic virtual string GetId() {\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic class SavedEvent : Event {\n\t\t\tpublic ShopNpc Npc;\n\t\t}\n\t\t\n\t\tpublic static ShopNpc FromId(string id) {\n\t\t\tswitch (id) {\n\t\t\t\tcase HatTrader: return new HatTrader();\n\t\t\t\tcase WeaponTrader: return new WeaponTrader();\n\t\t\t\tcase ActiveTrader: return new ActiveTrader();\n\t\t\t\tcase AccessoryTrader: return new AccessoryTrader();\n\t\t\t\tcase Mike: return new Mike();\n\t\t\t\tcase Snek: return new Snek();\n\t\t\t\tcase Boxy: return new Boxy();\n\t\t\t\tcase Vampire: return new Vampire();\n\t\t\t\tcase Roger: return new Roger();\n\t\t\t\tcase TrashGoblin: return new TrashGoblin();\n\t\t\t\tcase Duck: return new DungeonDuck();\n\t\t\t\tcase Nurse: return new Nurse();\n\t\t\t\tcase Elon: return new DungeonElon();\n\t\t\t\tcase Gobetta: return new Gobetta();\n\t\t\t}\n\n\t\t\tLog.Error($\"Unknown npc id {id}!\");\n\t\t\treturn new Boxy();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/WeaponTrader.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.npc {\n\tpublic class WeaponTrader : ShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 19;\n\t\t\tHeight = 20;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"weapon_trader\"));\n\n\t\t\tvar b = new RectBodyComponent(2, 6, Width - 4, Height - 6);\n\t\t\tAddComponent(b);\n\t\t\tb.KnockbackModifier = 0;\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 7;\n\t\t}\n\n\t\tprotected override string GetDialog() {\n\t\t\treturn $\"weapontrader_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn WeaponTrader;\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is WeaponStand;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Boxy.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Boxy : DungeonShopNpc {\n\t\tprivate bool open;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 15;\n\t\t\tHeight = 18;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"boxy\"));\n\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"idle\";\n\n\t\t\tGetComponent<DropsComponent>().Add(\"bk:boxy\");\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 9, 15, 9, BodyType.Static));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (open) {\n\t\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"open\";\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnItemBought(ItemBoughtEvent ibe) {\n\t\t\tif (open) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var s in GetComponent<RoomComponent>().Room.Tagged[Tags.Item]) {\n\t\t\t\tif (s is BoxyStand st && st != ibe.Stand && st.Item != null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar d = GetComponent<DialogComponent>();\n\t\t\t\n\t\t\td.StartAndClose(\"boxy_9\", 3);\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\n\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\n\t\t\t\topen = true;\n\t\t\t\tvar a = GetComponent<AnimationComponent>();\n\t\t\t\ta.Animation.Tag = \"open\";\n\t\t\t\ta.Animate();\n\t\t\t\t\n\t\t\t\tAchievements.Unlock(\"bk:open_up\");\n\t\t\t}, 4f);\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Boxy;\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is BoxyStand;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\twhere.Y -= 16;\n\t\t\t\n\t\t\tvar snek = new Boxy();\n\t\t\tarea.Add(snek);\n\t\t\tsnek.BottomCenter = where;\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Boxy));\n\n\t\t\tfor (var i = -1; i < 2; i++) {\n\t\t\t\tvar stand = new BoxyStand();\n\t\t\t\tarea.Add(stand);\n\t\t\t\tstand.Center = where + new Vector2((stand.Width + 4) * i, 4 + stand.Height);\n\n\t\t\t\tvar id = Items.GenerateAndRemove(pool, null, true);\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(id, area, false), null);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override string GetDealDialog() {\n\t\t\treturn $\"boxy_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tprotected override string GetHiDialog() {\n\t\t\treturn $\"boxy_{Rnd.Int(3, 6)}\";\n\t\t}\n\t\t\n\t\tpublic override string GetFailDialog() {\n\t\t\treturn $\"boxy_{Rnd.Int(7, 9)}\";\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\topen = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(open);\n\t\t}\n\t\t\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Creature || base.ShouldCollide(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/DungeonDuck.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class DungeonDuck : DungeonShopNpc {\n\t\tprivate bool interacted;\n\t\tprivate Chest chest;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 12;\n\t\t\tHeight = 10;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"duck\"));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 4;\n\t\t\t\n\t\t\tif (!interacted) {\n\t\t\t\tAddComponent(new InteractableComponent((e) => {\n\t\t\t\t\tGetComponent<DialogComponent>().Start(\"duck_2\", e);\n\t\t\t\t\treturn true;\n\t\t\t\t}));\n\n\t\t\t\tDialogs.RegisterCallback(\"duck_4\", (d, c) => {\n\t\t\t\t\tinteracted = true;\n\t\t\t\t\t\n\t\t\t\t\tif (chest != null) {\n\t\t\t\t\t\tchest.CanOpen = true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tRemoveComponent<InteractableComponent>();\n\t\t\t\t\t\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\n\t\t\t\tDialogs.RegisterCallback(\"duck_5\", (d, c) => {\n\t\t\t\t\tinteracted = true;\n\t\t\t\t\tRemoveComponent<InteractableComponent>();\n\t\t\t\t\t\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tinteracted = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(interacted);\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Duck;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\twhere.X -= 8;\n\t\t\t\n\t\t\tvar duck = new DungeonDuck();\n\t\t\tarea.Add(duck);\n\t\t\tduck.BottomCenter = where;\n\n\t\t\twhere.X += 16;\n\n\t\t\tvar chest = new DuckChest();\n\t\t\tarea.Add(chest);\n\t\t\tchest.BottomCenter = where;\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tif (chest == null && t >= 0.1f) {\n\t\t\t\tforeach (var c in GetComponent<RoomComponent>().Room.Tagged[Tags.Chest]) {\n\t\t\t\t\tif (c is DuckChest cs) {\n\t\t\t\t\t\tchest = cs;\n\t\t\t\t\t\tchest.CanOpen = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/DungeonElon.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class DungeonElon : DungeonShopNpc {\n\t\tprivate bool interacted;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 17;\n\t\t\tHeight = 19;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"elon\"));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => !interacted\n\t\t\t});\n\n\t\t\tDialogs.RegisterCallback(\"elon_4\", (d, cm) => {\n\t\t\t\tvar c = cm.To.GetComponent<ActiveWeaponComponent>();\n\t\t\t\n\t\t\t\tif (c.Item == null) {\n\t\t\t\t\treturn Dialogs.Get(\"elon_7\");\n\t\t\t\t}\n\n\t\t\t\tinteracted = true;\n\t\t\t\t\n\t\t\t\tvar id = Items.Generate(ItemType.Weapon, dt => dt.Id != c.Item.Id);\n\t\t\t\tvar i = c.Item;\n\t\t\t\n\t\t\t\tc.Drop();\n\t\t\t\ti.Done = true;\n\t\t\t\tc.Set(Items.CreateAndAdd(id, Area));\n\t\t\t\n\t\t\t\tRun.AddScourge(true);\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tif (interacted) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Start(\"elon_3\", e);\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Elon;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\tvar elon = new DungeonElon();\n\t\t\tarea.Add(elon);\n\t\t\telon.BottomCenter = where;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tinteracted = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(interacted);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/DungeonShopNpc.cs",
    "content": "namespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class DungeonShopNpc : ShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tRemove = false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Gobetta.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Gobetta : DungeonShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 15;\n\t\t\tHeight = 13;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"gobetta\"));\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Gobetta;\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is GobettaStand;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\twhere.Y -= 16;\n\t\t\t\n\t\t\tvar gobetta = new Gobetta();\n\t\t\tarea.Add(gobetta);\n\t\t\tgobetta.BottomCenter = where;\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Gobetta));\n\t\t\tvar c = 3;\n\t\t\tvar s = (int) Math.Floor(c / 2f) * 18;\n\t\t\t\n\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\tvar stand = new GobettaStand();\n\t\t\t\tarea.Add(stand);\n\t\t\t\tstand.Center = where + new Vector2((stand.Width + 4) * i - s, 4 + stand.Height + (i == 1 ? stand.Height * 0.5f : 0));\n\n\t\t\t\tvar id = Items.GenerateAndRemove(pool, null, true);\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(id, area, false), null);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override string GetDealDialog() {\n\t\t\treturn $\"gobetta_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tprotected override string GetHiDialog() {\n\t\t\treturn $\"gobetta_{Rnd.Int(3, 6)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Nurse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.ui.dialog;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Nurse : DungeonShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 40;\n\t\t\tHeight = 43;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"nurse\"));\n\t\t\tAddComponent(new RectBodyComponent(0, 26, 40, 17, BodyType.Static));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\t\n\t\t\t// GetComponent<DialogComponent>().Dialog.Voice = 4;\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tvar c = e.GetComponent<HealthComponent>();\n\t\t\tvar d = GetComponent<DialogComponent>();\n\n\t\t\tif (c.IsFull()) {\n\t\t\t\t// Ya look pretty good\n\t\t\t\td.StartAndClose(\"nurse_0\", 3);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar price = (int) (c.MaxHealth - c.Health) * 4;\n\t\t\tvar consumables = e.GetComponent<ConsumablesComponent>();\n\n\t\t\tif (consumables.Coins < price) {\n\n\t\t\t\td.Dialog.Str.SetVariable(\"price\", price);\n\t\t\t\td.StartAndClose(\"nurse_1\", 5);\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tc.ModifyHealth(c.MaxHealth, this);\n\t\t\tTextParticle.Add(e, Locale.Get(\"coins\"), price, true, true);\n\t\t\t\n\t\t\td.StartAndClose(\"nurse_2\", 5);\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Nurse;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\tvar nurse = new Nurse();\n\t\t\tarea.Add(nurse);\n\t\t\tnurse.BottomCenter = where + new Vector2(0, 8);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Creature || base.ShouldCollide(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Roger.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Roger : DungeonShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 18;\n\t\t\tHeight = 24;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"roger\"));\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Roger;\n\t\t}\n\t\t\n\t\tprotected override string GetDealDialog() {\n\t\t\treturn $\"roger_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is RogerStand;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\twhere.Y -= 16;\n\t\t\t\n\t\t\tvar roger = new Roger();\n\t\t\tarea.Add(roger);\n\t\t\troger.BottomCenter = where;\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Roger));\n\n\t\t\tfor (var i = -1; i < 2; i++) {\n\t\t\t\tvar stand = new RogerStand();\n\t\t\t\tarea.Add(stand);\n\t\t\t\tstand.Center = where + new Vector2((stand.Width + 8) * i, 4 + stand.Height - (i == 0 ? stand.Height * 0.5f : 0));\n\n\t\t\t\tvar id = Items.GenerateAndRemove(pool, null, true);\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(id, area, false), null);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override string GetFailDialog() {\n\t\t\treturn $\"roger_{Rnd.Int(3, 6)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Snek.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Snek : DungeonShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 18;\n\t\t\tHeight = 24;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"snek\"));\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(1, 14, 16, 10, BodyType.Static));\n\t\t}\n\n\t\tprotected override void OnItemBought(ItemBoughtEvent ibe) {\n\t\t\tforeach (var s in GetComponent<RoomComponent>().Room.Tagged[Tags.Item]) {\n\t\t\t\tif (s is SnekStand st && st != ibe.Stand && st.Item != null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar d = GetComponent<DialogComponent>();\n\t\t\t\n\t\t\td.StartAndClose(\"snek_6\", 3);\n\n\t\t\tTimer.Add(() => {\n\t\t\t\td.StartAndClose(\"snek_7\", 3);\n\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\tDone = true;\n\n\t\t\t\t\tvar stand = new SnekStand();\n\t\t\t\t\tArea.Add(stand);\n\t\t\t\t\tstand.Center = Center;\n\t\t\t\t\tstand.SetItem(Items.CreateAndAdd(\"bk:snek\", Area), this);\n\t\t\t\t}, 4f);\n\t\t\t}, 4f);\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Snek;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\tvar snek = new Snek();\n\t\t\tarea.Add(snek);\n\t\t\tsnek.BottomCenter = where;\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Snek));\n\n\t\t\tfor (var i = -1; i < 2; i++) {\n\t\t\t\tvar stand = new SnekStand();\n\t\t\t\tarea.Add(stand);\n\t\t\t\tstand.Center = where + new Vector2((stand.Width + 4) * i, 4 + stand.Height);\n\n\t\t\t\tvar id = Items.GenerateAndRemove(pool, null, true);\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(id, area, false), null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Creature || base.ShouldCollide(entity);\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is SnekStand;\n\t\t}\n\t\t\n\t\tprotected override string GetDealDialog() {\n\t\t\treturn $\"snek_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tprotected override string GetHiDialog() {\n\t\t\treturn $\"snek_{Rnd.Int(3, 6)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/TrashGoblin.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class TrashGoblin : DungeonShopNpc {\n\t\tprivate bool freed;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tHeight = 26;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"trash_goblin\"));\n\t\t\tAddComponent(new RectBodyComponent(0, 16, 14, 10, BodyType.Static));\n\t\t\t\n\t\t\tvar dl = GetComponent<DialogComponent>();\n\n\t\t\tdl.InitCallback = () => {\n\t\t\t\tdl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(\"note_0\"));\n\t\t\t\tdl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(\"note_1\"));\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(freed);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tfreed = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (freed) {\n\t\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"free\";\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.TrashGoblin;\n\t\t}\n\n\t\tpublic void Free() {\n\t\t\tif (freed) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfreed = true;\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"free\";\n\t\t\tGetComponent<DialogComponent>().StartAndClose(\"trash_goblin_1\", 5);\n\n\t\t\tTimer.Add(() => {\n\t\t\t\ttry {\n\t\t\t\t\tChestRegistry.PlaceRandom(BottomCenter + new Vector2(0, 12), Area);\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tLog.Error(ex);\n\t\t\t\t}\n\t\t\t}, 3f);\n\t\t}\n\n\t\tprotected override string GetHiDialog() {\n\t\t\treturn freed ? \"trash_goblin_2\" : \"trash_goblin_0\";\n\t\t}\n\n\t\tprotected override bool OwnsStand(ItemStand stand) {\n\t\t\treturn stand is TrashGoblinStand;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\twhere.Y -= 16;\n\t\t\t\n\t\t\tvar goblin = new TrashGoblin();\n\t\t\tarea.Add(goblin);\n\t\t\tgoblin.BottomCenter = where;\n\t\t\tgoblin.X += 1;\n\n\t\t\tvar stand = new TrashGoblinStand();\n\t\t\tarea.Add(stand);\n\t\t\tstand.Center = where + new Vector2(0, 4 + stand.Height);\n\n\t\t\tstand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), area, false), null);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Creature || base.ShouldCollide(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/npc/dungeon/Vampire.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.npc.dungeon {\n\tpublic class Vampire : DungeonShopNpc {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 22;\n\t\t\tHeight = 30;\n\t\t\tFlips = false;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"vampire\"));\n\t\t\tAddComponent(new RectBodyComponent(4, 19, 14, 11, BodyType.Static, false));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2));\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t}\n\n\t\tprotected override string GetDealDialog() {\n\t\t\treturn $\"vampire_{Rnd.Int(3)}\";\n\t\t}\n\n\t\tprotected override string GetHiDialog() {\n\t\t\treturn \"vampire_3\";\n\t\t}\n\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tif (entity.GetComponent<HealthComponent>().ModifyHealth(-1, this)) {\n\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\tvar coin = Items.CreateAndAdd(\"bk:copper_coin\", Area);\n\t\t\t\t\tcoin.TopCenter = BottomCenter;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGetComponent<DialogComponent>().Start($\"vampire_{Rnd.Int(4, 7)}\");\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override string GetId() {\n\t\t\treturn ShopNpc.Vampire;\n\t\t}\n\n\t\tpublic static void Place(Vector2 where, Area area) {\n\t\t\tvar sells = Rnd.Chance(60);\n\n\t\t\tif (sells) {\n\t\t\t\twhere.Y -= 24;\n\t\t\t}\n\n\t\t\tvar vampire = new Vampire();\n\t\t\tarea.Add(vampire);\n\t\t\tvampire.BottomCenter = where;\n\n\t\t\tif (!sells) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Vampire));\n\t\t\tvar c = Rnd.Int(1, 4);\n\t\t\tvar s = (int) Math.Floor(c / 2f) * 18;\n\t\t\t\n\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\tvar stand = new VampireStand();\n\t\t\t\tarea.Add(stand);\n\t\t\t\tstand.Center = where + new Vector2((stand.Width + 4) * i - s, 4 + stand.Height);\n\n\t\t\t\tvar id = Items.GenerateAndRemove(pool, null, true);\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(id, area, false), null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Creature || base.ShouldCollide(entity);\n\t\t}\n\t\t\n\t\tpublic override string GetFailDialog() {\n\t\t\treturn $\"vampire_{Rnd.Int(7, 10)}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/AnimatedFollowerPet.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class AnimatedFollowerPet : Pet {\n\t\tprivate string sprite;\n\n\t\tpublic AnimatedFollowerPet(string spr) {\n\t\t\tsprite = spr;\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(sprite) {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\n\t\t\tvar region = GetComponent<AnimationComponent>().Animation.GetCurrentTexture();\n\t\t\t\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Backpack.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Backpack : Pet {\n\t\tprivate InteractFx fx;\n\t\tprivate bool open;\n\t\tprivate TextureRegion itemRegion;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 12;\n\t\t\t\n\t\t\tAddComponent(new FollowerComponent {\n\t\t\t\tMaxDistance = 96,\n\t\t\t\tFollowSpeed = 2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"backpack\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\tAddComponent(new ItemComponent());\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => e == Owner && (e.GetComponent<ActiveWeaponComponent>().Item != null || GetComponent<ItemComponent>().Item != null),\n\t\t\t\tOnStart = e => AddFx()\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tvar id = GameSave.GetString(\"backpack\");\n\n\t\t\t\tif (id != null) {\n\t\t\t\t\tvar item = Items.CreateAndAdd(id, Area);\n\t\t\t\t\tGetComponent<ItemComponent>().Set(item, false);\n\t\t\t\t\titem.GetComponent<OwnerComponent>().Owner = Owner;\n\t\t\t\t\titemRegion = item.Region;\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tGameSave.Put(\"backpack\", GetComponent<ItemComponent>().Item?.Id);\n\t\t}\n\n\t\tprivate void AddFx() {\n\t\t\tif (fx != null && !fx.Done) {\n\t\t\t\tfx.Close();\n\t\t\t}\n\t\t\t\n\t\t\tvar i = GetComponent<ItemComponent>().Item;\n\t\t\tEngine.Instance.State.Ui.Add(fx = new InteractFx(this, i == null ? Locale.Get(\"place_an_item\") : i.Name));\n\t\t}\n\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tvar w = entity.GetComponent<ActiveWeaponComponent>();\n\n\t\t\tif (w.Item != null && w.Item.Scourged) {\n\t\t\t\tentity.GetComponent<DialogComponent>().StartAndClose($\"~~{Locale.Get(\"scourged\")}~~\", 2);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tvar i = GetComponent<ItemComponent>();\n\t\t\tvar w2 = entity.GetComponent<WeaponComponent>();\n\n\t\t\tif (i.Item != null && w2.Item == null) {\n\t\t\t\ti.Exchange(w2);\n\t\t\t\tw.RequestSwap();\n\t\t\t} else {\n\t\t\t\ti.Exchange(w);\n\t\t\t}\n\n\t\t\tif (w.Item != null) {\n\t\t\t\tAudio.PlaySfx(w.Item.Data.WeaponType.GetSwapSfx());\n\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().AnimateSwap();\n\t\t\t} else if (entity.GetComponent<WeaponComponent>().Item != null) {\n\t\t\t\tw.RequestSwap();\n\t\t\t}\n\n\n\t\t\tif (i.Item != null) {\n\t\t\t\titemRegion = i.Item.Region;\n\t\t\t} else {\n\t\t\t\titemRegion = null;\n\t\t\t}\n\n\t\t\tAddFx();\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (!open && cse.Entity == Owner) {\n\t\t\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"open\";\n\t\t\t\t\t});\n\n\t\t\t\t\tGetComponent<FollowerComponent>().Paused = true;\n\t\t\t\t\tGetComponent<RectBodyComponent>().Velocity *= 0.5f;\n\n\t\t\t\t\tAudio.PlaySfx(\"unlock\");\n\t\t\t\t\topen = true;\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (open && cee.Entity == Owner) {\n\t\t\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\t\t\topen = false;\n\t\t\t\t\t\tGetComponent<AnimationComponent>().Animation.Tag = \"idle\";\n\t\t\t\t\t});\n\n\t\t\t\t\tGetComponent<FollowerComponent>().Paused = false;\n\t\t\t\t\t\n\t\t\t\t\tAudio.PlaySfx(\"swap\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (open && itemRegion != null) {\n\t\t\t\tGraphics.Render(itemRegion, Position + new Vector2(6, 7), 0, itemRegion.Center, GetComponent<AnimationComponent>().Scale);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/BooGraphicsComponent.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.graphics;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class BooGraphicsComponent : GraphicsComponent {\n\t\tprivate Animation animation;\n\t\tprivate bool flipped;\n\t\tprivate double angle;\n\t\tprivate Vector2 scale = Vector2.One;\n\t\t\n\t\tpublic BooGraphicsComponent(string anim) {\n\t\t\tanimation = Animations.Get(anim).CreateAnimation();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tanimation.Update(dt);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar slice = animation.GetCurrentTexture();\n\t\t\tvar origin = slice.Center;\n\t\t\tvar body = Entity.GetAnyComponent<BodyComponent>();\n\t\t\tvar vx = Math.Abs(body.Velocity.X);\n\t\t\t\n\t\t\tif (vx > 0.1f) {\n\t\t\t\tflipped = vx < 0;\n\t\t\t}\n\n\t\t\tangle = MathUtils.LerpAngle(angle, Math.Min(2, vx), Engine.Delta * 8);\n\t\t\tGraphics.Render(slice, Entity.Position + origin, (float) angle, origin, flipped ? new Vector2(-scale.X, scale.Y) : scale);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is StateChangedEvent ev && animation != null) {\n\t\t\t\tvar tag = ev.NewState.Name.ToLower().Replace(\"state\", \"\");\n\t\t\t\t\n\t\t\t\tif (animation.HasTag(tag)) {\n\t\t\t\t\tanimation.Tag = tag;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Bubblo.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Bubblo : DiagonalPet {\n\t\tprivate static int[] widths = {\n\t\t\t13, 10, 7\n\t\t};\n\n\t\tprivate static string[] tags = {\n\t\t\t\"idle\", \"mid\", \"small\"\n\t\t};\n\t\t\n\t\tprivate int hits;\n\t\tprivate int stage;\n\t\tprivate List<Entity> Colliding = new List<Entity>();\n\t\tprivate bool hidden;\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tAddGraphics(\"globbo\", false, widths[stage], widths[stage] + 1);\n\t\t\tbase.PostInit();\n\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\t\t\ta.CustomFlip = true;\n\t\t\ta.Animation.Tag = tags[stage];\n\t\t\t\n\t\t\tGetComponent<ShadowComponent>().Callback = RenderShadow;\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (!hidden && t >= 0.2f) {\n\t\t\t\tt = 0;\n\t\t\t\t\n\t\t\t\tforeach (var c in Colliding) {\n\t\t\t\t\tif (c.GetComponent<HealthComponent>().ModifyHealth(-3, this)) {\n\t\t\t\t\t\tHit();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void Hit() {\n\t\t\thits++;\n\n\t\t\tif (hits >= 2) {\n\t\t\t\tif (stage == 0) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar s = stage + 1;\n\n\t\t\t\tif (s == 3) {\n\t\t\t\t\tDone = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\t\tvar b = new Bubblo();\n\t\t\t\t\tb.stage = s;\n\t\t\t\t\tb.Owner = Owner;\n\t\t\t\t\tArea.Add(b);\n\t\t\t\t\tb.Center = Center;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnJump() {\n\t\t\tbase.OnJump();\n\n\t\t\tif (!hidden && stage > 0) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\thidden = false;\n\t\t\thits = 0;\n\t\t\tDone = false;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (!hidden) {\n\t\t\t\tbase.Render();\n\t\t\t}\n\t\t}\n\n\t\tprotected override void RenderShadow() {\n\t\t\tif (!hidden) {\n\t\t\t\tGraphicsComponent?.Render(true);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (!hidden && cse.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Add(cse.Entity);\n\n\t\t\t\t\tif (cse.Entity.GetComponent<HealthComponent>().ModifyHealth(-3, this)) {\n\t\t\t\t\t\tHit();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Remove(cee.Entity);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Crystal.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Crystal : Pet {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 12;\n\t\t\tHeight = 14;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"crystal\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\n\t\t\tvar b = new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true);\n\t\t\tAddComponent(b);\n\n\t\t\tb.KnockbackModifier = 0;\n\t\t\tb.Body.LinearDamping = 100;\n\t\t}\n\t\t\n\t\tprivate float sinceLastTeleport;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tsinceLastTeleport -= dt;\n\n\t\t\tif (!OnScreen || sinceLastTeleport <= 0) {\n\t\t\t\tsinceLastTeleport = Rnd.Float(2, 5);\n\t\t\t\tTeleport();\n\t\t\t}\n\t\t}\n\n\t\tprivate void Teleport() {\n\t\t\tGetComponent<AnimationComponent>().Animate(() => {\n\t\t\t\tAnimationUtil.Poof(Center, Depth + 1);\n\t\t\t\tCenter = Owner.Center + MathUtils.CreateVector(Rnd.AnglePI(), Rnd.Float(12, 18));\n\t\t\t\tAnimationUtil.Poof(Center, Depth + 1);\n\t\t\t});\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Projectile p && !p.HasFlag(ProjectileFlags.Artificial) && p.Owner == Owner && p.Parent == null) {\n\t\t\t\tvar tt = Rnd.Int(5, 8);\n\t\t\t\tvar body = p.GetAnyComponent<BodyComponent>();\n\n\t\t\t\tvar builder = new ProjectileBuilder(Owner, p.Slice) {\n\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\tParent = p\n\t\t\t\t};\n\n\t\t\t\tbuilder.AddFlags(ProjectileFlags.Artificial);\n\n\t\t\t\tfor (var i = 0; i < tt; i++) {\n\t\t\t\t\tbuilder.Shoot(body.Angle + (i - tt * 0.5f) * 0.1f, body.Velocity.Length() * 0.05f);\n\n\t\t\t\t\tvar pr = builder.Build();\n\n\t\t\t\t\tpr.Color = ProjectileColor.Rainbow[i];\n\t\t\t\t\tpr.Position = p.Position;\n\t\t\t\t}\n\n\t\t\t\tAnimationUtil.Poof(Center, Depth + 1);\n\t\t\t\tp.Done = true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override void Follow() {\n\t\t\t// NO FOLLOWING, HOW DARE ARE YOU?\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/DiagonalPet.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.door;\nusing BurningKnight.level;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class DiagonalPet : RoomBasedPet {\n\t\tprivate static double[] angles = {\n\t\t\tMath.PI * 0.25f,\n\t\t\tMath.PI * 0.75f,\n\t\t\tMath.PI * 1.25f,\n\t\t\tMath.PI * 1.75f\n\t\t};\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tvar body = GetComponent<RectBodyComponent>().Body;\n\t\t\t\n\t\t\tbody.Restitution = 1;\n\t\t\tbody.Friction = 0;\n\t\t\t\n\t\t\tGetComponent<RectBodyComponent>().Velocity = MathUtils.CreateVector(angles[Rnd.Int(angles.Length)], 50);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is ProjectileLevelBody || entity is Door;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tvar velocity = GetComponent<RectBodyComponent>().Velocity;\n\t\t\tvar a = velocity.ToAngle() - Math.PI * 0.25f;\n\t\t\tvar l = velocity.Length();\n\n\t\t\tif (Math.Abs(a % (Math.PI * 0.5f)) >= 0.1f || l < 40) {\n\t\t\t\ta = (float) (Math.Floor(a / (Math.PI * 0.5f)) * (Math.PI * 0.5f) + Math.PI * 0.25f);\n\t\t\t\tGetComponent<RectBodyComponent>().Velocity = MathUtils.CreateVector(a, Math.Max(l, 40));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/FollowerPet.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class FollowerPet  : Pet {\n\t\tprotected string Sprite;\n\n\t\tpublic FollowerPet(string spr) {\n\t\t\tSprite = spr;\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tvar region = CommonAse.Items.GetSlice(Sprite);\n\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\t\t\t\n\t\t\tAddComponent(new ZSliceComponent(CommonAse.Items, Sprite));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new ZComponent { Float = true });\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\t\n\t\t\tGetComponent<ZSliceComponent>().Animate();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/GeneratorPet.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.tween;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class GeneratorPet : Pet {\n\t\tprivate string sprite;\n\t\tprivate Func<Area, Item> callback;\n\t\tprivate int numRooms;\n\t\tprivate int roomsCleared;\n\t\t\n\t\tpublic GeneratorPet(string spr, int rooms, Func<Area, Item> generate) {\n\t\t\tsprite = spr;\n\t\t\tnumRooms = rooms;\n\t\t\tcallback = generate;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new ZSliceComponent(\"items\", sprite));\n\t\t\tAddComponent(new ZComponent { Float = true });\n\n\t\t\tvar region = GetComponent<ZSliceComponent>().Sprite;\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, region.Width, region.Height));\n\t\t\t\n\t\t\tSubscribe<RoomClearedEvent>();\n\t\t\tGetComponent<ZSliceComponent>().Animate();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomClearedEvent) {\n\t\t\t\troomsCleared++;\n\n\t\t\t\tif (roomsCleared >= numRooms) {\n\t\t\t\t\tGetComponent<FollowerComponent>().Pause = 1f;\n\t\t\t\t\troomsCleared = 0;\n\n\t\t\t\t\tvar a = GetComponent<ZSliceComponent>();\n\t\t\t\t\t\n\t\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\t\t\n\t\t\t\t\t\t\tvar item = callback(Area);\n\n\t\t\t\t\t\t\tif (item != null) {\n\t\t\t\t\t\t\t\titem.Center = Center;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.6f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.6f);\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/LampPet.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class LampPet : FollowerPet {\n\t\tpublic LampPet(string spr) : base(spr) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 64f, new Color(1f, 0.8f, 0.2f, 1f)));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse && Sprite == \"bk:sharp_lamp\" && cse.Entity is Creature c && !c.IsFriendly()) {\n\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-2, this);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override void Follow() {\n\t\t\tif (Sprite == \"bk:led\") {\n\t\t\t\tif (!HasComponent<OrbitalComponent>()) {\n\t\t\t\t\tAddComponent(new OrbitalComponent());\n\t\t\t\t\tOwner.GetComponent<OrbitGiverComponent>().AddOrbiter(this);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbase.Follow();\n\t\t\t}\n\t\t}\n\n\t\tprivate float lastFlame;\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt * 0.5f;\n\t\t\tGetComponent<LightComponent>().Light.Radius = 38f + (float) Math.Cos(t) * 6;\n\t\t\t\n\t\t\tlastFlame += dt;\n\n\t\t\tif (lastFlame > 0.3f) {\n\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\tX = CenterX,\n\t\t\t\t\tY = Y + 1,\n\t\t\t\t\tDepth = Layers.Wall + 1\n\t\t\t\t});\n\n\t\t\t\tlastFlame = 0;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/LilBoo.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class LilBoo : Pet {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 6;\n\t\t\tHeight = 8;\n\t\t\t\n\t\t\tAddComponent(new BooGraphicsComponent(\"ghost_pet\"));\n\n\t\t\tvar b = new RectBodyComponent(0, 0, Width, Height) {\n\t\t\t\tKnockbackModifier = 0.2f\n\t\t\t};\n\t\t\t\n\t\t\tAddComponent(b);\n\t\t\tb.Body.LinearDamping = 3;\n\t\t\t\n\t\t\t\n\t\t\tBecome<IdleState>();\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is Player) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (GetComponent<StateComponent>().StateInstance is WanderState) {\n\t\t\t\treturn entity is Level;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t#region Boo states\n\t\tprivate class IdleState : SmartState<LilBoo> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar d = Self.DistanceTo(Self.Owner);\n\n\t\t\t\tif (d > 48) {\n\t\t\t\t\tSelf.Become<FollowState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate class FollowState : SmartState<LilBoo> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar dx = Self.DxTo(Self.Owner);\n\t\t\t\tvar dy = Self.DyTo(Self.Owner);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\t\n\t\t\t\tif (d > 256) {\n\t\t\t\t\tAnimationUtil.Poof(Self.Center);\n\t\t\t\t\tSelf.Center = Self.Owner.Center + Rnd.Offset(24);\n\t\t\t\t\tAnimationUtil.Poof(Self.Center);\n\t\t\t\t\t\n\t\t\t\t\tSelf.Become<HappyState>();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (d < 32) {\n\t\t\t\t\tSelf.Become<HappyState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\t\t\t\tvar s = dt * 20;\n\t\t\t\t\n\t\t\t\tbody.Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t}\n\t\t}\n\n\t\tprivate class EmotionState : SmartState<LilBoo> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T > 1f) {\n\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate class HappyState : EmotionState {\n\t\t\t\n\t\t}\n\n\t\tprivate class WanderState : SmartState<LilBoo> {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Pet.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Pet : Creature {\n\t\tpublic Entity Owner;\n\t\tpublic Action<float> Controller;\n\n\t\tprotected bool Saveable;\n\t\tprivate bool findOwner;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tController?.Invoke(dt);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tRemoveComponent<HealthComponent>();\t\t\t\n\t\t\tRemoveComponent<TileInteractionComponent>();\n\n\t\t\tif (!Saveable) {\n\t\t\t\tRemoveTag(Tags.LevelSave);\n\t\t\t} else {\n\t\t\t\tfindOwner = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tFollow();\n\t\t}\n\n\t\tprotected virtual void Follow() {\n\t\t\tOwner?.GetComponent<FollowerComponent>()?.AddFollower(this);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/PetRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.twitch;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic static class PetRegistry {\n\t\tprivate static Dictionary<string, Func<Entity, Entity>> defined = new Dictionary<string, Func<Entity, Entity>>();\n\n\t\tpublic static Entity Create(string id, Entity owner) {\n\t\t\treturn !defined.TryGetValue(id, out var d) ? null : d(owner);\n\t\t}\n\t\t\n\t\tpublic static Entity CreateRandom(Entity owner) {\n\t\t\tvar keys = defined.Keys.ToArray();\n\t\t\treturn Create(keys[Rnd.Int(keys.Length)], owner);\n\t\t}\n\n\t\tpublic static void Define(string id, Func<Entity, Entity> pet, Mod mod = null) {\n\t\t\tdefined[$\"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}\"] = pet;\n\t\t}\n\n\t\tpublic static bool Has(string id) {\n\t\t\treturn defined.ContainsKey(id);\n\t\t}\n\n\t\tstatic PetRegistry() {\n\t\t\tDefine(\"backpack\", o => o.Area.Add(new Backpack {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"crystal\", o => o.Area.Add(new Crystal {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"lil_boo\", o => o.Area.Add(new LilBoo {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"strawberry\", o => o.Area.Add(new Strawberry() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"snek\", o => o.Area.Add(new SnekPet {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"meat_guy\", o => {\n\t\t\t\tvar timer = 0f;\n\t\t\t\tvar pet = new AnimatedFollowerPet(\"meat_guy\") {\n\t\t\t\t\tOwner = o\n\t\t\t\t};\n\n\t\t\t\tpet.Controller += dt => {\n\t\t\t\t\ttimer += dt;\n\n\t\t\t\t\tif (timer >= 2f) {\n\t\t\t\t\t\ttimer = 0;\n\n\t\t\t\t\t\tif ((o.GetComponent<RoomComponent>().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_meatguy\", 4, 0.5f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar a = pet.AngleTo(o.GetComponent<AimComponent>().RealAim);\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(o, \"small\") {\n\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\tColor = ProjectileColor.Yellow\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.Shoot(a, 10f);\n\n\t\t\t\t\t\tvar projectile = builder.Build();\n\n\t\t\t\t\t\tprojectile.Center = pet.Center + MathUtils.CreateVector(a, 5f);\n\t\t\t\t\t\tprojectile.Owner = pet;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\to.Area.Add(pet);\n\t\t\t\treturn pet;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"skele_buddy\", o => {\n\t\t\t\tvar timer = 0f;\n\t\t\t\tvar pet = new AnimatedFollowerPet(\"skele_buddy\") {\n\t\t\t\t\tOwner = o\n\t\t\t\t};\n\n\t\t\t\tpet.Controller += dt => {\n\t\t\t\t\ttimer += dt;\n\n\t\t\t\t\tif (timer >= 2f) {\n\t\t\t\t\t\ttimer = 0;\n\n\t\t\t\t\t\tif ((o.GetComponent<RoomComponent>().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_meatguy\", 4, 0.5f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar a = pet.AngleTo(o.GetComponent<AimComponent>().RealAim) - Math.PI;\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(o, \"circle\") {\n\t\t\t\t\t\t\tScale = Rnd.Float(0.6f, 1f),\n\t\t\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\t\t\tColor = ProjectileColor.Red\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\t\t\tvar projectile = builder.Shoot(a + (i - 1) * 0.3f + Rnd.Float(-0.1f, 0.1f), Rnd.Float(4, 6)).Build();\n\n\t\t\t\t\t\t\tprojectile.Center = pet.Center + MathUtils.CreateVector(a, 5f);\n\t\t\t\t\t\t\tprojectile.Owner = pet;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\to.Area.Add(pet);\n\t\t\t\treturn pet;\n\t\t\t});\n\n\t\t\tDefine(\"coin_pouch\", o => o.Area.Add(new GeneratorPet(\"bk:coin_pouch\", 2, a => Items.CreateAndAdd(\"bk:coin\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"key_pouch\", o => o.Area.Add(new GeneratorPet(\"bk:key_pouch\", 3, a => Items.CreateAndAdd(\"bk:key\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"bomb_pouch\", o => o.Area.Add(new GeneratorPet(\"bk:bomb_pouch\", 3, a => Items.CreateAndAdd(\"bk:bomb\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"batman\", o => o.Area.Add(new GeneratorPet(\"bk:batman\", 3, a => Items.CreateAndAdd(\"bk:battery\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"pouch_pouch\", o => o.Area.Add(new GeneratorPet(\"bk:pouch_pouch\", 4, a => Items.CreateAndAdd(\"bk:pouch\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"shield_pouch\", o => o.Area.Add(new GeneratorPet(\"bk:shield_pouch\", 8, a => Items.CreateAndAdd(\"bk:shield\", a)) {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"shield_buddy\", o => o.Area.Add(new ShieldBuddy() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"wallet\", o => o.Area.Add(new Wallet() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"spiked_cookie\", o => o.Area.Add(new SpikedCookie() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\n\t\t\tDefine(\"shooty\", o => o.Area.Add(new Shooty() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"bubblo\", o => o.Area.Add(new Bubblo() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"the_eye\", o => o.Area.Add(new TheEye() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t\t\n\t\t\tDefine(\"twitch\", o => o.Area.Add(new TwitchPet() {\n\t\t\t\tOwner = o\n\t\t\t}));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/RoomBasedPet.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class RoomBasedPet : Pet {\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (t >= 1f) {\n\t\t\t\tt = 0;\n\n\t\t\t\tif (Done) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\t\t\t\tvar rm = Owner.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r != rm) {\n\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\tCenter = rm.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t\t\t\tOnJump();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void OnJump() {\n\t\t\t\n\t\t}\n\n\t\tprotected override void Follow() {\n\t\t\t\n\t\t}\n\n\t\tpublic void AddGraphics(string sprite, bool sensor = true, int w = -1, int h = -1) {\n\t\t\tAddComponent(new AnimationComponent(sprite) {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\n\t\t\tvar region = GetComponent<AnimationComponent>().Animation.GetCurrentTexture();\n\n\t\t\tif (w == -1) {\n\t\t\t\tWidth = region.Width;\n\t\t\t} else {\n\t\t\t\tWidth = w;\n\t\t\t}\n\n\t\t\tif (h == -1) {\n\t\t\t\tHeight = region.Height;\n\t\t\t} else {\n\t\t\t\tHeight = h;\n\t\t\t}\n\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, sensor));\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/ShieldBuddy.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class ShieldBuddy : Pet {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 12;\n\t\t\tHeight = 13;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"shield_buddy\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Projectile p && p.Owner != Owner) {\n\t\t\t\tp.Break();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Shooty.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.projectile;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Shooty : DiagonalPet {\n\t\tpublic override void PostInit() {\n\t\t\tAddGraphics(\"shooty\", false);\n\t\t\tbase.PostInit();\n\t\t\tt = Rnd.Float(2f);\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (t >= 2f) {\n\t\t\t\tt = 0;\n\n\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (r.Tagged[Tags.MustBeKilled].Count > 0) {\n\t\t\t\t\tvar o = Owner;\n\t\t\t\t\t\t\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_meatguy\", 4, 0.5f);\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(o, \"small\") {\n\t\t\t\t\t\tColor = ProjectileColor.Yellow,\n\t\t\t\t\t\tRange = 32f\n\t\t\t\t\t};\n\n\t\t\t\t\tbuilder.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\tvar a = i * Math.PI * 0.5f;\n\t\t\t\t\t\tvar projectile = builder.Shoot(a, 4f).Build();\n\n\t\t\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(a, 5f);\n\t\t\t\t\t\tprojectile.Owner = this;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/SnekPet.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class SnekPet : Pet {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAchievements.Unlock(\"bk:snek\");\n\n\t\t\tWidth = 18;\n\t\t\tHeight = 24;\n\t\t\t\n\t\t\tAddComponent(new SimpleZAnimationComponent(\"snek\"));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new ZComponent { Float = true });\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\t\n\t\t\tGetComponent<SimpleZAnimationComponent>().Animate();\n\t\t\t\n\t\t\tAddComponent(new FollowerComponent {\n\t\t\t\tMaxDistance = 4\n\t\t\t});\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Creature c && !c.IsFriendly()) {\n\t\t\t\t\tc.GetComponent<BuffsComponent>().Add(new PoisonBuff());\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar component = GetComponent<FollowerComponent>();\n\n\t\t\tif (component.Following == null || component.Following == this) {\n\t\t\t\tOwner.GetComponent<FollowerComponent>().AddFollower(this);\n\t\t\t} else if (component.Following == Owner) {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar target = room.FindClosest(Center, Tags.MustBeKilled, e => e != this);\n\n\t\t\t\tif (target != null) {\n\t\t\t\t\tif (!target.HasComponent<FollowerComponent>()) {\n\t\t\t\t\t\ttarget.AddComponent(new FollowerComponent());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tGetComponent<FollowerComponent>().Remove();\n\t\t\t\t\ttarget.GetComponent<FollowerComponent>().AddFollower(this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/SpikedCookie.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class SpikedCookie : DiagonalPet {\n\t\tprivate List<Entity> Colliding = new List<Entity>();\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tAddGraphics(\"spiked_cookie\", false);\n\t\t\tbase.PostInit();\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (t >= 0.2f) {\n\t\t\t\tt = 0;\n\t\t\t\t\n\t\t\t\tforeach (var c in Colliding) {\n\t\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-3, this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Add(cse.Entity);\n\t\t\t\t\tcse.Entity.GetComponent<HealthComponent>().ModifyHealth(-3, this);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Remove(cee.Entity);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Strawberry.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Strawberry : FollowerPet {\n\t\tpublic Strawberry() : base(\"bk:strawberry\") {\n\t\t\t\n\t\t}\n\n\t\tprivate float delay;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tdelay -= dt;\n\n\t\t\tif (delay <= 0) {\n\t\t\t\tdelay = Rnd.Float(1f, 3f);\n\t\t\t\tvar cn = Rnd.Int(1, 4);\n\n\t\t\t\tfor (var i = 0; i < cn; i++) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"heart_{Rnd.Int(1, 4)}\"))));\n\t\t\t\t\t\tpart.Position = Center;\n\n\t\t\t\t\t\tif (TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\n\t\t\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\t\t\tpart.Particle.Alpha = 0.9f;\n\t\t\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t\t\t}, i * 0.3f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Mob m) {\n\t\t\t\t\tm.GetComponent<BuffsComponent>().Add(new CharmedBuff {\n\t\t\t\t\t\tDuration = 10\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/TheEye.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class TheEye : RoomBasedPet {\n\t\tprivate List<Entity> Colliding = new List<Entity>();\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"eye\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\n\t\t\tWidth = 25;\n\t\t\tHeight = 19;\n\t\t\tDepth = Layers.FlyingMob;\n\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, false));\n\t\t\t\n\t\t\tAddComponent(new StateComponent());\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t\t\n\t\t\tvar body = GetComponent<BodyComponent>().Body;\n\n\t\t\tbody.Restitution = 1;\n\t\t\tbody.LinearDamping = 10;\n\t\t\tFlying = true;\n\t\t}\n\n\t\tprotected override void OnJump() {\n\t\t\tbase.OnJump();\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t}\n\t\t\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (t >= 0.2f) {\n\t\t\t\tt = 0;\n\n\t\t\t\tif (GetComponent<StateComponent>().StateInstance is AttackState) {\n\t\t\t\t\tforeach (var c in Colliding) {\n\t\t\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-3, this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (entity is Chasm || entity is HalfWall || entity is SolidProp) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ((entity is Door || entity is Level) && GetComponent<StateComponent>().StateInstance is IdleState) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.ShouldCollide(entity);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Level) {\n\t\t\t\t\tif (GetComponent<StateComponent>().StateInstance is AttackState) {\n\t\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t\t}\n\t\t\t\t} else if (cse.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Add(cse.Entity);\n\n\t\t\t\t\tif (GetComponent<StateComponent>().StateInstance is AttackState) {\n\t\t\t\t\t\tcse.Entity.GetComponent<HealthComponent>().ModifyHealth(-3, this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity.HasTag(Tags.MustBeKilled)) {\n\t\t\t\t\tColliding.Remove(cee.Entity);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate Entity target;\n\t\t\n\t\t#region Eye States\n\t\tprivate class IdleState : SmartState<TheEye> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.Owner.GetComponent<FollowerComponent>().AddFollower(Self);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<FollowerComponent>().Remove();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T <= 1f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar r = Self.Owner.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r == null || r.Tagged[Tags.MustBeKilled].Count == 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tSelf.target = r.FindClosest(Self.Center, Tags.MustBeKilled);\n\n\t\t\t\tif (Self.target != null) {\n\t\t\t\t\tBecome<AttackState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate class AttackState : SmartState<TheEye> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = MathUtils.CreateVector(Self.AngleTo(Self.target), 600);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<RectBodyComponent>().Velocity.LengthSquared() <= 2048) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/pet/Wallet.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Utilities;\nusing MathUtils = Lens.util.MathUtils;\n\nnamespace BurningKnight.entity.creature.pet {\n\tpublic class Wallet : Pet {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 12;\n\t\t\tHeight = 13;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"wallet\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, Width, Height, BodyType.Dynamic));\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t\t\n\t\t\tAddComponent(new StateComponent());\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\n\t\t\tGetComponent<SensorBodyComponent>().Body.LinearDamping = 3;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tOwner.GetComponent<ConsumablesComponent>().MaxCoins = 255;\n\t\t}\n\n\t\tprivate Item target;\n\t\t\n\t\t#region Wallet States\n\t\tprivate class IdleState : SmartState<Wallet> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tvar r = Self.Owner.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r != null && r.Tagged[Tags.Item].Count > 0) {\n\t\t\t\t\tvar min = float.MaxValue;\n\t\t\t\t\tSelf.target = null;\n\t\t\t\t\t\n\t\t\t\t\tforeach (var i in r.Tagged[Tags.Item]) {\n\t\t\t\t\t\tif (!(i is Item)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar item = (Item) i;\n\n\t\t\t\t\t\tif (item.Type == ItemType.Coin && !item.HasComponent<OwnerComponent>() && !item.Done) {\n\t\t\t\t\t\t\tvar d = Self.DistanceTo(i);\n\n\t\t\t\t\t\t\tif (d < min) {\n\t\t\t\t\t\t\t\tmin = d;\n\t\t\t\t\t\t\t\tSelf.target = item;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Self.target != null) {\n\t\t\t\t\t\tBecome<PickupState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate class PickupState : SmartState<Wallet> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<FollowerComponent>().Remove();\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.Follow();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.target.Done || Self.target.HasComponent<OwnerComponent>()) {\n\t\t\t\t\tSelf.target = null;\n\t\t\t\t\tSelf.Become<IdleState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar dx = Self.DxTo(Self.target);\n\t\t\t\tvar dy = Self.DyTo(Self.target);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tvar b = Self.GetComponent<SensorBodyComponent>().Body;\n\t\t\t\tvar s = 360 * dt / d;\n\t\t\t\t\n\t\t\t\tb.LinearVelocity += new Vector2(dx * s, dy * s);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Item i && i.Type == ItemType.Coin) {\n\t\t\t\tOwner.GetComponent<InventoryComponent>().Pickup(i);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/ActiveItemComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.assets.items;\nusing BurningKnight.debug;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.level.biome;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class ActiveItemComponent : ItemComponent {\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Item != null && Run.Depth < 1) {\n\t\t\t\tItem.Done = true;\n\t\t\t\tItem = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomClearedEvent) {\n\t\t\t\tif (Item != null && Item.UseTime > 0.02f) {\n\t\t\t\t\tvar o = Item.Delay;\n\t\t\t\t\tItem.Delay = Math.Max(Item.Delay - 1, 0f);\n\n\t\t\t\t\tif (Math.Abs(o) >= 0.01f && Math.Abs(Item.Delay) < 0.01f) {\n\t\t\t\t\t\tAudio.PlaySfx(\"item_active_charged\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override void OnItemSet(Item previous) {\n\t\t\tbase.OnItemSet(previous);\n\t\t\t\n\t\t\tif (Run.Depth > 0 && GlobalSave.IsFalse(\"control_active\") && GetComponent<DialogComponent>().Dialog?.Str != null) {\n\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\t\t\t\t\n\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Active, false)));\n\n\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\n\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Active, true)));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdialog.StartAndClose(\"control_6\", 5);\n\t\t\t}\n\n\t\t\tif (Item.Id == \"bk:snow_bucket\" && !(Run.Level.Biome is IceBiome)) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar i = Item;\n\t\t\t\t\n\t\t\t\t\tDrop();\n\t\t\t\t\ti.Done = true;\n\n\t\t\t\t\tEntity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:water_bucket\", Entity.Area));\n\t\t\t\t}, 3f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Run.Depth > 0 && Item != null && !Item.Done && Input.WasPressed(Controls.Active, GetComponent<InputComponent>())) {\n\t\t\t\tif (GetComponent<PlayerInputComponent>().InDialog) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (GetComponent<StateComponent>().StateInstance is Player.SleepingState) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<Player.IdleState>();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Item.Use((Player) Entity)) {\n\t\t\t\t\tif (CheatWindow.InfiniteActive) {\n\t\t\t\t\t\tItem.Delay = 0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (Run.Depth > 0 && GlobalSave.IsFalse(\"control_active\")) {\n\t\t\t\t\t\tEntity.GetComponent<DialogComponent>().Close();\n\t\t\t\t\t\tGlobalSave.Put(\"control_active\", true);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tAudio.PlaySfx(\"item_active\");\n\n\t\t\t\t\tif (Item.SingleUse && !CheatWindow.InfiniteActive) {\n\t\t\t\t\t\tItem.Done = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Clear() {\n\t\t\tItem = null;\n\t\t}\n\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn item.Type == ItemType.Active;\n\t\t}\n\t\t\n\t\tpublic bool IsFullOrEmpty() {\n\t\t\treturn Item == null || Item.Delay <= 0.01f;\n\t\t}\n\n\t\tpublic void Charge(int amount) {\n\t\t\tif (Item != null && Item.UseTime > 0.02f) {\n\t\t\t\tItem.Delay = Math.Max(Item.Delay - amount, 0f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/ActiveWeaponComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.assets;\nusing Lens.entity.component.logic;\nusing Lens.input;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class ActiveWeaponComponent : WeaponComponent {\n\t\tprivate bool stopped = true;\n\t\tprivate float timeSinceReady;\n\t\t\n\t\tpublic ActiveWeaponComponent() {\n\t\t\tAtBack = false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar controller = GetComponent<InputComponent>();\n\t\t\tvar data = controller.GamepadEnabled ? controller.GamepadData : null;\n\n\t\t\tvar lamp = GetComponent<LampComponent>().Item;\n\t\t\tvar useLamp = lamp != null && lamp.Id == \"bk:explosive_lamp\";\n\t\t\tvar Item = useLamp ? lamp : this.Item;\n\n\t\t\tif ((useLamp || !Disabled) && Item != null) {\n\t\t\t\tvar ready = Item.Delay <= 0.001f;\n\n\t\t\t\tif (ready) {\n\t\t\t\t\tif (timeSinceReady <= 0.001f && Item.Type == ItemType.Weapon) {\n\t\t\t\t\t\tvar t = Item.Data.WeaponType;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (t == WeaponType.Ranged) {\n\t\t\t\t\t\t\tforeach (var u in Item.Uses) {\n\t\t\t\t\t\t\t\tif (u is SimpleShootUse s) {\n\t\t\t\t\t\t\t\t\tif (s.ReloadSfx) {\n\t\t\t\t\t\t\t\t\t\tEntity.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_shotgun_reload\", 2, 0.8f);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\t\n\t\t\t\t\t\t} else if (t == WeaponType.Melee) {\n\t\t\t\t\t\t\tEntity.GetComponent<AudioEmitterComponent>().EmitRandomized(\"item_sword_cooldown\", 0.5f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttimeSinceReady += dt;\n\t\t\t\t} else {\n\t\t\t\t\ttimeSinceReady = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar b = GetComponent<BuffsComponent>();\n\t\t\t\t\n\t\t\t\tif (b.Has<FrozenBuff>() || b.Has<CharmedBuff>() || GetComponent<StateComponent>().StateInstance is Player.RollState) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ((Input.WasPressed(Controls.Use, controller) || (data != null && (\n\t\t\t\t\tdata.DPadDownCheck || data.DPadLeftCheck || data.DPadUpCheck || data.DPadRightCheck                                                  \n\t\t\t\t  ))) || ((Item.Automatic || timeSinceReady > 0.2f || (data != null && Input.IsDownOnController(Controls.Use, data))) && Input.IsDown(Controls.Use, controller) && ready)) {\n\t\t\t\t  \n\t\t\t\t\tif (!Entity.TryGetComponent<PlayerInputComponent>(out var d) || d.InDialog) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (GetComponent<StateComponent>().StateInstance is Player.SleepingState) {\n\t\t\t\t\t\tGetComponent<StateComponent>().Become<Player.IdleState>();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (Run.Depth == -2) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().Close();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (b.Has<InvisibleBuff>()) {\n\t\t\t\t\t\tb.Remove<InvisibleBuff>();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (useLamp) {\n\t\t\t\t\t\tGetComponent<ConsumablesComponent>().SpawnBomb();\n\t\t\t\t\t\tItem.Delay = 0.5f;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tItem.Use((Player) Entity);\n\t\t\t\t\t}\n\n\t\t\t\t\tGetComponent<StatsComponent>().UsedWeaponInRoom = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttimeSinceReady = 0;\n\t\t\t}\n\t\n\t\t\tif ((Input.WasPressed(Controls.Swap, controller) || (Input.Mouse.WheelDelta != 0 && stopped)) && Run.Depth > 0 && GetComponent<WeaponComponent>().Item != null) {\n\t\t\t\tif (!GetComponent<InventoryComponent>().Busy) {\n\t\t\t\t\tstopped = false;\n\t\t\t\t\tSwap();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstopped = Input.Mouse.WheelDelta == 0;\n\t\t}\n\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn item.Type == ItemType.Weapon && (Item == null || Run.Depth < 1 || Entity.GetComponent<WeaponComponent>().Item != null);\n\t\t}\n\n\t\tprotected override void OnItemSet(Item previous) {\n\t\t\tbase.OnItemSet(previous);\n\t\t\t\n\t\t\tprevious?.PutAway();\n\t\t\tItem?.TakeOut();\n\n\t\t\tif (Item != null && InGameState.Ready) {\n\t\t\t\tAudio.PlaySfx(Item.Data.WeaponType.GetSwapSfx());\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\t\t\t\t\t\t\t\t\n\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Use, false)));\n\n\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\n\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Use, true)));\n\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\tdialog.StartAndClose(\"control_2\", 5);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/ConsumablesComponent.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.input;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class ConsumablesComponent : ItemComponent {\n\t\tprivate byte bombs;\n\t\tprivate byte keys;\n\t\tprivate byte coins;\n\n\t\tpublic byte MaxCoins = 99;\n\n\t\tpublic int Bombs {\n\t\t\tset {\n\t\t\t\tvar n = (byte) MathUtils.Clamp(0, 99, value);\n\n\t\t\t\tif (n != bombs && AcceptChange(n - bombs, n, ItemType.Bomb)) {\n\t\t\t\t\tbombs = (byte) MathUtils.Clamp(0, 99, ((int) bombs + lastAmount));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tget => bombs;\n\t\t}\n\n\t\tpublic int Keys {\n\t\t\tset {\n\t\t\t\tvar n = (byte) MathUtils.Clamp(0, 99, value);\n\n\t\t\t\tif (n != keys && AcceptChange(n - keys, n, ItemType.Key)) {\n\t\t\t\t\tkeys = (byte) MathUtils.Clamp(0, 99, (int) keys + lastAmount);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tget => keys;\n\t\t}\n\t\t\n\t\tpublic int Coins {\n\t\t\tset {\n\t\t\t\tvar n = (byte) MathUtils.Clamp(0, MaxCoins, value);\n\n\t\t\t\tif (n != coins && AcceptChange(n - coins, n, ItemType.Coin)) {\n\t\t\t\t\tcoins = (byte) MathUtils.Clamp(0, MaxCoins, (int) coins + lastAmount);\n\n\t\t\t\t\tif (coins >= 99) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:rich\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tget => coins;\n\t\t}\n\n\t\tprivate int lastAmount;\n\t\t\n\t\tprivate bool AcceptChange(int amount, int totalNow, ItemType type) {\n\t\t\tvar e = amount > 0\n\t\t\t\t? (Event) new ConsumableAddedEvent {\n\t\t\t\t\tAmount = amount,\n\t\t\t\t\tTotalNow = totalNow,\n\t\t\t\t\tType = type\n\t\t\t\t}\n\t\t\t\t: new ConsumableRemovedEvent {\n\t\t\t\t\tAmount = amount,\n\t\t\t\t\tTotalNow = totalNow,\n\t\t\t\t\tType = type\n\t\t\t\t};\n\n\t\t\tlastAmount = amount;\n\n\t\t\tif (!Send(e)) {\n\t\t\t\tif (e is ConsumableAddedEvent c) {\n\t\t\t\t\tlastAmount = c.Amount;\n\t\t\t\t} else {\n\t\t\t\t\tlastAmount = ((ConsumableRemovedEvent) e).Amount;\n\t\t\t\t}\n\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool justPlayed;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemCheckEvent ev) {\n\t\t\t\tvar type = ev.Item.Type;\n\t\t\t\t\n\t\t\t\tif (type == ItemType.Bomb || type == ItemType.Key || type == ItemType.Coin || type == ItemType.Battery || type == ItemType.Pouch) {\n\t\t\t\t\t// var a = Entity.GetComponent<AudioEmitterComponent>();\n\t\t\t\t\t\n\t\t\t\t\tswitch (type) {\n\t\t\t\t\t\tcase ItemType.Bomb: {\n\t\t\t\t\t\t\tif (Run.Depth > 0 && GlobalSave.IsFalse(\"control_bomb\")) {\n\t\t\t\t\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\n\t\t\t\t\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Bomb, false)));\n\n\t\t\t\t\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\n\t\t\t\t\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Bomb, true)));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tdialog.StartAndClose(\"control_0\", 3);\n\t\t\t\t\t\t\t\tGlobalSave.Put(\"control_bomb\", true);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_bomb\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase ItemType.Key: {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_key_pickup\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase ItemType.Coin: {\n\t\t\t\t\t\t\tswitch (ev.Item.Id) {\n\t\t\t\t\t\t\t\tcase \"bk:emerald\": {\n\t\t\t\t\t\t\t\t\tif (!justPlayed) {\n\t\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"item_emerald\", 1f - Audio.Db3);\n\t\t\t\t\t\t\t\t\t\tjustPlayed = true;\n\t\t\t\t\t\t\t\t\t\tTimer.Add(() => justPlayed = false, 0.1f);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"bk:platinum_coin\": {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"item_platinum_coin\", 0.2f);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"bk:gold_coin\": {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"item_gold_coin\", 0.2f);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"bk:iron_coin\": {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"item_silver_coin\", 0.2f);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"item_coin\", 0.2f);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcase ItemType.Battery: {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_charge\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase ItemType.Pouch: {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_bag\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tSend(new ItemAddedEvent {\n\t\t\t\t\t\tItem = ev.Item,\n\t\t\t\t\t\tWho = Entity,\n\t\t\t\t\t\tComponent = this\n\t\t\t\t\t});\n\n\t\t\t\t\tvar p = (Player) Entity;\n\t\t\t\t\t\n\t\t\t\t\tev.Item.RemoveDroppedComponents();\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\tEntity.Area.Add(new ParticleEntity(Particles.Dust()) {\n\t\t\t\t\t\t\tPosition = ev.Item.Center, \n\t\t\t\t\t\t\tParticle = {\n\t\t\t\t\t\t\t\tScale = Rnd.Float(0.4f, 0.8f)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tEngine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null\n\t\t\t\t\t\t? ev.Item.GetComponent<AnimatedItemGraphicsComponent>().Animation.GetFirstCurrent()\n\t\t\t\t\t\t: ev.Item.Region, p, false, () => {\n\t\t\t\t\t\t\tev.Item.Use(p);\n\t\t\t\t\t\t\tev.Item.Done = true;\n\t\t\t\t\t\t}, ev.Item.Id == \"bk:emerald\"));\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Run.Depth > 0 && Input.WasPressed(Controls.Bomb, GetComponent<InputComponent>())) {\n\t\t\t\tSpawnBomb();\n\t\t\t}\n\t\t}\n\n\t\tpublic void SpawnBomb() {\n\t\t\tif (GetComponent<PlayerInputComponent>().InDialog) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (GetComponent<StateComponent>().StateInstance is Player.SleepingState) {\n\t\t\t\tGetComponent<StateComponent>().Become<Player.IdleState>();\n\t\t\t}\n\n\t\t\tvar spawn = false;\n\n\t\t\tif (bombs > 0) {\n\t\t\t\tBombs--;\n\n\t\t\t\tspawn = true;\n\t\t\t} else {\n\t\t\t\tvar h = GetComponent<HeartsComponent>();\n\n\t\t\t\tif (h.Bombs > 0) {\n\t\t\t\t\th.ModifyBombs(-1, Entity, true);\n\t\t\t\t\tspawn = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (spawn) {\n\t\t\t\tvar bomb = new Bomb(Entity);\n\t\t\t\tEntity.Area.Add(bomb);\n\t\t\t\tbomb.Center = Entity.Center;\n\t\t\t\tbomb.MoveToMouse();\n\t\t\t} else {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Set(Item item, bool animate = true) {\n\t\t\titem.Done = true;\n\t\t}\n\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn item.Type == ItemType.Bomb || item.Type == ItemType.Key || item.Type == ItemType.Coin || item.Type == ItemType.Pouch;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte(bombs);\n\t\t\tstream.WriteByte(keys);\n\t\t\tstream.WriteByte(coins);\n\t\t}\n\n\t\tpublic override void Load(FileReader reader) {\n\t\t\tbase.Load(reader);\n\n\t\t\tbombs = reader.ReadByte();\n\t\t\tkeys = reader.ReadByte();\n\t\t\tcoins = reader.ReadByte();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/entity/creature/player/HeartsComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class HeartsComponent : SaveableComponent {\n\t\tpublic const int Cap = 32;\n\t\tpublic const int PerRow = Cap / 2;\n\t\t\n\t\tprivate byte shieldHalfs;\n\t\tprivate byte bombs;\n\t\tprivate byte bombsMax;\n\n\t\tpublic int ShieldHalfs => shieldHalfs;\n\t\tpublic int Bombs => bombs;\n\t\t\n\t\tpublic int BombsMax {\n\t\t\tget => bombsMax;\n\t\t\tset {\n\t\t\t\tif (bombsMax == value) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar old = bombsMax;\n\t\t\t\tvar nw = value;\n\n\t\t\t\tif (!Send(new MaxHealthModifiedEvent {\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tAmount = nw - old\n\t\t\t\t})) {\n\t\t\t\t\tbombsMax = (byte) MathUtils.Clamp(0, 255, nw);\n\t\t\t\t\tbombs = Math.Min(bombs, bombsMax);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic int Total => ((int) bombs) * 2 + shieldHalfs;\n\t\tpublic int TotalMax => ((int) bombsMax) * 2 + shieldHalfs;\n\n\t\tpublic void ModifyShields(int amount, Entity setter) {\n\t\t\tvar component = GetComponent<HealthComponent>();\n\t\t\tamount = (int) (amount < 0 ? Math.Max(ShieldHalfs, amount) : Math.Min(Cap - component.MaxHealth - Total, amount));\n\n\t\t\tvar e = new HealthModifiedEvent {\n\t\t\t\tAmount = amount,\n\t\t\t\tFrom = setter,\n\t\t\t\tWho = Entity,\n\t\t\t\tDefault = false,\n\t\t\t\tHealthType = HealthType.Shield\n\t\t\t};\n\t\t\t\n\t\t\tif (amount != 0 && !Send(e)) {\n\t\t\t\tif (amount > 0) {\n\t\t\t\t\tEntity.GetComponent<HealthComponent>().EmitParticles(HealthType.Shield);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tshieldHalfs = (byte) Math.Max(0, (float) shieldHalfs + e.Amount);\n\n\t\t\t\tif (shieldHalfs > 0) {\n\t\t\t\t\tAchievements.Unlock(\"bk:shielded\");\n\t\t\t\t}\n\n\t\t\t\tSend(new PostHealthModifiedEvent {\n\t\t\t\t\tAmount = e.Amount,\n\t\t\t\t\tFrom = setter,\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tDefault = false,\n\t\t\t\t\tHealthType = HealthType.Shield\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void ModifyBombs(int amount, Entity setter, bool pr = false) {\n\t\t\tvar component = GetComponent<HealthComponent>();\n\t\t\tamount = (int) (amount < 0 ? -Math.Min(Bombs, -amount) : Math.Min(bombsMax, amount));\n\n\t\t\tvar e = new HealthModifiedEvent {\n\t\t\t\tAmount = amount,\n\t\t\t\tFrom = setter,\n\t\t\t\tWho = Entity,\n\t\t\t\tDefault = false,\n\t\t\t\tHealthType = HealthType.Bomb,\n\t\t\t\tPressedForBomb = pr\n\t\t\t};\n\t\t\t\n\t\t\tif (amount != 0 && !Send(e)) {\n\t\t\t\tif (amount > 0) {\n\t\t\t\t\tEntity.GetComponent<HealthComponent>().EmitParticles(HealthType.Bomb);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbombs = (byte) Math.Max(0, (float) bombs + e.Amount);\n\n\t\t\t\tSend(new PostHealthModifiedEvent {\n\t\t\t\t\tAmount = e.Amount,\n\t\t\t\t\tFrom = setter,\n\t\t\t\t\tWho = Entity,\n\t\t\t\t\tDefault = false,\n\t\t\t\t\tHealthType = HealthType.Bomb,\n\t\t\t\t\tPressedForBomb = pr\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic bool Hurt(int amount, Entity setter, DamageType type = DamageType.Regular) {\n\t\t\tif (amount > 0) {\n\t\t\t\tamount *= -1;\n\t\t\t}\n\t\t\t\n\t\t\tvar e = new HealthModifiedEvent {\n\t\t\t\tAmount = amount,\n\t\t\t\tType = type,\n\t\t\t\tFrom = setter,\n\t\t\t\tWho = Entity,\n\t\t\t\tDefault = false,\n\t\t\t\tHealthType = shieldHalfs > 0 ? HealthType.Shield : HealthType.Bomb\n\t\t\t};\n\t\t\t\n\t\t\tif (!Send(e)) {\n\t\t\t\tif (shieldHalfs > 0) {\n\t\t\t\t\tvar iron = Math.Min(e.Amount, shieldHalfs);\n\t\t\t\t\tshieldHalfs = (byte) Math.Max(0, shieldHalfs + iron);\n\n\t\t\t\t\tSend(new PostHealthModifiedEvent {\n\t\t\t\t\t\tAmount = e.Amount,\n\t\t\t\t\t\tFrom = setter,\n\t\t\t\t\t\tType = type,\n\t\t\t\t\t\tWho = Entity,\n\t\t\t\t\t\tDefault = false,\n\t\t\t\t\t\tHealthType = HealthType.Shield\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t} else if (bombs > 0) {\n\t\t\t\t\tvar iron = Math.Min(e.Amount, bombs);\n\t\t\t\t\tbombs = (byte) Math.Max(0, bombs + iron);\n\n\t\t\t\t\tSend(new PostHealthModifiedEvent {\n\t\t\t\t\t\tAmount = e.Amount,\n\t\t\t\t\t\tFrom = setter,\n\t\t\t\t\t\tType = type,\n\t\t\t\t\t\tWho = Entity,\n\t\t\t\t\t\tDefault = false,\n\t\t\t\t\t\tHealthType = HealthType.Bomb\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic bool CanHaveMore => Total + GetComponent<HealthComponent>().MaxHealth < Cap;\n\t\t\t\t\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte(shieldHalfs);\n\t\t\tstream.WriteByte(bombs);\n\t\t\tstream.WriteByte(bombsMax);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tshieldHalfs = stream.ReadByte();\n\t\t\tbombs = stream.ReadByte();\n\t\t\tbombsMax = stream.ReadByte();\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tbase.RenderDebug();\n\t\t\t\n\t\t\tImGui.Text($\"Iron halfs: {shieldHalfs}\");\n\t\t\tvar v = (int) bombsMax;\n\n\t\t\tif (ImGui.InputInt(\"Bombs Max\", ref v)) {\n\t\t\t\tbombsMax = (byte) v;\n\t\t\t}\n\t\t\t\n\t\t\tv = (int) bombs;\n\n\t\t\tif (ImGui.InputInt(\"Bombs\", ref v)) {\n\t\t\t\tbombs = (byte) v;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/InteractorComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Security.AccessControl;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.input;\nusing Lens.util;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class InteractorComponent : Component {\n\t\tpublic Entity CurrentlyInteracting;\n\t\tpublic List<Entity> InteractionCandidates = new List<Entity>();\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (CurrentlyInteracting != null && Input.WasPressed(Controls.Interact, GetComponent<InputComponent>()) && !GetComponent<InventoryComponent>().Busy) {\n\t\t\t\tif (Run.Depth == -2 && GlobalSave.IsFalse(\"control_interact\")) {\n\t\t\t\t\tGlobalSave.Put(\"control_interact\", true);\n\t\t\t\t\tEntity.GetComponent<DialogComponent>().Close();\n\t\t\t\t}\n\n\t\t\t\tif (CurrentlyInteracting.GetComponent<InteractableComponent>().Interact(Entity)) {\n\t\t\t\t\tSend(new InteractedEvent {\n\t\t\t\t\t\tWho = Entity,\n\t\t\t\t\t\tWith = CurrentlyInteracting\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tEndInteraction();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void EndInteraction() {\n\t\t\tif (CurrentlyInteracting.TryGetComponent<InteractableComponent>(out var component)) {\n\t\t\t\tcomponent.OnEnd?.Invoke(Entity);\n\t\t\t\tcomponent.CurrentlyInteracting = null;\n\t\t\t}\n\t\t\t\n\t\t\tif (InteractionCandidates.Count == 0) {\n\t\t\t\tCurrentlyInteracting = null;\n\t\t\t} else {\n\t\t\t\tCurrentlyInteracting = InteractionCandidates[0];\n\t\t\t\tInteractionCandidates.RemoveAt(0);\n\t\t\t\tOnStart();\n\t\t\t}\n\t\t}\n\n\t\tprivate void OnStart() {\n\t\t\tif (!CurrentlyInteracting.TryGetComponent<InteractableComponent>(out var component)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcomponent.CurrentlyInteracting = Entity;\n\t\t\tcomponent.OnStart?.Invoke(Entity);\n\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\tvar hasGamepad = GamepadComponent.Current != null && GamepadComponent.Current.Attached;\n\t\t\t\t\n\t\t\t\tvar region = CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Interact, false));\n\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(CurrentlyInteracting, null, region, hasGamepad ? -5 : 0));\n\n\t\t\t\tif (hasGamepad) {\n\t\t\t\t\tregion = CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Interact, true));\n\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(CurrentlyInteracting, null, region, 5));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent start) {\n\t\t\t\tif (start.Body.CanCollide && CanInteract(start.Entity)) {\n\t\t\t\t\tvar entity = start.Entity.GetComponent<InteractableComponent>().AlterInteraction?.Invoke() ?? start.Entity;\n\n\t\t\t\t\tif (CurrentlyInteracting != entity) {\n\t\t\t\t\t\tif (CurrentlyInteracting != null) {\n\t\t\t\t\t\t\tif (!InteractionCandidates.Contains(entity)) {\n\t\t\t\t\t\t\t\tInteractionCandidates.Add(entity);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tCurrentlyInteracting = entity;\n\t\t\t\t\t\t\tOnStart();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent end && end.Body.CanCollide) {\n\t\t\t\tif (CurrentlyInteracting == end.Entity) {\n\t\t\t\t\tEndInteraction();\n\t\t\t\t} else {\n\t\t\t\t\tInteractionCandidates.Remove(end.Entity);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic Func<Entity, bool> CanInteractCallback;\n\t\t\n\t\tpublic virtual bool CanInteract(Entity e) {\n\t\t\treturn e.TryGetComponent<InteractableComponent>(out var component) && (component.CanInteract?.Invoke(Entity) ?? true) && (CanInteractCallback == null || CanInteractCallback(e));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/LampComponent.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.debug;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.pet;\nusing BurningKnight.entity.item;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class LampComponent : ItemComponent {\n\t\tprivate FollowerPet pet;\n\t\tprivate bool loaded;\n\t\tprivate bool hadLamp;\n\t\tprivate Item prev;\n\t\t\n\t\tpublic override void Set(Item item, bool animate = true) {\n\t\t\tbase.Set(item, (item == null || item.Id != \"bk:no_lamp\") && animate);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tloaded = true;\n\n\t\t\tif (Item == null) {\n\t\t\t\tSet(Items.CreateAndAdd(\"bk:no_lamp\", Entity.Area), false);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnItemSet(Item previous) {\n\t\t\tbase.OnItemSet(previous);\n\n\t\t\tif (pet != null) {\n\t\t\t\tif (pet.TryGetComponent<FollowerComponent>(out var f)) {\n\t\t\t\t\tf.Remove();\n\t\t\t\t} else {\n\t\t\t\t\tpet.GetComponent<OrbitalComponent>().Orbiting.GetComponent<OrbitGiverComponent>().RemoveOrbiter(pet);\n\t\t\t\t}\n\n\t\t\t\tpet.Done = true;\n\t\t\t\tpet = null;\n\t\t\t}\n\n\t\t\tif (prev != null && prev.Id != \"bk:no_lamp\") {\n\t\t\t\tEntity.RemoveComponent<HealthComponent>();\n\t\t\t\tEntity.RemoveComponent<HeartsComponent>();\n\t\t\t\tEntity.RemoveComponent<InventoryComponent>();\n\t\t\t\t\n\t\t\t\tEntity.AddComponent(new HealthComponent());\n\n\t\t\t\tvar hp = Entity.GetComponent<HealthComponent>();\n\t\t\t\t\t\n\t\t\t\thp.InitMaxHealth = 6;\n\t\t\t\thp.SaveMaxHp = true;\n\t\t\t\thp.MaxHealthCap = 32;\n\t\t\t\thp.InvincibilityTimerMax = 1f;\n\n\t\t\t\tif (CheatWindow.AutoGodMode) {\n\t\t\t\t\tLog.Info(\"Entering god mode for the player\");\n\t\t\t\t\thp.Unhittable = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEntity.AddComponent(new HeartsComponent());\n\t\t\t\tEntity.AddComponent(new InventoryComponent());\n\t\t\t\t\n\t\t\t\tif (Entity.TryGetComponent<WeaponComponent>(out var w)) {\n\t\t\t\t\tw.Disabled = false;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (Entity.TryGetComponent<ActiveWeaponComponent>(out var aw)) {\n\t\t\t\t\taw.Disabled = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprev = Item;\n\t\t\t\n\t\t\tif (loaded) {\n\t\t\t\tItem?.Use(Entity);\n\t\t\t\thadLamp = true;\n\t\t\t}\n\n\t\t\tif (Item == null || Item.Id == \"bk:no_lamp\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tpet = new LampPet(Item.Id) {\n\t\t\t\tOwner = Entity\n\t\t\t};\n\n\t\t\tEntity.Area.Add(pet);\n\t\t\tpet.Center = Entity.Center + MathUtils.CreateVector(Rnd.AnglePI(), Rnd.Float(16f, 48f));\n\t\t\tAnimationUtil.Poof(pet.Center);\n\t\t}\n\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn item.Type == ItemType.Lamp;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/LocalPlayer.cs",
    "content": "﻿using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class LocalPlayer : Player {\n\t\tpublic static LocalPlayer Locate(Area area) {\n\t\t\tforeach (var player in area.Tagged[Tags.Player]) {\n\t\t\t\tif (player is LocalPlayer localPlayer) {\n\t\t\t\t\treturn localPlayer;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new GamepadComponent());\n\t\t\tAddComponent(new PlayerInputComponent());\n\t\t}\n\n\t\tprivate bool died;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DiedEvent ev && ev.Who == this) {\n\t\t\t\tif (!GetComponent<HealthComponent>().Dead && !died) {\n\t\t\t\t\tdied = true;\n\t\t\t\t\tDone = false;\n\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"player_death\");\n\t\t\t\t\tRemoveComponent<PlayerInputComponent>();\n\t\t\t\t\t\n\t\t\t\t\tAchievements.Unlock(\"bk:rip\");\n\t\t\t\t\tItems.Unlock(\"bk:dagger\");\n\n\t\t\t\t\tvar body = GetComponent<RectBodyComponent>();\n\n\t\t\t\t\tbody.KnockbackModifier = 0;\n\t\t\t\t\tbody.Velocity = Vector2.Zero;\n\n\t\t\t\t\tif (InGameState.EveryoneDied(this)) {\n\t\t\t\t\t\tAudio.FadeOut();\n\n\t\t\t\t\t\t((InGameState) Engine.Instance.State).HandleDeath();\n\n\t\t\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\t\t\tCamera.Instance.Follow(this, 1);\n\n\t\t\t\t\t\tTween.To(0.3f, Engine.Instance.Speed, x => Engine.Instance.Speed = x, 0.5f).OnEnd = () => {\n\t\t\t\t\t\t\tvar t = Tween.To(1, Engine.Instance.Speed, x => Engine.Instance.Speed = x, 0.5f);\n\n\t\t\t\t\t\t\tt.Delay = 0.8f;\n\t\t\t\t\t\t\tt.OnEnd = () => ((InGameState) Engine.Instance.State).AnimateDoneScreen(this);\n\n\t\t\t\t\t\t\tHandleEvent(e);\n\t\t\t\t\t\t\tAnimateDeath(ev);\n\n\t\t\t\t\t\t\tDone = true;\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tHandleEvent(e);\n\t\t\t\t\t\tAnimateDeath(ev);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else if (e is PostHealthModifiedEvent hp && hp.Amount < 0 && !hp.PressedForBomb) {\n\t\t\t\tEngine.Instance.Split = 1f;\n\t\t\t\tEngine.Instance.Flash = 1f;\n\t\t\t\tEngine.Instance.Freeze = 1f;\n\t\t\t\t\n\t\t\t\tCamera.Instance.Shake(4);\n\n\t\t\t\tif (Camera.Instance != null && Settings.Flashes) {\n\t\t\t\t\tCamera.Instance.TextureZoom -= 0.2f;\n\t\t\t\t\tTween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.3f);\t\t\t\t\t\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/Player.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.debug;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.twitch;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class Player : Creature, DropModifier {\n\t\tprivate static Color tint = new Color(50, 234, 60, 200);\n\n\t\tpublic const int MaxPlayers = 5;\n\n\t\tpublic static Color[] IndexTints = {\n\t\t\tPalette.Default[59],\n\t\t\tPalette.Default[42],\n\t\t\tPalette.Default[35],\n\t\t\tPalette.Default[55],\n\t\t\tPalette.Default[31]\n\t\t};\n\n\t\tpublic static Vector4[] VectorTints;\n\n\t\tstatic Player() {\n\t\t\tVectorTints = new Vector4[MaxPlayers];\n\t\t\t\n\t\t\tfor (var i = 0; i < MaxPlayers; i++) {\n\t\t\t\tvar color = IndexTints[i];\n\t\t\t\tVectorTints[i] = new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic Color Tint => IndexTints[GetComponent<InputComponent>().Index];\n\t\t\n\t\tpublic static int Quacks;\n\t\tpublic static bool ToBoss;\n\t\tpublic static bool InBuilding;\n\t\tpublic static Color LightColor = new Color(1f, 0.8f, 0.6f, 1f);\n\t\t\n\t\tpublic static string[] StartingWeapons = new string[MaxPlayers];\n\t\tpublic static string[] StartingItems = new string[MaxPlayers];\n\t\tpublic static string[] StartingLamps = new string[MaxPlayers];\n\t\tpublic static List<string> DailyItems;\n\t\tpublic string ProjectileTexture = \"rect\";\n\n\t\tpublic bool ItemDamage;\n\t\tpublic bool Sliding;\n\n\t\tpublic bool Dead;\n\n\t\tpublic void AnimateItemPickup(Item item, Action action = null, bool add = true, bool ban = true) {\n\t\t\tif (ban) {\n\t\t\t\tvar banner = new UiDescriptionBanner();\n\t\t\t\tbanner.Show(item);\n\t\t\t\tEngine.Instance.State.Ui.Add(banner);\n\t\t\t}\n\n\t\t\tif (item.Type == ItemType.Weapon && Run.Depth == 0) {\n\t\t\t\tAudio.PlaySfx(item.Data.WeaponType.GetPickupSfx());\n\t\t\t} else {\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"item_pickup\");\n\t\t\t}\n\n\t\t\tif (add || item.Type == ItemType.Lamp || item.Type == ItemType.Active || item.Type == ItemType.ConsumableArtifact || item.Type == ItemType.Weapon || item.Type == ItemType.Hat) {\n\t\t\t\tGetComponent<InventoryComponent>().Busy = true;\n\t\t\t\t\n\t\t\t\tEngine.Instance.State.Ui.Add(new ConsumableParticle(item.Region, this, item.Type != ItemType.Active, () => {\n\t\t\t\t\titem.Area?.Remove(item);\n\t\t\t\t\titem.Done = false;\n\t\t\t\t\t\n\t\t\t\t\taction?.Invoke();\n\t\t\t\t\tGetComponent<InventoryComponent>().Busy = false;\n\n\t\t\t\t\tif (item.Type != ItemType.ConsumableArtifact && item.Type != ItemType.Active && item.Type != ItemType.Weapon && item.Type != ItemType.Hat && item.Type != ItemType.Lamp) {\n\t\t\t\t\t\tGetComponent<InventoryComponent>().Add(item);\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddComponent(new InputComponent());\n\t\t\tAddComponent(new CursorComponent());\n\t\t\t\n\t\t\tInBuilding = false;\n\t\t\tGetComponent<HealthComponent>().SaveMaxHp = true;\n\t\t\t\n\t\t\tHeight = 11;\n\t\t\t\n\t\t\t// Graphics\n\t\t\tif (Run.Depth != 0) {\n\t\t\t\tAddComponent(new LightComponent(this, 64, LightColor));\n\t\t\t}\n\n\t\t\tAddComponent(new PlayerGraphicsComponent {\n\t\t\t\tOffset = new Vector2(0, -5)\n\t\t\t});\n\t\t\t\n\t\t\t// Inventory\n\t\t\tAddComponent(new LampComponent());\n\t\t\tAddComponent(new InventoryComponent());\n\t\t\tAddComponent(new ActiveItemComponent());\n\t\t\tAddComponent(new ActiveWeaponComponent());\n\t\t\tAddComponent(new WeaponComponent());\n\t\t\tAddComponent(new ConsumablesComponent());\n\t\t\tAddComponent(new HatComponent());\n\t\t\t\n\t\t\t// Stats\n\t\t\tAddComponent(new ManaComponent());\n\t\t\tAddComponent(new HeartsComponent());\n\t\t\tAddComponent(new StatsComponent());\n\n\t\t\t// Collisions\n\t\t\tAddComponent(new RectBodyComponent(4, Height - 1, 8, 1) {\n\t\t\t\tCanCollide = false\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(2, 1, Width - 4, Height - 1, BodyType.Dynamic, true));\n\t\t\tGetComponent<SensorBodyComponent>().Body.SleepingAllowed = false;\n\t\t\t\n\t\t\tAddComponent(new InteractorComponent {\n\t\t\t\tCanInteractCallback = e => !died && !GetComponent<InventoryComponent>().Busy\n\t\t\t});\n\n\t\t\t// Other mechanics\n\t\t\tAddComponent(new OrbitGiverComponent());\n\t\t\tAddComponent(new FollowerComponent());\n\t\t\tAddComponent(new AimComponent(AimComponent.AimType.Cursor));\n\t\t\tAddComponent(new DialogComponent());\n\t\t\t\n\t\t\tAddComponent(new ZComponent());\n\t\t\t\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\n\t\t\tAddTag(Tags.Player);\n\t\t\tAddTag(Tags.PlayerTarget);\n\t\t\tAddTag(Tags.PlayerSave);\n\t\t\tRemoveTag(Tags.LevelSave);\n\n\t\t\tAlwaysActive = true;\n\n\t\t\tInitStats(true);\n\t\t\t\n\t\t\tSubscribe<NewFloorEvent>();\n\t\t}\n\n\t\tpublic void InitStats(bool fromInit = false) {\n\t\t\tHasFlight = false;\n\t\t\tSuperHot = false;\n\n\t\t\tScourge.Clear();\n\n\t\t\tGetComponent<AimComponent>().ShowLaserLine = false;\n\t\t\tGetComponent<OrbitGiverComponent>().DestroyAll();\n\t\t\tGetComponent<FollowerComponent>().DestroyAll();\n\n\t\t\tvar hp = GetComponent<HealthComponent>();\n\n\t\t\tif (fromInit) {\n\t\t\t\thp.InitMaxHealth = 6;\n\t\t\t}\n\n\t\t\thp.MaxHealthCap = 32;\n\t\t\thp.InvincibilityTimerMax = 1f;\n\n\t\t\tif (CheatWindow.AutoGodMode) {\n\t\t\t\tLog.Info(\"Entering god mode for the player\");\n\t\t\t\thp.Unhittable = true;\n\t\t\t}\n\t\t}\n\n\t\tprivate int lastDepth = -3;\n\n\t\tpublic void FindSpawnPoint() {\n\t\t\tif (Run.StartedNew && Run.Depth > 0) {\n\t\t\t\tTwitchBridge.OnNewRun?.Invoke();\n\n\t\t\t\tvar index = GetComponent<InputComponent>().Index;\n\t\t\t\t\n\t\t\t\tif (StartingLamps[index] != null) {\n\t\t\t\t\tvar i = Items.CreateAndAdd(StartingLamps[index], Area);\n\t\t\t\t\ti.Scourged = false;\n\t\t\t\t\tGetComponent<LampComponent>().Set(i, false);\n\t\t\t\t\tLog.Debug($\"Starting lamp: {StartingLamps[index]}\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (StartingWeapons[index] == null || !ItemPool.StartingWeapon.Contains(Items.Datas[StartingWeapons[index]].Pools)) {\n\t\t\t\t\tStartingWeapons[index] = Items.Generate(ItemPool.StartingWeapon, item => Item.Unlocked(item.Id));\n\t\t\t\t}\n\n\t\t\t\tif (StartingWeapons[index] != null) {\n\t\t\t\t\tvar i = Items.CreateAndAdd(StartingWeapons[index], Area);\n\t\t\t\t\ti.Scourged = false;\n\n\t\t\t\t\tvar l = GetComponent<LampComponent>().Item;\n\n\t\t\t\t\tif (l != null && l.Id == \"bk:sharp_lamp\" && i.Data.WeaponType != WeaponType.Melee) {\n\t\t\t\t\t\tStartingWeapons[index] = Items.Generate(ItemPool.StartingWeapon, item => Item.Unlocked(item.Id));\n\t\t\t\t\t\ti.Done = true;\n\t\t\t\t\t\ti = Items.CreateAndAdd(StartingWeapons[index], Area);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tGetComponent<ActiveWeaponComponent>().Set(i, false);\n\t\t\t\t\tLog.Debug($\"Starting weapon: {StartingWeapons[index]}\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (StartingItems[index] != null) {\n\t\t\t\t\tvar i = Items.CreateAndAdd(StartingItems[index], Area);\n\t\t\t\t\ti.Scourged = false;\n\t\t\t\t\tGetComponent<ActiveItemComponent>().Set(i, false);\n\t\t\t\t\t\n\t\t\t\t\tLog.Debug($\"Starting item: {StartingItems[index]}\");\n\t\t\t\t}\n\n\t\t\t\tif (DailyItems != null) {\n\t\t\t\t\tif (Run.Type == RunType.Daily) {\n\t\t\t\t\t\tvar inventory = GetComponent<InventoryComponent>();\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var id in DailyItems) {\n\t\t\t\t\t\t\tLog.Info($\"Giving {id}\");\n\t\t\t\t\t\t\tinventory.Pickup(Items.CreateAndAdd(id, Area), false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tDailyItems = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfindASpawn = true;\n\n\t\t\tif (lastDepth == Run.Depth) {\n\t\t\t\tLog.Info(\"Old depth is the same as the current one\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlastDepth = Run.Depth;\n\t\t\t\n\t\t\tif (Run.Depth > 1 && !GetComponent<StatsComponent>().TookDamageOnLevel) {\n\t\t\t\tAchievements.Unlock(\"bk:dodge_overlord\");\n\t\t\t}\n\t\t\t\n\t\t\tHandleEvent(new NewLevelStartedEvent());\n\t\t}\n\n\t\tprivate bool set;\n\t\tprivate float t;\n\t\tprivate bool findASpawn;\n\t\tpublic bool Teleported;\n\n\t\tprivate bool FindSpawn() {\n\t\t\tif (/*BK.Version.Dev || */ToBoss) {\n\t\t\t\tToBoss = false;\n\t\t\t\t\n\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\t\tvar rm = (Room) r;\n\n\t\t\t\t\tif (rm.Type == RoomType.Boss) {\n\t\t\t\t\t\tCenter = r.Center + new Vector2(0, 32) + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\t\t\trm.Discover();\n\t\t\t\t\t\tLog.Debug(\"Teleported to boss room\");\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var cc in Area.Tagged[Tags.Checkpoint]) {\n\t\t\t\tCenter = cc.Center + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\tLog.Debug(\"Teleported to spawn point\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tforeach (var cc in Area.Tagged[Tags.Entrance]) {\n\t\t\t\tCenter = cc.Center + new Vector2(0, 4) + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\tLog.Debug(\"Teleported to entrance\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\tvar rm = (Room) r;\n\n\t\t\t\tif (rm.Type == RoomType.Entrance) {\n\t\t\t\t\tCenter = r.Center + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\t\trm.Discover();\n\t\t\t\t\tLog.Debug(\"Teleported to entrance room\");\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\tvar rm = (Room) r;\n\n\t\t\t\tif (rm.Type == RoomType.Exit) {\n\t\t\t\t\tLog.Debug(\"Teleported to exit room\");\n\t\t\t\t\tCenter = new Vector2(rm.CenterX, rm.Bottom - 1.4f * 16) + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\t\trm.Discover();\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\tvar rm = (Room) r;\n\n\t\t\t\tLog.Debug(\"Teleported to random room\");\n\t\t\t\tCenter = new Vector2(rm.CenterX, rm.Bottom - 1.4f * 16) + Rnd.Vector(-0.5f, 0.5f);\n\t\t\t\trm.Discover();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tLog.Error(\"Failed to teleport!\");\n\t\t\tAnimationUtil.Poof(Center, 20);\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tif (findASpawn) {\n\t\t\t\tif (FindSpawn()) {\n\t\t\t\t\tTeleported = true;\n\t\t\t\t\tfindASpawn = false;\n\t\t\t\t\t\n\t\t\t\t\tif (!CheatWindow.AutoGodMode) {\n\t\t\t\t\t\tGetComponent<HealthComponent>().Unhittable = false;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tLog.Error(\"Did not find a spawn point!\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\n\t\t\tif (!set && t >= 0.3f) {\n\t\t\t\tset = true;\n\t\t\t\tGetComponent<RoomComponent>().Room?.Discover();\n\n\t\t\t\tif (Run.Depth == 0) {\n\t\t\t\t\tCageLock.CheckProgress();\n\t\t\t\t\tHatStand.CheckHats();\n\t\t\t\t\tItems.CheckForCollector();\n\t\t\t\t\tBuilder.CheckShortcutUnlocks();\n\n\t\t\t\t\tif (Assets.FailedToLoadAudio) {\n\t\t\t\t\t\tAssets.FailedToLoadAudio = false;\n\t\t\t\t\t\t((InGameState) Engine.Instance.State).TopUi.Add(new UiError(\"Audio Failed\",\t\"Failed to init audio device\"));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t#region Player States\n\t\tpublic class IdleState : EntityState {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!CheatWindow.NoSleep && T >= 6f && Self.HasComponent<PlayerInputComponent>()) {\n\t\t\t\t\tBecome<SittingState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class SittingState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<PlayerGraphicsComponent>().Animate();\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\t\n\t\t\t\tvar pr = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\t\tpr.EnableClip = false;\n\t\t\t\tSelf.GetComponent<PlayerGraphicsComponent>().Animate();\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= 24f && Self.HasComponent<PlayerInputComponent>()) {\n\t\t\t\t\tBecome<SleepingState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class SleepingState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<PlayerGraphicsComponent>().Animate();\n\t\t\t}\n\t\t\t\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<PlayerGraphicsComponent>().Animate();\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (T >= 3f) {\n\t\t\t\t\tT = 0;\n\n\t\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float,\n\t\t\t\t\t\t\t\t\tnew TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"sleep\"))));\n\n\t\t\t\t\t\t\t\tpart.Position = Self.Center;\n\n\t\t\t\t\t\t\t\tif (Self.TryGetComponent<ZComponent>(out var z)) {\n\t\t\t\t\t\t\t\t\tpart.Position -= new Vector2(0, z.Z);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tSelf.Area.Add(part);\n\n\t\t\t\t\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56));\n\t\t\t\t\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\t\t\t\t\tpart.Particle.Alpha = 0.9f;\n\t\t\t\t\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t\t\t\t\t}, i * 0.5f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class DuckState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tQuacks++;\n\t\t\t\tif (Quacks >= 150) {\n\t\t\t\t\tAchievements.Unlock(\"bk:quackers\");\n\t\t\t\t}\n\n\t\t\t\tvar hat = Self.GetComponent<HatComponent>().Item;\n\n\t\t\t\tif (hat != null && (hat.Id == \"bk:villager_head\" || hat.Id == \"bk:stone_hat\")) {\n\t\t\t\t\tAudio.PlaySfx($\"villager{Rnd.Int(1, 5)}\", 1f, Rnd.Float(-0.5f, 0.5f));\n\t\t\t\t} else {\n\t\t\t\t\tAudio.PlaySfx(\"quck\", 1f, Rnd.Float(-0.5f, 0.5f));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.HandleEvent(new QuackEvent {\n\t\t\t\t\tPlayer = (Player) Self\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<RectBodyComponent>().Velocity.Length() > 10f) {\n\t\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\t\tAnimationUtil.Poof(Self.Center);\n\t\t\t\t\t\tT = 0;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tT = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class RunState : SmartState<Player> {\n\t\t\tprivate float lastParticle = 0.25f;\n\t\t\tprivate uint lastFrame;\n\t\t\t\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tlastParticle -= dt;\n\n\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\tlastParticle = 0.25f;\n\t\t\t\t\t\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\n\t\t\t\t\tpart.Position = Self.Center;\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\tSelf.Area.Add(part);\n\t\t\t\t}\n\n\t\t\t\tif (!Self.HasFlight) {\n\t\t\t\t\tvar anim = Self.GetComponent<PlayerGraphicsComponent>().Animation;\n\n\t\t\t\t\tif (anim.Frame != lastFrame) {\n\t\t\t\t\t\tlastFrame = anim.Frame;\n\n\t\t\t\t\t\tif (Run.Level != null && (lastFrame == 2 || lastFrame == 6)) {\n\t\t\t\t\t\t\tvar x = (int) (Self.CenterX / 16);\n\t\t\t\t\t\t\tvar y = (int) (Self.Bottom / 16);\n\n\t\t\t\t\t\t\tif (!Run.Level.IsInside(x, y)) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar i = Run.Level.ToIndex(x, y);\n\t\t\t\t\t\t\tvar tile = Run.Level.Get(i);\n\t\t\t\t\t\t\tvar liquid = Run.Level.Liquid[i];\n\t\t\t\t\t\t\tvar room = Self.GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\t\t\tAudio.PlaySfx(Run.Level.Biome.GetStepSound(liquid == 0 ? tile : (Tile) liquid),\n\t\t\t\t\t\t\t\troom != null && room.Tagged[Tags.MustBeKilled].Count > 0 ? 0.18f : 0.25f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tpublic class PostRollState : EntityState {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (T >= 0.2f) {\n\t\t\t\t\tSelf.GetComponent<RectBodyComponent>().Acceleration = Vector2.Zero;\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class RollState : EntityState {\n\t\t\tprivate const float RollTime = 0.25f;\n\t\t\tprivate const float RollForce = 1600f;\n\t\t\t\n\t\t\tprivate float lastParticle = 0.05f;\n\t\t\tprivate Vector2 direction;\n\t\t\tprivate bool wasUnhittable;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tvar z = Self.GetComponent<ZComponent>();\n\t\t\t\tvar start = z.Z;\n\n\t\t\t\tTween.To(start + 8, start, x => z.Z = x, 0.15f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\tTween.To(start, z.Z, x => z.Z = x, 0.15f, Ease.QuadIn);\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"player_roll\", 0.5f);\n\t\t\t\tvar hp = Self.GetComponent<HealthComponent>();\n\n\t\t\t\twasUnhittable = hp.Unhittable;\n\t\t\t\thp.Unhittable = true;\n\n\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\t\t\t\tvar angle = body.Acceleration.LengthSquared() > 0.1f \n\t\t\t\t\t?\tbody.Acceleration.ToAngle()\n\t\t\t\t\t: (Camera.Instance.ScreenToCamera(Input.Mouse.ScreenPosition) - Self.Center).ToAngle();\n\n\t\t\t\tdirection = new Vector2((float) Math.Cos(angle) * RollForce, (float) Math.Sin(angle) * RollForce);\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = Self.Center;\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\tSelf.Area.Add(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<HealthComponent>().Unhittable = wasUnhittable;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (T >= RollTime) {\n\t\t\t\t\tBecome<PostRollState>();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar body = Self.GetComponent<RectBodyComponent>();\n\t\t\t\tbody.Velocity += direction * (RollTime - T * 0.5f);\n\t\t\t\tbody.Position += body.Velocity * dt * 0.1f;\n\n\t\t\t\tlastParticle -= dt;\n\n\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\tlastParticle = 0.1f;\n\t\t\t\t\t\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = Self.Center;\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\tSelf.Area.Add(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic void ChangeDirection() {\n\t\t\t\tdirection *= -1;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\tif (HasFlight && entity is HalfWall) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn !(entity is Player || entity is HalfProjectileLevel || entity is ProjectileLevelBody || ((entity is ItemStand || entity is Bomb) && InAir())) && base.ShouldCollide(entity);\n\t\t}\n\n\t\tpublic bool HasFlight;\n\t\tpublic bool SuperHot;\n\n\t\tpublic override bool InAir() {\n\t\t\treturn HasFlight || base.InAir() || GetComponent<StateComponent>().StateInstance is RollState;\n\t\t}\n\t\t\n\t\tpublic override bool HasNoHealth(HealthModifiedEvent e = null) {\n\t\t\treturn base.HasNoHealth(e) && GetComponent<HeartsComponent>().Total == 0;\n\t\t}\n\t\t\n\t\tpublic override bool HasNoHealth(PostHealthModifiedEvent e = null) {\n\t\t\treturn base.HasNoHealth(e) && GetComponent<HeartsComponent>().Total == 0;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is LostSupportEvent) {\n\t\t\t\tif (GetComponent<HealthComponent>().Unhittable) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (!GetComponent<BuffsComponent>().PitImmunity) {\n\t\t\t\t\tGetComponent<HealthComponent>().ModifyHealth(-1, Run.Level);\n\t\t\t\t}\n\t\t\t\t\n\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = Center;\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\tArea.Add(part);\n\t\t\t\t}\n\t\t\t} else if (e is RoomChangedEvent c) {\n\t\t\t\tif (c.New == null || Run.Level == null || Camera.Instance == null) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (c.New.Tagged[Tags.MustBeKilled].Count > 0) {\n\t\t\t\t\tAudio.PlaySfx(\"level_door_shut\");\n\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\tif (p.GetComponent<RoomComponent>().Room != c.New) {\n\t\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\t\t\t\t\t\t\tp.Center = Center;\n\t\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\n\t\t\t\tvar pr = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\n\t\t\t\tif (c.Old != null) {\n\t\t\t\t\tif (Scourge.IsEnabled(Scourge.OfLost)) {\n\t\t\t\t\t\tc.Old.Hide();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (c.Old.Type == RoomType.DarkMarket || c.Old.Type == RoomType.Hidden) {\n\t\t\t\t\t\tpr.EnableClip = false;\n\t\t\t\t\t\tc.Old.Hide(true);\n\t\t\t\t\t\tInBuilding = false;\n\t\t\t\t\t\t((InGameState) Engine.Instance.State).UpdateRainVolume();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (c.New.Type == RoomType.DarkMarket) {\n\t\t\t\t\tAchievements.Unlock(\"bk:dark_market\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (c.New.Type == RoomType.DarkMarket || c.New.Type == RoomType.Hidden) {\n\t\t\t\t\tpr.EnableClip = true;\n\t\t\t\t\tpr.ClipPosition = new Vector2(c.New.X + 16, c.New.Y + 16);\n\t\t\t\t\tpr.ClipSize = new Vector2(c.New.Width - 16, c.New.Height - 32);\n\t\t\t\t\tInBuilding = true;\n\t\t\t\t\t((InGameState) Engine.Instance.State).UpdateRainVolume();\n\t\t\t\t} else {\n\t\t\t\t\tpr.EnableClip = false;\n\t\t\t\t}\n\n\t\t\t\tif (c.New.Type == RoomType.Shop) {\n\t\t\t\t\tAudio.PlaySfx(\"level_door_bell\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tc.New.Discover();\n\t\t\t\tvar level = Run.Level;\n\n\t\t\t\tif (InGameState.Ready) {\n\t\t\t\t\tswitch (c.New.Type) {\n\t\t\t\t\t\tcase RoomType.Secret:\n\t\t\t\t\t\tcase RoomType.Special:\n\t\t\t\t\t\tcase RoomType.Shop:\n\t\t\t\t\t\tcase RoomType.SubShop:\n\t\t\t\t\t\tcase RoomType.Treasure: {\n\t\t\t\t\t\t\tforeach (var door in c.New.Doors) {\n\t\t\t\t\t\t\t\tif (door.TryGetComponent<LockComponent>(out var component) && component.Lock is GoldLock) {\n\t\t\t\t\t\t\t\t\tif (!(c.New.Type == RoomType.Shop && ((door.Rooms[0] != null && door.Rooms[0].Type == RoomType.SubShop) ||\n\t\t\t\t\t\t\t\t\t                                    (door.Rooms[1] != null && door.Rooms[1].Type == RoomType.SubShop)))) {\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tcomponent.Lock.SetLocked(false, this);\n\t\t\t\t\t\t\t\t\t} \n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase RoomType.OldMan:\n\t\t\t\t\t\tcase RoomType.Granny: {\n\t\t\t\t\t\t\tif (c.New.Type == RoomType.OldMan) {\n\t\t\t\t\t\t\t\tGetComponent<StatsComponent>().SawDeal = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tc.New.OpenHiddenDoors();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\t\t\t\t\tvar room = (Room) r;\n\n\t\t\t\t\t\t\t\tif (room.Type == (c.New.Type == RoomType.OldMan ? RoomType.Granny : RoomType.OldMan)) {\n\t\t\t\t\t\t\t\t\troom.CloseHiddenDoors();\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (c.New.Type == RoomType.Secret) {\n\t\t\t\t\t\tExplosionMaker.CheckForCracks(level, c.New, this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (c.Old != null) {\n\t\t\t\t\tif (c.Old.Type == RoomType.OldMan) {\n\t\t\t\t\t\tvar found = false;\n\n\t\t\t\t\t\tforeach (var p in c.Old.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tif (p != this && p is Player) {\n\t\t\t\t\t\t\t\tfound = true;\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!found) {\n\t\t\t\t\t\t\tc.Old.CloseHiddenDoors();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (c.Old.Type == RoomType.Treasure && Run.Type != RunType.BossRush && !Rnd.Chance(5)) {\n\t\t\t\t\t\tvar found = false;\n\n\t\t\t\t\t\tforeach (var p in c.Old.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tif (p != this && p is Player) {\n\t\t\t\t\t\t\t\tfound = true;\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!found) {\n\t\t\t\t\t\t\tforeach (var door in c.Old.Doors) {\n\t\t\t\t\t\t\t\tvar x = (int) Math.Floor(door.CenterX / 16);\n\t\t\t\t\t\t\t\tvar y = (int) Math.Floor(door.Bottom / 16);\n\t\t\t\t\t\t\t\tvar t = level.Get(x, y);\n\n\t\t\t\t\t\t\t\tif (level.Get(x, y).Matches(TileFlags.Passable)) {\n\t\t\t\t\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\t\t\t\t\tlevel.Set(index, level.Biome is IceBiome ? Tile.WallB : Tile.WallA);\n\t\t\t\t\t\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\t\t\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t\t\t\t\t\t\t\tlevel.LoadPassable();\n\n\t\t\t\t\t\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tc.Old.ApplyToEachTile((x, y) => {\n\t\t\t\t\t\t\t\tif (Run.Level.Get(x, y).IsWall()) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tvar part = new TileParticle();\n\n\t\t\t\t\t\t\t\t\tpart.Top = Run.Level.Tileset.WallTopADecor;\n\t\t\t\t\t\t\t\t\tpart.TopTarget = Run.Level.Tileset.WallTopADecor;\n\t\t\t\t\t\t\t\t\tpart.Side = Run.Level.Tileset.FloorSidesD[0];\n\t\t\t\t\t\t\t\t\tpart.Sides = Run.Level.Tileset.WallSidesA[2];\n\t\t\t\t\t\t\t\t\tpart.Tile = Tile.WallA;\n\n\t\t\t\t\t\t\t\t\tpart.X = x * 16;\n\t\t\t\t\t\t\t\t\tpart.Y = y * 16;\n\t\t\t\t\t\t\t\t\tpart.Target.X = x * 16;\n\t\t\t\t\t\t\t\t\tpart.Target.Y = y * 16;\n\t\t\t\t\t\t\t\t\tpart.TargetZ = -8f;\n\n\t\t\t\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t\t\t\t}, Rnd.Float(0.5f));\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tforeach (var d in c.Old.Doors) {\n\t\t\t\t\t\t\t\td.Done = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tc.Old.Done = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Darken the lighting in evil rooms\n\t\t\t\tif (c.New.Type == RoomType.OldMan || c.New.Type == RoomType.Spiked) {\n\t\t\t\t\tTween.To(0.7f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f);\n\t\t\t\t} else if (c.Old != null && (c.Old.Type == RoomType.OldMan || c.Old.Type == RoomType.Spiked)) {\n\t\t\t\t\tTween.To(1f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f);\n\t\t\t\t}\n\t\t\t} else if (e is HealthModifiedEvent hm) {\n\t\t\t\tif (hm.Amount < 0) {\n\t\t\t\t\tif ((hm.From is Mob m && m.HasPrefix) || (hm.From is creature.bk.BurningKnight k && k.InFight) || hm.From is BkOrbital) {\n\t\t\t\t\t\thm.Amount = Math.Min(hm.Amount, -2);\n\t\t\t\t\t} else if (hm.Type != DamageType.Custom && hm.Type != DamageType.Explosive) {\n\t\t\t\t\t\thm.Amount = Math.Max(-1, hm.Amount);\n\t\t\t\t\t}\n\t\t\t\t}\t\t\t\n\t\t\t} else if (e is PostHealthModifiedEvent h) {\n\t\t\t\tif (h.Amount < 0 && !h.PressedForBomb) {\n\t\t\t\t\tHandleEvent(new PlayerHurtEvent {\n\t\t\t\t\t\tPlayer = this\n\t\t\t\t\t});\n\n\t\t\t\t\tvar hp = GetComponent<HealthComponent>().Health + GetComponent<HeartsComponent>().Total;\n\n\t\t\t\t\tif (hp > 0) {\n\t\t\t\t\t\tif (h.HealthType == HealthType.Shield) {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"player_shield_hurt\", 1f);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tAudio.PlaySfx(hp < 2 ? \"player_low_hp_hurt\" : \"player_hurt\", 1f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Settings.Blood) {\n\t\t\t\t\t\tvar cl = GetBloodColor();\n\n\t\t\t\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 3); i++) {\n\t\t\t\t\t\t\t\tArea.Add(new SplashParticle {\n\t\t\t\t\t\t\t\t\tPosition = Center - new Vector2(2.5f),\n\t\t\t\t\t\t\t\t\tColor = cl\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tArea.Add(new SplashFx {\n\t\t\t\t\t\t\tPosition = Center,\n\t\t\t\t\t\t\tColor = ColorUtils.Mod(cl)\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is RoomClearedEvent rce) {\n\t\t\t\tCamera.Instance.Unfollow(rce.Room);\n\t\t\t\tAudio.PlaySfx(\"level_room_cleared\", 0.25f + Audio.Db3);\n\n\t\t\t\tif (Run.Depth > 0 && !alerted && CheckClear(Area)) {\n\t\t\t\t\talerted = true;\n\t\t\t\t\tAnimationUtil.Confetti(Center);\n\t\t\t\t\tAudio.PlaySfx(\"level_cleared\");\n\t\t\t\t}\n\t\t\t} else if (e is NewLevelStartedEvent) {\n\t\t\t\tGetComponent<HealthComponent>().Unhittable = true;\n\t\t\t} else if (e is ProjectileCreatedEvent pce) {\n\t\t\t\tif (Flying || HasFlight) {\n\t\t\t\t\tpce.Projectile.AddFlags(ProjectileFlags.FlyOverStones);\n\t\t\t\t}\n\t\t\t} else if (e is FlagCollisionStartEvent fcse) {\n\t\t\t\tif (fcse.Flag == Flag.Burning) {\n\t\t\t\t\tGetComponent<HealthComponent>().ModifyHealth(-1, Run.Level);\n\t\t\t\t}\n\t\t\t} else if (e is RevivedEvent re) {\n\t\t\t\tAnimationUtil.TeleportAway(this, () => {\n\t\t\t\t\tFindSpawn();\n\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\tAnimationUtil.TeleportIn(this);\n\t\t\t\t});\n\t\t\t} else if (e is CollisionStartedEvent cse) {\n\t\t\t\tif (ItemDamage && cse.Entity is Item) {\n\t\t\t\t\tGetComponent<HealthComponent>().ModifyHealth(-1, cse.Entity, DamageType.Custom);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool alerted;\n\t\t\n\t\tpublic static bool CheckClear(Area area) {\n\t\t\tforeach (var r in area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) r;\n\n\t\t\t\tif ((room.Type == RoomType.Regular) && !room.Cleared) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic void RenderOutline() {\n\t\t\tvar component = GetComponent<PlayerGraphicsComponent>();\n\t\t\tvar color = component.Tint;\n\t\t\t\n\t\t\tcomponent.Tint = new Color(0f, 0f, 0f, 0.65f);\n\t\t\tcomponent.SimpleRender(false);\n\t\t\tcomponent.Tint = color;\n\t\t}\n\n\t\tpublic override bool ShouldCollideWithDestroyableInAir() {\n\t\t\treturn !HasFlight;\n\t\t}\n\n\t\tprotected override bool HandleDeath(DiedEvent d) {\n\t\t\tDone = false;\n\t\t\tdied = true;\n\t\t\tvar ing = (InGameState) Engine.Instance.State;\n\n\t\t\ting.Killer.Animation = null;\n\t\t\ting.Killer.Slice = null;\n\t\t\ting.Killer.UseSlice = true;\n\n\t\t\tvar b = GetComponent<RectBodyComponent>();\n\t\t\t\n\t\t\tb.Knockback = Vector2.Zero;\n\t\t\tb.Velocity = Vector2.Zero;\n\t\t\t\n\t\t\tif (d.From != null && d.From != this) {\n\t\t\t\tvar anim = d.From.GetAnyComponent<AnimationComponent>();\n\n\t\t\t\tif (anim != null) {\n\t\t\t\t\ting.Killer.Animation = Animations.Get(anim.Id)?.CreateAnimation();\n\t\t\t\t\t\n\t\t\t\t\tif (ing.Killer.Animation != null) {\n\t\t\t\t\t\ting.Killer.Animation.Tag = \"idle\";\n\t\t\t\t\t\ting.Killer.UseSlice = false;\n\n\t\t\t\t\t\tvar c = ing.Killer.Animation.GetCurrentTexture();\n\t\t\t\t\t\t\n\t\t\t\t\t\ting.Killer.Width = c.Width;\n\t\t\t\t\t\ting.Killer.Height = c.Height;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvar slice = d.From.GetAnyComponent<SliceComponent>();\n\n\t\t\t\t\tif (slice != null) {\n\t\t\t\t\t\ting.Killer.Slice = slice.Sprite;\n\t\t\t\t\t\ting.Killer.Width = ing.Killer.Slice.Width;\n\t\t\t\t\t\ting.Killer.Height = ing.Killer.Slice.Height;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (d.From == this) {\n\t\t\t\ting.Killer.Slice = CommonAse.Ui.GetSlice(\"self\");\n\t\t\t}\n\n\t\t\tif (ing.Killer.Slice == null && ing.Killer.Animation == null) {\n\t\t\t\ting.Killer.Slice = CommonAse.Items.GetSlice(\"unknown\");\n\t\t\t\ting.Killer.Width = ing.Killer.Slice.Width;\n\t\t\t\ting.Killer.Height = ing.Killer.Slice.Height;\n\t\t\t}\n\n\t\t\ting.Killer.Width *= 2;\n\t\t\ting.Killer.Height *= 2;\n\t\t\ting.Killer.RelativeCenterX = Display.UiWidth * 0.75f;\n\n\t\t\tLog.Info($\"Killed by: {(d.From?.GetType().Name ?? \"null\")}\");\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool IgnoresProjectiles() {\n\t\t\treturn GetComponent<StateComponent>().StateInstance is RollState;\n\t\t}\n\n\t\tprivate bool died;\n\n\t\tpublic override void AnimateDeath(DiedEvent d) {\n\t\t\tDead = true;\n\t\t\t\n\t\t\tbase.AnimateDeath(d);\n\t\t\t\n\t\t\tfor (var i = 0; i < 6; i++) {\n\t\t\t\tArea.Add(new ParticleEntity(Particles.Dust()) {\n\t\t\t\t\tPosition = Center + new Vector2(Rnd.Int(-4, 4), Rnd.Int(-4, 4)), \n\t\t\t\t\tDepth = 30\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tGetComponent<OrbitGiverComponent>().DestroyAll();\n\t\t\tGetComponent<FollowerComponent>().DestroyAll();\n\t\t\t\n\t\t\tvar stone = new Tombstone();\n\t\t\tstone.DisableDialog = true;\n\n\t\t\tif (InGameState.Multiplayer) {\n\t\t\t\tstone.HasPlayer = true;\n\t\t\t\tstone.Index = GetComponent<InputComponent>().Index;\n\t\t\t\tstone.WasGamepad = GetComponent<InputComponent>().GamepadEnabled;\n\n\t\t\t\tif (GetComponent<InputComponent>().Index == 0) {\n\t\t\t\t\tvar minIndex = 1024;\n\t\t\t\t\tPlayer pl = null;\n\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\tvar i = p.GetComponent<InputComponent>().Index;\n\n\t\t\t\t\t\tif (p != this && i < minIndex) {\n\t\t\t\t\t\t\tminIndex = i;\n\t\t\t\t\t\t\tpl = (Player) p;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pl != null) {\n\t\t\t\t\t\tvar c = ForceGetComponent<ConsumablesComponent>();\n\t\t\t\t\t\tc.Entity = pl;\n\t\t\t\t\t\tComponents.Remove(typeof(ConsumablesComponent));\n\t\t\t\t\t\tpl.Components[typeof(ConsumablesComponent)] = c;\n\t\t\t\t\t\tAddComponent(new ConsumablesComponent());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar pool = new List<string>();\n\n\t\t\tforeach (var i in GetComponent<InventoryComponent>().Items) {\n\t\t\t\tif (i.Type != ItemType.Hat && i.Id != \"bk:no_lamp\") {\n\t\t\t\t\tpool.Add(i.Id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar w = GetComponent<ActiveItemComponent>().Item;\n\n\t\t\tif (w != null) {\n\t\t\t\tpool.Add(w.Id);\n\t\t\t}\n\n\t\t\tw = GetComponent<WeaponComponent>().Item;\n\n\t\t\tif (w != null) {\n\t\t\t\tpool.Add(w.Id);\n\t\t\t}\n\t\t\t\n\t\t\tw = GetComponent<ActiveWeaponComponent>().Item;\n\n\t\t\tif (w != null) {\n\t\t\t\tpool.Add(w.Id);\n\t\t\t}\n\n\t\t\tif (pool.Count == 0) {\n\t\t\t\tpool.Add(\"bk:coin\");\n\t\t\t}\n\n\t\t\tGlobalSave.Put(\"next_tomb\", pool[Rnd.Int(pool.Count)]);\n\t\t\tGlobalSave.Put(\"tomb_depth\", Run.Depth);\n\t\t\t\n\t\t\tArea.Add(stone);\n\t\t\t\t\n\t\t\tstone.CenterX = CenterX;\n\t\t\tstone.Bottom = Bottom;\n\n\t\t\tif (InGameState.EveryoneDied(this)) {\n\t\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t\tCamera.Instance.Follow(stone, 0.5f);\n\t\t\t} else {\n\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteInt32(lastDepth);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tlastDepth = stream.ReadInt32();\n\t\t}\n\n\t\tpublic void ModifyDrops(List<Item> drops) {\n\t\t\tif (!Dead) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar inventory = GetComponent<InventoryComponent>();\n\n\t\t\tforeach (var i in inventory.Items) {\n\t\t\t\tif (i.Id != \"bk:no_lamp\") {\n\t\t\t\t\tdrops.Add(Items.Create(i.Id));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var c in Components.Values) {\n\t\t\t\tif (c is ItemComponent i && i.Item != null && i.Item.Type != ItemType.Hat && i.Item.Id != \"bk:no_lamp\") {\n\t\t\t\t\tdrops.Add(Items.Create(i.Item.Id));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (!GetComponent<HealthComponent>().Dead && (Run.LastDepth == -1 || Run.LastDepth == 0)) {\n\t\t\t\tvar index = GetComponent<InputComponent>().Index;\n\t\t\t\t\n\t\t\t\tStartingWeapons[index] = GetComponent<ActiveWeaponComponent>().Item?.Id;\n\t\t\t\tStartingItems[index] = GetComponent<ActiveItemComponent>().Item?.Id;\n\t\t\t\tStartingLamps[index] = GetComponent<LampComponent>().Item?.Id;\n\t\t\t}\n\t\t}\n\n\t\tprotected override string GetHurtSfx() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprotected override string GetDeadSfx() {\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic T ForceGetComponent<T>() where T : Component {\n\t\t\treturn base.GetComponent<T>();\n\t\t}\n\n\t\tpublic override T GetComponent<T>() {\n\t\t\tvar minIndex = 1024;\n\t\t\tvar pl = this;\n\t\t\t\n\t\t\tif (InGameState.Multiplayer && typeof(T) == typeof(ConsumablesComponent) && base.GetComponent<InputComponent>().Index != 0) {\n\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\tvar i = p.GetComponent<InputComponent>().Index;\n\t\t\t\t\t\n\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\treturn p.GetComponent<T>();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i < minIndex) {\n\t\t\t\t\t\tminIndex = i;\n\t\t\t\t\t\tpl = (Player) p;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn pl.ForceGetComponent<T>();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/PlayerClass.cs",
    "content": "﻿namespace BurningKnight.entity.creature.player {\n\tpublic enum PlayerClass {\n\t\tWarrior,\n\t\tMage,\n\t\tRanger,\n\t\tAny\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/PlayerGraphicsComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.pet;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.orbital;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class PlayerGraphicsComponent : AnimationComponent {\n\t\tpublic static Color AimLineColor = new Color(1f, 0f, 0f, 1f);\n\n\t\tprivate Vector2 scale = Vector2.One;\n\t\tprivate Animation head;\n\n\t\tprivate TextureRegion wing;\n\t\tpublic bool Hidden;\n\t\t\n\t\tpublic PlayerGraphicsComponent() : base(\"gobbo\", \"body\") {\n\t\t\tCustomFlip = true;\n\t\t\tShadowOffset = 8;\n\n\t\t\thead = Animations.Get(\"gobbo\").CreateAnimation(\"head\");\n\t\t\twing = CommonAse.Items.GetSlice(\"wing\");\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\thead.Update(dt);\n\n\t\t\tif (!(GetComponent<StateComponent>().StateInstance is Player.SleepingState)) {\n\t\t\t\tFlipped = Entity.CenterX > GetComponent<CursorComponent>().Cursor.GamePosition.X;\n\t\t\t}\n\t\t}\n\n\t\tprivate float angle;\n\n\t\tprotected override void CallRender(Vector2 pos, bool shadow) {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar region = Animation.GetCurrentTexture();\n\t\t\tvar origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height);\n\t\t\tvar s = scale * Scale;\n\n\t\t\tvar v = GetComponent<RectBodyComponent>().Acceleration;\n\t\t\tvar target = (v.Length() > 0.1f ? 1f : 0f) * 0.25f * (Flipped ? -1 : 1);\n\t\t\tangle += (target - angle) * Engine.Delta * 3f;\n\n\t\t\tvar state = GetComponent<StateComponent>().StateInstance;\n\t\t\tvar a = 0; // (state is Player.RollState || state is Player.DuckState || state is Player.PostRollState || state is Player.SittingState) ? 0 : angle;\n\n\t\t\tif (shadow) {\n\t\t\t\ta *= -1;\n\t\t\t}\n\n\t\t\tif (FlippedVerticaly) {\n\t\t\t\tpos.Y += region.Source.Height;\n\t\t\t}\n\t\t\t\n\t\t\tif (!shadow) {\n\t\t\t\tpos.Y -= GetComponent<ZComponent>().Z;\n\t\t\t}\n\n\t\t\tvar p = pos + origin;\n\t\t\tp.Floor();\n\t\t\tGraphics.Render(region, p, a, origin, s, Graphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t\tvar st = GetComponent<StateComponent>().StateInstance;\n\t\t\t\n\t\t\tif (st is Player.RollState || st is Player.SleepingState) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar h = GetComponent<HatComponent>();\n\t\t\tvar hat = h.Item;\n\n\t\t\tif (hat != null && !h.DoNotRender) {\n\t\t\t\tvar r = $\"{hat.Id}_{(Entity.GetComponent<StateComponent>().StateInstance is Player.DuckState ? \"b\" : \"a\")}\";\n\t\t\t\tvar m = shadow ? -4 : 4;\n\t\t\t\t\n\t\t\t\tregion = CommonAse.Items.GetSlice(r);\n\t\t\t\torigin = new Vector2(region.Width / 2, region.Height + 4);\n\n\t\t\t\tvar pp = new Vector2(Entity.CenterX, m +\n\t\t\t\t\tEntity.Bottom - (shadow ? 0 : GetComponent<ZComponent>().Z) + (shadow ? -1 : 1) *\n\t\t\t\t\t(offsets[Math.Min(offsets.Length - 1, Animation.Frame + Animation.StartFrame)] - 15));\n\n\t\t\t\tpp.Floor();\n\n\t\t\t\tGraphics.Render(region, pp, a, origin, Scale * new Vector2(s.X, s.Y * (shadow ? -1 : 1)), Flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None);\n\t\t\t} else {\t\n\t\t\t\tregion = head.GetFrame(Animation.Tag, (int) Animation.Frame);\n\n\t\t\t\tif (region == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\torigin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height);\n\n\t\t\t\tvar pp = pos + origin;\n\t\t\t\tpp.Floor();\n\t\t\t\tGraphics.Render(region, pp, a, origin, s, Graphics.ParseEffect(Flipped, FlippedVerticaly));\n\t\t\t}\n\t\t}\n\n\t\tpublic void AnimateSwap() {\n\t\t\tscale.Y = 0.3f;\n\t\t\tscale.X = 2f;\n\t\t\t\t\n\t\t\tTween.To(1f, scale.X, x => scale.X = x, 0.2f);\n\t\t\tTween.To(1f, scale.Y, x => scale.Y = x, 0.2f);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is WeaponSwappedEvent) {\n\t\t\t\tAnimateSwap();\n\t\t\t} else if (e is InteractedEvent) {\n\t\t\t\tscale.Y = 0.5f;\n\t\t\t\tscale.X = 2f;\n\t\t\t\t\n\t\t\t\tTween.To(1f, scale.X, x => scale.X = x, 0.2f);\n\t\t\t\tTween.To(1f, scale.Y, x => scale.Y = x, 0.2f);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate static sbyte[] offsets = {\n\t\t\t13, 12, 12, 12, 12, 0, 0, 0, 0, 11, 11, 11, 12, 12, 12, 11, 11, 11, 10, 10, 11, 11, 10, 10, 11\n\t\t};\n\n\t\tpublic void SimpleRender(bool shadow) {\n\t\t\tbase.Render(shadow);\n\t\t}\n\n\t\tprivate static bool RayShouldCollide(Entity entity) {\n\t\t\treturn entity is SolidProp || !(entity is Entrance || entity is Exit || entity is Player || entity is MeleeArc || entity is Orbital || entity is Pet || entity is Prop || entity is Spikes || entity is Chasm || entity is MovingPlatform || entity is PlatformBorder || entity is Item || entity is Projectile || entity is Bomb);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar o = (shadow ? -1 : 1) * (offsets[Math.Min(offsets.Length - 1, Animation.Frame + Animation.StartFrame)] - 11);\n\t\t\tvar s = GetComponent<StateComponent>().StateInstance;\n\t\t\tvar w = !(s is Player.RollState || s is Player.SleepingState);\n\t\t\tvar z = GetComponent<ZComponent>();\n\n\t\t\t// Render wings\n\t\t\tif (((Player) Entity).HasFlight) {\n\t\t\t\tvar a = (float) (Math.Sin(Engine.Time * 5f) * 0.5f) * (shadow ? -1 : 1);\n\n\t\t\t\tif (!shadow) {\n\t\t\t\t\tz.Z = -a * 3 + 4;\n\t\t\t\t}\n\n\t\t\t\ta -= (float) Math.PI / 4 * (shadow ? -1 : 1);\n\t\t\t\tvar wy = shadow ? Entity.Height : 0;\n\n\t\t\t\twy += GetComponent<ZComponent>().Z * (shadow ? 1 : -1);\n\n\t\t\t\tGraphics.Render(wing, Entity.Center + new Vector2(-1, wy), a, new Vector2(8),\n\t\t\t\t\tshadow ? MathUtils.InvertY : Vector2.One);\n\n\t\t\t\tGraphics.Render(wing, Entity.Center + new Vector2(1, wy), -a, new Vector2(8),\n\t\t\t\t\tshadow ? MathUtils.InvertXY : MathUtils.InvertX);\n\t\t\t}\n\n\t\t\tvar g = shadow ? 0 : (int) z.Z;\n\n\t\t\tif (w) {\n\t\t\t\tGetComponent<WeaponComponent>().Render(shadow, o - g);\n\t\t\t}\n\n\t\t\tif (!shadow && InGameState.Multiplayer) {\n\t\t\t\tvar pos = Entity.Position + Offset;\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(Player.VectorTints[Entity.GetComponent<InputComponent>().Index]);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tCallRender(pos + d, false);\n\t\t\t\t}\n\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t\t\n\t\t\tvar stopShader = StartShaders();\n\n\t\t\tSimpleRender(shadow);\n\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tif (!shadow) {\n\t\t\t\tvar aim = GetComponent<AimComponent>();\n\t\t\t\t\n\t\t\t\tif (aim.ShowLaserLine) {\n\t\t\t\t\tvar from = aim.Center;\n\t\t\t\t\tvar to = aim.RealAim;\n\t\t\t\t\tvar min = 1f;\n\t\t\t\t\tvar closest = MathUtils.CreateVector(MathUtils.Angle(to.X - from.X, to.Y - from.Y), Display.UiWidth) + from;\n\n\t\t\t\t\tPhysics.World.RayCast((fixture, point, normal, fraction) => {\n\t\t\t\t\t\tif (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) {\n\t\t\t\t\t\t\tmin = fraction;\n\t\t\t\t\t\t\tclosest = point;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn min;\n\t\t\t\t\t}, from, to);\n\t\t\t\t\t\n\t\t\t\t\tGraphics.Batch.FillRectangle((int) closest.X - 1, (int) closest.Y - 1,3, 3, AimLineColor);\n\t\t\t\t\tGraphics.Batch.DrawLine(from, new Vector2((int) closest.X, (int) closest.Y), AimLineColor, 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (w) {\n\t\t\t\tGetComponent<ActiveWeaponComponent>().Render(shadow, o - g);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/PlayerInputComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity.component;\nusing Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class PlayerInputComponent : Component {\n\t\tpublic static bool EnableUpdates;\n\t\t\n\t\tprivate const float Speed = 20f;\n\t\tprivate DialogComponent dialog;\n\t\tprivate bool wasSitting;\n\n\t\tpublic static float TimeIdle;\n\t\tpublic bool InDialog;\n\n\t\tpublic DialogComponent Dialog {\n\t\t\tget => dialog;\n\t\t\t\n\t\t\tset {\n\t\t\t\tvar old = dialog;\n\t\t\t\tdialog = value;\n\n\t\t\t\tif (dialog == null) {\n\t\t\t\t\tif (old != null) {\n\t\t\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\t\t\t\t\t\t// Tween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 1f);\n\t\t\t\t\t}\n\t\t\t\t} else if (dialog != null) {\n\t\t\t\t\tCamera.Instance.Targets.Clear();\n\n\t\t\t\t\tif (old == null) {\t\t\t\t\n\t\t\t\t\t\t// Tween.To(2f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.35f);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tCamera.Instance.Follow(dialog.Entity, 1f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate float holdTimer;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tEnableUpdates = !((Player) Entity).SuperHot;\n\n\t\t\tif (GetComponent<BuffsComponent>().Has<FrozenBuff>()) {\n\t\t\t\tEnableUpdates = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (DialogComponent.Talking != null || Boss.Exploding) {\n\t\t\t\tEnableUpdates = true;\n\t\t\t}\n\t\t\t\n\t\t\tvar idle = true;\n\t\t\tvar controller = GetComponent<InputComponent>();\n\t\t\tvar data = controller.GamepadData;\n\n\t\t\tif (data != null && data.WasAttached && !data.Attached) {\n\t\t\t\tdata.WasAttached = false;\n\t\t\t\tEngine.Instance.State.Paused = true;\n\t\t\t\tidle = false;\n\t\t\t}\n\n\t\t\tif (InDialog) {\n\t\t\t\tEnableUpdates = true;\n\t\t\t\tvar dd = dialog?.Dialog;\n\n\t\t\t\tif (dd != null) {\n\t\t\t\t\tvar isAnswer = dialog.Current is AnswerDialog;\n\t\t\t\t\tvar a = isAnswer ? (AnswerDialog) dialog.Current : null;\n\t\t\t\t\t\n\t\t\t\t\tif (dd.DoneSaying) {\n\t\t\t\t\t\tif (dialog.Current is ChoiceDialog c) {\n\t\t\t\t\t\t\tif (Input.WasPressed(Controls.UiUp, controller, true)) {\n\t\t\t\t\t\t\t\tc.Choice -= 1;\n\n\t\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (c.Choice < 0) {\n\t\t\t\t\t\t\t\t\tc.Choice += c.Options.Length;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (Input.WasPressed(Controls.UiDown, controller, true)) {\n\t\t\t\t\t\t\t\tc.Choice = (c.Choice + 1) % c.Options.Length;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (dd.Saying && !dd.JustStarted) {\n\t\t\t\t\t\tif ((!isAnswer && (Input.WasPressed(Controls.Interact, controller, true) || Input.WasPressed(Controls.UiSelect, controller, true))) || (isAnswer && !a.Focused)) {\n\t\t\t\t\t\t\tif (dd.DoneSaying) {\n\t\t\t\t\t\t\t\tdd.Finish();\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdd.Str.FinishTyping();\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tAccelerate(Vector2.Zero, dt);\n\n\t\t\t\t/*if (Input.WasPressed(Controls.Pause)) {\n\t\t\t\t\tdd?.Close();\n\t\t\t\t\tdialog?.OnEnd();\n\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\tInGameState.SkipPause = true;\n\t\t\t\t} else {*/\n\t\t\t\t\treturn;\n\t\t\t\t//}\n\t\t\t}\n\n\t\t\tif (Run.Depth == 0 && InGameState.Multiplayer && controller.Index > 0) {\n\t\t\t\tif (controller.GamepadData.CurrentState.Buttons.B == ButtonState.Pressed) {\n\t\t\t\t\tif (holdTimer <= 0) {\n\t\t\t\t\t\tholdTimer = 0;\n\t\t\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\n\t\t\t\t\t\tif (dialog.Current == null) {\n\t\t\t\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(\"button_b\"));\n\n\t\t\t\t\t\t\tdialog.StartAndClose(\"remove_player\", 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tholdTimer += dt;\n\n\t\t\t\t\tif (holdTimer >= 2f) {\n\t\t\t\t\t\tAnimationUtil.Poof(Entity.Center);\n\t\t\t\t\t\tEntity.Done = true;\n\t\t\t\t\t\t((Player) Entity).Dead = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\t\t\t\t\t\tCamera.Instance.Shake(10);\n\n\t\t\t\t\t\tvar count = 0;\n\n\t\t\t\t\t\tforeach (var p in Entity.Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tif (p != Entity) {\n\t\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (count == 1) {\n\t\t\t\t\t\t\tInGameState.Multiplayer = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t} else {\n\t\t\t\t\tholdTimer = -1;\n\t\t\t\t}\n\t\t\t} \n\n\t\t\tif (Run.Depth > 0 && Run.Type != RunType.Daily && Input.Keyboard.WasPressed(Keys.P)) {\n\t\t\t\tRun.StartNew(1, Run.Type);\n\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar state = Entity.GetComponent<StateComponent>();\n\t\t\tvar duck = state.StateInstance is Player.DuckState;\n\t\t\t\n\t\t\tif (duck) {\n\t\t\t\tif (Input.WasReleased(Controls.Duck, controller)) {\n\t\t\t\t\tidle = false;\n\n\t\t\t\t\tif (wasSitting) {\n\t\t\t\t\t\tstate.Become<Player.SittingState>();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate.Become<Player.IdleState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (Input.WasPressed(Controls.Duck, controller)) {\n\t\t\t\tidle = false;\n\t\t\t\twasSitting = state.StateInstance is Player.SittingState;\n\t\t\t\tstate.Become<Player.DuckState>();\n\t\t\t\tGlobalSave.Put(\"control_duck\", true);\n\t\t\t}\n\n\t\t\tif (state.StateInstance is Player.PostRollState) {\n\t\t\t\tEnableUpdates = true;\n\t\t\t} if (state.StateInstance is Player.RollState r) {\n\t\t\t\tEnableUpdates = true;\n\t\t\t\t\n\t\t\t\t// Movement tech :) Direction changing\n\t\t\t\tif (Input.WasPressed(Controls.Swap, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tr.ChangeDirection();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Movement tech :) Roll cancelling\n\t\t\t\tif (Input.WasPressed(Controls.Roll, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tstate.Become<Player.IdleState>();\n\t\t\t\t}\n\t\t\t} else if (!duck) {\n\t\t\t\tvar acceleration = new Vector2();\n\n\t\t\t\tif (Input.IsDown(Controls.Up, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tacceleration.Y -= 1;\n\t\t\t\t}\t\t\t\n\t\t\t\t\n\t\t\t\tif (Input.IsDown(Controls.Down, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tacceleration.Y += 1;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (Input.IsDown(Controls.Left, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tacceleration.X -= 1;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (Input.IsDown(Controls.Right, controller)) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tacceleration.X += 1;\n\t\t\t\t}\n\n\t\t\t\tif (controller.KeyboardEnabled && Input.Mouse.CheckMiddleButton) {\n\t\t\t\t\tidle = false;\n\t\t\t\t\tvar a = Entity.AngleTo(GetComponent<CursorComponent>().Cursor.GamePosition);\n\t\t\t\t\tacceleration += new Vector2((float) Math.Cos(a), (float) Math.Sin(a));\n\t\t\t\t}\n\n\t\t\t\tif (controller.GamepadEnabled && data != null && data.Attached) {\n\t\t\t\t\tacceleration += data.GetLeftStick();\n\t\t\t\t}\n\n\t\t\t\tif (Input.WasPressed(Controls.Roll, controller) && !Send(new PlayerRolledEvent {\n\t\t\t\t\tWho = (Player) Entity\n\t\t\t\t})) {\n\t\t\t\t\tEnableUpdates = true;\n\t\t\t\t\tidle = false;\n\t\t\t\t\tGlobalSave.Put(\"control_roll\", true);\n\t\t\t\t\tstate.Become<Player.RollState>();\n\t\t\t\t} else {\n\t\t\t\t\tif (acceleration.Length() > 0.1f) {\n\t\t\t\t\t\tEnableUpdates = true;\n\t\t\t\t\t\tstate.Become<Player.RunState>();\n\t\t\t\t\t} else if (!(state.StateInstance is Player.SittingState || state.StateInstance is Player.SleepingState)) {\n\t\t\t\t\t\tstate.Become<Player.IdleState>();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (acceleration.Length() > 0.1f) {\n\t\t\t\t\t\tidle = false;\n\t\t\t\t\t\tacceleration.Normalize();\n\t\t\t\t\t}\n\n\t\t\t\t\tAccelerate(acceleration, dt);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (BK.StandMode && idle && !Engine.Instance.State.Paused && Run.Depth > 0) {\n\t\t\t\tTimeIdle += dt;\n\n\t\t\t\tif (TimeIdle >= 120f) {\n\t\t\t\t\tTimeIdle = 0;\n\t\t\t\t\tLog.Info(\"The game was idle for 120 seconds, restarting\");\n\t\t\t\t\tGlobalSave.ResetControlKnowldge();\n\t\t\t\t\tRun.StartNew(0);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tTimeIdle = 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Accelerate(Vector2 acceleration, float dt) {\n\t\t\tif (GetComponent<RectBodyComponent>().Confused) {\n\t\t\t\tacceleration *= -1;\n\t\t\t}\n\t\t\t\n\t\t\tvar body = GetComponent<RectBodyComponent>();\t\n\t\t\tvar i = GetComponent<TileInteractionComponent>();\n\t\t\tvar b = GetComponent<BuffsComponent>();\n\t\t\t\t\t\n\t\t\tvar s = Speed;\n\t\t\tvar sp = 20;\n\n\t\t\tif (((Player) Entity).Sliding || !b.IceImmunity && i.Touching[(int) Tile.Ice]) {\n\t\t\t\tsp -= 19;\n\t\t\t\ts *= 0.25f;\n\t\t\t}\n\n\t\t\tif (i.Touching[(int) Tile.Cobweb]) {\n\t\t\t\ts *= 0.6f;\n\t\t\t}\n\n\t\t\tif (i.Touching[(int) Tile.Water] || i.Touching[(int) Tile.Lava]) {\n\t\t\t\ts *= 0.9f;\n\t\t\t}\n\n\t\t\tvar ac = acceleration * s;\n\t\t\tvar st = (GetComponent<StatsComponent>().Speed);\n\t\t\t\n\t\t\tbody.Acceleration = ac * st * 1.5f;\n\t\t\tbody.Velocity -= body.Velocity * dt * sp * 1.5f - body.Acceleration;\n\n\t\t\tif (st > 1) {\n\t\t\t\tbody.Position += ac * (0.5f * dt * (st - 1));\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Entity.TryGetComponent<RectBodyComponent>(out var body) && body.Body != null) {\n\t\t\t\tbody.Body.LinearVelocity = Vector2.Zero;\n\t\t\t\tbody.Acceleration = Vector2.Zero;\n\t\t\t}\n\n\t\t\tEnableUpdates = true;\n\t\t\tEntity.GetComponent<StateComponent>().Become<Player.IdleState>();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/creature/player/WeaponComponent.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.level.entities;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.creature.player {\n\tpublic class WeaponComponent : ItemComponent {\n\t\tpublic bool Disabled;\n\t\t\n\t\tprotected bool AtBack = true;\n\t\tprivate bool requestSwap;\n\n\t\tpublic void RequestSwap() {\n\t\t\trequestSwap = true;\n\t\t}\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Item != null && Run.Depth < 1) {\n\t\t\t\tItem.Done = true;\n\t\t\t\tItem = null;\n\t\t\t}\n\n\t\t\tUpdateItem = !AtBack;\n\t\t}\n\n\t\tprotected override void OnItemSet(Item previous) {\n\t\t\tbase.OnItemSet(previous);\n\n\t\t\tif (Item != null && Item.Scourged) {\n\t\t\t\tAchievements.Unlock(\"bk:scourged_weapon\");\n\t\t\t}\n\t\t}\n\n\t\tpublic void Render(bool shadow, int offset) {\n\t\t\tif (!Disabled && Item != null && Item.Renderer != null) {\n\t\t\t\tif (!shadow) {\n\t\t\t\t\tvar sh = Shaders.Item;\n\t\t\t\t\tShaders.Begin(sh);\n\t\t\t\t\tsh.Parameters[\"time\"].SetValue(Engine.Time * 0.1f);\n\t\t\t\t\tsh.Parameters[\"size\"].SetValue(ItemGraphicsComponent.FlashSize);\n\t\t\t\t}\n\n\t\t\t\tItem.Renderer.Render(AtBack, Engine.Instance.State.Paused, Engine.Delta, shadow, offset);\n\n\t\t\t\tif (!shadow) {\n\t\t\t\t\tShaders.End();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override bool ShouldReplace(Item item) {\n\t\t\treturn (Run.Depth > 0 || !AtBack) && item.Type == ItemType.Weapon && !Disabled;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (requestSwap) {\n\t\t\t\tSwap();\n\t\t\t\trequestSwap = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemAddedEvent ev) {\n\t\t\t\tif (!Disabled && ev.Component == this) {\n\t\t\t\t\tev.Old?.Drop();\n\t\t\t\t\tev.Item?.Pickup();\n\t\t\t\t\t\n\t\t\t\t\tif (ev.Item != null && ev.Old == null && AtBack) {\n\t\t\t\t\t\tif (GlobalSave.IsTrue(\"control_swap\")) {\n\t\t\t\t\t\t\tEntity.GetComponent<ActiveWeaponComponent>().requestSwap = InGameState.Ready;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar dialog = GetComponent<DialogComponent>();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdialog.Dialog.Str.ClearIcons();\n\t\t\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Swap, false)));\n\n\t\t\t\t\t\t\tif (GamepadComponent.Current != null && GamepadComponent.Current.Attached) {\n\t\t\t\t\t\t\t\tdialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Swap, true)));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdialog.StartAndClose(\"control_5\", 5);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected void Swap() {\n\t\t\tif (GlobalSave.IsFalse(\"control_swap\")) {\n\t\t\t\tGlobalSave.Put(\"control_swap\", true);\n\t\t\t\tEntity.GetComponent<DialogComponent>().Close();\n\t\t\t}\n\t\t\t\n\t\t\tvar component = AtBack ? Entity.GetComponent<ActiveWeaponComponent>() : Entity.GetComponent<WeaponComponent>();\n\t\t\t\n\t\t\tif (!Send(new WeaponSwappedEvent {\n\t\t\t\tWho = (Player) Entity,\n\t\t\t\tOld = Item,\n\t\t\t\tCurrent = component.Item\n\t\t\t})) {\n\t\t\t\t// Swap the items\n\t\t\t\tvar tmp = component.Item;\n\t\t\t\tcomponent.Item = Item;\n\t\t\t\tItem = tmp;\n\n\t\t\t\tif (!AtBack) {\n\t\t\t\t\tcomponent.Item?.PutAway();\n\t\t\t\t\tItem?.TakeOut();\n\t\t\t\t\t\n\t\t\t\t\tAudio.PlaySfx(Item == null ? \"swap\" : Item.Data.WeaponType.GetSwapSfx());\n\t\t\t\t} else {\n\t\t\t\t\tLog.Error(\"Swap is called from not active weapon component\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tDisabled = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(Disabled);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/controller/CutsceneController.cs",
    "content": "using System;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.input;\n\nnamespace BurningKnight.entity.cutscene.controller {\n\tpublic class CutsceneController : Entity {\n\t\tpublic DialogComponent Current;\n\t\tpublic CutsceneState State;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Current == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar dd = Current.Dialog;\n\t\t\tvar controller = GamepadComponent.Current;\n\t\t\t\n\t\t\tif (dd.Saying && !dd.JustStarted) {\n\t\t\t\tif (Input.WasPressed(Controls.Interact, controller, true) || Input.WasPressed(Controls.UiSelect, controller, true)) {\n\t\t\t\t\tif (dd.DoneSaying) {\n\t\t\t\t\t\tdd.Finish();\n\n\t\t\t\t\t\tvar c = Current;\n\t\t\t\t\t\tc.FinishCallback?.Invoke();\n\t\t\t\t\t\tc.FinishCallback = null;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdd.Str.FinishTyping();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Start(DialogComponent component, string what, Action onEnd) {\n\t\t\tCurrent = component;\n\t\t\tcomponent.Start(what, null, onEnd);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/controller/GobboCutsceneController.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.cutscene.entity;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics.gamerenderer;\nusing Lens.util.camera;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.cutscene.controller {\n\tpublic class GobboCutsceneController : CutsceneController {\n\t\tprivate BabyGobbo baby;\n\t\tprivate OldGobbo dad;\n\t\tprivate Gobbo gobbo;\n\t\tprivate Vector2 dadStart;\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tbaby = Area.Find<BabyGobbo>();\n\t\t\tdad = Area.Find<OldGobbo>();\n\t\t\tdadStart = dad.BottomCenter;\n\n\t\t\tdad.GraphicsComponent.Flipped = true;\n\n\t\t\tTimer.Add(() => FirstPart(), 1);\n\t\t\tPixelPerfectGameRenderer.GameScale = 2;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tPixelPerfectGameRenderer.GameScale = 1;\n\t\t}\n\n\t\tprivate void FirstPart() {\n\t\t\tvar dadDialog = dad.GetComponent<DialogComponent>();\n\t\t\tvar sonDialog = baby.GetComponent<DialogComponent>();\n\n\t\t\tdadDialog.Dialog.AlwaysShowArrow = true;\n\t\t\tsonDialog.Dialog.AlwaysShowArrow = true;\n\t\t\t\n\t\t\tStart(dadDialog, \"dad_0\", () => {\n\t\t\t\tdadDialog.Close();\n\n\t\t\t\tStart(sonDialog, \"son_0\", () => {\n\t\t\t\t\tsonDialog.Close();\n\n\t\t\t\t\tStart(dadDialog, \"dad_1\", () => {\n\t\t\t\t\t\tdadDialog.Close();\n\t\t\t\t\t\tdad.GraphicsComponent.Flipped = false;\n\t\t\t\t\t\tdad.GetComponent<AnimationComponent>().Animation.Tag = \"run\";\n\t\t\t\t\t\tdad.RunAway = true;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tState.Say(Locale.Get(\"20_years_later\"), () => {\n\t\t\t\t\t\t\t\tdad.Done = true;\n\t\t\t\t\t\t\t\tgobbo = new Gobbo();\n\t\t\t\t\t\t\t\tArea.Add(gobbo);\n\t\t\t\t\t\t\t\tgobbo.BottomCenter = dadStart;\n\t\t\t\t\t\t\t\tgobbo.GraphicsComponent.Flipped = true;\n\n\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\tSecondPart();\n\t\t\t\t\t\t\t\t}, 1f);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}, 2f);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tprivate void SecondPart() {\n\t\t\tvar gobboDialog = gobbo.GetComponent<DialogComponent>();\n\t\t\tvar sonDialog = baby.GetComponent<DialogComponent>();\n\n\t\t\tgobboDialog.Dialog.AlwaysShowArrow = true;\n\n\t\t\tStart(gobboDialog, \"gobbo_0\", () => {\n\t\t\t\tgobboDialog.Close();\n\n\t\t\t\tStart(sonDialog, \"son_0\", () => {\n\t\t\t\t\tsonDialog.Close();\n\n\t\t\t\t\tStart(gobboDialog, \"gobbo_1\", () => {\n\t\t\t\t\t\tgobboDialog.Close();\n\t\t\t\t\t\tgobbo.GraphicsComponent.Flipped = false;\n\t\t\t\t\t\tgobbo.GetComponent<AnimationComponent>().Animation.Tag = \"run\";\n\t\t\t\t\t\tgobbo.RunAway = true;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tState.Transition(() => {\n\t\t\t\t\t\t\t\tRun.Depth = -2;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}, 2f);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/entity/BabyGobbo.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\n\nnamespace BurningKnight.entity.cutscene.entity {\n\tpublic class BabyGobbo : CutsceneEntity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 8;\n\t\t\tHeight = 8;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"baby_gobbo\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 7;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/entity/CutsceneEntity.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.ui.editor;\nusing Lens.entity;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.cutscene.entity {\n\tpublic class CutsceneEntity : SaveableEntity, PlaceableEntity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\tAddComponent(new DialogComponent());\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/entity/Gobbo.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.cutscene.entity {\n\tpublic class Gobbo : CutsceneEntity {\n\t\tpublic bool RunAway;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 11;\n\t\t\tHeight = 14;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"new_gobbo\"));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (RunAway) {\n\t\t\t\tX += dt * 60;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/entity/Heinur.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.cutscene.entity {\n\tpublic class Heinur : CutsceneEntity {\n\t\tpublic bool Attract;\n\t\tpublic Action Callback;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 42;\n\t\t\tHeight = 42;\n\t\t\t\n\t\t\tAddComponent(new BkGraphicsComponent(\"heinur\"));\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, 42, 42));\n\n\t\t\tGetComponent<SensorBodyComponent>().Body.LinearDamping = 2;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!Attract) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tvar dx = p.DxTo(this);\n\t\t\t\tvar dy = p.DyTo(this);\n\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tif (d <= 24) {\n\t\t\t\t\tAnimationUtil.Explosion(Center);\n\t\t\t\t\tDone = true;\n\t\t\t\t\tCallback();\n\n\t\t\t\t\tCamera.Instance.Shake(20);\n\t\t\t\t\tEngine.Instance.Flash = 2;\n\t\t\t\t\t\n\t\t\t\t\tvar ba = GetComponent<SensorBodyComponent>();\n\t\t\t\t\tba.Velocity = ba.Knockback = Vector2.Zero;\n\t\t\t\t\t\t\n\t\t\t\t\tvar bb = p.GetComponent<SensorBodyComponent>(); \n\t\t\t\t\tbb.Velocity = bb.Knockback = Vector2.Zero;\n\n\t\t\t\t\treturn; \n\t\t\t\t}\n\n\t\t\t\tvar a = MathUtils.Angle(dx, dy);\n\t\t\t\tvar force = 360 * dt;\n\n\t\t\t\tif (d <= 64) {\n\t\t\t\t\tforce *= 2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tp.GetComponent<RectBodyComponent>().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\ta += (float) Math.PI;\n\t\t\t\tGetComponent<SensorBodyComponent>().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/cutscene/entity/OldGobbo.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.cutscene.entity {\n\tpublic class OldGobbo : CutsceneEntity {\n\t\tpublic bool RunAway;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 11;\n\t\t\tHeight = 14;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"old_gobbo\"));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (RunAway) {\n\t\t\t\tX += dt * 60;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/BossDoor.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class BossDoor : CustomDoor {\n\t\tpublic override void AddComponents() {\n\t\t\tOpenByDefault = false;\n\t\t\tbase.AddComponents();\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 17, (int) Width, 7);\n\t\t}\n\n\t\tprotected override void SetSize() {\n\t\t\tWidth = 24;\n\t\t\tHeight = 30;\n\t\t}\n\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 9);\n\t\t}\n\t\t\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, 0);\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn \"boss_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"boss_door\";\n\t\t}\n\t\t\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new BossLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/BossLock.cs",
    "content": "using BurningKnight.entity.creature.bk;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.rooms;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\n\nnamespace BurningKnight.entity.door {\n\tpublic class BossLock : IronLock {\n\t\tprivate bool triggered;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tSubscribe<SpawnTrigger.TriggeredEvent>();\n\t\t\tSubscribe<creature.bk.BurningKnight.DefeatedEvent>();\n\t\t\tSubscribe<BurningStatue.BrokenEvent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is SpawnTrigger.TriggeredEvent) {\n\t\t\t\ttriggered = true;\n\t\t\t} else if (e is creature.bk.BurningKnight.DefeatedEvent || e is BurningStatue.BrokenEvent) {\n\t\t\t\ttriggered = false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override void UpdateState() {\n\t\t\tvar shouldLock = triggered;\n\n\t\t\tif (!shouldLock) {\n\t\t\t\tforeach (var r in rooms) {\n\t\t\t\t\tif (r.Type != RoomType.Connection && r.Tagged[Tags.Player].Count > 0 &&\n\t\t\t\t\t    r.Tagged[Tags.MustBeKilled].Count > 0) {\n\t\t\t\t\t\t\n\t\t\t\t\t\tshouldLock = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldLock && !IsLocked) {\n\t\t\t\tSetLocked(true, null);\n\t\t\t\tGetComponent<StateComponent>().Become<ClosingState>();\n\t\t\t} else if (!shouldLock && IsLocked) {\n\t\t\t\tSetLocked(false, null);\n\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/CageDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class CageDoor : LockableDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new CageLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/CageLock.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.save;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics.animation;\nusing Steamworks.Data;\n\nnamespace BurningKnight.entity.door {\n\tpublic class CageLock : Lock {\n\t\tprivate static ColorSet palette = ColorSets.New(new[] {\n\t\t\tPalette.Default[9],\n\t\t\tPalette.Default[10],\n\t\t\tPalette.Default[11]\n\t\t}, new[] {\n\t\t\tPalette.Default[8],\n\t\t\tPalette.Default[9],\n\t\t\tPalette.Default[10]\n\t\t});\n\t\t\n\t\tprotected override ColorSet GetLockPalette() {\n\t\t\treturn palette;\n\t\t}\n\n\t\tprivate void SaveNpc() {\n\t\t\tvar rooms = ((Door) GetComponent<OwnerComponent>().Owner).Rooms;\n\n\t\t\tforeach (var r in rooms) {\n\t\t\t\tif (r == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tforeach (var n in r.Tagged[Tags.Npc]) {\n\t\t\t\t\tif (n is ShopNpc sn) {\n\t\t\t\t\t\tsn.Save();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlaySfx(\"item_cage_key_used\");\n\t\t\tCheckProgress();\n\t\t}\n\n\t\tpublic static void CheckProgress() {\n\t\t\tvar progress = 0;\n\t\t\tvar total = 0;\n\t\t\t\n\t\t\tforeach (var id in ShopNpc.AllNpc) {\n\t\t\t\tif (id == ShopNpc.TrashGoblin) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttotal++;\n\t\t\t\t\n\t\t\t\tif (GlobalSave.IsTrue(id)) {\n\t\t\t\t\tprogress++;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tAchievements.SetProgress(\"bk:npc_party2\", progress, total);\n\t\t}\n\n\t\tprotected override bool TryToConsumeKey(Entity entity) {\n\t\t\tif (entity.TryGetComponent<ActiveWeaponComponent>(out var a) && a.Item != null && a.Item.Id == \"bk:cage_key\") {\n\t\t\t\tvar i = a.Item;\n\t\t\t\ta.Set(null);\n\t\t\t\ti.Done = true;\n\t\t\t\t\n\t\t\t\ta.RequestSwap();\n\t\t\t\tSaveNpc();\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.TryGetComponent<WeaponComponent>(out var w) && w.Item != null && w.Item.Id == \"bk:cage_key\") {\n\t\t\t\tvar i = w.Item;\n\t\t\t\tw.Set(null);\n\t\t\t\ti.Done = true;\n\n\t\t\t\tSaveNpc();\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ChallengeDoor.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ChallengeDoor : CustomDoor {\n\t\tprotected override void SetSize() {\n\t\t\tWidth = 40;\n\t\t\tHeight = 33;\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 19, (int) Width, 7);\n\t\t}\n\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 9);\n\t\t}\n\t\t\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, 0);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new IronLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn \"challenge_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"challenge_door\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ConditionDoor.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ConditionDoor : LockableDoor {\n\t\tprivate static string[] conditions = {\n\t\t\t\"Played Once\",\n\t\t\t\"Saved Hat Trader\",\n\t\t\t\"Saved Weapon Trader\",\n\t\t\t\"Saved Artifact Trader\",\n\t\t\t\"Saved Active Trader\",\n\t\t\t\"Save Boss Rush Guy\",\n\t\t\t\"Completed 10 Challenges\",\n\t\t\t\"Completed 20 Challenges\",\n\t\t\t\"Completed 30 Challenges\",\n\t\t\t\"Achievement Branch A Complete\",\n\t\t\t\"Achievement Branch B Complete\",\n\t\t\t\"Achievement Branch C Complete\",\n\t\t\t\"Achievement Branch D Complete\"\n\t\t};\n\n\t\tprivate bool shouldLock;\n\t\tprivate bool cached;\n\t\tprivate bool lockInDemo;\n\t\tprivate int condition;\n\n\t\tprivate bool DecideState() {\n\t\t\tif (lockInDemo && BK.Demo) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tswitch (condition) {\n\t\t\t\tcase 0: return GlobalSave.IsTrue(\"played_once\");\n\t\t\t\tcase 1: return GlobalSave.IsTrue(ShopNpc.HatTrader);\n\t\t\t\tcase 2: return GlobalSave.IsTrue(ShopNpc.WeaponTrader);\n\t\t\t\tcase 3: return GlobalSave.IsTrue(ShopNpc.AccessoryTrader);\n\t\t\t\tcase 4: return GlobalSave.IsTrue(ShopNpc.ActiveTrader);\n\t\t\t\tcase 5: return GlobalSave.IsTrue(ShopNpc.Mike);\n\t\t\t\tcase 6: return GlobalSave.GetInt(\"challenges_completed\") >= 10;\n\t\t\t\tcase 7: return GlobalSave.GetInt(\"challenges_completed\") >= 20;\n\t\t\t\tcase 8: return GlobalSave.GetInt(\"challenges_completed\") >= 30;\n\t\t\t\tcase 9: return Achievements.IsGroupComplete(\"a\");\n\t\t\t\tcase 10: return Achievements.IsGroupComplete(\"b\");\n\t\t\t\tcase 11: return Achievements.IsGroupComplete(\"c\");\n\t\t\t\tcase 12: return Achievements.IsGroupComplete(\"d\");\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic bool ShouldLock() {\n\t\t\tif (!cached) {\n\t\t\t\tshouldLock = !DecideState();\n\t\t\t\tcached = true;\n\t\t\t}\n\n\t\t\treturn shouldLock;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tSkipLock = false;\n\t\t\tReplaced = false;\n\t\t\tbase.PostInit();\n\n\t\t\tSubscribe<Achievement.UnlockedEvent>();\n\t\t\t\n\t\t\tif (!Vertical) {\n\t\t\t\t// CenterX = (float) (Math.Round(CenterX / 16) * 16) + 8;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override Lock CreateLock() {\n\t\t\t//Replaced = false;\n\t\t\treturn /*Engine.EditingLevel ? null : */new ConditionLock();\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tImGui.Checkbox(\"Lock in demo\", ref lockInDemo);\n\t\t\tImGui.Combo(\"Condition\", ref condition, conditions, conditions.Length);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tcondition = stream.ReadByte();\n\t\t\tlockInDemo = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte((byte) condition);\n\t\t\tstream.WriteBoolean(lockInDemo);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is Achievement.UnlockedEvent) {\n\t\t\t\tcached = false;\n\t\t\t\tShouldLock();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ConditionLock.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ConditionLock : Lock {\n\t\tprivate bool first;\n\t\t\n\t\tpublic ConditionLock() {\n\t\t\tLockedByDefault = false;\n\t\t\tAlwaysActive = true;\n\t\t}\n\t\t\n\t\tprotected override bool Disposable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool Interactable() {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tUpdateState();\n\t\t}\n\t\t\n\t\tprotected virtual void UpdateState() {\n\t\t\tvar shouldLock = ((ConditionDoor) GetComponent<OwnerComponent>().Owner).ShouldLock();\n\n\t\t\tif (shouldLock && !IsLocked) {\n\t\t\t\tSetLocked(true, null);\n\n\t\t\t\tif (first) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<StateComponent>().Become<ClosingState>();\n\t\t\t\t}\n\t\t\t} else if (!shouldLock && IsLocked) {\n\t\t\t\tSetLocked(false, null);\n\n\t\t\t\tif (first) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<OpenState>();\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfirst = false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/CustomDoor.cs",
    "content": "using BurningKnight.assets;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class CustomDoor : LockableDoor {\n\t\tprivate TextureRegion bar;\n\t\tprivate TextureRegion pad;\n\t\t\n\t\tpublic CustomDoor() {\n\t\t\tOpenByDefault = true;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tvar p = GetPad();\n\n\t\t\tif (p != null) {\n\t\t\t\tpad = CommonAse.Props.GetSlice(p);\n\t\t\t\t\n\t\t\t\tArea.Add(new RenderTrigger(this, () => {\n\t\t\t\t\tGraphics.Render(pad, Position);\n\t\t\t\t}, -1));\n\t\t\t}\n\t\t\t\n\t\t\tvar b = GetBar();\n\n\t\t\tif (b == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbar = CommonAse.Props.GetSlice(b);\n\t\t\tArea.Add(new RenderTrigger(this, () => RenderFrame(false), Layers.FlyingMob));\n\t\t}\n\n\t\tprotected override float GetShadowOffset() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tprotected virtual string GetBar() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprotected virtual string GetPad() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprotected override void RenderShadow() {\n\t\t\tbase.RenderShadow();\n\n\t\t\tif (bar != null) {\n\t\t\t\tRenderFrame(true);\n\t\t\t}\n\t\t}\n\n\t\tprivate void RenderFrame(bool shadow) {\n\t\t\tGraphics.Render(bar, shadow ? new Vector2(X, Bottom + Height) : Position, 0, Vector2.Zero, shadow ? MathUtils.InvertY : MathUtils.Normal);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/Door.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.door {\n\tpublic class Door : SaveableEntity, PlaceableEntity {\n\t\tprivate const float CloseTimer = 1f;\n\t\t\n\t\tpublic bool Vertical;\n\t\tprotected bool OpenByDefault;\n\n\t\tpublic bool Open {\n\t\t\tget {\n\t\t\t\tvar component = GetComponent<StateComponent>();\n\t\t\t\treturn component.StateInstance is OpenState || component.StateInstance is OpeningState;\n\t\t\t}\t\n\t\t}\n\t\t\n\t\tprotected List<Entity> Colliding = new List<Entity>();\n\t\tprivate float lastCollisionTimer;\n\t\tprivate bool lit;\n\t\tinternal Room[] Rooms;\n\n\t\tpublic virtual Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, Vertical ? -7 : -7);\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tDepth = Layers.Door;\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\t// AddComponent(new ExplodableComponent());\n\n\t\t\tif (OpenByDefault) {\n\t\t\t\tGetComponent<StateComponent>().Become<OpenState>();\n\t\t\t} else {\n\t\t\t\tGetComponent<StateComponent>().Become<ClosedState>();\n\t\t\t}\n\n\t\t\tAddTag(Tags.Door);\n\t\t}\n\n\t\tprotected virtual float GetShadowOffset() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tprotected virtual void SetSize() {\n\t\t\tWidth = Vertical ? 8 : 20;\n\t\t\tHeight = Vertical ? 19 : 11;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tSetSize();\n\n\t\t\tAddComponent(new AnimationComponent(GetAnimation()) {\n\t\t\t\tShadowOffset = GetShadowOffset()\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(-2, -2, Width + 4, Height + 4, BodyType.Static, true));\n\t\t}\n\n\t\tprotected virtual void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tVertical = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(Vertical);\n\t\t}\n\n\t\tprotected virtual string GetAnimation() {\n\t\t\treturn Vertical ? \"side_door\" : \"regular_door\";\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent start) {\n\t\t\t\tif (start.Entity is Player) {\n\t\t\t\t\tColliding.Add(start.Entity);\n\n\t\t\t\t\tif (Colliding.Count >= 1 && CanOpen()) {\n\t\t\t\t\t\tvar state = GetComponent<StateComponent>();\n\n\t\t\t\t\t\tif (!(state.StateInstance is OpeningState || state.StateInstance is OpenState)) {\n\t\t\t\t\t\t\tHandleEvent(new DoorOpenedEvent {\n\t\t\t\t\t\t\t\tWho = this\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate.Become<OpeningState>();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent end) {\n\t\t\t\tif (end.Entity is Player) {\n\t\t\t\t\tColliding.Remove(end.Entity);\n\t\t\t\t\t\n\t\t\t\t\tif (Colliding.Count == 0 && !OpenByDefault) {\n\t\t\t\t\t\tlastCollisionTimer = CloseTimer;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected virtual bool CanOpen() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tvar pad = 4;\n\t\t\tGraphics.Batch.DrawRectangle(new RectangleF((int) (X + pad), (int) Y, (int) (Width - pad * 2), (int) Height), Color.Aqua, 1);\n\t\t}\n\n\t\tprivate bool added;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!added) {\n\t\t\t\tadded = true;\n\t\t\t\tvar x = (int) Math.Floor(CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(Bottom / 16);\n\n\t\t\t\tif (Run.Level.IsInside(x, y)) {\n\t\t\t\t\tRun.Level.Passable[Run.Level.ToIndex(x, y)] = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar state = GetComponent<StateComponent>();\n\t\t\t\n\t\t\tif (state.StateInstance is OpenState && Colliding.Count == 0 && !OpenByDefault) {\n\t\t\t\tlastCollisionTimer -= dt;\n\n\t\t\t\tif (lastCollisionTimer <= 0) {\n\t\t\t\t\tHandleEvent(new DoorClosedEvent {\n\t\t\t\t\t\tWho = this\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\tstate.Become<ClosingState>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rooms == null) {\n\t\t\t\tRooms = new Room[2];\n\t\t\t\tvar i = 0;\n\t\t\t\tvar pad = 4;\n\t\t\t\tvar rc = new Rectangle((int) (X + pad), (int) Y, (int) (Width - pad * 2), (int) Height);\n\n\t\t\t\tforeach (var room in Area.Tagged[Tags.Room]) {\n\t\t\t\t\tif (room.Overlaps(rc)) {\n\t\t\t\t\t\tvar r = (Room) room;\n\t\t\t\t\t\tRooms[i] = r;\n\t\t\t\t\t\t\n\t\t\t\t\t\tr.Doors.Add(this);\n\t\t\t\t\t\t\n\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\tif (i == 2) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rooms != null && !lit) {\n\t\t\t\tvar found = false;\n\t\t\t\n\t\t\t\tforeach (var rm in Rooms) {\n\t\t\t\t\tif (rm != null && rm.Tagged[Tags.Player].Count > 0) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (found) {\n\t\t\t\t\tforeach (var rm in Rooms) {\n\t\t\t\t\t\tif (rm != null && (rm.Type == RoomType.OldMan || rm.Type == RoomType.Granny)) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlit = true;\n\t\t\t\t\tExplosionMaker.LightUp(CenterX, CenterY);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class ClosedState : EntityState {\n\t\t\n\t\t}\n\n\t\tpublic class ClosingState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\t\t\t\t\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"level_door_close\", 2);\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<ClosedState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class OpenState : EntityState {\n\t\t\t\n\t\t}\n\n\t\tpublic class OpeningState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"level_door_open\", 5);\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\t\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<OpenState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/GoldLock.cs",
    "content": "﻿using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.entity.door {\n\tpublic class GoldLock : Lock {\n\t\tprivate static ColorSet palette = ColorSets.New(new[] {\n\t\t\tPalette.Default[9],\n\t\t\tPalette.Default[10],\n\t\t\tPalette.Default[11]\n\t\t}, new[] {\n\t\t\tPalette.Default[31],\n\t\t\tPalette.Default[30],\n\t\t\tPalette.Default[29]\n\t\t});\n\t\t\n\t\tprotected override ColorSet GetLockPalette() {\n\t\t\treturn palette;\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity entity) {\n\t\t\treturn entity.TryGetComponent<ConsumablesComponent>(out var component) && component.Keys > 0;\n\t\t}\n\n\t\tprotected override bool TryToConsumeKey(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.Keys > 0) {\n\t\t\t\tcomponent.Keys--;\n\t\t\t\tAudio.PlaySfx(\"item_key\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/HallDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class HallDoor : LockableDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new HallLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/HallLock.cs",
    "content": "using BurningKnight.entity.creature.npc;\r\nusing Lens.entity.component.logic;\r\n\r\nnamespace BurningKnight.entity.door {\r\n\tpublic class HallLock : IronLock {\r\n\t\tprotected override void UpdateState() {\r\n\t\t\tvar found = false;\r\n\r\n\t\t\tforeach (var n in Area.Tagged[Tags.Npc]) {\r\n\t\t\t\tif (n is ShopNpc sn && !sn.Hidden) {\r\n\t\t\t\t\tfound = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!found && !IsLocked) {\r\n\t\t\t\tSetLocked(true, null);\r\n\t\t\t\tGetComponent<StateComponent>().Become<ClosingState>();\r\n\t\t\t} else if (found && IsLocked) {\r\n\t\t\t\tSetLocked(false, null);\r\n\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/door/HeadDoor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.door {\n\tpublic class HeadDoor : CustomDoor {\n\t\tprivate Trigger trigger;\n\t\tprivate float last;\n\t\t\n\t\tprotected override void SetSize() {\n\t\t\tWidth = 30;\n\t\t\tHeight = 25;\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 5 + 8, (int) Width, 7);\n\t\t}\n\t\t\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 7);\n\t\t}\n\t\t\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, 8);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new IronLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn \"head_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"head_door\";\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tArea.Add(trigger = new Trigger {\n\t\t\t\tCallback = (e) => {\n\t\t\t\t\tif (e is Player p) {\n\t\t\t\t\t\tif (p.GetComponent<RectBodyComponent>().Velocity.Y >= 0 || p.Y > trigger.Y + 4) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n            // fixme: played multiple time\n\t\t\t\t\t\tif (Run.Scourge > 0 || p.GetComponent<ConsumablesComponent>().Coins >= 30) {\n\t\t\t\t\t\t\tif (last <= 0) {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_door_head_success\");\n\t\t\t\t\t\t\t\tlast = 0.3f;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (last <= 0) {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"level_door_head_fail\");\n\t\t\t\t\t\t\tlast = 0.3f;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tp.GetComponent<HealthComponent>().ModifyHealth(-1, this);\n\n\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\t\t\t\t\t\tp.TopCenter = BottomCenter + new Vector2(0, 2);\n\t\t\t\t\t\tAnimationUtil.Poof(p.Center);\n\n\t\t\t\t\t\tvar b = p.GetComponent<RectBodyComponent>();\n\t\t\t\t\t\t\n\t\t\t\t\t\tb.Acceleration = Vector2.Zero;\n\t\t\t\t\t\tb.Velocity = Vector2.Zero;\n\n\t\t\t\t\t\tp.GetComponent<BuffsComponent>().Add(new FrozenBuff() {\n\t\t\t\t\t\t\tDuration = 1f\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\ttrigger.TopCenter = TopCenter;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (last > 0) {\n\t\t\t\tlast -= dt;\n\t\t\t}\n\t\t\t\n\t\t\ttrigger.TopCenter = TopCenter;\n\t\t}\n\n\t\tprivate class Trigger : Entity {\n\t\t\tpublic Action<Entity> Callback;\n\t\t\t\n\t\t\tpublic override void AddComponents() {\n\t\t\t\tbase.AddComponents();\n\t\t\t\tAddComponent(new RectBodyComponent(0, 0, 16, 2, BodyType.Static, true));\n\t\t\t}\n\n\t\t\tpublic override bool HandleEvent(Event e) {\n\t\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\t\tCallback(cse.Entity);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/IronLock.cs",
    "content": "﻿using System.Collections.Generic;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.door {\n\tpublic class IronLock : Lock {\n\t\tprotected List<Room> rooms = new List<Room>();\n\t\tprivate bool first = true;\n\n\t\tpublic IronLock() {\n\t\t\tLockedByDefault = false;\n\t\t}\n\n\t\tpublic void CalcRooms() {\n\t\t\trooms.Clear();\n\t\t\t\n\t\t\tforeach (var room in Area.Tagged[Tags.Room]) {\n\t\t\t\tif (room.Overlaps(this)) {\n\t\t\t\t\trooms.Add((Room) room);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override bool Disposable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool Interactable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool updatedRooms;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!updatedRooms || rooms.Count == 0) {\n\t\t\t\tupdatedRooms = true;\n\t\t\t\tCalcRooms();\n\t\t\t}\n\n\t\t\tUpdateState();\n\t\t}\n\t\t\n\t\tprotected virtual void UpdateState() {\n\t\t\tvar shouldLock = false; // Run.Depth >= Run.ContentEndDepth;\n\n\t\t\tif (!shouldLock) {\n\t\t\t\tforeach (var r in rooms) {\n\t\t\t\t\tif (r.Tagged[Tags.Player].Count > 0) {\n\t\t\t\t\t\tif (r.Type != RoomType.Connection && r.Tagged[Tags.MustBeKilled].Count > 0) {\n\t\t\t\t\t\t\tvar found = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tforeach (var m in r.Tagged[Tags.MustBeKilled]) {\n\t\t\t\t\t\t\t\tif (!m.Done && !m.GetComponent<BuffsComponent>().Has<CharmedBuff>() && m.GetComponent<HealthComponent>().Health > 0.3f && (!(m is Mob mb) || mb.Target != null) && r.Contains(m.Center)) {\n\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (found) {\n\t\t\t\t\t\t\t\tforeach (var p in r.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\t\t\tif (!p.GetComponent<BuffsComponent>().Has<InvisibleBuff>()) {\n\t\t\t\t\t\t\t\t\t\tshouldLock = true;\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (r.Type == RoomType.Trap) {\n\t\t\t\t\t\t\tif (r.Inputs.Count > 0) {\n\t\t\t\t\t\t\t\tforeach (var c in r.Inputs) {\n\t\t\t\t\t\t\t\t\tif (c.On == c.DefaultState) {\n\t\t\t\t\t\t\t\t\t\tshouldLock = true;\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (r.Type == RoomType.Scourged) {\n\t\t\t\t\t\t\tforeach (var i in r.Tagged[Tags.Item]) {\n\t\t\t\t\t\t\t\tif (i is ScourgedStand st && st.Item != null) {\n\t\t\t\t\t\t\t\t\tshouldLock = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldLock && !IsLocked) {\n\t\t\t\tSetLocked(true, null);\n\n\t\t\t\tif (first) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<StateComponent>().Become<ClosingState>();\n\t\t\t\t}\n\t\t\t} else if (!shouldLock && IsLocked) {\n\t\t\t\tSetLocked(false, null);\n\n\t\t\t\tif (first) {\n\t\t\t\t\tGetComponent<StateComponent>().Become<OpenState>();\n\t\t\t\t} else {\n\t\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfirst = false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ItemDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class ItemDoor : LockableDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new ItemLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ItemLock.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.state;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ItemLock : Lock {\n\t\tprotected List<Room> rooms = new List<Room>();\n\n\t\tpublic void CalcRooms() {\n\t\t\trooms.Clear();\n\t\t\t\n\t\t\tforeach (var room in Area.Tagged[Tags.Room]) {\n\t\t\t\tif (room.Overlaps(this)) {\n\t\t\t\t\trooms.Add((Room) room);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override bool Disposable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool Interactable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool updatedRooms;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!updatedRooms || rooms.Count == 0) {\n\t\t\t\tupdatedRooms = true;\n\t\t\t\tCalcRooms();\n\t\t\t}\n\n\t\t\tUpdateState();\n\t\t}\n\n\t\tprotected virtual void UpdateState() {\n\t\t\tvar shouldLock = false;\n\n\t\t\tforeach (var r in rooms) {\n\t\t\t\tif (r.Tagged[Tags.Player].Count == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tforeach (var item in r.Tagged[Tags.Item]) {\n\t\t\t\t\tif ((item is ItemStand ist && ist.Item != null)) {\n\t\t\t\t\t\tshouldLock = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldLock && !IsLocked) {\n\t\t\t\tSetLocked(true, null);\n\t\t\t\tGetComponent<StateComponent>().Become<ClosingState>();\n\t\t\t} else if (!shouldLock && IsLocked) {\n\t\t\t\tSetLocked(false, null);\n\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/LevelDoor.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.door {\n\tpublic class LevelDoor : LockableDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new LevelLock();\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tSkipLock = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(!TryGetComponent<LockComponent>(out var c) || !c.Lock.IsLocked);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/LevelLock.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.entity.door {\n\tpublic class LevelLock : Lock {\n\t\tprivate static ColorSet palette = ColorSets.New(new[] {\n\t\t\t\tPalette.Default[9],\n\t\t\t\tPalette.Default[10],\n\t\t\t\tPalette.Default[11]\n\t\t}, new[] {\n\t\t\t\tPalette.Default[31],\n\t\t\t\tPalette.Default[30],\n\t\t\t\tPalette.Default[29]\n\t\t});\n\t\t\n\t\tprotected override ColorSet GetLockPalette() {\n\t\t\treturn palette;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tWidth = 20;\n\t\t\tHeight = 40;\n\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t}\n\n\t\tprotected override AnimationComponent CreateGraphicsComponent() {\n\t\t\treturn new AnimationComponent(\"level_lock\", GetLockPalette());\n\t\t}\n\n\t\tpublic override bool Interactable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected override bool TryToConsumeKey(Entity entity) {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/Lock.cs",
    "content": "﻿using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics.animation;\nusing Lens.util.camera;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.door {\n\tpublic class Lock : Entity {\n\t\tprivate bool locked;\n\t\tprotected bool LockedByDefault = true;\n\n\t\tpublic Entity Owner;\n\t\tpublic bool IsLocked => locked;\n\n\t\tpublic void SetLocked(bool value, Entity entity) {\n\t\t\tif (value == locked || Done) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlocked = value;\n\t\t\t\n\t\t\tif (!locked) {\n\t\t\t\tHandleEvent(new LockOpenedEvent {\n\t\t\t\t\tLock = this,\n\t\t\t\t\tWho = entity\n\t\t\t\t});\n\n\t\t\t\tif (Owner is Door) {\n\t\t\t\t\tOwner.GetComponent<StateComponent>().Become<Door.OpeningState>();\n\t\t\t\t}\n\n\t\t\t\tGetComponent<StateComponent>().Become<OpeningState>();\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"unlock\");\n\t\t\t} else {\n\t\t\t\tHandleEvent(new LockClosedEvent {\n\t\t\t\t\tLock = this,\n\t\t\t\t\tWho = entity\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic bool Move;\n\t\tprivate float t;\n\t\tprivate float shake;\n\t\t\n\t\tpublic Lock() {\n\t\t\tWidth = 10;\n\t\t\tHeight = 20;\n\t\t\tlocked = true;\n\t\t}\n\t\t\n\t\tprotected virtual bool Interact(Entity entity) {\n\t\t\tif (TryToConsumeKey(entity)) {\n\t\t\t\tSetLocked(false, entity);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tCamera.Instance.Shake(3);\n\t\t\tshake = 1f;\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected virtual bool TryToConsumeKey(Entity entity) {\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected virtual bool CanInteract(Entity entity) {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tif (Interactable()) {\n\t\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\t\tCanInteract = CanInteract\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent {\n\t\t\t\tDestroySounds = false\n\t\t\t});\n\t\t\t\t\t\t\t\n\t\t\tvar state = new StateComponent();\n\t\t\tAddComponent(state);\n\n\t\t\tif (LockedByDefault) {\n\t\t\t\tstate.Become<IdleState>();\n\t\t\t\tlocked = true;\n\t\t\t} else {\n\t\t\t\tstate.Become<OpenState>();\n\t\t\t\tlocked = false;\n\t\t\t}\n\n\t\t\tAddTag(Tags.Lock);\n\t\t}\n\n\t\tprotected virtual AnimationComponent CreateGraphicsComponent() {\n\t\t\treturn new AnimationComponent(\"lock\", GetLockPalette());\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (GraphicsComponent == null) {\n\t\t\t\t// Set here, because of the ui thread\n\t\t\t\tAddComponent(CreateGraphicsComponent());\n\t\t\t}\n\n\t\t\tif (!IsLocked) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar offset = GetComponent<AnimationComponent>().Offset;\n\n\t\t\tif (Move) {\n\t\t\t\tt += dt;\n\t\t\t\toffset.Y = (float) (Math.Cos(t * 3f) * 1.5f);\n\t\t\t}\n\n\t\t\tif (shake > 0) {\n\t\t\t\tshake -= dt;\n\t\t\t} else {\n\t\t\t\tshake = 0;\n\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\toffset.X = (float) (Math.Cos(shake * 20f) * shake * 2.5f);\n\t\t\tGetComponent<AnimationComponent>().Offset = offset;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\t\n\t\t}\n\n\t\tpublic void RealRender() {\n\t\t\tif (/*!Done && */!(GetComponent<StateComponent>().StateInstance is OpenState)) {\n\t\t\t\tbase.Render();\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool Disposable() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual ColorSet GetLockPalette() {\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic virtual bool Interactable() {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\t#region Lock States\n\t\tpublic class IdleState : EntityState {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic class OpenState : EntityState {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic class OpeningState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tif (((Lock) Self).Disposable()) {\n\t\t\t\t\t\tSelf.Done = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSelf.Done = false;\n\t\t\t\t\t\tBecome<OpenState>();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\t\t}\n\n\t\tpublic class ClosingState : EntityState {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Self.GetComponent<AnimationComponent>().Animation.Paused) {\n\t\t\t\t\tBecome<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/LockableDoor.cs",
    "content": "﻿using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.door {\n\tpublic class LockableDoor : Door, CollisionFilterEntity {\n\t\tprotected bool SkipLock;\n\t\tprotected bool Replaced;\n\n\t\tprotected virtual Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, Vertical ? 0 : 5, (int) Width, Vertical ? (int) Height + 10 : 7);\n\t\t}\n\n\t\tprotected virtual Vector2 GetLockOffset() {\n\t\t\treturn Vertical ? new Vector2(0, 1) : new Vector2(0, 2);\n\t\t}\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (!SkipLock) {\n\t\t\t\tAddLock(Replaced ? new IronLock() : CreateLock());\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (SkipLock) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar state = GetComponent<StateComponent>();\n\n\t\t\tif (TryGetComponent<LockComponent>(out var l)) {\n\t\t\t\tif (l.Lock == null || l.Lock.Done) {\n\t\t\t\t\tReplaceLock();\n\t\t\t\t} else if ((state.StateInstance is OpenState || state.StateInstance is OpeningState) && l.Lock.IsLocked) {\n\t\t\t\t\tstate.Become<ClosingState>();\n\t\t\t\t} else if (OpenByDefault && (state.StateInstance is ClosedState || state.StateInstance is ClosingState) && !l.Lock.IsLocked) {\n\t\t\t\t\tstate.Become<ClosingState>();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tReplaceLock();\n\t\t\t}\n\t\t}\n\n\t\tprivate void ReplaceLock() {\n\t\t\tReplaced = true;\n\t\t\tAddLock(new IronLock());\n\t\t}\n\n\t\tprivate void AddLock(Lock l) {\n\t\t\tif (l == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (HasComponent<LockComponent>()) {\n\t\t\t\tRemoveComponent<LockComponent>();\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new LockComponent(this, l, GetLockOffset()));\n\n\t\t\tif (!HasComponent<DoorBodyComponent>()) {\n\t\t\t\tvar box = GetHitbox();\n\n\t\t\t\tif (this is CustomDoor && !Vertical) {\n\t\t\t\t\tbox.Y += 8;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tAddComponent(new DoorBodyComponent(box.X, box.Y, box.Width, box.Height, BodyType.Static, true));\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tSkipLock = stream.ReadBoolean();\n\t\t\tReplaced = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(SkipLock || !TryGetComponent<LockComponent>(out var l) || l.Lock == null || l.Lock.Done);\n\t\t\tstream.WriteBoolean(Replaced);\n\t\t}\n\n\t\tprotected virtual Lock CreateLock() {\n\t\t\treturn new IronLock();\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Door);\n\t\t}\n\n\t\tprotected override bool CanOpen() {\n\t\t\treturn !TryGetComponent<LockComponent>(out var c) || !c.Lock.IsLocked;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (!SkipLock && TryGetComponent<LockComponent>(out var l)) {\n\t\t\t\tl.Lock?.RealRender();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/LockedDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class LockedDoor : LockableDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new GoldLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/PayedDoor.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class PayedDoor : CustomDoor {\n\t\tpublic override void AddComponents() {\n\t\t\tOpenByDefault = false;\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new DialogComponent {\n\t\t\t\tAnimateTyping = false\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new CloseDialogComponent(\"payed_door_0\"));\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 5 + 4, (int) Width, 7);\n\t\t}\n\t\t\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 3);\n\t\t}\n\n\t\tprotected override void SetSize() {\n\t\t\tWidth = 24;\n\t\t\tHeight = 23;\n\t\t}\n\t\t\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, 0);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new IronLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn \"payed_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"payed_door\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/RedDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class RedDoor : SpecialDoor {\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new RedLock();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/RedLock.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.creature.player;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.entity.door {\n\tpublic class RedLock : Lock {\n\t\tprivate static ColorSet palette = ColorSets.New(new[] {\n\t\t\tPalette.Default[9],\n\t\t\tPalette.Default[10],\n\t\t\tPalette.Default[11]\n\t\t}, new[] {\n\t\t\tPalette.Default[59],\n\t\t\tPalette.Default[60],\n\t\t\tPalette.Default[62]\n\t\t});\n\t\t\n\t\tprotected override ColorSet GetLockPalette() {\n\t\t\treturn palette;\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity entity) {\n\t\t\treturn entity.GetComponent<ActiveWeaponComponent>().Item?.Id == \"bk:treasure_key\" || entity.GetComponent<WeaponComponent>().Item?.Id == \"bk:treasure_key\";\n\t\t}\n\n\t\tprotected override bool TryToConsumeKey(Entity entity) {\n\t\t\tif (entity.TryGetComponent<ActiveWeaponComponent>(out var a) && a.Item != null && a.Item.Id == \"bk:treasure_key\") {\n\t\t\t\tvar i = a.Item;\n\t\t\t\ta.Set(null);\n\t\t\t\ti.Done = true;\n\t\t\t\t\n\t\t\t\ta.RequestSwap();\n\t\t\t\tAudio.PlaySfx(\"item_key\");\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.TryGetComponent<WeaponComponent>(out var w) && w.Item != null && w.Item.Id == \"bk:treasure_key\") {\n\t\t\t\tvar i = w.Item;\n\t\t\t\tw.Set(null);\n\t\t\t\ti.Done = true;\n\n\t\t\t\tAudio.PlaySfx(\"item_key\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ScourgedDoor.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.rooms;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ScourgedDoor : CustomDoor {\n\t\tprivate List<Player> Colliding = new List<Player>();\n\t\tprivate bool scourged;\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t}\n\n\t\tprivate bool Scourge(ItemComponent component) {\n\t\t\tif (component.Item != null && !component.Item.Scourged) {\n\t\t\t\tRun.AddScourge();\n\t\t\t\tcomponent.Item.Scourged = true;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce && rce.Who is Player p && Colliding.Contains(p)) {\n\t\t\t\tif (scourged || (rce.Old != null && rce.Old.Type == RoomType.Scourged)) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar a = Scourge(p.GetComponent<ActiveWeaponComponent>());\t\n\t\t\t\tvar b = Scourge(p.GetComponent<WeaponComponent>());\n\n\t\t\t\tif (!a && !b) {\n\t\t\t\t\tRun.AddScourge();\n\t\t\t\t}\n\n\t\t\t\tscourged = true;\n\t\t\t} else if (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Player p2) {\n\t\t\t\t\tColliding.Add(p2);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity is Player p2) {\n\t\t\t\t\tColliding.Remove(p2);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 5 + 4, (int) Width, 7);\n\t\t}\n\t\t\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 3);\n\t\t}\n\n\t\tprotected override void SetSize() {\n\t\t\tWidth = 24;\n\t\t\tHeight = 23;\n\t\t}\n\t\t\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, 0);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new IronLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn \"scourged_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn \"scourged_door\";\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tscourged = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(scourged);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/ShopDoor.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class ShopDoor : CustomDoor {\n\t\tprotected override void SetSize() {\n\t\t\tWidth = Vertical ? 14 : 24;\n\t\t\tHeight = Vertical ? 17 : 31;\n\n\t\t\tOpenByDefault = !Vertical;\n\t\t}\n\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, Vertical ? -6 : 0);\n\t\t}\n\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn Vertical ? new Vector2(0, -1) : new Vector2(0, 9);\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn Vertical ? new Rectangle(0, 0, (int) Width, (int) Height + 5) \n\t\t\t\t: new Rectangle(0, 14, (int) Width, 16);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn new GoldLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn Vertical ? null : \"shop_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn Vertical ? \"vertical_shop_door\" : \"shop_door\";\n\t\t}\n\n\t\tprotected override string GetPad() {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/SpecialDoor.cs",
    "content": "namespace BurningKnight.entity.door {\r\n\tpublic class SpecialDoor : LockableDoor {\r\n\t\tprotected override Lock CreateLock() {\r\n\t\t\treturn new GoldLock();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/door/SpikedDoor.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class SpikedDoor : CustomDoor {\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn new Rectangle(0, 5 + 4, (int) Width, 7);\n\t\t}\n\t\t\n\t\tprotected List<Player> Colliding = new List<Player>();\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tSubscribe<RoomChangedEvent>();\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce && rce.Who is Player p && Colliding.Contains(p)) {\n\t\t\t\tvar rolling = p.GetComponent<StateComponent>().StateInstance is Player.RollState;\n\t\t\t\tvar h = p.GetComponent<HealthComponent>();\n\t\t\t\t\n\t\t\t\tif (rolling && Rnd.Chance(95)) {\n\t\t\t\t\th.Unhittable = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\th.ModifyHealth(-1, this);\n\t\t\t\t\n\t\t\t\tif (rolling) {\n\t\t\t\t\th.Unhittable = true;\n\t\t\t\t}\n\t\t\t} else if (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Player p2 && cse.Body is DoorBodyComponent) {\n\t\t\t\t\tColliding.Add(p2);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity is Player p2 && cee.Body is DoorBodyComponent) {\n\t\t\t\t\tColliding.Remove(p2);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn new Vector2(0, 3);\n\t\t}\n\n\t\tprotected override void SetSize() {\n    \tWidth = 24;\n    \tHeight = 23;\n    }\n\t\t\n    public override Vector2 GetOffset() {\n    \treturn new Vector2(0, 0);\n    }\n\n    protected override Lock CreateLock() {\n    \treturn new IronLock();\n    }\n\n    protected override string GetBar() {\n    \treturn \"spiked_door\";\n    }\n\n    protected override string GetAnimation() {\n    \treturn \"spiked_door\";\n    }\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/TeleportTrigger.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.door {\n\tpublic class TeleportTrigger : SaveableEntity, PlaceableEntity {\n\t\tprivate sbyte depth;\n\t\tprivate string id;\n\t\tprivate string toId;\n\t\tprivate bool ignoreCollision;\n\t\tprivate bool toTop;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddTag(Tags.TeleportTrigger);\n\t\t\tAddComponent(new SensorBodyComponent(0, 0, Width, Height, BodyType.Static));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity is Player) {\n\t\t\t\t\tignoreCollision = false;\n\t\t\t\t}\n\t\t\t} else if (e is CollisionStartedEvent cse && cse.Entity is Player p) {\n\t\t\t\tif (ignoreCollision) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (depth != 0) {\n\t\t\t\t\tRun.Depth = depth;\n\t\t\t\t} else {\n\t\t\t\t\tforeach (var t in Area.Tagged[Tags.TeleportTrigger]) {\n\t\t\t\t\t\tvar tr = (TeleportTrigger) t;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (tr.id == toId) {\n\t\t\t\t\t\t\tif (tr.toTop) {\n\t\t\t\t\t\t\t\tp.TopCenter = tr.TopCenter - new Vector2(0, 1);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttr.ignoreCollision = true;\n\t\t\t\t\t\t\t\tp.BottomCenter = tr.BottomCenter + new Vector2(0, 1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tLog.Error($\"Failed to teleport to {toId}\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tvar v = (int) depth;\n\n\t\t\tif (id == null) {\n\t\t\t\tid = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tImGui.InputText(\"Id\", ref id, 128);\n\t\t\t\n\t\t\tif (ImGui.InputInt(\"To depth\", ref v)) {\n\t\t\t\tdepth = (sbyte) v;\n\t\t\t}\n\t\t\t\n\t\t\tif (v == 0) {\n\t\t\t\tif (toId == null) {\n\t\t\t\t\ttoId = \"\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.InputText(\"To Id\", ref toId, 128);\n\t\t\t}\n\n\t\t\tImGui.Separator();\n\n\t\t\tvar x = (int) X;\n\t\t\tvar y = (int) Y;\n\n\t\t\tif (ImGui.InputInt(\"X\", ref x)) {\n\t\t\t\tX = x;\n\t\t\t}\n\n\t\t\tif (ImGui.InputInt(\"Y\", ref y)) {\n\t\t\t\tY = y;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.InputFloat(\"Width\", ref Width);\n\t\t\tImGui.InputFloat(\"Height\", ref Height);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tWidth = stream.ReadFloat();\n\t\t\tHeight = stream.ReadFloat();\n\t\t\tdepth = stream.ReadSbyte();\n\t\t\tid = stream.ReadString();\n\n\t\t\tif (depth == 0) {\n\t\t\t\ttoId = stream.ReadString();\n\t\t\t}\n\n\t\t\ttoTop = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteFloat(Width);\n\t\t\tstream.WriteFloat(Height);\n\t\t\tstream.WriteSbyte(depth);\n\t\t\tstream.WriteString(id);\n\n\t\t\tif (depth == 0) {\n\t\t\t\tstream.WriteString(toId);\n\t\t\t}\n\n\t\t\tstream.WriteBoolean(toTop);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Engine.EditingLevel) {\n\t\t\t\tGraphics.Batch.FillRectangle(X, Y, Width, Height, ColorUtils.WhiteColor);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/TreasureDoor.cs",
    "content": "using BurningKnight.state;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.door {\n\tpublic class TreasureDoor : CustomDoor {\n\t\tprotected override void SetSize() {\n\t\t\tWidth = Vertical ? 10 : 24;\n\t\t\tHeight = Vertical ? 22 : 26;\n\t\t\tOpenByDefault = !Vertical;\n\t\t}\n\n\t\tpublic override Vector2 GetOffset() {\n\t\t\treturn new Vector2(0, Vertical ? -5 : 0);\n\t\t}\n\n\t\tprotected override Vector2 GetLockOffset() {\n\t\t\treturn Vertical ? new Vector2(0, 0) : new Vector2(0, 6);\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetHitbox() {\n\t\t\treturn Vertical ? new Rectangle(0, 0, (int) Width, (int) Height + 3) \n\t\t\t\t: new Rectangle(0, 12, (int) Width, 7);\n\t\t}\n\n\t\tprotected override Lock CreateLock() {\n\t\t\treturn Run.Depth == 1 || Run.Type == RunType.BossRush ? (Lock) new IronLock() : (Lock) new GoldLock();\n\t\t}\n\n\t\tprotected override string GetBar() {\n\t\t\treturn Vertical ? \"vertical_treasure_door\" : \"treasure_door\";\n\t\t}\n\n\t\tprotected override string GetAnimation() {\n\t\t\treturn Vertical ? \"vertical_treasure_door\" : \"treasure_door\";\n\t\t}\n\n\t\tprotected override string GetPad() {\n\t\t\treturn Vertical ? \"vertical_treasure_door_pad\" : null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/VerticalConditionDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class VerticalConditionDoor : ConditionDoor {\n\t\tpublic VerticalConditionDoor() {\n\t\t\tVertical = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/VerticalDoor.cs",
    "content": "namespace BurningKnight.entity.door {\r\n\tpublic class VerticalDoor : Door {\r\n\t\tpublic VerticalDoor() {\r\n\t\t\tVertical = true;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/door/VerticalHallDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class VerticalHallDoor : HallDoor {\n\t\tpublic VerticalHallDoor() {\n\t\t\tVertical = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/door/VerticalShopDoor.cs",
    "content": "namespace BurningKnight.entity.door {\n\tpublic class VerticalShopDoor : ShopDoor {\n\t\tpublic VerticalShopDoor() {\n\t\t\tVertical = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/BombPlacedEvent.cs",
    "content": "using BurningKnight.entity.bomb;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class BombPlacedEvent : Event {\r\n\t\tpublic Bomb Bomb;\r\n\t\tpublic Entity Owner;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/BuffAddedEvent.cs",
    "content": "using BurningKnight.entity.buff;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class BuffAddedEvent : Event {\n\t\tpublic Buff Buff;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/BuffRemovedEvent.cs",
    "content": "using BurningKnight.entity.buff;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class BuffRemovedEvent : Event {\n\t\tpublic Buff Buff;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/BurningKnightDefeatedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class BurningKnightDefeatedEvent : Event {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/CollisionEndedEvent.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.events {\n\tpublic class CollisionEndedEvent : Event {\n\t\tpublic Entity Entity;\n\t\tpublic BodyComponent Body;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/CollisionStartedEvent.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.events {\n\tpublic class CollisionStartedEvent : Event {\n\t\tpublic Entity Entity;\n\t\tpublic BodyComponent Body;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ConsumableAddedEvent.cs",
    "content": "﻿using BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ConsumableAddedEvent : Event {\n\t\tpublic int Amount;\n\t\tpublic int TotalNow;\n\t\tpublic ItemType Type;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ConsumableRemovedEvent.cs",
    "content": "﻿using BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ConsumableRemovedEvent : Event {\n\t\tpublic int Amount;\n\t\tpublic int TotalNow;\n\t\tpublic ItemType Type;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/DealChanceCalculateEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class DealChanceCalculateEvent : Event {\n\t\tpublic float GrannyStartChance;\n\t\tpublic float GrannyChance;\n\t\tpublic float DmStartChance;\n\t\tpublic float DmChance;\n\n\t\tpublic bool OpenBoth;\n\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/DiedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class DiedEvent : Event {\n\t\tpublic Entity From;\n\t\tpublic Entity Who;\n\t\tpublic bool BlockClear;\n\t\tpublic DamageType DamageType;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/DoorClosedEvent.cs",
    "content": "using BurningKnight.entity.door;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class DoorClosedEvent : Event {\n\t\tpublic Door Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/DoorOpenedEvent.cs",
    "content": "using BurningKnight.entity.door;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class DoorOpenedEvent : Event {\n\t\tpublic Door Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ExplodedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ExplodedEvent : Event {\n\t\tpublic Entity Who;\n\t\tpublic Entity Origin;\n\t\tpublic float Damage;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/FlagCollisionEndEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class FlagCollisionEndEvent : Event {\n\t\tpublic int Flag;\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/FlagCollisionStartEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class FlagCollisionStartEvent : Event {\n\t\tpublic int Flag;\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/GramophoneBrokenEvent.cs",
    "content": "using BurningKnight.level.entities;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class GramophoneBrokenEvent : Event {\n\t\tpublic Gramophone Gramophone;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/HealthModifiedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class HealthModifiedEvent : Event {\n\t\tpublic float Amount;\n\t\tpublic Entity From;\n\t\tpublic Entity Who;\n\t\tpublic bool Default = true;\n\t\tpublic DamageType Type = DamageType.Regular;\n\t\tpublic HealthType HealthType;\n\t\tpublic bool PressedForBomb;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/InteractedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class InteractedEvent : Event {\n\t\tpublic Entity Who;\n\t\tpublic Entity With;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemAddedEvent.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ItemAddedEvent : Event {\n\t\tpublic Item Item;\n\t\tpublic Item Old;\n\t\tpublic ItemComponent Component;\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemBoughtEvent.cs",
    "content": "using BurningKnight.entity.item;\r\nusing BurningKnight.entity.item.stand;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class ItemBoughtEvent : Event {\r\n\t\tpublic Item Item;\r\n\t\tpublic Entity Who;\r\n\t\tpublic ItemStand Stand;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemCheckEvent.cs",
    "content": "using BurningKnight.entity.item;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class ItemCheckEvent : Event {\r\n\t\tpublic Item Item;\r\n\t\tpublic bool Animate;\r\n\t\tpublic bool Blocked;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemPlacedEvent.cs",
    "content": "using BurningKnight.entity.item;\r\nusing BurningKnight.entity.item.stand;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class ItemPlacedEvent : Event {\r\n\t\tpublic Item Item;\r\n\t\tpublic Entity Who;\r\n\t\tpublic ItemStand Stand;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemPriceCalculationEvent.cs",
    "content": "using BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ItemPriceCalculationEvent : Event {\n\t\tpublic Item Item;\n\t\tpublic ShopStand Stand;\n\t\tpublic float Percent;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemRemovedEvent.cs",
    "content": "using BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ItemRemovedEvent : Event {\n\t\tpublic Item Item;\n\t\tpublic Entity Owner;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemTakenEvent.cs",
    "content": "using BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ItemTakenEvent : Event {\n\t\tpublic Item Item;\n\t\tpublic Entity Who;\n\t\tpublic ItemStand Stand;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/ItemUsedEvent.cs",
    "content": "﻿using BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class ItemUsedEvent : Event {\n\t\tpublic Item Item;\n\t\tpublic Entity Who;\n\t\tpublic bool Fake;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/KilledEvent.cs",
    "content": "using BurningKnight.entity.creature;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class KilledEvent : Event {\n\t\tpublic Creature Who;\n\t\tpublic Creature KilledBy;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/LockClosedEvent.cs",
    "content": "using BurningKnight.entity.door;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class LockClosedEvent : Event {\n\t\tpublic Lock Lock;\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/LockOpenedEvent.cs",
    "content": "﻿using BurningKnight.entity.door;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class LockOpenedEvent : Event {\n\t\tpublic Lock Lock;\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/LostSupportEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class LostSupportEvent : Event {\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/MaxHealthModifiedEvent.cs",
    "content": "using Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class MaxHealthModifiedEvent : Event {\r\n\t\tpublic Entity Who;\r\n\t\tpublic int Amount;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/MobTargetChange.cs",
    "content": "﻿using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class MobTargetChange : Event {\n\t\tpublic Entity Mob;\n\t\tpublic Entity Old;\n\t\tpublic Entity New;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/NewFloorEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class NewFloorEvent : Event {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/NewLevelStartedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class NewLevelStartedEvent : Event {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/PlayerHurtEvent.cs",
    "content": "using BurningKnight.entity.creature.player;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class PlayerHurtEvent : Event {\r\n\t\tpublic Player Player;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/PlayerRolledEvent.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class PlayerRolledEvent : Event {\n\t\tpublic Player Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/PlayerShootEvent.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class PlayerShootEvent : Event {\n\t\tpublic Player Player;\n\t\tpublic int Times = 1;\n\t\tpublic bool Accurate;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/PostHealthModifiedEvent.cs",
    "content": "using Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class PostHealthModifiedEvent : Event {\r\n\t\tpublic float Amount;\r\n\t\tpublic Entity From;\r\n\t\tpublic Entity Who;\r\n\t\tpublic bool Default = true;\r\n\t\tpublic DamageType Type = DamageType.Regular;\r\n\t\tpublic HealthType HealthType;\r\n\t\tpublic bool PressedForBomb;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/ProjectileCreatedEvent.cs",
    "content": "using BurningKnight.entity.item;\r\nusing BurningKnight.entity.projectile;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class ProjectileCreatedEvent : Event {\r\n\t\tpublic Projectile Projectile;\r\n\t\tpublic Entity Owner;\r\n\t\tpublic Item Item;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/QuackEvent.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class QuackEvent : Event {\n\t\tpublic Player Player;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/RemoveFromPoolUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.events {\n\tpublic class RemoveFromPoolUse : ItemUse {\n\t\tprivate List<string> items = new List<string>();\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (item.Used) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var i in items) {\n\t\t\t\tRun.Statistics.Banned.Add(i);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\titems.Clear();\n\n\t\t\tforeach (var i in settings[\"items\"].AsJsonArray) {\n\t\t\t\titems.Add(i.String(\"\"));\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tif (!root[\"items\"].IsJsonArray) {\n\t\t\t\troot[\"items\"] = new JsonArray();\n\t\t\t}\n\t\t\t\n\t\t\tvar items = root[\"items\"].AsJsonArray;\n\t\t\tvar toRemove = -1;\n\t\t\t\n\t\t\tfor (var i = 0; i < items.Count; i++) {\n\t\t\t\tvar item = items[i].AsString;\n\t\t\t\t\n\t\t\t\tif (ImGui.InputText($\"##item{i}\", ref item, 128)) {\n\t\t\t\t\titems[i] = item;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"-\")) {\n\t\t\t\t\ttoRemove = i;\n\t\t\t\t}\n\n\t\t\t\tif (!Items.Has(item)) {\n\t\t\t\t\tImGui.BulletText(\"Unknown item!\");\n\t\t\t\t}\t\n\t\t\t}\n\n\t\t\tif (toRemove > -1) {\n\t\t\t\titems.Remove(toRemove);\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"+\")) {\n\t\t\t\titems.Add(\"\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/RevivedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class RevivedEvent : Event {\n\t\tpublic Entity Who;\n\t\tpublic Entity WhoDamaged;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/RoomChangedEvent.cs",
    "content": "using BurningKnight.entity.room;\r\nusing BurningKnight.level.rooms;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class RoomChangedEvent : Event {\r\n\t\tpublic Entity Who;\r\n\t\tpublic Room Old;\r\n\t\tpublic Room New;\r\n\t\tpublic bool WasDiscovered;\r\n\t\tpublic bool JustDiscovered;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/RoomClearedEvent.cs",
    "content": "using BurningKnight.entity.room;\r\nusing BurningKnight.level.rooms;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class RoomClearedEvent : Event {\r\n\t\tpublic Room Room;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/SaveEndedEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class SaveEndedEvent : Event {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/SaveStartedEvent.cs",
    "content": "using Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class SaveStartedEvent : Event {\r\n\t\t\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/SecretRoomFoundEvent.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class SecretRoomFoundEvent : Event {\n\t\tpublic Entity Who;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/TileCollisionEndEvent.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class TileCollisionEndEvent : Event {\n\t\tpublic Entity Who;\n\t\tpublic Tile Tile;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/events/TileCollisionStartEvent.cs",
    "content": "using BurningKnight.level.tile;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.events {\r\n\tpublic class TileCollisionStartEvent : Event {\r\n\t\tpublic Entity Who;\r\n\t\tpublic Tile Tile;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/events/WeaponSwappedEvent.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.events {\n\tpublic class WeaponSwappedEvent : Event {\n\t\tpublic Player Who;\n\t\tpublic Item Current;\n\t\tpublic Item Old;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/ChasmFx.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class ChasmFx : Entity {\n\t\tprivate static TextureRegion region;\n\t\t\n\t\tprivate Vector2 scale;\n\t\tprivate Color color;\n\t\tprivate float vx;\n\t\tprivate float vy;\n\t\tprivate float t;\n\t\tprivate float life;\n\t\tprivate byte targetAlpha;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (region == null) {\n\t\t\t\tregion = CommonAse.Particles.GetSlice(\"wall\");\n\t\t\t}\n\t\t\t\n\t\t\tAlwaysActive = true;\n\n\t\t\tvar v = Rnd.Float(0.5f, 1f);\n\t\t\tcolor = new Color(v, v, v, 0);\n\t\t\tscale = new Vector2(Rnd.Float(0.15f, 0.3f));\n\t\t\ttargetAlpha = (byte) Rnd.Int(120, 255);\n\t\t\tlife = Rnd.Float(2f, 3f);\n\t\t\tvx = Rnd.Float(-1f, 1f) * 2;\n\t\t\tvy = Rnd.Float(0.5f, 2f) * -2;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tX += vx * dt;\n\t\t\tY += vy * dt;\n\n\t\t\tif (t < life - 0.5f) {\n\t\t\t\tif (color.A < targetAlpha) {\n\t\t\t\t\tcolor.A = (byte) Math.Min(targetAlpha, dt * 5 * targetAlpha + color.A);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolor.A = (byte) Math.Max(0, color.A - dt * 2 * targetAlpha);\n\n\t\t\t\tif (color.A <= 0) {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, 0, region.Center, scale);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/ExplosionLeftOver.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.entity.component.graphics;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class ExplosionLeftOver : Entity {\n\t\tpublic ExplosionLeftOver() {\n\t\t\tWidth = 38;\n\t\t\tHeight = 38;\n\t\t\tDepth = Layers.FloorParticles;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new SliceComponent(\"props\", \"explosion_leftover\"));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/Firefly.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.save;\nusing BurningKnight.ui.editor;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class Firefly : SaveableEntity, PlaceableEntity {\n\t\tprivate static TextureRegion region;\n\n\t\tprivate Vector2 size;\n\t\tprivate Vector2 lightSize;\n\t\tprivate Color color;\n\t\tprivate Color lightColor;\n\t\tprivate Vector2 start;\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tPosition = start;\n\t\t\tbase.Save(stream);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tstart = Position;\n\t\t\tWidth = 192;\n\t\t\tHeight = 192;\n\t\t\tCentered = true;\n\t\t\t\n\t\t\tif (region == null) {\n\t\t\t\tregion = CommonAse.Particles.GetSlice(\"circ\");\n\t\t\t}\n\n\t\t\tcolor = new Color(Rnd.Float(0, 0.5f), Rnd.Float(0.5f, 1f), Rnd.Float(0, 0.5f), 1f);\n\t\t\tlightColor = new Color(color.R, color.G, color.B, (byte) 128);\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 1f, color));\n\t\t\t\n\t\t\tsize = new Vector2(Rnd.Float(0.1f, 0.2f));\n\t\t\tlightSize = new Vector2(size.X * 3f);\n\n\t\t\tDepth = Layers.WallDecor;\n\t\t\tt = Rnd.Float(20f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tlightSize.X += ((t % 20 <= 16f ? size.X * 3f : size.X) - lightSize.X) * dt * 3;\n\t\t\tlightSize.Y = lightSize.X;\n\t\t\t\n\t\t\tX = (float) (start.X + Math.Cos(t / 8) * Math.Sin(t / 9) * 32);\n\t\t\tY = (float) (start.Y + Math.Sin(t / 7) * Math.Cos(t / 10) * 32);\n\n\t\t\tvar light = GetComponent<LightComponent>().Light;\n\t\t\t\n\t\t\tlight.Radius += ((t % 20 <= 16f ? 96f : 0) - light.Radius) * dt * 3;\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = lightColor;\n\t\t\tGraphics.Render(region, Position, 0.1f, region.Center, lightSize);\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, 0.1f, region.Center, size);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/InteractFx.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class InteractFx : Entity {\n\t\tprivate bool tweened;\n\t\tprivate string text;\n\t\tprivate Entity entity;\n\t\tprivate float y;\n\t\tprivate TweenTask task;\n\t\tprivate TextureRegion region;\n\t\tprivate float offset;\n\t\t\n\t\tpublic InteractFx(Entity e, string str, TextureRegion sprite = null, float of = 0) {\n\t\t\tentity = e;\n\t\t\ttext = str;\n\t\t\tregion = sprite;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t\toffset = of;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tif (region != null) {\n\t\t\t\tWidth = region.Width;\n\t\t\t\tHeight = region.Height;\n\t\t\t\t\n\t\t\t\tvar component = new ScalableSliceComponent(region);\n\t\t\t\tAddComponent(component);\n\n\t\t\t\tcomponent.Scale = Vector2.Zero;\n\t\t\t\tcomponent.Origin = new Vector2(Width / 2, Height / 2);\n\t\t\t\ttask = Tween.To(1f, component.Scale.X, x => component.Scale = new Vector2(x), 0.25f, Ease.BackOut);\n\t\t\t} else {\n\t\t\t\tvar size = Font.Medium.MeasureString(text);\n\n\t\t\t\tWidth = size.Width;\n\t\t\t\tHeight = size.Height;\n\t\t\t\t\n\t\t\t\tvar component = new TextGraphicsComponent(text);\n\t\t\t\tAddComponent(component);\n\n\t\t\t\tcomponent.Scale = 0;\n\t\t\t\ttask = Tween.To(component, new {Scale = 1.3f}, 0.25f, Ease.BackOut);\n\t\t\t}\n\n\t\t\tDepth = Layers.InGameUi;\n\t\t\tCenterX = entity.CenterX + offset;\n\t\t\tY = entity.Y - Height;\n\t\t\t\n\t\t\ty = 12;\n\t\t\tTween.To(0, y, x => y = x, 0.2f);\n\t\t\t\n\t\t\tUpdatePosition();\n\t\t}\n\n\t\tprivate void UpdatePosition() {\n\t\t\tif (entity == null) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tCenter = Camera.Instance.CameraToUi(new Vector2(entity.CenterX + offset, entity.Y - 8 + y));\n\n\t\t\tif (region == null) {\n\t\t\t\tGetComponent<TextGraphicsComponent>().Angle = (float) (Math.Cos(Engine.Instance.State.Time) * 0.05f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (!Engine.Instance.State.Paused) {\n\t\t\t\tbase.Render();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tUpdatePosition();\n\t\t\t\n\t\t\tif (!tweened) {\n\t\t\t\tvar d = entity.Done;\n\n\t\t\t\tif (d || !entity.TryGetComponent<InteractableComponent>(out var component) || component.CurrentlyInteracting == null) {\n\t\t\t\t\tif (!d && entity.TryGetComponent<OwnerComponent>(out var owner) && owner.Owner is ItemStand stand && stand.GetComponent<InteractableComponent>().CurrentlyInteracting != null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tClose();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Close() {\n\t\t\ttask.Ended = true;\n\n\t\t\tif (region != null) {\n\t\t\t\tvar c = GetComponent<ScalableSliceComponent>();\n\t\t\t\tTween.To(0, c.Scale.X, x => c.Scale = new Vector2(x), 0.25f, Ease.BackOut).OnEnd = () => Done = true;\n\t\t\t} else {\n\t\t\t\tTween.To(GetComponent<TextGraphicsComponent>(), new {Scale = 0}, 0.2f).OnEnd = () => Done = true;\n\t\t\t}\n\n\t\t\tTween.To(12, y, x => y = x, 0.5f);\n\t\t\ttweened = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/SplashFx.cs",
    "content": "using System;\nusing System.Linq;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class SplashFx : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate float angle;\n\t\tprivate Vector2 scale;\n\t\tprivate float targetScale;\n\t\tpublic Color Color;\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tX -= 16;\n\t\t\tY -= 16;\n\t\t\t\n\t\t\tWidth = 32;\n\t\t\tHeight = 32;\n\t\t\tangle = Rnd.Angle();\n\t\t\ttargetScale = Rnd.Float(0.7f, 1.2f);\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddTag(Tags.Mess);\n\n\t\t\tvar list = Animations.Get(\"splash_fx\").Layers.First().Value;\n\t\t\tregion = list[Rnd.Int(list.Count)].Texture;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tscale.X = Math.Min(targetScale, scale.X + dt * 5);\n\t\t\tscale.Y = scale.X;\n\t\t}\n\n\t\tpublic void RenderInSurface() {\n\t\t\tGraphics.Color = Color;\n\t\t\tGraphics.Render(region, Center, angle, region.Center, scale);\n\n\t\t\tif (scale.X >= targetScale) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/SplashParticle.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.physics;\r\nusing Lens.entity;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.fx {\r\n\tpublic class SplashParticle : Entity, CollisionFilterEntity {\r\n\t\tpublic Color Color;\r\n\t\tprivate float zv;\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tAlwaysActive = true;\r\n\r\n\t\t\tWidth = 5;\r\n\t\t\tHeight = 5;\r\n\t\t\t\r\n\t\t\tAddComponent(new RandomFrameComponent(\"splash_particle\") {\r\n\t\t\t\tTint = new Color(Color.R, Color.G, Color.B, 0.8f)\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\r\n\t\t\tAddComponent(new ZComponent());\r\n\r\n\t\t\tvar body = new CircleBodyComponent(0, 0, 4);\r\n\t\t\tAddComponent(body);\r\n\r\n\t\t\tvar f = Rnd.Float(60, 90);\r\n\t\t\tvar a = Rnd.AnglePI();\r\n\t\t\t\r\n\t\t\tbody.Body.LinearVelocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f);\r\n\t\t\tzv = Rnd.Float(1, 3);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tvar c = GetComponent<ZComponent>();\r\n\t\t\tc.Z += zv * dt * 60;\r\n\t\t\tzv -= dt * 10;\r\n\r\n\t\t\tif (c.Z <= 0) {\r\n\t\t\t\tRemove();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void RenderShadow() {\r\n\t\t\tGraphicsComponent.Render(true);\r\n\t\t}\r\n\r\n\t\tpublic bool ShouldCollide(Entity entity) {\r\n\t\t\treturn (entity is Door || (entity is SolidProp && !(entity is Tombstone)) || entity is Level);\r\n\t\t}\r\n\r\n\t\tprivate void Remove() {\r\n\t\t\tDone = true;\r\n\t\t\t\t\r\n\t\t\tArea.Add(new SplashFx {\r\n\t\t\t\tPosition = Center,\r\n\t\t\t\tColor = Color\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is CollisionStartedEvent ev && ShouldCollide(ev.Entity)) {\r\n\t\t\t\tRemove();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/fx/TileFx.cs",
    "content": "using Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class TileFx : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tDepth = Layers.WallDecor;\n\t\t\tAlwaysActive = true;\n\n\t\t\tt = Rnd.Float(0.5f);\n\t\t\tregion = Animations.Get(\"particles\").GetSlice(\"wall\");\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt * 4f;\n\n\t\t\tif (t >= 1f) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Render(region, Position);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/WaterfallFx.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class WaterfallFx : Entity {\n\t\tprivate static TextureRegion region;\n\n\t\tprivate float angle;\n\t\tprivate float angleSpeed;\n\t\tprivate float vy;\n\t\tprivate Vector2 scale;\n\t\tprivate Color color;\n\t\tprivate bool grow;\n\n\t\tpublic bool Lava;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (region == null) {\n\t\t\t\tregion = CommonAse.Particles.GetSlice(\"wall\");\n\t\t\t}\n\n\t\t\tcolor = new Color(255, 255, 255, 255);\n\t\t\tangleSpeed = Rnd.Float(-1, 1) * 4;\n\t\t\tscale = new Vector2(0);\n\t\t\t\n\t\t\tAlwaysActive = true;\n\t\t\tgrow = true;\n\t\t\tvy = Rnd.Float(4, 8);\n\n\t\t\tDepth = 4;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (grow) {\n\t\t\t\tscale.Y += dt;\n\t\t\t\tscale.X = scale.Y;\n\n\t\t\t\tif (scale.X >= 0.5f) {\n\t\t\t\t\tgrow = false;\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tY += vy * dt;\n\t\t\tvy += dt * 5;\n\t\t\tangle += angleSpeed * dt;\n\n\t\t\tif (Lava) {\n\t\t\t\tif (color.R > 200) {\n\t\t\t\t\tcolor.R -= (byte) (dt * 140f);\n\t\t\t\t\tcolor.B -= (byte) (dt * 400f);\n\t\t\t\t\tcolor.G -= (byte) (dt * 360f);\n\t\t\t\t}\t\n\t\t\t} else {\n\t\t\t\tif (color.B > 150) {\n\t\t\t\t\tcolor.R -= (byte) (dt * 400f);\n\t\t\t\t\tcolor.B -= (byte) (dt * 240f);\n\t\t\t\t\tcolor.G -= (byte) (dt * 300f);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcolor.A = (byte) Math.Max(0, color.A - dt * 55f);\n\t\t\t\n\t\t\tscale.Y -= dt * 0.3f;\n\t\t\tscale.X = scale.Y;\n\n\t\t\tif (color.A == 0 || scale.X <= 0) {\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Color.A /= 2;\n\t\t\tGraphics.Render(region, Position, angle, region.Center, scale);\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, angle, region.Center, scale / 2);\t\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/fx/WindFx.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing BurningKnight.assets;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.fx {\n\tpublic class WindFx : Entity {\n\t\tprivate static TextureRegion region;\n\t\tprivate const float MaxSpeed = 0.5f;\n\t\t\n\t\tprivate float angle;\n\t\tprivate float angleSpeed;\n\t\tprivate float speed;\n\t\tprivate float t;\n\t\tprivate Vector2 scale;\n\t\tprivate Color color;\n\t\tprivate float delay;\n\t\tprivate bool overlapped;\n\t\tprivate Vector2 velocity;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (region == null) {\n\t\t\t\tregion = CommonAse.Particles.GetSlice(\"wall\");\n\t\t\t}\n\n\t\t\tAlwaysActive = true;\n\t\t\tDepth = Layers.WindFx;\n\t\t\t\n\t\t\tReset();\n\t\t}\n\n\t\tprivate void Reset() {\n\t\t\tdelay = Rnd.Float(0, 5f);\n\t\t\tspeed = Rnd.Float(1f, 3f) * 20;\n\t\t\tangle = Rnd.AnglePI();\n\t\t\tangleSpeed = Rnd.Float(1f, 8f);\n\t\t\tscale = new Vector2(Rnd.Float(0.05f, 0.3f));\n\t\t\tt = 0;\n\t\t\t\n\t\t\tfloat v = Rnd.Float(0.5f, 1f);\n\t\t\tcolor = new Color(v, v, v, Rnd.Float(0.4f, 0.9f));\n\n\t\t\tvar wind = CalculateWind();\n\t\t\tvar a = wind.ToAngle() - Math.PI / 2;\n\t\t\tvar w = Display.Width * -0.75f;\n\t\t\tvar d = Rnd.Float(-w / 2, w / 2);\n\n\t\t\tPosition = Camera.Instance.Position + wind * w;\n\t\t\tX += (float) Math.Cos(a) * d;\n\t\t\tY += (float) Math.Sin(a) * d;\n\t\t\t\t\n\t\t\toverlapped = false;\n\t\t\tvelocity = wind;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tvar overlaps = Camera.Instance.Overlaps(this);\n\n\t\t\tif (delay > 0) {\n\t\t\t\tif (overlaps) {\n\t\t\t\t\tdelay = 0;\n\t\t\t\t} else {\n\t\t\t\t\tdelay -= dt;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tt += dt;\n\t\t\t\n\t\t\tvar w = CalculateWindSpeed();\n\n\t\t\tif (overlapped) {\n\t\t\t\tPosition += CalculateWind() * (dt * speed * w);\n\t\t\t} else {\n\t\t\t\tPosition += velocity * (dt * speed);\n\t\t\t}\n\n\t\t\tPosition += Camera.Instance.PositionDelta * (speed * 0.01f);\n\n\t\t\tangle += angleSpeed * dt * w;\n\t\t\t\n\t\t\tif (overlaps) {\n\t\t\t\toverlapped = true;\n\t\t\t} else if (overlapped) {\n\t\t\t\tReset();\n\t\t\t} else if (t > 3f) {\n\t\t\t\tReset();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Color = color;\n\t\t\tGraphics.Render(region, Position, angle, region.Center, scale);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\tpublic static Vector2 CalculateWind() {\n\t\t\tfloat t = Engine.Time * 0.1f;\n\t\t\tdouble a = Math.Cos(t) * Math.Sin(t * 1.3f) + Math.Cos(t * 1.5f);\n\t\t\t\n\t\t\treturn new Vector2(MathUtils.Clamp(-MaxSpeed, MaxSpeed, (float) Math.Cos(a)), MathUtils.Clamp(-MaxSpeed, MaxSpeed, (float) Math.Sin(a)));\n\t\t}\n\n\t\tpublic static float CalculateWindSpeed() {\n\t\t\tfloat t = Engine.Time * 0.1f;\n\t\t\treturn (float) (1 + Math.Cos(t) * Math.Sin(t * 0.9f) * 0.5f) * 2.5f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/AnimatedItemGraphicsComponent.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item {\n\tpublic class AnimatedItemGraphicsComponent : GraphicsComponent {\n\t\tpublic Animation Animation;\n\t\tpublic float T;\n\t\t\n\t\tpublic AnimatedItemGraphicsComponent(string animation) {\n\t\t\tAnimation = Animations.Create(animation);\n\t\t\tAnimation.Randomize();\n\t\t\tT = Rnd.Float(32f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tT += dt;\n\t\t\tAnimation.Update(dt);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (!Entity.HasComponent<OwnerComponent>()) {\n\t\t\t\tif (shadow) {\n\t\t\t\t\tvar region = Animation.GetCurrentTexture();\n\t\t\t\t\tGraphics.Render(region, Entity.Position, 0, new Vector2(0, -region.Height), Vector2.One, Graphics.ParseEffect(Flipped, !FlippedVerticaly));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tAnimation.Render(Entity.Position/* + new Vector2(0, ItemGraphicsComponent.CalculateMove(T * 1.2f))*/);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/BossStand.cs",
    "content": "using BurningKnight.entity.item.stand;\r\n\r\nnamespace BurningKnight.entity.item {\r\n\tpublic class BossStand : ItemStand {\r\n\t\tprotected override string GetSprite() {\r\n\t\t\treturn \"boss_stand\";\r\n\t\t}\r\n\r\n\t\tpublic override ItemPool GetPool() {\r\n\t\t\treturn ItemPool.Boss;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/Chance.cs",
    "content": "﻿using System;\nusing BurningKnight.entity.creature.player;\nusing ImGuiNET;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item {\n\tpublic class Chance {\n\t\tpublic const double OtherClasses = 0.1f;\n\t\t\n\t\tpublic double Any;\n\t\tpublic double Melee;\n\t\tpublic double Magic;\n\t\tpublic double Range;\n\n\t\tpublic Chance(double all, double warrior, double mage, double ranged) {\n\t\t\tAny = all;\n\t\t\tMelee = warrior;\n\t\t\tMagic = mage;\n\t\t\tRange = ranged;\n\t\t}\n\n\t\tpublic double Calculate(PlayerClass c) {\n\t\t\tswitch (c) {\n\t\t\t\tcase PlayerClass.Warrior: return Melee * Any;\n\t\t\t\tcase PlayerClass.Mage: return Magic * Any;\n\t\t\t\tcase PlayerClass.Ranger: return Range * Any;\n\t\t\t\tdefault: return Any;\t\t\n\t\t\t}\t\t\t\n\t\t}\n\n\t\tpublic static Chance All(double all = 1) {\n\t\t\treturn new Chance(all, 1, 1, 1);\n\t\t}\n\n\t\tpublic static Chance Warrior(double all) {\n\t\t\treturn new Chance(all, 1, OtherClasses, OtherClasses);\n\t\t}\n\n\t\tpublic static Chance Mage(double all) {\n\t\t\treturn new Chance(all, OtherClasses, 1, OtherClasses);\n\t\t}\n\n\t\tpublic static Chance Ranger(double all) {\n\t\t\treturn new Chance(all, OtherClasses, OtherClasses, 1);\n\t\t}\n\n\t\tpublic static Chance Parse(JsonValue value) {\n\t\t\tif (value.IsJsonArray) {\n\t\t\t\tvar array = value.AsJsonArray;\n\n\t\t\t\tif (array.Count != 4) {\n\t\t\t\t\tLog.Error(\"Invalid chance declaration, must be [ all, melee, ranged, mage ] (3 numbers)\");\n\t\t\t\t\treturn All();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn new Chance(array[0], array[1], array[2], array[3]);\n\t\t\t}\n\t\t\t\n\t\t\treturn All(value.Number(1f));\n\t\t}\n\n\t\tpublic JsonValue ToJson() {\n\t\t\treturn Any; /*new JsonArray {\n\t\t\t\tAny, Melee, Magic, Range\n\t\t\t};*/\n\t\t}\n\n\t\tprivate static bool simplify = true;\n\n\t\tpublic void RenderDebug() {\n\t\t\t/*ImGui.Checkbox(\"Show simplified\", ref simplify);\n\t\t\t\n\t\t\tif (simplify) {\n\t\t\t\tvar vl = Math.Pow(Any, -1);\n\t\t\t\t\n\t\t\t\tImGui.Text(\"1 in\");\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.InputDouble(\"Chance\", ref vl)) {\n\t\t\t\t\tAny = Math.Pow(vl, -1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.Separator();\n\t\t\t\n\t\t\t\tvl = Math.Pow(Melee, -1);\n\n\t\t\t\tImGui.Text(\"1 in\");\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.InputDouble(\"Melee\", ref Melee)) {\n\t\t\t\t\tMelee = Math.Pow(vl, -1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvl = Math.Pow(Magic, -1);\n\n\t\t\t\tImGui.Text(\"1 in\");\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.InputDouble(\"Magic\", ref Magic)) {\n\t\t\t\t\tMagic = Math.Pow(vl, -1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvl = Math.Pow(Range, -1);\n\n\t\t\t\tImGui.Text(\"1 in\");\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.InputDouble(\"Range\", ref Range)) {\n\t\t\t\t\tRange = Math.Pow(vl, -1);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}*/\n\t\t\t\n\t\t\tImGui.InputDouble(\"Chance\", ref Any);\n\t\t\t/*ImGui.Separator();\n\t\t\t\n\t\t\tImGui.InputDouble(\"Melee\", ref Melee);\n\t\t\tImGui.InputDouble(\"Magic\", ref Magic);\n\t\t\tImGui.InputDouble(\"Range\", ref Range);*/\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/EmeraldStand.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item {\n\tpublic class EmeraldStand : ItemStand {\n\t\tpublic static List<string> AlreadyOnStand = new List<string>();\n\n\t\tprivate TextureRegion emerald;\n\t\t\n\t\tprivate int price;\n\t\tprivate float priceWidth;\n\t\tprivate string priceString;\n\t\tprivate float priceX;\n\t\t\n\t\tpublic EmeraldStand() {\n\t\t\tdontSaveItem = true;\n\t\t\temerald = CommonAse.Ui.GetSlice(\"emerald\");\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tvar item = PickItem();\n\n\t\t\tif (item != null) {\n\t\t\t\tSetItem(item, null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Item != null) {\n\t\t\t\tAlreadyOnStand.Remove(Item.Id);\n\t\t\t}\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"shop_stand\";\n\t\t}\n\t\t\n\t\tprotected override bool CanTake(Entity entity) {\n\t\t\tif (!base.CanTake(entity)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (GlobalSave.Emeralds < price) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\tvar npc = Area.FindClosest(Center, Tags.Npc, n => n is ShopNpc);\n\n\t\t\t\tif (npc != null && npc.TryGetComponent<DialogComponent>(out var c)) {\n\t\t\t\t\tc.StartAndClose($\"shopkeeper_{Rnd.Int(15, 18)}\", 3);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tGlobalSave.Emeralds -= price;\n\t\t\tItems.Unlock(Item.Id);\n\t\t\tAlreadyOnStand.Remove(Item.Id);\n\n\t\t\tif (!ShowUnlocked) {\n\t\t\t\tItem.Done = true;\n\t\t\t\t\n\t\t\t\t/*var item = PickItem();\n\t\t\t\tSetItem(item, entity, false);*/\n\n\t\t\t\tAnimationUtil.Poof(Center, 1);\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlaySfx(\"item_purchase\");\n\t\t\tAchievements.Unlock(\"bk:unlock\");\n\t\t\t\n\t\t\tentity.HandleEvent(new ItemBoughtEvent {\n\t\t\t\tItem = item,\n\t\t\t\tWho = entity,\n\t\t\t\tStand = this\n\t\t\t});\n\n\t\t\tforeach (var i in Area.Tagged[Tags.Item]) {\n\t\t\t\tif (i is Item it) {\n\t\t\t\t\tit.CheckMasked();\n\t\t\t\t} else if (i is ItemStand its) {\n\t\t\t\t\tits.Item?.CheckMasked();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tDoStuff();\n\n\t\t\treturn ShowUnlocked;\n\t\t}\n\n\t\tprotected virtual void DoStuff() {\n\t\t\t\n\t\t}\n\n\t\tprotected virtual bool ApproveItem(ItemData item) {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected bool ShowUnlocked;\n\n\t\tprivate Item PickItem() {\n\t\t\tvar items = new List<ItemData>();\n\n\t\t\tforeach (var i in Items.Datas.Values) {\n\t\t\t\tif (i.Lockable && i.UnlockPrice > 0 && ApproveItem(i) && !AlreadyOnStand.Contains(i.Id) \n\t\t\t\t    && (ShowUnlocked || GlobalSave.IsFalse(i.Id))) {\n\t\t\t\t\t\n\t\t\t\t\titems.Add(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (items.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\titems.Sort((a, b) => a.UnlockPrice.CompareTo(b.UnlockPrice));\n\n\t\t\tvar id = items[0].Id;\n\t\t\tAlreadyOnStand.Add(id);\n\n\t\t\treturn Items.CreateAndAdd(id, Area);\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn Item != null;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (Item != null && price > 0) {\n\t\t\t\tGraphics.Print(priceString, Font.Small, Position + new Vector2(priceX, 14));\n\t\t\t\tGraphics.Render(emerald, Position + new Vector2(priceX + priceWidth + 2, 17));\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetItem(Item i, Entity entity, bool remove = true) {\n\t\t\tbase.SetItem(i, entity, remove);\n\t\t\tRecalculatePrice();\n\t\t}\n\n\t\tpublic void RecalculatePrice() {\n\t\t\tif (Item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (GlobalSave.IsTrue(Item.Id)) {\n\t\t\t\tprice = 0;\n\t\t\t} else {\n\t\t\t\tprice = Item.Data.UnlockPrice;\n\t\t\t\tvar player = LocalPlayer.Locate(Area);\n\n\t\t\t\tif (player != null && player.GetComponent<HatComponent>().Item?.Id == \"bk:dunce_hat\") {\n\t\t\t\t\tprice++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tpriceString = $\"{price}\";\n\t\t\t\tpriceWidth = Font.Small.MeasureString(priceString).Width;\n\t\t\t\tpriceX = (Width - priceWidth - 2 - emerald.Width) / 2f;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/Item.cs",
    "content": "using System;\nusing System.Linq;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.renderer;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.entity.item.useCheck;\nusing BurningKnight.level;\nusing BurningKnight.level.rooms;\nusing BurningKnight.physics;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.item {\n\tpublic class Item : SaveableEntity, CollisionFilterEntity, PlaceableEntity {\n\t\tpublic static TextureRegion UnknownRegion;\n\t\tpublic static bool Attact;\n\t\t\n\t\tpublic ItemType Type;\n\t\tpublic string Id;\n\t\tpublic string LastId;\n\t\tpublic string IdUnderScourge => Type != ItemType.Scourge && Scourge.IsEnabled(Scourge.OfEgg) ? Items.Datas.Values.ElementAt(Rnd.Int(Items.Datas.Count)).Id : Id;\n\t\tpublic string Name => Masked ? \"???\" : Locale.Get(IdUnderScourge);\n\t\tpublic string Description => Locale.Get($\"{IdUnderScourge}_desc\");\n\t\tpublic float UseTime = 0.3f;\n\t\tpublic float Delay;\n\t\tpublic string Animation;\n\t\tpublic bool AutoPickup;\n\t\tpublic bool LoadedSelf;\n\t\tpublic bool Used;\n\t\tpublic bool Touched;\n\t\tpublic bool Automatic;\n\t\tpublic bool SingleUse;\n\t\tpublic bool Scourged;\n\t\tpublic bool Hide;\n\t\t\n\t\tpublic ItemUse[] Uses;\n\t\tpublic ItemUseCheck UseCheck = ItemUseChecks.Default;\n\t\tpublic ItemRenderer Renderer;\n\n\t\tpublic bool Hidden => (Type != ItemType.Mana && Type != ItemType.Coin && Type != ItemType.Heart && Type != ItemType.Key && Type != ItemType.Bomb && (!TryGetComponent<OwnerComponent>(out var o) || !(o.Owner is Player)) && Scourge.IsEnabled(Scourge.OfUnknown));\n\t\tpublic TextureRegion Region => (Hidden) ? UnknownRegion : (Animation != null ? GetComponent<AnimatedItemGraphicsComponent>().Animation.GetCurrentTexture() : GetComponent<ItemGraphicsComponent>().Sprite);\n\t\t\n\t\tpublic Entity Owner => TryGetComponent<OwnerComponent>(out var o) ? o.Owner : null;\n\t\tpublic ItemData Data => Items.Datas[Id];\n\n\t\tprivate bool updateLight;\n\t\tprivate float t;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tif (Run.Depth > 0 && (Type != ItemType.Scourge && Type != ItemType.Coin && Type != ItemType.Key && Type != ItemType.Bomb && Type != ItemType.Heart) \n\t\t\t  && Rnd.Chance(Scourge.IsEnabled(Scourge.OfScourged) ? 0.66f : (Run.Scourge * 10 + 0.5f))) {\n\t\t\t\t\n\t\t\t\tScourged = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Uses == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var u in Uses) {\n\t\t\t\tu.Destroy();\n\t\t\t}\n\t\t}\n\n\t\tpublic bool Use(Entity entity, bool avoidCheck = false) {\n\t\t\tif (!avoidCheck && (Type == ItemType.Weapon || Type == ItemType.Active) && !UseCheck.CanUse(entity, this)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tforeach (var use in Uses) {\n\t\t\t\tif (use.SingleUse && Used) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tuse.Use(entity, this);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tDelay = Math.Abs(UseTime);\n\n\t\t\tentity.HandleEvent(new ItemUsedEvent {\n\t\t\t\tItem = this,\n\t\t\t\tWho = entity,\n\t\t\t\tFake = avoidCheck\n\t\t\t});\n\n\t\t\tUsed = true;\n\t\t\tRenderer?.OnUse();\n\n\t\t\tif (Type == ItemType.Active) {\n\t\t\t\t((Player) entity).AnimateItemPickup(this, null, false, false);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tpublic void Pickup() {\n\t\t\tvar entity = Owner;\n\t\t\n\t\t\tforeach (var use in Uses) {\n\t\t\t\ttry {\n\t\t\t\t\tuse.Pickup(entity, this);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Drop() {\n\t\t\tvar entity = Owner;\n\t\t\n\t\t\tforeach (var use in Uses) {\n\t\t\t\ttry {\n\t\t\t\t\tuse.Drop(entity, this);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void TakeOut() {\n\t\t\tvar entity = Owner;\n\t\t\n\t\t\tforeach (var use in Uses) {\n\t\t\t\ttry {\n\t\t\t\t\tuse.TakeOut(entity, this);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void PutAway() {\n\t\t\tvar entity = Owner;\n\t\t\n\t\t\tforeach (var use in Uses) {\n\t\t\t\ttry {\n\t\t\t\t\tuse.PutAway(entity, this);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Animation != null) {\n\t\t\t\tAddComponent(new AnimatedItemGraphicsComponent(Animation));\n\t\t\t} else {\n\t\t\t\tAddComponent(new ItemGraphicsComponent(Id));\n\t\t\t}\n\t\t\t\n\t\t\tif (LoadedSelf) {\n\t\t\t\tAddDroppedComponents();\n\t\t\t}\n\t\t\t\n\t\t\tCheckMasked();\n\n\t\t\tif (Id.Contains(\"mana\")) {\n\t\t\t\tAlwaysActive = true;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tif (Masked && Run.Depth < 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.TryGetComponent<InventoryComponent>(out var inventory)) {\n\t\t\t\tinventory.Pickup(this);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprotected virtual bool ShouldInteract(Entity entity) {\n\t\t\treturn !(entity is Player c && ((Type == ItemType.Mana && (!c.GetComponent<ManaComponent>().CanPickup(this) || t < 1f)) ||\n\t\t\t                                (Type == ItemType.Heart && !c.GetComponent<HealthComponent>().CanPickup(this)) ||\n\t\t\t                                (Type == ItemType.Battery && c.GetComponent<ActiveItemComponent>().IsFullOrEmpty()) ||\n\t\t\t                                (Type == ItemType.Coin && Id != \"bk:emerald\" && c.GetComponent<ConsumablesComponent>().Coins >= c.GetComponent<ConsumablesComponent>().MaxCoins) ||\n\t\t\t                                (Type == ItemType.Bomb && c.GetComponent<ConsumablesComponent>().Bombs == 99 && c.TryGetComponent<HeartsComponent>(out var b) && b.BombsMax > b.Bombs) ||\n\t\t\t                                (Type == ItemType.Key && c.GetComponent<ConsumablesComponent>().Keys == 99)\n\t\t\t         ));\n\t\t}\n\n\t\tpublic void OnInteractionStart(Entity entity) {\n\t\t\tif (!Scourged && AutoPickup && entity.TryGetComponent<InventoryComponent>(out var inventory)) {\n\t\t\t\tif (ShouldInteract(entity)) {\n\t\t\t\t\tinventory.Pickup(this);\n\t\t\t\t\tentity.GetComponent<InteractorComponent>().EndInteraction();\t\n\t\t\t\t}\n\t\t\t} else if (!HasComponent<OwnerComponent>() && Run.Depth != -2) {\n\t\t\t\tEngine.Instance.State.Ui.Add(new ItemPickupFx(this));\n\t\t\t}\t\t\t\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateBody() {\n\t\t\tvar slice = Region;\n\t\t\treturn new RectBodyComponent(0, 0, slice.Source.Width, slice.Source.Height);\n\t\t}\n\t\t\n\t\tpublic virtual void AddDroppedComponents() {\n\t\t\tvar body = CreateBody();\n\n\t\t\tt = 0;\n\t\t\t\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = Type == ItemType.Mana ? 1 : 4;\n\t\t\tbody.Body.Friction = 0;\n\t\t\tbody.Body.Mass = 0.1f;\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tOnStart = OnInteractionStart,\n\t\t\t\tCanInteract = ShouldInteract\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\t\n\t\t\tAddTag(Tags.LevelSave);\n\t\t\tAddTag(Tags.Item);\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new SupportableComponent());\n\n\t\t\tCheckMasked();\n\t\t}\n\n\t\tpublic void RandomizeVelocity(float force) {\n\t\t\tvar component = GetBody();\n\t\t\t\n\t\t\tif (component == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforce *= 60f;\n\t\t\tvar angle = Rnd.AnglePI();\n\t\t\t\n\t\t\tcomponent.Velocity += new Vector2((float) Math.Cos(angle) * force, (float) Math.Sin(angle) * force);\n\t\t}\n\n\t\tprotected virtual void RemoveBody() {\n\t\t\tRemoveComponent<RectBodyComponent>();\n\t\t}\n\t\t\n\t\tpublic virtual void RemoveDroppedComponents() {\n\t\t\tRemoveComponent<InteractableComponent>();\n\t\t\tRemoveComponent<ShadowComponent>();\n\t\t\tRemoveComponent<LightComponent>();\n\t\t\tRemoveBody();\n\t\t\t\n\t\t\tRemoveTag(Tags.LevelSave);\n\t\t\tRemoveTag(Tags.Item);\n\n\t\t\tRemoveComponent<RoomComponent>();\n\t\t\tRemoveComponent<ExplodableComponent>();\n\t\t\tRemoveComponent<SupportableComponent>();\n\n\t\t\tCheckMasked();\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteString(Id);\n\t\t\tstream.WriteBoolean(Used);\n\t\t\tstream.WriteBoolean(Touched);\n\t\t\tstream.WriteFloat(Delay);\n\t\t\tstream.WriteBoolean(Unknown);\n\t\t\tstream.WriteBoolean(Scourged);\n\t\t\tstream.WriteBoolean(Hide);\n\t\t}\n\n\t\tpublic void ConvertTo(string id) {\n\t\t\tvar item = Items.Create(id);\n\n\t\t\tif (item == null) {\n\t\t\t\tLog.Error($\"Failed to convert item {Id}, such id does not exist!\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (HasComponent<AnimatedItemGraphicsComponent>()) {\n\t\t\t\tRemoveComponent<AnimatedItemGraphicsComponent>();\n\t\t\t} else if (HasComponent<ItemGraphicsComponent>()) {\n\t\t\t\tRemoveComponent<ItemGraphicsComponent>();\n\t\t\t}\n\n\t\t\tUses = Items.ParseUses(Items.Datas[id].Uses);\n\t\t\t\n\t\t\tforeach (var u in Uses) {\n\t\t\t\tu.Item = this;\n\t\t\t\tu.Init();\n\t\t\t}\n\t\t\t\n\t\t\tUseTime = item.UseTime;\n\t\t\tRenderer = item.Renderer;\n\t\t\tAnimation = item.Animation;\n\t\t\tAutoPickup = item.AutoPickup;\n\t\t\tAutomatic = item.Automatic;\n\t\t\tSingleUse = item.SingleUse;\n\t\t\tType = item.Type;\n\t\t\tId = id;\n\t\t\tUsed = false;\n\t\t\tScourged = Scourged || item.Scourged;\n\t\t\t\n\t\t\tif (Renderer != null) {\n\t\t\t\tRenderer.Item = this;\n\t\t\t}\n\t\t\t\n\t\t\tif (Animation != null) {\n\t\t\t\tAddComponent(new AnimatedItemGraphicsComponent(Animation));\n\t\t\t} else {\n\t\t\t\tAddComponent(new ItemGraphicsComponent(Id));\n\t\t\t}\n\t\t\t\n\t\t\tif (HasBody()) {\n\t\t\t\tRemoveDroppedComponents();\n\t\t\t\tAddDroppedComponents();\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool HasBody() {\n\t\t\treturn HasComponent<RectBodyComponent>();\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\ttry {\n\t\t\t\tLoadedSelf = true;\n\t\t\t\tId = stream.ReadString();\n\t\t\t\tScourged = false;\n\n\t\t\t\tif (!Items.Has(Id)) {\n\t\t\t\t\tId = \"bk:revolver\";\n\t\t\t\t}\n\n\t\t\t\tConvertTo(Id);\n\t\t\t\t\n\t\t\t\tUsed = stream.ReadBoolean();\n\t\t\t\tTouched = stream.ReadBoolean();\n\t\t\t\tDelay = stream.ReadFloat();\n\t\t\t\tUnknown = stream.ReadBoolean();\n\n\t\t\t\tvar v = stream.ReadBoolean();\n\t\t\t\tScourged = Scourged || v;\n\n\t\t\t\tHide = stream.ReadBoolean();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tprivate float lastParticle;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tif (Type != ItemType.Active || UseTime < 0) {\n\t\t\t\tvar s = dt;\n\t\t\t\t\n\t\t\t\tif (Type == ItemType.Weapon && Owner != null && Owner.TryGetComponent<StatsComponent>(out var stats)) {\n\t\t\t\t\ts *= stats.FireRate;\n\n\t\t\t\t\tif (Data.WeaponType == WeaponType.Ranged) {\n\t\t\t\t\t\ts *= stats.RangedRate;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tDelay = Math.Max(0, Delay - s);\n\t\t\t}\n\n\t\t\tvar hasOwner = HasComponent<OwnerComponent>();\n\t\t\t\n\t\t\tif (Scourged) {\n\t\t\t\tlastParticle -= dt;\n\n\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\tlastParticle = Rnd.Float(0.05f, 0.3f);\n\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(0, 3); i++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Scourge());\n\n\t\t\t\t\t\tpart.Position = (hasOwner ? GetComponent<OwnerComponent>().Owner.Center : Center) + Rnd.Vector(-4, 4);\n\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.5f, 1.2f);\n\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t\tpart.Depth = hasOwner ? 1 : -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tif (hasOwner) {\n\t\t\t\tvar o = Owner;\n\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Update(o, this, dt);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Attact) {\n\t\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room.Tagged[Tags.Player].Count > 0) {\n\t\t\t\t\t\tvar force = 360 * dt;\n\t\t\t\t\t\tvar a = AngleTo(room.Tagged[Tags.Player][0]);\n\t\t\t\t\t\tGetBody().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (updateLight) {\n\t\t\t\t\tupdateLight = false;\n\t\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room == null || HasComponent<LightComponent>()) {\n\t\t\t\t\t\tif (room == null || room.Type == RoomType.Secret) {\n\t\t\t\t\t\t\tRemoveComponent<LightComponent>();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (room.Type != RoomType.Secret) {\n\t\t\t\t\t\tif (Type == ItemType.Mana || Type == ItemType.Coin || Type == ItemType.Heart || Type == ItemType.Battery ||\n\t\t\t\t\t\t    Type == ItemType.Key) {\n\t\t\t\t\t\t\tColor color;\n\n\t\t\t\t\t\t\tif (Type == ItemType.Coin || Type == ItemType.Key) {\n\t\t\t\t\t\t\t\tcolor = new Color(1f, 1f, 0.5f, 1f);\n\t\t\t\t\t\t\t} else if (Type == ItemType.Heart) {\n\t\t\t\t\t\t\t\tcolor = new Color(1f, 0.2f, 0.2f, 1f);\n\t\t\t\t\t\t\t} else if (Type == ItemType.Mana) {\n\t\t\t\t\t\t\t\tcolor = new Color(0.2f, 1f, 0.2f, 1f);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcolor = new Color(1f, 1f, 1f, 1f);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tAddComponent(new LightComponent(this, 32f, color));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Type == ItemType.Mana && t >= 0.1f) {\n\t\t\t\tvar p = LocalPlayer.Locate(Area);\n\n\t\t\t\tif (p == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (p.GetComponent<ManaComponent>().IsFull() || t < 1f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\t\t\t\tvar limitRange = room != null && room.Tagged[Tags.MustBeKilled].Count > 0;\n\t\t\t\tvar d = DistanceTo(p);\n\n\t\t\t\tif (d < 4) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (limitRange && d > 64) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar b = GetBody().Body;\n\t\t\t\tvar dx = DxTo(p);\n\t\t\t\tvar dy = DyTo(p);\n\t\t\t\tvar s = dt * 4;\n\n\t\t\t\tb.LinearVelocity -= new Vector2(dx / d * s, dy / d * s);\n\n\t\t\t\tvar a = b.LinearVelocity.ToAngle(); \n\t\t\t\td = Math.Min(b.LinearVelocity.Length() + dt * 300, 1000);\n\t\t\t\ta = (float) MathUtils.LerpAngle(a, AngleTo(p), dt * 10);\n\t\t\t\t\n\t\t\t\tb.LinearVelocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual BodyComponent GetBody() {\n\t\t\treturn TryGetComponent<RectBodyComponent>(out var b) ? b : null;\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\tif (Type == ItemType.Mana) {\n\t\t\t\tif (entity is ProjectileLevelBody || entity is HalfProjectileLevel || entity is Chasm) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room == null || room.Tagged[Tags.MustBeKilled].Count == 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn !(entity is Creature) || !ShouldInteract(entity);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is LostSupportEvent) {\n\t\t\t\tDone = true;\n\t\t\t\treturn true;\n\t\t\t} else if (e is RoomChangedEvent rce && !HasComponent<OwnerComponent>()) {\n\t\t\t\tupdateLight = true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tpublic bool Masked { get; protected set; }\n\n\t\tprivate bool unknown;\n\n\t\tpublic bool Unknown {\n\t\t\tget => unknown;\n\n\t\t\tset {\n\t\t\t\tunknown = value;\n\t\t\t\tCheckMasked();\n\t\t\t}\n\t\t}\n\n\t\tpublic void CheckMasked() {\n\t\t\tMasked = Unknown || \n\t\t\t         (Run.Depth == 0 \n\t\t\t          && Data.Lockable \n\t\t\t          && Type != ItemType.Lamp\n\t\t\t          && (Data.UnlockPrice == 0 || (TryGetComponent<OwnerComponent>(out var o) && o.Owner is PermanentStand)) \n\t\t\t          && !Unlocked(Id));\n\t\t}\n\n\t\tpublic static bool Unlocked(string id) {\n\t\t\treturn GlobalSave.IsTrue(id) || id == \"bk:sword\" || id == \"bk:no_lamp\" || id == \"bk:revolver\" || id == \"bk:no_hat\";\n\t\t}\n\n\t\tpublic bool HandleOwnerEvent(Event e) {\n\t\t\tif (Uses == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var use in Uses) {\n\t\t\t\tif (use.HandleEvent(e)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t#if DEBUG\n\t\tprivate string debugItem = \"\";\n\t\t\n\t\tpublic override void RenderImDebug() {\n\t\t\tif (ImGui.InputText(\"Item\", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tConvertTo(debugItem);\n\t\t\t}\n\n\t\t\tImGui.Checkbox(\"Scourged\", ref Scourged);\n\t\t\tImGui.Checkbox(\"Touched\", ref Touched);\n\t\t}\n\t\t#endif\n\n\t\tpublic class UnlockedEvent : Event {\n\t\t\tpublic ItemData Data;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemGraphicsComponent.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.ui.imgui;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item {\n\tpublic class ItemGraphicsComponent : SliceComponent {\n\t\tpublic const float FlashSize = 0.025f;\n\t\tpublic const int ScourgedColorId = 48;\n\t\tpublic static Color MaskedColor = new Color(0f, 0f, 0f, 0.75f);\n\t\tpublic static Vector4 ScourgedColor = Palette.Default[ScourgedColorId].ToVector4();\n\t\t\n\t\tpublic float T;\n\t\t\n\t\tpublic ItemGraphicsComponent(string slice) : base(CommonAse.Items, slice) {\n\t\t\tT = Rnd.Float(32f);\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tEntity.Width = Sprite.Source.Width;\n\t\t\tEntity.Height = Sprite.Source.Height;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tT += dt;\n\t\t}\n\n\t\tpublic static float CalculateMove(float t) {\n\t\t\treturn (float) (Math.Sin(t * 3f) * 0.5f + 0.5f) * -5.5f;\n\t\t}\n\n\t\tpublic virtual Vector2 CalculatePosition(bool shadow = false) {\n\t\t\treturn Entity.Position + Sprite.Center + new Vector2(0, shadow ? 8 : CalculateMove(T));\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tif (Entity.HasComponent<OwnerComponent>()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar item = (Item) Entity;\n\t\t\tvar s = item.Hidden ? Item.UnknownRegion : Sprite;\n\t\t\tvar origin = s.Center;\n\t\t\tvar position = CalculatePosition(shadow);\n\t\t\tvar angle = (float) Math.Cos(T * 1.8f) * 0.4f;\n\t\t\tvar cursed = item.Scourged;\n\n\t\t\tif (!shadow) {\n\t\t\t\tvar interact = Entity.TryGetComponent<InteractableComponent>(out var component) &&\n\t\t\t\t               component.OutlineAlpha > 0.05f;\n\n\t\t\t\tif (cursed || interact) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(cursed ? 1f : component.OutlineAlpha);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(!cursed ? ColorUtils.White : ColorUtils.Mix(ScourgedColor, ColorUtils.White, component.OutlineAlpha));\n\n\t\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\t\tGraphics.Render(s, position + d, angle, origin);\n\t\t\t\t\t}\n\n\t\t\t\t\tShaders.End();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (item.Masked) {\n\t\t\t\tGraphics.Color = MaskedColor;\n\t\t\t\tGraphics.Render(s, position, angle, origin);\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t} else {\n\t\t\t\tif (!shadow && DebugWindow.ItemShader && !Settings.LowQuality) {\n\t\t\t\t\tvar shader = Shaders.Item;\n\t\t\t\t\n\t\t\t\t\tShaders.Begin(shader);\n\t\t\t\t\tshader.Parameters[\"time\"].SetValue(T * 0.1f);\n\t\t\t\t\tshader.Parameters[\"size\"].SetValue(FlashSize);\n\t\t\t\t}\n\n\t\t\t\tGraphics.Render(s, position, angle, origin);\n\n\t\t\t\tif (!shadow && DebugWindow.ItemShader && !Settings.LowQuality) {\n\t\t\t\t\tShaders.End();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemInfo.cs",
    "content": "﻿using System;\n\nnamespace BurningKnight.entity.item {\n\tpublic class ItemInfo {\n\t\tpublic Chance Chance;\n\t\tpublic string Id;\n\t\tpublic Func<Item> Create;\n\t\tpublic float Warrior;\n\t\tpublic ItemType Type;\n\n\t\tpublic ItemInfo(string id, Func<Item> create, ItemType type = ItemType.Artifact, Chance chance = null) {\n\t\t\tId = id;\n\t\t\tCreate = create;\n\t\t\tChance = chance ?? Chance.All();\n\t\t\tType = type;\n\t\t}\n\n\t\tpublic bool Unlocked(string Key) {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemPair.cs",
    "content": "namespace BurningKnight.entity.item {\n\tpublic class ItemPair {\n\t\tpublic string Id;\n\t\tpublic int Count = 1;\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemPickupFx.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item {\n\tpublic class ItemPickupFx : Entity {\n\t\tprivate Item item;\n\t\tprivate bool tweened;\n\t\tprivate float y;\n\t\tprivate TweenTask task;\n\t\t\n\t\tpublic ItemPickupFx(Item it) {\n\t\t\titem = it;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tstring text;\n\n\t\t\tif (Locale.Current == \"de\" || Locale.Current == \"it\") {\n\t\t\t\ttext = item.Hidden ? \"???\" : (item.Scourged ? $\"{item.Name} ({Locale.Get(\"scourged\")})\" : item.Name);\n\t\t\t} else {\n\t\t\t\ttext = item.Hidden ? \"???\" : (item.Scourged ? $\"{Locale.Get(\"scourged\")} {item.Name}\" : item.Name);\n\t\t\t}\n\n\t\t\tvar size = Font.Medium.MeasureString(text);\n\n\t\t\tWidth = size.Width;\n\t\t\tHeight = size.Height;\n\t\t\t\n\t\t\tvar component = new TextGraphicsComponent(text);\n\t\t\tAddComponent(component);\n\n\t\t\tcomponent.Scale = 0;\n\t\t\ttask = Tween.To(component, new {Scale = 1.3f}, 0.25f, Ease.BackOut);\n\n\t\t\ty = 12;\n\t\t\tTween.To(0, y, x => y = x, 0.2f);\n\t\t\t\n\t\t\tUpdatePosition();\n\n\t\t\tif (item.Scourged) {\n\t\t\t\tcomponent.Color = Palette.Default[ItemGraphicsComponent.ScourgedColorId];\n\t\t\t}\n\t\t}\n\n\t\tprivate void UpdatePosition() {\n\t\t\tvar yy = 0f;\n\t\t\t\n\t\t\tif (item.Animation == null) {\n\t\t\t\tvar c = item.GetComponent<ItemGraphicsComponent>();\n\t\t\t\tyy = ItemGraphicsComponent.CalculateMove(c.T) * Display.UiScale;\n\t\t\t}\n\t\t\t\n\t\t\tCenter = Camera.Instance.CameraToUi(new Vector2(item.CenterX, item.Y - 8 + y + yy));\n\t\t\tGetComponent<TextGraphicsComponent>().Angle = (float) (Math.Cos(Engine.Instance.State.Time) * 0.05f);\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tif (!Engine.Instance.State.Paused) {\n\t\t\t\tbase.Render();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tUpdatePosition();\n\n\t\t\tif (!tweened) {\n\t\t\t\tif (!item.TryGetComponent<InteractableComponent>(out var component) || component.CurrentlyInteracting == null) {\n\t\t\t\t\tif (item.TryGetComponent<OwnerComponent>(out var owner) && owner.Owner is ItemStand stand && stand.GetComponent<InteractableComponent>().CurrentlyInteracting != null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\ttask.Ended = true;\n\t\t\t\t\t\n\t\t\t\t\tTween.To(GetComponent<TextGraphicsComponent>(), new {Scale = 0}, 0.2f).OnEnd = () => Done = true;\n\t\t\t\t\tTween.To(12, y, x => y = x, 0.5f);\n\t\t\t\t\t\n\t\t\t\t\ttweened = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemPool.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.util;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item {\n\tpublic class ItemPool {\n\t\tpublic static Dictionary<string, ItemPool> ByName = new Dictionary<string, ItemPool>();\n\t\tpublic static ItemPool[] ById = new ItemPool[32];\n\t\tpublic static string[] Names = new string[32];\n\n\t\tstatic ItemPool() {\n\t\t\t// So that imgui doesnt crash\n\t\t\tfor (var i = 0; i < 32; i++) {\n\t\t\t\tif (Names[i] == null) {\n\t\t\t\t\tNames[i] = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static readonly ItemPool Consumable = new ItemPool(\"consumable\");\n\t\tpublic static readonly ItemPool Treasure = new ItemPool(\"treasure\");\n\t\tpublic static readonly ItemPool Secret = new ItemPool(\"secret\");\n\t\tpublic static readonly ItemPool Snek = new ItemPool(\"snek\");\n\t\tpublic static readonly ItemPool Boxy = new ItemPool(\"boxy\");\n\t\tpublic static readonly ItemPool StartingWeapon = new ItemPool(\"starting_weapon\");\n\t\tpublic static readonly ItemPool Shop = new ItemPool(\"shop\");\n\t\tpublic static readonly ItemPool Boss = new ItemPool(\"boss\");\n\t\tpublic static readonly ItemPool ShopConsumable = new ItemPool(\"shop_consumable\");\n\t\tpublic static readonly ItemPool Safe = new ItemPool(\"safe\");\n\t\tpublic static readonly ItemPool Charger = new ItemPool(\"charger\");\n\t\tpublic static readonly ItemPool WoodenChest = new ItemPool(\"wooden_chest\");\n\t\tpublic static readonly ItemPool GoldChest = new ItemPool(\"gold_chest\");\n\t\tpublic static readonly ItemPool ScourgedChest = new ItemPool(\"scourged_chest\");\n\t\tpublic static readonly ItemPool DoubleChest = new ItemPool(\"double_chest\");\n\t\tpublic static readonly ItemPool TripleChest = new ItemPool(\"triple_chest\");\n\t\tpublic static readonly ItemPool RedChest = new ItemPool(\"red_chest\");\n\t\tpublic static readonly ItemPool Pet = new ItemPool(\"pet\");\n\t\tpublic static readonly ItemPool Orbital = new ItemPool(\"orbital\");\n\t\tpublic static readonly ItemPool StoneChest = new ItemPool(\"stone_chest\");\n\t\tpublic static readonly ItemPool Granny = new ItemPool(\"granny\");\n\t\tpublic static readonly ItemPool OldMan = new ItemPool(\"old_man\");\n\t\tpublic static readonly ItemPool Vampire = new ItemPool(\"vampire\");\n\t\tpublic static readonly ItemPool Roger = new ItemPool(\"roger\");\n\t\tpublic static readonly ItemPool Weapon = new ItemPool(\"weapon\");\n\t\tpublic static readonly ItemPool SpikedRoom = new ItemPool(\"spiked_room\");\n\t\tpublic static readonly ItemPool DuckChest = new ItemPool(\"duck_chest\");\n\t\tpublic static readonly ItemPool Gobetta = new ItemPool(\"gobetta\");\n\t\tpublic static readonly ItemPool BossRush = new ItemPool(\"boss_rush\");\n\n\t\tprivate static int count;\n\t\tpublic static int Count => count;\n\t\t\n\t\tpublic readonly string Name;\n\t\tpublic readonly int Id;\n\n\t\tpublic ItemPool(string name) {\n\t\t\tif (count >= 32) {\n\t\t\t\tLog.Error($\"Can not define item pool {name}, 32 pools were already defined\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tName = name;\n\t\t\tId = count;\n\n\t\t\tById[Id] = this;\n\t\t\tByName[name] = this;\n\t\t\tNames[Id] = name;\n\t\t\t\n\t\t\tcount++;\n\t\t}\n\n\t\tpublic int Apply(int pools, bool add = true) {\n\t\t\treturn BitHelper.SetBit(pools, Id, add);\n\t\t}\n\t\t\n\t\tpublic bool Contains(int pools) {\n\t\t\treturn BitHelper.IsBitSet(pools, Id);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemQuality.cs",
    "content": "namespace BurningKnight.entity.item {\n\t// Keep in sync with ItemEditor::Quality!!\n\tpublic enum ItemQuality {\n\t\tWooden,\n\t\tIron,\n\t\tGolden,\n\t\tTrash\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/ItemType.cs",
    "content": "namespace BurningKnight.entity.item {\n\t// Keep in sync with item editor defenition!!!\n\t// (in the same order)\n\tpublic enum ItemType {\n\t\tArtifact,\n\t\tActive,\n\t\tCoin,\n\t\tBomb,\n\t\tKey,\n\t\tHeart,\n\t\tConsumableArtifact,\n\t\tWeapon,\n\t\tBattery,\n\t\tHat,\n\t\tPouch,\n\t\tScourge,\n\t\tMana,\n\t\tLamp\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/PriceCalculator.cs",
    "content": "using System;\nusing BurningKnight.state;\n\nnamespace BurningKnight.entity.item {\n\tpublic static class PriceCalculator {\n\t\tpublic static int BasePrice(ItemType type) {\n\t\t\tswitch (type) {\n\t\t\t\tcase ItemType.Lamp:\n\t\t\t\tcase ItemType.Artifact: return 15;\n\t\t\t\t\n\t\t\t\tcase ItemType.Active:\n\t\t\t\tcase ItemType.Coin: return 10;\n\t\t\t\t\n\t\t\t\tcase ItemType.Bomb:\n\t\t\t\tcase ItemType.Key:\n\t\t\t\tcase ItemType.Battery:\n\t\t\t\tcase ItemType.Heart: return 3;\n\t\t\t\t\n\t\t\t\tcase ItemType.Hat: return 1;\n\t\t\t\t\n\t\t\t\tdefault: return 15;\n\t\t\t}\n\t\t}\n\n\t\tpublic static float GetPriceModifier(this ItemQuality quality) {\n\t\t\tswitch (quality) {\n\t\t\t\tcase ItemQuality.Wooden: default: return 1;\n\t\t\t\tcase ItemQuality.Iron: return 1.333f;\n\t\t\t\tcase ItemQuality.Golden: return 2f;\n\t\t\t\tcase ItemQuality.Trash: return 0.5f;\n\t\t\t}\t\n\t\t}\n\n\t\tpublic static float GetModifier(Item item) {\n\t\t\treturn Math.Max(1, Math.Min(99, (Run.Loop > 0 ? 7 : 1) * (Scourge.IsEnabled(Scourge.OfGreed) ? 2 : 1) * item.Data.Quality.GetPriceModifier()));\n\t\t}\n\t\t\n\t\tpublic static int Calculate(Item item) {\n\t\t\treturn (int) Math.Round(BasePrice(item.Type) * GetModifier(item));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/RandomItem.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.ui.editor;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.item {\n\tpublic class RandomItem : RoundItem {\n\t\tpublic bool Prevent;\n\t\n\t\tprivate static string GenerateId() {\n\t\t\treturn Items.Generate(ItemPool.Treasure);\n\t\t}\n\n\t\tprivate void TryToOverrideId() {\n\t\t\tif (Prevent) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tConvertTo(GenerateId());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tTryToOverrideId();\n\t\t\tbase.PostInit();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/Reroller.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.room;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item {\n\tpublic static class Reroller {\n\t\tprivate static bool CanReroll(Item i) {\n\t\t\treturn !(i.Id == \"bk:idol\" || i.Type == ItemType.Scourge || i.Type == ItemType.Bomb || i.Type == ItemType.Key || i.Type == ItemType.Heart || i.Type == ItemType.Coin || i.Type == ItemType.Battery || i.Type == ItemType.Mana || i is RoundItem);\n\t\t}\n\n\t\tpublic static void Reroll(Area area, Room room, bool rerollStands, bool spawnNewItems, bool ignore, ItemType[] types, Action<Item> processItem = null, bool d2 = false) {\n\t\t\tvar items = room.Tagged[Tags.Item].ToArray();\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(room.GetPool() ?? ItemPool.Shop));\n\t\t\t\n\t\t\tforeach (var e in items) {\n\t\t\t\tItem item = null;\n\t\t\t\t\n\t\t\t\tif (e is ItemStand s) {\n\t\t\t\t\tif (rerollStands) {\n\t\t\t\t\t\tif (s.Item == null) {\n\t\t\t\t\t\t\tif (spawnNewItems) {\n\t\t\t\t\t\t\t\tvar id = s is ShopStand std ? Items.Generate(std.GetPool()) : Items.GenerateAndRemove(pool);\n\t\t\t\t\t\t\t\ts.SetItem(Items.CreateAndAdd(id, area), null);\n\n\t\t\t\t\t\t\t\tTextParticle.Add(s, Locale.Get(\"rerolled\")).Stacks = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar i = s.Item;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!CanReroll(i)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\titem = i;\n\t\t\t\t\t}\n\t\t\t\t} else if (e is Item i) {\n\t\t\t\t\tif (!CanReroll(i)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (types != null) {\n\t\t\t\t\t\tvar found = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var t in types) {\n\t\t\t\t\t\t\tif (t == i.Type) {\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (found == ignore) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\titem = i;\n\t\t\t\t}\n\n\t\t\t\tif (item == null || (item.TryGetComponent<OwnerComponent>(out var o) && !(o.Owner is ItemStand))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (Reroll(item, pool, null, d2)) {\n\t\t\t\t\tprocessItem?.Invoke(item);\n\t\t\t\t}\n\n\t\t\t\tif (e is ShopStand st) {\n\t\t\t\t\tst.Recalculate();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlaySfx(\"item_reroll\");\n\t\t}\n\n\t\tpublic static bool Reroll(Item item, ItemPool pool, Func<ItemData, bool> filter = null) {\n\t\t\tvar id = Items.Generate(pool, i => i.Id != item.Id && Items.ShouldAppear(i) && (filter == null || filter(i)));\n\n\t\t\tif (id != null) {\n\t\t\t\titem.LastId = item.Id;\n\t\t\t\titem.ConvertTo(id);\n\t\t\t\titem.AutoPickup = false;\n\t\t\t\t\n\t\t\t\tTextParticle.Add(item, Locale.Get(\"rerolled\")).Stacks = false;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static bool Reroll(Item item, List<ItemData> pool, Func<ItemData, bool> filter = null, bool d2 = false) {\n\t\t\tvar id = d2 ? item.LastId : null;\n\n\t\t\tif (id == null) {\n\t\t\t\tid = Items.GenerateAndRemove(pool, i => i.Id != item.Id && (filter == null || filter(i)));\n\t\t\t}\n\t\t\t\n\t\t\tif (id != null) {\n\t\t\t\titem.LastId = item.Id;\n\t\t\t\titem.ConvertTo(id);\n\t\t\t\titem.AutoPickup = false;\n\n\t\t\t\tTextParticle.Add(item, Locale.Get(\"rerolled\")).Stacks = false;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/RoundItem.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item {\n\tpublic class RoundItem : Item {\n\t\tpublic bool Transparent;\n\t\tpublic bool Won;\n\t\t\n\t\tprotected override BodyComponent GetBody() {\n\t\t\treturn GetComponent<CircleBodyComponent>();\n\t\t}\n\n\t\tprotected override bool HasBody() {\n\t\t\treturn HasComponent<CircleBodyComponent>();\n\t\t}\n\n\t\tprotected override void RemoveBody() {\n\t\t\tRemoveComponent<CircleBodyComponent>();\n\t\t}\n\t\t\n\t\tprotected override BodyComponent CreateBody() {\n\t\t\treturn new CircleBodyComponent(0, 0, 8);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn !Transparent && base.ShouldCollide(entity);\n\t\t}\n\n\t\tprotected override bool ShouldInteract(Entity entity) {\n\t\t\treturn !Transparent && Won && base.ShouldInteract(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/Scourge.cs",
    "content": "using System.Collections.Generic;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item {\n\tpublic static class Scourge {\n\t\tprivate static Dictionary<string, bool> enabled = new Dictionary<string, bool>();\n\t\tpublic static List<string> Defined = new List<string>();\n\t\t\n\t\tpublic const string OfUnknown = \"bk:of_unknown\";\n\t\tpublic const string OfRisk = \"bk:of_risk\";\n\t\tpublic const string OfScourged = \"bk:of_scourged\";\n\t\tpublic const string OfBlood = \"bk:of_blood\";\n\t\tpublic const string OfLost = \"bk:of_lost\";\n\t\tpublic const string OfKeys = \"bk:of_keys\";\n\t\tpublic const string OfEgg = \"bk:of_egg\";\n\t\tpublic const string OfIllness = \"bk:of_illness\";\n\t\tpublic const string OfGreed = \"bk:of_greed\";\n\t\t\n\t\tpublic const string OfDeath = \"bk:of_death\";\n\n\t\tpublic static void Define(string curse) {\n\t\t\tDefined.Add(curse);\n\t\t}\n\n\t\tstatic Scourge() {\n\t\t\tDefine(OfUnknown);\n\t\t\tDefine(OfRisk);\n\t\t\tDefine(OfScourged);\n\t\t\tDefine(OfBlood);\n\t\t\tDefine(OfLost);\n\t\t\tDefine(OfKeys);\n\t\t\tDefine(OfEgg);\n\t\t\tDefine(OfIllness);\n\t\t\tDefine(OfGreed);\n\t\t\tDefine(OfDeath);\n\t\t}\n\n\t\tpublic static void Clear() {\n\t\t\tenabled.Clear();\n\t\t}\n\n\t\tpublic static void Enable(string curse) {\n\t\t\tif (IsEnabled(curse)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tenabled[curse] = true;\n\t\t\tLog.Info($\"Scourge {curse} was activated!\");\n\t\t}\n\n\t\tpublic static void Disable(string curse) {\n\t\t\tif (!IsEnabled(curse)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tenabled[curse] = false;\n\t\t\tLog.Info($\"Scourge {curse} was deactivated!\");\n\t\t}\n\n\t\tpublic static bool IsEnabled(string curse) {\n\t\t\tif (!enabled.ContainsKey(curse)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn enabled[curse];\n\t\t}\n\n\t\tpublic static bool ShouldAppear(string id) {\n\t\t\tif (id == OfDeath) {\n\t\t\t\tforeach (var s in Defined) {\n\t\t\t\t\tif (s != OfDeath && !IsEnabled(s)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (id == OfScourged) {\n\t\t\t\tvar found = false;\n\t\t\t\t\n\t\t\t\tforeach (var s in Defined) {\n\t\t\t\t\tif (IsEnabled(s)) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn !IsEnabled(id);\n\t\t}\n\n\t\tpublic static string Generate() {\n\t\t\tvar list = GenerateList();\n\t\t\treturn list.Count == 0 ? null : list[Rnd.Int(list.Count)];\n\t\t}\n\n\t\tpublic static string GenerateItemId() {\n\t\t\tvar id = Generate();\n\n\t\t\tif (id == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn $\"bk:scourge_{id.Replace(\"bk:\", \"\")}\";\n\t\t}\n\t\t\n\t\tpublic static List<string> GenerateList() {\n\t\t\tvar list = new List<string>();\n\n\t\t\tforeach (var s in Defined) {\n\t\t\t\tif (ShouldAppear(s)) {\n\t\t\t\t\tlist.Add(s);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/SingleChoiceStand.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.save;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.util.camera;\r\n\r\nnamespace BurningKnight.entity.item {\r\n\tpublic class SingleChoiceStand : ItemStand {\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tSubscribe<ItemTakenEvent>();\r\n\t\t}\r\n\r\n\t\tprotected override string GetSprite() {\r\n\t\t\treturn \"single_stand\";\r\n\t\t}\r\n\r\n\t\tprotected override bool CanInteract(Entity e) {\r\n\t\t\treturn Item != null && base.CanInteract(e);\r\n\t\t}\r\n\r\n\t\tprotected virtual void RemoveStands() {\r\n\t\t\tvar rm = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (rm == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tGlobalSave.Put(\"item_stolen\", true);\r\n\t\t\tvar it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it\r\n\t\t\t\t\r\n\t\t\tforeach (var s in it) {\r\n\t\t\t\tif (s is SingleChoiceStand ist) {\r\n\t\t\t\t\tif (s is HealChoiceStand) {\r\n\t\t\t\t\t\tAnimationUtil.Poof(ist.Center);\r\n\t\t\t\t\t\tist.Done = true;\r\n\t\t\t\t\t} else if (ist.Item != null) {\r\n\t\t\t\t\t\tvar i = ist.Item;\r\n\t\t\t\t\t\tist.SetItem(null, this);\r\n\t\t\t\t\t\ti.Done = true;\r\n\t\t\t\t\t\tAnimationUtil.Poof(ist.Center);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\tCamera.Instance.Shake(10);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is ItemTakenEvent ite && !(ite.Who is SingleChoiceStand || !(ite.Stand is SingleChoiceStand))) {\r\n\t\t\t\tvar rm = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\tif (rm == null) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (ite.Stand != this && ite.Stand.GetComponent<RoomComponent>().Room == rm) {\r\n\t\t\t\t\tRemoveStands();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/SpawnMobsUse.cs",
    "content": "using System;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item {\n\tpublic class SpawnMobsUse : ItemUse {\n\t\tpublic int Count;\n\n\t\tprivate static Func<int, int, bool> CheckDistance(Entity entity) {\n\t\t\treturn (x, y) => entity.DistanceTo(new Vector2(x * 16, y * 16)) > 32;\n\t\t}\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (!entity.TryGetComponent<RoomComponent>(out var r) || r.Room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar filter = CheckDistance(entity);\n\t\t\tMobRegistry.SetupForBiome(Run.Level.Biome.Id);\n\t\t\t\n\t\t\tfor (var i = 0; i < Count; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar mob = MobRegistry.Generate();\n\t\t\t\t\tentity.Area.Add(mob);\n\n\t\t\t\t\tif (MobRegistry.FindFor(mob.GetType())?.NearWall ?? false) {\n\t\t\t\t\t\tmob.Center = r.Room.GetRandomFreeTileNearWall(filter) * 16;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmob.Center = r.Room.GetRandomFreeTile(filter) * 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar where = mob.Center;\n\t\t\t\t\t\n\t\t\t\t\tfor (var j = 0; j < 8; j++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\t\tpart.Position = where + Rnd.Vector(-8, 8);\n\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 1.3f);\n\t\t\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 40);\n\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tAudio.PlaySfx(\"scroll\");\n\t\t\t\t}, (i - 1) * 0.2f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tCount = settings[\"count\"].Int(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar v = root[\"count\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Count\", ref v)) {\n\t\t\t\troot[\"count\"] = v;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/Weapon.cs",
    "content": "﻿namespace BurningKnight.entity.item {\n\tpublic class Weapon : Item {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/WeaponType.cs",
    "content": "namespace BurningKnight.entity.item {\n\t// Keep in sync with the ItemEditor's names!!\n\t// Don't forget to update WeaponTypeHelper's switch blocks after changing this\n\tpublic enum WeaponType {\n\t\tMelee,\n\t\tRanged,\n\t\tMagic,\n\t\tNone\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/WeaponTypeHelper.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.item {\n\tpublic static class WeaponTypeHelper {\n\t\tpublic static string GetPickupSfx(this WeaponType type) {\n\t\t\tswitch (type) {\n\t\t\t\tcase WeaponType.Melee: default: return \"item_sword_pickup\";\n\t\t\t\tcase WeaponType.Ranged: return \"item_gun_pickup\";\n\t\t\t\tcase WeaponType.Magic: return \"item_magic_pickup\";\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static string GetSwapSfx(this WeaponType type) {\n\t\t\tswitch (type) {\n\t\t\t\tcase WeaponType.Melee: default: return \"item_sword_switch\";\n\t\t\t\tcase WeaponType.Ranged: return \"item_gun_switch\";\n\t\t\t\tcase WeaponType.Magic: return \"item_magic_switch\";\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/renderer/AngledRenderer.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.item.renderer {\n\tpublic class AngledRenderer : ItemRenderer {\n\t\tpublic float Angle;\n\t\tpublic bool InvertBack;\n\t\tpublic float AddedAngle;\n\t\tpublic float SwingAngle;\n\t\t\n\t\tprivate double lastAngle;\n\t\tprivate float sx = 1;\n\t\tprivate float sy = 1;\n\t\tprivate float oy;\n\t\tprivate float ox;\n\n\t\tpublic override void Render(bool atBack, bool paused, float dt, bool shadow, int offset) {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar s = dt * 10f;\n\n\t\t\tsx += (1 - sx) * s;\n\t\t\tsy += (1 - sy) * s;\n\t\t\tox += (-ox) * s;\n\t\t\toy += (-oy) * s;\n\t\t\t\n\t\t\tvar region = Item.Region;\n\t\t\tvar owner = Item.Owner;\n\n\t\t\tvar of = owner.GraphicsComponent.Flipped;\n\t\t\tvar flipped = false;\n\t\t\t\n\t\t\tvar angle = MathUtils.Mod((of ? -Angle : Angle) + (atBack ? ((InvertBack ? -1 : 1) * (of ? -Math.PI / 4 : Math.PI / 4)) : lastAngle), Math.PI * 2);\n\t\t\tvar vf = angle > Math.PI * 0.5f && angle < Math.PI * 1.5f;\n\t\t\t\n\t\t\tif (!atBack && !paused && !shadow) {\n\t\t\t\tvar to = owner.GetComponent<AimComponent>().Aim;\n\t\t\t\t/*var dx = Nozzle.X - Origin.X;\n\t\t\t\tvar dy = Nozzle.Y - Origin.Y;\n\n\t\t\t\tif (vf) {\n\t\t\t\t\tdy *= -1;\n\t\t\t\t}\n\n\t\t\t\t*var a = MathUtils.Angle(dx, dy) + lastAngle - AddedAngle - SwingAngle;\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\tto -= MathUtils.CreateVector(a, d);\n\n\t\t\t\towner.GetComponent<AimComponent>().Aim = to;*/\n\t\t\t\tlastAngle = MathUtils.LerpAngle(lastAngle, owner.AngleTo(to), dt * 24f);\n\t\t\t}\n\n\t\t\tif (atBack) {\n\t\t\t\tflipped = !flipped;\n\t\t\t} else {\n\t\t\t\tangle += (SwingAngle + AddedAngle) * (of ? -1 : 1);\n\t\t\t}\n\n\t\t\tvar pos = new Vector2(owner.CenterX + (of ? -5 : 5), owner.CenterY + offset + (shadow ? owner.Height : 0));\n\t\t\tvar or = Origin + new Vector2(ox, oy);\n\t\t\tvar sc = new Vector2(flipped ? -sx : sx, (shadow ^ vf) ? -sy : sy);\n\t\t\tvar fangle = (float) angle * (shadow ? -1 : 1);\n\n\t\t\tif (!shadow && !atBack) {\n\t\t\t\tvar dx = Nozzle.X - or.X;\n\t\t\t\tvar dy = Nozzle.Y - or.Y;\n\n\t\t\t\tif (vf) {\n\t\t\t\t\tdy *= -1;\n\t\t\t\t}\n\n\t\t\t\tvar a = MathUtils.Angle(dx, dy) + angle;\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tvar aim = owner.GetComponent<AimComponent>();\n\n\t\t\t\taim.Center = pos + MathUtils.CreateVector(a, d);\n\n\t\t\t\td = (aim.Aim - pos).Length();\n\t\t\t\taim.RealAim = aim.Center + MathUtils.CreateVector(angle - AddedAngle - SwingAngle, d);\n\t\t\t}\n\n\t\t\tif (Item.Scourged) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ItemGraphicsComponent.ScourgedColor);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(region, pos + d, fangle, or, sc);\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tGraphics.Render(region, pos, fangle, or, sc);\n\t\t}\n\n\t\tpublic override void OnUse() {\n\t\t\tbase.OnUse();\n\n\t\t\tsx = 0.3f;\n\t\t\tsy = 2f;\n\t\t\tox = 8;\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tInvertBack = settings[\"invert_back\"].Bool(true);\n\t\t\tAddedAngle = settings[\"aa\"].Number(0).ToRadians();\n\t\t}\n\n\t\tpublic static void RenderDebug(string id, JsonValue parent, JsonValue root) {\n\t\t\tItemRenderer.RenderDebug(id, parent, root);\n\n\t\t\tvar invert = root[\"invert_back\"].AsBoolean;\n\n\t\t\tif (ImGui.Checkbox(\"Invert back?\", ref invert)) {\n\t\t\t\troot[\"invert_back\"] = invert;\n\t\t\t}\n\t\t\t\n\t\t\tvar min = (float) root[\"aa\"].Number(0);\n\n\t\t\tif (ImGui.InputFloat(\"Added Angle\", ref min)) {\n\t\t\t\troot[\"aa\"] = min;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/renderer/ItemRenderer.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.graphics;\nusing Lens.lightJson;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.renderer {\n\tpublic class ItemRenderer {\n\t\tpublic Item Item;\n\t\tpublic Vector2 Origin;\n\t\tpublic Vector2 Nozzle;\n\t\tpublic bool Hidden;\n\n\t\tpublic virtual void Render(bool atBack, bool paused, float dt, bool shadow, int offset) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Setup(JsonValue settings) {\n\t\t\tOrigin.X = settings[\"ox\"].Number(0);\n\t\t\tOrigin.Y = settings[\"oy\"].Number(0);\n\t\t\tNozzle.X = settings[\"nx\"].Number(0);\n\t\t\tNozzle.Y = settings[\"ny\"].Number(0);\n\t\t}\n\n\t\tpublic virtual void OnUse() {\n\t\t\t\n\t\t}\n\t\t\n\t\tprivate static bool snapGrid = true;\n\n\t\tpublic static unsafe void RenderDebug(string id, JsonValue parent, JsonValue root) {\n\t\t\tif (ImGui.TreeNode(\"Origin\")) {\n\t\t\t\tvar v = new System.Numerics.Vector2((float) root[\"ox\"].AsNumber * 3, (float) root[\"oy\"].AsNumber * 3);\n\t\t\t\tvar region = CommonAse.Items.GetSlice(id);\n\t\t\t\tvar m = ImGui.GetScrollY();\n\t\t\t\tvar pos = ImGui.GetWindowPos() + ImGui.GetCursorPos() - new System.Numerics.Vector2(0, m);\n\n\t\t\t\tif (ImGui.IsMouseDown(1)) {\n\t\t\t\t\tv = ImGui.GetMousePos() - pos;\n\t\t\t\t\t\n\t\t\t\t\tif (!(v.X < 0) && !(v.Y < 0) && !(v.X > region.Width * 3) && !(v.Y > region.Height * 3)) {\n\t\t\t\t\t\tif (snapGrid) {\n\t\t\t\t\t\t\tv.X = (float) (Math.Floor(v.X / 3) * 3);\n\t\t\t\t\t\t\tv.Y = (float) (Math.Floor(v.Y / 3) * 3);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tv.X = VelcroPhysics.Utilities.MathUtils.Clamp(v.X, 0, region.Width * 3);\n\t\t\t\t\t\tv.Y = VelcroPhysics.Utilities.MathUtils.Clamp(v.Y, 0, region.Height * 3);\n\n\t\t\t\t\t\troot[\"ox\"] = v.X / 3f;\n\t\t\t\t\t\troot[\"oy\"] = v.Y / 3f;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGuiNative.ImDrawList_AddRect(ImGui.GetWindowDrawList(), pos - new System.Numerics.Vector2(1, 1),\n\t\t\t\t\tpos + new System.Numerics.Vector2(region.Width * 3 + 1, region.Height * 3 + 1),\n\t\t\t\t\tColorUtils.WhiteColor.PackedValue, 0, 0, 1);\n\n\t\t\t\tItemEditor.DrawItem(region);\n\n\t\t\t\tImGuiNative.ImDrawList_AddCircleFilled(ImGui.GetWindowDrawList(), pos + v, 3, ColorUtils.WhiteColor.PackedValue,\n\t\t\t\t\t8);\n\n\t\t\t\tv /= 3f;\n\n\t\t\t\tImGui.Checkbox(\"Snap to grid\", ref snapGrid);\n\n\t\t\t\tif (ImGui.InputFloat2(\"Origin\", ref v)) {\n\t\t\t\t\troot[\"ox\"] = v.X;\n\t\t\t\t\troot[\"oy\"] = v.Y;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"tx\")) {\n\t\t\t\t\troot[\"ox\"] = 0;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"ty\")) {\n\t\t\t\t\troot[\"oy\"] = 0;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"cx\")) {\n\t\t\t\t\troot[\"ox\"] = region.Width / 2f;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"cy\")) {\n\t\t\t\t\troot[\"oy\"] = region.Height / 2f;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"bx\")) {\n\t\t\t\t\troot[\"ox\"] = region.Width;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"by\")) {\n\t\t\t\t\troot[\"oy\"] = region.Height;\n\t\t\t\t}\n\n\t\t\t\tImGui.TreePop();\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.TreeNode(\"Nozzle\")) {\n\t\t\t\tvar v = new System.Numerics.Vector2((float) root[\"nx\"].AsNumber * 3, (float) root[\"ny\"].AsNumber * 3);\n\t\t\t\tvar region = CommonAse.Items.GetSlice(id);\n\t\t\t\tvar m = ImGui.GetScrollY();\n\t\t\t\tvar pos = ImGui.GetWindowPos() + ImGui.GetCursorPos() - new System.Numerics.Vector2(0, m);\n\t\t\t\t\n\t\t\t\tif (ImGui.IsMouseDown(1)) {\n\t\t\t\t\tv = ImGui.GetMousePos() - pos;\n\n\t\t\t\t\tif (!(v.X < 0) && !(v.Y < 0) && !(v.X > region.Width * 3) && !(v.Y > region.Height * 3)) {\n\t\t\t\t\t\tif (snapGrid) {\n\t\t\t\t\t\t\tv.X = (float) (Math.Floor(v.X / 3) * 3);\n\t\t\t\t\t\t\tv.Y = (float) (Math.Floor(v.Y / 3) * 3);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tv.X = VelcroPhysics.Utilities.MathUtils.Clamp(v.X, 0, region.Width * 3);\n\t\t\t\t\t\tv.Y = VelcroPhysics.Utilities.MathUtils.Clamp(v.Y, 0, region.Height * 3);\n\n\t\t\t\t\t\troot[\"nx\"] = v.X / 3f;\n\t\t\t\t\t\troot[\"ny\"] = v.Y / 3f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tImGuiNative.ImDrawList_AddRect(ImGui.GetWindowDrawList(), pos - new System.Numerics.Vector2(1, 1),\n\t\t\t\t\tpos + new System.Numerics.Vector2(region.Width * 3 + 1, region.Height * 3 + 1),\n\t\t\t\t\tColorUtils.WhiteColor.PackedValue, 0, 0, 1);\n\n\t\t\t\tItemEditor.DrawItem(region);\n\n\t\t\t\tImGuiNative.ImDrawList_AddCircleFilled(ImGui.GetWindowDrawList(), pos + v, 3, ColorUtils.WhiteColor.PackedValue,\n\t\t\t\t\t8);\n\n\t\t\t\tv /= 3f;\n\n\t\t\t\tImGui.Checkbox(\"Snap to grid\", ref snapGrid);\n\n\t\t\t\tif (ImGui.InputFloat2(\"Nozzle\", ref v)) {\n\t\t\t\t\troot[\"nx\"] = v.X;\n\t\t\t\t\troot[\"ny\"] = v.Y;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"tx\")) {\n\t\t\t\t\troot[\"nx\"] = 0;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"ty\")) {\n\t\t\t\t\troot[\"ny\"] = 0;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"cx\")) {\n\t\t\t\t\troot[\"nx\"] = region.Width / 2f;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"cy\")) {\n\t\t\t\t\troot[\"ny\"] = region.Height / 2f;\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.Button(\"bx\")) {\n\t\t\t\t\troot[\"nx\"] = region.Width;\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"by\")) {\n\t\t\t\t\troot[\"oy\"] = region.Height;\n\t\t\t\t}\n\n\t\t\t\tImGui.TreePop();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/renderer/MovingAngledRenderer.cs",
    "content": "﻿using ImGuiNET;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.tween;\n\nnamespace BurningKnight.entity.item.renderer {\n\tpublic class MovingAngledRenderer : AngledRenderer {\n\t\tpublic float MaxAngle;\t\t\n\t\tpublic float MinAngle;\n\t\tpublic bool Stay;\n\t\tpublic float SwingTime;\n\t\tpublic float ReturnTime;\n\t\tprivate bool stayed;\n\t\t\n\t\tpublic override void OnUse() {\n\t\t\tvar task = Tween.To(stayed ? MinAngle : MaxAngle, SwingAngle, x => SwingAngle = x, SwingTime);\n\t\t\t\n\t\t\tif (!Stay) {\n\t\t\t\ttask.OnEnd = () => {\n\t\t\t\t\tTween.To(stayed ? MinAngle : MaxAngle, SwingAngle, x => SwingAngle = x, ReturnTime);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tstayed = !stayed;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tStay = settings[\"stay\"].Bool(false);\n\t\t\tMaxAngle = settings[\"max_angle\"].Number(180).ToRadians();\n\t\t\tMinAngle = settings[\"min_angle\"].Number(0).ToRadians();\n\t\t\tSwingTime = settings[\"st\"].Number(0.1f);\n\t\t\tReturnTime = settings[\"rt\"].Number(0.2f);\n\n\t\t\tSwingAngle = MinAngle;\n\t\t}\n\n\t\tpublic static void RenderDebug(string id, JsonValue parent, JsonValue root) {\n\t\t\tAngledRenderer.RenderDebug(id, parent, root);\n\n\t\t\tvar min = (float) root[\"min_angle\"].Number(0);\n\n\t\t\tif (ImGui.InputFloat(\"Min Angle\", ref min)) {\n\t\t\t\troot[\"min_angle\"] = min;\n\t\t\t}\n\t\t\t\n\t\t\tvar max = (float) root[\"max_angle\"].Number(180);\n\n\t\t\tif (ImGui.InputFloat(\"Max Angle\", ref max)) {\n\t\t\t\troot[\"max_angle\"] = max;\n\t\t\t}\n\t\t\t\n\t\t\tvar stay = root[\"stay\"].AsBoolean;\n\n\t\t\tif (ImGui.Checkbox(\"Stay?\", ref stay)) {\n\t\t\t\troot[\"stay\"] = stay;\n\t\t\t}\n\n\t\t\tvar st = (float) root[\"st\"].Number(0.1f);\n\n\t\t\tif (ImGui.InputFloat(\"Swing Time\", ref st)) {\n\t\t\t\troot[\"st\"] = st;\n\t\t\t}\n\n\t\t\tif (!stay) {\n\t\t\t\tvar rt = (float) root[\"rt\"].Number(0.2f);\n\n\t\t\t\tif (ImGui.InputFloat(\"Return Time\", ref rt)) {\n\t\t\t\t\troot[\"rt\"] = rt;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/renderer/RendererRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.mod;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.renderer {\n\tpublic static class RendererRegistry {\n\t\tpublic static Dictionary<string, Action<string, JsonValue, JsonValue>> DebugRenderers = new Dictionary<string, Action<string, JsonValue, JsonValue>>();\n\t\tpublic static Dictionary<string, Type> Renderers = new Dictionary<string, Type>();\n\n\t\tpublic static ItemRenderer Create(string id) {\n\t\t\tif (!Renderers.TryGetValue(id, out var renderer)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn (ItemRenderer) Activator.CreateInstance(renderer);\n\t\t}\n\n\n\t\tpublic static void Register<T>(Mod mod, Action<string, JsonValue, JsonValue> renderer = null) where T : ItemRenderer {\n\t\t\tvar type = typeof(T);\n\t\t\tvar name = type.Name;\n\t\t\tvar id = $\"{mod?.Prefix ?? Mods.BurningKnight}:{(name.EndsWith(\"Renderer\") ? name.Substring(0, name.Length - 8) : name)}\";\n\n\t\t\tRenderers[id] = type;\n\n\t\t\tif (renderer != null) {\n\t\t\t\tDebugRenderers[id] = renderer;\n\t\t\t}\n\t\t}\n\n\t\tprivate static void Register<T>(Action<string, JsonValue, JsonValue> renderer = null) where T : ItemRenderer {\n\t\t\tRegister<T>(null, renderer);\n\t\t}\n\n\t\tstatic RendererRegistry() {\n\t\t\tRegister<AngledRenderer>(AngledRenderer.RenderDebug);\n\t\t\tRegister<MovingAngledRenderer>(MovingAngledRenderer.RenderDebug);\n\t\t\tRegister<StickRenderer>(StickRenderer.RenderDebug);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/renderer/StickRenderer.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.item.renderer {\n\tpublic class StickRenderer : ItemRenderer {\n\t\tprivate double lastAngle;\n\t\tprivate Vector2 scale = Vector2.One;\n\t\tprivate bool horizontal;\n\t\tprivate float move;\n\t\tprivate float currentMove;\n\t\tprivate float moveTime;\n\t\tprivate float returnTime;\n\t\t\n\t\tpublic override void OnUse() {\n\t\t\tif (move > 0.1f) {\n\t\t\t\tTween.To(move, currentMove, x => currentMove = x, moveTime).OnEnd = () => {\n\t\t\t\t\tTween.To(0, currentMove, x => currentMove = x, returnTime);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\n\t\t\t\tscale.X = 1.4f;\n\t\t\t\tscale.Y = 0.3f;\n\n\t\t\t\tTween.To(1, scale.X, x => scale.X = x, 0.2f);\n\t\t\t\tTween.To(1, scale.Y, x => scale.Y = x, 0.2f);\t\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render(bool atBack, bool paused, float dt, bool shadow, int offset) {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar region = Item.Region;\n\t\t\tvar owner = Item.Owner;\n\t\t\t\n\t\t\tif (!atBack && !paused && !shadow) {\n\t\t\t\tvar to = owner.GetComponent<AimComponent>().Aim;\n\t\t\t\t/*var dx = Nozzle.X - Origin.X;\n\t\t\t\tvar dy = Nozzle.Y - Origin.Y;\n\t\t\t\t\n\t\t\t\tvar a = MathUtils.Angle(dx, dy) + lastAngle;\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tto -= MathUtils.CreateVector(a, d);*/\n\t\t\t\tlastAngle = MathUtils.LerpAngle(lastAngle, owner.AngleTo(to) + Math.PI * 0.5f, dt * 24f);\n\t\t\t}\n\n\t\t\tvar angle = atBack ? (float) Math.PI * (owner.GraphicsComponent.Flipped ? 0.25f : -0.25f) : (float) lastAngle;\n\n\t\t\tif (horizontal) {\n\t\t\t\tangle -= (float) Math.PI * 0.5f;\n\t\t\t}\n\n\t\t\tvar pos = new Vector2(\n\t\t\t\towner.CenterX + (owner.GraphicsComponent.Flipped ? -5 : 5) + (horizontal ? 0 : (region.Width / 2f) * (owner.GraphicsComponent.Flipped ? -1 : 1)),\n\t\t\t\towner.CenterY + offset + (shadow ? owner.Height : 0)\n\t\t\t);\n\n\t\t\tvar or = Origin + new Vector2(0, currentMove);\n\t\t\tvar fangle = shadow ? -angle : angle;\n\t\t\tvar sc = new Vector2(scale.X, shadow ? -scale.Y : scale.Y);\n\n\t\t\tif (!shadow && !atBack) {\n\t\t\t\tvar dx = Nozzle.X - or.X;\n\t\t\t\tvar dy = Nozzle.Y - or.Y;\n\t\t\t\tvar a = MathUtils.Angle(dx, dy) + angle;\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tvar aim = owner.GetComponent<AimComponent>();\n\t\t\t\taim.Center = pos + MathUtils.CreateVector(a, d);\n\n\t\t\t\td = (aim.Aim - pos).Length();\n\t\t\t\taim.RealAim = aim.Center + MathUtils.CreateVector(angle - (horizontal ? 0 : Math.PI / 2), d);\n\t\t\t}\n\n\t\t\tif (Item.Scourged) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ItemGraphicsComponent.ScourgedColor);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(region, pos + d, fangle, or, sc);\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(region, pos, fangle, or, sc);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\thorizontal = settings[\"h\"];\n\t\t\tmove = settings[\"mv\"].Number(0);\n\t\t\tmoveTime = settings[\"mt\"].Number(0.1f);\n\t\t\treturnTime = settings[\"rt\"].Number(0.2f);\n\t\t}\n\n\t\tpublic static void RenderDebug(string id, JsonValue parent, JsonValue root) {\t\t\t\n\t\t\tItemRenderer.RenderDebug(id, parent, root);\n\n\t\t\tvar h = root[\"h\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Horizontal\", ref h)) {\n\t\t\t\troot[\"h\"] = h;\n\t\t\t}\n\t\t\t\n\t\t\tvar mv = (float) root[\"mv\"].Number(0);\n\n\t\t\tif (ImGui.InputFloat(\"Move\", ref mv)) {\n\t\t\t\troot[\"mv\"] = mv;\n\t\t\t}\n\t\t\t\n\t\t\tvar mt = (float) root[\"mt\"].Number(0.1f);\n\n\t\t\tif (ImGui.InputFloat(\"Move Time\", ref mt)) {\n\t\t\t\troot[\"mt\"] = mt;\n\t\t\t}\n\t\t\t\n\t\t\tvar rt = (float) root[\"rt\"].Number(0.2f);\n\n\t\t\tif (ImGui.InputFloat(\"Return Time\", ref rt)) {\n\t\t\t\troot[\"rt\"] = rt;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ActiveStand.cs",
    "content": "using BurningKnight.assets.items;\r\n\r\nnamespace BurningKnight.entity.item.stand {\r\n\tpublic class ActiveStand : EmeraldStand {\r\n\t\tprotected override bool ApproveItem(ItemData item) {\r\n\t\t\treturn item.Type == ItemType.Active;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ArtifactStand.cs",
    "content": "using BurningKnight.assets.items;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class ArtifactStand : EmeraldStand {\n\t\tprotected override bool ApproveItem(ItemData item) {\n\t\t\treturn item.Type == ItemType.Artifact;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/BkStand.cs",
    "content": "using System;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.level;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class BkStand : ItemStand {\n\t\tprivate bool triggered;\n\t\tprivate bool did;\n\t\tprivate float t;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (!did && triggered) {\n\t\t\t\tCamera.Instance.Shake(0.5f);\n\t\t\t\tt += dt;\n\n\t\t\t\tif (t >= 1f) {\n\t\t\t\t\tdid = true;\n\n\t\t\t\t\t/*var torches = GetComponent<RoomComponent>().Room.Tagged[Tags.Torch];\n\t\t\t\t\tvar target = new Vector2(CenterX, Y - 16);\n\n\t\t\t\t\tforeach (var t in torches) { \n\t\t\t\t\t\tvar tr = (Torch) t;\n\n\t\t\t\t\t\ttr.XSpread = 1;\n\t\t\t\t\t\ttr.On = true;\n\t\t\t\t\t\ttr.Target = target;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t\t\tt.Done = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 1f);\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar bk = new entity.creature.bk.BurningKnight();\n\t\t\t\t\t\tArea.Add(bk);\n\t\t\t\t\t\tbk.Center = target;\n\t\t\t\t\n\t\t\t\t\t\tCamera.Instance.Shake(10);\n\n\t\t\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t\t\tt.Done = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tDone = true;\n\t\t\t\t\t}, 2f);*/\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemTakenEvent && !triggered) {\n\t\t\t\tTimer.Add(() => { triggered = true; }, 1f);\n\t\t\t\t\n\t\t\t\tCamera.Instance.Shake(12);\n\t\t\t\t\n\t\t\t\tvar xx = (int) Math.Floor(CenterX / 16) * 16;\n\t\t\t\tvar xy = (int) Math.Floor(CenterY / 16) * 16;\n\t\t\t\tvar p = 32;\n\n\t\t\t\t/*var torches = GetComponent<RoomComponent>().Room.Tagged[Tags.Torch];\n\n\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t((Torch) t).On = false;\n\t\t\t\t}\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tforeach (var t in torches) {\n\t\t\t\t\t\tvar tr = (Torch) t;\n\t\t\t\t\t\ttr.On = true;\n\t\t\t\t\t\ttr.XSpread = 0.1f;\n\t\t\t\t\t}\n\t\t\t\t}, 3f);*/\n\n\t\t\t\tfor (var x = xx - p; x < xx + Width + p; x += 16) {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(3, 9); i++) {\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x + Rnd.Float(-2, 18), xy - p + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(x + Rnd.Float(-2, 18), xy + Height + p - 16 + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (var y = xy; y < xy + Height; y += 16) {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(3, 9); i++) {\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(xx + Rnd.Float(-2, 18) - p, y + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\tPosition = new Vector2(xx + Width + p - 16 + Rnd.Float(-2, 18), y + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\tDelay = Rnd.Float(0.5f),\n\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/BoxyStand.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class BoxyStand : CustomStand {\n\t\tprotected override string GetIcon() {\n\t\t\treturn \"deal_key\";\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"boxy_stand\";\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Roger;\n\t\t}\n\n\t\tprotected override int CalculatePrice() {\n\t\t\treturn (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 2);\n\t\t}\n\n\t\tprotected override bool TryPay(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.Keys < Price) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tcomponent.Keys -= Price;\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprotected override bool HasEnoughToPay(Entity p) {\n\t\t\treturn p.GetComponent<ConsumablesComponent>().Keys >= Price;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/CustomStand.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class CustomStand : ShopStand {\n\t\tprivate TextureRegion icon;\n\t\tprivate float priceWidth;\n\t\tprivate float iconY;\n\n\t\tprotected virtual string GetIcon() {\n\t\t\treturn \"deal_heart\";\n\t\t}\n\n\t\tprotected override void CalculatePriceSize() {\n\t\t\tbase.CalculatePriceSize();\n\t\t\t\n\t\t\tPriceString = $\"{Price}\";\n\t\t\tpriceWidth = Font.Small.MeasureString(PriceString).Width;\n\t\t\tPriceX = (Width - priceWidth - icon.Width - 2) / 2f;\n\t\t\ticonY = (7 - icon.Height) / 2;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\ticon = CommonAse.Ui.GetSlice(GetIcon());\n\t\t}\n\n\t\tprotected override void RenderPrice() {\n\t\t\tif (HasSale) {\n\t\t\t\tGraphics.Color = Palette.Default[35];\n\t\t\t}\n\t\t\t\t\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tforeach (var p in r.Tagged[Tags.Player]) {\n\t\t\t\tif (!HasEnoughToPay(p)) {\n\t\t\t\t\tGraphics.Color *= 0.6f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\t\t\t\t\t\n\t\t\t}\n\t\t\t\t\n\t\t\tGraphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\tGraphics.Render(icon, Position + new Vector2(PriceX + priceWidth + 2, 17 + iconY));\n\t\t}\n\t\t\n\t\tprotected virtual bool HasEnoughToPay(Entity p) {\n\t\t\treturn p.GetComponent<ConsumablesComponent>().Bombs >= Price;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/DarkMageStand.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class DarkMageStand : ShopStand {\n\t\tprivate TextureRegion heart;\n\t\tprivate float priceWidth;\n\n\t\tprivate Entity payer;\n\t\tprivate Item takenItem;\n\t\tprivate int lastPrice;\n\n\t\tprotected override int CalculatePrice() {\n\t\t\treturn (int) Math.Max(1, PriceCalculator.GetModifier(Item));\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"dm_stand\";\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tOnSale = false;\n\t\t\theart = CommonAse.Ui.GetSlice(\"deal_heart\");\n\t\t\t\n\t\t\tSubscribe<ItemUsedEvent>();\n\t\t\tSubscribe<ItemAddedEvent>();\n\t\t}\n\n\t\tprotected override void CalculatePriceSize() {\n\t\t\tPriceString = $\"{Price}\";\n\t\t\tpriceWidth = Font.Small.MeasureString(PriceString).Width;\n\t\t\tPriceX = (Width - priceWidth - heart.Width - 2) / 2f;\n\t\t}\n\n\t\tprotected override void RenderPrice() {\n\t\t\tif (HasSale) {\n\t\t\t\tGraphics.Color = Palette.Default[35];\n\t\t\t}\n\t\t\t\t\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tforeach (var p in r.Tagged[Tags.Player]) {\n\t\t\t\tif (p.GetComponent<HealthComponent>().MaxHealth + p.GetComponent<HeartsComponent>().Total < Price * 2) {\n\t\t\t\t\tGraphics.Color *= 0.6f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\t\t\t\t\t\n\t\t\t}\n\t\t\t\t\n\t\t\tGraphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\tGraphics.Render(heart, Position + new Vector2(PriceX + priceWidth + 2, 17));\n\t\t}\n\n\t\tprotected override bool TryPay(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<HealthComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.MaxHealth + entity.GetComponent<HeartsComponent>().Total < Price * 2) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tpayer = entity;\n\t\t\tlastPrice = Price * 2;\n\t\t\ttakenItem = Item;\n\t\t\t\n\t\t\tvar stats = entity.GetComponent<StatsComponent>();\n\t\t\t\n\t\t\tstats.TookDeal = true;\n\t\t\tstats.HeartsPayed += Price;\n\t\t\t\n\t\t\tAchievements.Unlock(\"bk:deal\");\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif ((e is ItemUsedEvent ite && ite.Who == payer && ite.Item == takenItem) || (e is ItemAddedEvent iae && iae.Who == payer && iae.Item == takenItem)) {\n\t\t\t\tvar component = payer.GetComponent<HealthComponent>();\n\t\t\t\tvar hearts = payer.GetComponent<HeartsComponent>();\n\t\t\t\tvar a = Math.Min(component.MaxHealth, lastPrice);\n\n\t\t\t\tif (a > 0) {\n\t\t\t\t\tcomponent.ModifyHealth(-a, this, DamageType.Custom);\n\n\t\t\t\t\tif (!component.LastModifiedHearts) {\n\t\t\t\t\t\tcomponent.MaxHealth -= a;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar d = lastPrice - a;\n\n\t\t\t\tif (d > 0) {\n\t\t\t\t\thearts.Hurt(-d, this, DamageType.Custom);\n\t\t\t\t}\n\n\t\t\t\tTextParticle.Add(payer, Locale.Get(\"max_hp\"), lastPrice, true, true);\n\t\t\t\t\n\t\t\t\tpayer = null;\n\t\t\t\ttakenItem = null;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.OldMan;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/GarderobeStand.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class GarderobeStand : ItemStand {\n\t\tpublic static List<string> AlreadyOnStand = new List<string>();\n\n\t\tpublic GarderobeStand() {\n\t\t\tdontSaveItem = true;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Item != null) {\n\t\t\t\tAlreadyOnStand.Remove(Item.Id);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"gobetta_stand\";\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tvar item = PickItem();\n\n\t\t\tif (item != null) {\n\t\t\t\tSetItem(item, null);\n\t\t\t}\n\t\t}\n\n\t\tpublic void UpdateItem() {\n\t\t\tif (Item != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar item = PickItem();\n\n\t\t\tif (item != null) {\n\t\t\t\tSetItem(item, null);\n\t\t\t}\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn item != null && base.CanInteract(e);\n\t\t}\n\n\t\tprotected override bool CanTake(Entity entity) {\n\t\t\tif (!base.CanTake(entity)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\n\t\t\tvar ht = entity.GetComponent<HatComponent>();\n\t\t\tvar old = ht.Item;\n\t\t\t\n\t\t\tht.Set(item, true);\n\t\t\titem = null;\n\t\t\t\n\t\t\tSetItem(old, entity);\n\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\t\t\tAchievements.Unlock(\"bk:fancy_hat\");\n\t\t}\n\n\t\tprivate Item PickItem() {\n\t\t\tvar items = new List<ItemData>();\n\n\t\t\tforeach (var i in Items.Datas.Values) {\n\t\t\t\tif (i.Type == ItemType.Hat && GlobalSave.GetString(\"hat\") != i.Id && (i.Id == \"bk:no_hat\" || GlobalSave.IsTrue(i.Id)) && !AlreadyOnStand.Contains(i.Id)) {\n\t\t\t\t\titems.Add(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (items.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\titems.Sort((a, b) => a.UnlockPrice.CompareTo(b.UnlockPrice));\n\n\t\t\tvar id = items[0].Id;\n\t\t\tAlreadyOnStand.Add(id);\n\n\t\t\treturn Items.CreateAndAdd(id, Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/GobettaStand.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class GobettaStand : ShopStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"gobetta_stand\";\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Gobetta;\n\t\t}\n\n\t\tprotected override int CalculatePrice() {\n\t\t\treturn (int) Math.Max(1, (base.CalculatePrice() * 0.5f));\n\t\t}\n\n\t\tprotected override bool TryPay(Entity entity) {\n\t\t\tif (base.TryPay(entity)) {\n\t\t\t\tvar scourge = Scourge.GenerateItemId();\n\n\t\t\t\tif (scourge != null) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(scourge, entity.Area));\n\t\t\t\t\t}, 2f);\n\t\t\t\t}\n\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/GrannyStand.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class GrannyStand : ItemStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"granny_stand\";\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\t\t\n\t\t\tvar rm = GetComponent<RoomComponent>().Room;\n\t\t\t\n\t\t\tif (rm == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it\n\t\t\t\n\t\t\tforeach (var s in it) {\n\t\t\t\tif (s != this && s is GrannyStand ist && ist.Item != null) {\n\t\t\t\t\tist.Item.Done = true;\n\t\t\t\t\tist.Done = true;\n\t\t\t\t\tAnimationUtil.Poof(ist.Center);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tDone = true;\n\t\t\tCamera.Instance.Shake(10);\n\t\t\tAchievements.Unlock(\"bk:grannys_gift\");\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Granny;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/HatStand.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.save;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class HatStand : EmeraldStand {\n\t\tprotected override bool ApproveItem(ItemData item) {\n\t\t\treturn item.Type == ItemType.Hat;\n\t\t}\n\n\t\tprotected override void DoStuff() {\n\t\t\tbase.DoStuff();\n\t\t\t\n\t\t\tforeach (var i in Area.Tagged[Tags.Item].ToArray()) {\n\t\t\t\tif (i is GarderobeStand gs) {\n\t\t\t\t\tgs.UpdateItem();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCheckHats();\n\t\t}\n\n\t\tpublic static void CheckHats() {\n\t\t\tif (Achievements.Get(\"bk:fashion_matters2\").Unlocked) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar total = 0;\n\t\t\tvar progress = 0;\n\n\t\t\tforeach (var i in Items.Datas.Values) {\n\t\t\t\tif (i.Type == ItemType.Hat && i.Id != \"bk:no_hat\") {\n\t\t\t\t\ttotal++;\n\n\t\t\t\t\tif (GlobalSave.IsTrue(i.Id)) {\n\t\t\t\t\t\tprogress++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (progress > 0) {\n\t\t\t\tAchievements.Unlock(\"bk:fancy_hat\");\n\t\t\t}\n\n\t\t\tLog.Info($\"Fashion matters progress: {progress}/{total}\");\n\t\t\tAchievements.SetProgress(\"bk:fashion_matters2\", progress, total);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/HealChoiceStand.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class HealChoiceStand : SingleChoiceStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"health_stand\";\n\t\t}\n\n\t\tprotected virtual string GetSfx() {\n\t\t\treturn \"item_heart\";\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual void Heal(Entity entity) {\n\t\t\tvar h = entity.GetComponent<HealthComponent>();\n\t\t\th.ModifyHealth(h.MaxHealth, this);\n\t\t}\n\n\t\tprotected override bool Interact(Entity entity) {\n\t\t\tHeal(entity);\n\t\t\tRemoveStands();\n\n\t\t\tDone = true;\n\t\t\tAnimationUtil.Poof(Center);\n\t\t\tAudio.PlaySfx(GetSfx());\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/HealthStand.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class HealthStand : ItemStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"health_stand\";\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\tif (Item == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanInteract(e);\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\n\t\t\tvar h = who.GetComponent<HealthComponent>();\n\t\t\th.ModifyHealth(h.MaxHealth, this);\n\t\t\t\n\t\t\tTextParticle.Add(who, \"HP\", h.MaxHealth, true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ItemStand.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class ItemStand : Prop, CollisionFilterEntity {\n\t\tprivate static TextureRegion itemShadow;\n\t\tprivate static TextureRegion standShadow;\n\t\tprivate static Vector2 shadowOffset = new Vector2(3, 3);\n\n\t\tprotected Item item;\n\t\t\n\t\tpublic Item Item => item;\n\t\tpublic bool Hidden;\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn !Hidden;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (itemShadow == null) {\n\t\t\t\titemShadow = CommonAse.Props.GetSlice(\"item_shadow\");\n\t\t\t\tstandShadow = CommonAse.Props.GetSlice(\"stand_shadow\");\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void OnTake(Item item, Entity who) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void SetItem(Item i, Entity entity, bool remove = true) {\n\t\t\tif (item == i) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (item != null) {\n\t\t\t\tif (remove) {\n\t\t\t\t\titem.AddDroppedComponents();\n\t\t\t\t\titem.RemoveComponent<OwnerComponent>();\n\t\t\t\t}\n\n\t\t\t\tHandleEvent(new ItemTakenEvent {\n\t\t\t\t\tItem = item,\n\t\t\t\t\tWho = entity,\n\t\t\t\t\tStand = this\n\t\t\t\t});\n\n\t\t\t\tOnTake(item, entity);\n\t\t\t}\n\n\t\t\titem = i;\n\t\t\t\t\n\t\t\tif (item != null) {\n\t\t\t\titem.RemoveDroppedComponents();\n\n\t\t\t\tif (item.HasComponent<OwnerComponent>()) {\n\t\t\t\t\titem.RemoveComponent<OwnerComponent>();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\titem.AddComponent(new OwnerComponent(this));\n\t\t\t\titem.CenterX = CenterX;\n\t\t\t\titem.Bottom = Y + 6;\n\t\t\t\titem.AutoPickup = false;\n\t\t\t\t\n\t\t\t\tHandleEvent(new ItemPlacedEvent {\n\t\t\t\t\tItem = item,\n\t\t\t\t\tWho = entity,\n\t\t\t\t\tStand = this\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic ItemStand() {\n\t\t\tWidth = 14;\n\t\t\tHeight = 14;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (item != null) {\n\t\t\t\titem.Center = Center;\n\n\t\t\t\tif (item.Done) {\n\t\t\t\t\titem = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tvar g = new SliceComponent(\"props\", GetSprite());\n\t\t\tAddComponent(g);\n\t\t\tg.SetOwnerSize();\n\t\t\t\n\t\t\tAddTag(Tags.Item);\n\t\t\t\n\t\t\tvar body = new RectBodyComponent(0, 4, 14, 10);\n\t\t\tAddComponent(body);\n\t\t\tbody.Body.Mass = 100000000f;\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(-2, -2, Width + 4, Height + 4, BodyType.Static));\n\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = CanInteract,\n\t\t\t\tOnStart = OnInteractionStart\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new RoomComponent());\n\t\t}\n\t\t\n\t\tprotected virtual string GetSprite() {\n\t\t\treturn \"slab_a\";\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tif (!Hidden) {\n\t\t\t\tGraphics.Render(standShadow, Position + new Vector2(0, Height));\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool CanTake(Entity entity) {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual bool Interact(Entity entity) {\n\t\t\tif (Item != null && Item.Masked && Run.Depth < 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.TryGetComponent<InventoryComponent>(out var inventory)) {\n\t\t\t\tif (item != null) {\n\t\t\t\t\tif (CanTake(entity)) {\n\t\t\t\t\t\tvar i = item;\n\t\t\t\t\t\tvar remove = false;\n\n\t\t\t\t\t\tif (this is GarderobeStand) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t} else if (this is PermanentStand && Item != null && Item.Type == ItemType.Weapon) {\n\t\t\t\t\t\t\tvar c = entity.GetComponent<ActiveWeaponComponent>();\n\t\t\t\t\t\t\tvar item = c.Item;\n\n\t\t\t\t\t\t\tc.Set(Items.CreateAndAdd(Item.Id, Area), false);\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_pickup\");\n\n\t\t\t\t\t\t\tif (item != null) {\n\t\t\t\t\t\t\t\titem.Done = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t} else if (this is PermanentStand && Item != null && Item.Type == ItemType.Active) {\n\t\t\t\t\t\t\tvar c = entity.GetComponent<ActiveItemComponent>();\n\t\t\t\t\t\t\tvar item = c.Item;\n\n\t\t\t\t\t\t\tc.Set(Items.CreateAndAdd(Item.Id, Area), false);\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_pickup\");\n\n\t\t\t\t\t\t\tif (item != null) {\n\t\t\t\t\t\t\t\titem.Done = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t} else if (this is LampStand && Item != null && Item.Type == ItemType.Lamp) {\n\t\t\t\t\t\t\tvar c = entity.GetComponent<LampComponent>();\n\t\t\t\t\t\t\tvar item = c.Item;\n\n\t\t\t\t\t\t\tc.Set(Items.CreateAndAdd(Item.Id, Area), false);\n\t\t\t\t\t\t\tAudio.PlaySfx(\"item_pickup\");\n\n\t\t\t\t\t\t\tif (item != null) {\n\t\t\t\t\t\t\t\titem.Done = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSetItem(null, entity, false);\n\t\t\t\t\t\t\tremove = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!inventory.Pickup(i) && remove) {\n\t\t\t\t\t\t\tSetItem(i, null, false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this is HatStand || this is ShopStand || Run.Depth == -2;\n\t\t\t\t} else if (!(this is ShopStand) && entity.TryGetComponent<ActiveWeaponComponent>(out var weapon) && weapon.Item != null) {\n\t\t\t\t\tif (weapon.Item.Scourged) {\n\t\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSetItem(weapon.Drop(), entity);\n\t\t\t\t\t\tweapon.RequestSwap();\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprivate void OnInteractionStart(Entity entity) {\n\t\t\tif (item != null && entity is LocalPlayer) {\n\t\t\t\tif (item.AutoPickup) {\n\t\t\t\t\titem.OnInteractionStart(entity);\n\t\t\t\t\titem = null;\n\t\t\t\t} else if (Run.Depth != -2) {\n\t\t\t\t\tEngine.Instance.State.Ui.Add(new ItemPickupFx(item));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool CanInteract(Entity e) {\n\t\t\treturn !Hidden && (Item != null || Run.Depth != -2);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Hidden || !TryGetComponent<InteractableComponent>(out var component)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cursed = item != null && item.Scourged;\n\t\t\tvar interact = component.OutlineAlpha > 0.05f;\n\t\t\tvar renderOutline = interact || cursed;\n\t\t\t\n\t\t\tif (item == null && renderOutline) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(component.OutlineAlpha);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(((SliceComponent) GraphicsComponent).Sprite, Position + d);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tGraphicsComponent.Render(false);\n\t\t\t\n\t\t\tif (item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tGraphics.Color = Level.ShadowColor;\n\t\t\tGraphics.Render(itemShadow, Position + shadowOffset);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\n\t\t\tvar t = item.Animation == null ? item.GetComponent<ItemGraphicsComponent>().T : 0;\n\t\t\tvar angle = (float) Math.Cos(t * 3f) * 0.4f;\n\t\t\t\n\t\t\tvar region = item.Region;\n\t\t\tvar animated = item.Animation != null;\n\t\t\tvar pos = item.Center + new Vector2(0, (animated ? 0 : (float) (Math.Sin(t * 3f) * 0.5f + 0.5f) * -5.5f - 3) - 5.5f);\n\t\t\t\n\t\t\tif (renderOutline) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(cursed ? 1f : component.OutlineAlpha);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(!cursed ? ColorUtils.White : ColorUtils.Mix(ItemGraphicsComponent.ScourgedColor, ColorUtils.White, component.OutlineAlpha));\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(region, pos + d, animated ? 0 : angle, region.Center);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tShaders.End();\n\t\t\t}\n\n\t\t\tif (animated) {\n\t\t\t\tGraphics.Render(region, pos, 0, region.Center);\t\t\t\t\n\t\t\t} else {\n\t\t\t\tif (item.Masked) {\n\t\t\t\t\tGraphics.Color = ItemGraphicsComponent.MaskedColor;\n\t\t\t\t\tGraphics.Render(region, pos, angle, region.Center);\n\t\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t\t} else {\n\t\t\t\t\tvar shader = Shaders.Item;\n\t\t\t\t\n\t\t\t\t\tShaders.Begin(shader);\n\t\t\t\t\tshader.Parameters[\"time\"].SetValue(t * 0.1f);\n\t\t\t\t\tshader.Parameters[\"size\"].SetValue(ItemGraphicsComponent.FlashSize);\n\n\t\t\t\t\tGraphics.Render(region, pos, angle, region.Center);\n\t\t\t\t\tShaders.End();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected bool dontSaveItem;\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tif (dontSaveItem) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (stream.ReadBoolean()) {\n\t\t\t\tvar item = new Item();\n\n\t\t\t\tArea.Add(item, false);\n\t\t\t\t\n\t\t\t\titem.Load(stream);\n\t\t\t\titem.LoadedSelf = false;\n\t\t\t\titem.PostInit();\n\n\t\t\t\tSetItem(item, null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tif (!dontSaveItem) {\n\t\t\t\tstream.WriteBoolean(item != null);\n\t\t\t\titem?.Save(stream);\n\t\t\t}\n\t\t}\n\n\t\tprotected string debugItem = \"\";\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tif (ImGui.InputText(\"Item\", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tvar item = Item;\n\t\t\t\tSetItem(Items.CreateAndAdd(debugItem, Area), null);\n\n\t\t\t\tif (item != null) {\n\t\t\t\t\titem.Done = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual ItemPool GetPool() {\n\t\t\treturn ItemPool.Treasure;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/LampStand.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.events;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class LampStand : ItemStand {\n\t\tpublic static List<string> AlreadyOnStand = new List<string>();\n\t\t\n\t\tpublic LampStand() {\n\t\t\tShowUnlocked = true;\n\t\t\tdontSaveItem = true;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tt = Rnd.Float(6);\n\t\t\tAddComponent(new LightComponent(this, 32f, new Color(1f, 0.8f, 0.3f, 1f)));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tCheck();\n\t\t\tSubscribe<Item.UnlockedEvent>();\n\t\t}\n\n\t\tprivate void Check() {\n\t\t\tif (Item != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar item = PickItem();\n\n\t\t\tif (item != null) {\n\t\t\t\tSetItem(item, null);\n\t\t\t\tHidden = false;\n\t\t\t} else if (!Engine.EditingLevel) {\n\t\t\t\tHidden = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Item != null) {\n\t\t\t\tAlreadyOnStand.Remove(Item.Id);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\t\t\tAlreadyOnStand.Remove(item.Id);\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"lamp_stand\";\n\t\t}\n\t\t\n\t\tprotected virtual bool ApproveItem(ItemData item) {\n\t\t\treturn item.Type == ItemType.Lamp && item.Id != \"bk:no_lamp\";\n\t\t}\n\n\t\tprotected bool ShowUnlocked = true;\n\n\t\tprivate Item PickItem() {\n\t\t\tvar items = new List<ItemData>();\n\n\t\t\tforeach (var i in Items.Datas.Values) {\n\t\t\t\tif (ApproveItem(i) && !AlreadyOnStand.Contains(i.Id) && GlobalSave.IsTrue(i.Id)) {\n\t\t\t\t\titems.Add(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (items.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar id = items[0].Id;\n\t\t\tAlreadyOnStand.Add(id);\n\n\t\t\treturn Items.CreateAndAdd(id, Area);\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn Item != null;\n\t\t}\n\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t\tGetComponent<LightComponent>().Light.Radius = 32f + (float) Math.Cos(t) * 6;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is Item.UnlockedEvent) {\n\t\t\t\tCheck();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/LampUnlockStand.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class LampUnlockStand : ItemStand {\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tCheckHidden();\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"single_stand\";\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\t\t\tItems.Unlock(item.Id);\n\t\t\tCheckHidden();\n\t\t}\n\n\t\tpublic void CheckHidden() {\n\t\t\tif (!Engine.EditingLevel && (Item == null || GlobalSave.IsTrue(Item.Id))) {\n\t\t\t\tHidden = true;\n\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t} else {\n\t\t\t\tHidden = false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/PermanentStand.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.events;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class PermanentStand : ItemStand {\n\t\tprotected string SavedItem;\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (SavedItem == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Item != null) {\n\t\t\t\tif (Item.Id == SavedItem) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tItem.Done = true;\n\t\t\t}\n\n\t\t\tdebugItem = SavedItem;\n\t\t\tSetItem(Items.CreateAndAdd(SavedItem, Area), null);\n\t\t}\n\n\t\tpublic override void SetItem(Item i, Entity entity, bool remove = true) {\n\t\t\tbase.SetItem(i, entity, remove);\n\t\t\tItem?.CheckMasked();\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tif (ImGui.InputText(\"Item\", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tif (Item != null) {\n\t\t\t\t\tItem.Done = true;\n\t\t\t\t}\n\n\t\t\t\tSetItem(Items.CreateAndAdd(debugItem, Area), null);\n\t\t\t\tSavedItem = debugItem;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(SavedItem);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tSavedItem = stream.ReadString();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/RogerStand.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class RogerStand : CustomStand {\n\t\tprotected override string GetIcon() {\n\t\t\treturn \"deal_bomb\";\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"roger_stand\";\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Roger;\n\t\t}\n\n\t\tprotected override int CalculatePrice() {\n\t\t\treturn (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 2);\n\t\t}\n\n\t\tprotected override bool TryPay(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.Bombs < Price) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tcomponent.Bombs -= Price;\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ScourgedStand.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class ScourgedStand : ItemStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"scourge_stand\";\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tAlwaysActive = true;\n\t\t\tSubscribe<ItemTakenEvent>();\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn Item != null && base.CanInteract(e);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemTakenEvent ite && !(ite.Who is ScourgedStand || !(ite.Stand is ScourgedStand))) {\n\t\t\t\tvar rm = GetComponent<RoomComponent>().Room;\n\t\t\t\t\n\t\t\t\tif (ite.Stand != this && ite.Stand.GetComponent<RoomComponent>().Room == rm) {\n\t\t\t\t\tvar it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it\n\t\t\t\t\n\t\t\t\t\tforeach (var s in it) {\n\t\t\t\t\t\tif (s is ScourgedStand ist && ist.Item != null) {\n\t\t\t\t\t\t\tvar i = ist.Item;\n\t\t\t\t\t\t\tist.SetItem(null, this);\n\t\t\t\t\t\t\ti.Done = true;\n\t\t\t\t\t\t\tAnimationUtil.Poof(ist.Center);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ShieldChoiceStand.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class ShieldChoiceStand : HealChoiceStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"shield_stand\";\n\t\t}\n\n\t\tprotected override string GetSfx() {\n\t\t\treturn \"item_shield\";\n\t\t}\n\n\t\tprotected override void Heal(Entity entity) {\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:shield\", entity.Area));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/ShopStand.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class ShopStand : ItemStand {\n\t\tpublic bool Sells = true;\n\t\tpublic bool Free;\n\n\t\tprotected int Price;\n\t\tprotected string PriceString;\n\t\tprotected float PriceX;\n\t\tprotected bool OnSale;\n\t\tprotected bool HasSale;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tOnSale = Rnd.Chance(10 + Run.Luck * 2);\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Shop;\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"shop_stand\";\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn Item != null && base.CanInteract(e);\n\t\t}\n\n\t\tprotected virtual bool TryPay(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.Coins < Price) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tcomponent.Coins -= Price;\n\t\t\tAchievements.Unlock(\"bk:shopper\");\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate bool OkToBuy(Entity entity) {\n\t\t\tif (Item.Type == ItemType.Active) {\n\t\t\t\tvar item = entity.GetComponent<ActiveItemComponent>().Item;\n\n\t\t\t\tif (item != null && item.Scourged) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else if (Item.Type == ItemType.Weapon) {\n\t\t\t\tvar item = entity.GetComponent<ActiveWeaponComponent>().Item;\n\n\t\t\t\tif (item != null && item.Scourged) {\n\t\t\t\t\titem = entity.GetComponent<WeaponComponent>().Item;\n\n\t\t\t\t\tif (item != null && item.Scourged) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprotected override bool CanTake(Entity entity) {\n\t\t\tif (!base.CanTake(entity)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!Sells || Free) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (!OkToBuy(entity)) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\tentity.GetComponent<DialogComponent>().StartAndClose($\"~~{Locale.Get(\"scourged\")}~~\", 2);\n\n\t\t\t\treturn false;\n\t\t\t} else if (!TryPay(entity)) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\n\t\t\t\tforeach (var n in GetComponent<RoomComponent>().Room.Tagged[Tags.Npc]) {\n\t\t\t\t\tif (n is ShopNpc s) {\n\t\t\t\t\t\tn.GetComponent<DialogComponent>().StartAndClose(s.GetFailDialog(), 3);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else if (n is ShopKeeper) {\n\t\t\t\t\t\tn.GetComponent<DialogComponent>().StartAndClose($\"shopkeeper_{Rnd.Int(15, 18)}\", 3);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tSells = false;\n\n\t\t\tAudio.PlaySfx(\"item_purchase\");\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\n\t\t\tif (!Free) {\n\t\t\t\twho.HandleEvent(new ItemBoughtEvent {\n\t\t\t\t\tItem = item,\n\t\t\t\t\tWho = who,\n\t\t\t\t\tStand = this\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (Item != null && Sells && !Free) {\n\t\t\t\tRenderPrice();\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void RenderPrice() {\n\t\t\tif (HasSale) {\n\t\t\t\tGraphics.Color = Palette.Default[35];\n\n\t\t\t\tif (Price == 0) {\n\t\t\t\t\tHasSale = false;\n\t\t\t\t\tOnSale = false;\n\t\t\t\t\tPrice = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tforeach (var p in r.Tagged[Tags.Player]) {\n\t\t\t\tif (p.GetComponent<ConsumablesComponent>().Coins < Price) {\n\t\t\t\t\tGraphics.Color *= 0.6f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\t\t\t\t\t\n\t\t\t}\n\t\t\t\t\n\t\t\tGraphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\tprotected virtual int CalculatePrice() {\n\t\t\treturn PriceCalculator.Calculate(Item);\n\t\t}\n\t\t\n\t\tpublic void Recalculate() {\n\t\t\tif (Free) {\n\t\t\t\tPrice = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Item == null) {\n\t\t\t\tPrice = 0;\n\t\t\t\tSells = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tSells = true;\n\t\t\tPrice = CalculatePrice();\n\n\t\t\tif (OnSale) {\n\t\t\t\tPrice = (int) Math.Floor(Price * 0.5f);\n\t\t\t\tHasSale = true;\n\t\t\t}\n\t\t\t\n\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\n\t\t\tif (r != null) {\n\t\t\t\tvar e = new ItemPriceCalculationEvent {\n\t\t\t\t\tStand = this,\n\t\t\t\t\tItem = Item\n\t\t\t\t};\n\n\t\t\t\tforeach (var p in r.Tagged[Tags.Player]) {\n\t\t\t\t\tp.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\tif (e.Percent > 0.001f) {\n\t\t\t\t\tPrice = (int) Math.Floor(Price * Math.Max(0f, (1f - e.Percent * 0.01f)));\n\t\t\t\t\tHasSale = true;\n\t\t\t\t}\n\n\t\t\t\tif (r.Tagged[Tags.ShopKeeper].Count > 0) {\n\t\t\t\t\tvar min = sbyte.MaxValue;\n\t\t\t\t\t\n\t\t\t\t\tforeach (var s in r.Tagged[Tags.ShopKeeper]) {\n\t\t\t\t\t\tmin = Math.Min(min, ((ShopKeeper) s).Mood);\n\t\t\t\t\t}\n\n\t\t\t\t\tPrice = Math.Max(Price, Price - (min - 3));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCalculatePriceSize();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemPlacedEvent || (e is RoomChangedEvent rce && rce.Who is Player && rce.New == GetComponent<RoomComponent>().Room)) {\n\t\t\t\tRecalculate();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected virtual void CalculatePriceSize() {\n\t\t\tPriceString = $\"{Price}\";\n\t\t\tPriceX = (Width - Font.Small.MeasureString(PriceString).Width) / 2f;\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (ImGui.InputInt(\"Price\", ref Price)) {\n\t\t\t\tCalculatePriceSize();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tOnSale = stream.ReadBoolean();\n\t\t\tFree = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(OnSale);\n\t\t\tstream.WriteBoolean(Free);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/SnekStand.cs",
    "content": "namespace BurningKnight.entity.item.stand {\n\tpublic class SnekStand : ShopStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"snek_stand\";\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Snek;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/TrashGoblinStand.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.util;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class TrashGoblinStand : ItemStand {\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"scourge_stand\";\n\t\t}\n\n\t\tprotected override void OnTake(Item item, Entity who) {\n\t\t\tbase.OnTake(item, who);\n\n\t\t\tforeach (var n in GetComponent<RoomComponent>().Room.Tagged[Tags.Npc]) {\n\t\t\t\tif (n is TrashGoblin g) {\n\t\t\t\t\tg.Free();\n\t\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\t\tDone = true;\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/VampireStand.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.stand {\n\tpublic class VampireStand : CustomStand {\n\t\tprivate Entity payer;\n\t\tprivate Item takenItem;\n\t\tprivate int lastPrice;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tSubscribe<ItemUsedEvent>();\n\t\t\tSubscribe<ItemAddedEvent>();\n\t\t}\n\n\t\tprotected override string GetIcon() {\n\t\t\treturn \"deal_hp\";\n\t\t}\n\n\t\tprotected override string GetSprite() {\n\t\t\treturn \"vampire_stand\";\n\t\t}\n\n\t\tpublic override ItemPool GetPool() {\n\t\t\treturn ItemPool.Vampire;\n\t\t}\n\n\t\tprotected override int CalculatePrice() {\n\t\t\treturn (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 1.5f);\n\t\t}\n\n\t\tprotected override bool TryPay(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<HealthComponent>(out var component)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (component.Health < Price * 2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tpayer = entity;\n\t\t\tlastPrice = Price * 2;\n\t\t\ttakenItem = Item;\n\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif ((e is ItemUsedEvent ite && ite.Who == payer && ite.Item == takenItem) || (e is ItemAddedEvent iae && iae.Who == payer && iae.Item == takenItem)) {\n\t\t\t\tvar component = payer.GetComponent<HealthComponent>();\n\t\t\t\t \n\t\t\t\tcomponent.ModifyHealth(-lastPrice, this, DamageType.Custom);\n\t\t\t\t\n\t\t\t\tpayer = null;\n\t\t\t\ttakenItem = null;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprotected override bool HasEnoughToPay(Entity p) {\n\t\t\treturn p.GetComponent<HealthComponent>().Health >= Price * 2;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/stand/WeaponStand.cs",
    "content": "using BurningKnight.assets.items;\r\n\r\nnamespace BurningKnight.entity.item.stand {\r\n\tpublic class WeaponStand : EmeraldStand {\r\n\t\tprotected override bool ApproveItem(ItemData item) {\r\n\t\t\treturn item.Type == ItemType.Weapon;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/AddHitboxUse.cs",
    "content": "using BurningKnight.physics;\r\nusing Lens.entity;\r\nusing Microsoft.Xna.Framework;\r\nusing VelcroPhysics.Dynamics;\r\nusing VelcroPhysics.Factories;\r\nusing VelcroPhysics.Shared;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class AddHitboxUse : ItemUse {\r\n\t\tprivate Body body;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tbase.Use(entity, item);\r\n\t\t\t\r\n\t\t\tbody = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, BodyType.Dynamic);\r\n\r\n\t\t\tbody.FixedRotation = true;\r\n\t\t\tbody.UserData = this;\r\n\t\t\tbody.LinearDamping = 0;\r\n\r\n\t\t\tvar r = Item.Region;\r\n\t\t\t\r\n\t\t\tvar w = r.Width;\r\n\t\t\tvar h = r.Height;\r\n\t\t\tvar x = -r.Width / 2;\r\n\t\t\tvar y = 0;\r\n\t\t\t\r\n\t\t\tFixtureFactory.AttachPolygon(new Vertices(4) {\r\n\t\t\t\tnew Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h)\r\n\t\t\t}, 1f, body).IsSensor = true;\r\n\r\n\t\t\tbody.Position = entity.Center;\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (body != null) {\r\n\t\t\t\tPhysics.RemoveBody(body);\r\n\t\t\t\tbody = null;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/AddTorchUse.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class AddTorchUse : ItemUse {\n\t\tprivate bool isOut;\n\t\tprivate float lastFlame;\n\t\t\n\t\tpublic override void Pickup(Entity entity, Item item) {\n\t\t\tisOut = true;\n\t\t\t// new Color(1f, 0.8f, 0.4f, 1f))\n\t\t\titem.AddComponent(new LightComponent(item, 192f, new Color(1f, 0, 0, 1f)));\n\t\t\tLog.Error(\"Add light\");\n\t\t}\n\n\t\tpublic override void Drop(Entity entity, Item item) {\n\t\t\tisOut = false;\n\t\t\titem.RemoveComponent<LightComponent>();\n\t\t\tLog.Error(\"Remove light\");\n\t\t}\n\n\t\tpublic override void Update(Entity entity, Item item, float dt) {\n\t\t\tbase.Update(entity, item, dt);\n\n\t\t\tif (isOut) {\n\t\t\t\tlastFlame += dt;\n\n\t\t\t\tif (lastFlame >= 0.3f) {\n\t\t\t\t\tlastFlame = 0;\n\t\t\t\t\t\n\t\t\t\t\tentity.Area.Add(new FireParticle {\n\t\t\t\t\t\tPosition = entity.Center + MathUtils.CreateVector(entity.AngleTo(entity.GetComponent<AimComponent>().Aim), 13),\n\t\t\t\t\t\tDepth = Layers.Wall + 1\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/AffectDealChanceUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class AffectDealChanceUse : ItemUse {\n\t\tprivate float granny;\n\t\tprivate bool addGranny;\n\t\tprivate float dm;\n\t\tprivate bool addDm;\n\t\tprivate bool both;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is DealChanceCalculateEvent d) {\n\t\t\t\tif (addGranny) {\n\t\t\t\t\td.GrannyChance += granny;\n\t\t\t\t} else {\n\t\t\t\t\td.GrannyChance *= granny;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (addDm) {\n\t\t\t\t\td.DmChance += dm;\n\t\t\t\t} else {\n\t\t\t\t\td.DmChance *= dm;\n\t\t\t\t}\n\n\t\t\t\tif (both) {\n\t\t\t\t\td.OpenBoth = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tboth = settings[\"bt\"].Bool(false);\n\t\t\tgranny = settings[\"gr\"].Number(0);\n\t\t\taddGranny = settings[\"agr\"].Bool(true);\n\t\t\tdm = settings[\"dm\"].Number(0);\n\t\t\taddDm = settings[\"adm\"].Bool(true);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"Open Both if one is present\", \"bt\", false);\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\troot.InputFloat(\"Granny\", \"gr\", 0);\n\t\t\troot.Checkbox(\"Add Granny\", \"agr\", true);\n\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\troot.InputFloat(\"Dm\", \"dm\", 0);\n\t\t\troot.Checkbox(\"Add Dm\", \"adm\", true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/BlankUse.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class BlankUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tBlankMaker.Make(entity.Center, entity.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/BlindFoldUse.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class BlindFoldUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (entity.TryGetComponent<WeaponComponent>(out var w)) {\n\t\t\t\tw.Disabled = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.TryGetComponent<ActiveWeaponComponent>(out var aw)) {\n\t\t\t\taw.Disabled = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/BlockDamageUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class BlockDamageUse : ItemUse {\n\t\tprivate float chance;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent hme) {\n\t\t\t\tif (hme.Amount < 0 && hme.Who == Item.Owner && Rnd.Chance(chance)) {\n\t\t\t\t\thme.Amount = 0;\n\n\t\t\t\t\tif (Item.Id == \"bk:cats_ear\") {\n\t\t\t\t\t\tTextParticle.Add(Item.Owner, \"Sick dodge!\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tchance = settings[\"chance\"].Number(10);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Chance\", \"chance\", 10);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/BreakPiggyBankUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class BreakPiggyBankUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar amount = Run.Depth * 5;\n\t\t\tentity.GetComponent<ConsumablesComponent>().Coins += amount;\n\t\t\t\n\t\t\tTextParticle.Add(entity, Locale.Get(\"coins\"), amount, true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/BucketUse.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class BucketUse : ItemUse {\n\t\tprivate bool water;\n\t\tprivate bool snow;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (water) {\n\t\t\t\tvar r = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (r != null) {\n\t\t\t\t\tforeach (var b in r.Tagged[Tags.Boss]) {\n\t\t\t\t\t\tif (b is BkHead h && h.CanBeSaved) {\n\t\t\t\t\t\t\th.Save();\n\t\t\t\t\t\t\tAudio.Stop();\n\t\t\t\t\t\t\tReplaceItem(entity, \"bk:bucket\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (snow) {\n\t\t\t\t\n\t\t\t} else if (Run.Level.Biome is IceBiome) {\n\t\t\t\tvar x = (int) Math.Floor(entity.CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(entity.CenterY / 16);\n\n\t\t\t\tfor (var xx = -1; xx <= 1; xx++) {\n\t\t\t\t\tfor (var yy = -1; yy <= 1; yy++) {\n\t\t\t\t\t\tvar d = Math.Sqrt(xx * xx + yy * yy);\n\n\t\t\t\t\t\tif (d <= 1 && Run.Level.IsInside(x + xx, y + yy) && Run.Level.Get(x + xx, y + yy) == Tile.WallA) {\n\t\t\t\t\t\t\tReplaceItem(entity, \"bk:snow_bucket\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void ReplaceItem(Entity entity, string id) {\n\t\t\tvar c = entity.GetComponent<ActiveItemComponent>();\n\t\t\tvar i = c.Item;\n\t\t\t\t\n\t\t\tc.Drop();\n\t\t\ti.Done = true;\n\n\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(id, entity.Area));\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\twater = settings[\"wt\"].Bool(false);\n\t\t\tsnow = settings[\"snw\"].Bool(true);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"Water Bucket\", \"wt\", false);\n\t\t\troot.Checkbox(\"Snow Bucket\", \"snw\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ChanceToUseWeaponUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ChanceToUseWeaponUse : ItemUse {\n\t\tprivate bool back;\n\t\tprivate bool up;\n\t\tprivate bool down;\n\t\tprivate float chance;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemUsedEvent ite && !ite.Fake && ite.Item != Item) {\n\t\t\t\tif (Rnd.Chance(chance + Run.Luck * 10)) {\n\t\t\t\t\tvar weapon = Item.Owner.GetComponent<ActiveWeaponComponent>().Item;\n\n\t\t\t\t\tif (weapon == null) {\n\t\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tvar aim = Item.Owner.GetComponent<AimComponent>();\n\t\t\t\t\tvar a = (aim.RealAim - aim.Center).ToAngle();\n\n\t\t\t\t\tif (up) {\n\t\t\t\t\t\taim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI * 0.5f, 48) + aim.Center;\n\t\t\t\t\t\tweapon.Use(Item.Owner, true);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (down) {\n\t\t\t\t\t\taim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI * 1.5f, 48) + aim.Center;\n\t\t\t\t\t\tweapon.Use(Item.Owner, true);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (back) {\n\t\t\t\t\t\taim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI, 48) + aim.Center;\n\t\t\t\t\t\tweapon.Use(Item.Owner, true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tback = settings[\"back\"].Bool(false);\n\t\t\tup = settings[\"up\"].Bool(false);\n\t\t\tdown = settings[\"down\"].Bool(false);\n\t\t\tchance = settings[\"chance\"].Number(10f);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"Back\", \"back\", false);\n\t\t\troot.Checkbox(\"Up\", \"up\", false);\n\t\t\troot.Checkbox(\"Down\", \"down\", false);\n\t\t\troot.InputFloat(\"Chance\", \"chance\", 10);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ConsumeUse.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ConsumeUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\titem.Done = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DetonateBombsUse.cs",
    "content": "using BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.entities;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DetonateBombsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (!entity.TryGetComponent<RoomComponent>(out var r)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar bombs = r.Room.Tagged[Tags.Bomb].ToArray();\n\n\t\t\tforeach (var b in bombs) {\n\t\t\t\tif (b is Bomb bm) {\n\t\t\t\t\tbm.Explode();\n\t\t\t\t} else if (b is ExplodingBarrel br) {\n\t\t\t\t\tbr.Explode();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DigUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.input;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DigUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar cursor = entity.GetComponent<CursorComponent>().Cursor.GamePosition;\n\t\t\tvar x = (int) Math.Floor(cursor.X / 16f);\n\t\t\tvar y = (int) Math.Floor((cursor.Y) / 16f);\n\n\t\t\tvar level = Run.Level;\n\n\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar index = level.ToIndex(x, y);\n\t\t\tvar tile = level.Tiles[index];\n\t\t\tvar t = (Tile) tile;\n\t\t\t\n\t\t\tif (!t.IsWall()) {\n\t\t\t\tif (t == Tile.Chasm) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\tif (level.Liquid[index] != 0) {\n\t\t\t\t\tlevel.Liquid[index] = 0;\n\t\t\t\t} else {\n\t\t\t\t\tlevel.Liquid[index] = 0;\n\t\t\t\t\tlevel.Set(index, Tile.Chasm);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlevel.Set(index, Tile.FloorA);\n\t\t\t}\n\t\t\t\n\t\t\tlevel.UpdateTile(x, y);\n\t\t\tlevel.CreateBody();\n\t\t\tlevel.CreateDestroyableBody();\n\t\t\tlevel.LoadPassable();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DiscoverSecretRoomsUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DiscoverSecretRoomsUse : ItemUse {\n\t\tprivate float chance;\n\n\t\tpublic override void Use(Entity entity, Item item) {\t\t\t\t\n\t\t\tExplosionMaker.CheckForCracks(Run.Level, entity.GetComponent<RoomComponent>().Room, entity);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tif (!Rnd.Chance(chance)) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\tExplosionMaker.CheckForCracks(Run.Level, rce.New, rce.Who);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tchance = settings[\"chance\"].Number(100);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar chance = root[\"chance\"].Number(100);\n\n\t\t\tif (ImGui.InputFloat(\"Chance\", ref chance)) {\n\t\t\t\troot[\"chance\"] = chance;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DiscoverSideRoomsUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DiscoverSideRoomsUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce) {\n\t\t\t\tif (rce.New == null) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\tvar discovered = new List<Room>() {\n\t\t\t\t\trce.Old\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tforeach (var d in rce.New.Doors) {\n\t\t\t\t\tif (d.Rooms[0] != null && d.Rooms[1] != null) {\n\t\t\t\t\t\tRoom room;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (d.Rooms[0] == rce.New) {\n\t\t\t\t\t\t\troom = d.Rooms[1];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\troom = d.Rooms[0];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (room.Type == RoomType.Secret || room.Type == RoomType.DarkMarket || room.Type == RoomType.Hidden || Rnd.Chance(20)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!discovered.Contains(room)) {\n\t\t\t\t\t\t\tdiscovered.Add(room);\n\t\t\t\t\t\t\troom.Discover();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoOnEnemyCollisionUse.cs",
    "content": "using BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.use.parent;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoOnEnemyCollisionUse : DoUsesUse {\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev && ev.Entity is Creature c && !c.IsFriendly()) {\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Use(c, Item);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoOnHurtUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.item.use.parent;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoOnHurtUse : DoUsesUse {\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is PostHealthModifiedEvent ev && ev.Amount < 0) {\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Use(ev.Who, Item);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoOnNewFloorUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.item.use.parent;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoOnNewFloorUse : DoUsesUse {\n\t\tprivate Entity e;\n\t\t\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\te = entity;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event ev) {\n\t\t\tif (ev is NewFloorEvent) {\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Use(e, Item);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(ev);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoOnTimerUse.cs",
    "content": "using BurningKnight.entity.item.use.parent;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoOnTimerUse : DoUsesUse {\n\t\tprivate float time;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Item = item;\n\t\t\t\t\tu.Use(entity, item);\n\t\t\t\t}\n\t\t\t}, time);\n\t\t}\n\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\ttime = settings[\"time\"].Number(1f);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Time\", \"time\", 1f);\n\t\t\tImGui.Separator();\n\t\t\tDoUsesUse.RenderDebug(root);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoUsesIfUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.use.parent;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoUsesIfUse : DoUsesUse {\n\t\tprivate static string[] options = {\n\t\t\t\"full_hp\",\n\t\t\t\"min_hp\",\n\t\t\t\"not_full_hp\"\n\t\t};\n\n\t\tprivate int option;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (IsTrue(entity)) {\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Use(entity, Item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool IsTrue(Entity entity) {\n\t\t\tswitch (option) {\n\t\t\t\tcase 0: {\n\t\t\t\t\treturn entity.GetComponent<HealthComponent>().IsFull();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase 1: {\n\t\t\t\t\treturn Math.Abs(entity.GetComponent<HealthComponent>().Health) < 1.1f;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase 2: {\n\t\t\t\t\treturn !entity.GetComponent<HealthComponent>().IsFull();\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\toption = settings[\"opt\"].Int(0);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tDoUsesUse.RenderDebug(root);\n\t\t\tImGui.Separator();\n\n\t\t\tvar option = root[\"opt\"].Int(0);\n\n\t\t\tif (ImGui.Combo(\"If\", ref option, options, options.Length)) {\n\t\t\t\troot[\"opt\"] = option;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DoWithUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item.use.parent;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DoWithUse : DoWithTagUse {\n\t\tprotected ItemUse[] Uses;\n\t\tprotected float chance;\n\n\t\tprotected override void DoAction(Entity entity, Item item, List<Entity> entities) {\n\t\t\tforeach (var e in entities) {\n\t\t\t\tif (chance < 100f && !Rnd.Chance(chance)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tforeach (var u in Uses) {\n\t\t\t\t\tu.Use(e, item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tif (!settings[\"uses\"].IsJsonArray) {\n\t\t\t\tsettings[\"uses\"] = new JsonArray();\n\t\t\t}\n\t\t\t\n\t\t\tUses = Items.ParseUses(settings[\"uses\"]);\n\t\t\tchance = settings[\"chance\"].Number(100);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Chance\", \"chance\", 100f);\n\t\t\t\n\t\t\tif (ImGui.TreeNode(\"With who\")) {\n\t\t\t\tDoWithTagUse.RenderDebug(root);\n\t\t\t\tImGui.TreePop();\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tif (!root[\"uses\"].IsJsonArray) {\n\t\t\t\troot[\"uses\"] = new JsonArray();\n\t\t\t}\n\t\t\t\n\t\t\tItemEditor.DisplayUse(root, root[\"uses\"]);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DuplicateItemsUse.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DuplicateItemsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\t\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Copy to array, because we are going to change the list in the loop\n\t\t\tvar items = room.Tagged[Tags.Item].ToArray();\n\n\t\t\tforeach (var it in items) {\n\t\t\t\tif (it is ItemStand ist) {\n\t\t\t\t\tif (ist.Item == null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar st = new ItemStand();\n\t\t\t\t\tentity.Area.Add(st);\n\n\t\t\t\t\tist.X -= ist.Width / 2f + 1;\n\n\t\t\t\t\tst.X = ist.X + ist.Width + 2;\n\t\t\t\t\tst.Y = ist.Y;\n\n\t\t\t\t\tst.SetItem(Items.CreateAndAdd(ist.Item.Id, entity.Area), item);\n\t\t\t\t} else if (it is Item i) {\n\t\t\t\t\tvar st = Items.CreateAndAdd(i.Id, entity.Area);\n\t\t\t\t\ti.X -= i.Width / 2f + 1;\n\t\t\t\t\t\n\t\t\t\t\tst.X = i.X + i.Width + 2;\n\t\t\t\t\tst.Y = i.Y;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar chests = room.Tagged[Tags.Chest].ToArray();\n\n\t\t\tforeach (var i in chests) {\n\t\t\t\ttry {\n\t\t\t\t\tvar st = (Entity) Activator.CreateInstance(i.GetType());\n\t\t\t\t\ti.X -= i.Width / 2f + 1;\n\n\t\t\t\t\tst.X = i.X + i.Width + 2;\n\t\t\t\t\tst.Y = i.Y;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DuplicateMobsAndHealUse.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DuplicateMobsAndHealUse : DuplicateMobsUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null || room.Tagged[Tags.Mob].Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tentity.GetComponent<HealthComponent>().ModifyHealth(2, item);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/DuplicateMobsUse.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class DuplicateMobsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\t\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Copy to array, because we are going to change the list in the loop\n\t\t\tvar mobs = room.Tagged[Tags.Mob].ToArray();\n\n\t\t\tforeach (var mob in mobs) {\n\t\t\t\ttry {\n\t\t\t\t\tvar m = (Mob) Activator.CreateInstance(mob.GetType());\n\t\t\t\t\tentity.Area.Add(m);\n\t\t\t\t\tm.Center = mob.Center;\n\n\t\t\t\t\tif (!(MobRegistry.FindFor(m.GetType())?.NearWall ?? false)) {\n\t\t\t\t\t\tm.Center += Rnd.Vector(-8, 8);\n\t\t\t\t\t}\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/EnableScourgeUse.cs",
    "content": "using BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class EnableScourgeUse : ItemUse {\n\t\tprivate string scourge;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tScourge.Enable(scourge);\n\n\t\t\tif (Run.Scourge == 0) {\n\t\t\t\tRun.AddScourge();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tscourge = settings[\"scourge\"].String(Scourge.OfUnknown);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputText(\"Scourge\", \"scourge\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ExplodeUse.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ExplodeUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tExplosionMaker.Make(entity);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/FireInAllDirsUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class FireInAllDirsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar weapon = entity.GetComponent<ActiveWeaponComponent>().Item;\n\n\t\t\tif (weapon == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar aim = entity.GetComponent<AimComponent>();\n\t\t\t\n\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\tvar angle = i / 4f * (float) Math.PI;\n\t\t\t\taim.RealAim = aim.Aim = MathUtils.CreateVector(angle, 48) + aim.Center;\n\n\t\t\t\tweapon.Use(entity, true);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveBombUse.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveBombUse: ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar h = entity.GetComponent<HeartsComponent>();\n\t\t\tvar a = Amount;\n\n\t\t\tif (h.Bombs < h.BombsMax) {\n\t\t\t\tvar t = Math.Min(Amount, h.BombsMax - h.Bombs);\n\t\t\t\th.ModifyBombs(t, null);\n\t\t\t\ta -= t;\n\t\t\t}\n\n\t\t\tif (a > 0) {\n\t\t\t\tentity.GetComponent<ConsumablesComponent>().Bombs += a;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveBuffImmunityUse.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveBuffImmunityUse : GiveBuffUse {\n\t\tpublic bool IceImmunity;\n\t\tpublic bool PitImmunity;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (IceImmunity) {\n\t\t\t\tentity.GetComponent<BuffsComponent>().IceImmunity = true;\n\t\t\t}\n\n\t\t\tif (PitImmunity) {\n\t\t\t\tentity.GetComponent<BuffsComponent>().PitImmunity = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tIceImmunity = settings[\"ice\"].Bool(false);\n\t\t\tPitImmunity = settings[\"pit\"].Bool(false);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BuffCheckEvent ev && ev.Buff.Type == Buff) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tGiveBuffUse.RenderDebug(root);\n\t\t\tImGui.Separator();\n\t\t\troot.Checkbox(\"Give ice immunity\", \"ice\", false);\n\t\t\troot.Checkbox(\"Pit immunity\", \"pit\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveBuffUse.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveBuffUse : ItemUse {\n\t\tprotected string Buff;\n\t\tprotected float Time;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar b = BuffRegistry.Create(Buff);\n\n\t\t\tif (b == null) {\n\t\t\t\tLog.Error($\"Unknown buff {Buff}\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Time < 0) {\n\t\t\t\tb.Infinite = true;\n\t\t\t} else {\n\t\t\t\tb.TimeLeft = b.Duration = Time;\n\t\t\t}\n\n\t\t\tif (entity.TryGetComponent<BuffsComponent>(out var buffs)) {\n\t\t\t\tbuffs.Add(b);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tTime = settings[\"time\"].Number(1);\n\t\t\tBuff = settings[\"buff\"].AsString ?? \"\";\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar time = root[\"time\"].Number(1);\n\t\t\tvar buff = root[\"buff\"].AsString ?? \"\";\n\n\t\t\tif (ImGui.InputText(\"Buff\", ref buff, 128)) {\n\t\t\t\troot[\"buff\"] = buff;\n\t\t\t}\n\n\t\t\tif (!BuffRegistry.All.ContainsKey(buff)) {\n\t\t\t\tImGui.BulletText(\"Unknown buff!\");\n\t\t\t}\n\n\t\t\tvar infinite = time < 0;\n\n\t\t\tif (ImGui.Checkbox(\"Infinite?\", ref infinite)) {\n\t\t\t\ttime = infinite ? -1 : 1;\n\t\t\t}\n\n\t\t\tif (!infinite) {\n\t\t\t\tif (ImGui.InputFloat(\"Duration\", ref time)) {\n\t\t\t\t\troot[\"time\"] = time;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveEmeraldsUse.cs",
    "content": "using BurningKnight.save;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveEmeraldsUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tGlobalSave.Emeralds += Amount;\n\n\t\t\tentity.Area.EventListener.Handle(new GaveEvent {\n\t\t\t\tAmount = Amount\n\t\t\t});\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class GaveEvent : Event {\n\t\t\tpublic int Amount;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveFlightUse.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveFlightUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (entity is Player p) {\n\t\t\t\tp.HasFlight = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveGoldUse.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveGoldUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.GetComponent<ConsumablesComponent>().Coins += Amount;\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tImGui.InputInt(\"Amount\", ref val);\n\t\t\troot[\"amount\"] = val;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveHeartContainersUse.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveHeartContainersUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar component = entity.GetComponent<HealthComponent>();\n\t\t\tcomponent.MaxHealth += Amount;\n\t\t\t\n\t\t\tif (!item.Used && Amount > 0) {\n\t\t\t\tcomponent.ModifyHealth(Amount, entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveItemUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveItemUse : ItemUse {\n\t\tpublic int Amount;\n\t\tpublic string Item;\n\t\tpublic bool OnStand;\n\t\tpublic bool Random;\n\t\tpublic bool Animate;\n\t\tpublic bool Hide;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar id = Random ? Items.Generate(i => i.Type == ItemType.Active || i.Type == ItemType.Weapon || i.Type == ItemType.Artifact) : Item;\n\t\t\t\n\t\t\tif (OnStand) {\n\t\t\t\tvar i = Items.CreateAndAdd(id, entity.Area);\n\n\t\t\t\tif (i == null) {\n\t\t\t\t\tLog.Error($\"Invalid item {id}\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar stand = new ItemStand();\n\t\t\t\tentity.Area.Add(stand);\n\t\t\t\tstand.Center = entity.Center - new Vector2(0, 8);\n\t\t\t\tstand.SetItem(i, null);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tfor (var j = 0; j < Amount; j++) {\n\t\t\t\tvar i = Items.CreateAndAdd(id, entity.Area);\n\n\t\t\t\tif (i == null) {\n\t\t\t\t\tLog.Error($\"Invalid item {id}\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// i.Hide = Hide;\n\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(i, Animate);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tItem = settings[\"item\"].AsString ?? \"\";\n\t\t\tOnStand = settings[\"on_stand\"].Bool(false);\n\t\t\tRandom = settings[\"random\"].Bool(false);\n\t\t\tAnimate = settings[\"animate\"].Bool(true);\n\t\t\tHide = settings[\"hide\"].Bool(false);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar stand = root[\"on_stand\"].Bool(false);\n\t\t\tvar random = root[\"random\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Spawn on stand?\", ref stand)) {\n\t\t\t\troot[\"on_stand\"] = stand;\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.Checkbox(\"Random item?\", ref random)) {\n\t\t\t\troot[\"random\"] = random;\n\t\t\t}\n\t\t\t\n\t\t\tif (stand) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (!random) {\n\t\t\t\tvar item = root[\"item\"].AsString ?? \"\";\n\n\t\t\t\tif (ImGui.InputText(\"Item\", ref item, 128)) {\n\t\t\t\t\troot[\"item\"] = item;\n\t\t\t\t}\n\n\t\t\t\tif (!Items.Datas.ContainsKey(item)) {\n\t\t\t\t\tImGui.BulletText(\"Unknown item!\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\n\t\t\troot.Checkbox(\"Animate?\", \"animate\", true);\n\t\t\troot.Checkbox(\"Hide?\", \"hide\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveKeyUse.cs",
    "content": "using BurningKnight.entity.creature.player;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class GiveKeyUse : ItemUse {\r\n\t\tpublic int Amount;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tentity.GetComponent<ConsumablesComponent>().Keys += Amount;\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\tAmount = settings[\"amount\"].Int(1);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar val = root[\"amount\"].Int(1);\r\n\r\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\r\n\t\t\t\troot[\"amount\"] = val;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveLaserAimUse.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveLaserAimUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tentity.GetComponent<AimComponent>().ShowLaserLine = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GivePhaseUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GivePhaseUse : ItemUse {\n\t\tpublic int Amount;\n\t\tpublic bool Broken;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (!item.Used && (!Broken || Rnd.Chance())) {\n\t\t\t\tentity.GetComponent<HealthComponent>().Phases += (byte) Amount;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tBroken = settings[\"broken\"].Bool(false);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\n\t\t\troot.Checkbox(\"Broken\", \"broken\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveRandomPickupUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveRandomPickupUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Consumable), entity.Area));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveScourgeImmunityUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GiveScourgeImmunityUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar sc = Run.Scourge;\n\t\t\t\n\t\t\tfor (var i = 0; i < sc; i++) {\n\t\t\t\tRun.RemoveScourge();\n\t\t\t}\n\n\t\t\tvar inventory = entity.GetComponent<InventoryComponent>();\n\t\t\tvar toRemove = new List<Item>();\n\n\t\t\tforeach (var i in inventory.Items) {\n\t\t\t\tif (i.Scourged) {\n\t\t\t\t\ti.Scourged = false;\n\t\t\t\t}\n\n\t\t\t\tif (i.Type == ItemType.Scourge) {\n\t\t\t\t\ttoRemove.Add(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCleanse(entity.GetComponent<WeaponComponent>());\n\t\t\tCleanse(entity.GetComponent<ActiveWeaponComponent>());\n\t\t\tCleanse(entity.GetComponent<ActiveItemComponent>());\n\n\t\t\t// fixme: doesnt do anything to ui inventory\n\t\t\tforeach (var i in toRemove) {\n\t\t\t\tinventory.Remove(i, true);\n\t\t\t}\n\n\t\t\tforeach (var s in Scourge.Defined) {\n\t\t\t\tScourge.Disable(s);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Cleanse(ItemComponent component) {\n\t\t\tif (component.Item != null) {\n\t\t\t\tcomponent.Item.Scourged = false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GiveWeaponUse.cs",
    "content": "using BurningKnight.assets.items;\r\nusing BurningKnight.entity.creature.player;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class GiveWeaponUse : ItemUse {\r\n\t\tpublic string Item;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar i = Items.CreateAndAdd(Item, entity.Area);\r\n\r\n\t\t\tif (i == null) {\r\n\t\t\t\tLog.Error($\"Invalid item {item}\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar o = entity.GetComponent<WeaponComponent>();\r\n\t\t\tvar c = (WeaponComponent) entity.GetComponent<ActiveWeaponComponent>();\r\n\r\n\t\t\tif (o.Item == item) {\r\n\t\t\t\tc = o;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar old = c.Item;\r\n\r\n\t\t\tc.Set(i, false);\r\n\t\t\told.Done = true;\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\tItem = settings[\"item\"].AsString ?? \"\";\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar item = root[\"item\"].AsString ?? \"\";\r\n\r\n\t\t\tif (ImGui.InputText(\"Item\", ref item, 128)) {\r\n\t\t\t\troot[\"item\"] = item;\r\n\t\t\t}\r\n\r\n\t\t\tif (!Items.Datas.ContainsKey(item)) {\r\n\t\t\t\tImGui.BulletText(\"Unknown item!\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/GoThonkUse.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class GoThonkUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar enemies = room.Tagged[Tags.Mob];\n\n\t\t\tif (enemies.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar attempt = 0;\n\t\t\tvar count = 0;\n\n\t\t\tdo {\n\t\t\t\tvar enemy = enemies[Rnd.Int(enemies.Count)];\n\n\t\t\t\tif (enemy.GetComponent<BuffsComponent>().Add(new FrozenBuff {\n\t\t\t\t\t\tDuration = 50\n\t\t\t\t}) != null) {\n\t\t\t\t\tif (!enemy.HasComponent<DialogComponent>()) {\n\t\t\t\t\t\tenemy.AddComponent(new DialogComponent());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tenemy.GetComponent<DialogComponent>().Start(\"mob_0\");\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (count >= 3) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (attempt++ < 99);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/InvokeItemsUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class InvokeItemsUse : ItemUse {\n\t\tprivate bool pets;\n\t\tprivate bool orbitals;\n\t\tprivate bool any;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\t\n\t\t\tvar inventory = entity.GetComponent<InventoryComponent>();\n\t\t\tvar items = new List<string>();\n\n\t\t\tforeach (var i in inventory.Items) {\n\t\t\t\tvar use = any;\n\n\t\t\t\tif (!use) {\n\t\t\t\t\tvar data = i.Data;\n\t\t\t\t\tuse = (pets && ItemPool.Pet.Contains(data.Pools)) || (orbitals && ItemPool.Orbital.Contains(data.Pools));\n\t\t\t\t}\n\n\t\t\t\tif (use) {\n\t\t\t\t\titems.Add(i.Id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var i in items) {\n\t\t\t\tinventory.Pickup(Items.CreateAndAdd(i, entity.Area), false);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tpets = settings[\"pets\"].Bool(true);\n\t\t\torbitals = settings[\"orbitals\"].Bool(false);\n\t\t\tany = settings[\"any\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"Pets\", \"pets\", true);\n\t\t\troot.Checkbox(\"Orbitals\", \"orbitals\", false);\n\t\t\troot.Checkbox(\"Any\", \"any\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ItemUse.cs",
    "content": "﻿using Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ItemUse {\n\t\tpublic Item Item;\n\t\tpublic bool SingleUse;\n\t\t\n\t\tpublic virtual void Use(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(Entity entity, Item item, float dt) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Pickup(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Drop(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void TakeOut(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PutAway(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Setup(JsonValue settings) {\n\t\t\tSingleUse = settings[\"single\"].Bool(false);\n\t\t}\n\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic virtual bool HandleEvent(Event e) {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/KillMobUse.cs",
    "content": "using System.Linq;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class KillMobUse : ItemUse {\n\t\tprivate bool all;\n\t\tprivate bool half;\n\t\tprivate int count;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar mobs = room.Tagged[Tags.Mob].ToList();\n\n\t\t\tif (all) {\n\t\t\t\tforeach (var m in mobs) {\n\t\t\t\t\t((Mob) m).Kill(entity);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (half) {\n\t\t\t\tvar c = mobs.Count / 2;\n\t\t\t\t\n\t\t\t\tfor (var g = 0; g < c; g++) {\n\t\t\t\t\t((Mob) mobs[g]).Kill(entity);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar i = 0;\n\n\t\t\tdo {\n\t\t\t\tvar index = Rnd.Int(mobs.Count);\n\t\t\t\tvar mob = mobs[index];\n\t\t\t\tmobs.RemoveAt(index);\n\n\t\t\t\t((Mob) mob).Kill(entity);\n\t\t\t\t\n\t\t\t\ti++;\n\t\t\t} while (mobs.Count > 0 && i < count);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tall = settings[\"all\"].Bool(false);\n\t\t\thalf = settings[\"half\"].Bool(false);\n\t\t\tcount = settings[\"count\"].Int(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar all = root[\"all\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"All?\", ref all)) {\n\t\t\t\troot[\"all\"] = all;\n\t\t\t}\n\n\t\t\tif (all || root.Checkbox(\"Half\", \"half\", false)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar count = root[\"count\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Count\", ref count)) {\n\t\t\t\troot[\"count\"] = count;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/LeaveLegoUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class LeaveLegoUse : ItemUse {\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(Entity entity, Item item, float dt) {\n\t\t\tbase.Update(entity, item, dt);\n\n\t\t\tvar r = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (r == null || r.Tagged[Tags.MustBeKilled].Count == 0) {\n\t\t\t\tt = 0;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tt += dt;\n\n\t\t\tif (t >= 5f) {\n\t\t\t\tt = 0;\n\t\t\t\tvar lego = new Lego();\n\t\t\t\tentity.Area.Add(lego);\n\t\t\t\tlego.BottomCenter = entity.BottomCenter;\n\t\t\t\tAnimationUtil.Ash(lego.Center);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeBombsBlankUse.cs",
    "content": "using BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeBombsBlankUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BombPlacedEvent bpe) {\n\t\t\t\tbpe.Bomb.OnDeath += (b) => BlankMaker.Make(b.Center, b.Area);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeBombsExplodeOnTouchUse.cs",
    "content": "using BurningKnight.entity.bomb.controller;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeBombsExplodeOnTouchUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BombPlacedEvent bce) {\n\t\t\t\tbce.Bomb.ExplodeOnTouch = true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeBombsHomeUse.cs",
    "content": "using BurningKnight.entity.bomb.controller;\nusing BurningKnight.entity.events;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeBombsHomeUse : ItemUse {\n\t\tprivate float speed;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BombPlacedEvent bce) {\n\t\t\t\tbce.Bomb.ExplodeOnTouch = true;\n\t\t\t\tbce.Bomb.Controller += TargetBombController.Make(null, speed);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tspeed = settings[\"speed\"].Number(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar speed = root[\"speed\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref speed)) {\n\t\t\t\troot[\"speed\"] = speed;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeItemsAttactUse.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeItemsAttactUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tItem.Attact = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeLayerPassableUse.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.projectile;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.physics;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class MakeLayerPassableUse : ItemUse {\r\n\t\tprivate bool forProjectiles;\r\n\t\tprivate bool forPlayer;\r\n\r\n\t\tprivate bool chasms;\r\n\t\tprivate bool props;\r\n\t\tprivate bool walls;\r\n\t\tprivate bool mobs;\r\n\t\tprivate bool stones;\r\n\t\tprivate bool projectiles;\r\n\t\tprivate bool breakProjectiles;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tif (forPlayer) {\r\n\t\t\t\tif (props) {\r\n\t\t\t\t\tCollisionFilterComponent.Add(entity, (o, e) => e is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (chasms) {\r\n\t\t\t\t\t((Creature) entity).Flying = true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (walls) {\r\n\t\t\t\t\tCollisionFilterComponent.Add(entity, (o, en) => en is Level || en is ProjectileLevelBody || en is HalfProjectileLevel || en is HalfWall ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (stones) {\r\n\t\t\t\t\tCollisionFilterComponent.Add(entity, (o, en) => en is HalfWall || en is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t}\r\n\t\t\t}\t\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is ProjectileCreatedEvent pce) {\r\n\t\t\t\tif (forProjectiles) {\r\n\t\t\t\t\tif (props) {\r\n\t\t\t\t\t\tCollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (walls) {\r\n\t\t\t\t\t\tpce.Projectile.AddFlags(ProjectileFlags.FlyOverStones);\r\n\t\t\t\t\t\tCollisionFilterComponent.Add(pce.Projectile, (o, en) => (en is Level || en is ProjectileLevelBody || en is Door) ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (mobs) {\r\n\t\t\t\t\t\tCollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Creature ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t\tif (stones) {\r\n\t\t\t\t\t\tCollisionFilterComponent.Add(pce.Projectile, (o, en) => en is HalfWall || en is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (projectiles) {\r\n\t\t\t\t\t\tCollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Projectile ? CollisionResult.Enable : CollisionResult.Default);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (breakProjectiles) {\r\n\t\t\t\t\t\tpce.Projectile.AddFlags(ProjectileFlags.BreakOtherProjectiles);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\tforProjectiles = settings[\"fp\"].Bool(false);\r\n\t\t\tforPlayer = settings[\"fpl\"].Bool(false);\r\n\t\t\tchasms = settings[\"ic\"].Bool(false);\r\n\t\t\tprops = settings[\"ip\"].Bool(false);\r\n\t\t\twalls = settings[\"iw\"].Bool(false);\r\n\t\t\tmobs = settings[\"im\"].Bool(false);\r\n\t\t\tstones = settings[\"st\"].Bool(false);\r\n\t\t\tprojectiles = settings[\"p\"].Bool(false);\r\n\t\t\tbreakProjectiles = settings[\"bp\"].Bool(false);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar v = root[\"fp\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"For projectiles\", ref v)) {\r\n\t\t\t\troot[\"fp\"] = v;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tv = root[\"fpl\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"For player\", ref v)) {\r\n\t\t\t\troot[\"fpl\"] = v;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\troot.Checkbox(\"Projectiles\", \"p\", false);\r\n\t\t\t\r\n\t\t\tv = root[\"ic\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Ignore chasms\", ref v)) {\r\n\t\t\t\troot[\"ic\"] = v;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tv = root[\"ip\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Ignore props\", ref v)) {\r\n\t\t\t\troot[\"ip\"] = v;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tv = root[\"iw\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Ignore walls\", ref v)) {\r\n\t\t\t\troot[\"iw\"] = v;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tv = root[\"im\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Ignore mobs\", ref v)) {\r\n\t\t\t\troot[\"im\"] = v;\r\n\t\t\t}\r\n\r\n\t\t\troot.Checkbox(\"Ignore stones\", \"st\", false);\r\n\t\t\troot.Checkbox(\"Break Projectiles\", \"bp\", false);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectileExpandUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectileExpandUse : ItemUse {\n\t\tprivate float speed;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pce.Projectile, ExpandProjectileController.Make(speed));\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tspeed = settings[\"speed\"].Number(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar speed = root[\"speed\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref speed)) {\n\t\t\t\troot[\"speed\"] = speed;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectileReshootUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectileReshootUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce && !pce.Projectile.HasFlag(ProjectileFlags.Artificial)) {\n\t\t\t\tProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, en) => {\n\t\t\t\t\tvar room = p.Owner.GetComponent<RoomComponent>().Room;\n\n\t\t\t\t\tif (room == null || room.Tagged[Tags.MustBeKilled].Count == 0 || Rnd.Chance(20)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar target = room.FindClosest(p.Center, Tags.MustBeKilled, ent => ent != en);\n\n\t\t\t\t\tif (target != null) {\n\t\t\t\t\t\tvar c = p.HasComponent<CircleBodyComponent>();\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(pce.Owner, p.Slice) {\n\t\t\t\t\t\t\tRectHitbox = !c,\n\t\t\t\t\t\t\tParent = p,\n\t\t\t\t\t\t\tScale = p.Scale,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tvar pr = builder.Shoot(p.AngleTo(target), 10).Build();\n\n\t\t\t\t\t\tpr.EntitiesHurt.AddRange(p.EntitiesHurt);\n\t\t\t\t\t\tpr.Center = p.Center;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectileShrinkUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectileShrinkUse : ItemUse {\n\t\tprivate float speed;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pce.Projectile, ShrinkProjectileController.Make(speed));\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tspeed = settings[\"speed\"].Number(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar speed = root[\"speed\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref speed)) {\n\t\t\t\troot[\"speed\"] = speed;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesBlankOnDeathUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesBlankOnDeathUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => {\n\t\t\t\t\tif (Rnd.Chance(20 + Run.Luck * 10)) {\n\t\t\t\t\t\tBlankMaker.Make(p.Center, p.Area, 18f);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesBoomerangUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesBoomerangUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tvar projectile = pce.Projectile;\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, BoomerangProjectileController.Make(pce.Owner));\n\n\t\t\t\tif (projectile.T > 0) {\n\t\t\t\t\tprojectile.T *= 2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesBounceUse.cs",
    "content": "using BurningKnight.entity.events;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesBounceUse : ItemUse {\n\t\tprivate int count;\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tcount = settings[\"count\"].Int(1);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tpce.Projectile.Bounce += count;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar count = root[\"count\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Count\", ref count)) {\n\t\t\t\troot[\"count\"] = count;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesHomeInUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.projectile.controller;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesHomeInUse : ItemUse {\n\t\tprivate float speed;\n\t\tprivate bool better;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\t/* if (pce.Projectile is Laser l) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar room = pce.Owner.GetComponent<RoomComponent>().Room;\n\t\t\t\t\t\tvar ent = room?.FindClosest(l.Position, Tags.MustBeKilled);\n\n\t\t\t\t\t\tif (ent == null) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tLog.Debug(ent.GetType().FullName);\n\n\t\t\t\t\t\tvar ac = better ? 0.05f : 0.15f;\n\n\t\t\t\t\t\tl.PlayerRotated = false;\n\t\t\t\t\t\tl.BodyComponent.Body.Rotation = MathUtils.Angle(ent.Center.Y - l.Position.Y, ent.Center.X - l.Position.X);\n\t\t\t\t\t}, 0.05f);\n\t\t\t\t} else { */\n\t\t\t\t\tif (better) {\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pce.Projectile, TargetProjectileController.MakeBetter(speed));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pce.Projectile, TargetProjectileController.Make(null, speed));\n\t\t\t\t\t}\n\t\t\t\t// }\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tspeed = settings[\"speed\"].Number(1);\n\t\t\tbetter = settings[\"better\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar speed = root[\"speed\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref speed)) {\n\t\t\t\troot[\"speed\"] = speed;\n\t\t\t}\n\n\t\t\troot.Checkbox(\"Better?\", \"better\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesHurtOnMissUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesHurtOnMissUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tif (!(pce.Projectile.Owner is Player)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar hurt = false;\n\n\t\t\t\tProjectileCallbacks.AttachCollisionCallback(pce.Projectile, (p, en) => {\n\t\t\t\t\tif (en.HasComponent<HealthComponent>() || (en is ProjectileLevelBody && Run.Level.Biome is IceBiome)) {\n\t\t\t\t\t\thurt = true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => {\n\t\t\t\t\tif (!hurt) {\n\t\t\t\t\t\tItem.Owner.GetComponent<HealthComponent>().ModifyHealth(-1, Item);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else if (e is MeleeArc.CreatedEvent mac) {\n\t\t\t\tif (!(mac.Arc.Owner is Player)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar hurt = false;\n\n\t\t\t\tmac.Arc.OnHurt += (m, en) => {\n\t\t\t\t\tif (en.HasComponent<HealthComponent>() || (en is ProjectileLevelBody && Run.Level.Biome is IceBiome)) {\n\t\t\t\t\t\thurt = true;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tmac.Arc.OnDeath += (m) => {\n\t\t\t\t\tif (!hurt) {\n\t\t\t\t\t\tItem.Owner.GetComponent<HealthComponent>().ModifyHealth(-1, Item);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesKillWithBuffUse.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesKillWithBuffUse : ItemUse {\n\t\tprivate Type buff;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, w) => {\n\t\t\t\t\tif (w is Mob m && w.GetComponent<BuffsComponent>().Buffs.ContainsKey(buff)) {\n\t\t\t\t\t\tm.Kill(Item);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tvar b = settings[\"buff\"].String(\"bk:frozen\");\n\n\t\t\tif (BuffRegistry.All.TryGetValue(b, out var i)) {\n\t\t\t\tbuff = i.Buff;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputText(\"Buff\", \"buff\", \"bk:frozen\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesShatternOnDeathUse.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesShatternOnDeathUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\t// Make sure that this is a new projectile, not created by this event\n\t\t\tif (e is ProjectileCreatedEvent pce && pce.Projectile.Parent == null) {\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(pce.Projectile,  (p, en, t) => {\n\t\t\t\t\tif (Rnd.Chance(30) || p.Parent != null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar cnt = Rnd.Int(3, 5);\n\t\t\t\t\t\n\t\t\t\t\tif (p is Laser l) {\n\t\t\t\t\t\tvar a = l.BodyComponent.Body.Rotation - (float) Math.PI;\n\t\t\t\t\t\tvar end = l.End + MathUtils.CreateVector(a, 5);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (var i = 0; i < cnt; i++) {\n\t\t\t\t\t\t\tvar laser = Laser.Make(p.Owner, a + Rnd.Float(-1.4f, 1.4f), 0f, null, p.Damage, parent: l, scale: l.Scale * Rnd.Float(0.4f, 0.8f));\n\n\t\t\t\t\t\t\tlaser.Position = end;\n\t\t\t\t\t\t\tlaser.Recalculate();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar v = p.GetAnyComponent<BodyComponent>().Velocity;\n\t\t\t\t\t\tvar a = v.ToAngle() - (float) Math.PI;\n\t\t\t\t\t\tvar s = v.Length();\n\t\t\t\t\t\tvar c = p.HasComponent<CircleBodyComponent>();\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(pce.Owner, p.Slice) {\n\t\t\t\t\t\t\tParent = p,\n\t\t\t\t\t\t\tScale = p.Scale * Rnd.Float(0.4f, 0.8f),\n\t\t\t\t\t\t\tRectHitbox = !c\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tfor (var i = 0; i < cnt; i++) {\n\t\t\t\t\t\t\tbuilder.Shoot(a + Rnd.Float(-1.4f, 1.4f), s * Rnd.Float(0.3f, 0.7f)).Build().Center = p.Center;\n\t\t\t\t\t\t}\t\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesSlowDown.cs",
    "content": "using BurningKnight.entity.events;\r\nusing BurningKnight.entity.projectile;\r\nusing BurningKnight.entity.projectile.controller;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class MakeProjectilesSlowDown : ItemUse {\r\n\t\tprivate float amount;\r\n\t\tprivate float time;\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is ProjectileCreatedEvent pce) {\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pce.Projectile,  SlowdownProjectileController.Make(amount, time));\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\tamount = settings[\"amount\"].Number(1);\r\n\t\t\ttime = settings[\"time\"].Number(1);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar val = root[\"amount\"].Number(1);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref val)) {\r\n\t\t\t\troot[\"amount\"] = val;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tval = root[\"time\"].Number(1);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"Time\", ref val)) {\r\n\t\t\t\troot[\"time\"] = val;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesSplitOnDeathUse.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.projectile;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class MakeProjectilesSplitOnDeathUse : ItemUse {\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\t// Make sure that this is a new projectile, not created by this event\r\n\t\t\tif (e is ProjectileCreatedEvent pce && pce.Projectile.Parent == null) {\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(pce.Projectile,  (p, en, t) => {\r\n\t\t\t\t\tif (Rnd.Chance(20)) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t\tvar v = p.GetAnyComponent<BodyComponent>().Velocity;\r\n\r\n\t\t\t\t\tif (p is Laser l) {\r\n\t\t\t\t\t\tvar a = l.BodyComponent.Body.Rotation;\r\n\t\t\t\t\t\tvar end = l.End - MathUtils.CreateVector(a, 5);\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tfor (var i = 0; i < 2; i++) {\r\n\t\t\t\t\t\t\tvar laser = Laser.Make(p.Owner, a + (i == 0 ? -1 : 1) * (float) Math.PI * 0.5f, 0f, null, p.Damage, parent: l);\r\n\r\n\t\t\t\t\t\t\tlaser.Position = end;\r\n\t\t\t\t\t\t\tlaser.Recalculate();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tvar c = p.HasComponent<CircleBodyComponent>();\r\n\t\t\t\t\t\tvar s = v.Length();\r\n\t\t\t\t\t\tvar a = v.ToAngle() - Math.PI;\r\n\r\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(pce.Owner, p.Slice) {\r\n\t\t\t\t\t\t\tParent = p,\r\n\t\t\t\t\t\t\tScale = p.Scale,\r\n\t\t\t\t\t\t\tRectHitbox = !c\r\n\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\tbuilder.Shoot(a - (float) Math.PI * 0.5f, s).Build().Center = p.Center;\r\n\t\t\t\t\t\tbuilder.Shoot(a + (float) Math.PI * 0.5f, s).Build().Center = p.Center;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeProjectilesSplitUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeProjectilesSplitUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tif (pce.Projectile.Parent?.Parent != null || Rnd.Chance(20)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, en) => {\n\t\t\t\t\tvar v = p.GetAnyComponent<BodyComponent>();\n\t\t\t\t\tvar a = v.Velocity.ToAngle();\n\t\t\t\t\tvar s = v.Velocity.Length();\n\t\t\t\t\tvar c = p.HasComponent<CircleBodyComponent>();\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(pce.Owner, p.Slice) {\n\t\t\t\t\t\tScale = p.Scale,\n\t\t\t\t\t\tRectHitbox = !c,\n\t\t\t\t\t\tParent = p\n\t\t\t\t\t};\n\n\t\t\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\t\t\tvar pr = builder.Shoot( a + 0.2f * (i == 0 ? -1 : 1), s).Build();\n\n\t\t\t\t\t\tpr.EntitiesHurt.AddRange(p.EntitiesHurt);\n\t\t\t\t\t\tpr.Center = p.Center;\n\t\t\t\t\t}\n\n\t\t\t\t\tp.Break();\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeRollKickProjectilesUse.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.projectile;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeRollKickProjectilesUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (!(Item.Owner is Player pl) || !(pl.GetComponent<StateComponent>().StateInstance is Player.RollState)) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (cse.Entity is Projectile p && !(p.Owner is Player) && p.HasFlag(ProjectileFlags.Reflectable)) {\n\t\t\t\t\tvar owner = Item.Owner;\n\t\t\t\t\tvar a = owner.AngleTo(p.Owner);\n\n\t\t\t\t\tp.Owner = owner;\n\t\t\t\t\tp.Damage *= 2f;\n\n\t\t\t\t\t// Lethal?\n\t\t\t\t\t// p.Pattern?.Remove(p);\n\n\t\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\t\tvar d = Math.Max(400, b.Velocity.Length() * 1.8f);\n\n\t\t\t\t\tb.Velocity = MathUtils.CreateVector(a, d);\n\t\t\t\t\t\n\t\t\t\t\tif (p.TryGetComponent<LightComponent>(out var l)) {\n\t\t\t\t\t\tl.Light.Color = MeleeArc.ReflectedColor;\n\t\t\t\t\t}\n\n\t\t\t\t\tp.Color = ProjectileColor.Yellow;\n\n\t\t\t\t\tCamera.Instance.ShakeMax(4f);\n\t\t\t\t\towner.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"projectile_reflected\", 2);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MakeShopRestockUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing Lens.entity;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MakeShopRestockUse : ItemUse {\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemBoughtEvent ibe) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tibe.Stand.SetItem(Items.CreateAndAdd(Items.Generate(ibe.Stand.GetPool(), i => i.Id != ibe.Item.Id && Items.ShouldAppear(i)), ibe.Stand.Area), null);\n\t\t\t\t}, 0.5f);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/MeleeArcUse.cs",
    "content": "﻿using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class MeleeArcUse : ItemUse {\n\t\tprotected float Damage;\n\t\tprotected float LifeTime;\n\t\tprotected int W;\n\t\tprotected int H;\n\t\tprotected float Angle;\n\t\tprotected string AttackSound = \"item_sword_attack\";\n\t\tprotected string HitSound = \"item_sword_hit\";\n\t\tprotected float Knockback;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(AttackSound, 4);\n\n\t\t\tvar arc = new MeleeArc {\n\t\t\t\tOwner = entity,\n\t\t\t\tLifeTime = LifeTime,\n\t\t\t\tDamage = Damage * (item.Scourged ? 1.5f : 1),\n\t\t\t\tWidth = W,\n\t\t\t\tHeight = H,\n\t\t\t\tSound = HitSound,\n\t\t\t\tPosition = entity.Center,\n\t\t\t\tKnockback = Knockback,\n\t\t\t\tAngle = entity.AngleTo(entity.GetComponent<AimComponent>().RealAim) + Angle\n\t\t\t};\n\n\t\t\tentity.HandleEvent(new MeleeArc.CreatedEvent {\n\t\t\t\tArc = arc,\n\t\t\t\tOwner = entity,\n\t\t\t\tBy = item\n\t\t\t});\n\t\t\t\n\t\t\tentity.Area.Add(arc);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tDamage = settings[\"damage\"].Number(1);\n\t\t\tW = settings[\"w\"].Int(8);\n\t\t\tH = settings[\"h\"].Int(24);\n\t\t\tLifeTime = settings[\"time\"].Number(0.2f);\n\t\t\tAngle = settings[\"angle\"].Number(0) * (float) Math.PI * 2;\n\t\t\tHitSound = settings[\"hs\"].String(\"item_sword_hit\");\n\t\t\tAttackSound = settings[\"as\"].String(\"item_sword_attack\");\n\t\t\tKnockback = settings[\"knockback\"].Number(0f);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Damage\", \"damage\", 1);\n\t\t\troot.InputInt(\"Width\", \"w\", 8);\n\t\t\troot.InputInt(\"Height\", \"h\", 24);\n\n\t\t\troot.InputFloat(\"Life time\", \"time\", 0.2f);\n\t\t\troot.InputFloat(\"Angle\", \"angle\", 0);\n\t\t\troot.InputFloat(\"Knockback\", \"knockback\", 0);\n\n\t\t\tImGui.Separator();\n\n\t\t\troot.InputText(\"Hit Sound\", \"hs\", \"item_sword_hit\");\n\t\t\troot.InputText(\"Attack Sound\", \"as\", \"item_sword_attack\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModEachAttackUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModEachAttackUse : ItemUse {\n\t\tprivate int count;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemUsedEvent iue && iue.Item.Type == ItemType.Weapon) {\n\t\t\t\tcount = (count + 1) % 5;\n\t\t\t} else if (count == 0) {\n\t\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\t\tpce.Projectile.Scale += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyActiveChargeUse.cs",
    "content": "using System;\r\nusing BurningKnight.entity.creature.player;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class ModifyActiveChargeUse : ItemUse {\r\n\t\tprivate bool percent;\r\n\t\tprivate float amount;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar i = entity.GetComponent<ActiveItemComponent>().Item;\r\n\r\n\t\t\tif (i == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (percent) {\r\n\t\t\t\ti.Delay = Math.Max(0, i.Delay - i.UseTime * amount * 0.01f);\r\n\t\t\t} else {\r\n\t\t\t\ti.Delay = Math.Max(0, i.Delay - amount);\r\n\t\t\t}\r\n\r\n\t\t\tif (i.Delay <= 0.001f) {\r\n\t\t\t\ti.Delay = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\tpercent = settings[\"percent\"].Bool(false);\r\n\t\t\tamount = settings[\"amount\"].Number(1f);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar percent = root[\"percent\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Percent?\", ref percent)) {\r\n\t\t\t\troot[\"percent\"] = percent;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar amount = root[\"amount\"].Number(1f);\r\n\r\n\t\t\tif (ImGui.InputFloat(percent ? \"Amount (%)\" : \"Amount (charge)\", ref amount)) {\r\n\t\t\t\troot[\"amount\"] = amount;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyArcUse.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyArcUse : ItemUse {\n\t\tpublic float Damage;\n\t\tpublic float Chance;\n\t\tpublic bool ToAny;\n\t\tpublic bool EventCreated = true;\n\t\tpublic string BuffToApply;\n\t\tpublic bool InfiniteBuff;\n\t\tpublic float BuffDuration;\n\t\tpublic bool RandomEffect;\n\t\tpublic float EffectChangeSpeed;\n\t\tpublic bool Mine;\n\t\tpublic float Scale;\n\t\t\n\t\tprivate float lastEffectTime;\n\t\tprivate int lastEffect = -1;\n\n\t\tprivate static string[] effects = {\n\t\t\tBurningBuff.Id, FrozenBuff.Id, PoisonBuff.Id, CharmedBuff.Id, SlowBuff.Id, BrokenArmorBuff.Id\n\t\t};\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is MeleeArc.CreatedEvent pce) {\n\t\t\t\tvar a = Item == pce.By;\n\t\t\t\t\n\t\t\t\tif (ToAny || (EventCreated && a)) {\n\t\t\t\t\tModifyProjectile(pce.Arc);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic void ModifyProjectile(MeleeArc arc) {\n\t\t\tif (Rnd.Float() > Chance + Run.Luck * 0.2f) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tarc.Mines = Mine;\n\t\t\tarc.Damage *= Damage;\n\n\t\t\tif (Math.Abs(Scale - 1) > 0.01f) {\n\t\t\t\tarc.Width *= Scale;\n\t\t\t\tarc.Height *= Scale;\n\n\t\t\t\t// arc.AdjustSize();\n\t\t\t}\n\n\t\t\tif (RandomEffect) {\n\t\t\t\tif (lastEffect == -1 || (EffectChangeSpeed > 0 && Engine.Time - lastEffectTime >= EffectChangeSpeed)) {\n\t\t\t\t\tlastEffect = Rnd.Int(effects.Length);\n\t\t\t\t\tlastEffectTime = Engine.Time;\n\t\t\t\t}\n\n\t\t\t\tApplyBuff(arc, effects[lastEffect]);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (BuffToApply != null) {\n\t\t\t\tApplyBuff(arc, BuffToApply);\n\t\t\t}\n\t\t}\n\n\t\tprivate void ApplyBuff(MeleeArc arc, string buff) {\n\t\t\tif (buff != null) {\n\t\t\t\tif (!BuffRegistry.All.TryGetValue(buff, out var info)) {\n\t\t\t\t\tLog.Error($\"Unknown buff {buff}\");\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tarc.Color = info.Effect.GetColor();\n\n\t\t\t\tarc.OnHurt += (p, e) => {\n\t\t\t\t\tif (e.TryGetComponent<BuffsComponent>(out var buffs)) {\n\t\t\t\t\t\tvar b = BuffRegistry.Create(buff);\n\n\t\t\t\t\t\tif (InfiniteBuff) {\n\t\t\t\t\t\t\tb.Infinite = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tb.TimeLeft = b.Duration = BuffDuration;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbuffs.Add(b);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\t\t\t\n\t\t\t\n\t\t\tChance = settings[\"chance\"].Number(1);\n\t\t\tDamage = settings[\"damage\"].Number(1);\n\t\t\tScale = settings[\"scale\"].Number(1);\n\t\t\tToAny = settings[\"any\"].Bool(false);\n\t\t\tMine = settings[\"mine\"].Bool(false);\n\n\t\t\tBuffToApply = settings[\"buff\"].String(null);\n\n\t\t\tif (BuffToApply != null) {\n\t\t\t\tInfiniteBuff = settings[\"infinite_buff\"].Bool(false);\n\t\t\t\tBuffDuration = settings[\"buff_time\"].Number(10);\n\t\t\t} else {\n\t\t\t\tBuffDuration = 10;\n\t\t\t}\n\n\t\t\tRandomEffect = settings[\"rne\"].Bool(false);\n\n\t\t\tif (RandomEffect) {\n\t\t\t\tEffectChangeSpeed = settings[\"ecs\"].Number(3f);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"From Any Source\", \"any\", false);\n\t\t\t\n\t\t\troot.InputFloat(\"Chance\", \"chance\");\n\t\t\troot.InputFloat(\"Damage Modifier\", \"damage\");\n\t\t\troot.InputFloat(\"Scale\", \"scale\");\n\t\t\troot.Checkbox(\"Make it mine\", \"mine\", false);\n\n\t\t\tImGui.Separator();\n\n\t\t\tif (root.Checkbox(\"Random Effect\", \"rne\", false)) {\n\t\t\t\troot.InputFloat(\"Effect Change Speed\", \"ecs\", 3f);\n\t\t\t} else {\n\t\t\t\tif (ImGui.TreeNode(\"Buff\")) {\n\t\t\t\t\tif (!BuffRegistry.All.ContainsKey(root.InputText(\"Buff\", \"buff\", \"bk:frozen\"))) {\n\t\t\t\t\t\tImGui.BulletText(\"Unknown buff!\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!root.Checkbox(\"Infinite\", \"infinite_buff\", false)) {\n\t\t\t\t\t\troot.InputFloat(\"Buff Duration\", \"buff_time\");\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyBombsUse.cs",
    "content": "using System;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyBombsUse : ItemUse {\n\t\tpublic bool SpawnBullets;\n\t\tpublic bool SpawnBombs;\n\t\tpublic bool SetFuseTime;\n\t\tpublic float FuseTime;\n\t\tpublic float RadiusMod;\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tSpawnBullets = settings[\"spawn_bullets\"].Bool(false);\n\t\t\tSpawnBombs = settings[\"spawn_bombs\"].Bool(false);\n\t\t\tSetFuseTime = settings[\"set_fuse\"].Bool(false);\n\t\t\tFuseTime = settings[\"fuse_time\"].Number(1);\n\t\t\tRadiusMod = settings[\"radius\"].Number(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar spawnBullets = root[\"spawn_bullets\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Spawn Bullets?\", ref spawnBullets)) {\n\t\t\t\troot[\"spawn_bullets\"] = spawnBullets;\n\t\t\t}\n\t\t\t\n\t\t\tvar spawnBombs = root[\"spawn_bombs\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Spawn Bombs?\", ref spawnBombs)) {\n\t\t\t\troot[\"spawn_bombs\"] = spawnBombs;\n\t\t\t}\n\t\t\t\n\t\t\troot.InputFloat(\"Radius Modifier\", \"radius\", 1f);\n\n\t\t\tvar setFuseTime = root[\"set_fuse\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Set fuse?\", ref setFuseTime)) {\n\t\t\t\troot[\"set_fuse\"] = setFuseTime;\n\t\t\t}\n\n\t\t\tif (!setFuseTime) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar fuseTime = root[\"fuse_time\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Fuse time\", ref fuseTime)) {\n\t\t\t\troot[\"fuse_time\"] = fuseTime;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is BombPlacedEvent bpe) {\n\t\t\t\tvar bomb = bpe.Bomb;\n\t\t\t\tvar c = bomb.GetComponent<ExplodeComponent>();\n\n\t\t\t\tc.Radius *= RadiusMod;\n\t\t\t\t\n\t\t\t\tif (SetFuseTime) {\n\t\t\t\t\tc.Timer = FuseTime + Rnd.Float(-0.1f, 1f);\n\t\t\t\t}\n\n\t\t\t\tif (SpawnBombs) {\n\t\t\t\t\tbomb.OnDeath += b => {\n\t\t\t\t\t\tif (b.Parent != null) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\t\tvar bm = new Bomb(b.Owner, Bomb.ExplosionTime, b);\n\t\t\t\t\t\t\tb.Area.Add(bm);\n\t\t\t\t\t\t\tbm.Center = b.Center + Rnd.Vector(-4, 4);\n\t\t\t\t\t\t\tbm.VelocityTo(i / 2f * (float) Math.PI, 300f);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (SpawnBullets) {\n\t\t\t\t\tbomb.OnDeath += b => {\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(b.Owner, \"rect\") {\n\t\t\t\t\t\t\tScale = b.Scale\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\t\t\t\tbuilder.Shoot((float) i / 8 * (float) Math.PI * 2, 8).Build().Center = b.Center;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyConsumableWeightsUse.cs",
    "content": "using System;\nusing BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyConsumableWeightsUse : ItemUse {\n\t\tprivate bool keys;\n\t\tprivate bool bombs;\n\t\tprivate bool coins;\n\t\tprivate float amount;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ConsumableAddedEvent cae) {\n\t\t\t\tvar t = cae.Type;\n\n\t\t\t\tif ((t == ItemType.Coin && coins) || (t == ItemType.Bomb && bombs) || (t == ItemType.Key && keys)) {\n\t\t\t\t\tcae.TotalNow -= cae.Amount;\n\t\t\t\t\tcae.Amount = (int) Math.Round(cae.Amount * amount);\n\t\t\t\t\tcae.TotalNow += cae.Amount;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tamount = settings[\"amount\"].Int(1);\n\t\t\tkeys = settings[\"keys\"].Bool(false);\n\t\t\tbombs = settings[\"bombs\"].Bool(false);\n\t\t\tcoins = settings[\"coins\"].Bool(true);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Modifier\", \"amount\");\n\t\t\troot.Checkbox(\"Coins\", \"coins\", true);\n\t\t\troot.Checkbox(\"Keys\", \"keys\", false);\n\t\t\troot.Checkbox(\"Bombs\", \"bombs\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyGameSaveValueUse.cs",
    "content": "using BurningKnight.save;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class ModifyGameSaveValueUse : ItemUse {\r\n\t\tprivate string id;\r\n\t\tprivate float amount;\r\n\t\tprivate bool over;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tbase.Use(entity, item);\r\n\r\n\t\t\tif (item.Used) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tGameSave.Put(id, over ? amount : GameSave.GetFloat(id) + amount);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\t\r\n\t\t\tid = settings[\"idd\"].String(\"\");\r\n\t\t\tamount = settings[\"am\"].Number(0);\r\n\t\t\tover = settings[\"ov\"].Bool(false);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar id = root[\"idd\"].String(\"\");\r\n\r\n\t\t\tif (ImGui.InputText(\"Field id##gs\", ref id, 128)) {\r\n\t\t\t\troot[\"idd\"] = id;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar amount = root[\"am\"].Number(0);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"Amount##gs\", ref amount)) {\r\n\t\t\t\troot[\"am\"] = amount;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar over = root[\"ov\"].Bool(false);\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Override?\", ref over)) {\r\n\t\t\t\troot[\"ov\"] = over;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyGenUse.cs",
    "content": "using BurningKnight.entity.projectile;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyGenUse : ItemUse {\n\t\tprivate bool xlLevel;\n\t\tprivate float chestRewardChance;\n\t\tprivate float mobDest;\n\t\tprivate float mimicChance;\n\t\tprivate bool genMarket;\n\t\tprivate bool shops;\n\t\tprivate bool treasure;\n\t\tprivate bool melee;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (xlLevel) {\n\t\t\t\tLevelSave.XL = true;\n\t\t\t}\n\n\t\t\tLevelSave.ChestRewardChance += chestRewardChance;\n\t\t\tLevelSave.MobDestructionChance += mobDest;\n\t\t\tLevelSave.MimicChance += mimicChance;\n\t\t\tLevelSave.GenerateMarket = genMarket;\n\t\t\tLevelSave.GenerateShops = shops;\n\t\t\tLevelSave.GenerateTreasure = treasure;\n\t\t\tLevelSave.MeleeOnly = melee;\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\txlLevel = settings[\"xl\"].Bool(false);\n\t\t\tchestRewardChance = settings[\"crc\"].Number(0);\n\t\t\tmobDest = settings[\"md\"].Number(0);\n\t\t\tmimicChance = settings[\"mimic\"].Number(0);\n\t\t\tgenMarket = settings[\"gm\"].Bool(false);\n\t\t\tshops = settings[\"sp\"].Bool(false);\n\t\t\ttreasure = settings[\"tr\"].Bool(false);\n\t\t\tmelee = settings[\"ml\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"XL Level\", \"xl\", false);\n\t\t\troot.Checkbox(\"Generate Market\", \"gm\", false);\n\t\t\troot.Checkbox(\"Only Shops\", \"sp\", false);\n\t\t\troot.Checkbox(\"Only Treasure\", \"tr\", false);\n\t\t\troot.Checkbox(\"Only Generate Melee\", \"ml\", false);\n\t\t\troot.InputFloat(\"Chest Reward Chance Modifier\", \"crc\", 0);\n\t\t\troot.InputFloat(\"Mob Not Shoot Chance Modifier\", \"md\", 0);\n\t\t\troot.InputFloat(\"Mimic Chance Modifier\", \"mimic\", 0);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyHpUse.cs",
    "content": "﻿using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\t\n\tpublic class ModifyHpUse : ItemUse {\n\t\tpublic int Amount;\n\t\tpublic bool SetToMin;\n\t\tpublic bool SetToMax;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (SetToMin) {\n\t\t\t\tentity.GetComponent<HealthComponent>().InitMaxHealth = 1;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (SetToMax) {\n\t\t\t\tvar h = entity.GetComponent<HealthComponent>();\n\t\t\t\th.ModifyHealth(h.MaxHealth, item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\tvar a = Amount;\n\n\t\t\tif (a > 0 && Scourge.IsEnabled(Scourge.OfIllness)) {\n\t\t\t\tif (a == 1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ta = (int) (a / 2f);\n\t\t\t}\n\t\t\t\n\t\t\tentity.GetComponent<HealthComponent>().ModifyHealth(a, entity);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tSetToMin = settings[\"to_min\"].Bool(false);\n\t\t\tSetToMax = settings[\"to_max\"].Bool(false);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Amount\", \"amount\");\n\t\t\troot.Checkbox(\"Set To Min\", \"to_min\", false);\n\t\t\troot.Checkbox(\"Fully Heal\", \"to_max\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyLuckUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyLuckUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tRun.Luck += Amount;\n\t\t\tTextParticle.Add(entity, Locale.Get(\"luck\"), Amount, true, Amount < 0);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyManaMaxUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyManaMaxUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar m = entity.GetComponent<ManaComponent>();\n\t\t\tm.ManaMax += Amount * 2;\n\t\t\tm.ModifyMana(Amount * 2);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Amount\", \"amount\");\n\t\t}\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyManaUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyManaUse : ItemUse {\n\t\tpublic int Amount;\n\t\tpublic bool SetToMin;\n\t\tpublic bool SetToMax;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (SetToMin) {\n\t\t\t\tentity.GetComponent<ManaComponent>().SetMana(1);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (SetToMax) {\n\t\t\t\tvar h = entity.GetComponent<ManaComponent>();\n\t\t\t\th.ModifyMana(h.ManaMax);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tentity.GetComponent<ManaComponent>().ModifyMana(Amount);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tSetToMin = settings[\"to_min\"].Bool(false);\n\t\t\tSetToMax = settings[\"to_max\"].Bool(false);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Amount\", \"amount\");\n\t\t\troot.Checkbox(\"Set To Min\", \"to_min\", false);\n\t\t\troot.Checkbox(\"Set To Max\", \"to_max\", false);\n\t\t}\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyMaxHpUse.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyMaxHpUse : ItemUse {\n\t\tpublic int Amount;\n\t\tpublic bool Set;\n\t\tpublic bool GiveHp;\n\t\tpublic bool Bomb;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (Bomb) {\n\t\t\t\tvar component = entity.GetComponent<HeartsComponent>();\n\n\t\t\t\tif (Set) {\n\t\t\t\t\tcomponent.BombsMax = Amount;\n\t\t\t\t} else {\n\t\t\t\t\tcomponent.BombsMax += Amount;\n\t\t\t\t}\n\n\t\t\t\tif (GiveHp && Amount > 0) {\n\t\t\t\t\tcomponent.ModifyBombs(Amount, entity);\n\t\t\t\t\tTextParticle.Add(entity, \"HP\", Amount, true);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Amount > 0) {\n\t\t\t\t\tif (entity.GetComponent<LampComponent>().Item?.Id == \"bk:shielded_lamp\") {\n\t\t\t\t\t\tentity.GetComponent<HeartsComponent>().ModifyShields(Amount, entity);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else if (entity.GetComponent<LampComponent>().Item?.Id == \"bk:explosive_lamp\") {\n\t\t\t\t\t\tvar c = entity.GetComponent<HeartsComponent>();\n\t\t\t\t\t\tAmount = (int) Math.Ceiling(Amount / 2f);\n\n\t\t\t\t\t\tc.BombsMax += Amount;\n\n\t\t\t\t\t\tif (GiveHp) {\n\t\t\t\t\t\t\tc.ModifyBombs(Amount, entity);\n\t\t\t\t\t\t\tTextParticle.Add(entity, \"HP\", Amount, true);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn;\t\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar component = entity.GetComponent<HealthComponent>();\n\n\t\t\t\tif (Set) {\n\t\t\t\t\tcomponent.MaxHealth = Amount;\n\t\t\t\t} else {\n\t\t\t\t\tcomponent.MaxHealth += Amount;\n\t\t\t\t}\n\n\t\t\t\tif (GiveHp && Amount > 0) {\n\t\t\t\t\tcomponent.ModifyHealth(Amount, entity);\n\t\t\t\t\tTextParticle.Add(entity, \"HP\", Amount, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tTextParticle.Add(entity, Locale.Get(\"max_hp\"), Math.Abs(Amount), true, Amount < 0);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tGiveHp = settings[\"give_hp\"].Bool(true);\n\t\t\tSet = settings[\"set\"].Bool(false);\n\t\t\tBomb = settings[\"bomb\"].Bool(false);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\n\t\t\t\troot[\"amount\"] = val;\n\t\t\t}\n\n\t\t\tvar giveHp = root[\"give_hp\"].Bool(true);\n\n\t\t\tif (ImGui.Checkbox(\"Give health\", ref giveHp)) {\n\t\t\t\troot[\"give_hp\"] = giveHp;\n\t\t\t}\n\n\t\t\troot.Checkbox(\"Set\", \"set\", false);\n\t\t\troot.Checkbox(\"Bomb\", \"bomb\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyProjectileTextureUse.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyProjectileTextureUse : ItemUse {\n\t\tprivate string texture;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (entity is Player p) {\n\t\t\t\tp.ProjectileTexture = texture;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\ttexture = settings[\"texture\"].String(\"rect\");\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputText(\"Texture\", \"texture\", \"rect\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyProjectilesUse.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyProjectilesUse : ItemUse {\n\t\tpublic bool SetScale;\n\t\tpublic float Scale;\n\t\tpublic bool SetDamage;\n\t\tpublic float Damage;\n\t\tpublic bool SetRange;\n\t\tpublic float Range;\n\t\t\n\t\tpublic float Chance;\n\t\tpublic bool ToAny;\n\t\tpublic bool EventCreated = true;\n\t\tpublic string BuffToApply;\n\t\tpublic bool InfiniteBuff;\n\t\tpublic float BuffDuration;\n\t\tpublic bool Explosive;\n\t\tpublic bool RandomEffect;\n\t\tpublic float EffectChangeSpeed;\n\n\t\tprivate float lastEffectTime;\n\t\tprivate int lastEffect = -1;\n\n\t\tprivate static string[] effects = {\n\t\t\tBurningBuff.Id, FrozenBuff.Id, PoisonBuff.Id, CharmedBuff.Id, SlowBuff.Id, BrokenArmorBuff.Id\n\t\t};\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ProjectileCreatedEvent pce) {\n\t\t\t\tif (ToAny || (EventCreated && Item == pce.Item)) {\n\t\t\t\t\tModifyProjectile(pce.Projectile);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic void ModifyProjectile(Projectile projectile) {\n\t\t\tif (Rnd.Float() > Chance + Run.Luck * 0.2f) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// This might turn out to be a disaster\n\t\t\tif (SetRange) {\n\t\t\t\tprojectile.T = Range;\n\t\t\t} else {\n\t\t\t\tprojectile.T *= Range;\n\t\t\t}\n\t\t\t\n\t\t\tif (SetDamage) {\n\t\t\t\tprojectile.Damage = Damage;\n\t\t\t} else {\n\t\t\t\tprojectile.Damage *= Damage;\n\t\t\t}\n\n\t\t\tif (SetScale) {\n\t\t\t\tprojectile.Scale = Scale;\n\t\t\t} else {\n\t\t\t\tprojectile.Scale *= Scale;\n\t\t\t}\n\n\t\t\tif (RandomEffect) {\n\t\t\t\tif (lastEffect == -1 || (EffectChangeSpeed > 0 && Engine.Time - lastEffectTime >= EffectChangeSpeed)) {\n\t\t\t\t\tlastEffect = Rnd.Int(effects.Length + 1);\n\t\t\t\t\tlastEffectTime = Engine.Time;\n\t\t\t\t}\n\n\t\t\t\tvar e = lastEffect == effects.Length;\n\t\t\t\tApplyBuff(projectile, e ? null : effects[lastEffect], e);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (BuffToApply != null || Explosive) {\n\t\t\t\tApplyBuff(projectile, BuffToApply, Explosive);\n\t\t\t}\n\t\t}\n\n\t\tprivate void ApplyBuff(Projectile projectile, string buff, bool explosive) {\n\t\t\tif (explosive) {\n\t\t\t\tprojectile.Color = ProjectileColor.Brown;\n\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => {\n\t\t\t\t\tExplosionMaker.Make(p, 32, false, damage: 4, scale: 0.5f);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (buff != null) {\n\t\t\t\tif (!BuffRegistry.All.TryGetValue(buff, out var info)) {\n\t\t\t\t\tLog.Error($\"Unknown buff {buff}\");\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprojectile.Color = info.Effect.GetColor();\n\n\t\t\t\tProjectileCallbacks.AttachHurtCallback(projectile, (p, e) => {\n\t\t\t\t\tif (e.TryGetComponent<BuffsComponent>(out var buffs) && !e.GetComponent<HealthComponent>().Unhittable) {\n\t\t\t\t\t\tvar b = BuffRegistry.Create(buff);\n\n\t\t\t\t\t\tif (InfiniteBuff) {\n\t\t\t\t\t\t\tb.Infinite = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tb.TimeLeft = b.Duration = BuffDuration;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbuffs.Add(b);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\t\t\t\n\t\t\t\n\t\t\tChance = settings[\"chance\"].Number(1);\n\t\t\tScale = settings[\"amount\"].Number(1);\n\t\t\tDamage = settings[\"damage\"].Number(1);\n\t\t\tRange = settings[\"range\"].Number(1);\n\t\t\tSetScale = settings[\"samount\"].Bool(false);\n\t\t\tSetDamage = settings[\"sdamage\"].Bool(false);\n\t\t\tSetRange = settings[\"srange\"].Bool(false);\n\t\t\tToAny = settings[\"any\"].Bool(false);\n\t\t\tExplosive = settings[\"explosive\"].Bool(false);\n\t\t\t\n\t\t\tBuffToApply = settings[\"buff\"].String(null);\n\n\t\t\tif (BuffToApply != null) {\n\t\t\t\tInfiniteBuff = settings[\"infinite_buff\"].Bool(false);\n\t\t\t\tBuffDuration = settings[\"buff_time\"].Number(10);\n\t\t\t} else {\n\t\t\t\tBuffDuration = 10;\n\t\t\t}\n\n\t\t\tRandomEffect = settings[\"rne\"].Bool(false);\n\n\t\t\tif (RandomEffect) {\n\t\t\t\tEffectChangeSpeed = settings[\"ecs\"].Number(3f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"From Any Source\", \"any\", false);\n\t\t\t\n\t\t\troot.InputFloat(\"Chance\", \"chance\");\n\n\t\t\troot.Checkbox(\"Set Scale\", \"samount\");\n\t\t\troot.InputFloat(\"Scale Modifier\", \"amount\");\n\t\t\troot.Checkbox(\"Set Damage\", \"sdamage\");\n\t\t\troot.InputFloat(\"Damage Modifier\", \"damage\");\n\t\t\troot.Checkbox(\"Set Range\", \"srange\");\n\t\t\troot.InputFloat(\"Range Modifier\", \"range\");\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tif (root.Checkbox(\"Random Effect\", \"rne\", false)) {\n\t\t\t\troot.InputFloat(\"Effect Change Speed\", \"ecs\", 3f);\n\t\t\t} else {\n\t\t\t\troot.Checkbox(\"Make Explosive\", \"explosive\", false);\n\n\t\t\t\tif (ImGui.TreeNode(\"Buff\")) {\n\t\t\t\t\tif (!BuffRegistry.All.ContainsKey(root.InputText(\"Buff\", \"buff\", \"bk:frozen\"))) {\n\t\t\t\t\t\tImGui.BulletText(\"Unknown buff!\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!root.Checkbox(\"Infinite\", \"infinite_buff\", false)) {\n\t\t\t\t\t\troot.InputFloat(\"Buff Duration\", \"buff_time\");\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyShieldHeartsUse.cs",
    "content": "﻿using BurningKnight.entity.creature.player;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyShieldHeartsUse : ItemUse {\n\t\tpublic int Amount;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.GetComponent<HeartsComponent>().ModifyShields(Amount * 2, entity);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyShootUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyShootUse : ItemUse {\n\t\tprivate int amount;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is PlayerShootEvent pse) {\n\t\t\t\tpse.Times += amount;\n\t\t\t\tpse.Accurate = true;\n\t\t\t}\n\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tamount = settings[\"amount\"].Int(1);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Amount\", \"amount\", 1);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyStatUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyStatUse : ItemUse {\n\t\tprivate Stat stat;\n\t\tprivate float value;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tswitch (stat) {\n\t\t\t\tcase Stat.InvincibilityTime: {\n\t\t\t\t\tentity.GetComponent<HealthComponent>().InvincibilityTimerMax += value;\n\t\t\t\t\tTextParticle.Add(entity, Locale.Get(\"invincibility_time\"));\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tstat = (Stat) settings[\"stat\"].Int(0);\n\t\t\tvalue = settings[\"val\"].Number(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar stat = root[\"stat\"].Int(0);\n\n\t\t\tif (ImGui.Combo(\"Stat\", ref stat, stats, stats.Length)) {\n\t\t\t\troot[\"stat\"] = stat;\n\t\t\t}\n\t\t\t\n\t\t\tvar value = root[\"val\"].Number(1);\n\n\t\t\tif (ImGui.InputFloat(\"Amount\", ref value)) {\n\t\t\t\troot[\"val\"] = value;\n\t\t\t}\n\t\t}\n\n\t\tprivate enum Stat {\n\t\t\tInvincibilityTime,\n\t\t\t\n\t\t\tTotal\n\t\t}\n\n\t\tprivate static string[] stats;\n\n\t\tstatic ModifyStatUse() {\n\t\t\tstats = new string[(int) Stat.Total];\n\n\t\t\tfor (var i = 0; i < (int) Stat.Total; i++) {\n\t\t\t\tstats[i] = $\"{(Stat) i}\";\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ModifyStatsUse.cs",
    "content": "using System;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ModifyStatsUse : ItemUse {\n\t\tpublic float Speed;\n\t\tpublic bool AddSpeed;\n\t\t\n\t\tpublic float Damage;\n\t\tpublic bool AddDamage;\n\t\t\n\t\tpublic float FireRate;\n\t\tpublic bool AddFireRate;\n\t\t\n\t\tpublic float RangedRate;\n\t\tpublic bool AddRangedRate;\n\t\t\n\t\tpublic float Accuracy;\n\t\tpublic bool AddAccuracy;\n\t\t\n\t\tpublic float Range;\n\t\tpublic bool AddRange;\n\t\t\n\t\tpublic float Knockback;\n\t\tpublic bool AddKnockback;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tvar stats = entity.GetComponent<StatsComponent>();\n\n\t\t\tif (Math.Abs(Math.Abs(Speed) - (AddSpeed ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"speed\"), Math.Abs(Speed), true, Speed < 0);\n\t\t\t\t\n\t\t\t\tif (AddSpeed) {\n\t\t\t\t\tstats.Speed += Speed;\n\t\t\t\t} else {\n\t\t\t\t\tstats.Speed *= Speed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.Abs(Math.Abs(Damage) - (AddDamage ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"damage\"), Math.Abs(Damage), true, Damage < 0);\n\n\t\t\t\tif (AddDamage) {\n\t\t\t\t\tstats.Damage += Damage;\n\t\t\t\t} else {\n\t\t\t\t\tstats.Damage *= Damage;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.Abs(Math.Abs(FireRate) - (AddFireRate ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"fire_rate\"), Math.Abs(FireRate), true, FireRate < 0);\n\t\t\t\t\n\t\t\t\tif (AddFireRate) {\n\t\t\t\t\tstats.FireRate += FireRate;\n\t\t\t\t} else {\n\t\t\t\t\tstats.FireRate *= FireRate;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.Abs(Math.Abs(RangedRate) - (AddRangedRate ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"fire_rate\"), Math.Abs(RangedRate), true, RangedRate < 0);\n\t\t\t\t\n\t\t\t\tif (AddRangedRate) {\n\t\t\t\t\tstats.RangedRate += RangedRate;\n\t\t\t\t} else {\n\t\t\t\t\tstats.RangedRate *= RangedRate;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.Abs(Math.Abs(Accuracy) - (AddAccuracy ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"accuracy\"), Math.Abs(Accuracy), true, Accuracy < 0);\n\n\t\t\t\tif (AddAccuracy) {\n\t\t\t\t\tstats.Accuracy += Accuracy;\n\t\t\t\t} else {\n\t\t\t\t\tstats.Accuracy *= Accuracy;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Math.Abs(Math.Abs(Range) - (AddRange ? 0 : 1)) >= 0.01f) {\n\t\t\t\tTextParticle.Add(entity, Locale.Get(\"range\"), Math.Abs(Range), true, Range < 0);\n\n\t\t\t\tif (AddRange) {\n\t\t\t\t\tstats.Range += Range;\n\t\t\t\t} else {\n\t\t\t\t\tstats.Range *= Range;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tSpeed = settings[\"speed\"].Number(0);\n\t\t\tAddSpeed = settings[\"add_speed\"].Bool(true);\n\n\t\t\tDamage = settings[\"damage\"].Number(0);\n\t\t\tAddDamage = settings[\"add_damage\"].Bool(true);\n\n\t\t\tFireRate = settings[\"fire_rate\"].Number(0);\n\t\t\tAddFireRate = settings[\"add_fire_rate\"].Bool(true);\n\t\t\t\n\t\t\tRangedRate = settings[\"ranged_rate\"].Number(0);\n\t\t\tAddRangedRate = settings[\"add_ranged_rate\"].Bool(true);\n\n\t\t\tAccuracy = settings[\"accuracy\"].Number(0);\n\t\t\tAddAccuracy = settings[\"add_accuracy\"].Bool(true);\n\n\t\t\tRange = settings[\"range\"].Number(0);\n\t\t\tAddRange = settings[\"add_range\"].Bool(true);\n\n\t\t\tKnockback = settings[\"knockback\"].Number(0);\n\t\t\tAddKnockback = settings[\"add_knockback\"].Bool(true);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Speed\", \"speed\", 0);\n\t\t\troot.Checkbox(\"Add Speed\", \"add_speed\");\n\t\t\t\n\t\t\troot.InputFloat(\"Damage\", \"damage\", 0);\n\t\t\troot.Checkbox(\"Add Damage\", \"add_damage\");\n\t\t\t\n\t\t\troot.InputFloat(\"Fire Rate\", \"fire_rate\", 0);\n\t\t\troot.Checkbox(\"Add Fire Rate\", \"add_fire_rate\");\n\t\t\t\n\t\t\troot.InputFloat(\"Ranged Rate\", \"ranged_rate\", 0);\n\t\t\troot.Checkbox(\"Add Ranged Rate\", \"add_ranged_rate\");\n\t\t\t\n\t\t\troot.InputFloat(\"Accuracy\", \"accuracy\", 0);\n\t\t\troot.Checkbox(\"Add Accuracy\", \"add_accuracy\");\n\t\t\t\n\t\t\troot.InputFloat(\"Range\", \"range\", 0);\n\t\t\troot.Checkbox(\"Add Range\", \"add_range\");\n\t\t\t\n\t\t\troot.InputFloat(\"Knockback\", \"knockback\", 0);\n\t\t\troot.Checkbox(\"Add Knockback\", \"add_knockback\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/PlaceDecoyUse.cs",
    "content": "using BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class PlaceDecoyUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar decoy = new Decoy();\n\t\t\tentity.Area.Add(decoy);\n\t\t\tdecoy.BottomCenter = entity.BottomCenter;\n\n\t\t\tentity.GetComponent<BuffsComponent>().Add(new InvisibleBuff {\n\t\t\t\tInfinite = true\n\t\t\t});\n\t\t\t\n\t\t\tdecoy.OnDeath += () => {\n\t\t\t\tentity.GetComponent<BuffsComponent>().Remove<InvisibleBuff>();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/PokemonUse.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class PokemonUse : ItemUse {\n\t\tprivate Type type;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (type == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tvar m = (Mob) Activator.CreateInstance(type);\n\t\t\t\tentity.Area.Add(m);\n\n\t\t\t\tm.GetComponent<BuffsComponent>().Add(new CharmedBuff {\n\t\t\t\t\tInfinite = true\n\t\t\t\t});\n\n\t\t\t\tvar h = m.GetComponent<HealthComponent>();\n\t\t\t\th.InitMaxHealth = (int) (h.Health * 3);\n\t\t\t\t\n\t\t\t\tm.Center = entity.Center;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is KilledEvent k && k.KilledBy == Item.Owner && k.Who is Mob m && !(m is WallWalker || m is Boss)) {\n\t\t\t\ttype = k.Who.GetType();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/PoofUse.cs",
    "content": "using BurningKnight.assets.particle;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class PoofUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar where = entity.Center;\n\t\t\t\n\t\t\tfor (var i = 0; i < 20; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\tpart.Position = where + Rnd.Vector(-16, 16);\n\t\t\t\tpart.Particle.Scale = Rnd.Float(1, 2f);\n\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/PreventDamageUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.level;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class PreventDamageUse : ItemUse {\n\t\tprivate bool spikes;\n\t\tprivate bool lava;\n\t\tprivate bool chasm;\n\t\tprivate bool bombs;\n\t\tprivate bool contact;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent ev) {\n\t\t\t\tif ((spikes && ev.From is Spikes)\n\t\t\t\t    || (lava && ev.From is Level)\n\t\t\t\t    || (chasm && ev.From is Chasm)\n\t\t\t\t    || (bombs && ev.Type == DamageType.Explosive)\n\t\t\t\t    || (contact && ev.Type == DamageType.Contact)) {\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tlava = settings[\"lv\"].Bool(false);\n\t\t\tspikes = settings[\"sp\"].Bool(false);\n\t\t\tchasm = settings[\"cs\"].Bool(false);\n\t\t\tbombs = settings[\"bms\"].Bool(false);\n\t\t\tcontact = settings[\"cnt\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar v = root[\"lv\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"From lava\", ref v)) {\n\t\t\t\troot[\"lv\"] = v;\n\t\t\t}\n\t\t\t\n\t\t\tv = root[\"sp\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"From spikes\", ref v)) {\n\t\t\t\troot[\"sp\"] = v;\n\t\t\t}\n\t\t\t\n\t\t\tv = root[\"cs\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"From chasm\", ref v)) {\n\t\t\t\troot[\"cs\"] = v;\n\t\t\t}\n\t\t\t\n\t\t\tv = root[\"bms\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"From explosions\", ref v)) {\n\t\t\t\troot[\"bms\"] = v;\n\t\t\t}\n\n\t\t\troot.Checkbox(\"From Contact\", \"cnt\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RandomActiveUse.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class RandomActiveUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar id = Items.Generate(ItemType.Active);\n\n\t\t\tif (id == null) {\n\t\t\t\tLog.Error(\"Failed to chose an active item\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLog.Info($\"Using active item {id} with d8\");\n\n\t\t\tvar it = Items.Create(id);\n\t\t\titem.GetComponent<ItemGraphicsComponent>().Sprite = CommonAse.Items.GetSlice(id);\n\n\t\t\tforeach (var u in it.Uses) {\n\t\t\t\tu.Item = it;\n\t\t\t\tu.Use(entity, it);\n\t\t\t}\n\t\t\t\n\t\t\tTimer.Add(() => {\n\t\t\t\titem.GetComponent<ItemGraphicsComponent>().Sprite = CommonAse.Items.GetSlice(item.Id);\n\t\t\t}, 2);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RandomUse.cs",
    "content": "﻿using BurningKnight.entity.item.use.parent;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class RandomUse : DoUsesUse {\n\t\tprotected override void DoAction(Entity entity, Item item, ItemUse use) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tUses[Rnd.Int(Uses.Length)].Use(entity, item);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RegenUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class RegenUse : ItemUse {\n\t\tprivate int speed;\n\t\tprivate int count;\n\t\tprivate bool onKills;\n\t\tprivate bool onChests;\n\t\tprivate bool onPurchase;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\tentity.Subscribe<Chest.OpenedEvent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is KilledEvent) {\n\t\t\t\tif (onKills) {\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (count >= speed) {\n\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\tItem.Owner.GetComponent<HealthComponent>().ModifyHealth(1, Item);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is Chest.OpenedEvent) {\n\t\t\t\tif (onChests) {\n\t\t\t\t\tItem.Owner.GetComponent<HealthComponent>().ModifyHealth(1, Item);\n\t\t\t\t}\n\t\t\t} else if (e is ItemBoughtEvent) {\n\t\t\t\tif (onPurchase) {\n\t\t\t\t\tItem.Owner.GetComponent<HealthComponent>().ModifyHealth(1, Item);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tspeed = settings[\"speed\"].Int(10);\n\t\t\tonKills = settings[\"kills\"].Bool(true);\n\t\t\tonChests = settings[\"chests\"].Bool(false);\n\t\t\tonPurchase = settings[\"purchase\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tif (root.Checkbox(\"On Kills\", \"kills\", true)) {\n\t\t\t\troot.InputInt(\"Speed\", \"speed\", 10);\n\t\t\t}\n\n\t\t\troot.Checkbox(\"On Chests\", \"chests\", false);\n\t\t\troot.Checkbox(\"On Purchase\", \"purchase\", false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ReplaceHeartsWithShieldsUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ReplaceHeartsWithShieldsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tvar h = entity.GetComponent<HealthComponent>();\n\t\t\tvar amount = h.MaxHealth;\n\n\t\t\tif (amount == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tentity.GetComponent<HeartsComponent>().ModifyShields(amount, item);\n\t\t\th.InitMaxHealth = 0;\n\t\t\t\n\t\t\tTextParticle.Add(entity, Locale.Get(\"max_hp\"), amount, true, true);\n\t\t\tTextParticle.Add(entity, Locale.Get(\"shields\"), amount, true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RerollAndHideUse.cs",
    "content": "namespace BurningKnight.entity.item.use {\n\tpublic class RerollAndHideUse : RerollItemsUse {\n\t\tprotected override void ProcessItem(Item item) {\n\t\t\tbase.ProcessItem(item);\n\t\t\titem.Unknown = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RerollItemsOnPlayerUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class RerollItemsOnPlayerUse : ItemUse {\n\t\tprivate bool rerollWeapons;\n\t\tprivate bool rerollArtifacts;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (rerollArtifacts) {\n\t\t\t\tReroll(entity, entity.GetComponent<InventoryComponent>());\n\t\t\t}\n\n\t\t\tif (rerollWeapons) {\n\t\t\t\tReroll(entity.GetComponent<ActiveWeaponComponent>());\n\t\t\t\tReroll(entity.GetComponent<WeaponComponent>());\n\t\t\t}\n\n\t\t\tentity.HandleEvent(new RerolledEvent {\n\t\t\t\tEntity = entity\n\t\t\t});\n\t\t}\n\n\t\tprivate void Reroll(ItemComponent component) {\n\t\t\tif (component?.Item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar item = component.Item;\n\t\t\tReroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type);\n\t\t}\n\n\t\tprivate void Reroll(Entity entity, InventoryComponent component) {\n\t\t\tif (entity is Player player) {\n\t\t\t\tplayer.InitStats();\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var item in component.Items) {\n\t\t\t\tReroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type);\n\t\t\t\titem.Use(entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\trerollWeapons = settings[\"weapons\"].Bool(false);\n\t\t\trerollArtifacts = settings[\"artifacts\"].Bool(true);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar rerollWeapons = root[\"weapons\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Reroll weapons?\", ref rerollWeapons)) {\n\t\t\t\troot[\"weapons\"] = rerollWeapons;\n\t\t\t}\n\t\t\t\n\t\t\tvar rerollArtifacts = root[\"artifacts\"].Bool(true);\n\t\t\t\n\t\t\tif (ImGui.Checkbox(\"Reroll artifacts?\", ref rerollArtifacts)) {\n\t\t\t\troot[\"artifacts\"] = rerollArtifacts;\n\t\t\t}\n\t\t}\n\n\t\tpublic class RerolledEvent : Event {\n\t\t\tpublic Entity Entity;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RerollItemsUse.cs",
    "content": "using BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class RerollItemsUse : ItemUse {\r\n\t\tprivate bool rerollStands;\r\n\t\tprivate bool spawnNewItems;\r\n\t\tprivate bool ignore;\r\n\t\tprivate ItemType[] types;\r\n\t\tprivate float consumeChance;\r\n\t\tprivate bool d2;\r\n\t\t\r\n\t\tpublic override void Use(Entity entity, Item self) {\r\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (room == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tReroller.Reroll(entity.Area, room, rerollStands, spawnNewItems, ignore, types, ProcessItem, d2);\r\n\t\t}\r\n\r\n\t\tprotected virtual void ProcessItem(Item item) {\r\n\t\t\tif (consumeChance > 0 && Rnd.Chance(consumeChance * 100)) {\r\n\t\t\t\titem.Done = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\trerollStands = settings[\"r_stands\"].Bool(true);\r\n\t\t\tspawnNewItems = settings[\"s_new\"].Bool(true);\r\n\t\t\tignore = settings[\"ignore\"].Bool(true);\r\n\t\t\tconsumeChance = settings[\"cc\"].Number(0);\r\n\t\t\td2 = settings[\"d2\"].Bool(false);\r\n\r\n\t\t\tvar tps = settings[\"types\"];\r\n\r\n\t\t\tif (tps.IsJsonArray) {\r\n\t\t\t\tvar tp = tps.AsJsonArray;\r\n\r\n\t\t\t\tif (tp.Count == 0) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\ttypes = new ItemType[tp.Count];\r\n\r\n\t\t\t\tfor (var i = 0; i < tp.Count; i++) {\r\n\t\t\t\t\ttypes[i] = (ItemType) tp[i].Int(0);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar rerollStands = root[\"r_stands\"].Bool(true);\r\n\t\t\tvar spawnNew = root[\"s_new\"].Bool(true);\r\n\t\t\tvar ignore = root[\"ignore\"].Bool(true);\r\n\r\n\t\t\troot.InputFloat(\"Consume Chance\", \"cc\", 0);\r\n\t\t\troot.Checkbox(\"D2\", \"d2\", false);\r\n\t\t\t\r\n\t\t\tif (ImGui.Checkbox(\"Reroll stands\", ref rerollStands)) {\r\n\t\t\t\troot[\"r_stands\"] = rerollStands;\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Spawn new\", ref spawnNew)) {\r\n\t\t\t\troot[\"s_new\"] = spawnNew;\r\n\t\t\t}\r\n\r\n\t\t\tvar tps = root[\"types\"];\r\n\r\n\t\t\tif (!tps.IsJsonArray) {\r\n\t\t\t\ttps = root[\"types\"] = new JsonArray();\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.TreeNode(\"Item types\")) {\r\n\t\t\t\tif (ImGui.Checkbox(\"Ignore those types\", ref ignore)) {\r\n\t\t\t\t\troot[\"ignore\"] = ignore;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.Separator();\r\n\t\t\t\t\r\n\t\t\t\tvar tp = tps.AsJsonArray;\r\n\t\t\t\tvar toRemove = -1;\r\n\t\t\t\tvar toAdd = -1;\r\n\r\n\t\t\t\tfor (var i = 0; i < ItemEditor.Types.Length; i++) {\r\n\t\t\t\t\tvar v = tp.Contains(i);\r\n\r\n\t\t\t\t\tif (ImGui.Checkbox(ItemEditor.Types[i], ref v)) {\r\n\t\t\t\t\t\tif (v) {\r\n\t\t\t\t\t\t\ttoAdd = i;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\ttoRemove = tp.IndexOf(i);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (toRemove != -1) {\r\n\t\t\t\t\ttp.Remove(toRemove);\r\n\t\t\t\t} else if (toAdd != -1) {\r\n\t\t\t\t\ttp.Add(toAdd);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.TreePop();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/RevealMapUse.cs",
    "content": "using BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class RevealMapUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\t\n\t\t\tvar level = Run.Level;\n\t\t\tAudio.PlaySfx(\"item_map\");\n\t\t\t\n\t\t\tforeach (var e in entity.Area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) e;\n\t\t\t\t\n\t\t\t\tif (room.Type == RoomType.DarkMarket || room.Type == RoomType.Hidden) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (Rnd.Chance(95) && room.Type != RoomType.Secret && room.Type != RoomType.Granny && room.Type != RoomType.OldMan) {\n\t\t\t\t\tfor (var y = room.MapY; y < room.MapY + room.MapH; y++) {\n\t\t\t\t\t\tfor (var x = room.MapX; x < room.MapX + room.MapW; x++) {\n\t\t\t\t\t\t\tlevel.Explored[level.ToIndex(x, y)] = true;\n\t\t\t\t\t\t}\t\n\t\t\t\t\t}\n\n\t\t\t\t\troom.Explored = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SaleItemsUse.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class SaleItemsUse : ItemUse {\r\n\t\tprivate float percent;\r\n\t\tprivate bool onlyOnceUsed;\r\n\t\tprivate bool used;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tused = true;\r\n\t\t\t\r\n\t\t\tforeach (var i in entity.GetComponent<RoomComponent>().Room.Tagged[Tags.Item]) {\r\n\t\t\t\tif (i is ShopStand s) {\r\n\t\t\t\t\ts.Recalculate();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tused = false;\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is ItemPriceCalculationEvent ipce) {\r\n\t\t\t\tif (!onlyOnceUsed || used) {\r\n\t\t\t\t\tipce.Percent += percent;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\tpercent = settings[\"prc\"].Number(50f);\r\n\t\t\tonlyOnceUsed = settings[\"wu\"].Bool(false);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar v = root[\"prc\"].Number(50f);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"% sale\", ref v)) {\r\n\t\t\t\troot[\"prc\"] = v;\r\n\t\t\t}\r\n\r\n\t\t\troot.Checkbox(\"Only when used\", \"wu\", false);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ScourgeUse.cs",
    "content": "using BurningKnight.assets.particle.custom;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ScourgeUse : ItemUse {\n\t\tprivate int amount;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\tRun.AddScourge();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tamount = settings[\"amount\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputInt(\"Amount\", \"amount\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SetKnockbackModifierUse.cs",
    "content": "using BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SetKnockbackModifierUse : ItemUse {\n\t\tprivate float mod;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.GetAnyComponent<BodyComponent>().KnockbackModifier = mod;\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tmod = settings[\"mod\"].Number(0);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"mod\"].Number(0);\n\n\t\t\tif (ImGui.InputFloat(\"Modifier\", ref val)) {\n\t\t\t\troot[\"mod\"] = val;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SetMaxHpUse.cs",
    "content": "using BurningKnight.entity.component;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class SetMaxHpUse : ItemUse {\r\n\t\tpublic int Amount;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar component = entity.GetComponent<HealthComponent>();\r\n\t\t\tcomponent.InitMaxHealth = Amount + 1; // 1 is hidden\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\tAmount = settings[\"amount\"].Int(1);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar val = root[\"amount\"].Int(1);\r\n\r\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\r\n\t\t\t\troot[\"amount\"] = val;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SetMusicSpeed.cs",
    "content": "using BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.tween;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SetMusicSpeed : ItemUse {\n\t\tprivate float speed;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tTween.To(speed, Audio.Speed, x => Audio.Speed = x, 0.4f);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tspeed = settings[\"speed\"].Number(1f);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputFloat(\"Speed\", \"speed\", 1f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ShootLaserUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ShootLaserUse : ShootUse {\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\tvar ac = 0.1f;\n\n\t\t\tSpawnProjectile = (entity, item) => {\n\t\t\t\tvar aim = entity.GetComponent<AimComponent>();\n\t\t\t\tvar from = aim.Center;\n\t\t\t\tvar am = aim.RealAim;\n\t\t\t\tvar a = MathUtils.Angle(am.X - from.X, am.Y - from.Y);\n\n\t\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomized(\"item_laser_player\");\n\t\t\t\t\n\t\t\t\tvar cnt = 1;\n\t\t\t\tvar accurate = false;\n\n\t\t\t\tif (entity is Player pl) {\n\t\t\t\t\tvar e = new PlayerShootEvent {\n\t\t\t\t\t\tPlayer = pl\n\t\t\t\t\t};\n\n\t\t\t\t\tentity.HandleEvent(e);\n\n\t\t\t\t\tcnt += e.Times - 1;\n\t\t\t\t\taccurate = e.Accurate;\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < cnt; i++) {\n\t\t\t\t\tvar addition = 0f;\n\t\t\t\t\t\n\t\t\t\t\tif (accurate) {\n\t\t\t\t\t\taddition = (i - (int) (cnt * 0.5f)) * 0.2f + Rnd.Float(-ac / 2f, ac / 2f);\n\t\t\t\t\t} else if (cnt == 1 || i > 0) {\n\t\t\t\t\t\taddition = Rnd.Float(-ac / 2f, ac / 2f);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar laser = Laser.Make(entity, a, addition, item, damage: (item.Scourged ? 1.5f : 1f));\n\n\t\t\t\t\tlaser.Position = from;\n\t\t\t\t\tlaser.PlayerRotated = true;\n\t\t\t\t\tlaser.Damage *= 1.2f;\n\t\t\t\t\tlaser.Recalculate();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ShootQueueUse.cs",
    "content": "using ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util.camera;\r\nusing Lens.util.timer;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class ShootQueueUse : SimpleShootUse {\r\n\t\tprivate int amount;\r\n\t\tprivate float delay;\r\n\t\t\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tif (wait && !ProjectileDied) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < amount; i++) {\r\n\t\t\t\tif (i == 0) {\r\n\t\t\t\t\tSpawnProjectile(entity, item);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tTimer.Add(() => SpawnProjectile(entity, item), i * delay);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tCamera.Instance.ShakeMax(1.5f);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\tamount = settings[\"amn\"].Int(3);\r\n\t\t\tdelay = settings[\"dl\"].Number(0.1f);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tSimpleShootUse.RenderDebug(root);\r\n\t\t\t\r\n\t\t\tvar amount = root[\"amn\"].Int(3);\r\n\r\n\t\t\tif (ImGui.InputInt(\"Projectile Count\", ref amount)) {\r\n\t\t\t\troot[\"amn\"] = amount;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar delay = root[\"dl\"].Number(0.1f);\r\n\t\t\t\r\n\t\t\tif (ImGui.InputFloat(\"Projectile Delay\", ref delay)) {\r\n\t\t\t\troot[\"dl\"] = delay;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/ShootUse.cs",
    "content": "﻿using System;\nusing Lens.entity;\nusing Lens.util.camera;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class ShootUse : ItemUse {\n\t\tpublic Action<Entity, Item> SpawnProjectile;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tSpawnProjectile(entity, item);\n\t\t\tCamera.Instance.ShakeMax(3);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SimpleShootUse.cs",
    "content": "﻿using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\nusing Num = System.Numerics;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SimpleShootUse : ShootUse {\n\t\tprivate static string[] manaDropNames = {\n\t\t\t\"Where it lands\",\n\t\t\t\"Where it starts\",\n\t\t\t\"Where it starts, after death\"\n\t\t};\n\t\t\n\t\tprivate float damage;\n\t\tprivate float speed;\n\t\tprivate float speedMax;\n\t\tprivate float range;\n\t\tprivate float scaleMin;\n\t\tprivate float scaleMax;\n\t\tprivate string slice;\n\t\tprivate float accuracy;\n\t\tprivate int count;\n\t\tprivate string prefab;\n\t\tprivate bool light;\n\t\tprivate float knockback;\n\t\tprivate bool rect;\n\t\tprivate string sfx;\n\t\tprivate int sfxNumber;\n\t\tprivate int manaUsage;\n\t\tprotected bool wait;\n\t\tprivate bool toCursor;\n\t\tprivate bool toEnemy;\n\t\tprivate string color;\n\t\tpublic bool ReloadSfx;\n\t\tprivate bool shells;\n\t\tprivate int manaDrop;\n\t\tprivate float angleAdd;\n\t\tprivate bool emeralds;\n\t\t\n\t\tpublic bool ProjectileDied = true;\n\t\tprivate ItemUse[] modifiers;\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\t#region Json parsing\n\t\t\tmodifiers = Items.ParseUses(settings[\"modifiers\"]);\n\n\t\t\tif (modifiers != null) {\n\t\t\t\tforeach (var m in modifiers) {\n\t\t\t\t\tm.Item = Item;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tdamage = settings[\"damage\"].Number(1);\n\t\t\tspeed = settings[\"speed\"].Number(6);\n\t\t\tspeedMax = settings[\"speedm\"].Number(10);\n\t\t\trange = settings[\"range\"].Number(0) * 0.5f;\n\t\t\tscaleMin = settings[\"scale\"].Number(1);\n\t\t\tscaleMax = settings[\"scalem\"].Number(1);\n\t\t\tslice = settings[\"texture\"].String(\"rect\");\n\t\t\ttoCursor = settings[\"cursor\"].Bool(false);\n\t\t\ttoEnemy = settings[\"tomb\"].Bool(false);\n\t\t\tsfx = settings[\"sfx\"].String(\"item_gun_fire\");\n\t\t\tsfxNumber = settings[\"sfxn\"].Int(0);\n\t\t\tReloadSfx = settings[\"rsfx\"].Bool(false);\n\t\t\tmanaUsage = settings[\"mana\"].Int(0);\n\t\t\tcolor = settings[\"color\"].String(\"\");\n\t\t\tangleAdd = settings[\"ang\"].Number(0);\n\n\t\t\tif (manaUsage > 0) {\n\t\t\t\tmanaDrop = settings[\"mdr\"].Int(0);\n\t\t\t}\n\n\t\t\tif (slice == \"default\") {\n\t\t\t\tslice = \"rect\";\n\t\t\t}\n\t\t\t\n\t\t\taccuracy = settings[\"accuracy\"].Number(0).ToRadians();\n\t\t\tcount = settings[\"amount\"].Int(1);\n\t\t\tprefab = settings[\"prefab\"].String(\"\");\n\t\t\tlight = settings[\"light\"].Bool(true);\n\t\t\tknockback = settings[\"knockback\"].Number(1);\n\t\t\trect = settings[\"rect\"].Bool(false);\n\t\t\twait = settings[\"wait\"].Bool(false);\n\t\t\tshells = settings[\"shells\"].Bool(true);\n\t\t\temeralds = settings[\"emeralds\"].Bool(false);\n\t\t\t#endregion\n\n\t\t\tSpawnProjectile = (entity, item) => {\n\t\t\t\tif (manaUsage > 0) {\n\t\t\t\t\tvar mana = entity.GetComponent<ManaComponent>();\n\n\t\t\t\t\tif (mana.Mana < manaUsage) {\n\t\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmana.ModifyMana(-manaUsage);\n\t\t\t\t}\n\n\t\t\t\tif (emeralds) {\n\t\t\t\t\tif (GlobalSave.Emeralds == 0) {\n\t\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\t\tTextParticle.Add(entity, Locale.Get(\"no_emeralds\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tGlobalSave.Emeralds--;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar bad = entity is Creature c && !c.IsFriendly();\n\t\t\t\tvar sl = slice;\n\t\t\t\t\n\t\t\t\tif (bad) {\n\t\t\t\t\tsl = \"small\";\n\t\t\t\t}\n\n\t\t\t\tif (sfx == \"item_gun_fire\") {\n\t\t\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(sfx, 2, 0.5f, sz: 0.2f);\n\t\t\t\t} else {\n\t\t\t\t\tif (sfxNumber == 0) {\n\t\t\t\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomized(sfx, 0.5f, sz: 0.25f);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(sfx, sfxNumber, 0.5f, sz: 0.25f);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar aim = entity.GetComponent<AimComponent>();\n\t\t\t\tvar from = toCursor ? entity.Center : aim.Center;\n\t\t\t\tvar am = toCursor ? entity.GetComponent<CursorComponent>().Cursor.GamePosition : aim.RealAim;\n\n\t\t\t\tif (toEnemy) {\n\t\t\t\t\tvar target = entity.Area.FindClosest(from, Tags.MustBeKilled, e => true);\n\n\t\t\t\t\tif (target != null) {\n\t\t\t\t\t\tam = target.Center;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar a = MathUtils.Angle(am.X - from.X, am.Y - from.Y);\n\t\t\t\tvar pr = prefab.Length == 0 ? null : ProjectileRegistry.Get(prefab);\n\t\t\t\tvar ac = accuracy;\n\n\t\t\t\tentity.TryGetComponent<StatsComponent>(out var stats);\n\n\t\t\t\tif (stats != null) {\n\t\t\t\t\tac /= stats.Accuracy;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar cnt = count;\n\t\t\t\tvar accurate = false;\n\n\t\t\t\tif (entity is Player pl) {\n\t\t\t\t\tvar e = new PlayerShootEvent {\n\t\t\t\t\t\tPlayer = (Player) entity\n\t\t\t\t\t};\n\n\t\t\t\t\tentity.HandleEvent(e);\n\n\t\t\t\t\tcnt += e.Times - 1;\n\t\t\t\t\taccurate = e.Accurate;\n\n\t\t\t\t\tif (sl == \"rect\") {\n\t\t\t\t\t\tsl = pl.ProjectileTexture;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < cnt; i++) {\n\t\t\t\t\tvar angle = a;\n\t\t\t\t\t\n\t\t\t\t\tif (accurate) {\n\t\t\t\t\t\tangle += (i - (int) (cnt * 0.5f)) * 0.2f + Rnd.Float(-ac / 2f, ac / 2f);\n\t\t\t\t\t} else if (cnt == 1 || i > 0) {\n\t\t\t\t\t\tangle += Rnd.Float(-ac / 2f, ac / 2f);\n\t\t\t\t\t}\n\n\t\t\t\t\tangle += angleAdd * (float) Math.PI * 2;\n\n\t\t\t\t\tvar antiAngle = angle - (float) Math.PI;\n\t\t\t\t\tvar builder = new ProjectileBuilder(Item, sl);\n\n\t\t\t\t\tbuilder.Shoot(angle, Rnd.Float(speed, speedMax));\n\t\t\t\t\tbuilder.Scale = Rnd.Float(scaleMin, scaleMax);\n\t\t\t\t\tbuilder.Damage = damage * (item.Scourged ? 1.5f : 1f);\n\t\t\t\t\tbuilder.RectHitbox = rect;\n\t\t\t\t\tbuilder.Range = range;\n\n\t\t\t\t\tif (Item.Owner is ShopKeeper) {\n\t\t\t\t\t\tbuilder.Range *= 3;\n\t\t\t\t\t}\n\n\t\t\t\t\tCamera.Instance.Push(antiAngle, 4f);\n\t\t\t\t\tentity.GetComponent<RectBodyComponent>()?.KnockbackFrom(antiAngle, 0.4f * knockback);\n\n\t\t\t\t\tif (!string.IsNullOrEmpty(color) && ProjectileColor.Colors.TryGetValue(color, out var clr)) {\n\t\t\t\t\t\tbuilder.Color = clr;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (light) {\n\t\t\t\t\t\tbuilder.LightRadius = Rnd.Float(24f, 48f);\n\t\t\t\t\t}\n\n\t\t\t\t\t// R.I.P flash frame 2018-2021\n\t\t\t\t\t// projectile.FlashTimer = 0.05f;\n\n\t\t\t\t\tvar projectile = builder.Build();\n\t\t\t\t\tprojectile.Center = from;\n\n\t\t\t\t\tif (modifiers != null) {\n\t\t\t\t\t\tforeach (var m in modifiers) {\n\t\t\t\t\t\t\tif (m is ModifyProjectilesUse mpu) {\n\t\t\t\t\t\t\t\tmpu.ModifyProjectile(projectile);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tpr?.Invoke(projectile);\n\n\t\t\t\t\tif (wait && i == 0) {\n\t\t\t\t\t\tProjectileDied = false;\n\n\t\t\t\t\t\tif (prefab == \"bk:axe\") {\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => {\n\t\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(prj, (prj2, e2, t2) => ProjectileDied = true);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => ProjectileDied = true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (manaUsage > 0) {\n\t\t\t\t\t\tif (manaDrop == 0) {\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => {\n\t\t\t\t\t\t\t\tPlaceMana(entity.Area, prj.Center);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else if (manaDrop == 1) {\n\t\t\t\t\t\t\tPlaceMana(entity.Area, entity.Center);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar where = entity.Center;\n\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => {\n\t\t\t\t\t\t\t\tPlaceMana(entity.Area, where);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shells) {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar p = new ShellParticle(new Particle(Controllers.Destroy, new TexturedParticleRenderer {\n\t\t\t\t\t\t\tRegion = CommonAse.Particles.GetSlice(\"shell\")\n\t\t\t\t\t\t}));\n\n\t\t\t\t\t\tp.Position = entity.Center;\n\t\t\t\t\t\tp.Y += Rnd.Float(-4, 10);\n\n\t\t\t\t\t\tentity.Area.Add(p);\n\n\t\t\t\t\t\tvar f = (entity.CenterX > entity.GetComponent<CursorComponent>().Cursor.GamePosition.X ? 1 : -1);\n\n\t\t\t\t\t\tp.Particle.Velocity =\n\t\t\t\t\t\t\tnew Vector2(f * Rnd.Float(40, 60), 0) + entity.GetAnyComponent<BodyComponent>().Velocity;\n\n\t\t\t\t\t\tp.Particle.Angle = 0;\n\t\t\t\t\t\tp.Particle.Zv = Rnd.Float(1.5f, 2.5f);\n\t\t\t\t\t\tp.Particle.AngleVelocity = f * Rnd.Float(40, 70);\n\n\t\t\t\t\t\tp.AddShadow();\n\t\t\t\t\t}, 0.2f);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprivate class ShellParticle : ParticleEntity {\n\t\t\tprivate bool played;\n\t\t\t\n\t\t\tpublic ShellParticle(Particle particle) : base(particle) {\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (!played && Particle.Z <= 0) {\n\t\t\t\t\tplayed = true;\n\t\t\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"projectile_shell\", 3);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tif (root.InputInt(\"Mana Usage\", \"mana\", 0) > 0) {\n\t\t\t\tvar b = root[\"mdr\"].Int(0);\n\n\t\t\t\tif (ImGui.Combo(\"Place Mana\", ref b, manaDropNames, manaDropNames.Length)) {\n\t\t\t\t\troot[\"mdr\"] = b;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ImGui.TreeNode(\"Stats\")) {\n\t\t\t\troot.Checkbox(\"To Cursor\", \"cursor\", false);\n\t\t\t\troot.Checkbox(\"To Cloest Target\", \"tomb\", false);\n\t\t\t\troot.InputFloat(\"Damage\", \"damage\");\n\t\t\t\troot.InputInt(\"Projectile Count\", \"amount\");\n\t\t\t\troot.InputText(\"Sound\", \"sfx\", \"item_gun_fire\");\n\t\t\t\troot.InputInt(\"Sound Prefix Number\", \"sfxn\", 0);\n\t\t\t\troot.Checkbox(\"Reload Sound\", \"rsfx\", false);\n\t\t\t\troot.Checkbox(\"Drop Shells\", \"shells\", true);\n\t\t\t\troot.Checkbox(\"Uses Emeralds\", \"emeralds\", false);\n\n\t\t\t\tvar c = root.InputText(\"Color\", \"color\");\n\n\t\t\t\tif (!string.IsNullOrEmpty(c) && !ProjectileColor.Colors.ContainsKey(c)) {\n\t\t\t\t\tImGui.BulletText(\"Unknown color\");\n\t\t\t\t}\n\n\t\t\t\tImGui.Separator();\n\n\t\t\t\troot.InputFloat(\"Min Speed\", \"speed\", 10);\n\t\t\t\troot.InputFloat(\"Max Speed\", \"speedm\", 10);\n\t\t\t\troot.Checkbox(\"Disable Boost\", \"dsb\", false);\n\n\t\t\t\tImGui.Separator();\n\t\t\t\t\n\t\t\t\troot.InputFloat(\"Min Scale\", \"scale\");\n\t\t\t\troot.InputFloat(\"Max Scale\", \"scalem\");\n\t\t\t\t\n\t\t\t\tImGui.Separator();\n\n\t\t\t\tvar range = (float) root[\"range\"].Number(0);\n\n\t\t\t\tif (ImGui.InputFloat(\"Range\", ref range)) {\n\t\t\t\t\troot[\"range\"] = range;\n\t\t\t\t}\n\n\t\t\t\tvar knockback = (float) root[\"knockback\"].Number(1);\n\n\t\t\t\tif (ImGui.InputFloat(\"Knockback\", ref knockback)) {\n\t\t\t\t\troot[\"knockback\"] = knockback;\n\t\t\t\t}\n\n\t\t\t\troot.InputFloat(\"Additional Angle\", \"ang\", 0);\n\t\t\t\tvar accuracy = (float) root[\"accuracy\"].Number(0);\n\n\t\t\t\tif (ImGui.InputFloat(\"Accuracy\", ref accuracy)) {\n\t\t\t\t\troot[\"accuracy\"] = accuracy;\n\t\t\t\t}\n\n\t\t\t\tvar light = root[\"light\"].Bool(true);\n\n\t\t\t\tif (ImGui.Checkbox(\"Light\", ref light)) {\n\t\t\t\t\troot[\"light\"] = light;\n\t\t\t\t}\n\n\t\t\t\tvar rect = root[\"rect\"].Bool(false);\n\n\t\t\t\tif (ImGui.Checkbox(\"Rect body\", ref rect)) {\n\t\t\t\t\troot[\"rect\"] = rect;\n\t\t\t\t}\n\n\t\t\t\tvar wait = root[\"wait\"].Bool(false);\n\n\t\t\t\tif (ImGui.Checkbox(\"Wait for projectile death\", ref wait)) {\n\t\t\t\t\troot[\"wait\"] = wait;\n\t\t\t\t}\n\n\t\t\t\tvar prefab = root[\"prefab\"].String(\"\");\n\n\t\t\t\tif (ImGui.InputText(\"Prefab\", ref prefab, 128)) {\n\t\t\t\t\troot[\"prefab\"] = prefab;\n\t\t\t\t}\n\n\t\t\t\tif (prefab.Length > 0 && ProjectileRegistry.Get(prefab) == null) {\n\t\t\t\t\tImGui.BulletText(\"Unknown prefab\");\n\t\t\t\t}\n\n\t\t\t\tvar slice = root[\"texture\"].String(\"rect\");\n\n\t\t\t\tif (slice == \"default\") {\n\t\t\t\t\tslice = \"rect\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar region = CommonAse.Projectiles.GetSlice(slice, false);\n\n\t\t\t\tif (region != null) {\n\t\t\t\t\tImGui.Image(ImGuiHelper.ProjectilesTexture, new Num.Vector2(region.Width * 3, region.Height * 3),\n\t\t\t\t\t\tnew Num.Vector2(region.X / region.Texture.Width, region.Y / region.Texture.Height),\n\t\t\t\t\t\tnew Num.Vector2((region.X + region.Width) / region.Texture.Width,\n\t\t\t\t\t\t\t(region.Y + region.Height) / region.Texture.Height));\n\t\t\t\t}\n\n\t\t\t\tif (ImGui.InputText(\"Texture\", ref slice, 128)) {\n\t\t\t\t\troot[\"texture\"] = slice;\n\t\t\t\t}\n\n\t\t\t\tImGui.TreePop();\n\t\t\t}\n\n\t\t\tif (ImGui.TreeNode(\"Modifiers\")) {\n\t\t\t\tif (!root[\"modifiers\"].IsJsonArray) {\n\t\t\t\t\troot[\"modifiers\"] = new JsonArray();\n\t\t\t\t}\n\n\t\t\t\tItemEditor.DisplayUse(root, root[\"modifiers\"], \"bk:ModifyProjectiles\");\n\t\t\t\tImGui.TreePop();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (wait && !ProjectileDied) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.Use(entity, item);\n\t\t}\n\n\t\tprivate void PlaceMana(Area area, Vector2 where) {\n\t\t\tfor (var j = 0; j < Math.Floor(manaUsage / 2f); j++) {\n\t\t\t\tItems.CreateAndAdd(\"bk:mana\", area).Center = where;\n\t\t\t}\n\n\t\t\tif (manaUsage % 2 == 1) {\n\t\t\t\tItems.CreateAndAdd(\"bk:half_mana\", area).Center = where;\n\t\t\t}\n\n\t\t\tAnimationUtil.Poof(where);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnBombUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SpawnBombUse : ConsumeUse {\n\t\tpublic float Timer;\n\t\tpublic int Amount;\n\t\tpublic bool Randomly;\n\t\t\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tItems.Unlock(\"bk:grenade_launcher\");\n\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\n\n\t\t\tif (room == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < Amount; i++) {\n\t\t\t\tif (Randomly) {\n\t\t\t\t\tLens.util.timer.Timer.Add(() => {\n\t\t\t\t\t\tif (entity?.Area == null || room == null) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tvar bomb = new Bomb(entity, Timer);\n\t\t\t\t\t\tentity.Area.Add(bomb);\n\t\t\t\t\t\tbomb.Center = room == null ? entity.Center + Rnd.Vector(-4, 4) : room.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t\t}, i * 0.1f);\n\t\t\t\t} else {\n\t\t\t\t\tif (entity?.Area == null) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar bomb = new Bomb(entity, Timer);\n\t\t\t\t\tentity.Area.Add(bomb);\n\t\t\t\t\t\n\t\t\t\t\tbomb.Center = entity.Center;\n\t\t\t\t\tbomb.MoveToMouse();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tTimer = settings[\"timer\"].Number(2);\n\t\t\tAmount = settings[\"amount\"].Int(1);\n\t\t\tRandomly = settings[\"randomly\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"timer\"].Number(2);\n\n\t\t\tif (ImGui.InputFloat(\"Timer\", ref val)) {\n\t\t\t\troot[\"timer\"] = val;\n\t\t\t}\n\t\t\t\n\t\t\tvar am = root[\"amount\"].Int(1);\n\n\t\t\tif (ImGui.InputInt(\"Amount\", ref am)) {\n\t\t\t\troot[\"amount\"] = am;\n\t\t\t}\n\n\t\t\tvar randomly = root[\"randomly\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Randomly\", ref randomly)) {\n\t\t\t\troot[\"randomly\"] = randomly;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnDropUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SpawnDropUse : ItemUse {\n\t\tprivate static string drop;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\t\t\t\n\t\t\tif (!assets.loot.Drops.Defined.TryGetValue(drop, out var d)) {\n\t\t\t\tLog.Error($\"Unknown drop {drop}\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcreature.drop.Drop.Create(new List<Drop> {\n\t\t\t\td\n\t\t\t}, entity);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\tdrop = settings[\"drop\"].String(\"missing\");\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.InputText(\"Drop\", \"drop\");\n\t\t\t\n\t\t\tif (!assets.loot.Drops.Defined.ContainsKey(drop)) {\n\t\t\t\tImGui.Text($\"Unknown drop {drop}\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnItemsUse.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class SpawnItemsUse : ItemUse {\r\n\t\tpublic const int Distance = 24;\r\n\t\tpublic List<ItemPair> ToSpawn = new List<ItemPair>();\r\n\t\t\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar count = 0;\r\n\r\n\t\t\tvar center = entity.Center;\r\n\t\t\tvar room = entity.GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (room != null) {\r\n\t\t\t\tcenter = room.Center;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tforeach (var i in ToSpawn) {\r\n\t\t\t\tcount += i.Count;\r\n\t\t\t}\r\n\r\n\t\t\tvar j = 0f;\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < ToSpawn.Count; i++) {\r\n\t\t\t\tvar it = ToSpawn[i];\r\n\r\n\t\t\t\tfor (var m = 0; m < it.Count; m++) {\r\n\t\t\t\t\tvar itm = Items.CreateAndAdd(it.Id, entity.Area);\r\n\t\t\t\t\tvar angle = j / count * Math.PI * 2;\r\n\t\t\t\t\t\r\n\t\t\t\t\titm.Center = center + new Vector2((float) Math.Cos(angle) * Distance, (float) Math.Sin(angle) * Distance);\r\n\t\t\t\t\t\r\n\t\t\t\t\tj++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\tToSpawn.Clear();\r\n\t\t\tvar v = settings[\"items\"];\r\n\r\n\t\t\tif (!v.IsJsonArray) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tforeach (var i in v.AsJsonArray) {\r\n\t\t\t\tToSpawn.Add(new ItemPair {\r\n\t\t\t\t\tCount = i[0],\r\n\t\t\t\t\tId = i[1]\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar toRemove = -1;\r\n\t\t\t\r\n\t\t\tif (!root[\"items\"].IsJsonArray) {\r\n\t\t\t\troot[\"items\"] = new JsonArray();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar toSpawn = root[\"items\"].AsJsonArray;\r\n\r\n\t\t\tfor (var i = 0; i < toSpawn.Count; i++) {\r\n\t\t\t\tvar item = toSpawn[i];\r\n\t\t\t\tvar v = item[0].Int(1);\r\n\t\t\t\tvar n = item[1].String(\"\");\r\n\r\n\t\t\t\tif (ImGui.InputText($\"##ss{i}\", ref n, 128)) {\r\n\t\t\t\t\titem[1] = n;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.InputInt($\"##sl{i}\", ref v)) {\r\n\t\t\t\t\titem[0] = v;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"-\")) {\r\n\t\t\t\t\ttoRemove = i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Button(\"+\")) {\r\n\t\t\t\ttoSpawn.Add(new JsonArray {\r\n\t\t\t\t\t1, \"bk:copper_coin\"\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tif (toRemove > -1) {\r\n\t\t\t\ttoSpawn.Remove(toRemove);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnOrbitalUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.orbital;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SpawnOrbitalUse : ItemUse {\n\t\tprivate string orbital;\n\t\tprivate bool random;\n\t\tprivate bool onlyIfHasNone;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tif (onlyIfHasNone) {\n\t\t\t\tvar inventory = entity.GetComponent<InventoryComponent>();\n\n\t\t\t\tforeach (var i in inventory.Items) {\n\t\t\t\t\tif (ItemPool.Orbital.Contains(i.Data.Pools)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (random) {\n\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Orbital), entity.Area, true));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar o = OrbitalRegistry.Create(orbital, entity);\n\n\t\t\tif (o == null) {\n\t\t\t\tLog.Error($\"Failed to create orbital with id {orbital}\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tentity.GetComponent<OrbitGiverComponent>().AddOrbiter(o);\n\t\t}\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\n\t\t\trandom = settings[\"random\"].Bool(false);\n\t\t\torbital = settings[\"orbital\"].String(\"\");\n\t\t\tonlyIfHasNone = settings[\"oin\"].Bool(false);\n\t\t}\n\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\troot.Checkbox(\"Only if has none\", \"oin\", false);\n\t\t\t\n\t\t\tif (root.Checkbox(\"Random\", \"random\", false)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!OrbitalRegistry.Has(root.InputText(\"Orbital\", \"orbital\", \"\", 128))) {\n\t\t\t\tImGui.BulletText(\"Unknown orbital!\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnPetUse.cs",
    "content": "using BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.pet;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class SpawnPetUse : ItemUse {\r\n\t\tprivate string pet;\r\n\t\tprivate bool random;\r\n\t\tprivate bool onlyIfHasNone;\r\n\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tif (onlyIfHasNone) {\r\n\t\t\t\tvar inventory = entity.GetComponent<InventoryComponent>();\r\n\r\n\t\t\t\tforeach (var i in inventory.Items) {\r\n\t\t\t\t\tif (ItemPool.Pet.Contains(i.Data.Pools)) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (random) {\r\n\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Pet), entity.Area));\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar o = PetRegistry.Create(pet, entity);\r\n\r\n\t\t\tif (o == null) {\r\n\t\t\t\tLog.Error($\"Failed to create pet with id {pet}\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\to.Center = entity.Center + Rnd.Offset(24);\r\n\t\t\tAnimationUtil.Poof(o.Center, entity.Depth + 1);\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\t\r\n\t\t\tpet = settings[\"pet\"].String(\"\");\r\n\t\t\trandom = settings[\"random\"].Bool(false);\r\n\t\t\tonlyIfHasNone = settings[\"oin\"].Bool(false);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\troot.Checkbox(\"Only if has none\", \"oin\", false);\r\n\t\t\t\r\n\t\t\tif (root.Checkbox(\"Random\", \"random\", false)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (!PetRegistry.Has(root.InputText(\"Pet\", \"pet\", \"\", 128))) {\r\n\t\t\t\tImGui.BulletText(\"Unknown pet!\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpawnProjectilesUse.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.entity.projectile;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Microsoft.Xna.Framework;\r\nusing Num = System.Numerics;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class SpawnProjectilesUse : ItemUse {\r\n\t\tprivate int damage;\r\n\t\tprivate float speed;\r\n\t\tprivate float range;\r\n\t\tprivate string slice;\r\n\t\tprivate int amount;\r\n\t\t\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar s = range * 0.5f / speed;\r\n\t\t\tvar builder = new ProjectileBuilder(entity, slice) {\r\n\t\t\t\tLightRadius = 32f,\r\n\t\t\t\tColor = ProjectileColor.Yellow,\r\n\t\t\t\tDamage = damage\r\n\t\t\t};\r\n\r\n\t\t\tif (range > 0.01f) {\r\n\t\t\t\tbuilder.Range = s;\r\n\t\t\t}\r\n\r\n\t\t\tfor (var i = 0; i < amount; i++) {\r\n\t\t\t\tvar angle = (float) i / amount * Math.PI * 2;\r\n\t\t\t\tbuilder.Shoot(angle, speed).Build();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\t\t\t\r\n\t\t\tdamage = settings[\"damage\"].Int(1);\r\n\t\t\tamount = settings[\"amount\"].Int(1);\r\n\t\t\tspeed = settings[\"speed\"].Number(60);\r\n\t\t\trange = settings[\"range\"].Number(0);\r\n\t\t\tslice = settings[\"texture\"].AsString;\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar val = root[\"amount\"].Int(1);\r\n\r\n\t\t\tif (ImGui.InputInt(\"Amount\", ref val)) {\r\n\t\t\t\troot[\"amount\"] = val;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tval = root[\"damage\"].Int(1);\r\n\r\n\t\t\tif (ImGui.InputInt(\"Damage\", ref val)) {\r\n\t\t\t\troot[\"damage\"] = val;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar spd = (float) root[\"speed\"].Number(60);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"Speed\", ref spd)) {\r\n\t\t\t\troot[\"speed\"] = spd;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar range = (float) root[\"range\"].Number(0);\r\n\r\n\t\t\tif (ImGui.InputFloat(\"Range\", ref range)) {\r\n\t\t\t\troot[\"range\"] = range;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar slice = root[\"texture\"].String(\"\");\r\n\t\t\tvar region = CommonAse.Projectiles.GetSlice(slice);\r\n\t\t\t\r\n\t\t\tImGui.Image(ImGuiHelper.ProjectilesTexture, new Num.Vector2(region.Width * 3, region.Height * 3),\r\n\t\t\t\tnew Num.Vector2(region.X / region.Texture.Width, region.Y / region.Texture.Height),\r\n\t\t\t\tnew Num.Vector2((region.X + region.Width) / region.Texture.Width, \r\n\t\t\t\t\t(region.Y + region.Height) / region.Texture.Height));\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Texture\", ref slice, 128)) {\r\n\t\t\t\troot[\"texture\"] = slice;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SpeedUpOrbitalsUse.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SpeedUpOrbitalsUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tentity.GetComponent<OrbitGiverComponent>().Speed *= 2;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/SuperHotUse.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class SuperHotUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tif (entity is Player p) {\n\t\t\t\tp.SuperHot = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/TeleportToCursorUse.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.input;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class TeleportToCursorUse : ItemUse {\r\n\t\tpublic override void Use(Entity entity, Item item) {\r\n\t\t\tvar position = entity.GetComponent<CursorComponent>().Cursor.GamePosition;\r\n\t\t\tvar tileX = (int) (position.X / 16);\r\n\t\t\tvar tileY = (int) (position.Y / 16);\r\n\r\n\t\t\tvar level = Run.Level;\r\n\r\n\t\t\tif (!level.IsInside(tileX, tileY)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!level.Get(tileX, tileY).Matches(TileFlags.Passable)) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tAnimationUtil.Poof(entity.Center);\r\n\t\t\tentity.Center = position;\r\n\t\t\tAnimationUtil.Poof(entity.Center);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/TeleportToPrevRoomUse.cs",
    "content": "using BurningKnight.entity.events;\nusing BurningKnight.entity.room;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class TeleportToPrevRoomUse : ItemUse {\n\t\tprivate Room previous;\n\n\t\tpublic override void Use(Entity e, Item item) {\n\t\t\tbase.Use(e, item);\n\n\t\t\tif (previous == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tAnimationUtil.TeleportAway(e, () => {\n\t\t\t\te.Center = previous.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\tCamera.Instance.Jump();\n\t\t\t\tAnimationUtil.TeleportIn(e);\n\n\t\t\t\tprevious = null;\n\t\t\t});\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is RoomChangedEvent rce && rce.Who == Item.Owner) {\n\t\t\t\tprevious = rce.Old;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/TeleportToShopUse.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class TeleportToShopUse : ItemUse {\n\t\tpublic override void Use(Entity e, Item item) {\n\t\t\tbase.Use(e, item);\n\t\t\t\n\t\t\tvar rooms = e.Area.Tagged[Tags.Room];\n\n\t\t\tif (rooms.Count < 2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar room = e.GetComponent<RoomComponent>().Room;\n\t\t\tvar newRoom = (Room) Rnd.Element<Entity>(rooms, r => r != room && r is Room rm && rm.Type == RoomType.Shop);\n\n\t\t\tif (newRoom != null) {\n\t\t\t\tAnimationUtil.TeleportAway(e, () => {\n\t\t\t\t\te.Center = newRoom.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\tAnimationUtil.TeleportIn(e);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/TeleportUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item.use.parent;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class TeleportUse : DoWithTagUse {\n\t\tprotected override void DoAction(Entity entity, Item item, List<Entity> entities) {\n\t\t\tvar rooms = entity.Area.Tagged[Tags.Room];\n\n\t\t\tif (rooms.Count < 2) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var e in entities) {\n\t\t\t\tvar room = e.GetComponent<RoomComponent>().Room;\n\t\t\t\tvar newRoom = (Room) Rnd.Element<Entity>(rooms, r => r != room && r is Room rm && rm.Type != RoomType.Granny && rm.Type != RoomType.OldMan && rm.Type != RoomType.Secret && rm.Type != RoomType.Special && rm.Type != RoomType.Hidden);\n\n\t\t\t\tif (newRoom != null) {\n\t\t\t\t\tAnimationUtil.TeleportAway(e, () => {\n\t\t\t\t\t\te.Center = newRoom.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\t\tAnimationUtil.TeleportIn(e);\n\t\t\t\t\t\te.GetComponent<HealthComponent>().Unhittable = false;\n\t\t\t\t\t});\n\n\t\t\t\t\tentity.GetComponent<AudioEmitterComponent>().EmitRandomized(\"quck\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/TriggerHurtEventUse.cs",
    "content": "using BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic class TriggerHurtEventUse : ItemUse {\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tentity.HandleEvent(new HealthModifiedEvent {\n\t\t\t\tAmount = -1,\n\t\t\t\tWho = entity,\n\t\t\t\tFrom = item\n\t\t\t});\n\t\t\t\n\t\t\tentity.HandleEvent(new PostHealthModifiedEvent {\n\t\t\t\tAmount = -1,\n\t\t\t\tWho = entity,\n\t\t\t\tFrom = item\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/UseOnEventUse.cs",
    "content": "using System;\r\nusing BurningKnight.state;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\n\r\nnamespace BurningKnight.entity.item.use {\r\n\tpublic class UseOnEventUse : ItemUse {\r\n\t\tprivate string type;\r\n\t\tprivate Type typeInstance;\r\n\t\tprivate string use;\r\n\t\tprivate JsonValue options;\r\n\r\n\t\tpublic override void Setup(JsonValue settings) {\r\n\t\t\tbase.Setup(settings);\r\n\r\n\t\t\ttype = settings[\"tp\"].String(\"\");\r\n\t\t\tuse = settings[\"use\"].String(\"\");\r\n\t\t\toptions = settings[\"us\"];\r\n\r\n\t\t\tif (options == JsonValue.Null) {\r\n\t\t\t\toptions = new JsonObject();\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\ttypeInstance = Type.GetType(type, true, false);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error(e);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e.GetType() == typeInstance) {\r\n\t\t\t\tvar u = UseRegistry.Create(use);\r\n\r\n\t\t\t\tif (u == null) {\r\n\t\t\t\t\tLog.Error($\"{use} is invalid item use id\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tu.Item = Item;\r\n\t\t\t\t\tu.Setup(options);\r\n\t\t\t\t\tu.Use(Item.Owner, Item);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug(JsonValue root) {\r\n\t\t\tvar type = root[\"tp\"].String(\"\");\r\n\t\t\tvar use = root[\"use\"].String(\"\");\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Use\", ref use, 128)) {\r\n\t\t\t\troot[\"use\"] = use;\r\n\t\t\t}\r\n\r\n\t\t\tvar c = !UseRegistry.Uses.ContainsKey(use);\r\n\r\n\t\t\tif (c) {\r\n\t\t\t\tImGui.BulletText(\"Unknown use\");\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Event type\", ref type, 256)) {\r\n\t\t\t\troot[\"tp\"] = type;\r\n\t\t\t}\r\n\r\n\t\t\ttry {\r\n\t\t\t\tType.GetType(type, true, false);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tImGui.BulletText(\"Unknown type\");\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (c) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar us = root[\"us\"];\r\n\r\n\t\t\tif (us == JsonValue.Null) {\r\n\t\t\t\tus = root[\"us\"] = new JsonObject();\r\n\t\t\t}\r\n\r\n\t\t\tus[\"id\"] = use;\r\n\t\t\t\r\n\t\t\tItemEditor.DisplayUse(root, us);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/UseRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.use.parent;\nusing Lens.lightJson;\nusing Lens.util;\n\nnamespace BurningKnight.entity.item.use {\n\tpublic static class UseRegistry {\n\t\tpublic static Dictionary<string, Type> Uses = new Dictionary<string, Type>();\n\t\tpublic static Dictionary<string, Action<JsonValue>> Renderers = new Dictionary<string, Action<JsonValue>>();\n\n\t\tpublic static void Register<T>(Mod mod, Action<JsonValue> renderer = null) where T : ItemUse {\n\t\t\tvar type = typeof(T);\n\t\t\tvar name = type.Name;\n\t\t\tvar id = $\"{mod?.Prefix ?? Mods.BurningKnight}:{(name.EndsWith(\"Use\") ? name.Substring(0, name.Length - 3) : name)}\";\n\n\t\t\tUses[id] = type;\n\n\t\t\tif (renderer != null) {\n\t\t\t\tRenderers[id] = renderer;\n\t\t\t}\n\t\t}\n\n\t\tprivate static void Register<T>(Action<JsonValue> renderer = null) where T : ItemUse {\n\t\t\tRegister<T>(null, renderer);\n\t\t}\n\n\t\tpublic static ItemUse Create(string id) {\n\t\t\tif (!Uses.TryGetValue(id, out var use)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn (ItemUse) Activator.CreateInstance(use);\n\t\t}\n\n\t\tstatic UseRegistry() {\n\t\t\tRegister<DigUse>();\n\t\t\tRegister<SpawnBombUse>(SpawnBombUse.RenderDebug);\n\t\t\tRegister<ConsumeUse>();\n\t\t\tRegister<MeleeArcUse>(MeleeArcUse.RenderDebug);\n\t\t\tRegister<ModifyShieldHeartsUse>(ModifyHpUse.RenderDebug);\n\t\t\tRegister<ModifyHpUse>(ModifyHpUse.RenderDebug);\n\t\t\tRegister<ModifyManaUse>(ModifyManaUse.RenderDebug);\n\t\t\tRegister<ModifyMaxHpUse>(ModifyMaxHpUse.RenderDebug);\n\t\t\tRegister<GiveHeartContainersUse>(ModifyHpUse.RenderDebug);\n\t\t\tRegister<SimpleShootUse>(SimpleShootUse.RenderDebug);\n\t\t\tRegister<ShootQueueUse>(ShootQueueUse.RenderDebug);\n\t\t\tRegister<RandomUse>(RandomUse.RenderDebug);\n\t\t\tRegister<GiveGoldUse>(GiveGoldUse.RenderDebug);\n\t\t\tRegister<GiveKeyUse>(GiveKeyUse.RenderDebug);\n\t\t\tRegister<GiveBombUse>(GiveBombUse.RenderDebug);\n\t\t\tRegister<GiveItemUse>(GiveItemUse.RenderDebug);\n\t\t\tRegister<SetMaxHpUse>(SetMaxHpUse.RenderDebug);\n\t\t\tRegister<SpawnItemsUse>(SpawnItemsUse.RenderDebug);\n\t\t\tRegister<SpawnMobsUse>(SpawnMobsUse.RenderDebug);\n\t\t\tRegister<DiscoverSecretRoomsUse>(DiscoverSecretRoomsUse.RenderDebug);\n\t\t\tRegister<ModifyStatUse>(ModifyStatUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesSplitOnDeathUse>();\n\t\t\tRegister<MakeProjectilesShatternOnDeathUse>();\n\t\t\tRegister<MakeProjectilesBounceUse>(MakeProjectilesBounceUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesHomeInUse>(MakeProjectilesHomeInUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesSlowDown>(MakeProjectilesSlowDown.RenderDebug);\n\t\t\tRegister<TeleportToCursorUse>();\n\t\t\tRegister<MakeLayerPassableUse>(MakeLayerPassableUse.RenderDebug);\n\t\t\tRegister<SpawnOrbitalUse>(SpawnOrbitalUse.RenderDebug);\n\t\t\tRegister<SpawnPetUse>(SpawnPetUse.RenderDebug);\n\t\t\tRegister<RerollItemsUse>(RerollItemsUse.RenderDebug);\n\t\t\tRegister<RerollAndHideUse>(RerollItemsUse.RenderDebug);\n\t\t\tRegister<SpawnProjectilesUse>(SpawnProjectilesUse.RenderDebug);\n\t\t\tRegister<UseOnEventUse>(UseOnEventUse.RenderDebug);\n\t\t\tRegister<MakeShopRestockUse>();\n\t\t\tRegister<SaleItemsUse>(SaleItemsUse.RenderDebug);\n\t\t\tRegister<ModifyActiveChargeUse>(ModifyActiveChargeUse.RenderDebug);\n\t\t\tRegister<PreventDamageUse>(PreventDamageUse.RenderDebug);\n\t\t\tRegister<RemoveFromPoolUse>(RemoveFromPoolUse.RenderDebug);\n\t\t\tRegister<ModifyGameSaveValueUse>(ModifyGameSaveValueUse.RenderDebug);\n\t\t\tRegister<GiveWeaponUse>(GiveWeaponUse.RenderDebug);\n\t\t\tRegister<AddHitboxUse>();\n\t\t\tRegister<GiveEmeraldsUse>(GiveEmeraldsUse.RenderDebug);\n\t\t\tRegister<ModifyProjectilesUse>(ModifyProjectilesUse.RenderDebug);\n\t\t\tRegister<TeleportUse>(TeleportUse.RenderDebug);\n\t\t\tRegister<DoOnEnemyCollisionUse>(DoOnEnemyCollisionUse.RenderDebug);\n\t\t\tRegister<DoOnHurtUse>(DoOnHurtUse.RenderDebug);\n\t\t\tRegister<GiveBuffUse>(GiveBuffUse.RenderDebug);\n\t\t\tRegister<GiveBuffImmunityUse>(GiveBuffImmunityUse.RenderDebug);\n\t\t\tRegister<DoWithUse>(DoWithUse.RenderDebug);\n\t\t\tRegister<TriggerHurtEventUse>();\n\t\t\tRegister<SetKnockbackModifierUse>(SetKnockbackModifierUse.RenderDebug);\n\t\t\tRegister<RandomActiveUse>();\n\t\t\tRegister<ScourgeUse>(ScourgeUse.RenderDebug);\n\t\t\tRegister<ModifyLuckUse>(ModifyLuckUse.RenderDebug);\n\t\t\tRegister<RerollItemsOnPlayerUse>(RerollItemsOnPlayerUse.RenderDebug);\n\t\t\tRegister<GoThonkUse>();\n\t\t\tRegister<RevealMapUse>();\n\t\t\tRegister<RevealMapUse>();\n\t\t\tRegister<ModifyBombsUse>(ModifyBombsUse.RenderDebug);\n\t\t\tRegister<DuplicateItemsUse>();\n\t\t\tRegister<DuplicateMobsUse>();\n\t\t\tRegister<DuplicateMobsAndHealUse>();\n\t\t\tRegister<GiveLaserAimUse>();\n\t\t\tRegister<KillMobUse>(KillMobUse.RenderDebug);\n\t\t\tRegister<GiveFlightUse>();\n\t\t\tRegister<SpawnDropUse>(SpawnDropUse.RenderDebug);\n\t\t\tRegister<ModifyStatsUse>(ModifyStatsUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesBoomerangUse>();\n\t\t\tRegister<EnableScourgeUse>(EnableScourgeUse.RenderDebug);\n\t\t\tRegister<SetMusicSpeed>(SetMusicSpeed.RenderDebug);\n\t\t\tRegister<DoOnTimerUse>(DoOnTimerUse.RenderDebug);\n\t\t\tRegister<MakeBombsHomeUse>(MakeBombsHomeUse.RenderDebug);\n\t\t\tRegister<MakeBombsExplodeOnTouchUse>();\n\t\t\tRegister<RegenUse>(RegenUse.RenderDebug);\n\t\t\tRegister<ReplaceHeartsWithShieldsUse>();\n\t\t\tRegister<GivePhaseUse>(GivePhaseUse.RenderDebug);\n\t\t\tRegister<ExplodeUse>();\n\t\t\tRegister<DiscoverSideRoomsUse>();\n\t\t\tRegister<DetonateBombsUse>();\n\t\t\tRegister<GiveScourgeImmunityUse>();\n\t\t\tRegister<MakeBombsBlankUse>();\n\t\t\tRegister<BlankUse>();\n\t\t\tRegister<MakeProjectilesBlankOnDeathUse>();\n\t\t\tRegister<AffectDealChanceUse>(AffectDealChanceUse.RenderDebug);\n\t\t\tRegister<LeaveLegoUse>();\n\t\t\tRegister<DoOnNewFloorUse>(DoUsesUse.RenderDebug);\n\t\t\tRegister<DoUsesIfUse>(DoUsesIfUse.RenderDebug);\n\t\t\tRegister<ModifyArcUse>(ModifyArcUse.RenderDebug);\n\t\t\tRegister<BlindFoldUse>();\n\t\t\tRegister<MakeProjectileShrinkUse>(MakeProjectileShrinkUse.RenderDebug);\n\t\t\tRegister<MakeProjectileExpandUse>(MakeProjectileExpandUse.RenderDebug);\n\t\t\tRegister<SuperHotUse>();\n\t\t\tRegister<ModifyManaMaxUse>(ModifyManaMaxUse.RenderDebug);\n\t\t\tRegister<ModifyConsumableWeightsUse>(ModifyConsumableWeightsUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesHurtOnMissUse>();\n\t\t\tRegister<TeleportToShopUse>();\n\t\t\tRegister<PlaceDecoyUse>();\n\t\t\tRegister<InvokeItemsUse>(InvokeItemsUse.RenderDebug);\n\t\t\tRegister<SpeedUpOrbitalsUse>();\n\t\t\tRegister<TeleportToPrevRoomUse>();\n\t\t\tRegister<BreakPiggyBankUse>();\n\t\t\tRegister<MakeProjectilesKillWithBuffUse>(MakeProjectilesKillWithBuffUse.RenderDebug);\n\t\t\tRegister<ModifyShootUse>(ModifyShootUse.RenderDebug);\n\t\t\tRegister<ModifyGenUse>(ModifyGenUse.RenderDebug);\n\t\t\tRegister<MakeProjectilesSplitUse>();\n\t\t\tRegister<PoofUse>();\n\t\t\tRegister<MakeProjectileReshootUse>();\n\t\t\tRegister<PokemonUse>();\n\t\t\tRegister<BlockDamageUse>(BlockDamageUse.RenderDebug);\n\t\t\tRegister<ModifyProjectileTextureUse>(ModifyProjectileTextureUse.RenderDebug);\n\t\t\tRegister<ShootLaserUse>();\n\t\t\tRegister<GiveRandomPickupUse>();\n\t\t\tRegister<BucketUse>(BucketUse.RenderDebug);\n\t\t\tRegister<FireInAllDirsUse>();\n\t\t\tRegister<MakeItemsAttactUse>();\n\t\t\tRegister<MakeRollKickProjectilesUse>();\n\t\t\tRegister<ChanceToUseWeaponUse>(ChanceToUseWeaponUse.RenderDebug);\n\t\t\tRegister<ModEachAttackUse>();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/parent/DoUsesUse.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.lightJson;\n\nnamespace BurningKnight.entity.item.use.parent {\n\tpublic abstract class DoUsesUse : ItemUse {\n\t\tprotected ItemUse[] Uses;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tbase.Use(entity, item);\n\n\t\t\tforeach (var u in Uses) {\n\t\t\t\tDoAction(entity, item, u);\n\t\t\t}\n\t\t}\n\n\t\tprotected abstract void DoAction(Entity entity, Item item, ItemUse use);\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\n\t\t\tif (!settings[\"uses\"].IsJsonArray) {\n\t\t\t\tsettings[\"uses\"] = new JsonArray();\n\t\t\t}\n\t\t\t\n\t\t\tUses = Items.ParseUses(settings[\"uses\"]);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tif (!root[\"uses\"].IsJsonArray) {\n\t\t\t\troot[\"uses\"] = new JsonArray();\n\t\t\t}\n\t\t\t\n\t\t\tItemEditor.DisplayUse(root, root[\"uses\"]);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/use/parent/DoWithTagUse.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.item.use.parent {\n\tpublic abstract class DoWithTagUse : ItemUse {\n\t\tprivate bool self;\n\t\tprivate bool sameRoom;\n\t\tprivate bool all;\n\t\tprivate int tag;\n\n\t\tpublic override void Use(Entity entity, Item item) {\n\t\t\tvar list = new List<Entity>();\n\n\t\t\tif (self) {\n\t\t\t\tlist.Add(entity);\n\t\t\t}\n\n\t\t\tvar tags = (sameRoom ? entity.GetComponent<RoomComponent>().Room.Tagged : entity.Area.Tagged);\n\n\t\t\tfor (var i = 0; i < BitTag.Total; i++) {\n\t\t\t\tif ((tag & 1 << i) != 0) {\n\t\t\t\t\tvar l = tags[i];\n\t\t\t\t\t\n\t\t\t\t\tif (all) {\n\t\t\t\t\t\tlist.AddRange(l);\n\t\t\t\t\t} else if (l.Count > 0) {\n\t\t\t\t\t\tlist.Add(l[Rnd.Int(l.Count)]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tDoAction(entity, item, list);\n\t\t}\n\n\t\tprotected abstract void DoAction(Entity entity, Item item, List<Entity> entities);\n\n\t\tpublic override void Setup(JsonValue settings) {\n\t\t\tbase.Setup(settings);\n\t\t\t\t\n\t\t\tself = settings[\"self\"].Bool(false);\n\t\t\tsameRoom = settings[\"same_room\"].Bool(true);\n\t\t\tall = settings[\"all\"].Bool(true);\n\t\t\ttag = settings[\"tag\"].Int(1);\n\t\t}\n\t\t\n\t\tpublic static void RenderDebug(JsonValue root) {\n\t\t\tvar val = root[\"self\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Self\", ref val)) {\n\t\t\t\troot[\"self\"] = val;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tval = root[\"same_room\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"Same room?\", ref val)) {\n\t\t\t\troot[\"same_room\"] = val;\n\t\t\t}\n\t\t\t\n\t\t\tval = root[\"all\"].Bool(false);\n\n\t\t\tif (ImGui.Checkbox(\"All?\", ref val)) {\n\t\t\t\troot[\"all\"] = val;\n\t\t\t}\n\t\t\t\n\t\t\tvar tag = root[\"tag\"].Int(0);\n\t\t\tImGui.Text($\"Tags: {tag}\");\n\t\t\t\n\t\t\tfor (var i = 0; i < BitTag.Total; i++) {\n\t\t\t\tvar t = BitTag.Tags[i];\n\t\t\t\tvar on = (tag & 1 << i) != 0;\n\t\t\t\t\n\t\t\t\tif (ImGui.Checkbox(t.Name, ref on)) {\n\t\t\t\t\tif (on) {\n\t\t\t\t\t\ttag |= 1 << i;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttag &= ~(1 << i);\n\t\t\t\t\t}\n\n\t\t\t\t\troot[\"tag\"] = tag;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/useCheck/ItemUseCheck.cs",
    "content": "﻿using BurningKnight.entity.buff;\r\nusing BurningKnight.entity.component;\r\nusing Lens.entity;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.entity.item.useCheck {\r\n\tpublic class ItemUseCheck {\r\n\t\tpublic virtual bool CanUse(Entity entity, Item item) {\r\n\t\t\treturn item.Delay < 0.05f && (item.Type != ItemType.Weapon || !entity.GetComponent<BuffsComponent>().Has<CharmedBuff>());\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/item/useCheck/ItemUseChecks.cs",
    "content": "﻿namespace BurningKnight.entity.item.useCheck {\n\tpublic static class ItemUseChecks {\n\t\tpublic static ItemUseCheck Default = new ItemUseCheck();\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/item/util/MeleeArc.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.item.util {\n\tpublic delegate void ArcHurtCallback(MeleeArc p, Entity e);\n\tpublic delegate void ArcDeathCallback(MeleeArc p);\n\n\tpublic class MeleeArc : Entity {\n\t\tpublic static Color ReflectedColor = new Color(0.5f, 1f, 0.5f, 1f);\n\t\t\n\t\tpublic float LifeTime = 0.1f;\n\t\tpublic float Damage;\n\t\tpublic Entity Owner;\n\t\tpublic float Angle;\n\t\tpublic string Sound = \"item_sword_hit\";\n\t\tpublic Color Color = ColorUtils.WhiteColor;\n\t\tpublic bool Mines;\n\t\tpublic float Knockback;\n\n\t\tpublic ArcHurtCallback OnHurt;\n\t\tpublic ArcDeathCallback OnDeath;\n\n\t\tprivate float t;\n\t\tprivate Vector2 velocity;\n\t\tprivate List<Entity> hurt = new List<Entity>();\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tconst float force = 40f;\n\t\t\tvelocity = new Vector2((float) Math.Cos(Angle) * force, (float) Math.Sin(Angle) * force);\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, -Height / 2f, Width, Height, BodyType.Dynamic, true) {\n\t\t\t\tAngle = Angle\n\t\t\t});\n\n\t\t\tAddComponent(new AnimationComponent(\"sword_trail\", null, \"idle\") {\n\t\t\t\tOffset = new Vector2(4, 12),\n\t\t\t\tScale = new Vector2(Width / 8, Height / 24)\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 32f, Color.White));\n\n\t\t\tGetComponent<AnimationComponent>().OriginY = 12;\n\t\t\tCamera.Instance.Push(Angle - (float) Math.PI, 4f);\n\t\t}\n\n\t\tpublic void AdjustSize() {\n\t\t\tGetComponent<RectBodyComponent>().Resize(0, -Height / 2f, Width, Height);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tvar component = GetComponent<AnimationComponent>();\n\t\t\tvar region = component.Animation.GetCurrentTexture();\n\n\t\t\tGraphics.Color = Color;\n\t\t\tGraphics.Render(region, Position, Angle, component.Offset, component.Scale);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is HalfProjectileLevel bdd) {\n\t\t\t\t\tif (Mines) {\n\t\t\t\t\t\tPhysics.Fixture.GetAABB(out var hitbox, 0);\n\t\t\t\t\t\tProjectileLevelBody.Mine(Run.Level, hitbox.Center.X, hitbox.Center.Y);\n\t\t\t\t\t}\n\t\t\t\t} else if (ev.Entity is ProjectileLevelBody bd) {\n\t\t\t\t\tif (Mines) {\n\t\t\t\t\t\tPhysics.Fixture.GetAABB(out var hitbox, 0);\n\t\t\t\t\t\tProjectileLevelBody.Mine(Run.Level, hitbox.Center.X, hitbox.Center.Y);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (Run.Level.Biome is IceBiome) {\n\t\t\t\t\t\tPhysics.Fixture.GetAABB(out var hitbox, 0);\n\n\t\t\t\t\t\tif (bd.Break(hitbox.Center.X, hitbox.Center.Y)) {\n\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"level_snow_break\", 3);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (ev.Entity is Bomb) {\n\t\t\t\t\tev.Entity.GetComponent<RectBodyComponent>().KnockbackFrom(Owner, 1f + Knockback);\n\t\t\t\t} else if (ev.Entity is Projectile p) {\n\t\t\t\t\tif ((p.Owner is Mob) != (Owner is Mob) && ((p.FirstOwner is Mob) != (Owner is Mob))) {\n\t\t\t\t\t\tif (p.HasFlag(ProjectileFlags.Reflectable)) {\n\t\t\t\t\t\t\tp.Owner = Owner;\n\t\t\t\t\t\t\tp.Damage *= 2f;\n\n\t\t\t\t\t\t\t// fixme: lethal\n\t\t\t\t\t\t\t// p.Pattern?.Remove(p);\n\n\t\t\t\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\t\t\t\tvar d = Math.Max(400, b.Velocity.Length() * 1.8f);\n\t\t\t\t\t\t\tvar a = Owner.AngleTo(p);\n\n\t\t\t\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\n\t\t\t\t\t\t\tif (p.TryGetComponent<LightComponent>(out var l)) {\n\t\t\t\t\t\t\t\tl.Light.Color = ReflectedColor;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tp.Color = ProjectileColor.Yellow;\n\n\t\t\t\t\t\t\tCamera.Instance.ShakeMax(4f);\n\t\t\t\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"projectile_reflected\", 2);\n\t\t\t\t\t\t} else if (p.HasFlag(ProjectileFlags.BreakableByMelee)) {\n\t\t\t\t\t\t\tp.Break();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (ev.Entity != Owner && (!(ev.Entity is Player) || !(Owner is Player))) {\n\t\t\t\t\tif (ev.Entity.TryGetComponent<HealthComponent>(out var health)) {\n\t\t\t\t\t\tif (!hurt.Contains(ev.Entity)) {\n\t\t\t\t\t\t\tif (Knockback > 0) {\n\t\t\t\t\t\t\t\tev.Entity.GetAnyComponent<BodyComponent>()?.KnockbackFrom(Owner, Knockback);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (health.ModifyHealth(-Damage, Owner, DamageType.Melee)) {\n\t\t\t\t\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(Sound, 3);\n\t\t\t\t\t\t\t\tOnHurt?.Invoke(this, ev.Entity);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\thurt.Add(ev.Entity);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (ev.Entity is ProjectileLevelBody && !HitWall) {\n\t\t\t\t\t\tHitWall = true;\n\t\t\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().EmitRandomized(\"item_sword_hit_wall\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate bool HitWall;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\t\t\tPosition = Owner.Center + velocity * t;\n\n\t\t\tif (t >= LifeTime) {\n\t\t\t\tOnDeath?.Invoke(this);\n\t\t\t\tDone = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic class CreatedEvent : Event {\n\t\t\tpublic MeleeArc Arc;\n\t\t\tpublic Entity Owner;\n\t\t\tpublic Item By;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/orbital/AnimatedOrbital.cs",
    "content": "using BurningKnight.entity.component;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.orbital {\n\tpublic class AnimatedOrbital : Orbital {\n\t\tprivate string sprite;\n\n\t\tpublic AnimatedOrbital(string spr) {\n\t\t\tsprite = spr;\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(sprite) {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\n\t\t\tvar region = GetComponent<AnimationComponent>().Animation.GetCurrentTexture();\n\t\t\t\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/orbital/Marshmallow.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.orbital {\n\tpublic class Marshmallow : AnimatedOrbital {\n\t\tprivate float timer;\n\t\t\n\t\tpublic Marshmallow() : base(\"marshmallow\") {\n\t\t\ttimer = Rnd.Float(1);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\ttimer += dt;\n\n\t\t\tif (timer >= 1f) {\n\t\t\t\ttimer = 0;\n\n\t\t\t\tif ((Owner.GetComponent<RoomComponent>().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_meatguy\", 4, 0.5f);\n\n\t\t\t\tvar a = GetComponent<OrbitalComponent>().CurrentAngle;\n\n\t\t\t\tvar builder = new ProjectileBuilder(Owner, \"small\") {\n\t\t\t\t\tColor = ProjectileColor.White,\n\t\t\t\t\tLightRadius = 32f\n\t\t\t\t};\n\n\t\t\t\tbuilder.Shoot(a, 6f);\n\t\t\t\tbuilder.Move(a, 5f);\n\n\t\t\t\tvar projectile = builder.Build();\n\n\t\t\t\t/*Owner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\t\tProjectile = projectile,\n\t\t\t\t\tOwner = Owner\n\t\t\t\t});*/\n\t\t\t\t\n\t\t\t\tprojectile.Owner = this;\n\t\t\t\tGetComponent<AnimationComponent>().Animate();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/orbital/Orbital.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.tween;\n\nnamespace BurningKnight.entity.orbital {\n\tpublic delegate void OrbitalCollisionHandler(Orbital o, Entity e);\n\t\n\tpublic class Orbital : Entity {\n\t\tpublic OrbitalCollisionHandler OnCollision;\n\t\tpublic Entity Owner => GetComponent<OrbitalComponent>().Orbiting;\n\t\tpublic Action<float> Controller; \n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new OrbitalComponent());\n\t\t}\n\n\t\tprivate bool animated;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (!animated) {\n\t\t\t\tanimated = true;\n\t\t\t\t\n\t\t\t\tif (TryGetComponent<ScalableSliceComponent>(out var g)) {\n\t\t\t\t\tAnimationUtil.Poof(Center, Depth + 1);\n\t\t\t\t\tg.Animate();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tController?.Invoke(dt);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tOnCollision?.Invoke(this, cse.Entity);\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/orbital/OrbitalRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.orbital {\n\tpublic static class OrbitalRegistry {\n\t\tprivate static Dictionary<string, Func<Entity, Entity>> defined = new Dictionary<string, Func<Entity, Entity>>();\n\n\t\tpublic static Entity Create(string id, Entity owner) {\n\t\t\treturn !defined.TryGetValue(id, out var d) ? null : d(owner);\n\t\t}\n\t\t\n\t\tpublic static void Define(string id, Func<Entity, Entity> orbital, Mod mod = null) {\n\t\t\tdefined[$\"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}\"] = orbital;\n\t\t}\n\n\t\tpublic static bool Has(string id) {\n\t\t\treturn defined.ContainsKey(id);\n\t\t}\n\n\t\tstatic OrbitalRegistry() {\n\n\t\t\tDefine(\"prism\", o => {\n\t\t\t\tvar orbital = new Prism();\n\t\t\t\to.Area.Add(orbital);\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\n\t\t\tDefine(\"goo\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:goo\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"bullet_stone\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:bullet_stone\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner && p.Owner != orbital) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tvar timer = 0f;\n\n\t\t\t\torbital.Controller += (dt) => {\n\t\t\t\t\ttimer += dt;\n\n\t\t\t\t\tif (timer >= 2f) {\n\t\t\t\t\t\ttimer = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((o.GetComponent<RoomComponent>().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\to.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_gun_fire\", 2, 0.5f);\n\n\n\t\t\t\t\t\tvar a = orbital.AngleTo(o.GetComponent<AimComponent>().RealAim);\n\n\n\t\t\t\t\t\tvar builder = new ProjectileBuilder(o, \"small\") {\n\t\t\t\t\t\t\tColor = ProjectileColor.Yellow,\n\t\t\t\t\t\t\tLightRadius = 32f\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tbuilder.Shoot(a, 10f);\n\t\t\t\t\t\tbuilder.Move(a, 5f);\n\n\t\t\t\t\t\tvar projectile = builder.Build();\n\n\t\t\t\t\t\t/*Owner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\t\t\t\tProjectile = projectile,\n\t\t\t\t\t\t\tOwner = Owner\n\t\t\t\t\t\t});*/\n\n\t\t\t\t\t\tprojectile.Owner = orbital;\n\t\t\t\t\t\torbital.GetComponent<ScalableSliceComponent>().Animate();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"sword\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:sword_orbital\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new RectBodyComponent(0, 0, 9, 15, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Creature c && c.IsFriendly() != ((Creature) orbital.Owner).IsFriendly()) {\n\t\t\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-1, orbital);\n\t\t\t\t\t} else if (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"broken_stone\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\t\t\t\t\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:broken_stone\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\t\t\t\t\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (Rnd.Chance(20 - Run.Luck * 5)) {\n\t\t\t\t\t\t\tor.Done = true;\n\t\t\t\t\t\t\tAnimationUtil.Poof(or.Center);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"jelly\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:jelly\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 5, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Owner = o;\n\n\t\t\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\t\t\tvar d = b.Velocity.Length();\n\t\t\t\t\t\tvar a = b.Velocity.ToAngle() - Math.PI + Rnd.Float(-0.3f, 0.3f);\n\n\t\t\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (p.TryGetComponent<LightComponent>(out var l)) {\n\t\t\t\t\t\t\tl.Light.Color = MeleeArc.ReflectedColor;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"nano_orb\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:nano_orb\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\t\n\t\t\tDefine(\"planet\", o => {\n\t\t\t\tvar orbital = new Orbital();\n\t\t\t\to.Area.Add(orbital);\n\n\t\t\t\tvar g = new ScalableSliceComponent(\"items\", \"bk:earth\") {\n\t\t\t\t\tShadowZ = 2\n\t\t\t\t};\n\n\t\t\t\torbital.AddComponent(g);\n\t\t\t\tg.AddShadow();\n\t\t\t\tg.SetOwnerSize();\n\n\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true));\n\t\t\t\t\n\t\t\t\torbital.OnCollision += (or, e) => {\n\t\t\t\t\tif (e is Projectile p && p.Owner != orbital.Owner) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t\tvar s = (ScalableSliceComponent) or.GraphicsComponent;\n\n\t\t\t\t\t\tif (Math.Abs(s.Scale.Y - 1) > 0.01f) {\n\t\t\t\t\t\t\treturn; // Already animating\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tTween.To(1, 1.5f, x => s.Scale.X = x, 0.3f);\n\t\t\t\t\t\tTween.To(0, 1, x => s.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\t\t\t\ts.Sprite = CommonAse.Items.GetSlice(planets[Rnd.Int(planets.Length)]);\n\t\t\t\t\t\t\ts.SetOwnerSize();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\torbital.RemoveComponent<CircleBodyComponent>();\n\t\t\t\t\t\t\torbital.AddComponent(new CircleBodyComponent(0, 0, Math.Min(orbital.Width, orbital.Height) / 2f, BodyType.Dynamic, true));\n\n\t\t\t\t\t\t\tTween.To(1, 1.5f, x => s.Scale.X = x, 0.4f, Ease.ElasticOut);\n\t\t\t\t\t\t\tTween.To(1, 0, x => s.Scale.Y = x, 0.5f, Ease.ElasticOut);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t\n\t\t\tDefine(\"marshmallow\", o => {\n\t\t\t\tvar orbital = new Marshmallow();\n\t\t\t\to.Area.Add(orbital);\n\t\t\t\treturn orbital;\n\t\t\t});\n\t\t}\n\n\t\tprivate static string[] planets = {\n\t\t\t\"bk:mercury\", \"bk:venus\", \"bk:earth\",\n\t\t\t\"bk:moon\", \"bk:mars\", \"bk:jupiter\",\n\t\t\t\"bk:saturn\", \"bk:uranus\", \"bk:neptune\"\n\t\t};\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/orbital/Prism.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.math;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.orbital {\n\tpublic class Prism : Orbital {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 12;\n\t\t\tHeight = 14;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"prism\") {\n\t\t\t\tShadowOffset = -2\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true));\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Projectile p && !p.HasFlag(ProjectileFlags.Artificial) && p.Owner == Owner && p.Parent == null) {\n\t\t\t\tvar tt = Rnd.Int(4, 8);\n\t\t\t\tvar body = p.GetAnyComponent<BodyComponent>();\n\n\t\t\t\tvar builder = new ProjectileBuilder(Owner, p.Slice) {\n\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\tParent = p\n\t\t\t\t};\n\n\t\t\t\tbuilder.AddFlags(ProjectileFlags.Artificial);\n\n\t\t\t\tfor (var i = 0; i < tt; i++) {\n\t\t\t\t\tbuilder.Shoot(body.Angle + (i - tt * 0.5f) * 0.1f, body.Velocity.Length() * 0.05f);\n\n\t\t\t\t\tvar pr = builder.Build();\n\t\t\t\t\t\n\t\t\t\t\tpr.Color = ProjectileColor.Rainbow[i];\n\t\t\t\t\tpr.Position = p.Position;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tAnimationUtil.Poof(Center, Depth + 1);\n\t\t\t\tp.Done = true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/pc/Controller.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.pc {\n\tpublic class Controller : Entity {\n\t\tpublic Pico Pico;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tHeight = 9;\n\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, false));\n\t\t\tAddComponent(new SensorBodyComponent(-10, -10, Width + 20, Height + 20, BodyType.Static, true));\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"controller\"));\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tPico.TurnOn();\n\t\t\tPico.Entity = e;\n\t\t\t\n\t\t\te.RemoveComponent<PlayerInputComponent>();\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/pc/Pico.cs",
    "content": "using BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.pc {\n\tpublic class Pico : SaveableEntity, PlaceableEntity {\n\t\tprivate bool on;\n\t\tprivate Controller controller;\n\t\t// private Emulator emulator;\n\t\t// private MonoGameGraphicsBackend backend;\n\t\tprivate const float UpdateTime30 = 1 / 30f;\n\t\tprivate const float UpdateTime60 = 1 / 60f;\n\t\tprivate float deltaUpdate30, deltaUpdate60, deltaDraw;\n\t\tprivate string cart = \"ma_puzzle\";\n\n\t\tpublic Entity Entity;\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tcontroller = new Controller();\n\t\t\tArea.Add(controller);\n\n\t\t\tcontroller.Y = Bottom + 16;\n\t\t\tcontroller.X = X + 16;\n\t\t\tcontroller.Pico = this;\n\t\t\t\n\t\t\tArea.Add(new RenderTrigger(this, RenderDisplay, Layers.Console));\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 138;\n\t\t\tHeight = 150 + 5;\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, false));\n\t\t\tAddComponent(new SliceComponent(\"props\", \"pico\"));\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tpublic void TurnOn() {\n\t\t\tif (on) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/*if (emulator == null) {\n\t\t\t\tbackend = new MonoGameGraphicsBackend(Engine.GraphicsDevice);\n\t\t\t\temulator = new Emulator(backend, new MonoGameAudioBackend(), new MonoGameInputBackend());\n\t\t\t}*/\n\t\t\t\n\t\t\ton = true;\n\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tCamera.Instance.Position = Position + new Vector2(Display.Width * 0.25f, 0);// + new Vector2(5 + 64, 16 + 64);\n\n\t\t\tLoadCart();\n\t\t}\n\n\t\tprivate void LoadCart() {\n\t\t\t/*if (!emulator.CartridgeLoader.Load($\"Content/Carts/{cart}.p8\")) {\n\t\t\t\tLog.Error($\"Failed to load the cart {cart}\");\n\t\t\t}*/\n\t\t}\n\n\t\tpublic void TurnOff() {\n\t\t\tif (!on) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tEntity.AddComponent(new PlayerInputComponent());\n\t\t\tEntity = null;\n\t\t\t\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\n\t\t\ton = false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!on) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Input.WasPressed(Controls.Pause, GamepadComponent.Current, true)) {\n\t\t\t\tTurnOff();\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tdeltaUpdate60 += dt;\n\t\t\tdeltaUpdate30 += dt;\n\n\t\t\t/*\n\t\t\twhile (deltaUpdate30 >= UpdateTime30) {\n\t\t\t\tdeltaUpdate30 -= UpdateTime30;\n\t\t\t\temulator.Update30();\n\t\t\t}\n\t\t\t\n\t\t\twhile (deltaUpdate60 >= UpdateTime60) {\n\t\t\t\tdeltaUpdate60 -= UpdateTime60;\n\t\t\t\temulator.Update60();\n\t\t\t}*/\n\t\t}\n\t\t\n\t\tpublic void RenderDisplay() {\n\t\t\t/*if (!on) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar u = emulator.CartridgeLoader.HighFps ? UpdateTime60 : UpdateTime30;\n\t\t\t\n\t\t\tdeltaDraw += Engine.Delta;\n\n\t\t\twhile (deltaDraw >= u) {\n\t\t\t\tdeltaDraw -= u;\n\t\t\t\temulator.Graphics.drawCalls = 0;\n\t\t\t\temulator.Draw();\n\t\t\t}\n\n\t\t\temulator.Graphics.Flip();\n\t\t\tGraphics.Render(backend.Surface, Position + new Vector2(5, 16));*/\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tImGui.InputText(\"Cart\", ref cart, 64);\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Load\")) {\n\t\t\t\tLoadCart();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/pool/Pool.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.pool {\n\tpublic class Pool<T> {\n\t\tprotected List<float> Chances = new List<float>();\n\t\tprotected List<T> Classes = new List<T>();\n\n\t\tpublic int Size => Classes.Count;\n\n\t\tpublic virtual T Generate() {\n\t\t\tvar I = Rnd.Chances(Chances);\n\n\t\t\tif (I == -1) {\n\t\t\t\tLog.Error(\"-1 as pool result!\");\n\t\t\t\treturn default(T);\n\t\t\t}\n\n\t\t\treturn Classes[I];\n\t\t}\n\n\t\tpublic void Add(T Type, float Chance) {\n\t\t\tClasses.Add(Type);\n\t\t\tChances.Add(Chance);\n\t\t}\n\n\t\tpublic void Clear() {\n\t\t\tClasses.Clear();\n\t\t\tChances.Clear();\n\t\t}\n\n\t\tpublic void AddFrom(Pool<T> Pool) {\n\t\t\tClasses.AddRange(Pool.Classes);\n\t\t\tChances.AddRange(Pool.Chances);\n\t\t}\n\n\t\tpublic T Get(int i) {\n\t\t\treturn Classes[i];\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/BasicProjectileGraphicsComponent.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.graphics;\nusing Lens.graphics.animation;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class BasicProjectileGraphicsComponent : SliceComponent {\n\t\tpublic BasicProjectileGraphicsComponent(string image, string slice) : base(image, slice) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void RenderLight() {\n\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/Laser.cs",
    "content": "using System;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.level;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Solver;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class Laser : Projectile {\n\t\tpublic float LifeTime = 1.5f;\n\t\tpublic bool Dynamic = true;\n\t\tpublic float AdditionalAngle;\n\t\tpublic float Range = 15f;\n\t\tpublic Vector2 End;\n\t\tpublic bool PlayerRotated;\n\n\t\tprivate float angle;\n\n\t\tpublic float Angle {\n\t\t\tget => angle;\n\t\t\tset {\n\t\t\t\tangle = value;\n\n\t\t\t\tif (BodyComponent?.Body != null) {\n\t\t\t\t\tBodyComponent.Body.Rotation = angle + AdditionalAngle;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static Laser Make(Entity owner, float a, float additional, Item item = null, float damage = 1, float scale = 1f, float range = -1, Laser parent = null) {\n\t\t\tif (owner is Item i) {\n\t\t\t\titem = i;\n\t\t\t\towner = i.Owner;\n\t\t\t}\n\n\t\t\tvar projectile = new Laser {\n\t\t\t\tOwner = owner,\n\t\t\t\tFirstOwner = owner,\n\t\t\t\tDamage = damage,\n\t\t\t\tFlags = 0,\n\t\t\t\tSlice = \"laser\",\n\t\t\t\tBounce = 0,\n\t\t\t\tScale = scale,\n\t\t\t\tColor = ProjectileColor.Red,\n\t\t\t\tParent = parent,\n\t\t\t\tItem = item\n\t\t\t};\n\n\t\t\towner.Area.Add(projectile);\n\n\t\t\tvar graphics = new LaserGraphicsComponent(\"projectiles\", \"laser\");\n\t\t\tprojectile.AddComponent(graphics);\n\n\t\t\tif (range > 0) {\n\t\t\t\tprojectile.Range = range;\n\t\t\t}\n\n\t\t\tif (parent != null) {\n\t\t\t\tprojectile.Scale *= 0.7f;\n\t\t\t\tprojectile.Range *= 0.5f;\n\t\t\t}\n\n\t\t\tprojectile.Position = owner.Center;\n\n\t\t\towner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\tOwner = owner,\n\t\t\t\tItem = item,\n\t\t\t\tProjectile = projectile\n\t\t\t});\n\n\t\t\tprojectile.Width = 32;\n\t\t\tprojectile.Height = 9 * projectile.Scale;\n\n\t\t\tprojectile.CreateBody();\n\n\t\t\tprojectile.AdditionalAngle = additional;\n\t\t\tprojectile.Angle = a;\n\n\t\t\treturn projectile;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddTag(Tags.Laser);\n\t\t}\n\n\t\tprivate void CreateBody() {\n\t\t\tAddComponent(new RectBodyComponent(0, -Height * 0.5f, Width, Height));\n\t\t}\n\n\t\tprivate static bool RayShouldCollide(Entity entity) {\n\t\t\treturn entity is ProjectileLevelBody || entity is Level || entity is Door;\n\t\t}\n\n\t\tpublic override bool BreaksFrom(Entity entity, BodyComponent body) {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic void Recalculate() {\n\t\t\tvar min = 1f;\n\n\t\t\tVector2 closest;\n\t\t\tvar aim = Owner.GetComponent<AimComponent>();\n\n\t\t\tPosition = aim.Center;\n\n\t\t\tvar from = Position;\n\t\t\t\n\t\t\tif (PlayerRotated) {\n\t\t\t\tBodyComponent.Body.Rotation = angle = (aim.RealAim - from).ToAngle();\n\t\t\t}\n\n\t\t\tclosest = Position + MathUtils.CreateVector(BodyComponent.Body.Rotation, Range * 5);\n\n\t\t\tPhysics.World.RayCast((fixture, point, normal, fraction) => {\n\t\t\t\tif (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) {\n\t\t\t\t\tmin = fraction;\n\t\t\t\t\tclosest = point;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn min;\n\t\t\t}, from, closest);\n\n\t\t\tvar v = (from - closest);\n\t\t\tvar len = v.Length();\n\n\t\t\tif (Math.Abs(len - Width) > 1) {\n\t\t\t\tWidth = len;\n\t\t\t\tBodyComponent.Resize(0, -Height * 0.5f, Width, Height);\n\t\t\t}\n\n\t\t\tBodyComponent.Body.Rotation = angle + AdditionalAngle;\n\t\t\tEnd = Position + MathUtils.CreateVector(BodyComponent.Body.Rotation, Width);\n\t\t}\n\n\t\tprivate float lastClear;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tlastClear += dt;\n\n\t\t\tif (lastClear >= 0.05f) {\n\t\t\t\tlastClear = 0;\n\t\t\t\tEntitiesHurt.Clear();\n\t\t\t}\n\n\t\t\tif (LifeTime > 0) {\n\t\t\t\tLifeTime -= dt;\n\n\t\t\t\tif (LifeTime <= 0) {\n\t\t\t\t\tBreak();\n\t\t\t\t\tDone = true;\n\t\t\t\t\tLifeTime = 0;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Dynamic) {\n\t\t\t\tRecalculate();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Resize(float newScale) {\n\t\t\tScale = newScale;\n\t\t\tHeight = 9 * Scale;\n\n\t\t\tGetComponent<RectBodyComponent>().Resize(0, 0, Width, Height, true);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/LaserGraphicsComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing Lens.assets;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class LaserGraphicsComponent : BasicProjectileGraphicsComponent {\n\t\tprivate TextureRegion aura;\n\t\tprivate TextureRegion light;\n\t\tprivate TextureRegion end;\n\t\tprivate TextureRegion endAura;\n\t\tprivate TextureRegion endLight;\n\t\t\n\t\tprivate Vector2 origin;\n\t\tprivate Vector2 centerOrigin;\n\t\tprivate Vector2 lightOrigin;\n\t\tpublic float Rotation => ((Projectile) Entity).GetAnyComponent<BodyComponent>().Body.Rotation;\n\t\t\n\t\tpublic LaserGraphicsComponent(string image, string slice) : base(image, slice) {\n\t\t\tvar a = Animations.Get(image);\n\t\t\t\n\t\t\taura = a.GetSlice($\"{slice}_aura\", false);\n\t\t\tlight = a.GetSlice($\"{slice}_light\", false);\n\t\t\tend = a.GetSlice(\"end_aura\", false);\n\t\t\tendAura = a.GetSlice(\"end\", false);\n\t\t\tendLight = a.GetSlice(\"end_light\", false);\n\n\t\t\torigin = new Vector2(0, aura.Height * 0.5f);\n\t\t\tcenterOrigin = new Vector2(0, Sprite.Height * 0.5f);\n\t\t\tlightOrigin = new Vector2(0, light.Height * 0.5f);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar scale = new Vector2(Entity.Width / aura.Width, Entity.Height / aura.Height);\n\t\t\tvar p = (Laser) Entity;\n\t\t\tvar a = Rotation;\n\n\t\t\tGraphics.Color = p.Color;\n\t\t\tGraphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * 255);\n\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position + new Vector2(0, 6), a, centerOrigin, scale);\n\t\t\t} else {\n\t\t\t\tGraphics.Render(Sprite, Entity.Position, a, centerOrigin, scale);\n\t\t\t\t\n\t\t\t\tvar sc = new Vector2(p.Scale);\n\t\t\t\tvar aa = a + (float) Math.PI * 0.25f;\n\n\t\t\t\tGraphics.Render(endAura, Entity.Position, aa, endAura.Center, sc);\n\t\t\t\tGraphics.Render(endAura, p.End, aa, endAura.Center, sc);\n\t\t\t}\n\n\t\t\tGraphics.Color.A = 255;\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t\t\n\t\tpublic void RenderTopLight() {\n\t\t\tvar p = (Laser) Entity;\n\t\t\tvar s = p.Scale;\n\t\t\tvar a = Rotation;\n\n\t\t\tGraphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * 255);\n\n\t\t\tvar sc = new Vector2(p.Scale);\n\t\t\tvar aa = a + (float) Math.PI * 0.25f;\n\n\t\t\tGraphics.Render(endLight, Entity.Position, aa, endLight.Center, sc);\n\t\t\tGraphics.Render(endLight, p.End, aa, endLight.Center, sc);\n\t\t\t\n\t\t\tGraphics.Render(light, Entity.Position, a, lightOrigin, new Vector2(Entity.Width, s));\n\n\t\t\tGraphics.Color.A = 255;\n\t\t}\n\n\t\tpublic override void RenderLight() {\n\t\t\tvar p = (Laser) Entity;\n\t\t\tvar a = Rotation;\n\t\t\tvar sc = new Vector2(p.Scale);\n\n\t\t\tGraphics.Color = p.Color;\n\t\t\tGraphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * Lights.AuraAlpha);\n\t\t\t\n\t\t\tvar aa = a + (float) Math.PI * 0.25f;\n\t\t\tGraphics.Render(end, Entity.Position, aa, end.Center, sc);\n\t\t\tGraphics.Render(end, p.End, aa, end.Center, sc);\n\t\t\t\n\t\t\tGraphics.Render(aura, Entity.Position, a, origin, new Vector2(Entity.Width / aura.Width, Entity.Height / aura.Height));\n\t\t\tGraphics.Color.A = 255;\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/LetterTemplateData.cs",
    "content": "using System.Collections.Generic;\r\n\r\nnamespace BurningKnight.entity.projectile {\r\n\tpublic static class LetterTemplateData {\r\n\t\tpublic static Dictionary<char, string[]> Data = new Dictionary<char, string[]>();\r\n\t\t\r\n\t\tstatic LetterTemplateData() {\r\n\t\t\tData['a'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['b'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['c'] = new[] {\r\n\t\t\t\t\" xx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\" xx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['d'] = new[] {\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['e'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['f'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t};\r\n\r\n\t\t\tData['g'] = new[] {\r\n\t\t\t\t\" xx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['h'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['i'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['j'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\"xx \",\r\n\t\t\t};\r\n\r\n\t\t\tData['k'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['l'] = new[] {\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['m'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['n'] = new[] {\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['o'] = new[] {\r\n\t\t\t\t\" xx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t};\r\n\r\n\t\t\tData['p'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t};\r\n\r\n\t\t\tData['q'] = new[] {\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\" xx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['r'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['s'] = new[] {\r\n\t\t\t\t\" xx\",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"  x\",\r\n\t\t\t\t\"xx \",\r\n\t\t\t};\r\n\r\n\t\t\tData['t'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\" x \",\r\n\t\t\t};\r\n\r\n\t\t\tData['u'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\" xx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['v'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\" x \",\r\n\t\t\t};\r\n\r\n\t\t\tData['w'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['x'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t};\r\n\r\n\t\t\tData['y'] = new[] {\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"x x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"  x\",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\t\t\tData['z'] = new[] {\r\n\t\t\t\t\"xxx\",\r\n\t\t\t\t\"  x\",\r\n\t\t\t\t\" x \",\r\n\t\t\t\t\"x  \",\r\n\t\t\t\t\"xxx\",\r\n\t\t\t};\r\n\r\n\r\n\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/Missile.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class Missile : Projectile {\n\t\tprivate const float MinUpTime = 2f;\n\t\t\n\t\tprivate Entity target;\n\t\tprivate bool goingDown;\n\t\tprivate float toY;\n\t\tprivate float shadowSize;\n\t\tprivate bool exploded;\n\t\tpublic bool HurtOwner = true;\n\t\t\n\t\tpublic Missile(Entity owner, Entity tar) {\n\t\t\ttarget = tar;\n\t\t\tOwner = owner;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tSlice = \"missile\";\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysVisible = true;\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tvar graphics = new ProjectileGraphicsComponent(\"projectiles\", Slice);\n\n\t\t\tAddComponent(graphics);\n\t\t\tAddTag(Tags.MobProjectile);\n\n\t\t\tvar w = graphics.Sprite.Source.Width;\n\t\t\tvar h = graphics.Sprite.Source.Height;\n\n\t\t\tWidth = w;\n\t\t\tHeight = h;\n\t\t\tCenter = Owner.Center;\n\t\t\tT = MinUpTime + 1;\n\n\t\t\tRemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\n\t\t\tAddComponent(new RectBodyComponent(0, 0, w, h));\n\t\t\t\n\t\t\tBodyComponent.Body.IsBullet = true;\n\t\t\tBodyComponent.Body.LinearVelocity = new Vector2(0, -100f);\n\n\t\t\tOwner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\tOwner = Owner,\n\t\t\t\tProjectile = this\n\t\t\t});\n\n\t\t\tDepth = Layers.TileLights;\n\t\t\t\n\t\t\tCollisionFilterComponent.Add(this, (p, e) => {\n\t\t\t\tif (e is Level || e is Prop) {\n\t\t\t\t\treturn CollisionResult.Disable;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn CollisionResult.Default;\n\t\t\t});\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tProjectileCallbacks.AttachDeathCallback(this, (p, e, t) => {\n\t\t\t\tExplosionMaker.Make(this, damageOwner: HurtOwner);\n\t\t\t\texploded = true;\n\t\t\t});\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent) {\n\t\t\t\treturn false; // Ignore all collision\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override bool BreaksFrom(Entity entity, BodyComponent body) {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tPosition += BodyComponent.Velocity * dt;\n\n\t\t\tif (goingDown) {\n\t\t\t\tif (Bottom >= toY && !exploded) {\n\t\t\t\t\tBreak();\n\t\t\t\t}\n\t\t\t} else if (T <= 1f && Bottom < Camera.Instance.Y) {\n\t\t\t\tT = MinUpTime + 1;\n\t\t\t\tgoingDown = true;\n\t\t\t\tCenterX = target.CenterX;\n\t\t\t\ttoY = target.Bottom;\n\t\t\t\tGraphicsComponent.FlippedVerticaly = true;\n\t\t\t\tBodyComponent.Body.LinearVelocity = new Vector2(0, 100f);\n\n\t\t\t\tTween.To(16, 0, x => shadowSize = x, 1f);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void RenderShadow() {\n\t\t\tif (goingDown) {\n\t\t\t\tGraphics.Batch.DrawCircle(CenterX, toY, shadowSize, 16, ColorUtils.WhiteColor, 2f);\n\t\t\t\tGraphics.Batch.DrawCircle(CenterX, toY, shadowSize * 0.5f, 16, ColorUtils.WhiteColor, 2f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/OldProjectile.cs",
    "content": "﻿using Lens.entity;\n\n/*\n * Ancient projectile class, reworked a tiny bit to look less messy\n * Still is a huge mess, and has way too much data per bullet and pretty much no caps\n */\nnamespace BurningKnight.entity.projectile {\n\t/*public class OldProjectile : Entity, CollisionFilterEntity {\n\t\tpublic ProjectileDeathCallback OnDeath;\n\t\tpublic ProjectileCallbacks.UpdateCallback Controller;\n\t\tpublic ProjectileHurtCallback OnHurt;\n\t\tpublic ProjectileNearingDeathCallback NearDeath;\n\t\tpublic ProjectileCollisionCallback OnCollision;\n\t\tpublic Projectile Parent;\n\t\tpublic Color Color = ProjectileColor.Red;\n\n\t\tpublic ProjectilePattern Pattern;\n\t\tpublic BodyComponent BodyComponent;\n\t\tpublic Entity Owner;\n\t\tpublic Entity FirstOwner;\n\t\tpublic Item Item;\n\t\tpublic List<Entity> EntitiesHurt = new List<Entity>();\n\n\t\tpublic string Slice;\n\n\t\t// can be in collision callback\n\t\tpublic bool BreakOther;\n\n\t\t// melee\n\t\tpublic bool CanBeReflected = true;\n\t\tpublic bool CanBeBroken = true;\n\n\t\t// Collision\n\t\tpublic bool Spectral;\n\t\tpublic bool DieOffscreen;\n\t\tpublic bool HurtsEveryone;\n\t\tpublic bool PreventSpectralBreak;\n\t\tpublic bool BreaksFromWalls = true;\n\t\tpublic int BounceLeft;\n\n\t\tpublic bool Artificial;\n\t\tpublic bool Dying;\n\t\tpublic bool Rotates;\n\t\tpublic bool ManualRotation;\n\t\tpublic bool Scourged;\n\t\tpublic bool Boost = true;\n\t\tpublic bool PreventDespawn;\n\t\tpublic bool IndicateDeath;\n\n\t\tpublic bool NearingDeath => T >= Range - 0.9f && (Range - T) % 0.6f >= 0.3f;\n\n\t\tpublic float Damage = 1;\n\t\tpublic float Range = -1;\n\t\tpublic float T;\n\t\tpublic float FlashTimer;\n\t\tpublic float Scale = 1;\n\n\t\tpublic static Projectile Make(Entity owner, string slice, double angle = 0, \n\t\t\tfloat speed = 0, bool circle = true, int bounce = 0, Projectile parent = null, \n\t\t\tfloat scale = 1, float damage = 1, Item item = null, float range = -1) {\n\n\t\t\tif (slice == \"default\") {\n\t\t\t\tslice = \"rect\";\n\t\t\t}\n\n\t\t\tvar projectile = new Projectile();\n\t\t\towner.Area.Add(projectile);\n\t\t\t\n\t\t\tif (owner is Mob && Rnd.Chance(LevelSave.MobDestructionChance)) {\n\t\t\t\tprojectile.Done = true;\n\t\t\t\treturn projectile;\n\t\t\t}\n\n\t\t\tprojectile.Range = range;\n\t\t\t\n\t\t\tif (parent != null) {\n\t\t\t\tprojectile.Color = parent.Color;\n\t\t\t} else if (owner is Player) {\n\t\t\t\tprojectile.Color = ProjectileColor.Yellow;\n\t\t\t}\n\n\t\t\tprojectile.Boost = owner is Player;\n\t\t\tprojectile.Damage = damage;\n\t\t\tprojectile.Scale = scale;\n\t\t\tprojectile.Slice = slice;\n\t\t\tprojectile.Parent = parent;\n\t\t\tprojectile.Owner = owner;\n\t\t\tprojectile.FirstOwner = owner;\n\t\t\tprojectile.BounceLeft = bounce;\n\t\t\t\n\t\t\tvar graphics = new ProjectileGraphicsComponent(\"projectiles\", slice);\n\t\t\tprojectile.AddComponent(graphics);\n\n\t\t\tif (graphics.Sprite == null) {\n\t\t\t\tLog.Error($\"Not found projectile slice {slice}\");\n\t\t\t\tprojectile.Done = true;\n\t\t\t\treturn projectile;\n\t\t\t}\n\t\t\t\n\t\t\towner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\tOwner = owner,\n\t\t\t\tItem = item,\n\t\t\t\tProjectile = projectile\n\t\t\t});\n\n\t\t\tscale = projectile.Scale;\n\n\t\t\tvar w = graphics.Sprite.Source.Width * scale;\n\t\t\tvar h = graphics.Sprite.Source.Height * scale;\n\n\t\t\tprojectile.Width = w;\n\t\t\tprojectile.Height = h;\n\t\t\tprojectile.Center = owner.Center;\n\n\t\t\tif (owner is Mob m && m.HasPrefix) {\n\t\t\t\tprojectile.Scourged = true;\n\t\t\t\tprojectile.Color = ProjectileColor.Black;\n\t\t\t\tprojectile.AddLight(64, ProjectileColor.Black);\n\t\t\t}\n\n\t\t\tif (circle) {\n\t\t\t\tprojectile.AddComponent(projectile.BodyComponent = new CircleBodyComponent(0, 0, w / 2f, BodyType.Dynamic, false, true));\n\t\t\t} else {\n\t\t\t\tprojectile.AddComponent(projectile.BodyComponent = new RectBodyComponent(0, 0, w, h, BodyType.Dynamic, false, true));\n\t\t\t}\n\t\t\t\n\t\t\tprojectile.BodyComponent.Body.Restitution = 1;\n\t\t\tprojectile.BodyComponent.Body.Friction = 0;\n\t\t\tprojectile.BodyComponent.Body.IsBullet = true;\n\n\t\t\tprojectile.BodyComponent.Body.Rotation = (float) angle;\n\n\t\t\tif (owner.TryGetComponent<BuffsComponent>(out var buffs) && buffs.Has<SlowBuff>()) {\n\t\t\t\tspeed *= 0.5f;\n\t\t\t}\n\t\t\t\n\t\t\tspeed *= 10f;\n\n\t\t\tif (Math.Abs(speed) > 0.01f) {\n\t\t\t\tprojectile.BodyComponent.Velocity =\n\t\t\t\t\tnew Vector2((float) (Math.Cos(angle) * speed), (float) (Math.Sin(angle) * speed));\n\t\t\t}\n\t\t\t\n\t\t\tif (parent != null && parent.TryGetComponent<LightComponent>(out var l)) {\n\t\t\t\tprojectile.AddLight(l.Light.Radius, l.Light.Color);\n\t\t\t}\n\t\t\t\n\t\t\treturn projectile;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddTag(Tags.Projectile);\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tprotected virtual void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic void AddLight(float radius, Color color) {\n\t\t\tif (HasComponent<LightComponent>() || Area.Tagged[Tags.Projectile].Count > 40) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, radius * Scale, color));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tT += dt;\n\n\t\t\tif (NearDeath != null && NearingDeath) {\n\t\t\t\tNearDeath(this);\n\t\t\t\tNearDeath = null;\n\t\t\t}\n\n\t\t\tif (FlashTimer > 0) {\n\t\t\t\tFlashTimer -= dt;\n\t\t\t}\n\n\t\t\tif (Dying) {\n\t\t\t\tScale -= dt * 10;\n\n\t\t\t\tif (Scale <= 0) {\n\t\t\t\t\tScale = 0;\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ((Range > -1 && T >= Range) || (!BreaksFromWalls && Spectral && !OnScreen && !PreventSpectralBreak)) {\n\t\t\t\tAnimateDeath(null, true);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tController?.Invoke(this, dt);\n\n\t\t\tif (Rotates) {\n\t\t\t\tBodyComponent.Body.Rotation += dt * 10;\n\t\t\t} else if (!ManualRotation) {\n\t\t\t\tBodyComponent.Body.Rotation = BodyComponent.Body.LinearVelocity.ToAngle();\n\t\t\t}\n\t\t\t\n\t\t\tif (!OnScreen && DieOffscreen) {\n\t\t\t\tBreak(null);\n\t\t\t}\n\n\t\t\tif (Boost) {\n\t\t\t\tPosition += BodyComponent.Body.LinearVelocity * (dt);\n\t\t\t}\n\t\t\t\n\t    if (!PreventDespawn && Pattern == null && BodyComponent.Velocity.Length() < 0.1f) {\n\t\t    Break(null);\n\t    }\n\t\t}\n\n\t\tpublic virtual bool BreaksFrom(Entity entity, BodyComponent body) {\n\t\t\tif (entity is Projectile p && p.BreakOther && p.Owner != Owner) {\n\t\t\t\tp.Break(this);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar r = false;\n\t\t\t\n\t\t\tif (TryGetComponent<CollisionFilterComponent>(out var c)) {\n\t\t\t\tvar rs = c.Invoke(entity);\n\t\t\t\t\n\t\t\t\tif (rs == CollisionResult.Disable) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (rs == CollisionResult.Enable) {\n\t\t\t\t\tr = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((entity == Owner || (Owner is Pet pt && entity == pt.Owner) || (Owner is Orbital o && entity == o.Owner)) && (!HurtsEveryone || T < 1f)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is Turret) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (!r && entity is creature.bk.BurningKnight) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is PlatformBorder || entity is MovingPlatform || entity is Spikes || entity is ShopStand || entity is Statue) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Owner is RoomControllable && entity is Mob) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!BreaksFromWalls && entity is RoomControllable && entity != Owner) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (CanHitOwner && entity == Owner) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (entity is Creature && !HurtsEveryone && Owner is Mob == entity is Mob) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn (!(entity is Creature || entity is Level || entity is Tree)) && \n\t\t\t       (BreaksFromWalls && IsWall(entity, body))\n\t\t\t        || entity.HasComponent<HealthComponent>();\n\t\t}\n\n\t\tprivate bool IsWall(Entity entity, BodyComponent body) {\n\t\t\treturn (entity is ProjectileLevelBody || (!Spectral && entity is HalfProjectileLevel) || entity is Prop ||\n\t\t\t        (entity is Door d && !d.Open && !(body is DoorBodyComponent || d is CustomDoor)));\n\t\t}\n\n\t\tpublic bool CanHitOwner;\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (Dying) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ev.Entity is Creature c && c.IgnoresProjectiles()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (EntitiesHurt.Contains(ev.Entity)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (OnCollision != null && OnCollision(this, ev.Entity)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (((HurtsEveryone && (ev.Entity != Owner) || T > 1f) || (\n\t\t\t\t\t    (CanHitOwner && ev.Entity == Owner && T > 0.3f) \n\t\t\t\t\t    || (ev.Entity != Owner && (!(Owner is Pet pt) || pt.Owner != ev.Entity)\n\t\t\t\t\t                           && (!(Owner is Orbital or) || or.Owner != ev.Entity)\n\t\t\t\t\t        && !(Owner is RoomControllable && ev.Entity is Mob) \n\t\t\t\t\t        && (\n\t\t\t\t\t\t        !(Owner is Creature ac) \n\t\t\t\t\t\t        || !(ev.Entity is Creature bc) \n\t\t\t\t\t\t        || (ac.IsFriendly() != bc.IsFriendly() || (bc.TryGetComponent<BuffsComponent>(out var bf) && bf.Has<CharmedBuff>())) \n\t\t\t\t\t\t        || bc is ShopKeeper || ac is Player\n\t\t\t\t\t        )\n\t\t\t\t\t    )\n\t\t\t\t    )) && ev.Entity.TryGetComponent<HealthComponent>(out var health) && (HurtsEveryone || CanHitOwner || !(ev.Entity is Player) || !(Owner is Player))\n\t\t\t\t\t\t&& !(Owner is Pet ppt && ppt.Owner == ev.Entity)) {\n\n\t\t\t\t\tvar h = health.ModifyHealth(-Damage, Owner);\n\n\t\t\t\t\tif (FirstOwner is Mob && FirstOwner == ev.Entity && Owner is Player && health.Dead && T >= 0.2f) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:return_to_sender\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tEntitiesHurt.Add(ev.Entity);\n\n\t\t\t\t\tif (h) {\n\t\t\t\t\t\tOnHurt?.Invoke(this, ev.Entity);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (((HurtsEveryone && (ev.Entity != Owner) || T > 1f) || (\n\t\t\t\t\t    (CanHitOwner && ev.Entity == Owner && T > 0.3f)\n\t\t\t\t\t    || (ev.Entity != Owner && (!(Owner is Pet pt) || pt.Owner != ev.Entity)\n\t\t\t\t\t                           && (!(Owner is Orbital or) || or.Owner != ev.Entity)\n\t\t\t\t\t        && !(Owner is RoomControllable && ev.Entity is Mob)\n\t\t\t\t\t        && (\n\t\t\t\t\t\t        !(Owner is Creature ac)\n\t\t\t\t\t\t        || !(ev.Entity is Creature bc)\n\t\t\t\t\t\t        || (ac.IsFriendly() != bc.IsFriendly() || (bc.TryGetComponent<BuffsComponent>(out var bf) && bf.Has<CharmedBuff>()))\n\t\t\t\t\t\t        || bc is ShopKeeper || ac is Player\n\t\t\t\t\t        )\n\t\t\t\t\t    )\n\t\t\t\t    )) && ev.Entity.TryGetComponent<HealthComponent>(out var health) && (HurtsEveryone || CanHitOwner || !(ev.Entity is Player) || !(Owner is Player))\n\t\t\t\t\t\t&& !(Owner is Pet ppt && ppt.Owner == ev.Entity)) {\n\n\t\t\t\t\tvar h = health.ModifyHealth(-Damage, Owner);\n\n\t\t\t\t\tif (FirstOwner is Mob && FirstOwner == ev.Entity && Owner is Player && health.Dead && T >= 0.2f) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:return_to_sender\");\n\t\t\t\t\t}\n\n\t\t\t\t\tEntitiesHurt.Add(ev.Entity);\n\n\t\t\t\t\tif (h) {\n\t\t\t\t\t\tOnHurt?.Invoke(this, ev.Entity);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\t\tvar mute = false;\n\t\t\t\t\n\t\t\t\tif (Run.Level.Biome is IceBiome && !(Owner is creature.bk.BurningKnight) && ev.Entity is ProjectileLevelBody lvl) {\n\t\t\t\t\tif (lvl.Break(CenterX, CenterY)) {\n\t\t\t\t\t\tmute = true;\n\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"level_snow_break\", 3);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (BreaksFrom(ev.Entity, ev.Body)) {\n\t\t\t\t\tif (BounceLeft > 0) {\n\t\t\t\t\t\tBounceLeft -= 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (!mute && IsWall(ev.Entity, ev.Body)) {\n\t\t\t\t\t\t\tif (Owner is Player) {\n\t\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"projectile_wall\", 2, 0.5f);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomized(\"projectile_wall_enemy\", 0.5f);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tAnimateDeath(ev.Entity);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\tif (entity == Owner) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is Tombstone && !(Owner is Player)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn !(entity is Level || entity is HalfWall) && !(entity is Door d && d.Open) && !((Spectral && (entity is Prop || entity is Door || entity is HalfProjectileLevel || entity is ProjectileLevelBody)) || entity is Chasm || entity is MovingPlatform || entity is PlatformBorder || (entity is Creature && Owner is Mob == entity is Mob) || entity is Creature || entity is Item || entity is Projectile || entity is ShopStand || entity is Bomb);\n\t\t}\n\n\t\tpublic void Break(Entity from = null) {\n\t\t\tAnimateDeath(from);\n\t\t}\n\t\t\n\t\tprotected virtual void AnimateDeath(Entity from, bool timeout = false) {\n\t\t\tif (Dying) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDying = true;\n\n\t\t\ttry {\n\t\t\t\tvar l = Math.Min(15, BodyComponent.Velocity.Length());\n\t\t\t\t\n\t\t\t\tif (l > 1f) {\n\t\t\t\t\tvar a = VectorExtension.ToAngle(BodyComponent.Velocity);\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\t\tpart.Position = Center;\n\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.4f, 0.4f), l);\n\t\t\t\t\t\tpart.Depth = Layers.WindFx;\n\t\t\t\t\t\tpart.Particle.Scale = 0.7f;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tCamera.Instance.ShakeMax(4);\n\t\t\t\t\n\t\t\t\tOnDeath?.Invoke(this, from, timeout);\n\t\t\t\tBodyComponent.Velocity = Vector2.Zero;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void Resize(float newScale) {\n\t\t\tScale = newScale;\n\n\t\t\tvar graphics = GetComponent<ProjectileGraphicsComponent>();\n\t\t\t\n\t\t\tvar w = graphics.Sprite.Source.Width * Scale;\n\t\t\tvar h = graphics.Sprite.Source.Height * Scale;\n\t\t\tvar center = Center;\n\t\t\t\n\t\t\tWidth = w;\n\t\t\tHeight = h;\n\t\t\tCenter = center;\n\t\t\t\n\t\t\tif (HasComponent<CircleBodyComponent>()) {\n\t\t\t\tGetComponent<CircleBodyComponent>().Resize(0, 0, w / 2f, w / 2, true);\n\t\t\t} else {\n\t\t\t\tGetComponent<RectBodyComponent>().Resize(0, 0, w, h, true);\n\t\t\t}\n\t\t}\n\t}*/\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/Projectile.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.ice;\nusing BurningKnight.entity.creature.mob.jungle;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.pet;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.orbital;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.entities.statue;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class Projectile : Entity, CollisionFilterEntity {\n\t\tpublic const ProjectileFlags DefaultFlags = ProjectileFlags.Reflectable | ProjectileFlags.BreakableByMelee | ProjectileFlags.Fresh;\n\n\t\tpublic Projectile Parent; // Potentially not needed\n\t\tpublic Entity Owner;\n\t\tpublic Entity FirstOwner; // Potentially not needed\n\t\tpublic Item Item;\n\t\tpublic Color Color = ProjectileColor.Red;\n\t\tpublic ProjectileFlags Flags = DefaultFlags;\n\t\tpublic ProjectileCallbacks Callbacks;\n\t\tpublic string Slice;\n\n\t\tpublic List<Entity> EntitiesHurt = new List<Entity>(); // can we get rid of it?\n\n\t\tpublic float Damage = 1;\n\t\tpublic float T = -1;\n\t\tpublic float Scale = 1;\n\t\tpublic int Bounce;\n\n\t\tpublic bool Dying {\n\t\t\tget => T < -128;\n\t\t\tprivate set => T = value ? -129 : -1;\n\t\t}\n\n\t\tpublic bool NearingDeath => T < 0.9f && T % 0.6f >= 0.3f;\n\t\tpublic BodyComponent BodyComponent => GetAnyComponent<BodyComponent>();\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddTag(Tags.Projectile);\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\n\t\t\tAlwaysActive = true;\n\t\t}\n\n\t\tprotected virtual void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Dying) {\n\t\t\t\tScale -= dt * 10;\n\n\t\t\t\tif (Scale <= 0) {\n\t\t\t\t\tScale = 0;\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (T > 0) {\n\t\t\t\tT -= dt;\n\n\t\t\t\tif (T <= 0) {\n\t\t\t\t\tBreak(null, true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tT -= dt;\n\n\t\t\t\tif (T <= -8) {\n\t\t\t\t\tBreak(null, true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tFlags &= ~ProjectileFlags.Fresh;\n\t\t\tCallbacks?.OnUpdate?.Invoke(this, dt);\n\n\t\t\tvar bodyComponent = GetAnyComponent<BodyComponent>();\n\n\t\t\tif (!Dying && (Owner is Player || Owner is Sniper)) {\n\t\t\t\tPosition += bodyComponent.Body.LinearVelocity * dt;\n\t\t\t}\n\n\t\t\tif (!HasFlag(ProjectileFlags.ManualRotation)) {\n\t\t\t\tif (HasFlag(ProjectileFlags.AutomaticRotation)) {\n\t\t\t\t\tbodyComponent.Body.Rotation += dt * 10;\n\t\t\t\t} else {\n\t\t\t\t\tbodyComponent.Body.Rotation = VectorExtension.ToAngle(bodyComponent.Body.LinearVelocity);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Owner is Mob) {\n\t\t\t\tif (Area.Tagged[Tags.Player].Count == 0) {\n\t\t\t\t\tBreak();\n\n\t\t\t\t\t// Future proofing return, do not remove\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else if (Owner is Player) {\n\t\t\t\tif (Area.Tagged[Tags.PlayerProjectile].Count >= 69 && HasTag(Tags.PlayerProjectile)) {\n\t\t\t\t\tRemoveTag(Tags.PlayerProjectile);\n\t\t\t\t\tBreak();\n\n\t\t\t\t\t// Future proofing return, do not remove\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool HasFlag(ProjectileFlags flag) {\n\t\t\treturn (Flags & flag) != 0;\n\t\t}\n\n\t\t// Aka should bounce from the object or no\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\tif (entity == Owner) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is Tombstone && !(Owner is Player)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is Chasm || entity is MovingPlatform || entity is PlatformBorder || entity is Creature\n\t\t\t    || entity is Item || entity is Projectile || entity is ShopStand || entity is Bomb) {\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn !(entity is Level || entity is HalfWall)\n\t\t\t\t&& !(entity is Door d && d.Open)\n\t\t\t\t&& !(\n\t\t\t\t (\n\t\t\t\t   HasFlag(ProjectileFlags.FlyOverStones) || HasFlag(ProjectileFlags.FlyOverWalls)\n\t\t\t\t ) && (entity is Prop || entity is Door || entity is HalfProjectileLevel || entity is ProjectileLevelBody)\n\t\t\t\t);\n\t\t}\n\n\t\t// Aka should break on collision with it or no\n\t\tpublic virtual bool BreaksFrom(Entity entity, BodyComponent body) {\n\t\t\tif (TryGetComponent<CollisionFilterComponent>(out var c)) {\n\t\t\t\tvar rs = c.Invoke(entity);\n\n\t\t\t\tif (rs == CollisionResult.Disable) {\n\t\t\t\t\treturn false;\n\t\t\t\t} else if (rs == CollisionResult.Enable) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((entity == Owner || (Owner is Pet pt && entity == pt.Owner) || (Owner is Orbital o && entity == o.Owner)) && (!HasFlag(ProjectileFlags.HurtsEveryone) || T < 1f)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (entity is Turret) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif ((Owner is RoomControllable && entity is Mob) || entity is creature.bk.BurningKnight || entity is PlatformBorder || entity is MovingPlatform || entity is Spikes || entity is ShopStand || entity is Statue) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (HasFlag(ProjectileFlags.FlyOverWalls) && entity is RoomControllable && entity != Owner) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (HasFlag(ProjectileFlags.HitsOwner) && entity == Owner) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (entity is Creature && !HasFlag(ProjectileFlags.HurtsEveryone) && Owner is Mob == entity is Mob) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (IsWall(entity, body)) {\n\t\t\t\treturn !HasFlag(ProjectileFlags.FlyOverWalls);\n\t\t\t}\n\n\t\t\treturn (!(entity is MeleeArc || entity is Item || ((entity is Orbital oo && oo.Owner == Owner) || (entity is Pet pp && pp.Owner == Owner)) || entity is Chasm || entity is Projectile || entity is Creature || entity is Level || entity is Tree)) || entity.HasComponent<HealthComponent>();\n\t\t}\n\n\t\tprivate bool IsWall(Entity entity, BodyComponent body) {\n\t\t\treturn ((entity is ProjectileLevelBody || (!(HasFlag(ProjectileFlags.FlyOverStones) || HasFlag(ProjectileFlags.FlyOverWalls)) && entity is HalfProjectileLevel))\n\t\t\t\t|| entity is Prop ||\n\t\t\t\t(entity is Door d && !d.Open && !(body is DoorBodyComponent || d is CustomDoor)));\n\t\t}\n\n\t\tprivate bool IgnoreHurtRules(Entity e) {\n\t\t\treturn e is ShopKeeper;\n\t\t}\n\n\t\tprivate bool ShouldHurt(Entity entity) {\n\t\t\tvar e = HasFlag(ProjectileFlags.HurtsEveryone);\n\n\t\t\tif (entity == Owner && !(HasFlag(ProjectileFlags.HitsOwner) || e)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!e && Owner is Creature oc && entity is Creature ec && !IgnoreHurtRules(oc) && !IgnoreHurtRules(ec)) {\n\t\t\t\tvar ownerFriendly = oc.IsFriendly();\n\t\t\t\tvar entityFriendly = ec.IsFriendly();\n\n\t\t\t\tif (ownerFriendly == entityFriendly) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (!Dying && !HasFlag(ProjectileFlags.Fresh) && e is CollisionStartedEvent cse) {\n\t\t\t\tvar entity = cse.Entity;\n\n\t\t\t\tif (entity is Creature creature) {\n\t\t\t\t\tif (creature.IgnoresProjectiles()) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} else if (entity is Projectile projectile) {\n\t\t\t\t\tif (HasFlag(ProjectileFlags.BreakOtherProjectiles)) {\n\t\t\t\t\t\tprojectile.Break(this);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (EntitiesHurt.Contains(entity)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (entity.TryGetComponent<HealthComponent>(out var hp) && ShouldHurt(entity)) {\n\t\t\t\t\thp.ModifyHealth(-Damage, Owner, !(Owner is Snowman) ? DamageType.Custom : DamageType.Regular);\n\n\t\t\t\t\tCallbacks?.OnHurt?.Invoke(this, entity);\n\t\t\t\t\tEntitiesHurt.Add(entity);\n\t\t\t\t}\n\n\t\t\t\tif (Callbacks?.OnCollision != null && Callbacks.OnCollision(this, entity)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar mute = false;\n\n\t\t\t\tif (Run.Level.Biome is IceBiome && !(Owner is creature.bk.BurningKnight) && cse.Entity is ProjectileLevelBody lvl) {\n\t\t\t\t\tif (lvl.Break(CenterX, CenterY)) {\n\t\t\t\t\t\tmute = true;\n\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"level_snow_break\", 3);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (BreaksFrom(entity, cse.Body)) {\n\t\t\t\t\tif (IsWall(entity, cse.Body)) {\n\t\t\t\t\t\tif (!mute) {\n\t\t\t\t\t\t\tif (Owner is Player) {\n\t\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"projectile_wall\", 2, 0.5f);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomized(\"projectile_wall_enemy\", 0.5f);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Bounce <= 0) {\n\t\t\t\t\t\tBreak(entity);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tBounce--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic virtual void Resize(float scale) {\n\t\t\tvar graphics = GetComponent<ProjectileGraphicsComponent>();\n\n\t\t\tvar w = graphics.Sprite.Source.Width * scale;\n\t\t\tvar h = graphics.Sprite.Source.Height * scale;\n\t\t\tvar center = Center;\n\n\t\t\tWidth = w;\n\t\t\tHeight = h;\n\t\t\tCenter = center;\n\n\t\t\tif (HasComponent<CircleBodyComponent>()) {\n\t\t\t\tGetComponent<CircleBodyComponent>().Resize(0, 0, w / 2f, w / 2, true);\n\t\t\t} else {\n\t\t\t\tGetComponent<RectBodyComponent>().Resize(0, 0, w, h, true);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Break(Entity from = null, bool timeout = false) {\n\t\t\tif (Dying) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDying = true;\n\n\t\t\ttry {\n\t\t\t\tvar bodyComponent = GetAnyComponent<BodyComponent>();\n\t\t\t\tvar l = Math.Min(15, bodyComponent.Velocity.Length());\n\n\t\t\t\tif (l > 1f && Area.Tagged[Tags.Projectile].Count < 99) {\n\t\t\t\t\tvar a = VectorExtension.ToAngle(bodyComponent.Velocity);\n\n\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust()) {\n\t\t\t\t\t\t\tPosition = Center\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.4f, 0.4f), l);\n\t\t\t\t\t\tpart.Depth = Layers.WindFx;\n\t\t\t\t\t\tpart.Particle.Scale = 0.7f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tCamera.Instance.ShakeMax(4);\n\t\t\t\tCallbacks?.OnDeath?.Invoke(this, from, timeout);\n\n\t\t\t\tbodyComponent.Velocity = Vector2.Zero;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddFlags(params ProjectileFlags[] projectileFlags) {\n\t\t\tforeach (var flag in projectileFlags) {\n\t\t\t\tFlags |= flag;\n\t\t\t}\n\t\t}\n\n\t\tpublic void RemoveFlags(params ProjectileFlags[] projectileFlags) {\n\t\t\tforeach (var flag in projectileFlags) {\n\t\t\t\tFlags &= ~flag;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileBuilder.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class ProjectileBuilder {\n\t\tpublic Entity Owner;\n\n\t\tprivate Projectile parent;\n\n\t\tpublic Projectile Parent {\n\t\t\tget => parent;\n\n\t\t\tset {\n\t\t\t\tif (value != null) {\n\t\t\t\t\tColor = value.Color;\n\t\t\t\t}\n\n\t\t\t\tparent = value;\n\t\t\t}\n\t\t}\n\n\t\tpublic ProjectileFlags Flags = Projectile.DefaultFlags;\n\t\tpublic string Slice;\n\n\t\tpublic Vector2 Velocity;\n\t\tpublic Vector2 Offset;\n\n\t\tpublic float Scale = 1f;\n\t\tpublic float Damage = 1f;\n\t\tpublic float Range = -1f;\n\n\t\tpublic bool RectHitbox;\n\t\tpublic bool Poof;\n\n\t\tpublic Color Color = ProjectileColor.Red;\n\t\tpublic float LightRadius;\n\n\t\tpublic int Bounce;\n\n\t\tprivate bool empty;\n\n\t\tpublic ProjectileBuilder(Entity projectileOwner, string projectileSlice) {\n\t\t\tif (projectileSlice == \"default\") {\n\t\t\t\tprojectileSlice = \"rect\";\n\t\t\t}\n\n\t\t\tSlice = projectileSlice;\n\t\t\tOwner = projectileOwner;\n\n\t\t\tif (Owner is Mob mob) {\n\t\t\t\tif (Rnd.Chance(LevelSave.MobDestructionChance)) {\n\t\t\t\t\tempty = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (mob.HasPrefix) {\n\t\t\t\t\tLightRadius = 64;\n\t\t\t\t\tColor = Color.Black;\n\n\t\t\t\t\tAddFlags(ProjectileFlags.Scourged);\n\t\t\t\t}\n\t\t\t} else if (Owner is Player || (Owner is Item item && item.Owner is Player)) {\n\t\t\t\tColor = ProjectileColor.Yellow;\n\t\t\t}\n\t\t}\n\n\t\tpublic ProjectileBuilder Shoot(double angle, float speed) {\n\t\t\tVelocity = MathUtils.CreateVector(angle, speed);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic ProjectileBuilder Move(double angle, float distance) {\n\t\t\tOffset = MathUtils.CreateVector(angle, distance);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic ProjectileBuilder AddFlags(params ProjectileFlags[] projectileFlags) {\n\t\t\tforeach (var flag in projectileFlags) {\n\t\t\t\tFlags |= flag;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic ProjectileBuilder RemoveFlags(params ProjectileFlags[] projectileFlags) {\n\t\t\tforeach (var flag in projectileFlags) {\n\t\t\t\tFlags &= ~flag;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Projectile Build() {\n\t\t\tif (empty || ((Owner is Mob && !(Owner is creature.bk.BurningKnight)) && Owner.Area.Tagged[Tags.MobProjectile].Count >= 199)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tItem item = null;\n\n\t\t\tif (Owner is Item i) {\n\t\t\t\titem = i;\n\t\t\t\tOwner = i.Owner;\n\t\t\t}\n\n\t\t\tvar projectile = new Projectile {\n\t\t\t\tOwner = Owner,\n\t\t\t\tFirstOwner = Owner,\n\t\t\t\tDamage = Damage,\n\t\t\t\tFlags = Flags,\n\t\t\t\tSlice = Slice,\n\t\t\t\tBounce = Math.Min(8, Bounce),\n\t\t\t\tScale = Scale,\n\t\t\t\tColor = Color,\n\t\t\t\tParent = parent,\n\t\t\t\tItem = item\n\t\t\t};\n\n\t\t\tOwner.Area.Add(projectile);\n\n\t\t\tif (Owner is Mob) {\n\t\t\t\tprojectile.AddTag(Tags.MobProjectile);\n\n\t\t\t\tif ((Owner is Boss && Run.Loop > 0) || Run.Loop > 1) {\n\t\t\t\t\tprojectile.AddFlags(ProjectileFlags.Scourged);\n\t\t\t\t}\n\t\t\t} else if (Owner is Player) {\n\t\t\t\tprojectile.AddTag(Tags.PlayerProjectile);\n\t\t\t}\n\n\t\t\tvar graphics = new ProjectileGraphicsComponent(\"projectiles\", Slice);\n\n\t\t\tif (graphics.Sprite == null) {\n\t\t\t\tLog.Error($\"Not found projectile slice {Slice}\");\n\t\t\t\tempty = true;\n\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tprojectile.AddComponent(graphics);\n\n\t\t\tvar w = graphics.Sprite.Source.Width * Scale;\n\t\t\tvar h = graphics.Sprite.Source.Height * Scale;\n\n\t\t\tprojectile.Width = w;\n\t\t\tprojectile.Height = h;\n\t\t\tprojectile.Center = Owner.Center + Offset;\n\n\t\t\tBodyComponent bodyComponent;\n\n\t\t\tif (RectHitbox) {\n\t\t\t\tprojectile.AddComponent(bodyComponent = new RectBodyComponent(0, 0, w, h, BodyType.Dynamic, false, true));\n\t\t\t} else {\n\t\t\t\tprojectile.AddComponent(bodyComponent = new CircleBodyComponent(0, 0, w / 2f, BodyType.Dynamic, false, true));\n\t\t\t}\n\n\t\t\tvar body = bodyComponent.Body;\n\n\t\t\tbody.Restitution = 1;\n\t\t\tbody.Friction = 0;\n\t\t\tbody.IsBullet = true;\n\t\t\tbody.Rotation = Velocity.ToAngle();\n\n\t\t\tif (Owner.TryGetComponent<BuffsComponent>(out var buffs) && buffs.Has<SlowBuff>()) {\n\t\t\t\tVelocity *= 0.5f;\n\t\t\t}\n\n\t\t\tif (Range > 0) {\n\t\t\t\t// / Velocity.Length()\n\t\t\t\tprojectile.T = Range;\n\t\t\t}\n\n\t\t\tVelocity *= 10f;\n\t\t\tbody.LinearVelocity = Velocity;\n\n\t\t\tvar count = Owner.Area.Tagged[Tags.Projectile].Count;\n\n\t\t\tif (count < 99) {\n\t\t\t\tif (LightRadius > 0) {\n\t\t\t\t\tprojectile.AddComponent(new LightComponent(projectile, LightRadius * Scale, Color));\n\t\t\t\t}\n\n\t\t\t\tif (Poof) {\n\t\t\t\t\tAnimationUtil.Poof(projectile.Center);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tOwner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\tOwner = Owner,\n\t\t\t\tItem = item,\n\t\t\t\tProjectile = projectile\n\t\t\t});\n\n\t\t\treturn projectile;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileCallbacks.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic class ProjectileCallbacks {\n\t\tpublic delegate void UpdateCallback(Projectile p, float dt);\n\t\tpublic delegate void DeathCallback(Projectile p, Entity from, bool t);\n\t\tpublic delegate void HurtCallback(Projectile p, Entity e);\n\t\tpublic delegate bool CollisionCallback(Projectile p, Entity e);\n\n\t\tpublic UpdateCallback OnUpdate;\n\t\tpublic DeathCallback OnDeath;\n\t\tpublic HurtCallback OnHurt;\n\t\tpublic CollisionCallback OnCollision;\n\n\t\tpublic static void AttachUpdateCallback(Projectile p, UpdateCallback callback) {\n\t\t\tif (p.Callbacks == null) {\n\t\t\t\tp.Callbacks = new ProjectileCallbacks();\n\t\t\t}\n\n\t\t\tp.Callbacks.OnUpdate += callback;\n\t\t}\n\n\t\tpublic static void AttachDeathCallback(Projectile p, DeathCallback callback) {\n\t\t\tif (p.Callbacks == null) {\n\t\t\t\tp.Callbacks = new ProjectileCallbacks();\n\t\t\t}\n\n\t\t\tp.Callbacks.OnDeath += callback;\n\t\t}\n\n\t\tpublic static void AttachHurtCallback(Projectile p, HurtCallback callback) {\n\t\t\tif (p.Callbacks == null) {\n\t\t\t\tp.Callbacks = new ProjectileCallbacks();\n\t\t\t}\n\n\t\t\tp.Callbacks.OnHurt += callback;\n\t\t}\n\n\t\tpublic static void AttachCollisionCallback(Projectile p, CollisionCallback callback) {\n\t\t\tif (p.Callbacks == null) {\n\t\t\t\tp.Callbacks = new ProjectileCallbacks();\n\t\t\t}\n\n\t\t\tp.Callbacks.OnCollision += callback;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileColor.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic static class ProjectileColor {\n\t\tpublic static Color Yellow = Palette.Default[30];\n\t\tpublic static Color BkRed = new Color(1f, 0f, 0f);\n\t\tpublic static Color Red = Palette.Default[0];\n\t\tpublic static Color Green = Palette.Default[35];\n\t\tpublic static Color DarkGreen = Palette.Default[37];\n\t\tpublic static Color Blue = Palette.Default[40];\n\t\tpublic static Color Cyan = Palette.Default[42];\n\t\tpublic static Color Purple = Palette.Default[54];\n\t\tpublic static Color Orange = Palette.Default[28];\n\t\tpublic static Color Pink = Palette.Default[59];\n\t\tpublic static Color Brown = Palette.Default[19];\n\t\tpublic static Color Gray = Palette.Default[6];\n\t\tpublic static Color Black = Color.Black;\n\t\tpublic static Color White = Color.White;\n\n\t\tpublic static Color[] Rainbow = {\n\t\t\tRed, Orange, Yellow, Green, Cyan, Blue, Purple\n\t\t};\n\n\t\tpublic static Color[] DesertRainbow = {\n\t\t\tRed, Orange, Yellow\n\t\t};\n\n\t\tpublic static Dictionary<string, Color> Colors = new Dictionary<string, Color> {\n\t\t\t{ \"yellow\", Yellow },\n\t\t\t{ \"red\", Red },\n\t\t\t{ \"green\", Green },\n\t\t\t{ \"blue\", Blue },\n\t\t\t{ \"cyan\", Cyan },\n\t\t\t{ \"purple\", Purple },\n\t\t\t{ \"orange\", Orange },\n\t\t\t{ \"pink\", Pink },\n\t\t\t{ \"brown\", Brown },\n\t\t\t{ \"black\", Black },\n\t\t\t{ \"white\", White },\n\t\t};\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileFlags.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.projectile {\n\t[Flags]\n\tpublic enum ProjectileFlags {\n\t\tScourged = 1 << 1,\n\t\tReflectable = 1 << 2,\n\t\tManualRotation = 1 << 3,\n\t\tAutomaticRotation = 1 << 4,\n\t\tBreakableByMelee = 1 << 5,\n\t\tFlyOverStones = 1 << 6,\n\t\tArtificial = 1 << 7,\n\t\tBreakOtherProjectiles = 1 << 8,\n\t\tDieOffScreen = 1 << 9,\n\t\tFlyOverWalls = 1 << 10,\n\t\tFresh = 1 << 11,\n\t\tHitsOwner = 1 << 12,\n\t\tHurtsEveryone = 1 << 13\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileGraphicsComponent.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob.boss;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.graphics;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.projectile {\r\n\tpublic class ProjectileGraphicsComponent : BasicProjectileGraphicsComponent {\r\n\t\tpublic static TextureRegion Flash;\r\n\t\tpublic bool IgnoreRotation;\r\n\t\tpublic float Rotation => IgnoreRotation ? 0 : ((Projectile) Entity).GetAnyComponent<BodyComponent>().Body.Rotation;\r\n\t\tpublic TextureRegion Aura;\r\n\t\tpublic TextureRegion Light;\r\n\r\n\t\tpublic ProjectileGraphicsComponent(string image, string slice) : base(image, slice) {\r\n\t\t\tif (Flash == null) {\r\n\t\t\t\tFlash = CommonAse.Particles.GetSlice(\"flash\");\r\n\t\t\t}\r\n\r\n\t\t\tvar a = Animations.Get(image);\r\n\r\n\t\t\tAura = a.GetSlice($\"{slice}_aura\", false);\r\n\t\t\tLight = a.GetSlice($\"{slice}_light\", false);\r\n\t\t}\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tif (Light == null) {\r\n\t\t\t\t((Projectile) Entity).Color = ColorUtils.WhiteColor;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate bool ShouldIndicateProjectileDeath(Projectile projectile) {\r\n\t\t\treturn projectile.Owner is OldKing;\r\n\t\t}\r\n\r\n\t\tpublic override void Render(bool shadow) {\r\n\t\t\tvar p = (Projectile) Entity;\r\n\t\t\tvar scale = new Vector2(p.Scale);\r\n\t\t\tvar a = Rotation;\r\n\t\t\tvar b = false; // p.FlashTimer > 0; // future egor: do we really need this frame that no one notices anyway? think about it, requires extra 4 bytes per bullet\r\n\t\t\tvar spr = b ? Flash : Sprite;\r\n\t\t\tvar or = spr.Center;\r\n\r\n\t\t\tif (shadow) {\r\n\t\t\t\tGraphics.Render(spr, Entity.Center + new Vector2(0, 6), a, or, scale);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar d = p.Dying || (ShouldIndicateProjectileDeath(p) && p.NearingDeath);\r\n\t\t\tvar started = false;\r\n\r\n\t\t\tbool scourged = p.HasFlag(ProjectileFlags.Scourged);\r\n\r\n\t\t\tif (!d) {\r\n\t\t\t\t// fixme: p.Effect.GetColor()\r\n\t\t\t\tGraphics.Color = scourged ? ColorUtils.BlackColor : p.Color;\r\n\t\t\t} else if (Light == null) {\r\n\t\t\t\tvar shader = Shaders.Entity;\r\n\t\t\t\tShaders.Begin(shader);\r\n\r\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\r\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\r\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\r\n\r\n\t\t\t\tstarted = true;\r\n\t\t\t}\r\n\r\n\t\t\tGraphics.Render(spr, Entity.Center, a, or, scale);\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\r\n\t\t\tif (started) {\r\n\t\t\t\tShaders.End();\r\n\t\t\t}\r\n\r\n\t\t\tif (!b && Light != null) {\r\n\t\t\t\tif (scourged) {\r\n\t\t\t\t\tGraphics.Color = p.Color;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tGraphics.Render(Light, Entity.Center, a, or, scale);\r\n\r\n\t\t\t\tif (scourged) {\r\n\t\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void RenderLight() {\r\n\t\t\tif (Aura != null) {\r\n\t\t\t\tvar p = (Projectile) Entity;\r\n\r\n\t\t\t\tif (!(p.Dying || (ShouldIndicateProjectileDeath(p) && p.NearingDeath))) {\r\n\t\t\t\t\tGraphics.Color = p.Color;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar a = !p.HasFlag(ProjectileFlags.BreakableByMelee) && !p.HasFlag(ProjectileFlags.Reflectable);\r\n\r\n\t\t\t\tGraphics.Color.A = (byte) Math.Round(Lights.AuraAlpha * (a ?\r\n\t\t\t\t\t((Math.Sin(Engine.Time * 4f * Math.PI) * 0.5f + 0.5f) * 2)\r\n\t\t\t\t\t: 1));\r\n\r\n\t\t\t\tGraphics.Render(Aura, Entity.Center, Rotation, Aura.Center, new Vector2(((Projectile) Entity).Scale));\r\n\t\t\t\tGraphics.Color.A = 255;\r\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileGraphicsEffect.cs",
    "content": "namespace BurningKnight.entity.projectile {\n\tpublic enum ProjectileGraphicsEffect {\n\t\tNormal,\n\t\tPoison,\n\t\tCharming,\n\t\tFreezing,\n\t\tSlowing,\n\t\tBurning,\n\t\tBrokenArmor\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectilePattern.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile {\n\tpublic delegate void ProjectilePatternController(Projectile p, ProjectilePattern.ProjectileData data, ProjectilePattern pt, int i, float dt);\n\t\n\tpublic class ProjectilePattern : Entity {\n\t\tpublic List<ProjectileData> Projectiles = new List<ProjectileData>();\n\t\tprivate int maxProjectiles;\n\t\t\n\t\tpublic ProjectilePatternController Controller;\n\t\tpublic Vector2 Velocity;\n\n\t\tpublic int Count => maxProjectiles;\n\t\tpublic float T;\n\t\tprivate bool launched;\n\t\t\n\t\tpublic ProjectilePattern(ProjectilePatternController c) {\n\t\t\tController = c;\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = 0;\n\t\t\tHeight = 0;\n\t\t}\n\n\t\tpublic void Launch(float angle, float speed) {\n\t\t\tVelocity = new Vector2((float) Math.Cos(angle) * speed, (float) Math.Sin(angle) * speed);\n\t\t\tlaunched = true;\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (launched) {\n\t\t\t\tT += dt;\n\t\t\t\tPosition += Velocity * dt;\n\n\t\t\t\tif (Controller != null) {\n\t\t\t\t\tforeach (var p in Projectiles) {\n\t\t\t\t\t\tController(p.Projectile, p, this, p.Id, dt);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = Projectiles.Count - 1; i >= 0; i--) {\n\t\t\t\tif (Projectiles[i].Projectile.Done) {\n\t\t\t\t\tProjectiles.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (launched) {\n\t\t\t\tif (Projectiles.Count == 0) {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Kill() {\n\t\t\tDone = true;\n\n\t\t\tforeach (var p in Projectiles) {\n\t\t\t\tp.Projectile.Done = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Add(Projectile p) {\n\t\t\tif (!p.Done) {\n\t\t\t\tProjectiles.Add(new ProjectileData {\n\t\t\t\t\tProjectile = p,\n\t\t\t\t\tId = maxProjectiles,\n\t\t\t\t\tDistance = DistanceTo(p),\n\t\t\t\t\tAngle = AngleTo(p)\n\t\t\t\t});\n\n\t\t\t\tp.AddFlags(ProjectileFlags.ManualRotation);\n\t\t\t}\n\n\t\t\tmaxProjectiles++;\n\t\t}\n\n\t\tpublic void Remove(Projectile p) {\n\t\t\tfor (var i = 0; i < Projectiles.Count; i++) {\n\t\t\t\tif (Projectiles[i].Projectile == p) {\n\t\t\t\t\tProjectiles.RemoveAt(i);\n\t\t\t\t\tp.RemoveFlags(ProjectileFlags.ManualRotation);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic class ProjectileData {\n\t\t\tpublic Projectile Projectile;\n\t\t\tpublic int Id;\n\t\t\tpublic float Angle;\n\t\t\tpublic float Distance;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileRegistry.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.mod;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature;\r\nusing BurningKnight.entity.creature.mob;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.entity.item.use;\r\nusing BurningKnight.entity.projectile.controller;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.level.paintings;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.physics;\r\nusing BurningKnight.state;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.input;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\n\r\nnamespace BurningKnight.entity.projectile {\r\n\tpublic static class ProjectileRegistry {\r\n\t\tprivate static Dictionary<string, Action<Projectile>> registry = new Dictionary<string, Action<Projectile>>();\r\n\r\n\t\tpublic static void Add(string id, Action<Projectile> fn, Mod mod = null) {\r\n\t\t\tregistry[$\"{mod?.Prefix ?? Mods.BurningKnight}:{id}\"] = fn;\r\n\t\t}\r\n\r\n\t\tpublic static Action<Projectile> Get(string id) {\r\n\t\t\treturn registry.TryGetValue(id, out var f) ? f : null;\r\n\t\t}\r\n\r\n\t\tstatic ProjectileRegistry() {\r\n\t\t\tAdd(\"skull\", skull => {\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => {\r\n\t\t\t\t\tvar b = new ProjectileBuilder(p.Owner, \"small\");\r\n\t\t\t\t\tb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\r\n\r\n\t\t\t\t\tfor (var i = 0; i < 8; i++) {\r\n\t\t\t\t\t\tvar bullet = b.Shoot(((float) i) / 4 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build();\r\n\t\t\t\t\t\tbullet.Center = p.Center;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(null, 0.5f));\r\n\r\n\t\t\t\tskull.T = 5f;\r\n\t\t\t\tskull.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable);\r\n\t\t\t\tskull.GetComponent<ProjectileGraphicsComponent>().IgnoreRotation = true;\r\n\t\t\t});\r\n\t\t\r\n\t\t\tAdd(\"disk\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default);\r\n\r\n\t\t\t\tp.Bounce += 10;\r\n\t\t\t\tp.AddFlags(ProjectileFlags.HitsOwner);\r\n\r\n\t\t\t\tp.GetComponent<CircleBodyComponent>().Body.AngularVelocity = 10f;\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"what\", p => {\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, WhatController.Make());\r\n\t\t\t\tp.GetComponent<CircleBodyComponent>().Body.AngularVelocity = 10f;\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"soap\", p => {\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(2));\r\n\t\t\t});\r\n\r\n\t\t\tAdd(\"grenade\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => {\r\n\t\t\t\t\tif (with is Mob) {\r\n\t\t\t\t\t\tp.Bounce = 0;\r\n\t\t\t\t\t\treturn CollisionResult.Enable;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn CollisionResult.Default;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(1));\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tExplosionMaker.Make(pr, 16, damage: 8);\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, (pr, dt) => {\r\n\t\t\t\t\tif (pr.T >= 3f) {\r\n\t\t\t\t\t\tpr.Break();\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"missile\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => {\r\n\t\t\t\t\tif (with is Mob) {\r\n\t\t\t\t\t\tp.Bounce = 0;\r\n\t\t\t\t\t\treturn CollisionResult.Enable;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (with is Prop) {\r\n\t\t\t\t\t\treturn CollisionResult.Disable;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn CollisionResult.Default;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.Make(null, 0.5f));\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SmokeProjectileController.Make());\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tExplosionMaker.Make(pr, 32);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"shotgun\", p => {\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(1));\r\n\t\t\t\tp.Bounce += 1;\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"follower\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => {\r\n\t\t\t\t\tif (with is Mob) {\r\n\t\t\t\t\t\tp.Bounce = 0;\r\n\t\t\t\t\t\treturn CollisionResult.Enable;\r\n\t\t\t\t\t} \r\n\t\t\t\t\t\r\n\t\t\t\t\tif (with is Prop) {\r\n\t\t\t\t\t\treturn CollisionResult.Disable;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn CollisionResult.Default;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.MakeCursor());\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SmokeProjectileController.Make());\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tExplosionMaker.Make(pr, 32);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"flak\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => {\r\n\t\t\t\t\tif (with is Mob) {\r\n\t\t\t\t\t\tp.Bounce = 0;\r\n\t\t\t\t\t\treturn CollisionResult.Enable;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn CollisionResult.Default;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.5f));\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tvar b = new ProjectileBuilder(pr.Owner, \"shot\");\r\n\r\n\t\t\t\t\tfor (var i = 0; i < 8; i++) {\r\n\t\t\t\t\t\tvar pr2 = b.Shoot((float) i / 8 * (float) Math.PI * 2, 8).Build();\r\n\t\t\t\t\t\tpr2.Center = pr.Center;\r\n\r\n\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(pr2, SlowdownProjectileController.Make(1));\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\tProjectileCallbacks.AttachUpdateCallback(p, (pr, dt) => {\r\n\t\t\t\t\tif (pr.T >= 1f) {\r\n\t\t\t\t\t\tpr.Break();\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\tAdd(\"duck\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"portal\", p => {\r\n\t\t\t\tp.Center = p.Owner.GetComponent<CursorComponent>().Cursor.GamePosition;\r\n\t\t\t\tp.GetAnyComponent<BodyComponent>().Velocity *= -1;\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"axe\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => ((with is Creature && with != p.Owner) || ((Projectile) entity).Bounce == 0) ? CollisionResult.Disable : CollisionResult.Default);\r\n\r\n\t\t\t\tvar ts = Timer.Add(() => {\r\n\t\t\t\t\tp.Item.Renderer.Hidden = false;\r\n\r\n\t\t\t\t\tforeach (var u in p.Item.Uses) {\r\n\t\t\t\t\t\tif (u is SimpleShootUse ss) {\r\n\t\t\t\t\t\t\tss.ProjectileDied = true;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}, 3f);\r\n\t\t\t\t\r\n\t\t\t\tp.T = 5;\r\n\r\n\t\t\t\tProjectileCallbacks.AttachCollisionCallback(p, (projectile, e) => {\r\n\t\t\t\t\tif (Run.Level.Biome is IceBiome && e is ProjectileLevelBody lvl) {\r\n\t\t\t\t\t\tif (lvl.Break(projectile.CenterX, projectile.CenterY)) {\r\n\t\t\t\t\t\t\tAudioEmitterComponent.Dummy(projectile.Area, projectile.Center).EmitRandomizedPrefixed(\"level_snow_break\", 3);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (projectile.Bounce == 0) {\r\n\t\t\t\t\t\tif (e == projectile.Owner) {\r\n\t\t\t\t\t\t\tprojectile.Item.Renderer.Hidden = false;\r\n\t\t\t\t\t\t\tprojectile.Break();\r\n\r\n\t\t\t\t\t\t\tforeach (var u in projectile.Item.Uses) {\r\n\t\t\t\t\t\t\t\tif (u is SimpleShootUse ss) {\r\n\t\t\t\t\t\t\t\t\tss.ProjectileDied = true;\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (!(e is Mob)) {\r\n\t\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (projectile.BreaksFrom(e, null)) {\r\n\t\t\t\t\t\tif (e is Painting || e is BreakableProp || e is ExplodingBarrel || e.HasComponent<HealthComponent>()) {\r\n\t\t\t\t\t\t\tprojectile.Bounce++;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tvar b = projectile.GetComponent<RectBodyComponent>().Body;\r\n\t\t\t\t\t\t\tb.LinearVelocity *= -1;\r\n\r\n\t\t\t\t\t\t\tprojectile.Bounce = 0;\r\n\t\t\t\t\t\t\tprojectile.EntitiesHurt.Clear();\r\n\t\t\t\t\t\t\tProjectileCallbacks.AttachUpdateCallback(projectile, ReturnProjectileController.Make(projectile.Owner));\r\n\r\n\t\t\t\t\t\t\tvar pi = projectile.Callbacks?.OnDeath;\r\n\r\n\t\t\t\t\t\t\tProjectileCallbacks.AttachDeathCallback(projectile, (pr, ee, t) => {\r\n\t\t\t\t\t\t\t\tpr.Item.Renderer.Hidden = false;\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tforeach (var u in pr.Item.Uses) {\r\n\t\t\t\t\t\t\t\t\tif (u is SimpleShootUse ss) {\r\n\t\t\t\t\t\t\t\t\t\tss.ProjectileDied = true;\r\n\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tts.Cancel();\r\n\t\t\t\t\t\t\t\tpr.Owner.GetComponent<AudioEmitterComponent>().EmitRandomized(\"item_axe_catch\");\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tpi?.Invoke(projectile, e, false);\r\n\t\t\t\t\t\t\treturn true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t\tp.Bounce = 1;\r\n\t\t\t\tp.AddFlags(ProjectileFlags.AutomaticRotation);\r\n\r\n\t\t\t\tp.Item.Renderer.Hidden = true;\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"lava_wand\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\r\n\t\t\t\tp.AddFlags(ProjectileFlags.AutomaticRotation);\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tAudioEmitterComponent.Dummy(pr.Area, pr.Center).EmitRandomized(\"item_magic_lava_appear\");\r\n\t\t\t\t\r\n\t\t\t\t\tvar x = (int) Math.Round(pr.CenterX / 16f);\r\n\t\t\t\t\tvar y = (int) Math.Round(pr.CenterY / 16f);\r\n\t\t\t\t\tconst float r = 2.3f;\r\n\r\n\t\t\t\t\tfor (var xx = -r; xx <= r; xx++) {\r\n\t\t\t\t\t\tfor (var yy = -r; yy <= r; yy++) {\r\n\t\t\t\t\t\t\tvar zx = (int) xx + x;\r\n\t\t\t\t\t\t\tvar zy = (int) yy + y;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (Math.Sqrt(xx * xx + yy * yy) <= r && Run.Level.Get(zx, zy).IsPassable()) {\r\n\t\t\t\t\t\t\t\tRun.Level.Set(zx, zy, Tile.Lava);\r\n\r\n\t\t\t\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\t\t\t\tRun.Level.Set(zx, zy, Tile.Ember);\r\n\t\t\t\t\t\t\t\t\tRun.Level.UpdateTile(zx, zy);\r\n\t\t\t\t\t\t\t\t}, Rnd.Float(5f, 15f));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tRun.Level.TileUp();\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\tAdd(\"discord_rod\", p => {\r\n\t\t\t\tCollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\t\t\t\tp.AddFlags(ProjectileFlags.AutomaticRotation);\r\n\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tpr.Owner.Center = pr.Center;\r\n\t\t\t\t\tAudio.PlaySfx(\"item_discord\");\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAdd(\"web_wand\", p => {\r\n\t\t\t\t// CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default);\r\n\r\n\t\t\t\tp.AddFlags(ProjectileFlags.AutomaticRotation);\r\n\t\t\t\tProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => {\r\n\t\t\t\t\tAudioEmitterComponent.Dummy(pr.Area, pr.Center).EmitRandomized(\"item_magic_web_appear\");\r\n\r\n\t\t\t\t\tvar x = (int) Math.Round(pr.CenterX / 16f);\r\n\t\t\t\t\tvar y = (int) Math.Round(pr.CenterY / 16f);\r\n\t\t\t\t\tconst float r = 2.3f;\r\n\r\n\t\t\t\t\tfor (var xx = -r; xx <= r; xx++) {\r\n\t\t\t\t\t\tfor (var yy = -r; yy <= r; yy++) {\r\n\t\t\t\t\t\t\tvar zx = (int) xx + x;\r\n\t\t\t\t\t\t\tvar zy = (int) yy + y;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (Math.Sqrt(xx * xx + yy * yy) <= r && Run.Level.Get(zx, zy).IsPassable()) {\r\n\t\t\t\t\t\t\t\tRun.Level.Set(zx, zy, Tile.Cobweb);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tRun.Level.TileUp();\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/ProjectileTemplate.cs",
    "content": "using System;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.projectile {\r\n\tpublic static class ProjectileTemplate {\r\n\t\tpublic static void Make(Entity owner, string texture, Vector2 center, float angle, float speed, int bounce, int start, Action<Projectile> modifier,  params string[] data) {\r\n\t\t\tvar height = data.Length;\r\n\t\t\tvar width = 0;\r\n\r\n\t\t\tfor (var i = 0; i < height; i++) {\r\n\t\t\t\twidth = Math.Max(width, data[i].Length);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar c = new Vector2();\r\n\t\t\tvar d = 0.2f;\r\n\r\n\t\t\tvar builder = new ProjectileBuilder(owner, texture);\r\n\t\t\tbuilder.Shoot(angle, speed);\r\n\t\t\tbuilder.Bounce = bounce;\r\n\r\n\t\t\tfor (var x = 0; x < width; x++) {\r\n\t\t\t\tvar x1 = x;\r\n\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\tfor (var y = 0; y < height; y++) {\r\n\t\t\t\t\t\tif (data[y][x1] != ' ') {\r\n\t\t\t\t\t\t\tvar p = builder.Build();\r\n\r\n\t\t\t\t\t\t\tp.Center = center + MathUtils.RotateAround(new Vector2(0, (y - height / 2f) * 10), angle, c);\r\n\t\t\t\t\t\t\tmodifier?.Invoke(p);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\t\r\n\t\t\t\t}, (width - x + start) * d);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void MakeFast(Entity owner, string texture, Vector2 center, float angle, Action<Projectile> modifier, string[] data, Action end) {\r\n\t\t\tvar height = data.Length;\r\n\t\t\tvar width = 0;\r\n\r\n\t\t\tfor (var i = 0; i < height; i++) {\r\n\t\t\t\twidth = Math.Max(width, data[i].Length);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar c = new Vector2();\r\n\t\t\tvar first = true;\r\n\r\n\t\t\tvar builder = new ProjectileBuilder(owner, texture);\r\n\r\n\t\t\tfor (var x = 0; x < width; x++) {\r\n\t\t\t\tfor (var y = 0; y < height; y++) {\r\n\t\t\t\t\tif (data[y][x] != ' ') {\r\n\t\t\t\t\t\tvar first1 = first;\r\n\r\n\t\t\t\t\t\tvar x2 = x;\r\n\t\t\t\t\t\tvar y1 = y;\r\n\r\n\t\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\t\tvar p = builder.Build();\r\n\t\t\t\t\t\t\tp.Center = center + MathUtils.RotateAround(new Vector2(x2 * 10, (y1 - height / 2f) * 10), angle, c);\r\n\r\n\t\t\t\t\t\t\tmodifier?.Invoke(p);\r\n\r\n\t\t\t\t\t\t\tif (first1) {\r\n\t\t\t\t\t\t\t\tend();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}, first ? 0.5f : Rnd.Float(0, 0.4f));\r\n\r\n\t\t\t\t\t\tfirst = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Write(string what, Entity owner, string texture, Vector2 center, float angle, float speed, int bounce) {\r\n\t\t\twhat = what.ToLower();\r\n\r\n\t\t\tfor (var i = 0; i < what.Length; i++) {\r\n\t\t\t\tvar c = what[i];\r\n\r\n\t\t\t\tif (c == ' ') {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!LetterTemplateData.Data.TryGetValue(c, out var data)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tMake(owner, texture, center, angle, speed, bounce, (what.Length - i) * 4, null, data);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/BoomerangProjectileController.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class BoomerangProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(Entity owner, float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tif (p.T < 0.2f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar dx = p.DxTo(owner);\n\t\t\t\tvar dy = p.DyTo(owner);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\t\t\t\tvar s = dt * 250 * speed;\n\n\t\t\t\tif (d <= 8f) {\n\t\t\t\t\tp.Break();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tb.Velocity += new Vector2(dx / d * s, dy / d * s);\n\t\t\t\tb.Angle = b.Velocity.ToAngle();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/ExpandProjectileController.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic class ExpandProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(float speed = 1f) {\n\t\t\tvar t = 0f;\n\t\t\tvar z = 0f;\n\t\t\tvar dmg = -1f;\n\t\t\t\n\t\t\treturn (p, dt) => {\n\t\t\t\tt += dt * speed;\n\t\t\t\tz += dt;\n\t\t\t\t\n\t\t\t\tif (dmg < 0) {\n\t\t\t\t\tdmg = p.Damage;\n\t\t\t\t}\n\n\t\t\t\tif (z >= 0.05f) {\n\t\t\t\t\tvar s = Math.Min(1, t * 5f); // (p.Scale > 1 ? 1f / p.Scale : p.Scale);\n\t\t\t\t\tz -= 0.05f;\n\n\t\t\t\t\tp.Resize(s);\n\t\t\t\t\tp.Damage = dmg * p.Scale;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/HsvProjectileController.cs",
    "content": "using Lens.graphics;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic class HsvProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(float speed = 1f, float start = 0) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tp.Color = ColorUtils.FromHSV((p.T + start) * speed * 120 % 360, 100, 100);\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/ReturnProjectileController.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.entity;\nusing Lens.util;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class ReturnProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(Entity owner, float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar dx = p.DxTo(owner);\n\t\t\t\tvar dy = p.DyTo(owner);\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\t\tif (d <= 8f) {\n\t\t\t\t\tp.Break();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tb.Velocity = MathUtils.CreateVector(MathUtils.LerpAngle(b.Velocity.ToAngle(), Math.Atan2(dy, dx), dt * 50 * speed), b.Velocity.Length());\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/ShrinkProjectileController.cs",
    "content": "using System;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class ShrinkProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(float speed = 1f) {\n\t\t\tvar t = 0f;\n\t\t\tvar z = 0.05f;\n\t\t\tvar dmg = -1f;\n\t\t\tvar sc = 2f;\n\t\t\t\n\t\t\treturn (p, dt) => {\n\t\t\t\tif (dmg < 0) {\n\t\t\t\t\t// sc = p.Scale;\n\t\t\t\t\tdmg = p.Damage;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tt += dt * speed;\n\t\t\t\tz += dt;\n\n\t\t\t\tif (z >= 0.05f) {\n\t\t\t\t\tvar s = sc - t * 4f / Math.Max(1, p.Scale); // (p.Scale > 1 ? 1f / p.Scale : p.Scale);\n\t\t\t\t\tz = 0;\n\n\t\t\t\t\tp.Resize(s);\n\t\t\t\t\tp.Damage = dmg * p.Scale;\n\n\t\t\t\t\tif (p.Width <= 0 || p.Height <= 0) {\n\t\t\t\t\t\tp.Break();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/SlowdownProjectileController.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.util.timer;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class SlowdownProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(float speed = 1, float time = 1f, float vmin = 0.1f) {\n\t\t\tvar stopped = false;\n\t\t\t\n\t\t\treturn (p, dt) => {\n\t\t\t\tif (stopped) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar v = b.Velocity;\n\n\t\t\t\tb.Velocity -= v * (speed * dt * 2);\n\n\t\t\t\tif (b.Velocity.Length() < vmin) {\n\t\t\t\t\tstopped = true;\n\t\t\t\t\tTimer.Add(() => { p.Break(); }, time);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/SmokeProjectileController.cs",
    "content": "using BurningKnight.assets.particle;\r\nusing BurningKnight.entity.component;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.entity.projectile.controller {\r\n\tpublic static class SmokeProjectileController {\r\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make() {\r\n\t\t\tvar t = 0f;\r\n\t\t\t\r\n\t\t\treturn (p, dt) => {\r\n\t\t\t\tt += dt;\r\n\r\n\t\t\t\tif (t >= 0.1f) {\r\n\t\t\t\t\tt = 0;\r\n\t\t\t\t\t\r\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\r\n\t\t\t\t\tp.Area.Add(part);\r\n\t\t\t\t\tpart.Particle.Position = p.Center;\r\n\t\t\t\t\tpart.Particle.Velocity = p.GetAnyComponent<BodyComponent>().Velocity * -0.2f;\r\n\t\t\t\t\tpart.Particle.Scale = Rnd.Float(0.6f, 0.8f);\r\n\t\t\t\t\tpart.Depth = Layers.Creature;\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/TargetProjectileController.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class TargetProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(Entity target, float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar d = b.Velocity.Length();\n\t\t\t\tvar a = b.Velocity.ToAngle();\n\n\t\t\t\tvar from = p.Center;\n\n\t\t\t\tif (p.Owner.TryGetComponent<AimComponent>(out var aim)) {\n\t\t\t\t\tfrom = aim.RealAim;\n\t\t\t\t}\n\n\t\t\t\tif (target == null) {\n\t\t\t\t\tvar md = 320000f;\n\n\t\t\t\t\tforeach (var m in (p.Owner.TryGetComponent<RoomComponent>(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) {\n\t\t\t\t\t\tif (m.GetComponent<HealthComponent>().Unhittable) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar dd = m.DistanceTo(from);\n\n\t\t\t\t\t\tif (dd < md) {\n\t\t\t\t\t\t\tmd = dd;\n\t\t\t\t\t\t\ttarget = m;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (target == null) {\n\t\t\t\t\t\tb.Angle = b.Velocity.ToAngle();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (target.Done) {\n\t\t\t\t\ttarget = null;\n\t\t\t\t\tb.Angle = b.Velocity.ToAngle();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ta = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 16 * Math.Max(0.2f, 1 - Math.Min(1, p.DistanceTo(target) / 96)));\n\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t\tb.Angle = a;\n\t\t\t};\n\t\t}\n\n\t\tpublic static ProjectileCallbacks.UpdateCallback MakeCursor(float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar d = b.Velocity.Length();\n\t\t\t\tvar a = b.Velocity.ToAngle();\n\n\t\t\t\ta = (float) MathUtils.LerpAngle(a, p.AngleTo(p.Owner.GetComponent<CursorComponent>().Cursor.GamePosition) + Rnd.Float(-2, 2), dt * speed * 4);\n\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t\tb.Angle = a;\n\t\t\t};\n\t\t}\n\n\t\tpublic static ProjectileCallbacks.UpdateCallback MakeBetter(float speed = 1f) {\n\t\t\treturn (p, dt) => {\n\t\t\t\tvar b = p.GetAnyComponent<BodyComponent>();\n\t\t\t\tvar d = b.Velocity.Length();\n\t\t\t\tvar a = b.Velocity.ToAngle();\n\t\t\t\tEntity target = null;\n\t\t\t\t\n\t\t\t\tvar md = 320000f;\n\t\t\t\tvar from = p.Center;\n\n\t\t\t\tif (p.Owner.TryGetComponent<AimComponent>(out var aim)) {\n\t\t\t\t\tfrom = aim.RealAim;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tforeach (var m in (p.Owner.TryGetComponent<RoomComponent>(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) {\n\t\t\t\t\tif (m.Done || m.GetComponent<HealthComponent>().Unhittable) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar dd = m.DistanceTo(from);\n\n\t\t\t\t\tif (dd < md) {\n\t\t\t\t\t\tmd = dd;\n\t\t\t\t\t\ttarget = m;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (target == null) {\n\t\t\t\t\tb.Angle = b.Velocity.ToAngle();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ta = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 16 * Math.Max(0.3f, 1 - Math.Min(1, md / 96)));\n\t\t\t\tb.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t\t\tb.Angle = a;\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/TimedProjectileController.cs",
    "content": "using System;\nusing BurningKnight.assets.particle.custom;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class TimedProjectileController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make(float time, Action<Projectile> action) {\n\t\t\tvar t = 0f;\n\t\t\t\n\t\t\treturn (p, dt) => {\n\t\t\t\tt += dt;\n\n\t\t\t\tif (t >= time) {\n\t\t\t\t\tt = 0;\n\n\t\t\t\t\taction(p);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tpublic static ProjectileCallbacks.UpdateCallback MakeFadingParticles(float time, Color tint) {\n\t\t\treturn Make(time, p => {\n\t\t\t\tvar pr = new FadingParticle(p.GetComponent<ProjectileGraphicsComponent>().Sprite, tint);\n\t\t\t\tp.Area.Add(pr);\n\t\t\t\tpr.Center = p.Center;\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/controller/WhatController.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.util;\n\nnamespace BurningKnight.entity.projectile.controller {\n\tpublic static class WhatController {\n\t\tpublic static ProjectileCallbacks.UpdateCallback Make() {\n\t\t\tvar time = 0f;\n\t\t\tvar i = 0;\n\n\t\t\treturn (p, dt) => {\n\t\t\t\ttime += dt;\n\n\t\t\t\tif (time >= 0.3f) {\n\t\t\t\t\ttime = 0;\n\t\t\t\t\ti++;\n\n\t\t\t\t\tvar builder = new ProjectileBuilder(p.Owner, \"circle\");\n\n\t\t\t\t\tbuilder.Shoot(p.GetAnyComponent<BodyComponent>().Velocity.ToAngle() + i / 4f * (float) Math.PI, 8f);\n\t\t\t\t\tbuilder.Range = 1f;\n\n\t\t\t\t\tvar projectile = builder.Build();\n\t\t\t\t\tprojectile.Center = p.Center;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/pattern/CircleProjectilePattern.cs",
    "content": "using System;\r\nusing BurningKnight.entity.component;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.projectile.pattern {\r\n\tpublic static class CircleProjectilePattern {\r\n\t\tpublic static ProjectilePatternController Make(float radius, float speed) {\r\n\t\t\treturn (p, data, pt, i, dt) => {\r\n\t\t\t\tvar angle = pt.T * speed + ((float) i) / pt.Count * Math.PI * 2;\r\n\t\t\t\tp.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius);\r\n\r\n\t\t\t\tvar body = p.GetAnyComponent<BodyComponent>()?.Body;\r\n\r\n\t\t\t\tif (body != null) {\r\n\t\t\t\t\tbody.Rotation = (float) angle;\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/pattern/CircleWithCenterProjectilePattern.cs",
    "content": "using System;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.entity.projectile.pattern {\r\n\tpublic static class CircleWithCenterProjectilePattern {\r\n\t\tpublic static ProjectilePatternController Make(float radius, float speed) {\r\n\t\t\treturn (p, data, pt, i, dt) => {\r\n\t\t\t\tif (i == 0) {\r\n\t\t\t\t\tp.Center = pt.Center;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tvar angle = pt.T * speed + ((float) i) / (pt.Count - 1) * Math.PI * 2;\r\n\t\t\t\tp.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius); \r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/pattern/ExpandingCirclePattern.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.projectile.pattern {\n\tpublic static class ExpandingCirclePattern {\n\t\tpublic static ProjectilePatternController Make(int total, float radius, float speed, float delay, float expansionSpeed, float rotationDelay) {\n\t\t\treturn (p, data, pt, i, dt) => {\n\t\t\t\tif (pt.T > delay) {\n\t\t\t\t\tradius += Math.Max(0, Math.Min(1, (pt.T - delay) / delay)) * expansionSpeed * dt;\n\t\t\t\t}\n\n\t\t\t\tvar angle = Math.Max(0, Math.Min(1, (pt.T) / rotationDelay)) * pt.T * speed + ((float) i) / (total) * Math.PI * 2;\n\t\t\t\tp.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius); \n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/projectile/pattern/KeepShapePattern.cs",
    "content": "using Lens.util;\n\nnamespace BurningKnight.entity.projectile.pattern {\n\tpublic static class KeepShapePattern {\n\t\tpublic static ProjectilePatternController Make(float speed) {\n\t\t\treturn (p, data, pt, i, dt) => {\n\t\t\t\tvar angle = pt.T * speed;\n\t\t\t\tp.Center = pt.Center + MathUtils.CreateVector(angle + data.Angle, data.Distance);\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/Room.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.entity.room.controller;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.entity.room {\n\tpublic class Room : SaveableEntity, PlaceableEntity {\n\t\tpublic int MapX;\n\t\tpublic int MapY;\n\t\tpublic int MapW = 4;\n\t\tpublic int MapH = 4;\n\t\tpublic TagLists Tagged = new TagLists();\n\t\tpublic RoomType Type;\n\t\tpublic bool Explored;\n\t\tpublic bool Cleared;\n\t\tpublic string Id;\n\t\tpublic RoomDef Parent;\n\t\tpublic Rect Rect;\n\t\t\n\t\tpublic List<RoomControllable> Controllable = new List<RoomControllable>();\n\t\tpublic List<RoomInput> Inputs = new List<RoomInput>();\n\t\tpublic List<Piston> Pistons = new List<Piston>();\n\t\tpublic List<RoomController> Controllers = new List<RoomController>();\n\t\tpublic List<Door> Doors = new List<Door>();\n\n\t\tprivate bool checkCleared;\n\t\tprivate Entity cleared;\n\t\tprivate float t;\n\n\t\tpublic void CheckCleared(Entity entity) {\n\t\t\tif (!Cleared) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tcheckCleared = true;\n\t\t\t\t\tcleared = entity;\n\t\t\t\t}, 0.1f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddTag(Tags.Room);\n\t\t}\n\n\t\tpublic ItemPool GetPool() {\n\t\t\tswitch (Type) {\n\t\t\t\tcase RoomType.Shop: return ItemPool.Shop;\n\t\t\t\tcase RoomType.Secret: return ItemPool.Secret;\n\t\t\t\tcase RoomType.Boss: return ItemPool.Boss;\n\t\t\t\tcase RoomType.Treasure: return ItemPool.Treasure;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tUpdateSize();\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tif (Type == RoomType.Shop || Type == RoomType.Treasure || Type == RoomType.Boss) {\n\t\t\t\tAddComponent(new LightComponent(this, 128f, new Color(1f, 0.9f, 0.5f, 0.8f)));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void UpdateSize() {\n\t\t\tX = MapX * 16 + 4;\n\t\t\tY = MapY * 16 - 4;\n\t\t\tWidth = MapW * 16 - 8;\n\t\t\tHeight = MapH * 16 - 8;\n\n\t\t\tRect = new Rect().Setup(MapX, MapY, MapW, MapH);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\t\t\t\n\t\t\tif (!settedUp && t >= 0.1f) {\n\t\t\t\tsettedUp = true;\n\t\t\t\tSetup();\n\n\t\t\t\tif (!Engine.EditingLevel && Type == RoomType.Hidden) {\n\t\t\t\t\tHide(true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tc.Update(dt);\n\t\t\t}\n\n\t\t\tif (checkCleared) {\n\t\t\t\tvar found = false;\n\n\t\t\t\tforeach (var m in Tagged[Tags.MustBeKilled]) {\n\t\t\t\t\tif (m.GetComponent<HealthComponent>().Health > 0) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\tif (!Cleared) {\n\t\t\t\t\t\tSpawnReward();\n\n\t\t\t\t\t\tCleared = true;\n\t\t\t\t\t\n\t\t\t\t\t\tcleared.HandleEvent(new RoomClearedEvent {\n\t\t\t\t\t\t\tRoom = this\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcheckCleared = false;\n\t\t\t}\n\t\t}\n\n\t\tprivate static string[] rewards = {\n\t\t\t// \"bk:copper_coin\",\n\t\t\t\"bk:key\",\n\t\t\t\"bk:key\",\n\t\t\t\"bk:bomb\",\n\t\t\t\"bk:bomb\",\n\t\t\t\"bk:troll_bomb\",\n\t\t\t// \"bk:heart\",\n\t\t\t// \"bk:heart\",\n\t\t\t\"bk:pouch\",\n\t\t\t\"bk:copper_coin\"\n\t\t};\n\n\t\tprivate Entity CreateReward() {\n\t\t\tif (Rnd.Chance(LevelSave.ChestRewardChance)) {\n\t\t\t\treturn ChestRegistry.PlaceRandom(Vector2.Zero, Area);\n\t\t\t}\n\n\t\t\tvar id = rewards[Rnd.Int(rewards.Length)];\n\n\t\t\tif (id == \"bk:troll_bomb\") {\n\t\t\t\tvar bomb = new Bomb(null);\n\t\t\t\tArea.Add(bomb);\n\t\t\t\t\n\t\t\t\treturn bomb;\n\t\t\t}\n\t\t\t\n\t\t\treturn Items.CreateAndAdd(id, Area);\n\t\t}\n\n\t\tprivate void SpawnReward() {\n\t\t\tif (Run.Depth < 1 || Type != RoomType.Regular || Rnd.Chance(40 - Run.Luck)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var e in Tagged[Tags.LevelSave]) {\n\t\t\t\tif (e is MovingPlatform) {\n\t\t\t\t\t// To avoid it getting stuck\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar where = new Dot(MapX + MapW / 2, MapY + MapH / 2);\n\t\t\t\n\t\t\tfor (var x = -1; x < 2; x++) {\n\t\t\t\tfor (var y = -1; y < 2; y++) {\n\t\t\t\t\tvar x1 = x;\n\t\t\t\t\tvar y1 = y;\n\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tvar part = new TileParticle();\n\n\t\t\t\t\t\tpart.Top = Run.Level.Tileset.FloorD[0];\n\t\t\t\t\t\tpart.TopTarget = Run.Level.Tileset.WallTopADecor;\n\t\t\t\t\t\tpart.Side = Run.Level.Tileset.FloorSidesD[0];\n\t\t\t\t\t\tpart.Sides = Run.Level.Tileset.WallSidesA[2];\n\t\t\t\t\t\tpart.Tile = Tile.FloorD;\n\n\t\t\t\t\t\tpart.X = (where.X + x1) * 16;\n\t\t\t\t\t\tpart.Y = (where.Y + y1) * 16 + 8;\n\t\t\t\t\t\tpart.Target.X = (where.X + x1) * 16;\n\t\t\t\t\t\tpart.Target.Y = (where.Y + y1) * 16 + 8;\n\t\t\t\t\t\tpart.TargetZ = -8f;\n\n\t\t\t\t\t\tArea.Add(part);\n\t\t\t\t\t}, Rnd.Float(1f));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tTimer.Add(() => {\n\t\t\t\tvar reward = CreateReward();\n\t\t\t\treward.BottomCenter = where * 16 + new Vector2(8, 24);\n\t\t\t\tAnimationUtil.Poof(reward.Center);\n\t\t\t}, 1.5f);\n\t\t}\n\n\t\tprivate bool settedUp;\n\t\t\n\t\tprivate void Setup() {\n\t\t\tvar level = Run.Level;\n\t\t\tExplored = level.Explored[level.ToIndex(MapX + 1, MapY + 1)];\n\t\t\t\n\t\t\tApplyToEachTile((x, y) => {\n\t\t\t\tvar tile = level.Get(x, y);\n\n\t\t\t\tif (tile.Matches(Tile.Piston, Tile.PistonDown)) {\n\t\t\t\t\tPistons.Add(new Piston(x, y));\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tc.Init();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tc.Destroy();\n\t\t\t}\n\n\t\t\tPistons.Clear();\n\t\t\tControllable.Clear();\n\t\t\tInputs.Clear();\n\t\t}\n\n\t\tpublic void Discover() {\n\t\t\tExplored = true;\n\t\t\t\n\t\t\tApplyToEachTile((x, y) => {\n\t\t\t\tRun.Level.Explored[Run.Level.ToIndex(x, y)] = true;\n\t\t\t});\n\t\t}\n\n\t\tpublic void Hide(bool fast = false) {\n\t\t\tExplored = false;\n\t\t\t\n\t\t\tApplyToEachTile((x, y) => {\n\t\t\t\tvar i = Run.Level.ToIndex(x, y);\n\n\t\t\t\tif (!Run.Level.Get(i).IsWall() || !Run.Level.Get(i + Run.Level.Width).IsWall()) {\n\t\t\t\t\tRun.Level.Explored[i] = false;\n\n\t\t\t\t\tif (fast) {\n\t\t\t\t\t\tRun.Level.Light[i] = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tTween.To(0, 1f, xx => Run.Level.Light[i] = xx, 0.5f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, Type == RoomType.DarkMarket || Type == RoomType.Hidden ? 1 : 0);\n\t\t}\n\t\t\n\t\tpublic void ApplyToEachTile(Action<int, int> callback, int offset = 0) {\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tfor (int y = MapY + offset; y < MapY + MapH - 1 - offset; y++) {\n\t\t\t\tfor (int x = MapX + offset; x < MapX + MapW - offset; x++) {\n\t\t\t\t\tif (level.IsInside(x, y)) {\n\t\t\t\t\t\tcallback(x, y);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Generate() {\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tc.Generate();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tMapX = stream.ReadInt16();\n\t\t\tMapY = stream.ReadInt16();\n\t\t\tMapW = stream.ReadInt16();\n\t\t\tMapH = stream.ReadInt16();\n\t\t\t\n\t\t\tType = RoomRegistry.FromIndex(stream.ReadByte());\n\t\t\t\n\t\t\tvar count = stream.ReadByte();\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar c = RoomControllerRegistery.Get(stream.ReadString());\n\n\t\t\t\tif (c != null) {\n\t\t\t\t\tControllers.Add(c);\n\t\t\t\t\tc.Room = this;\n\t\t\t\t\tc.Load(stream);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tId = stream.ReadString();\n\t\t}\n\t\t\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteInt16((short) MapX);\n\t\t\tstream.WriteInt16((short) MapY);\n\t\t\tstream.WriteInt16((short) MapW);\n\t\t\tstream.WriteInt16((short) MapH);\n\n\t\t\tstream.WriteByte((byte) RoomRegistry.FromType(Type));\n\t\t\tstream.WriteByte((byte) Controllers.Count);\n\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tstream.WriteString(c.Id);\n\t\t\t\tc.Save(stream);\n\t\t\t}\n\n\t\t\tstream.WriteString(Id);\n\t\t}\n\t\t\n\t\tprotected int GetRenderLeft(Camera camera, Level level) {\n\t\t\treturn (int) MathUtils.Clamp(0, level.Width - 1, Math.Max((int) Math.Floor(camera.X / 16 - 1f), MapX));\n\t\t}\n\n\t\tprotected int GetRenderTop(Camera camera, Level level) {\n\t\t\treturn (int) MathUtils.Clamp(0, level.Height - 1, Math.Max((int) Math.Floor(camera.Y / 16 - 1f), MapY));\n\t\t}\n\n\t\tprotected int GetRenderRight(Camera camera, Level level) {\n\t\t\treturn (int) MathUtils.Clamp(0, level.Width - 1, Math.Min((int) Math.Ceiling(camera.Right / 16 + 1f), MapX + MapW));\n\t\t}\n\n\t\tprotected int GetRenderBottom(Camera camera, Level level) {\n\t\t\treturn (int) MathUtils.Clamp(0, level.Height - 1, Math.Min((int) Math.Ceiling(camera.Bottom / 16 + 1f), MapY + MapH));\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tGraphics.Batch.DrawRectangle(new RectangleF(X, Y, Width, Height), Color.Red);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tvar v = (int) Type;\n\n\t\t\tif (ImGui.Combo(\"Type\", ref v, RoomRegistry.Names, RoomRegistry.Names.Length)) {\n\t\t\t\tType = (RoomType) v;\n\t\t\t}\n\n\t\t\tif (Id == null) {\n\t\t\t\tId = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tImGui.InputText(\"Id\", ref Id, 128);\n\t\t\tImGui.Separator();\n\n\t\t\tImGui.InputInt(\"Map X\", ref MapX);\n\t\t\tImGui.InputInt(\"Map Y\", ref MapY);\n\t\t\tImGui.InputInt(\"Map W\", ref MapW);\n\t\t\tImGui.InputInt(\"Map H\", ref MapH);\n\n\t\t\tif (Id == null) {\n\t\t\t\tId = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Text($\"Doors: {Doors.Count}\");\n\n\t\t\tX = MapX * 16 + 4;\n\t\t\tY = MapY * 16 - 4;\n\t\t\tWidth = MapW * 16 - 8;\n\t\t\tHeight = MapH * 16 - 8;\n\n\t\t\t/*if (ImGui.Button(\"Sync\")) {\n\t\t\t\tMapX = (int) Math.Floor(X / 16);\n\t\t\t\tMapY = (int) Math.Floor(Y / 16);\n\t\t\t\tMapW = (int) Math.Floor(Width / 16);\n\t\t\t\tMapH = (int) Math.Floor(Height / 16);\n\t\t\t}*/\n\t\t}\n\n\t\tpublic List<Point> GetFreeTiles(Func<int, int, bool> filter = null) {\n\t\t\tvar list = new List<Point>();\n\n\t\t\tfor (var x = MapX + 1; x < MapX + MapW - 1; x++) {\n\t\t\t\tfor (var y = MapY + 1; y < MapY + MapH - 1; y++) {\n\t\t\t\t\tif (Run.Level.IsPassable(x, y) && (filter == null || filter(x, y))) {\n\t\t\t\t\t\tlist.Add(new Point(x, y));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn list;\n\t\t}\n\n\t\tpublic Vector2 GetRandomFreeTile(Func<int, int, bool> filter = null) {\n\t\t\tvar tiles = GetFreeTiles(filter);\n\n\t\t\tif (tiles.Count == 0) {\n\t\t\t\treturn Center;\n\t\t\t}\n\n\t\t\tvar tile = tiles[Rnd.Int(tiles.Count)];\n\t\t\treturn new Vector2(tile.X, tile.Y);\n\t\t}\n\n\t\tpublic Vector2 GetRandomFreeTileNearWall(Func<int, int, bool> filter = null) {\n\t\t\treturn GetRandomFreeTile((x, y) => {\n\t\t\t\tif (Run.Level.CheckFor(x - 1, y, TileFlags.Passable)\n\t\t\t\t&& Run.Level.CheckFor(x + 1, y, TileFlags.Passable)\n\t\t\t\t&& Run.Level.CheckFor(x, y - 1, TileFlags.Passable)\n\t\t\t\t&& Run.Level.CheckFor(x, y + 1, TileFlags.Passable)) {\n\t\t\t\t\t// No wall here :/\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn filter == null || filter(x, y);\n\t\t\t});\n\t\t}\n\t\t\n\t\tpublic Vector2 GetRandomWallFreeTile(Func<int, int, bool> filter = null) {\n\t\t\treturn GetRandomFreeTile((x, y) => {\n\t\t\t\tif (!Run.Level.CheckFor(x - 1, y, TileFlags.Passable)\n\t\t\t\t    || !Run.Level.CheckFor(x + 1, y, TileFlags.Passable)\n\t\t\t\t    || !Run.Level.CheckFor(x, y - 1, TileFlags.Passable)\n\t\t\t\t    || !Run.Level.CheckFor(x, y + 1, TileFlags.Passable)) {\n\t\t\t\t\t// Wall here :/\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn filter == null || filter(x, y);\n\t\t\t});\n\t\t}\n\n\t\tpublic void AddController(string id) {\n\t\t\tvar c = RoomControllerRegistery.Get(id);\n\n\t\t\tif (c != null) {\n\t\t\t\tControllers.Add(c);\n\t\t\t\tc.Room = this;\n\t\t\t\tc.Init();\n\t\t\t}\n\t\t}\n\n\t\tpublic void HandleInputChange(RoomInput.ChangedEvent e) {\n\t\t\tforeach (var c in Controllers) {\n\t\t\t\tc.HandleInputChange(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic Entity FindClosest(Vector2 to, int tag, Func<Entity, bool> filter = null) {\n\t\t\tvar min = float.MaxValue;\n\t\t\tEntity en = null;\n\t\t\t\n\t\t\tforeach (var e in Tagged[tag]) {\n\t\t\t\tif (filter?.Invoke(e) ?? true) {\n\t\t\t\t\tvar d = e.DistanceTo(to);\n\n\t\t\t\t\tif (d < min) {\n\t\t\t\t\t\tmin = d;\n\t\t\t\t\t\ten = e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn en;\n\t\t}\n\n\t\tpublic void OpenHiddenDoors() {\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tforeach (var door in Doors) {\n\t\t\t\tvar x = (int) Math.Floor(door.CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(door.CenterY / 16);\n\t\t\t\tvar t = level.Get(x, y);\n\n\t\t\t\tif (t == Tile.WallA || t == Tile.WallB) {\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\t\t\t\n\t\t\t\t\tlevel.Set(index, Type == RoomType.OldMan ? Tile.EvilFloor : Tile.GrannyFloor);\n\t\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t\t\t\tlevel.LoadPassable();\n\n\t\t\t\t\tExplosionMaker.LightUp(x * 16 + 8, y * 16 + 8);\n\n\t\t\t\t\tLevel.Animate(Area, x, y);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void CloseHiddenDoors() {\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tforeach (var door in Doors) {\n\t\t\t\tvar x = (int) Math.Floor(door.CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(door.Bottom / 16);\n\t\t\t\tvar t = level.Get(x, y);\n\n\t\t\t\tif (level.Get(x, y).Matches(TileFlags.Passable)) {\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\t\t\t\n\t\t\t\t\tlevel.Set(index, level.Biome is IceBiome ? Tile.WallB : Tile.WallA);\n\t\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\t\t\t\t\tlevel.LoadPassable();\n\n\t\t\t\t\tHide();\n\n\t\t\t\t\tCamera.Instance.Shake(10);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void PaintTunnel(List<Door> Doors, Tile Floor, Rect space = null, bool Bold = false, bool shift = true, bool randomRect = true) {\n\t\t\tif (Doors.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar Level = Run.Level;\n\t\t\tvar C = space;\n\n\t\t\tif (C == null) {\n\t\t\t\tvar c = new Dot(MapX + MapW /2, MapY + MapH / 2);\n\t\t\t\tC = new Rect(c.X, c.Y, c.X, c.Y);\n\t\t\t}\n\n\t\t\tvar minLeft = C.Left;\n\t\t\tvar maxRight = C.Right;\n\t\t\tvar minTop = C.Top;\n\t\t\tvar maxBottom = C.Bottom;\n\t\t\tvar Right = MapX + MapW - 1;\n\t\t\tvar Bottom = MapY + MapH - 1;\n\n\t\t\tPainter.Clip = new Rect(MapX, MapY, MapX + MapW - 1, MapY + MapH - 1);\n\n\t\t\tforeach (var Door in Doors) {\n\t\t\t\tvar dx = (int) Math.Floor(Door.CenterX / 16f);\n\t\t\t\tvar dy = (int) Math.Floor(Door.CenterY / 16f);\n\t\t\t\tvar Start = new Dot(dx, dy);\n\t\t\t\tDot Mid;\n\t\t\t\tDot End;\n\n\t\t\t\tif (shift) {\n\t\t\t\t\tif ((int) Start.X == MapX) {\n\t\t\t\t\t\tStart.X++;\n\t\t\t\t\t} else if ((int) Start.Y == MapY) {\n\t\t\t\t\t\tStart.Y++;\n\t\t\t\t\t} else if ((int) Start.X == Right) {\n\t\t\t\t\t\tStart.X--;\n\t\t\t\t\t} else if ((int) Start.Y == Bottom) {\n\t\t\t\t\t\tStart.Y--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tint RightShift;\n\t\t\t\tint DownShift;\n\n\t\t\t\tif (Start.X < C.Left) {\n\t\t\t\t\tRightShift = (int) (C.Left - Start.X);\n\t\t\t\t} else if (Start.X > C.Right) {\n\t\t\t\t\tRightShift = (int) (C.Right - Start.X);\n\t\t\t\t} else {\n\t\t\t\t\tRightShift = 0;\n\t\t\t\t}\n\n\t\t\t\tif (Start.Y < C.Top) {\n\t\t\t\t\tDownShift = (int) (C.Top - Start.Y);\n\t\t\t\t} else if (Start.Y > C.Bottom) {\n\t\t\t\t\tDownShift = (int) (C.Bottom - Start.Y);\n\t\t\t\t} else {\n\t\t\t\t\tDownShift = 0;\n\t\t\t\t}\n\n\t\t\t\tif (dx == MapX || dx == Right) {\n\t\t\t\t\tMid = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Start.X + RightShift), MathUtils.Clamp(MapY + 1, Bottom - 1, Start.Y));\n\t\t\t\t\tEnd = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Mid.X), MathUtils.Clamp(MapY + 1, Bottom - 1, Mid.Y + DownShift));\n\t\t\t\t} else {\n\t\t\t\t\tMid = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Start.X), MathUtils.Clamp(MapY + 1, Bottom - 1, Start.Y + DownShift));\n\t\t\t\t\tEnd = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Mid.X + RightShift), MathUtils.Clamp(MapY + 1, Bottom - 1, Mid.Y));\n\t\t\t\t}\n\n\t\t\t\tPainter.DrawLine(Level, Start, Mid, Floor, Bold);\n\t\t\t\tPainter.DrawLine(Level, Mid, End, Floor, Bold);\n\n\t\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\t\tPainter.Set(Level, End, Tiles.RandomFloor());\n\t\t\t\t}\n\n\t\t\t\tminLeft = Math.Min(minLeft, End.X);\n\t\t\t\tminTop = Math.Min(minTop, End.Y);\n\t\t\t\tmaxRight = Math.Max(maxRight, End.X);\n\t\t\t\tmaxBottom = Math.Max(maxBottom, End.Y);\n\t\t\t}\n\n\t\t\tif (randomRect && Rnd.Chance(20)) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tminLeft--;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tminTop--;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tmaxRight++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tmaxBottom++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tminLeft = MathUtils.Clamp(MapX + 1, Right - 1, minLeft);\n\t\t\tminTop = MathUtils.Clamp(MapY + 1, Bottom - 1, minTop);\n\t\t\tmaxRight = MathUtils.Clamp(MapX + 1, Right - 1, maxRight);\n\t\t\tmaxBottom = MathUtils.Clamp(MapY + 1, Bottom - 1, maxBottom);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Rect(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Clip = null;\n\t\t}\n\n\t\tpublic bool ContainsTile(int x, int y, int d = 0) {\n\t\t\treturn x >= MapX + d && x < MapX + MapW - d && y >= MapY + d - 1 && y < MapY + MapH - d;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/AlwaysOnSpikes.cs",
    "content": "using BurningKnight.entity.room.controllable.spikes;\nusing Lens.entity.component.logic;\n\nnamespace BurningKnight.entity.room.controllable {\n\tpublic class AlwaysOnSpikes : Spikes {\n\t\tprotected override void InitState() {\n\t\t\tOn = true;\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/FireTrap.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable {\n\tpublic class FireTrap : RoomControllable {\n\t\tprivate static TextureRegion tile;\n\t\tprivate float timer;\n\t\tprivate bool flaming;\n\t\tprivate float lastParticle;\n\t\t\n\t\tprotected List<Entity> Colliding = new List<Entity>();\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tDepth = Layers.Entrance;\n\n\t\t\tif (tile == null) {\n\t\t\t\ttile = CommonAse.Props.GetSlice(\"firetrap\");\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(1, 1, 11, 14, BodyType.Static, true));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tResetTimer();\n\t\t}\n\n\t\tprivate void ResetTimer() {\n\t\t\ttimer = X / 256f * 5f % 5f;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!On) {\n\t\t\t\tResetTimer();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room.Tagged[Tags.Player].Count == 0 || room.Tagged[Tags.MustBeKilled].Count == 0) {\n\t\t\t\t\tResetTimer();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimer += dt;\n\n\t\t\tif (flaming) {\n\t\t\t\tif (timer <= 0.3f) {\n\t\t\t\t\tlastParticle -= dt;\n\t\t\t\t\t\n\t\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\t\tlastParticle = 0.1f;\n\t\t\t\t\t\t\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\tPosition = new Vector2(CenterX, CenterY),\n\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\tMod = 2\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (timer >= 1.5f) {\n\t\t\t\t\tlastParticle -= dt;\n\t\t\t\t\tHurt();\n\n\t\t\t\t\tif (lastParticle <= 0) {\n\t\t\t\t\t\tlastParticle = 0.15f;\n\t\t\t\t\t\t\n\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\tPosition = new Vector2(CenterX, CenterY),\n\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\tMod = 4\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (timer >= 5f) {\n\t\t\t\t\t\ttimer = 0;\n\t\t\t\t\t\tflaming = false;\n\t\t\t\t\t}\n\t\t\t\t}\t\n\t\t\t} else {\n\t\t\t\tif (timer >= 5f) {\n\t\t\t\t\ttimer = 0;\n\t\t\t\t\tflaming = true;\n\t\t\t\t\tlastParticle = 0;\n\t\t\t\t}\t\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Render(tile, Position);\n\t\t}\n\t\t\n\t\tprotected virtual bool ShouldHurt(Entity e) {\n\t\t\treturn e is Player;\n\t\t}\n\t\t\n\t\tprotected void Hurt() {\n\t\t\tforeach (var c in Colliding) {\n\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-1, this);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (ShouldHurt(cse.Entity)) {\n\t\t\t\t\tColliding.Add(cse.Entity);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tColliding.Remove(cee.Entity);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/Piston.cs",
    "content": "using BurningKnight.level.tile;\r\nusing BurningKnight.state;\r\n\r\nnamespace BurningKnight.entity.room.controllable {\r\n\tpublic class Piston {\r\n\t\tpublic readonly int X;\r\n\t\tpublic readonly int Y;\r\n\r\n\t\tpublic Piston(int x, int y) {\r\n\t\t\tX = x;\r\n\t\t\tY = y;\r\n\t\t}\r\n\r\n\t\tpublic bool IsOn() {\r\n\t\t\treturn Run.Level.Get(X, Y) == Tile.Piston;\r\n\t\t}\r\n\r\n\t\tpublic void Set(bool value) {\r\n\t\t\tif (IsOn() != value) {\r\n\t\t\t\tRun.Level.Set(X, Y, value ? Tile.Piston : Tile.PistonDown);\r\n\t\t\t\tRun.Level.ReCreateBodyChunk(X, Y);\r\n\t\t\t\tRun.Level.UpdateTile(X, Y);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void Toggle() {\r\n\t\t\tSet(!IsOn());\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/RollingSpike.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.room.controllable {\n\tpublic class RollingSpike : RoomControllable, CollisionFilterEntity {\n\t\tpublic Vector2 StartVelocity = new Vector2(32, 0);\n\t\tprivate List<Player> colliding = new List<Player>();\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tvar b = new CircleBodyComponent(0, 0, 8);\n\t\t\tAddComponent(b);\n\t\t\t\n\t\t\tb.Body.Restitution = 1;\n\t\t\tb.Body.Friction = 0;\n\t\t\tb.Body.Mass = 100000f;\n\t\t\t\n\t\t\tvar a = new AnimationComponent(\"rolling_spike\");\n\t\t\tAddComponent(a);\n\n\t\t\tAlwaysActive = true;\n\t\t\ta.OriginY *= 0.5f;\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\n\t\t\tvar v = GetComponent<CircleBodyComponent>().Velocity;\n\t\t\t\n\t\t\tstream.WriteFloat(v.X);\n\t\t\tstream.WriteFloat(v.Y);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tStartVelocity = GetComponent<CircleBodyComponent>().Velocity = new Vector2(stream.ReadFloat(), stream.ReadFloat());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tGetComponent<CircleBodyComponent>().Velocity = StartVelocity;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tforeach (var p in colliding) {\n\t\t\t\tp.GetComponent<HealthComponent>().ModifyHealth(-1, this);\n\t\t\t\tp.GetAnyComponent<BodyComponent>()?.KnockbackFrom(this, 4);\n\t\t\t}\n\n\t\t\tvar velocity = GetComponent<CircleBodyComponent>().Velocity;\n\t\t\tvar a = velocity.ToAngle();\n\t\t\tvar l = velocity.Length();\n\n\t\t\tif (Math.Abs(a % (Math.PI * 0.5f)) >= 0.1f || l < 20) {\n\t\t\t\ta = (float) (Math.Floor(a / (Math.PI * 0.5f)) * (Math.PI * 0.5f));\n\t\t\t\tGetComponent<CircleBodyComponent>().Velocity = MathUtils.CreateVector(a, Math.Max(l, 32));\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<AnimationComponent>().Angle += Math.Sign(Math.Abs(velocity.X) > 0.1f ? velocity.X : velocity.Y) * dt * 10;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tvar n = ev.Entity;\n\n\t\t\t\tif (!(n is Prop) && !(n is Level) && !(n is Chasm) && !(n is RollingSpike)) {\n\t\t\t\t\tif (n is Player p) {\n\t\t\t\t\t\tcolliding.Add(p);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee && cee.Entity is Player p) {\n\t\t\t\tcolliding.Remove(p);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\t// fixme: do not hurt\n\t\t\treturn !(entity is Projectile || entity is RollingSpike || (entity is Creature));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/RoomControllable.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.save;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\n\nnamespace BurningKnight.entity.room.controllable {\n\tpublic class RoomControllable : SaveableEntity, PlaceableEntity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new SupportableComponent());\n\t\t}\n\n\t\tpublic bool On { get; protected set; } = true;\n\t\t\n\t\tpublic virtual void TurnOn() {\n\t\t\tOn = true;\n\t\t}\n\n\t\tpublic virtual void TurnOff() {\n\t\t\tOn = false;\n\t\t}\n\n\t\tpublic void SetState(bool on) {\n\t\t\tif (on != On) {\n\t\t\t\tToggle();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Toggle() {\n\t\t\tif (On) {\n\t\t\t\tTurnOff();\n\t\t\t} else {\n\t\t\t\tTurnOn();\n\t\t\t}\n\t\t}\n\n\t\tprivate bool added;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!added) {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tadded = true;\n\t\t\t\troom.Controllable.Add(this);\n\t\t\t}\n\t\t}\n\n\t\tprotected void RemoveFromRoom() {\n\t\t\tGetComponent<RoomComponent>().Room?.Controllable.Remove(this);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tvar on = On;\n\n\t\t\tif (ImGui.Checkbox(\"On\", ref on)) {\n\t\t\t\tif (on) {\n\t\t\t\t\tTurnOn();\n\t\t\t\t} else {\n\t\t\t\t\tTurnOff();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/Support.cs",
    "content": "using System.Collections.Generic;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.room.controllable {\r\n\tpublic class Support : RoomControllable {\r\n\t\tpublic List<Entity> Supporting = new List<Entity>();\r\n\t\r\n\t\tpublic virtual void Apply(Entity e, float dt) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic class StartedSupportingEvent : Event {\r\n\t\t\tpublic Support Support;\r\n\t\t\tpublic Entity Entity;\r\n\t\t}\r\n\t\t\r\n\t\tpublic class EndedSupportingEvent : Event {\r\n\t\t\tpublic Support Support;\r\n\t\t\tpublic Entity Entity;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/platform/MovingPlatform.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable.platform {\n\tpublic class MovingPlatform : Platform, CollisionFilterEntity {\n\t\tprotected byte tw = 2;\n\t\tprotected byte th = 2;\n\n\t\tpublic PlatformController Controller = PlatformController.LeftRight;\n\t\tpublic int StartingStep;\n\t\t\n\t\tprivate int step;\n\t\tprivate Vector2 velocity;\n\n\t\tprivate PlatformBorder left;\n\t\tprivate PlatformBorder right;\n\t\tprivate PlatformBorder up;\n\t\tprivate PlatformBorder down;\n\n\t\tprotected virtual string GetAnimation() {\n\t\t\treturn \"moving_platform\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = tw * 16;\n\t\t\tHeight = th * 16 + 6;\n\t\t\tOn = true;\n\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new AnimationComponent(GetAnimation()));\n\n\t\t\tvar w = tw * 16;\n\t\t\tvar h = th * 16;\n\t\t\tvar b = new RectBodyComponent(0.5f, 0.5f - 1, w - 1, h + 3);\n\t\t\tAddComponent(b);\n\t\t\t\n\t\t\tb.Body.Friction = 0;\n\t\t\t\n\t\t\tArea.Add(left = new PlatformBorder());\n\t\t\tleft.Setup(this, -12, 0, 8, th * 16);\n\t\t\t\n\t\t\tArea.Add(right = new PlatformBorder());\n\t\t\tright.Setup(this, tw * 16 + 4, 0, 8, th * 16);\n\t\t\t\n\t\t\tArea.Add(up = new PlatformBorder());\n\t\t\tup.Setup(this, 0, -8, tw * 16, 8);\n\t\t\t\n\t\t\tArea.Add(down = new PlatformBorder());\n\t\t\tdown.Setup(this, 0, th * 16 + 1, tw * 16, 8);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tstep = StartingStep;\n\t\t\tStop();\n\t\t}\n\n\t\tprotected override bool ShouldMove(Entity e) {\n\t\t\treturn base.ShouldMove(e) && e.Bottom < Bottom - 4;\n\t\t}\n\n\t\tprotected void ResetBorders() {\n\t\t\tleft.On = true;\n\t\t\tright.On = true;\n\t\t\tup.On = true;\n\t\t\tdown.On = true;\n\t\t}\n\n\t\tprotected void RoundUp() {\n\t\t\tvar x = ((int) Math.Round(X / 16)) * 16;\n\t\t\tvar y = ((int) Math.Round(Y / 16)) * 16;\n\n\t\t\tif (MathUtils.Distance(X - x, Y - y) < 3) {\n\t\t\t\tX = x;\n\t\t\t\tY = y;\n\t\t\t}\n\t\t}\n\n\t\t#region Platform States\n\t\tprotected class IdleState : SmartState<MovingPlatform> {\n\t\t\tprivate const float Delay = 1f;\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\n\t\t\t\tif (Self.On && T >= Delay) {\n\t\t\t\t\tBecome<MovingState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected class MovingState : SmartState<MovingPlatform> {\n\t\t\tprivate const float Speed = 48;\n\t\t\tprivate bool first = true;\n\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.ResetBorders();\n\t\t\t\tSelf.Center -= Self.velocity * 0.1f;\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\n\t\t\t\tif (Math.Abs(Self.velocity.X) + Math.Abs(Self.velocity.Y) < 0.1f) {\n\t\t\t\t\tSelf.velocity = directions[Rnd.Int(2) + 2];\n\t\t\t\t}\n\n\t\t\t\tif (Math.Abs(Self.velocity.X) > 0.1f && Math.Abs(Self.velocity.Y) > 0.1f) {\n\t\t\t\t\tSelf.velocity.Y = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Self.velocity * Speed;\n\n\t\t\t\tif (Math.Abs(Self.velocity.X) > 0.1f) {\n\t\t\t\t\tvar s = (int) Math.Round(Self.Y / 16);\n\t\t\t\t\tvar x = (int) (Self.velocity.X > 0 ? (Math.Ceiling(Self.X / 16) + Self.tw - 1) : (Math.Floor(Self.X / 16)));\n\t\t\t\t\t\n\t\t\t\t\tfor (var y = s; y < s + Self.th; y++) {\n\t\t\t\t\t\tvar t = Run.Level.Get(x, y);\n\n\t\t\t\t\t\tif (t != Tile.Chasm) {\n\t\t\t\t\t\t\tSelf.RoundUp();\n\t\t\t\t\t\t\tSelf.ResetBorders();\n\n\t\t\t\t\t\t\tif (Self.velocity.X > 0) {\n\t\t\t\t\t\t\t\tSelf.right.On = false;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tSelf.left.On = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tSelf.Stop();\n\n\t\t\t\t\t\t\tif (first) {\n\t\t\t\t\t\t\t\tBecome<MovingState>();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvar s = (int) Math.Round(Self.X / 16);\n\t\t\t\t\tvar y = (int) (Self.velocity.Y > 0 ? (Math.Ceiling(Self.Y / 16) + Self.th - 1) : (Math.Floor(Self.Y / 16)));\n\t\t\t\t\t\n\t\t\t\t\tfor (var x = s; x < s + Self.tw; x++) {\n\t\t\t\t\t\tvar t = Run.Level.Get(x, y);\n\n\t\t\t\t\t\tif (t != Tile.Chasm) {\n\t\t\t\t\t\t\tSelf.RoundUp();\n\t\t\t\t\t\t\tSelf.ResetBorders();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (Self.velocity.Y > 0) {\n\t\t\t\t\t\t\t\tSelf.down.On = false;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tSelf.up.On = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tSelf.Stop();\n\n\t\t\t\t\t\t\tif (first) {\n\t\t\t\t\t\t\t\tBecome<MovingState>();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfirst = false;\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<RectBodyComponent>().Velocity = Vector2.Zero;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprivate static Vector2[] directions = {\n\t\t\tnew Vector2(1, 0),\n\t\t\tnew Vector2(0, 1),\n\t\t\tnew Vector2(-1, 0),\n\t\t\tnew Vector2(0, -1)\n\t\t};\n\n\t\tprotected virtual void Stop() {\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t\tstep++;\n\n\t\t\tswitch (Controller) {\n\t\t\t\tcase PlatformController.LeftRight: default: {\n\t\t\t\t\tstep %= 2;\n\n\t\t\t\t\tif (Math.Abs(velocity.X) < 0.1f) {\n\t\t\t\t\t\tvelocity = directions[0];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvelocity.X *= -1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase PlatformController.UpDown: {\n\t\t\t\t\tstep %= 2;\n\n\t\t\t\t\tif (Math.Abs(velocity.Y) < 0.1f) {\n\t\t\t\t\t\tvelocity = directions[1];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvelocity.Y *= -1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase PlatformController.ClockWise: {\n\t\t\t\t\tstep %= 4;\n\t\t\t\t\tvelocity = directions[step];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase PlatformController.CounterClockWise: {\n\t\t\t\t\tstep %= 4;\n\t\t\t\t\tvelocity = directions[3 - step];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (OnScreen) {\n\t\t\t\tCamera.Instance.ShakeMax(4);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void TurnOn() {\n\t\t\tbase.TurnOn();\n\t\t\tGetComponent<StateComponent>().Become<MovingState>();\n\t\t}\n\n\t\tpublic override void TurnOff() {\n\t\t\tbase.TurnOff();\n\t\t\tGetComponent<StateComponent>().Become<IdleState>();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte((byte) Controller);\n\t\t\tstream.WriteByte((byte) StartingStep);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tController = (PlatformController) stream.ReadByte();\n\t\t\tStartingStep = stream.ReadByte();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent ev) {\n\t\t\t\tif (ev.Entity is MovingPlatform m) {\n\t\t\t\t\tvar rect = new Rectangle((int) X, (int) Y, (int) Width, (int) Height - 6);\n\t\t\t\t\t\n\t\t\t\t\trect.X += (int) (velocity.X * Width);\n\t\t\t\t\trect.Y += (int) (velocity.Y * (Height - 6));\n\n\t\t\t\t\tif (new Rectangle((int) m.X, (int) m.Y, (int) m.Width, (int) m.Height - 6).Intersects(rect)) {\n\t\t\t\t\t\tStop();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tbool CollisionFilterEntity.ShouldCollide(Entity entity) {\n\t\t\treturn entity is MovingPlatform;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/platform/Platform.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.save;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable.platform {\n\tpublic class Platform : Support {\n\t\tprivate Vector2 startingPoint;\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tDepth = -11;\n\t\t\tAlwaysActive = true;\n\t\t\tstartingPoint = Position;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tRemoveComponent<SupportableComponent>();\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tstartingPoint = new Vector2(stream.ReadInt32(), stream.ReadInt32());\n\t\t\tPosition = startingPoint;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteInt32((int) startingPoint.X);\n\t\t\tstream.WriteInt32((int) startingPoint.Y);\n\t\t}\n\n\t\tpublic override void Apply(Entity e, float dt) {\n\t\t\tvar b = e.GetAnyComponent<BodyComponent>();\n\n\t\t\tif (b == null || !ShouldMove(e)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Apply(e, dt);\n\t\t\tb.Position += GetComponent<RectBodyComponent>().Velocity * dt;\n\t\t}\n\n\t\tprotected virtual bool ShouldMove(Entity e) {\n\t\t\treturn !(e is Creature c && c.InAir());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/platform/PlatformBorder.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.entities;\nusing BurningKnight.physics;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable.platform {\n\tpublic class PlatformBorder : Entity, CollisionFilterEntity {\n\t\tpublic Support Super;\n\t\tpublic Vector2 Offset;\n\t\t\n\t\tprivate bool on = true;\n\t\t\n\t\tpublic bool On {\n\t\t\tset {\n\t\t\t\ton = value;\n\t\t\t\tGetComponent<RectBodyComponent>().Body.IsSensor = !value;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Setup(Support super, int x, int y, int w, int h) {\n\t\t\tSuper = super;\n\t\t\tOffset = new Vector2(x, y);\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, w, h, BodyType.Static));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Super == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Super.Done) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tPosition = Offset + Super.Position;\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\tif (!on) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn !(\n\t\t\t\tentity is Prop \n\t      || entity is Projectile \n\t\t\t  || entity is Level \n\t\t\t\t|| entity is Chasm \n\t\t\t\t|| (entity is Creature c && c.InAir()) \n\t\t\t\t|| (entity.TryGetComponent<TileInteractionComponent>(out var t) && (!t.HasNoTileSupport)) \n\t\t\t\t|| (entity.TryGetComponent<SupportableComponent>(out var s) && s.HasAnotherSupportBesides(Super))\n\t\t\t);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/platform/PlatformController.cs",
    "content": "namespace BurningKnight.entity.room.controllable.platform {\r\n\tpublic enum PlatformController {\r\n\t\tLeftRight,\r\n\t\tUpDown,\r\n\t\tClockWise,\r\n\t\tCounterClockWise\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/platform/SteppingPlatform.cs",
    "content": "using Lens.entity;\r\n\r\nnamespace BurningKnight.entity.room.controllable.platform {\r\n\tpublic class SteppingPlatform : MovingPlatform {\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tOn = false;\r\n\t\t}\r\n\r\n\t\tprotected override string GetAnimation() {\r\n\t\t\treturn \"stepping_platform\";\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is StartedSupportingEvent) {\r\n\t\t\t\tif (!On) {\r\n\t\t\t\t\tTurnOn();\r\n\t\t\t\t}\r\n\t\t\t} else if (e is EndedSupportingEvent) {\r\n\t\t\t\tif (On && Supporting.Count == 0) {\r\n\t\t\t\t\tTurnOff();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/spikes/SensingSpikes.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\n\nnamespace BurningKnight.entity.room.controllable.spikes {\n\tpublic class SensingSpikes : Spikes {\n\t\tprivate float timer;\n\t\tprivate bool wasTriggered;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (timer > 0) {\n\t\t\t\ttimer -= dt;\n\n\t\t\t\tif (timer <= 0) {\n\t\t\t\t\tTurnOff();\n\t\t\t\t}\n\t\t\t} else if (!On && Colliding.Count > 0) {\n\t\t\t\tforeach (var c in Colliding) {\n\t\t\t\t\tif (c is Player) {\n\t\t\t\t\t\ttimer = 1.5f;\n\t\t\t\t\t\tTurnOnSlowly();\n\n\t\t\t\t\t\tif (!wasTriggered) {\n\t\t\t\t\t\t\twasTriggered = true;\n\n\t\t\t\t\t\t\tif (Run.Statistics != null) {\n\t\t\t\t\t\t\t\tRun.Statistics.SpikesTriggered++;\n\n\t\t\t\t\t\t\t\tif (Run.Statistics.SpikesTriggered >= 100) {\n\t\t\t\t\t\t\t\t\tAchievements.Unlock(\"bk:spikes\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/spikes/Spikes.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable.spikes {\n\tpublic class Spikes : RoomControllable {\n\t\tprivate static TextureRegion tile;\n\t\tprivate static Vector2 offset = new Vector2(0, 5);\n\t\t\n\t\tprotected List<Entity> Colliding = new List<Entity>();\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tInitState();\n\t\t\tY -= offset.Y;\n\t\t}\n\n\t\tprotected virtual void InitState() {\n\t\t\tOn = false;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tHeight = 21;\n\n\t\t\tif (tile == null) {\n\t\t\t\ttile = CommonAse.Props.GetSlice(\"spikes_base\");\n\t\t\t}\n\n\t\t\tArea.Add(new RenderTrigger(this, RenderBase, Layers.Entrance));\n\t\t\t\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new AnimationComponent(\"spikes\"));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\tAddComponent(new RectBodyComponent(3, 5, 10, 10, BodyType.Static, true));\n\t\t\t\n\t\t\tGetComponent<StateComponent>().Become<HiddenState>();\n\t\t}\n\n\t\tprivate void RenderBase() {\n\t\t\tGraphics.Render(tile, Position + offset);\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphicsComponent.Offset.Y -= 7;\n\t\t\tGraphicsComponent.Render(true);\n\t\t\tGraphicsComponent.Offset.Y += 7;\n\t\t}\n\t\t\n\t\tpublic override void TurnOn() {\n\t\t\tbase.TurnOn();\n\t\t\tvar s = GetComponent<StateComponent>();\n\n\t\t\tif (s.StateInstance is HiddenState || s.StateInstance is HidingState) {\n\t\t\t\ts.Become<ShowingState>();\n\t\t\t}\n\t\t}\n\n\t\tpublic void TurnOnSlowly() {\n\t\t\tif (On) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tOn = true;\n\t\t\tvar s = GetComponent<StateComponent>();\n\n\t\t\tif (s.StateInstance is HiddenState || s.StateInstance is HidingState) {\n\t\t\t\ts.Become<FshowingState>();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void TurnOff() {\n\t\t\tbase.TurnOff();\n\t\t\tvar s = GetComponent<StateComponent>();\n\n\t\t\tif (s.StateInstance is IdleState || s.StateInstance is ShowingState || s.StateInstance is FshowingState) {\n\t\t\t\ts.Become<HidingState>();\n\t\t\t}\n\t\t}\n\n\t\tprotected void Hurt() {\n\t\t\tforeach (var c in Colliding) {\n\t\t\t\tif (!(c is Creature cc && cc.InAir()) || c is ExplodingBarrel) {\n\t\t\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(-1, this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t#region Spike States\n\t\tprotected class IdleState : SmartState<Spikes> {\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tSelf.Hurt();\n\t\t\t}\n\t\t}\n\n\t\tprotected class HiddenState : SmartState<Spikes> {\n\t\t\t\n\t\t}\n\n\t\tprotected class ShowingState : SmartState<Spikes> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\n\t\t\t\tif (Self.OnScreen) {\n\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"level_spike\", 1f - Audio.Db3);\n\t\t\t\t}\n\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tvar a = Self.GetComponent<AnimationComponent>().Animation;\n\n\t\t\t\tif (a.Frame > 3) {\n\t\t\t\t\tSelf.Hurt();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (a.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected class FshowingState : SmartState<Spikes> {\n\t\t\tprivate bool playedSfx;\n\t\t\t\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().Emit(\"level_spike_peaking\");\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tvar a = Self.GetComponent<AnimationComponent>().Animation;\n\n\t\t\t\tif (a.Frame > 2) {\n\t\t\t\t\tSelf.Hurt();\n\n\t\t\t\t\tif (!playedSfx) {\n\t\t\t\t\t\tplayedSfx = true;\n\n\t\t\t\t\t\tif (Self.OnScreen) {\n\t\t\t\t\t\t\tSelf.GetComponent<AudioEmitterComponent>().EmitRandomized(\"level_spike\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (a.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<IdleState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected class HidingState : SmartState<Spikes> {\n\t\t\tpublic override void Init() {\n\t\t\t\tbase.Init();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(true);\n\t\t\t}\n\n\t\t\tpublic override void Destroy() {\n\t\t\t\tbase.Destroy();\n\t\t\t\tSelf.GetComponent<AnimationComponent>().SetAutoStop(false);\n\t\t\t}\n\n\t\t\tpublic override void Update(float dt) {\n\t\t\t\tbase.Update(dt);\n\t\t\t\tvar a = Self.GetComponent<AnimationComponent>().Animation;\n\n\t\t\t\tif (a.Frame < 2) {\n\t\t\t\t\tSelf.Hurt();\n\t\t\t\t}\n\n\t\t\t\tif (a.Paused) {\n\t\t\t\t\tSelf.GetComponent<StateComponent>().Become<HiddenState>();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tprotected virtual bool ShouldHurt(Entity e) {\n\t\t\treturn e.HasComponent<HealthComponent>();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (ShouldHurt(cse.Entity)) {\n\t\t\t\t\tColliding.Add(cse.Entity);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tColliding.Remove(cee.Entity);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/turret/QuadRotatingTurret.cs",
    "content": "namespace BurningKnight.entity.room.controllable.turret {\n\tpublic class QuadRotatingTurret : QuadTurret {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tRotates = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/turret/QuadTurret.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\n\nnamespace BurningKnight.entity.room.controllable.turret {\n\tpublic class QuadTurret : Turret {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\t\t\t\n\t\t\ta.Animation.Tag = \"four\";\n\t\t\ta.Animation.Paused = true;\n\t\t}\n\n\t\tprotected override void Fire(double angle) {\n\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\tSendProjectile(angle + i * Math.PI / 2f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/turret/RotatingTurret.cs",
    "content": "namespace BurningKnight.entity.room.controllable.turret {\r\n\tpublic class RotatingTurret : Turret {\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tRotates = true;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controllable/turret/Turret.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.rooms;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.controllable.turret {\n\tpublic class Turret : RoomControllable, CollisionFilterEntity {\n\t\tprivate float beforeNextBullet;\n\t\tprotected bool Rotates;\n\n\t\tprotected uint Angle {\n\t\t\tget => GetComponent<AnimationComponent>().Animation.Frame;\n\t\t\tset => GetComponent<AnimationComponent>().Animation.Frame = value;\n\t\t}\n\n\t\tpublic uint StartingAngle;\n\t\tpublic bool ReverseDirection;\n\t\tpublic float TimingOffset;\n\t\tpublic float Speed = 1f;\n\n\t\tpublic override void Init() {\n\t\t\tY -= 4;\n\t\t\tbase.Init();\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(3, 4, 10, 11, BodyType.Static));\n\n\t\t\tvar a = new AnimationComponent(\"turret\", \"on\");\n\t\t\tAddComponent(a);\n\n\t\t\ta.Animation.Tag = \"single\";\n\t\t\ta.Animation.Paused = true;\n\t\t\ta.ShadowOffset = 4;\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new AudioEmitterComponent());\n\n\t\t\tAlwaysActive = true;\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\tOn = false;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent) {\n\t\t\t\tDone = true;\n\t\t\t\tRemoveFromRoom();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tStartingAngle = stream.ReadByte();\n\t\t\tReverseDirection = stream.ReadBoolean();\n\t\t\tTimingOffset = stream.ReadFloat();\n\t\t\tSpeed = stream.ReadFloat();\n\n\t\t\tif (Math.Abs(Speed) < 0.01f) {\n\t\t\t\tSpeed = 1f;\n\t\t\t}\n\n\t\t\tif (Run.Depth == -2 || Run.Depth == Run.ContentEndDepth) {\n\t\t\t\tTimingOffset = 0;\n\t\t\t\tbeforeNextBullet = 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte((byte) StartingAngle);\n\t\t\tstream.WriteBoolean(ReverseDirection);\n\t\t\tstream.WriteFloat(TimingOffset);\n\t\t\tstream.WriteFloat(Speed);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tAngle = StartingAngle;\n\t\t\t\n\t\t\tif (Run.Depth == Run.ContentEndDepth) {\n\t\t\t\tSpeed = 2.5f;\n\t\t\t\tTimingOffset = 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void TurnOn() {\n\t\t\tbase.TurnOn();\n\t\t\t\n\t\t\tbeforeNextBullet = 0.2f + TimingOffset % 3;\n\t\t\t\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\n\t\t\ta.Scale.X = 2f;\n\t\t\ta.Scale.Y = 0.4f;\n\t\t\ta.Animation.Layer = \"on\";\n\n\t\t\tTween.To(1f, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\tTween.To(1f, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\t\t}\n\n\t\tpublic override void TurnOff() {\n\t\t\tbase.TurnOff();\n\t\t\t\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\n\t\t\ta.Scale.X = 2f;\n\t\t\ta.Scale.Y = 0.4f;\n\t\t\ta.Animation.Layer = \"off\";\n\n\t\t\tTween.To(1f, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\tTween.To(1f, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\t// Always enabled in tutorial\n\t\t\tif (Run.Depth != -2 && On) {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (room != null && room.Type == RoomType.Regular) {\n\t\t\t\t\tif (room.Tagged[Tags.MustBeKilled].Count == 0) {\n\n\t\t\t\t\t\tTurnOff();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!On) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbeforeNextBullet -= dt * Speed;\n\n\t\t\tif (beforeNextBullet <= 0) {\n\t\t\t\tbeforeNextBullet = 3;\n\t\t\t\t\n\t\t\t\tvar a = GetComponent<AnimationComponent>();\n\n\t\t\t\tTween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\tTween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\n\t\t\t\t\tTween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\tTween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\n\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\t\t\t\tvar t = Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\t\t\t\tif (Rotates) {\n\t\t\t\t\t\t\tt.OnEnd = () => {\n\t\t\t\t\t\t\t\ta.Animate();\n\t\t\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"level_turret_rotating\");\n\t\t\t\t\t\t\t\tAngle = (uint) ((Angle + (ReverseDirection ? -1 : 1)) % 8);\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar r = GetComponent<RoomComponent>();\n\n\t\t\t\t\t\tif (r.Room != null && r.Room.Tagged[Tags.Player].Count > 0) {\n\t\t\t\t\t\t\tFire(Angle / 4f * Math.PI);\n\n\t\t\t\t\t\t\tif (OnScreen) {\n\t\t\t\t\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"level_turret_fire\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void Fire(double angle) {\n\t\t\tSendProjectile(angle);\n\t\t}\n\n\t\tprotected void SendProjectile(double angle) {\n\t\t\tvar builder = new ProjectileBuilder(this, \"small\") {\n\t\t\t\tLightRadius = 32f,\n\t\t\t\tColor = ProjectileColor.Red,\n\t\t\t\tPoof = true,\n\t\t\t};\n\n\t\t\tbuilder.Move(angle, 8f);\n\t\t\tbuilder.Shoot(angle, 6f);\n\t\t\tbuilder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee);\n\n\t\t\tbuilder.Build();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Run.Depth != -2 || On) {\n\t\t\t\tbase.Render();\n\t\t\t}\n\t\t}\n\n\t\tpublic void RenderShadow() {\n\t\t\tif (Run.Depth != -2 || On) {\n\t\t\t\tGraphicsComponent.Render(true);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tvar u = (int) StartingAngle;\n\n\t\t\tif (ImGui.InputInt(\"Starting angle\", ref u)) {\n\t\t\t\tAngle = StartingAngle = (uint) u % 8;\n\t\t\t}\n\n\t\t\tImGui.InputFloat(\"Before next\", ref beforeNextBullet);\n\t\t\tImGui.InputFloat(\"Speed\", ref Speed);\n\t\t}\n\t\t\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Chasm);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/BossRoomController.cs",
    "content": "using BurningKnight.entity.room.controllable.turret;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class BossRoomController : RoomController {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tforeach (var c in Room.Controllable) {\n\t\t\t\tif (c is Turret t) {\n\t\t\t\t\tt.TurnOn();\n\t\t\t\t\tt.TimingOffset = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/ChallengeRoomController.cs",
    "content": "using System;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class ChallengeRoomController : RoomController, Subscriber {\n\t\tprivate bool spawned;\n\t\tprivate byte wave;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tvar e = Room.Area.EventListener;\n\t\t\t\n\t\t\te.Subscribe<Chest.OpenedEvent>(this);\n\t\t\te.Subscribe<ItemTakenEvent>(this);\n\t\t\te.Subscribe<DiedEvent>(this);\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteBoolean(spawned);\n\t\t\tstream.WriteByte(wave);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tspawned = stream.ReadBoolean();\n\t\t\twave = stream.ReadByte();\n\t\t}\n\t\t\n\t\tprivate static Func<int, int, bool> CheckDistance(Entity entity) {\n\t\t\treturn (x, y) => entity == null || entity.DistanceTo(new Vector2(x * 16, y * 16)) > 32;\n\t\t}\n\n\t\tprivate void Spawn(Entity entity) {\n\t\t\tspawned = true;\n\t\t\tSpawnWave(entity);\n\t\t}\n\n\t\tprivate void SpawnWave(Entity entity) {\n\t\t\tvar filter = CheckDistance(entity);\n\t\t\tMobRegistry.SetupForBiome(Run.Level.Biome.Id);\n\n\t\t\tvar c = Rnd.Int(5, 11);\n\t\t\t\n\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar mob = MobRegistry.Generate();\n\t\t\t\t\tentity.Area.Add(mob);\n\t\t\t\t\tvar v = MobRegistry.FindFor(mob.GetType());\n\n\t\t\t\t\tif (v?.NearWall ?? false) {\n\t\t\t\t\t\tmob.Center = Room.GetRandomFreeTileNearWall(filter) * 16;\n\t\t\t\t\t} else if (v?.AwayFromWall ?? false) {\n\t\t\t\t\t\tmob.Center = Room.GetRandomWallFreeTile(filter) * 16;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmob.Center = Room.GetRandomFreeTile(filter) * 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (mob.TryGetComponent<ZAnimationComponent>(out var z)) {\n\t\t\t\t\t\tz.Animate();\n\t\t\t\t\t} else if (mob.TryGetComponent<MobAnimationComponent>(out var m)) {\n\t\t\t\t\t\tm.Animate();\n\t\t\t\t\t}\n\n\t\t\t\t\tvar where = mob.Center;\n\t\t\t\t\t\n\t\t\t\t\tfor (var j = 0; j < 8; j++) {\n\t\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\t\tpart.Position = where + Rnd.Vector(-8, 8);\n\t\t\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 1.3f);\n\t\t\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 40);\n\t\t\t\t\t\tRun.Level.Area.Add(part);\n\t\t\t\t\t\tpart.Depth = 1;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tAudio.PlaySfx(\"scroll\");\n\t\t\t\t}, (i) * 0.2f);\n\t\t\t}\n\n\t\t\twave++;\n\t\t}\n\n\t\tpublic bool HandleEvent(Event e) {\n\t\t\tif (wave == 4) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\n\t\t\tif (e is DiedEvent de && de.Who.GetComponent<RoomComponent>().Room == Room) {\n\t\t\t\tforeach (var m in Room.Tagged[Tags.MustBeKilled]) {\n\t\t\t\t\tvar mob = (Mob) m;\n\n\t\t\t\t\tif (!mob.GetComponent<HealthComponent>().HasNoHealth) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSpawnWave(de.From);\n\t\t\t\tde.BlockClear = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (spawned) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (e is ItemTakenEvent ite) {\n\t\t\t\tif (ite.Stand.GetComponent<RoomComponent>().Room == Room) {\n\t\t\t\t\tSpawn(ite.Who);\n\t\t\t\t}\n\t\t\t} else if (e is Chest.OpenedEvent coe) {\n\t\t\t\tif (coe.Chest.GetComponent<RoomComponent>().Room == Room) {\n\t\t\t\t\tSpawn(coe.Who);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/FollowingSpikeBallController.cs",
    "content": "using System;\nusing BurningKnight.entity.room.controllable.spikes;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class FollowingSpikeBallController : RoomController {\n\t\tprivate Vector2 ball;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tball = Room.Center;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tvar target = Room.Center;\n\n\t\t\tif (Room.Tagged[Tags.Player].Count > 0) {\n\t\t\t\ttarget = Room.Tagged[Tags.Player][0].Center;\n\t\t\t}\n\n\t\t\tvar dx = target.X - ball.X;\n\t\t\tvar dy = target.Y - ball.Y;\n\t\t\tvar d = MathUtils.Distance(dx, dy);\n\n\t\t\tif (d > 1f) {\n\t\t\t\tvar s = dt * 32;\n\t\t\t\t\n\t\t\t\tball.X += dx / d * s;\n\t\t\t\tball.Y += dy / d * s;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in Room.Controllable) {\n\t\t\t\tif (c is Spikes) {\n\t\t\t\t\tc.SetState(MathUtils.Distance(ball.X - c.CenterX, ball.Y - c.CenterY) < 28);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/PistonActivatorController.cs",
    "content": "using System;\r\nusing BurningKnight.entity.room.input;\r\nusing Lens.util;\r\n\r\nnamespace BurningKnight.entity.room.controller {\r\n\tpublic class PistonActivatorController : RoomController {\r\n\t\tprivate int value;\r\n\t\t\r\n\t\tpublic override void HandleInputChange(RoomInput.ChangedEvent e) {\r\n\t\t\tbase.HandleInputChange(e);\r\n\r\n\t\t\tvar old = value;\r\n\t\t\tvalue += e.Input.On ? 1 : -1;\r\n\t\t\tvalue = Math.Max(0, value);\r\n\r\n\t\t\tif (old > 0 && value == 0) {\r\n\t\t\t\tforeach (var p in Room.Pistons) {\r\n\t\t\t\t\tp.Set(false);\r\n\t\t\t\t}\r\n\t\t\t} else if (old == 0 && value > 0) {\r\n\t\t\t\tforeach (var p in Room.Pistons) {\r\n\t\t\t\t\tp.Set(true);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/RoomController.cs",
    "content": "using BurningKnight.entity.room.input;\nusing Lens.entity;\nusing Lens.util.file;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class RoomController {\n\t\tpublic Room Room;\n\t\tpublic float T;\n\t\tpublic string Id;\n\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\tT += dt;\n\t\t}\n\n\t\tpublic virtual void HandleInputChange(RoomInput.ChangedEvent e) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Save(FileWriter stream) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Load(FileReader stream) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Generate() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/RoomControllerRegistery.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.room.controllable;\nusing Lens.util;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic static class RoomControllerRegistery {\n\t\tprivate static Dictionary<string, Func<RoomController>> defined = new Dictionary<string, Func<RoomController>>();\n\n\t\tstatic RoomControllerRegistery() {\n\t\t\tAdd<TimedPistonSwitchController>(\"timed_piston_switch\");\n\t\t\tAdd<SpikeFieldController>(\"spike_field\");\n\t\t\tAdd<FollowingSpikeBallController>(\"following_spike_ball\");\n\t\t\tAdd<PistonActivatorController>(\"piston_activator\");\n\t\t\tAdd<TrapRoomController>(\"trap\");\n\t\t\tAdd<ChallengeRoomController>(\"challenge\");\n\t\t\tAdd<BossRoomController>(\"boss_room\");\n\t\t}\n\t\t\n\t\tpublic static void Add(string id, Func<RoomController> maker, Mod mod = null) {\n\t\t\tdefined[$\"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}\"] = maker;\n\t\t}\n\n\t\tpublic static void Add<T>(string id, Mod mod = null) where T : RoomController {\n\t\t\tAdd(id, () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn Activator.CreateInstance<T>();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}, mod);\n\t\t}\n\n\t\tpublic static RoomController Get(string id) {\n\t\t\tif (defined.TryGetValue(id, out var c)) {\n\t\t\t\tvar d = c();\n\t\t\t\td.Id = id;\n\t\t\t\treturn d;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic static bool Has(string id) {\n\t\t\treturn defined.ContainsKey(id);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/SpikeFieldController.cs",
    "content": "using BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.entity.room.input;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class SpikeFieldController : RoomController {\n\t\tprivate byte variant;\n\t\tprivate bool on = true;\n\t\t\n\t\tpublic override void Generate() {\n\t\t\tbase.Generate();\n\t\t\tvariant = (byte) Rnd.Int(8);\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte(variant);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tvariant = stream.ReadByte();\n\t\t}\n\n\t\tpublic override void HandleInputChange(RoomInput.ChangedEvent e) {\n\t\t\tbase.HandleInputChange(e);\n\t\t\ton = !on;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tforeach (var c in Room.Controllable) {\n\t\t\t\tif (c is Spikes) {\n\t\t\t\t\tif (on) {\n\n\t\t\t\t\t\tfloat x = (int) (c.X / 16);\n\t\t\t\t\t\tfloat y = (int) (c.Y / 16);\n\n\t\t\t\t\t\tvar f = 0f;\n\n\t\t\t\t\t\tif (variant < 2) {\n\t\t\t\t\t\t\tf = (x + y) / 2;\n\t\t\t\t\t\t} else if (variant < 4) {\n\t\t\t\t\t\t\tf = (x - y) / 2;\n\t\t\t\t\t\t} else if (variant < 6) {\n\t\t\t\t\t\t\tf = x / 2;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tf = y / 2;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tc.SetState(((int) (f + T * 0.5f * (variant % 2 == 0 ? 1 : -1)) % 2) == 0);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.SetState(false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/TimedPistonSwitchController.cs",
    "content": "namespace BurningKnight.entity.room.controller {\n\tpublic class TimedPistonSwitchController : RoomController {\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (T >= 2f) {\n\t\t\t\tT = 0;\n\t\t\t\t\n\t\t\t\tforeach (var p in Room.Pistons) {\n\t\t\t\t\tp.Toggle();\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/controller/TrapRoomController.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room.input;\n\nnamespace BurningKnight.entity.room.controller {\n\tpublic class TrapRoomController : RoomController {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tCheckState();\n\t\t}\n\n\t\tpublic override void HandleInputChange(RoomInput.ChangedEvent e) {\n\t\t\tbase.HandleInputChange(e);\n\t\t\tCheckState();\n\t\t}\n\n\t\tprivate void CheckState() {\n\t\t\tvar on = Room.Inputs.Count == 0;\n\n\t\t\tforeach (var c in Room.Inputs) {\n\t\t\t\tif (c.On == c.DefaultState) {\n\t\t\t\t\ton = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in Room.Controllable) {\n\t\t\t\tif (on) {\n\t\t\t\t\tc.TurnOn();\n\t\t\t\t} else {\n\t\t\t\t\tc.TurnOff();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!on) {\n\t\t\t\tRoom.CheckCleared(LocalPlayer.Locate(Room.Area));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/input/Button.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.input {\n\tpublic class Button : RoomInput {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAddComponent(new AnimationComponent(\"button\"));\n\t\t\tAddComponent(new RectBodyComponent(2, 2, 10, 9, BodyType.Static, true));\n\t\t\tAddComponent(new StateComponent());\n\n\t\t\tApplyState();\n\n\t\t\tDepth = Layers.Entrance;\n\t\t\t// DefaultState = true;\n\t\t}\n\n\t\tprivate void ApplyState() {\n\t\t\tvar s = GetComponent<StateComponent>();\n\t\t\t\n\t\t\tif (On) {\n\t\t\t\ts.Become<OnState>();\n\t\t\t} else {\n\t\t\t\ts.Become<OffState>();\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (On) {\n\t\t\t\treturn base.HandleEvent(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (e is CollisionStartedEvent cse && cse.Entity is Player) {\n\t\t\t\tTurnOn();\n\t\t\t\tAudio.PlaySfx(\"level_lever\");\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprotected override void UpdateState() {\n\t\t\tbase.UpdateState();\t\t\t\n\t\t\t\n\t\t\tApplyState();\n\t\t\tCamera.Instance.ShakeMax(6);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tOn = stream.ReadBoolean();\n\t\t\tApplyState();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(On);\n\t\t}\n\n\t\t#region Button States\n\t\tprivate class OnState : SmartState<Button> {\n\t\t\t\n\t\t}\n\t\t\n\t\tprivate class OffState : SmartState<Button> {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/input/Lever.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.tween;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.input {\n\tpublic class Lever : RoomInput {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tHeight = 12;\n\n\t\t\tAddComponent(new AnimationComponent(\"lever\"));\n\t\t\tAddComponent(new RectBodyComponent(0, 0, 16, 12, BodyType.Static, true));\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\tAddComponent(new StateComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tApplyState();\n\t\t}\n\n\t\tprivate void ApplyState() {\n\t\t\tvar s = GetComponent<StateComponent>();\n\t\t\t\n\t\t\tif (On) {\n\t\t\t\ts.Become<OnState>();\n\t\t\t} else {\n\t\t\t\ts.Become<OffState>();\n\t\t\t}\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tToggle();\n\t\t\tAudio.PlaySfx(\"level_lever\");\n\t\t\t\n\t\t\treturn false;\n\t\t} \n\n\t\tprotected override void UpdateState() {\n\t\t\tbase.UpdateState();\t\t\t\n\t\t\t\n\t\t\tApplyState();\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\n\t\t\ta.Scale.X = 2f;\n\t\t\ta.Scale.Y = 0f;\n\t\t\t\n\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f);\n\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f);\n\t\t\t\n\t\t\tCamera.Instance.ShakeMax(6);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tOn = stream.ReadBoolean();\n\t\t\tApplyState();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(On);\n\t\t}\n\n\t\t#region Lever States\n\t\tprivate class OnState : SmartState<Lever> {\n\t\t\t\n\t\t}\n\t\t\n\t\tprivate class OffState : SmartState<Lever> {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/input/PreasurePlate.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.room.input {\n\tpublic class PreasurePlate : RoomInput {\n\t\tprivate List<Entity> colliding = new List<Entity>();\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tDepth = Layers.Entrance;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"preasure_plate\"));\n\t\t\tAddComponent(new RectBodyComponent(1, 1, 14, 14, BodyType.Static, true));\n\t\t\tAddComponent(new StateComponent());\n\t\t\t\n\t\t\tUpdateState();\n\t\t}\n\n\t\tprotected override void UpdateState() {\n\t\t\tbase.UpdateState();\n\t\t\t\n\t\t\tvar s = GetComponent<StateComponent>();\n\t\t\t\n\t\t\tif (On) {\n\t\t\t\ts.Become<OnState>();\n\t\t\t} else {\n\t\t\t\ts.Become<OffState>();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void TurnOff() {\n\t\t\t\n\t\t}\n\n\t\tpublic override void TurnOn() {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tcolliding.Add(cse.Entity);\n\n\t\t\t\tif ((!(cse.Entity is Creature c) || !c.InAir()) && !On) {\n\t\t\t\t\tOn = true;\n\t\t\t\t\tUpdateState();\n\t\t\t\t\tSendEvents();\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tcolliding.Remove(cee.Entity);\n\t\t\t\tvar cn = colliding.Count;\n\n\t\t\t\tforeach (var en in colliding) {\n\t\t\t\t\tif (en is Creature c && c.InAir()) {\n\t\t\t\t\t\tcn--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (On && cn == 0) {\n\t\t\t\t\tOn = false;\n\t\t\t\t\tUpdateState();\n\t\t\t\t\tSendEvents();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\t#region Plate States\n\t\tprivate class OnState : SmartState<PreasurePlate> {\n\t\t\t\n\t\t}\n\t\t\n\t\tprivate class OffState : SmartState<PreasurePlate> {\n\t\t\t\n\t\t}\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/room/input/RoomInput.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.save;\r\nusing BurningKnight.ui.editor;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.entity.room.input {\r\n\tpublic class RoomInput : SaveableEntity, PlaceableEntity {\r\n\t\tpublic bool DefaultState { get; protected set; }\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tOn = DefaultState;\r\n\t\t\t\r\n\t\t\tAddComponent(new RoomComponent());\r\n\t\t\tAddComponent(new SupportableComponent());\r\n\t\t}\r\n\r\n\t\tpublic bool On { get; protected set; }\r\n\t\t\r\n\t\tpublic virtual void TurnOn() {\r\n\t\t\tif (On) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tOn = true;\r\n\t\t\tUpdateState();\r\n\t\t\tSendEvents();\r\n\t\t}\r\n\t\t\r\n\t\tpublic virtual void TurnOff() {\r\n\t\t\tif (!On) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tOn = false;\r\n\t\t\tUpdateState();\r\n\t\t\tSendEvents();\r\n\t\t}\r\n\r\n\t\tprotected virtual void UpdateState() {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tprotected void SendEvents() {\r\n\t\t\tvar e = new ChangedEvent {\r\n\t\t\t\tInput = this\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tHandleEvent(e);\r\n\t\t\tGetComponent<RoomComponent>().Room?.HandleInputChange(e);\r\n\t\t}\r\n\r\n\t\tpublic void Toggle() {\r\n\t\t\tif (On) {\r\n\t\t\t\tTurnOff();\r\n\t\t\t} else {\r\n\t\t\t\tTurnOn();\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic class ChangedEvent : Event {\r\n\t\t\tpublic RoomInput Input;\r\n\t\t}\r\n\r\n\t\tprivate bool added;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!added) {\r\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\tif (room == null) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tadded = true;\r\n\t\t\t\troom.Inputs.Add(this);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected void RemoveFromRoom() {\r\n\t\t\tGetComponent<RoomComponent>().Room?.Inputs.Remove(this);\r\n\t\t}\r\n\r\n\t\t/*public override void Render() {\r\n\t\t\tbase.Render();\r\n\t\t\tGraphics.Print(On ? \"on\" : \"off\", Font.Small, Position);\r\n\t\t}*/\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/LoginSign.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.level.entities;\nusing BurningKnight.save;\nusing Lens.assets;\n\nnamespace BurningKnight.entity.twitch {\n\tpublic class LoginSign : Sign {\n\t\tpublic LoginSign() {\n\t\t\tRegion = \"sign_twitch\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tGetComponent<CloseDialogComponent>().DecideVariant = (e) => {\n\t\t\t\tvar id = TwitchBridge.TwitchUsername;\n\n\t\t\t\tif (id == null) {\n\t\t\t\t\treturn Locale.Get(\"not_logged_in\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn $\"{Locale.Get(\"logged_in_as\")}\\n[cl purple]@{id}[cl]\";\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/TwitchBridge.cs",
    "content": "using System;\nusing BurningKnight.save;\n\nnamespace BurningKnight.entity.twitch {\n\tpublic static class TwitchBridge {\n\t\tpublic static bool On = false;\n\t\tpublic static Action<string, Action<bool>> TurnOn;\n\t\tpublic static Action<Action> TurnOff;\n\t\tpublic static string LastUsername;\n\t\t\n\t\tpublic static Action OnHubEnter;\n\t\tpublic static Action OnNewRun;\n\n\t\tpublic static string TwitchUsername => GlobalSave.GetString(\"twitch_username\", \"\").Replace(\"_\", \"\\\\_\");\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/TwitchExit.cs",
    "content": "using System.Threading;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level.entities;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.entity.twitch {\n\tpublic class TwitchExit : Exit {\n\t\tprivate LoginSign sign;\n\t\t\n\t\tprotected override string GetSlice() {\n\t\t\treturn \"twitch_exit\";\n\t\t}\n\n\t\tprivate void TurnOn(Entity entity) {\n\t\t\tif (!TwitchBridge.On) {\n\t\t\t\tentity.RemoveComponent<PlayerInputComponent>();\n\t\t\t\tvar id = TwitchBridge.TwitchUsername;\n\t\t\t\t\n\t\t\t\tsign.GetComponent<DialogComponent>().Start(\"logging_in\");\n\t\t\t\t\n\t\t\t\tnew Thread(() => {\n\t\t\t\t\tTwitchBridge.TurnOn(GlobalSave.GetString(\"twitch_username\"), (ok) => {\n\t\t\t\t\t\tif (ok) {\n\t\t\t\t\t\t\tbase.Interact(entity);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsign.GetComponent<DialogComponent>().StartAndClose($\"{Locale.Get(\"failed_to_login\")}\\n[cl purple]{id}[cl]\", 3);\n\t\t\t\t\t\t\tentity.AddComponent(new PlayerInputComponent());\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}).Start();\n\t\t\t} else {\n\t\t\t\tbase.Interact(entity);\n\t\t\t}\n\t\t}\n\n\t\tprotected override bool Interact(Entity entity) {\n\t\t\tif (TwitchBridge.On && TwitchBridge.LastUsername != GlobalSave.GetString(\"twitch_username\")) {\n\t\t\t\tTwitchBridge.TurnOff(() => {\n\t\t\t\t\tTurnOn(entity);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tTurnOn(entity);\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (sign != null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsign = (LoginSign) Area.FindClosest(Center, Tags.LevelSave, e => e is LoginSign);\n\t\t}\n\n\t\tprotected override void Descend() {\n\t\t\tRun.StartNew(1, RunType.Twitch);\n\t\t}\n\n\t\tprotected override string GetFxText() {\n\t\t\treturn Locale.Get(\"twitch_mode\");\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn !InGameState.Multiplayer && GlobalSave.GetString(\"twitch_username\") != null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/TwitchNpc.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Lens.util;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.entity.twitch {\n\tpublic class TwitchNpc : Npc {\n\t\tstatic TwitchNpc() {\n\t\t\tDialogs.RegisterCallback(\"twitch_0\", (d, c) => {\n\t\t\t\ttry {\n\t\t\t\t\tvar id = GlobalSave.GetString(\"twitch_username\");\n\n\t\t\t\t\tif (id != null) {\n\t\t\t\t\t\tc.Dialog.Str.SetVariable(\"username\", id);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Dialogs.Get($\"twitch_{(id == null ? 1 : 5)}\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\t\n\t\t\tDialogs.RegisterCallback(\"twitch_2\", (d, c) => {\n\t\t\t\tvar a = ((AnswerDialog) d).Answer;\n\n\t\t\t\tLog.Info($\"Twitch username is set the seed to {a}\");\n\t\t\t\tGlobalSave.Put(\"twitch_username\", a);\n\t\t\t\tc.Dialog.Str.SetVariable(\"username\", a);\n\n\t\t\t\treturn null;\n\t\t\t});\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 10;\n\t\t\tHeight = 11;\n\t\t\t\n\t\t\tAddComponent(new AnimationComponent(\"twitch\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 2;\n\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tGetComponent<DialogComponent>().Start(\"twitch_0\", e);\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/TwitchPet.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.pet;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.twitch {\n\tpublic class TwitchPet : AnimatedFollowerPet {\n\t\tpublic string Color = \"#ffffff\";\n\t\tpublic string Nick = \"egordorichev\";\n\n\t\tprivate float nickW;\n\t\tprivate float nickTimeLeft = 5;\n\t\tprivate bool nickOn = true;\n\t\tprivate float a = 1;\n\t\t\n\t\tpublic TwitchPet() : base(\"twitch_pet\") {\n\t\t\t\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tUpdateColor();\n\t\t\tnickW = Nick.Length * 4;\n\n\t\t\ttry {\n\t\t\t\tnickW = Font.Small.MeasureString(Nick).Width;\n\t\t\t} catch (Exception e) {\n\t\t\t\t\n\t\t\t}\n\n\t\t\tAddTag(Tags.PlayerSave);\n\t\t\tSubscribe<ItemUsedEvent>(); \n\t\t}\n\n\t\tpublic void UpdateColor() {\n\t\t\tGetComponent<AnimationComponent>().Tint = ColorUtils.FromHex(Color);\n\t\t}\n\t\t\n\t\tprivate void RenderNick() {\n\t\t\tif (a <= 0.01f) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color.A = (byte) (a * 255);\n\t\t\tGraphics.Print(Nick, Font.Small, Camera.Instance.CameraToUi(new Vector2(CenterX, Y - 10)) - new Vector2(nickW * 0.5f, 0));\n\t\t\tGraphics.Color.A = 255;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tColor = stream.ReadString();\n\t\t\tNick = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteString(Color);\n\t\t\tstream.WriteString(Nick);\n\t\t}\n\n\t\tprivate float cooldown;\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemUsedEvent iue && iue.Item.Type == ItemType.Weapon && cooldown <= 0.01f) {\n\t\t\t\tcooldown = 2f;\n\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"item_meatguy\", 4, 0.5f);\n\t\t\t\t\t\t\n\t\t\t\tvar a = AngleTo(Owner.GetComponent<AimComponent>().RealAim);\n\t\t\t\tvar an = GetComponent<AnimationComponent>();\n\n\t\t\t\tvar projectile = new ProjectileBuilder(Owner, \"small\") {\n\t\t\t\t\tScale = 0.8f,\n\t\t\t\t\tLightRadius = 32f,\n\t\t\t\t\tColor = an.Tint\n\t\t\t\t}.Shoot(a, 8f).Build();\n\n\t\t\t\tprojectile.Center = Center + MathUtils.CreateVector(a, 5f);\n\n\t\t\t\tan.Animate();\n\t\t\t\t\n\t\t\t\tOwner.HandleEvent(new ProjectileCreatedEvent {\n\t\t\t\t\tProjectile = projectile,\n\t\t\t\t\tOwner = Owner\n\t\t\t\t});\n\n\t\t\t\tprojectile.Owner = this;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprivate bool added;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tnickTimeLeft -= dt;\n\n\t\t\tif (nickTimeLeft <= 0) {\n\t\t\t\tnickOn = !nickOn;\n\n\t\t\t\tif (nickOn) {\n\t\t\t\t\tnickTimeLeft = Rnd.Float(3, 6);\n\t\t\t\t} else {\n\t\t\t\t\tnickTimeLeft = Rnd.Float(32, 128);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ta += ((nickOn ? 1 : 0) - a) * dt * 4;\n\t\t\t\n\t\t\tif (!added) {\n\t\t\t\tadded = true;\n\t\t\t\t((InGameState) Engine.Instance.State).Ui.Add(new RenderTrigger(this, RenderNick, 0));\n\t\t\t}\n\n\t\t\tif (Owner == null && Area.Tagged[Tags.Player].Count > 0) {\n\t\t\t\tOwner = Area.Tagged[Tags.Player][0];\n\t\t\t\tFollow();\n\t\t\t}\n\n\t\t\tif (cooldown > 0) {\n\t\t\t\tcooldown -= dt;\n\t\t\t}\n\t\t}\n\n\t\tprotected override void Follow() {\n\t\t\tbase.Follow();\n\n\t\t\tif (Owner != null) {\n\t\t\t\tvar f = GetComponent<FollowerComponent>();\n\n\t\t\t\tif (f.Follower == Owner) {\n\t\t\t\t\tf.MaxDistance = 48;\n\t\t\t\t\tf.FollowSpeed = 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/BkRageHappening.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class BkRageHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tvar a = player.Area.Tagged[Tags.BurningKnight];\n\n\t\t\tif (a.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar bk = (creature.bk.BurningKnight) a[0];\n\t\t\tbk.ForcedRage = true;\n\t\t\tbk.CheckForScourgeRage();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/BombHappening.cs",
    "content": "using BurningKnight.entity.bomb;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class BombHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tvar rm = player.GetComponent<RoomComponent>().Room;\n\t\t\t\n\t\t\tfor (var i = 0; i < 12; i++) {\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tvar bomb = new Bomb(player, 3f);\n\t\t\t\t\tplayer.Area.Add(bomb);\n\t\t\t\t\tbomb.Center = rm.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\t}, i * 0.1f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/BombingHappening.cs",
    "content": "using BurningKnight.entity.bomb;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class BombingHappening : Happening {\n\t\tprivate Player on;\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\ton = player;\n\t\t}\n\n\t\tprivate float delay;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (on == null || on.Done) {\n\t\t\t\ton = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tdelay -= dt;\n\n\t\t\tif (delay <= 0) {\n\t\t\t\tdelay = 1.5f;\n\t\t\t\tvar bomb = new Bomb(on, 2);\n\t\t\t\ton.Area.Add(bomb);\n\t\t\t\tbomb.Center = on.Center;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/BuffHappening.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing Lens.util;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class BuffHappening : Happening {\n\t\tprivate string buff;\n\t\tprivate float duration;\n\n\t\tpublic BuffHappening(string b, float d = 10f) {\n\t\t\tbuff = b;\n\t\t\tduration = d;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tif (!player.TryGetComponent<BuffsComponent>(out var bfz)) {\n\t\t\t\tLog.Error(\"Fail\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar bf = bfz.Add(buff);\n\n\t\t\tif (bf != null) {\n\t\t\t\tbf.TimeLeft = duration;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/ChestHappening.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level.entities.chest;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class ChestHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\ttry {\n\t\t\t\tChestRegistry.PlaceRandom(player.TopCenter + new Vector2(0, -2), player.Area);\n\t\t\t} catch (Exception ex) {\n\t\t\t\tLog.Error(ex);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/DarknessHappening.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class DarknessHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tRun.Level.Dark = true;\n\t\t\tLights.ClearColor = new Color(0f, 0f, 0f, 1f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/FloorResetHappening.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.save;\nusing BurningKnight.state;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class FloorResetHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tSaveManager.Delete(SaveType.Level);\n\t\t\tInGameState.IgnoreSave = true;\n\n\t\t\tRun.Redo = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/GiveShieldHappening.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class GiveShieldHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:shield\", player.Area));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/Happening.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic abstract class Happening {\n\t\tpublic abstract void Happen(Player player);\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic virtual void End(Player player) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual float GetVoteDelay() {\n\t\t\treturn 30;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/HappeningRegistry.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.mod;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.item;\nusing BurningKnight.level.rooms;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic static class HappeningRegistry {\n\t\tpublic static Dictionary<string, Happening> Defined = new Dictionary<string, Happening>();\n\t\t\n\t\tstatic HappeningRegistry() {\n\t\t\t// Bad\n\t\t\tAdd(\"omega_hurt\", new HurtHappening(3));\n\t\t\tAdd(\"confused\", new BuffHappening(ConfusedBuff.Id, 30));\n\t\t\tAdd(\"snail\", new BuffHappening(SlowBuff.Id, 30));\n\t\t\tAdd(\"broken\", new BuffHappening(BrokenArmorBuff.Id, 30));\n\t\t\tAdd(\"darkness\", new DarknessHappening());\n\t\t\tAdd(\"scourge_token\", new ItemGiveHappening(() => Scourge.GenerateItemId()));\n\t\t\tAdd(\"risk\", new ItemGiveHappening(() => \"bk:scourge_of_risk\"));\n\t\t\tAdd(\"double_trouble\", new ItemGiveHappening(() => \"bk:scourge_of_blood\"));\n\t\t\tAdd(\"rage\", new BkRageHappening());\n\t\t\tAdd(\"regular_tp\", new TeleportHappening(RoomType.Regular, RoomType.Trap));\n\t\t\tAdd(\"reset\", new FloorResetHappening());\n\t\t\tAdd(\"sudoku\", new BombHappening());\n\t\t\tAdd(\"items_hurt\", new MakeItemsDamageUse());\n\t\t\tAdd(\"scourged\", new ScourgeHappening(3));\n\t\t\tAdd(\"reroll_items\", new RerollHappening(false, true));\n\t\t\tAdd(\"reroll_weapon\", new RerollHappening(true, false));\n\t\t\tAdd(\"nerf\", new ModifyMaxHpHappening(-2));\n\t\t\tAdd(\"rob\", new ModifyCoinsHappening(-10));\n\t\t\tAdd(\"steal\", new StealWeaponHappening());\n\t\t\tAdd(\"bomb\", new BombingHappening());\n\t\t\tAdd(\"slide\", new SlideHappening());\n\n\t\t\t// Good\n\t\t\tAdd(\"give_random_consumable\", new RandomItemHappening(ItemPool.Consumable));\n\t\t\tAdd(\"invincible\", new BuffHappening(InvincibleBuff.Id, 30));\n\t\t\tAdd(\"heal\", new HealHappening(2));\n\t\t\tAdd(\"cleanse\", new ScourgeHappening(-3));\n\t\t\tAdd(\"chest\", new ChestHappening());\n\t\t\tAdd(\"gift\", new ModifyCoinsHappening(10));\n\t\t\t\n\t\t\t// Neutral\n\t\t\t// Add(\"entrance_tp\", new TeleportHappening(RoomType.Entrance));\n\t\t\t// Add(\"exit_tp\", new TeleportHappening(RoomType.Exit, RoomType.Boss));\n\t\t}\n\n\t\tpublic static void Add(string id, Happening happening, Mod mod = null) {\n\t\t\tDefined[$\"{mod?.Prefix ?? Mods.BurningKnight}:{id}\"] = happening;\n\t\t}\n\n\t\tpublic static Happening Get(string id) {\n\t\t\treturn Defined.TryGetValue(id, out var happening) ? happening : null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/HealHappening.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class HealHappening : Happening {\n\t\tprivate int amount;\n\n\t\tpublic HealHappening(int a) {\n\t\t\tamount = a;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<HealthComponent>().ModifyHealth(amount, player);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/HurtHappening.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class HurtHappening : Happening {\n\t\tprivate int damage;\n\n\t\tpublic HurtHappening(int dmg = 1) {\n\t\t\tdamage = dmg;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<HealthComponent>().ModifyHealth(-damage, null, DamageType.Custom);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/ItemGiveHappening.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class ItemGiveHappening : Happening {\n\t\tprivate Func<string> id;\n\n\t\tpublic ItemGiveHappening(Func<string> i) {\n\t\t\tid = i;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(id(), player.Area));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/MakeItemsDamageUse.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class MakeItemsDamageUse : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.ItemDamage = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/ModifyCoinsHappening.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class ModifyCoinsHappening : Happening {\n\t\tprivate int amount;\n\n\t\tpublic ModifyCoinsHappening(int a) {\n\t\t\tamount = a;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tvar c = player.GetComponent<ConsumablesComponent>();\n\t\t\tc.Coins += amount;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/ModifyMaxHpHappening.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class ModifyMaxHpHappening : Happening {\n\t\tprivate int amount;\n\n\t\tpublic ModifyMaxHpHappening(int a) {\n\t\t\tamount = a;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tvar h = player.GetComponent<HealthComponent>();\n\n\t\t\tif (amount < 0 && h.MaxHealth <= 1) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\th.MaxHealth += amount;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/RandomItemHappening.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class RandomItemHappening : Happening {\n\t\tprivate ItemPool pool;\n\n\t\tpublic RandomItemHappening(ItemPool pl) {\n\t\t\tpool = pl;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Items.Generate(pool), player.Area));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/RandomTypedItemHappening.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class RandomTypedItemHappening : Happening {\n\t\tprivate ItemType pool;\n\n\t\tpublic RandomTypedItemHappening(ItemType pl) {\n\t\t\tpool = pl;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Items.Generate(pool), player.Area));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/RerollHappening.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.use;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class RerollHappening : Happening {\n\t\tprivate bool rerollWeapons;\n\t\tprivate bool rerollArtifacts;\n\n\t\tpublic RerollHappening(bool w, bool a) {\n\t\t\trerollWeapons = w;\n\t\t\trerollArtifacts = a;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player entity) {\n\t\t\t\n\t\t\tif (rerollArtifacts) {\n\t\t\t\tReroll(entity, entity.GetComponent<InventoryComponent>());\n\t\t\t}\n\n\t\t\tif (rerollWeapons) {\n\t\t\t\tReroll(entity.GetComponent<ActiveWeaponComponent>());\n\t\t\t\tReroll(entity.GetComponent<WeaponComponent>());\n\t\t\t}\n\n\t\t\tentity.HandleEvent(new RerollItemsOnPlayerUse.RerolledEvent {\n\t\t\t\tEntity = entity\n\t\t\t});\n\t\t}\n\t\t\n\t\tprivate void Reroll(ItemComponent component) {\n\t\t\tif (component?.Item == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar item = component.Item;\n\t\t\tReroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type);\n\t\t}\n\n\t\tprivate void Reroll(Player entity, InventoryComponent component) {\n\t\t\tif (entity is Player player) {\n\t\t\t\tplayer.InitStats();\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var item in component.Items) {\n\t\t\t\tReroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type);\n\t\t\t\titem.Use(entity);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/ScourgeHappening.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class ScourgeHappening : Happening {\n\t\tprivate int amount;\n\n\t\tpublic ScourgeHappening(int a) {\n\t\t\tamount = a;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player entity) {\n\t\t\tif (amount < 0) {\n\t\t\t\tvar sc = Run.Scourge;\n\t\t\t\n\t\t\t\tfor (var i = 0; i < sc; i++) {\n\t\t\t\t\tRun.RemoveScourge();\n\t\t\t\t}\n\n\t\t\t\tvar inventory = entity.GetComponent<InventoryComponent>();\n\t\t\t\tvar toRemove = new List<Item>();\n\n\t\t\t\tforeach (var i in inventory.Items) {\n\t\t\t\t\tif (i.Scourged) {\n\t\t\t\t\t\ti.Scourged = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i.Type == ItemType.Scourge) {\n\t\t\t\t\t\ttoRemove.Add(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tCleanse(entity.GetComponent<WeaponComponent>());\n\t\t\t\tCleanse(entity.GetComponent<ActiveWeaponComponent>());\n\t\t\t\tCleanse(entity.GetComponent<ActiveItemComponent>());\n\n\t\t\t\t// fixme: doesnt do anything to ui inventory\n\t\t\t\tforeach (var i in toRemove) {\n\t\t\t\t\tinventory.Remove(i, true);\n\t\t\t\t}\n\n\t\t\t\tforeach (var s in Scourge.Defined) {\n\t\t\t\t\tScourge.Disable(s);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (var i = 0; i < amount; i++) {\n\t\t\t\t\tRun.AddScourge();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void Cleanse(ItemComponent component) {\n\t\t\tif (component.Item != null) {\n\t\t\t\tcomponent.Item.Scourged = false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/SlideHappening.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class SlideHappening : Happening {\n\t\tpublic override void Happen(Player player) {\n\t\t\tplayer.Sliding = true;\n\t\t}\n\n\t\tpublic override void End(Player player) {\n\t\t\tplayer.Sliding = false;\n\t\t}\n\n\t\tpublic override float GetVoteDelay() {\n\t\t\treturn 60;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/StealWeaponHappening.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class StealWeaponHappening : Happening {\n\t\tpublic override void Happen(Player e) {\n\t\t\tvar c = e.GetComponent<ActiveWeaponComponent>();\n\t\t\tvar item = c.Item;\n\t\t\tTextParticle.Add(e, item.Name, 1, true, true);\n\n\t\t\tc.Drop();\n\t\t\titem.Done = true;\n\n\t\t\tif (e.GetComponent<WeaponComponent>().Item == null) {\n\t\t\t\tc.Set(Items.CreateAndAdd(LevelSave.MeleeOnly || item.Data.WeaponType == WeaponType.Melee ? \"bk:ancient_sword\" : \"bk:ancient_revolver\", e.Area));\n\t\t\t} else {\n\t\t\t\tc.RequestSwap();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/entity/twitch/happening/TeleportHappening.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util;\nusing Lens.util.camera;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.entity.twitch.happening {\n\tpublic class TeleportHappening : Happening {\n\t\tprivate RoomType[] types;\n\n\t\tpublic TeleportHappening(params RoomType[] t) {\n\t\t\ttypes = t;\n\t\t}\n\t\t\n\t\tpublic override void Happen(Player player) {\n\t\t\tvar list = new List<Room>();\n\n\t\t\tforeach (var rm in player.Area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) rm;\n\n\t\t\t\tforeach (var t in types) {\n\t\t\t\t\tif (room.Type == t) {\n\t\t\t\t\t\tlist.Add(room);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (list.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar r = list[Rnd.Int(list.Count)];\n\t\t\t\n\t\t\tAnimationUtil.TeleportAway(player, () => {\n\t\t\t\tplayer.Center = r.GetRandomFreeTile() * 16 + new Vector2(8);\n\t\t\t\tCamera.Instance.Jump();\n\n\t\t\t\tAnimationUtil.TeleportIn(player);\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/export_achievements.sh",
    "content": "cp Content/Animations/achievements.ase .\n\nrm -rf achievement_sprites\nmkdir achievement_sprites\naseprite -b achievements.ase --scale 4 --save-as achievement_sprites/{slice}.png\n\ncd achievement_sprites\nmkdir gray\n\nfor file in ./*\ndo\n  convert \"$file\" -colorspace Gray \"gray/$file\"\ndone\n\ncd ..\nls -l achievement_sprites\nrm achievements.ase\n"
  },
  {
    "path": "BurningKnight/level/Chasm.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.physics;\nusing Lens.entity;\n\nnamespace BurningKnight.level {\n\tpublic class Chasm : Entity, CollisionFilterEntity {\n\t\tpublic Level Level;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new ChasmBodyComponent());\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn !entity.TryGetComponent<SupportableComponent>(out var t) || t.Supports.Count == 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/ChasmBodyComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.level {\n\tpublic class ChasmBodyComponent : BodyComponent {\n\t\tprivate bool dirty;\n\t\tprivate Body[] chunks;\n\t\tprivate int cw;\n\t\tprivate int ch;\n\t\tprivate int cs;\n\n\t\tprivate List<int> toUpdate = new List<int>();\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.AlwaysActive = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (dirty) {\n\t\t\t\tdirty = false;\n\t\t\t\tCreate();\n\t\t\t\ttoUpdate.Clear();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (toUpdate.Count > 0) {\n\t\t\t\tvar updated = new List<int>();\n\t\t\t\tvar level = Run.Level;\n\n\t\t\t\tforeach (var u in toUpdate) {\n\t\t\t\t\tvar cx = (int) Math.Floor(level.FromIndexX(u) / (float) LevelBodyComponent.ChunkSize);\n\t\t\t\t\tvar cy = (int) Math.Floor(level.FromIndexY(u) / (float) LevelBodyComponent.ChunkSize);\n\t\t\t\t\tvar ci = cx + cy * cw;\n\n\t\t\t\t\tif (updated.Contains(ci)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tupdated.Add(ci);\n\t\t\t\t\tPhysics.RemoveBody(chunks[ci]);\n\t\t\t\t\tRecreateChunk(cx, cy);\n\t\t\t\t}\n\n\t\t\t\ttoUpdate.Clear();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tif (chunks != null) {\n\t\t\t\tforeach (var c in chunks) {\n\t\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t\t}\n\n\t\t\t\tchunks = null;\n\t\t\t}\n\n\t\t\tdirty = false;\n\t\t\ttoUpdate.Clear();\n\t\t}\n\n\t\tpublic void CreateBody() {\n\t\t\tif (chunks == null) {\n\t\t\t\tCreate();\n\t\t\t} else {\n\t\t\t\tdirty = true;\n\t\t\t}\n\t\t}\n\n\t\tprivate void Create() {\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tcw = (int) Math.Floor(level.Width / (float) LevelBodyComponent.ChunkSize + 0.5f);\n\t\t\tch = (int) Math.Floor(level.Height / (float) LevelBodyComponent.ChunkSize + 0.5f);\n\t\t\tcs = cw * ch;\n\t\t\t\n\t\t\tif (chunks != null) {\n\t\t\t\tforeach (var c in chunks) {\n\t\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tchunks = new Body[cs];\n\t\t\t}\n\n\t\t\tfor (int cy = 0; cy < ch; cy++) {\n\t\t\t\tfor (int cx = 0; cx < cw; cx++) {\n\t\t\t\t\tRecreateChunk(cx, cy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void ReCreateBodyChunk(int x, int y) {\n\t\t\tvar cx = (int) Math.Floor(x / (float) LevelBodyComponent.ChunkSize);\n\t\t\tvar cy = (int) Math.Floor(y / (float) LevelBodyComponent.ChunkSize);\n\t\t\tvar ci = cx + cy * cw;\n\n\t\t\tif (ci < 0 || ci / LevelBodyComponent.ChunkSize >= chunks.Length) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\ttoUpdate.Add(x + y * Run.Level.Width);\n\t\t}\n\t\t\n\t\tprivate void RecreateChunk(int cx, int cy) {\n\t\t\tvar level = Run.Level;\n\t\t\t\n\t\t\tvar body = BodyFactory.CreateBody(Physics.World, Vector2.Zero);\n\t\t\tbody.FixedRotation = true;\n\t\t\tbody.UserData = this;\n\t\t\t\n\t\t\tvar i = cx + cy * cw;\n\t\t\tvar c = chunks[i];\n\n\t\t\tif (c != null) {\n\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t}\n\t\t\t\n\t\t\tchunks[i] = body;\n\n\t\t\tvar list = new List<Vector2>();\n\n\t\t\tfor (int y = cy * LevelBodyComponent.ChunkSize; y < (cy + 1) * LevelBodyComponent.ChunkSize; y++) {\n\t\t\t\tfor (int x = cx * LevelBodyComponent.ChunkSize; x < (cx + 1) * LevelBodyComponent.ChunkSize; x++) {\n\t\t\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tvar tile = level.Tiles[index];\n\n\t\t\t\t\tif (TileFlags.Matches(tile, TileFlags.Hole)) {\n\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours4) {\n\t\t\t\t\t\t\tvar n = dir + index;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!level.IsInside(n) || TileFlags.Matches(level.Tiles[n], TileFlags.Hole) || TileFlags.Matches(level.Tiles[n], TileFlags.Solid)) {\n\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sum >= 4) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar xx = x * 16;\n\t\t\t\t\t\tvar yy = y * 16;\n\t\t\t\t\t\t\n\t\t\t\t\t\tlist.Clear();\n\n\t\t\t\t\t\tif (Check(level, x - 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + (Check(level, x - 1, y) ? 0 : 4), yy));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 4, yy + 4));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 6 + 4, yy));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (Check(level, x + 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16 - (Check(level, x + 1, y) ? 0 : 4), yy));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16 - 4, yy));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 10 - 4, yy + 4));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (Check(level, x + 1, y) || Check(level, x, y + 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16 - (Check(level, x + 1, y) ? 0 : 4), yy + 17));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16 - 4, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 10 - 4, yy + 16));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (Check(level, x - 1, y) || Check(level, x, y + 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + (Check(level, x - 1, y) ? 0 : 4), yy + 17));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 4, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 6 + 4, yy + 16));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tFixtureFactory.AttachPolygon(new Vertices(list), 1f, body);\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool Check(Level level, int x, int y) {\n\t\t\treturn level.IsInside(x, y) && (level.CheckFor(x, y, TileFlags.Solid) || level.CheckFor(x, y, TileFlags.Hole));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/DoorPlaceholder.cs",
    "content": "using BurningKnight.util.geometry;\n\nnamespace BurningKnight.level {\n\tpublic class DoorPlaceholder {\n\t\tprivate Variant type = Variant.Empty;\n\t\t\n\t\tpublic Variant Type {\n\t\t\tget => type;\n\n\t\t\tset {\n\t\t\t\tif (value.CompareTo(type) > 0) {\n\t\t\t\t\ttype = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic int X;\n\t\tpublic int Y;\n\t\t\n\t\tpublic DoorPlaceholder(Dot P) {\n\t\t\tX = P.X;\n\t\t\tY = P.Y;\n\t\t}\n\n\t\tpublic enum Variant {\n\t\t\tEmpty,\n\t\t\tRegular,\n\t\t\tMaze,\n\t\t\tEnemy,\n\t\t\tLocked,\n\t\t\tTreasure,\n\t\t\tShop,\n\t\t\tRed,\n\t\t\tChallenge,\n\t\t\tSpiked,\n\t\t\tScourged,\n\t\t\tPortal,\n\t\t\tPayed,\n\t\t\tHead,\n\t\t\tBoss,\n\t\t\tSecret,\n\t\t\tHidden\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/Flag.cs",
    "content": "namespace BurningKnight.level {\n\tpublic static class Flag {\n\t\tpublic const int Burning = 0;\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/HalfProjectileBodyComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.util;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.level {\n\tpublic class HalfProjectileBodyComponent : LevelBodyComponent {\n\t\tprotected override void RecreateChunk(int cx, int cy) {\n\t\t\tvar level = Level;\n\t\t\t\n\t\t\tvar body = BodyFactory.CreateBody(Physics.World, Vector2.Zero);\n\t\t\tbody.FixedRotation = true;\n\t\t\tbody.UserData = this;\n\n\t\t\tvar i = cx + cy * cw;\n\t\t\tvar c = chunks[i];\n\n\t\t\tif (c != null) {\n\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t}\n\t\t\t\n\t\t\tchunks[i] = body;\n\n\t\t\tvar list = new List<Vector2>();\n\n\t\t\tfor (int y = cy * ChunkSize; y < (cy + 1) * ChunkSize; y++) {\n\t\t\t\tfor (int x = cx * ChunkSize; x < (cx + 1) * ChunkSize; x++) {\n\t\t\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tvar tile = level.Liquid[index];\n\t\t\t\t\tvar side = x == 0 || y == 0 || x == level.Width - 1 || y == level.Height - 1;\n\n\t\t\t\t\tif (side || TileFlags.Matches(tile, TileFlags.Solid)) {\n\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\tif (!side) {\n\t\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours8) {\n\t\t\t\t\t\t\t\tvar n = dir + index;\n\n\t\t\t\t\t\t\t\tif (level.IsInside(n) && (TileFlags.Matches(level.Tiles[n], TileFlags.Solid))) {\n\t\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sum == 8) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar xx = (x) * 16;\n\t\t\t\t\t\tvar yy = (y) * 16 - 8;\n\n\t\t\t\t\t\tlist.Clear();\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst int v = 3;\n\n\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y - 1) ? 0 : 7 + v)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y - 1) ? 0 : 7 + v)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y + 1) ? 16 : 8 + v)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y + 1) ? 16 : 8 + v)));\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tFixtureFactory.AttachPolygon(new Vertices(list), 1f, body);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tforeach (var p in list) {\n\t\t\t\t\t\t\t\tLog.Info($\"{p.X - xx}:{p.Y - yy}\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected override bool Check(Level level, int x, int y) {\n\t\t\treturn level.IsInside(x, y) && (level.CheckFor(x, y, TileFlags.HalfWall, true));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/HalfProjectileLevel.cs",
    "content": "using BurningKnight.entity.projectile;\nusing BurningKnight.physics;\nusing Lens.entity;\n\nnamespace BurningKnight.level {\n\tpublic class HalfProjectileLevel : Entity, CollisionFilterEntity {\n\t\tpublic Level Level;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddComponent(new HalfProjectileBodyComponent {\n\t\t\t\tLevel = Level\n\t\t\t});\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Projectile;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/HalfWall.cs",
    "content": "using Lens.entity;\n\nnamespace BurningKnight.level {\n\tpublic class HalfWall : Entity {\n\t\tpublic Level Level;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new HalfWallBodyComponent {\n\t\t\t\tLevel = Level\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/HalfWallBodyComponent.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.level {\n\tpublic class HalfWallBodyComponent : LevelBodyComponent {\n\t\tprotected override bool Check(Level level, int x, int y) {\n\t\t\treturn level.IsInside(x, y) && (level.CheckFor(x, y, TileFlags.HalfWall, true));\n\t\t}\n\t\t\n\t\tprotected override void RecreateChunk(int cx, int cy) {\n\t\t\tvar level = Level;\n\t\t\t\n\t\t\tvar body = BodyFactory.CreateBody(Physics.World, Vector2.Zero);\n\t\t\tbody.FixedRotation = true;\n\t\t\tbody.UserData = this;\n\n\t\t\tvar i = cx + cy * cw;\n\t\t\tvar c = chunks[i];\n\n\t\t\tif (c != null) {\n\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t}\n\t\t\t\n\t\t\tchunks[i] = body;\n\n\t\t\tvar list = new List<Vector2>();\n\n\t\t\tfor (int y = cy * ChunkSize; y < (cy + 1) * ChunkSize; y++) {\n\t\t\t\tfor (int x = cx * ChunkSize; x < (cx + 1) * ChunkSize; x++) {\n\t\t\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tvar tile = level.Liquid[index];\n\t\t\t\t\tvar side = x == 0 || y == 0 || x == level.Width - 1 || y == level.Height - 1;\n\n\t\t\t\t\tif (side || TileFlags.Matches(tile, TileFlags.Solid)) {\n\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\tif (!side) {\n\t\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours8) {\n\t\t\t\t\t\t\t\tvar n = dir + index;\n\n\t\t\t\t\t\t\t\tif (level.IsInside(n) && (TileFlags.Matches(level.Liquid[n], TileFlags.Solid))) {\n\t\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sum == 8) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar xx = (x) * 16;\n\t\t\t\t\t\tvar yy = (y) * 16 - 8;\n\n\t\t\t\t\t\tlist.Clear();\n\n\t\t\t\t\t\tif (side || Check(level, x - 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 6, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (side || Check(level, x + 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 10, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y + 1) ? 17 : 24)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y + 1) ? 17 : 24)));\n\n\t\t\t\t\t\tFixtureFactory.AttachPolygon(new Vertices(list), 1f, body);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/Level.cs",
    "content": "// #define ART_DEBUG\n\nusing System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.debug;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.variant;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Audio;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.level {\n\tpublic abstract class Level : SaveableEntity {\n\t\tpublic const float LightMin = 0.01f;\n\t\tpublic const float LightMax = 0.95f;\n\t\tpublic static bool RenderPassable = false;\n\t\tpublic static Color ShadowColor = new Color(0f, 0f, 0f, 0.5f);\n\t\tpublic static Color FloorColor = new Color(1f, 1f, 1f, 1f);\n\t\t\n\t\tpublic Tileset Tileset;\n\t\tpublic Tileset MatrixTileset;\n\t\tpublic Biome Biome;\n\t\tpublic bool DrawLight = true;\n\t\tpublic bool NoLightNoRender = true;\n\t\tpublic bool Dark;\n\t\tpublic bool Rains;\n\t\tpublic bool Snows;\n\n\t\tpublic List<string> ItemsToSpawn;\n\n\t\tprivate int width;\n\t\tprivate int height;\n\t\tprivate float time;\n\n\t\tpublic new int Width {\n\t\t\tget => width;\n\n\t\t\tset {\n\t\t\t\twidth = value;\n\t\t\t\tSize = width * height;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic new int Height {\n\t\t\tget => height;\n\n\t\t\tset {\n\t\t\t\theight = value;\n\t\t\t\tSize = width * height;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic int Size;\n\t\tpublic byte[] Tiles;\n\t\tpublic byte[] Liquid;\n\t\tpublic byte[] Variants;\n\t\tpublic byte[] LiquidVariants;\n\t\tpublic byte[] Flags;\n\t\tpublic byte[] WallDecor;\n\t\tpublic bool[] Explored;\n\t\tpublic bool[] Passable;\n\t\tpublic bool[] MatrixLeak;\n\t\tpublic float[] Light;\n\n\t\tpublic Chasm Chasm;\n\t\tpublic HalfWall HalfWall;\n\t\tpublic HalfProjectileLevel HalfProjectile;\n\t\tpublic ProjectileLevelBody ProjectileLevelBody;\n\t\tpublic RenderTarget2D WallSurface;\n\t\tpublic RenderTarget2D MessSurface;\n\n\t\tpublic LevelVariant Variant;\n\n\t\tpublic Level(BiomeInfo biome) {\n\t\t\tSetBiome(biome);\n\t\t\t\n\t\t\tRun.Level = this;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\trainSound?.Stop();\n\t\t\trainSound?.Dispose();\n\n\t\t\tif (Chasm != null) {\n\t\t\t\tHalfProjectile.Done = true;\n\t\t\t\tArea.Remove(HalfProjectile);\n\t\t\t\t\n\t\t\t\tHalfWall.Done = true;\n\t\t\t\tArea.Remove(HalfWall);\n\n\t\t\t\tChasm.Done = true;\n\t\t\t\tArea.Remove(Chasm);\n\n\t\t\t\tProjectileLevelBody.Done = true;\n\t\t\t\tArea.Remove(ProjectileLevelBody);\n\t\t\t}\n\n\t\t\tif (Run.Level == this) {\n\t\t\t\tRun.Level = null;\n\t\t\t}\n\n\t\t\tif (WallSurface != null) {\n\t\t\t\tWallSurface?.Dispose();\n\t\t\t\tMessSurface?.Dispose();\n\t\t\t}\n\n\t\t\tmanager?.Destroy();\n\t\t}\n\n\t\tpublic void SetBiome(BiomeInfo biome) {\n\t\t\tif (biome != null) {\n\t\t\t\tBiome = (Biome) Activator.CreateInstance(biome.Type);\n\t\t\t\tTileset = Tilesets.Get(Biome.Tileset);\n\n\t\t\t\tif (Tilesets.Biome != null && Tileset != null) {\n\t\t\t\t\tTileset.Tiles[(int) Tile.EvilFloor] = Tilesets.Biome.EvilFloor;\n\t\t\t\t\tTileset.Tiles[(int) Tile.GrannyFloor] = Tilesets.Biome.GrannyFloor;\n\t\t\t\t\tTileset.Tiles[(int) Tile.EvilWall] = Tileset.Tiles[(int) Tile.WallA];\n\t\t\t\t\tTileset.Tiles[(int) Tile.GrannyWall] = Tileset.Tiles[(int) Tile.WallA];\n\t\t\t\t}\n\n\t\t\t\tBiome.Apply();\n\t\t\t}\n\n\t\t\tif (MatrixTileset == null) {\n\t\t\t\tMatrixTileset = Tilesets.Get(\"tech_biome\");\n\t\t\t}\n\t\t}\n\n\t\tprivate RenderTriggerManager manager;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tNoLightNoRender = Engine.Instance.State is InGameState;\n\t\t\tVariant = new RegularLevelVariant();\n\t\t\t\n\t\t\tvar s = BlendState.AlphaBlend;\n\t\t\t\t\n\t\t\tblend = new BlendState {\n\t\t\t\tBlendFactor = s.BlendFactor,\n\t\t\t\tAlphaDestinationBlend = s.AlphaDestinationBlend,\n\t\t\t\tColorDestinationBlend = s.ColorDestinationBlend,\n\t\t\t\tColorSourceBlend = s.ColorSourceBlend,\n\t\t\t\tAlphaBlendFunction = s.AlphaBlendFunction,\n\t\t\t\tColorBlendFunction = s.ColorBlendFunction,\n\t\t\t\t\t\n\t\t\t\tAlphaSourceBlend = Blend.DestinationAlpha\n\t\t\t};\n\n\t\t\tmessBlend = new BlendState {\n\t\t\t\tColorBlendFunction = BlendFunction.Add,\n\t\t\t\tColorSourceBlend = Blend.DestinationColor,\n\t\t\t\tColorDestinationBlend = Blend.Zero,\n\t\t\t\t\t\n\t\t\t\tAlphaSourceBlend = Blend.DestinationAlpha\n\t\t\t};\n\n\t\t\tDepth = Layers.Floor;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tmanager = new RenderTriggerManager(this);\n\t\t\t\n\t\t\tmanager.Add(new RenderTrigger(this, RenderChasms, Layers.Chasm));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderLiquids, Layers.Liquid));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderSides, Layers.Sides));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderWalls, Layers.Wall));\n\t\t\tmanager.Add(new RenderTrigger(this, Lights.Render, Layers.Light));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderLight, Layers.TileLights));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderShadowSurface, Layers.Shadows));\n\t\t\tmanager.Add(new RenderTrigger(this, RenderRocks, Layers.Rocks));\n\t\t}\n\n\t\tprivate SoundEffectInstance rainSound;\n\t\t\n\t\tpublic void Prepare() {\n\t\t\ttry {\n\t\t\t\tVariant?.PostInit(this);\n\n\t\t\t\tif (Dark) {\n\t\t\t\t\tLights.ClearColor = new Color(0f, 0f, 0f, 1f);\n\t\t\t\t}\n\n\t\t\t\tif (Rains) {\n\t\t\t\t\tfor (var i = 0; i < 40; i++) {\n\t\t\t\t\t\tRun.Level.Area.Add(new RainParticle());\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Assets.LoadSfx) {\n\t\t\t\t\t\tvar sound = \"level_rain_regular\";\n\n\t\t\t\t\t\tif (Biome is IceBiome) {\n\t\t\t\t\t\t\tsound = \"level_rain_snow\";\n\t\t\t\t\t\t} else if (Biome is JungleBiome) {\n\t\t\t\t\t\t\tsound = \"level_rain_jungle\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar s = Audio.GetSfx(sound);\n\n\t\t\t\t\t\tif (s != null) {\n\t\t\t\t\t\t\trainSound = s.CreateInstance();\n\n\t\t\t\t\t\t\tif (rainSound != null) {\n\t\t\t\t\t\t\t\trainSound.Volume = 0;\n\t\t\t\t\t\t\t\trainSound.IsLooped = true;\n\t\t\t\t\t\t\t\trainSound.Play();\n\n\t\t\t\t\t\t\t\tTween.To(0.5f * Settings.MusicVolume * Settings.MasterVolume, 0, x => rainSound.Volume = x, 0.5f)\n\t\t\t\t\t\t\t\t\t.Delay = 3f;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (Snows) {\n\t\t\t\t\tfor (var i = 0; i < 120; i++) {\n\t\t\t\t\t\tRun.Level.Area.Add(new SnowParticle());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tTileUp();\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new LevelBodyComponent {\n\t\t\t\tLevel = this\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadows));\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic void UpdateRainVolume() {\n\t\t\tif (rainSound != null) {\n\t\t\t\trainSound.Volume = (Player.InBuilding ? 0.1f : 0.5f) * Settings.MusicVolume * Settings.MasterVolume;\n\t\t\t}\n\t\t}\n\n\t\tpublic void ReCreateBodyChunk(int x, int y) {\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tMarkForBodyUpdate(x, y);\n\t\t\tMarkForBodyUpdate(x - 1, y);\n\t\t\tMarkForBodyUpdate(x + 1, y);\n\t\t\tMarkForBodyUpdate(x, y - 1);\n\t\t\tMarkForBodyUpdate(x, y + 1);\n\t\t}\n\t\t\n\t\tprivate void MarkForBodyUpdate(int x, int y) {\n\t\t\tGetComponent<LevelBodyComponent>().ReCreateBodyChunk(x, y);\n\t\t\tChasm.GetComponent<ChasmBodyComponent>().ReCreateBodyChunk(x, y);\n\t\t\tHalfWall.GetComponent<HalfWallBodyComponent>().ReCreateBodyChunk(x, y);\n\t\t\tHalfProjectile.GetComponent<HalfProjectileBodyComponent>().ReCreateBodyChunk(x, y);\n\t\t\tProjectileLevelBody.GetComponent<ProjectileBodyComponent>().ReCreateBodyChunk(x, y);\t\t\n\t\t}\n\t\t\n\t\tpublic void RecreateBody() {\n\t\t\tGetComponent<LevelBodyComponent>().CreateBody();\n\t\t\tChasm.GetComponent<ChasmBodyComponent>().CreateBody();\n\t\t\tHalfWall.GetComponent<HalfWallBodyComponent>().CreateBody();\n\t\t\tHalfProjectile.GetComponent<HalfProjectileBodyComponent>().CreateBody();\n\t\t\tProjectileLevelBody.GetComponent<ProjectileBodyComponent>().CreateBody();\t\t\n\t\t}\n\n\t\t\n\t\tpublic void CreateBody() {\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Chasm == null) {\n\t\t\t\tArea.Add(HalfWall = new HalfWall {\n\t\t\t\t\tLevel = this\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tArea.Add(HalfProjectile = new HalfProjectileLevel {\n\t\t\t\t\tLevel = this\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tArea.Add(Chasm = new Chasm {\n\t\t\t\t\tLevel = this\n\t\t\t\t});\n\n\t\t\t\tArea.Add(ProjectileLevelBody = new ProjectileLevelBody {\n\t\t\t\t\tLevel = this\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tChasm.GetComponent<ChasmBodyComponent>().CreateBody();\t\t\t\n\t\t\tHalfWall.GetComponent<HalfWallBodyComponent>().CreateBody();\n\t\t\tHalfProjectile.GetComponent<HalfProjectileBodyComponent>().CreateBody();\n\t\t\tProjectileLevelBody.GetComponent<ProjectileBodyComponent>().CreateBody();\n\t\t\tGetComponent<LevelBodyComponent>().CreateBody();\n\t\t}\n\n\t\tpublic void CreateDestroyableBody() {\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\t// Destroyable.GetComponent<DestroyableBodyComponent>().CreateBody();\n\t\t}\n\n\t\tprivate bool loadMarked;\n\t\tprivate bool first;\n\t\tprivate BlendState blend;\n\t\tprivate BlendState messBlend;\n\n\t\tpublic void LoadPassable() {\n\t\t\tif (!first) {\n\t\t\t\tfirst = true;\n\t\t\t\tCreatePassable();\n\t\t\t} else {\n\t\t\t\tloadMarked = true;\n\t\t\t}\n\n\t\t\tvar rooms = Area.Tagged[Tags.Room];\n\t\t\tvar f = GetFilling() == Tile.Chasm;\n\t\t\t\n\t\t\tfor (var i = 0; i < Size - Width; i++) {\n\t\t\t\tvar found = false;\n\t\t\t\tvar x = FromIndexX(i);\n\t\t\t\tvar y = FromIndexY(i);\n\t\t\t\t\n\t\t\t\tforeach (var r in rooms) {\n\t\t\t\t\tvar room = (Room) r;\n\t\t\t\t\t\n\t\t\t\t\tif (room.ContainsTile(x, y, 1)) {\n\t\t\t\t\t\tif (!f || room.Type != RoomType.Connection) {\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t//if (Get(i).Matches(Tile.WallA, Tile.Transition) && Get(i + Width).Matches(Tile.WallA, Tile.Transition)) {\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\tforeach (var d in Area.Tagged[Tags.Door]) {\n\t\t\t\t\t\tif ((int) Math.Floor(d.CenterX / 16) == x) {\n\t\t\t\t\t\t\tvar yy = (int) Math.Floor(d.CenterY / 16);\n\n\t\t\t\t\t\t\tif (yy == y + 1 || yy == y) {\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\tExplored[i] = true;\n\t\t\t\t\tLight[i] = 1f;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool IsPassable(int x, int y, bool chasm = false) {\n\t\t\treturn IsPassable(ToIndex(x, y), chasm);\n\t\t}\n\n\t\tpublic bool IsPassable(int i, bool chasm = false) {\n\t\t\tvar t = Get(i);\n\n\t\t\tif (Biome is IceBiome && (t == Tile.WallA || t == Tile.Transition)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (chasm && t == Tile.Chasm) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn t.Matches(TileFlags.Passable) && (Liquid[i] == 0 || Get(i, true).Matches(TileFlags.Passable));\n\t\t}\n\n\t\tpublic void CreatePassable(bool chasm = false) {\n\t\t\tfor (var i = 0; i < Size; i++) {\n\t\t\t\tPassable[i] = IsPassable(i, chasm);\n\t\t\t}\n\t\t}\n\n\t\tpublic void TileUp(bool full = false) {\n\t\t\tcleared = false;\n\t\t\tSize = width * height;\n\t\t\tPathFinder.SetMapSize(Width, Height);\n\t\t\tLevelTiler.TileUp(this, full);\n\t\t}\n\t\t\n\t\tpublic void UpdateTile(int x, int y) {\n\t\t\tvar i = ToIndex(x, y);\n\t\t\tLevelTiler.TileUp(this, i);\n\n\t\t\tfor (var xx = -3; xx <= 2; xx++) {\n\t\t\t\tfor (var yy = -3; yy <= 2; yy++) {\n\t\t\t\t\tvar index = ToIndex(xx + x, yy + y);\n\t\t\t\t\t\n\t\t\t\t\tif (IsInside(index)) {\n\t\t\t\t\t\tVariants[index] = 0;\n\t\t\t\t\t\tLiquidVariants[index] = 0;\n\t\t\t\t\t\tLevelTiler.TileUp(this, index);\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Fill(Tile tile) {\n\t\t\tbyte t = (byte) tile;\n\n\t\t\tfor (int i = 0; i < Size; i++) {\n\t\t\t\tTiles[i] = t;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Set(int i, Tile value) {\n\t\t\tif (value.Matches(TileFlags.LiquidLayer)) {\n\t\t\t\tvar t = Get(i);\n\t\t\t\t\n\t\t\t\tif (t == Tile.Chasm) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (t.IsWall() || t.Matches(Tile.SensingSpikeTmp) || t.Matches(Tile.SpikeOnTmp) || t.Matches(Tile.SpikeOnTmp) || t.Matches(Tile.Plate)) {\n\t\t\t\t\tTiles[i] = (byte) Tile.FloorA;\n\t\t\t\t\tVariants[i] = 0;\n\t\t\t\t}\n\n\t\t\t\tLiquid[i] = (byte) value;\n\t\t\t\tLiquidVariants[i] = 0;\n\t\t\t} else {\n\t\t\t\tif (value.IsWall() || value == Tile.Chasm || ((Tile) Liquid[i]).Matches(Tile.Lava, Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\t\tLiquid[i] = 0;\n\t\t\t\t\tLiquidVariants[i] = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTiles[i] = (byte) value;\n\t\t\t\tVariants[i] = 0;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Set(int x, int y, Tile value) {\n\t\t\tSet(ToIndex(x, y), value);\n\t\t}\n\t\t\n\t\tpublic Tile Get(int x, int y, bool liquid = false) {\n\t\t\treturn (Tile) (liquid ? Liquid[ToIndex(x, y)] : Tiles[ToIndex(x, y)]);\n\t\t}\n\t\t\n\t\tpublic Tile Get(int i, bool liquid = false) {\n\t\t\treturn (Tile) (liquid ? Liquid[i] : Tiles[i]);\n\t\t}\n\t\t\n\t\tpublic int ToIndex(int x, int y) {\n\t\t\treturn x + y * width;\n\t\t}\n\n\t\tpublic int FromIndexX(int index) {\n\t\t\treturn index % width;\n\t\t}\n\n\t\tpublic int FromIndexY(int index) {\n\t\t\treturn index / width;\n\t\t}\n\n\t\tpublic bool IsInside(int x, int y) {\n\t\t\treturn x >= 0 && y >= 0 && x < width && y < height;\n\t\t}\n\n\t\tpublic bool IsInside(int i) {\n\t\t\treturn i >= 0 && i < Size;\n\t\t}\n\n\t\tpublic bool CheckFor(int x, int y, int flag, bool liquid = false) {\n\t\t\treturn Get(x, y, liquid).Matches(flag);\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteString(Biome.Id);\n\t\t\tstream.WriteInt32(width);\n\t\t\tstream.WriteInt32(height);\n\n\t\t\tfor (int i = 0; i < Size; i++) {\n\t\t\t\tstream.WriteByte(Tiles[i]);\n\t\t\t\tstream.WriteByte(Liquid[i]);\n\t\t\t\tstream.WriteByte(Flags[i]);\n\t\t\t\tstream.WriteBoolean(Explored[i]);\n\t\t\t}\t\n\t\t\t\n\t\t\tstream.WriteBoolean(Dark);\n\t\t\tstream.WriteBoolean(Snows);\n\t\t\tstream.WriteBoolean(Rains);\n\n\t\t\tif (Variant == null) {\n\t\t\t\tVariant = new RegularLevelVariant();\n\t\t\t}\n\t\t\t\n\t\t\tstream.WriteString(Variant.Id);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tvar biome = stream.ReadString();\n\n\t\t\tif (BiomeRegistry.Defined.TryGetValue(biome, out var b)) {\n\t\t\t\tSetBiome(b);\n\t\t\t} else {\n\t\t\t\tSetBiome(BiomeRegistry.Defined[Biome.Castle]);\n\t\t\t}\n\t\t\t\n\t\t\tWidth = stream.ReadInt32();\n\t\t\tHeight = stream.ReadInt32();\n\n\t\t\tSetup();\n\n\t\t\tfor (var i = 0; i < Size; i++) {\n\t\t\t\tTiles[i] = stream.ReadByte();\n\t\t\t\tLiquid[i] = stream.ReadByte();\n\t\t\t\tFlags[i] = stream.ReadByte();\n\t\t\t\tExplored[i] = stream.ReadBoolean();\n\t\t\t}\n\t\t\t\n\t\t\tCreateBody();\n\t\t\tCreateDestroyableBody();\n\t\t\t\n\t\t\tDark = stream.ReadBoolean();\n\t\t\tSnows = stream.ReadBoolean();\n\t\t\tRains = stream.ReadBoolean();\n\n\t\t\tVariant = VariantRegistry.Create(stream.ReadString());\n\t\t\tLoadPassable();\n\t\t}\n\n\t\tpublic void MarkForClearing() {\n\t\t\tTiles = new byte[Size];\n\t\t\tLiquid = new byte[Size];\n\t\t\tVariants = new byte[Size];\n\t\t\tLiquidVariants = new byte[Size];\n\t\t\tcleared = false;\n\t\t}\n\n\t\tpublic void Setup() {\n\t\t\tSize = width * height;\n\t\t\t\n\t\t\tTiles = new byte[Size];\n\t\t\tLiquid = new byte[Size];\n\t\t\tVariants = new byte[Size];\n\t\t\tLiquidVariants = new byte[Size];\n\t\t\tLight = new float[Size];\n\t\t\tFlags = new byte[Size];\n\t\t\tWallDecor = new byte[Size];\n\t\t\tExplored = new bool[Size];\n\n\t\t\tvar light = Run.Depth == 0;\n\t\t\t\n\t\t\tfor (var i = 0; i < Size; i++) {\n\t\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\t\tWallDecor[i] = (byte) Rnd.Int(1, 9);\n\t\t\t\t}\n\n\t\t\t\tif (light) {\n\t\t\t\t\tExplored[i] = true;\n\t\t\t\t\tLight[i] = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPassable = new bool[Size];\n\t\t\tMatrixLeak = new bool[Size];\n\n\t\t\t/*if (Run.Depth > 0) {\n\t\t\t\tfor (var i = 0; i < Size; i++) {\n\t\t\t\t\tif (Rnd.Chance(1)) {\n\t\t\t\t\t\tMatrixLeak[i] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}*/\n\n\t\t\tPathFinder.SetMapSize(Width, Height);\n\t\t\t\n\t\t\tWallSurface = new RenderTarget2D(Engine.GraphicsDevice, Display.Width + 1, Display.Height + 1);\n\t\t\tMessSurface = new RenderTarget2D(Engine.GraphicsDevice, Width * 16, Height * 16, false, Engine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents);\n\t\t}\n\n\t\tpublic bool CheckFlag(int x, int y, int i) {\n\t\t\treturn CheckFlag(ToIndex(x, y), i);\n\t\t}\n\t\t\n\t\tpublic bool CheckFlag(int index, int i) {\n\t\t\treturn BitHelper.IsBitSet(Flags[index], i);\n\t\t}\n\n\t\tpublic void SetFlag(int x, int y, int i, bool on) {\n\t\t\tSetFlag(ToIndex(x, y), i, on);\n\t\t}\n\n\t\tpublic void SetFlag(int index, int i, bool on) {\n\t\t\tFlags[index] = (byte) BitHelper.SetBit(Flags[index], i, on);\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tGraphics.Batch.DrawRectangle(new RectangleF(0, 0, Width * 16, Height * 16), Color.Green);\n\t\t}\n\t\t\n\t\tpublic int GetRenderLeft(Camera camera) {\n\t\t\treturn (int) MathUtils.Clamp(0, Width - 1, (int) Math.Floor(camera.X / 16 - 1f));\n\t\t}\n\n\t\tpublic int GetRenderTop(Camera camera) {\n\t\t\treturn (int) MathUtils.Clamp(0, Height - 1, (int) Math.Floor(camera.Y / 16 - 1f));\n\t\t}\n\n\t\tpublic int GetRenderRight(Camera camera) {\n\t\t\treturn (int) MathUtils.Clamp(0, Width - 1, (int) Math.Ceiling(camera.Right / 16 + 1f));\n\t\t}\n\n\t\tpublic int GetRenderBottom(Camera camera) {\n\t\t\treturn (int) MathUtils.Clamp(0, Height - 1, (int) Math.Ceiling(camera.Bottom / 16 + 1f));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (loadMarked) {\n\t\t\t\tloadMarked = false;\n\t\t\t\tCreatePassable();\n\t\t\t}\n\t\t\t\n\t\t\ttime += dt;\n\t\t}\n\t\t\n\t\t// Renders light emited by tiles\n\t\tpublic void RenderTileLights() {\n\t\t\tif (!LevelLayerDebug.TileLight) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\t\t\t\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderTop(camera);\n\n\t\t\tGraphics.Color = new Color(1f, 1f, 0f, 1f);\n\t\t\t\n\t\t\tfor (int y = GetRenderBottom(camera); y >= toY; y--) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar light = Light[index];\n\n\t\t\t\t\tif (NoLightNoRender && light < LightMin) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// var tile = (Tile) Tiles[index];\n\t\t\t\t\tvar liquid = (Tile) Liquid[index];\n\n\t\t\t\t\tif (liquid == Tile.Lava) {\n\t\t\t\t\t\tGraphics.Render(Tilesets.Biome.Light[LiquidVariants[index]], new Vector2(x * 16 - 24, y * 16 - 24), 0, Vector2.Zero, new Vector2(2));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\t// Renders floor layer\n\t\tpublic override void Render() {\n\t\t\tif (this != Run.Level) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!LevelLayerDebug.Floor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tmanager.Update();\n\n\t\t\tvar camera = Camera.Instance;\n\t\t\t\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderTop(camera);\n\t\t\tvar active = !Engine.Instance.State.Paused;\n\n\t\t\tvar shader = Shaders.Chasm;\n\t\t\tShaders.Begin(shader);\n\n\t\t\tshader.Parameters[\"h\"].SetValue(8f / Tileset.WallTopA.Texture.Height);\n\t\t\tvar enabled = shader.Parameters[\"enabled\"];\n\t\t\tenabled.SetValue(false);\n\t\t\t\t\t\t\t\n\t\t\tfor (int y = GetRenderBottom(camera); y >= toY; y--) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar light = Light[index];\n\n\t\t\t\t\tif (NoLightNoRender && light < LightMin) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar tile = Tiles[index];\n\t\t\t\t\tvar t = (Tile) tile;\n\n\t\t\t\t\tif (tile > 0) {\n\t\t\t\t\t\tif (t.Matches(TileFlags.FloorLayer)) {\n\t\t\t\t\t\t\tif (!Settings.LowQuality && active && CheckFlag(index, Flag.Burning) && Rnd.Chance(10)) {\n\t\t\t\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\t\t\t\tPosition = new Vector2(x * 16 + Rnd.Float(-2, 18), y * 16 + Rnd.Float(-2, 18)),\n\t\t\t\t\t\t\t\t\tXChange = 0.1f,\n\t\t\t\t\t\t\t\t\tScale = 0.3f,\n\t\t\t\t\t\t\t\t\tVy = 8,\n\t\t\t\t\t\t\t\t\tT = 0.5f,\n\t\t\t\t\t\t\t\t\tB = 0\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar pos = new Vector2(x * 16, y * 16);\n\n\t\t\t\t\t\t\tif (t == Tile.PistonDown) {\n\t\t\t\t\t\t\t\tRenderWall(x, y, index, tile, t, 0);\n\t\t\t\t\t\t\t} else if (t != Tile.Chasm && t != Tile.SpikeOffTmp && t != Tile.SensingSpikeTmp) {\n\t\t\t\t\t\t\t\t\tGraphics.Render((MatrixLeak[index] && t.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD) ? MatrixTileset : Tileset).Tiles[tile][\n#if ART_DEBUG\n\t\t\t\t\t\t\t\t\t\t0\n#else\n\t\t\t\t\t\t\t\t\t\tVariants[index]\n#endif\n\t\t\t\t\t\t\t\t\t], pos);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tShaders.End(); \n\t\t}\n\n\t\tpublic void RenderShadows() {\n\t\t\tif (Done) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!LevelLayerDebug.Shadows) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\n\t\t\tfor (int y = toY; y >= GetRenderTop(camera); y--) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar tl = (Tile) Tiles[index];\n\t\t\t\t\tvar tileset = (MatrixLeak[index] ? MatrixTileset : Tileset);\n\n\t\t\t\t\tif (tl.Matches(TileFlags.WallLayer) && (IsInside(index + width))) {\n\t\t\t\t\t\tvar t = (Tile) Tiles[index + width];\n\n\t\t\t\t\t\tif (!t.IsWall() && t != Tile.Chasm) {\n\t\t\t\t\t\t\tGraphics.Render(tileset.WallA[CalcWallIndex(x, y)], new Vector2(x * 16, y * 16 + 10), 0, Vector2.Zero,\n\t\t\t\t\t\t\t\tVector2.One, SpriteEffects.FlipVertically);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (tl != Tile.Transition && (tl.IsWall() || tl == Tile.PistonDown)) {\n\t\t\t\t\t\tvar v = Variants[index];\n\t\t\t\t\t\tvar ar = tileset.WallAExtensions;\n\t\t\t\t\t\t\n\t\t\t\t\t\tswitch (tl) {\n\t\t\t\t\t\t\tcase Tile.WallB: {\n\t\t\t\t\t\t\t\tar = tileset.WallBExtensions;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcase Tile.Planks: {\n\t\t\t\t\t\t\t\tar = Tilesets.Biome.PlanksExtensions;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcase Tile.GrannyWall: {\n\t\t\t\t\t\t\t\tar = Tilesets.Biome.GrannyExtensions;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcase Tile.EvilWall: {\n\t\t\t\t\t\t\t\tar = Tilesets.Biome.EvilExtensions;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!BitHelper.IsBitSet(v, 1)) {\n\t\t\t\t\t\t\tGraphics.Render(ar[1], new Vector2(x * 16 + 16, y * 16 + 9));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!BitHelper.IsBitSet(v, 2)) {\n\t\t\t\t\t\t\tGraphics.Render(ar[2], new Vector2(x * 16, y * 16 + 16 + 8));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!BitHelper.IsBitSet(v, 3)) {\n\t\t\t\t\t\t\tGraphics.Render(ar[3], new Vector2(x * 16 - 8, y * 16 + 9));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar l = Liquid[index];\n\t\t\t\t\tvar lt = (Tile) l;\n\n\t\t\t\t\tif (lt.IsRock()) {\n\t\t\t\t\t\tGraphics.Render(tileset.Tiles[l][LiquidVariants[index]], new Vector2(x * 16, y * 16 + 3));\n\t\t\t\t\t} else if (lt == Tile.MetalBlock) {\n\t\t\t\t\t\tGraphics.Render(tileset.MetalBlockShadow, new Vector2(x * 16, y * 16 + 6), 0, Vector2.Zero,\n\t\t\t\t\t\t\tVector2.One, SpriteEffects.FlipVertically);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool cleared;\n\n\t\tpublic void RenderMess() {\n\t\t\tif (!LevelLayerDebug.Mess ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\t\t\tvar state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\tstate.End();\n\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(MessSurface);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Matrix.Identity);\n\n\t\t\tif (!cleared) {\n\t\t\t\tcleared = true;\n\t\t\t\tGraphics.Clear(Color.White);\n\t\t\t\t// Uncomment for a wild graphics effect\n\t\t\t}/* else {\n\t\t\t\tGraphics.Clear(new Color(1f, 1f, 1f, 1 / 255f));\n\t\t\t}*/\n\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t\n\t\t\tforeach (var p in Area.Tagged[Tags.Mess]) {\n\t\t\t\t((SplashFx) p).RenderInSurface();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, messBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\tvar region = new TextureRegion();\n\n\t\t\tregion.Texture = MessSurface;\n\t\t\tregion.Source.X = (int) Math.Floor(camera.X);\n\t\t\tregion.Source.Y = (int) Math.Floor(camera.Y);\n\t\t\tregion.Source.Width = Display.Width + 1;\n\t\t\tregion.Source.Height = Display.Height + 1;\n\t\t\t\n\t\t\tGraphics.Color = FloorColor;\n\n\t\t\tGraphics.Render(region, camera.TopLeft - new Vector2(camera.Position.X % 1, \n\t\t\t\t                        camera.Position.Y % 1));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tstate.Begin();\n\t\t}\n\t\t\n\t\tpublic void RenderRocks() {\n\t\t\tif (!LevelLayerDebug.Rocks) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\n\t\t\tfor (int y = toY; y >= GetRenderTop(camera); y--) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar light = Light[index];\n\n\t\t\t\t\tif (NoLightNoRender && light < LightMin) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar tile = Liquid[index];\n\n\t\t\t\t\tif (tile > 0) {\n\t\t\t\t\t\tvar tt = (Tile) tile;\n\n\t\t\t\t\t\tif (tt.IsHalfWall()) {\n\t\t\t\t\t\t\tGraphics.Render(Tileset.Tiles[tile][LiquidVariants[index]], new Vector2(x * 16, y * 16));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void RenderLiquids() {\n\t\t\tif (!LevelLayerDebug.Liquids) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\n\t\t\tvar region = new TextureRegion();\n\t\t\tvar shader = Shaders.Terrain;\n\t\t\t\t\t\t\n\t\t\tShaders.Begin(shader);\n\n\t\t\tvar paused = Engine.Instance.State.Paused;\n\t\t\t\n\t\t\tvar enabled = shader.Parameters[\"enabled\"];\n\t\t\tvar tilePosition = shader.Parameters[\"tilePosition\"];\n\t\t\tvar edgePosition = shader.Parameters[\"edgePosition\"];\n\t\t\tvar flow = shader.Parameters[\"flow\"];\n\t\t\tflow.SetValue(0f);\n\t\t\t\n\t\t\tshader.Parameters[\"time\"].SetValue(time * 0.04f);\n\t\t\tshader.Parameters[\"h\"].SetValue(64f / Tilesets.Biome.WaterPattern.Texture.Height);\n\n\t\t\tvar sy = shader.Parameters[\"sy\"];\n\n\t\t\tenabled.SetValue(true);\n\n\t\t\tfor (int y = toY; y >= GetRenderTop(camera); y--) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar light = Light[index];\n\n\t\t\t\t\tif (NoLightNoRender && light < LightMin) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar tile = Liquid[index];\n\n\t\t\t\t\tif (tile > 0) {\n\t\t\t\t\t\tvar tt = (Tile) tile;\n\n\t\t\t\t\t\tif (tt == Tile.Collider) {\n\t\t\t\t\t\t\t#if DEBUG\n\t\t\t\t\t\t\tif (Engine.EditingLevel) {\n\t\t\t\t\t\t\t\tenabled.SetValue(false);\n\t\t\t\t\t\t\t\tGraphics.Render(Tilesets.Biome.Collider, new Vector2(x * 16, y * 16));\n\t\t\t\t\t\t\t\tenabled.SetValue(true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (tt.IsHalfWall()) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tregion.Set(Tilesets.Biome.Patterns[tile]);\n\t\t\t\t\t\tregion.Source.Width = 16;\n\t\t\t\t\t\tregion.Source.Height = 16;\n\n\t\t\t\t\t\tif (tt == Tile.Water) {\n\t\t\t\t\t\t\tflow.SetValue(1f);\n\t\t\t\t\t\t\tsy.SetValue(y % 4 * 16f / Tilesets.Biome.WaterPattern.Texture.Height);\n\t\t\t\t\t\t} else if (tt == Tile.Lava) {\n\t\t\t\t\t\t\tflow.SetValue(0.25f);\n\t\t\t\t\t\t\tsy.SetValue(y % 4 * 16f / Tilesets.Biome.WaterPattern.Texture.Height);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tregion.Source.Y += y % 4 * 16;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tregion.Source.X += x % 4 * 16;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar pos = new Vector2(x * 16, y * 16);\n\t\t\t\t\t\tvar t = (Tile) tile;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!t.Matches(Tile.Ember, Tile.Chasm)) {\n\t\t\t\t\t\t\tvar edge = Tilesets.Biome.Edges[tile][LiquidVariants[index]];\n\n\t\t\t\t\t\t\tedgePosition.SetValue(new Vector2(\n\t\t\t\t\t\t\t\t(float) edge.Source.X / edge.Texture.Width,\n\t\t\t\t\t\t\t\t(float) edge.Source.Y / edge.Texture.Height\n\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttilePosition.SetValue(new Vector2(\n\t\t\t\t\t\t\t\t(float) region.Source.X / region.Texture.Width,\n\t\t\t\t\t\t\t\t(float) region.Source.Y / region.Texture.Height\n\t\t\t\t\t\t\t));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tGraphics.Render(region, pos);\n\n\t\t\t\t\t\t\tif ((t == Tile.Water || t == Tile.Lava) && !Settings.LowQuality && !paused) {\n\t\t\t\t\t\t\t\tif (t == Tile.Lava && Rnd.Chance(0.5f)) {\n\t\t\t\t\t\t\t\t\tvar p = Particles.Wrap(Particles.Lava(), Area, pos + Rnd.Vector(0, 16));\n\t\t\t\t\t\t\t\t\tp.Particle.Velocity = MathUtils.CreateVector(Rnd.Float(-10, 10), -Rnd.Float(30, 45));\n\t\t\t\t\t\t\t\t\tp.Particle.Scale = Rnd.Float(0.3f, 0.5f);\n\t\t\t\t\t\t\t\t\tp.Particle.T = 0;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (Get(index + width) == Tile.Chasm && Rnd.Chance(6)) {\n\t\t\t\t\t\t\t\t\tArea.Add(new WaterfallFx {\n\t\t\t\t\t\t\t\t\t\tPosition = pos + new Vector2(Rnd.Float(16), 16),\n\t\t\t\t\t\t\t\t\t\tLava = t == Tile.Lava\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tenabled.SetValue(false);\n\t\t\t\t\t\t\tGraphics.Render(region, pos);\n\t\t\t\t\t\t\tenabled.SetValue(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (tt == Tile.Water || tt == Tile.Lava) {\n\t\t\t\t\t\t\tflow.SetValue(0f);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tShaders.End();\n\t\t\tRenderMess();\n\t\t}\n\n\t\tprivate TextureRegion clear;\n\t\t\n\t\tprivate void RenderChasms() {\n\t\t\tif (!LevelLayerDebug.Chasms) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\t\t\t\n\t\t\tvar active = !Engine.Instance.State.Paused;\n\t\t\tvar state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\tstate.End();\n\n\t\t\tif (clear == null) {\n\t\t\t\tclear = CommonAse.Particles.GetSlice(\"wall\");\n\t\t\t}\n\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(MessSurface);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Matrix.Identity);\n\n\t\t\tfor (int y = GetRenderTop(camera); y < toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x < toX; x++) {\n\t\t\t\t\tif ((Tile) Tiles[ToIndex(x, y)] == Tile.Chasm) {\n\t\t\t\t\t\tGraphics.Render(clear, new Vector2(x * 16, y * 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tvar shader = Shaders.Chasm;\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\t\tstate.RasterizerState, shader, Camera.Instance?.Matrix);\n\n\t\t\tshader.Parameters[\"h\"].SetValue(8f / Tileset.WallTopA.Texture.Height);\n\t\t\tvar sy = shader.Parameters[\"y\"];\n\t\t\tvar enabled = shader.Parameters[\"enabled\"];\n\t\t\tenabled.SetValue(true);\n\n\t\t\tfor (int y = GetRenderTop(camera); y < toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x < toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\n\t\t\t\t\tif ((Tile) Tiles[index] == Tile.Chasm) {\n\t\t\t\t\t\tvar pos = new Vector2(x * 16, y * 16);\n\n\t\t\t\t\t\tif (active && Rnd.Chance(0.1f)) {\n\t\t\t\t\t\t\tArea.Add(new ChasmFx {\n\t\t\t\t\t\t\t\tPosition = pos + new Vector2(Rnd.Float(16), Rnd.Float(16))\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (index >= width) {\n\t\t\t\t\t\t\tvar tt = Get(index - width);\n\n\t\t\t\t\t\t\tif (tt != Tile.Chasm) {\n\t\t\t\t\t\t\t\tvar ind = CalcWallSide(x, y);\n\t\t\t\t\t\t\t\t/*var id = -1;\n\n\t\t\t\t\t\t\t\tif (!IsInside(index + 1 - width) || ((Tile) Tiles[index + 1 - width]).Matches(Tile.Chasm)) {\n\t\t\t\t\t\t\t\t\tid += 1;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (!IsInside(index - 1 - width) || ((Tile) Tiles[index - 1 - width]).Matches(Tile.Chasm)) {\n\t\t\t\t\t\t\t\t\tid += 2;\n\t\t\t\t\t\t\t\t}*/\n\n\t\t\t\t\t\t\t\tvar tileset = (MatrixLeak[index] ? MatrixTileset : Tileset);\n\t\t\t\t\t\t\t\tTextureRegion textureRegion;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tswitch (tt) {\n\t\t\t\t\t\t\t\t\tcase Tile.WallA: case Tile.Piston: case Tile.PistonDown:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.WallA[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.Planks:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = Tilesets.Biome.Planks[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.EvilWall: case Tile.EvilFloor:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = Tilesets.Biome.EvilWall[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.GrannyWall: case Tile.GrannyFloor:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = Tilesets.Biome.GrannyWall[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.FloorA:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.FloorSidesA[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.FloorB:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.FloorSidesB[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.FloorC:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.FloorSidesC[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Tile.FloorD:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.FloorSidesD[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tcase Tile.WallB:\n\t\t\t\t\t\t\t\t\t\ttextureRegion = tileset.WallB[ind];\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tsy.SetValue((float) textureRegion.Source.Y / textureRegion.Texture.Height);\n\t\t\t\t\t\t\t\tGraphics.Render(textureRegion, pos);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tenabled.SetValue(false);\n\t\t\tShaders.End();\n\t\t}\n\t\t\n\t\tprivate void RenderSides() {\n\t\t\tif (!LevelLayerDebug.Sides) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\t\t\t\n\t\t\tfor (int y = GetRenderTop(camera); y < toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x < toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar tl = (Tile) Tiles[index];\n\t\t\t\t\t\n\t\t\t\t\tif (tl.Matches(TileFlags.WallLayer)) {\n\t\t\t\t\t\tif ((IsInside(index + width) && !((Tile) Tiles[index + width]).IsWall())) {\n\t\t\t\t\t\t\tvar pos = new Vector2(x * 16, y * 16 + 8);\n\t\t\t\t\t\t\tvar a = tl.Matches(Tile.WallA, Tile.Piston);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (tl == Tile.Crack) {\n\t\t\t\t\t\t\t\ta = (IsInside(index + 1) && Get(index + 1) == Tile.WallA) ||\n\t\t\t\t\t\t\t\t    (IsInside(index + width) && Get(index + width) == Tile.WallA);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar tileset = (MatrixLeak[index] ? MatrixTileset : Tileset);\n\t\t\t\t\t\t\tvar ar = tileset.WallA;\n\t\t\t\t\t\t\tvar arr = tileset.WallSidesA;\n\n\t\t\t\t\t\t\tif (!a) {\n\t\t\t\t\t\t\t\tswitch (tl) {\n\t\t\t\t\t\t\t\t\tcase Tile.Planks: {\n\t\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.Planks;\n\t\t\t\t\t\t\t\t\t\tarr = Tilesets.Biome.PlankSides;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tcase Tile.Crack: {\n\t\t\t\t\t\t\t\t\t\tif (!(IsInside(index + 1) && Get(index + 1) == Tile.WallA) &&\n\t\t\t\t\t\t\t\t\t\t    !(IsInside(index + width) && Get(index + width) == Tile.WallA)) {\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\tar = tileset.WallB;\n\t\t\t\t\t\t\t\t\t\t\tarr = tileset.WallSidesB;\n\t\t\t\t\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tcase Tile.WallB: {\n\t\t\t\t\t\t\t\t\t\tar = tileset.WallB;\n\t\t\t\t\t\t\t\t\t\tarr = tileset.WallSidesB;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tcase Tile.EvilWall: {\n\t\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.EvilWall;\n\t\t\t\t\t\t\t\t\t\tarr = Tilesets.Biome.EvilWallSides;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tcase Tile.GrannyWall: {\n\t\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.GrannyWall;\n\t\t\t\t\t\t\t\t\t\tarr = Tilesets.Biome.GrannyWallSides;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar ind = -1;\n\n\t\t\t\t\t\t\tif (index >= Size - 1 || !((Tile) Tiles[index + 1]).Matches(Tile.Piston, Tile.WallA, Tile.WallB,\n\t\t\t\t\t\t\t\t    Tile.Planks, Tile.EvilWall, Tile.GrannyWall, Tile.Transition)) {\n\t\t\t\t\t\t\t\tind += 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (index <= 0 || !((Tile) Tiles[index - 1]).Matches(Tile.Piston, Tile.WallA, Tile.WallB, Tile.EvilWall,\n\t\t\t\t\t\t\t\t    Tile.GrannyWall, Tile.Planks, Tile.Transition)) {\n\t\t\t\t\t\t\t\tind += 2;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (ind != -1) {\n\t\t\t\t\t\t\t\tGraphics.Render(arr[ind], pos);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tGraphics.Render(ar[CalcWallIndex(x, y)], pos);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (tl == Tile.Chasm) {\n\t\t\t\t\t\tif (IsInside(index + width) && !Get(index + width).IsWall() && Get(index + width) != Tile.Chasm) {\n\t\t\t\t\t\t\tGraphics.Render(Tilesets.Biome.ChasmBottom[CalcChasmIndex(x, y + 1)], new Vector2(x * 16, y * 16 + 16));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tif (IsInside(index + 1) && !Get(index + 1).IsWall() && Get(index + 1) != Tile.Chasm) {\n\t\t\t\t\t\t\tGraphics.Render(Tilesets.Biome.ChasmRight[CalcChasmIndex(x + 1, y)], new Vector2(x * 16 + 16, y * 16));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tif (index > 0 && !Get(index - 1).IsWall() && Get(index - 1) != Tile.Chasm) {\n\t\t\t\t\t\t\tGraphics.Render(Tilesets.Biome.ChasmLeft[CalcChasmIndex(x - 1, y)], new Vector2(x * 16 - 16, y * 16));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void RenderShadowSurface() {\n\t\t\tif (!LevelLayerDebug.Shadows) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Done) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Engine.Instance.StateRenderer.UiTarget != null) {\n\t\t\t\tGraphics.Color = ShadowColor;\n\n\t\t\t\tvar c = Camera.Instance;\n\t\t\t\tvar z = c.Zoom;\n\t\t\t\tvar n = Math.Abs(z - 1) > 0.01f;\n\t\t\t\t\n\t\t\t\tif (n) {\n\t\t\t\t\tc.Zoom = 1;\n\t\t\t\t\tc.UpdateMatrices();\n\t\t\t\t}\n\n\t\t\t\tGraphics.Render(Engine.Instance.StateRenderer.UiTarget,\n\t\t\t\t\tCamera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, \n\t\t\t\t\t\tCamera.Instance.Position.Y % 1));\n\n\t\t\t\tif (n) {\n\t\t\t\t\tc.Zoom = z;\n\t\t\t\t\tc.UpdateMatrices();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void RenderWall(int x, int y, int index, int tile, Tile t, int m) {\n\t\t\tvar a = false;\n\t\t\tvar tileset = (MatrixLeak[index] ? MatrixTileset : Tileset);\n\t\t\t\n\t\t\tif (t != Tile.Transition) {\n\t\t\t\tvar region = t == Tile.Planks ? Tilesets.Biome.PlanksTop : tileset.Tiles[tile][0];\n\t\t\t\ta = t == Tile.WallA || t == Tile.Piston || t == Tile.PistonDown;\n\t\t\t\tvar ab = a || t == Tile.GrannyWall || t == Tile.EvilWall;\n\t\t\t\tvar effect = Graphics.ParseEffect(x % 2 == 0, y % 2 == 0);\n\n\t\t\t\tif (ab) {\n\t\t\t\t\tvar v = WallDecor[index];\n\n\t\t\t\t\tif (!t.Matches(Tile.Piston, Tile.PistonDown) && v > 0) {\n\t\t\t\t\t\tregion = Tileset.WallVariants[v - 1];\n\t\t\t\t\t}\n\t\t\t\t} else if (t == Tile.Crack) {\n\t\t\t\t\tab = (IsInside(index + 1) && Get(index + 1) == Tile.WallA) ||\n\t\t\t\t\t     (IsInside(index + width) && Get(index + width) == Tile.WallA);\n\t\t\t\t\tregion = ab\n\t\t\t\t\t\t? tileset.WallTopA\n\t\t\t\t\t\t: tileset.WallTopB;\n\t\t\t\t} else {\n\t\t\t\t\teffect = SpriteEffects.None;\n\t\t\t\t}\n\n\t\t\t\tGraphics.Render(region, new Vector2(x * 16, y * 16 - 8), 0, Vector2.Zero, Vector2.One, effect);\n\t\t\t}\n\t\t\t\n\t\t\tif (t.IsWall() || t == Tile.PistonDown) {\n\t\t\t\tbyte v = Variants[index];\n\n\t\t\t\tfor (int xx = 0; xx < 2; xx++) {\n\t\t\t\t\tfor (int yy = 0; yy < 2; yy++) {\n\t\t\t\t\t\tint lv = 0;\n\n\t\t\t\t\t\tif (yy > 0 || BitHelper.IsBitSet(v, 0)) {\n\t\t\t\t\t\t\tlv += 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (xx == 0 || BitHelper.IsBitSet(v, 1)) {\n\t\t\t\t\t\t\tlv += 2;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (yy == 0 || BitHelper.IsBitSet(v, 2)) {\n\t\t\t\t\t\t\tlv += 4;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (xx > 0 || BitHelper.IsBitSet(v, 3)) {\n\t\t\t\t\t\t\tlv += 8;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar ar = tileset.WallTopsA;\n\n\t\t\t\t\t\tif (!a) {\n\t\t\t\t\t\t\tswitch (t) {\n\t\t\t\t\t\t\t\tcase Tile.Transition: {\n\t\t\t\t\t\t\t\t\tar = tileset.WallTopsTransition;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcase Tile.WallB: {\n\t\t\t\t\t\t\t\t\tar = tileset.WallTopsB;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcase Tile.Crack: {\n\t\t\t\t\t\t\t\t\tif (!(IsInside(index + 1) && Get(index + 1) == Tile.WallA) && !(IsInside(index + width) && Get(index + width) == Tile.WallA)) {\n\t\t\t\t\t\t\t\t\t\tar = tileset.WallTopsB;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcase Tile.Planks: {\n\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.PlankTops;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcase Tile.GrannyWall: {\n\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.GrannyWallTops;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcase Tile.EvilWall: {\n\t\t\t\t\t\t\t\t\tar = Tilesets.Biome.EvilWallTops;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (lv == 15) {\n\t\t\t\t\t\t\tlv = 0;\n\n\t\t\t\t\t\t\tif (xx == 1 && yy == 0 && !BitHelper.IsBitSet(v, 4)) {\n\t\t\t\t\t\t\t\tlv += 1;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (xx == 1 && yy == 1 && !BitHelper.IsBitSet(v, 5)) {\n\t\t\t\t\t\t\t\tlv += 2;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (xx == 0 && yy == 1 && !BitHelper.IsBitSet(v, 6)) {\n\t\t\t\t\t\t\t\tlv += 4;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (xx == 0 && yy == 0 && !BitHelper.IsBitSet(v, 7)) {\n\t\t\t\t\t\t\t\tlv += 8;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (lv != 15) {\n\t\t\t\t\t\t\t\tvar vl = Tileset.WallMapExtra[lv];\n\n\t\t\t\t\t\t\t\tif (vl != -1) {\n\t\t\t\t\t\t\t\t\tvar i = ToIndex(x + (xx == 0 ? -1 : 1), y + yy - 1);\n\t\t\t\t\t\t\t\t\tvar light = DrawLight ? (i < 0 || i >= Light.Length ? 1 : Light[i]) : 1;\n\n\t\t\t\t\t\t\t\t\tif (light > LightMin) {\n\t\t\t\t\t\t\t\t\t\tGraphics.Color.A = (byte) (light * 255);\n\t\t\t\t\t\t\t\t\t\tvar ind = vl + 12 * CalcWallTopIndex(x, y);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tGraphics.Render(ar[ind],\n\t\t\t\t\t\t\t\t\t\t\tnew Vector2(x * 16 + xx * 8, y * 16 + yy * 8 - m));\n\n\t\t\t\t\t\t\t\t\t\tGraphics.Color.A = 255;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar vl = Tileset.WallMap[lv];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (vl != -1) {\n\t\t\t\t\t\t\t\tvar i = ToIndex(x + (xx == 0 ? -1 : 1), y + yy - 1);\n\t\t\t\t\t\t\t\tvar light = DrawLight ? (i < 0 || i >= Light.Length ? 1 : Light[i]) : 1;\n\n\t\t\t\t\t\t\t\tif (light > LightMin) {\n\t\t\t\t\t\t\t\t\tGraphics.Color.A = (byte) (light * 255);\n\n\t\t\t\t\t\t\t\t\tvar ind = vl + 12 * CalcWallTopIndex(x, y);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tGraphics.Render(ar[ind],\n\t\t\t\t\t\t\t\t\t\tnew Vector2(x * 16 + xx * 8, y * 16 + yy * 8 - m));\n\n\t\t\t\t\t\t\t\t\tGraphics.Color.A = 255;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (t != Tile.Transition) {\n\t\t\t\t\tvar ar = tileset.WallAExtensions;\n\n\t\t\t\t\tswitch (t) {\n\t\t\t\t\t\tcase Tile.WallB: {\n\t\t\t\t\t\t\tar = tileset.WallBExtensions;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tcase Tile.Planks: {\n\t\t\t\t\t\t\tar = Tilesets.Biome.PlanksExtensions;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tcase Tile.GrannyWall: {\n\t\t\t\t\t\t\tar = Tilesets.Biome.GrannyExtensions;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tcase Tile.EvilWall: {\n\t\t\t\t\t\t\tar = Tilesets.Biome.EvilExtensions;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (!BitHelper.IsBitSet(v, 0)) {\n\t\t\t\t\t\tGraphics.Render(ar[0], new Vector2(x * 16, y * 16 - m - 8));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!BitHelper.IsBitSet(v, 1)) {\n\t\t\t\t\t\tGraphics.Render(ar[1], new Vector2(x * 16 + 16, y * 16 - m));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!BitHelper.IsBitSet(v, 2)) {\n\t\t\t\t\t\tGraphics.Render(ar[2], new Vector2(x * 16, y * 16 - m + 16));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!BitHelper.IsBitSet(v, 3)) {\n\t\t\t\t\t\tGraphics.Render(ar[3], new Vector2(x * 16 - 8, y * 16 - m));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void RenderWalls() {\n\t\t\tif (!LevelLayerDebug.Walls) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\t\t\tvar state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\tstate.End();\n\t\t\t\n\t\t\tvar effect = state.SurfaceEffect;\n\t\t\tstate.SurfaceEffect = null;\n\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(WallSurface);\n\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\tGraphics.Clear(Color.TransparentBlack);\n\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\n\t\t\tfor (int y = GetRenderTop(camera); y <= toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\n\t\t\t\t\tvar tile = Tiles[index];\n\t\t\t\t\tvar t = (Tile) tile;\n\n\t\t\t\t\tif (tile > 0 && t.Matches(TileFlags.WallLayer)) {\n\t\t\t\t\t\tRenderWall(x, y, index, tile, t, 8);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Batch.End();\n\t\t\tRenderBlood();\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, blend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t((Player) p).RenderOutline();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\t\n\t\t\tvar c = Camera.Instance;\n\t\t\tvar z = c.Zoom;\n\t\t\tvar n = Math.Abs(z - 1) > 0.01f;\n\t\t\t\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = 1;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None,\n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\tGraphics.Render(WallSurface, Camera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, \n\t\t\t\t                             Camera.Instance.Position.Y % 1));\n\t\t\t\n\t\t\tGraphics.Batch.End();\n\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = z;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\t\t\t\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(state.GameTarget);\n\t\t\tstate.SurfaceEffect = effect;\n\t\t\tstate.Begin();\n\t\t\t\n\t\t\tif (!RenderPassable) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar color = new Color(1f, 1f, 1f, 0.5f);\n\n\t\t\tfor (int y = GetRenderTop(camera); y <= toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tif (Passable[ToIndex(x, y)]) {\n\t\t\t\t\t\tGraphics.Batch.DrawRectangle(new RectangleF(x * 16 + 1, y * 16 + 1, 14, 14), color);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void RenderBlood() {\n\t\t\tif (!LevelLayerDebug.Blood) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (MessSurface == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\t\t\tvar state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, messBlend, SamplerState.PointClamp, DepthStencilState.None, \n\t\t\t\tstate.RasterizerState, null, Camera.Instance?.Matrix);\n\t\t\t\n\t\t\tvar region = new TextureRegion();\n\n\t\t\tregion.Texture = MessSurface;\n\t\t\tregion.Source.X = (int) Math.Floor(camera.X);\n\t\t\tregion.Source.Y = (int) Math.Floor(camera.Y) + 8;\n\t\t\tregion.Source.Width = Display.Width + 1;\n\t\t\tregion.Source.Height = Display.Height + 1;\n\t\t\t\n\t\t\tGraphics.Render(region, camera.TopLeft - new Vector2(camera.Position.X % 1, \n\t\t\t\t                        camera.Position.Y % 1));\n\t\t\t\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t\t\n\t\tpublic void RenderLight() {\n\t\t\tif (!DrawLight || !LevelLayerDebug.TileLight) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar camera = Camera.Instance;\n\n\t\t\t// Cache the condition\n\t\t\tvar toX = GetRenderRight(camera);\n\t\t\tvar toY = GetRenderBottom(camera);\n\n\t\t\tvar dt = Engine.Delta * 10f;\n\t\t\tvar region = Tileset.WallTopA;\n\t\t\t\n\t\t\tfor (int y = GetRenderTop(camera); y <= toY; y++) {\n\t\t\t\tfor (int x = GetRenderLeft(camera); x <= toX; x++) {\n\t\t\t\t\tvar index = ToIndex(x, y);\n\t\t\t\t\tvar light = Light[index];\n\n\t\t\t\t\tif (Explored[index] && light < LightMax) {\n\t\t\t\t\t\tLight[index] = light = Math.Min(1, light + dt);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (light < LightMax) {\n\t\t\t\t\t\tGraphics.Color.A = (byte) (255 - light * 255);\n\t\t\t\t\t\tGraphics.Render(region, new Vector2(x * 16, y * 16));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Tiles[index] == (byte) Tile.Crack) {\n\t\t\t\t\t\tGraphics.Color.A = 255;\n\t\t\t\t\t\tGraphics.Render(Tileset.WallCrackA, new Vector2(x * 16, y * 16 - 8));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color.A = 255;\n\t\t}\n\t\t\n\t\tprivate byte CalcWallIndex(int x, int y) {\n\t\t\t#if ART_DEBUG\n\t\t\t\treturn 0;\n\t\t\t#else\n\t\t\t\treturn (byte) (((int) Math.Round(x * 3.5f + y * 2.74f)) % 12);\n\t\t\t#endif\n\t\t}\n\n\t\tprivate byte CalcWallSide(int x, int y) {\n#if ART_DEBUG\n\t\t\t\treturn 0;\n#else\n\t\t\treturn (byte) (((int) Math.Round(x * 3.5f + y * 2.74f)) % 4);\n#endif\n\t\t}\n\n\t\tprivate byte CalcChasmIndex(int x, int y) {\n#if ART_DEBUG\n\t\t\t\treturn 0;\n#else\n\t\t\treturn (byte) (((int) Math.Round(x * 7.417f + y * 2.12f)) % 3);\n#endif\n\t\t}\n\t\t\n\t\tprivate byte CalcWallTopIndex(int x, int y) {\n#if ART_DEBUG\n\t\t\t\treturn 0;\n#else\n\t\t\treturn (byte) (((int) Math.Round(x * 16.217f + y * 8.12f)) % 3);\n#endif\n\t\t}\n\n\t\tpublic virtual Tile GetFilling() {\n\t\t\treturn Biome.GetFilling();\n\t\t}\n\n\t\tpublic virtual int GetPadding() {\n\t\t\treturn 1;\n\t\t}\n\n\t\tprivate void ResizeArray<T>(ref T[] array, int w, int h, int newSize, T val) {\n\t\t\tvar newArray = new T[newSize];\n\n\t\t\tfor (var y = 0; y < h; y++) {\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tnewArray[x + y * w] = x >= Width || y >= Height ? val : array[x + y * Width];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tarray = newArray;\n\t\t}\n\n\t\tpublic void Resize(int w, int h) {\n\t\t\tvar size = w * h;\n\t\t\t\n\t\t\tResizeArray(ref Tiles, w, h, size, (byte) Tile.FloorA);\n\t\t\tResizeArray(ref Liquid, w, h, size, (byte) 0);\n\t\t\tResizeArray(ref Variants, w, h, size, (byte) 0);\n\t\t\tResizeArray(ref LiquidVariants, w, h, size, (byte) 0);\n\t\t\tResizeArray(ref Flags, w, h, size, (byte) 0);\n\t\t\tResizeArray(ref Explored, w, h, size, false);\n\t\t\tResizeArray(ref Passable, w, h, size, false);\n\t\t\tResizeArray(ref MatrixLeak, w, h, size, false);\n\t\t\tResizeArray(ref Light, w, h, size, 0);\n\n\t\t\tWidth = w;\n\t\t\tHeight = h;\n\t\t\tSize = size;\n\t\t\tcleared = false;\n\t\t\t\n\t\t\tPathFinder.SetMapSize(Width, Height);\n\n\t\t\tRefreshSurfaces();\n\t\t}\n\n\t\tpublic void RefreshSurfaces() {\n\t\t\tWallSurface.Dispose();\n\t\t\tMessSurface.Dispose();\n\t\t\tcleared = false;\n\n\t\t\tWallSurface = new RenderTarget2D(Engine.GraphicsDevice, Display.Width + 1, Display.Height + 1);\n\n\t\t\tMessSurface = new RenderTarget2D(Engine.GraphicsDevice, Width * 16, Height * 16, false,\n\t\t\t\tEngine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents);\n\t\t}\n\n\t\tpublic virtual string GetMusic() {\n\t\t\treturn Biome.GetMusic();\n\t\t}\n\n\t\tpublic static string GetDepthString(bool eng = false) {\n\t\t\tif (Run.Depth < 1) {\n\t\t\t\treturn Locale.Get(Run.Level.Biome.Id, eng);\n\t\t\t}\n\n\t\t\tvar s = $\"{Locale.Get(Run.Level.Biome.Id, eng)} {MathUtils.ToRoman((Run.Depth - 1) % 2 + 1)}\";\n\n\t\t\tif (Run.Loop > 0) {\n\t\t\t\ts = $\"L{Run.Loop} {s}\";\n\t\t\t}\n\t\t\t\n\t\t\treturn s;\n\t\t}\n\t\t \n\t\tpublic void Break(float x, float y) {\n\t\t\tBSet((int) Math.Floor(x / 16), (int) Math.Floor(y / 16));\n\t\t\t\n\t\t\tBSet((int) Math.Floor(x / 16 - 0.5f), (int) Math.Floor(y / 16));\n\t\t\tBSet((int) Math.Floor(x / 16 + 0.5f), (int) Math.Floor(y / 16));\n\t\t\tBSet((int) Math.Floor(x / 16), (int) Math.Floor(y / 16 - 0.5f));\n\t\t\tBSet((int) Math.Floor(x / 16), (int) Math.Floor(y / 16 + 0.5f));\n\t\t}\n\n\t\tprivate void BSet(int tx, int ty) {\n\t\t\tif (!IsInside(tx, ty)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar index = ToIndex(tx, ty);\n\t\t\tvar tile = (Tile) Tiles[index];\n\n\t\t\tif (tile != Tile.Planks && (!(Biome is IceBiome) || tile != Tile.WallA)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tSet(index, Tile.FloorA);\n\n\t\t\tif (tile == Tile.Planks) {\n\t\t\t\tSet(index, Tile.Ember);\n\t\t\t}\n\n\t\t\tUpdateTile(tx, ty);\n\t\t\t\n\t\t\tReCreateBodyChunk(tx, ty);\n\t\t\tAnimate(Area, tx, ty);\n\t\t}\n\n\t\tpublic static void Animate(Area area, int x, int y) {\n\t\t\tif (!Camera.Instance.Overlaps(new Rectangle(x * 16, y * 16, 16, 16))) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tarea.Add(new TileFx {\n\t\t\t\tX = x * 16,\n\t\t\t\tY = y * 16 - 8\n\t\t\t});\n\t\t\t\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\tpart.Position = new Vector2(x * 16 + 8, y * 16 + 8);\n\t\t\t\tarea.Add(part);\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Plank());\n\t\t\t\t\t\t\n\t\t\t\tpart.Position = new Vector2(x * 16 + 8, y * 16);\n\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\n\t\t\t\tarea.Add(part);\n\t\t\t}\n\n\t\t\tEngine.Instance.Freeze = 0.5f;\n\t\t\tCamera.Instance.Shake(2);\n\t\t\t\n\t\t\tAudioEmitterComponent.Dummy(area, new Vector2(x, y) * 16).EmitRandomizedPrefixed(\"level_chair_break\", 2, 0.75f);\n\t\t}\n\n\t\tpublic void ReTileAndCreateBodyChunks(int x, int y, int w, int h) {\n\t\t\tUpdateTile(x, y);\n\t\t\tReCreateBodyChunk(x, y);\n\t\t\t\n\t\t\tfor (var yy = y - 1; yy < y + h + 1; yy++) {\n\t\t\t\tfor (var xx = x - 1; xx < x + w + 1; xx++) {\n\t\t\t\t\tif (yy != y || xx != x) {\n\t\t\t\t\t\tUpdateTile(xx, yy);\n\t\t\t\t\t\tReCreateBodyChunk(xx, yy);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tImGui.Text($\"Size: {width}x{height} = {Size} (real {width * height})\");\n\t\t\tImGui.Text($\"Variant: {Variant.GetType().Name}\");\n\t\t\tImGui.Text($\"Tiles: {Tiles.Length}\");\n\t\t\tImGui.Text($\"Liquid: {Liquid.Length}\");\n\t\t\tImGui.Text($\"Variants: {Variants.Length}\");\n\t\t\tImGui.Text($\"LiquidVariants: {LiquidVariants.Length}\");\n\t\t\tImGui.Text($\"WallDecor: {WallDecor.Length}\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/LevelBodyComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\nusing MathUtils = Lens.util.MathUtils;\n\nnamespace BurningKnight.level {\n\tpublic class LevelBodyComponent : BodyComponent {\n\t\tpublic const byte ChunkSize = 8;\n\n\t\tpublic Level Level;\n\t\t\n\t\tprivate bool dirty;\n\t\tprotected Body[] chunks;\n\t\tprotected int cw;\n\t\tprivate int ch;\n\t\tprivate int cs;\n\n\t\tprotected List<int> toUpdate = new List<int>();\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tEntity.AlwaysActive = true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (dirty) {\n\t\t\t\tdirty = false;\n\t\t\t\tCreate();\n\t\t\t\ttoUpdate.Clear();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (toUpdate.Count > 0) {\n\t\t\t\tvar level = Level;\n\t\t\t\tvar updated = new List<int>();\n\n\t\t\t\tforeach (var u in toUpdate) {\n\t\t\t\t\tvar cx = (int) Math.Floor(level.FromIndexX(u) / (float) ChunkSize);\n\t\t\t\t\tvar cy = (int) Math.Floor(level.FromIndexY(u) / (float) ChunkSize);\n\t\t\t\t\tvar ci = cx + cy * cw;\n\n\t\t\t\t\tif (updated.Contains(ci)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tupdated.Add(ci);\n\t\t\t\t\tPhysics.RemoveBody(chunks[ci]);\n\t\t\t\t\tRecreateChunk(cx, cy);\n\t\t\t\t}\n\n\t\t\t\ttoUpdate.Clear();\n\t\t\t}\n\t\t}\n\n\t\tpublic void CreateBody() {\n\t\t\tif (chunks == null) {\n\t\t\t\tCreate();\n\t\t\t} else {\n\t\t\t\tdirty = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tif (chunks != null) {\n\t\t\t\tforeach (var c in chunks) {\n\t\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t\t}\n\n\t\t\t\tchunks = null;\n\t\t\t}\n\n\t\t\tdirty = false;\n\t\t\ttoUpdate.Clear();\n\t\t}\n\n\t\tprivate void Create() {\n\t\t\tvar level = Level;\n\t\t\t\n\t\t\tcw = (int) Math.Floor(level.Width / (float) ChunkSize + 0.5f);\n\t\t\tch = (int) Math.Floor(level.Height / (float) ChunkSize + 0.5f);\n\t\t\tcs = cw * ch;\n\t\t\t\n\t\t\tif (chunks != null) {\n\t\t\t\tforeach (var c in chunks) {\n\t\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tchunks = new Body[cs];\n\t\t\t}\n\n\t\t\tfor (int cy = 0; cy < ch; cy++) {\n\t\t\t\tfor (int cx = 0; cx < cw; cx++) {\n\t\t\t\t\tRecreateChunk(cx, cy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void RecreateChunk(int cx, int cy) {\n\t\t\tvar level = Level;\n\t\t\t\n\t\t\tvar body = BodyFactory.CreateBody(Physics.World, Vector2.Zero);\n\t\t\tbody.FixedRotation = true;\n\t\t\tbody.UserData = this;\n\n\t\t\tvar i = cx + cy * cw;\n\t\t\tvar c = chunks[i];\n\n\t\t\tif (c != null) {\n\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t}\n\t\t\t\n\t\t\tchunks[i] = body;\n\n\t\t\tvar list = new List<Vector2>();\n\n\t\t\tfor (int y = cy * ChunkSize; y < (cy + 1) * ChunkSize; y++) {\n\t\t\t\tfor (int x = cx * ChunkSize; x < (cx + 1) * ChunkSize; x++) {\n\t\t\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tvar tile = level.Tiles[index];\n\t\t\t\t\tvar liquid = level.Liquid[index];\n\t\t\t\t\tvar side = x == 0 || y == 0 || x == level.Width - 1 || y == level.Height - 1;\n\n\t\t\t\t\tif (side || TileFlags.Matches(tile, TileFlags.Solid)/* || TileFlags.Matches(liquid, TileFlags.Solid)*/) {\n\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\tif (!side) {\n\t\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours8) {\n\t\t\t\t\t\t\t\tvar n = dir + index;\n\n\t\t\t\t\t\t\t\tif (level.IsInside(n) && TileFlags.Matches(level.Tiles[n], TileFlags.Solid)/* || TileFlags.Matches(level.Liquid[n], TileFlags.Solid))*/) {\n\t\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sum == 8) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar xx = (x) * 16;\n\t\t\t\t\t\tvar yy = (y) * 16 - 8;\n\n\t\t\t\t\t\tlist.Clear();\n\n\t\t\t\t\t\tif (side || Check(level, x - 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 6, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (side || Check(level, x + 1, y) || Check(level, x, y - 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + 12));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 10, yy + (Check(level, x, y - 1) ? 0 : 8)));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (side || Check(level, x + 1, y) || Check(level, x, y + 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + (Check(level, x, y + 1) ? 17 : 24)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 16, yy + 18));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 10, yy + 24));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (side || Check(level, x - 1, y) || Check(level, x, y + 1)) {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + (Check(level, x, y + 1) ? 17 : 24)));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx, yy + 18));\n\t\t\t\t\t\t\tlist.Add(new Vector2(xx + 6, yy + 24));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tFixtureFactory.AttachPolygon(new Vertices(list), 1f, body);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void ReCreateBodyChunk(int x, int y) {\n\t\t\t\n\t\t\tvar cx = (int) Math.Floor(x / (float) LevelBodyComponent.ChunkSize);\n\t\t\tvar cy = (int) Math.Floor(y / (float) LevelBodyComponent.ChunkSize);\n\t\t\tvar ci = cx + cy * cw;\n\n\t\t\tif (ci < 0 || (chunks != null && ci / LevelBodyComponent.ChunkSize >= chunks.Length)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\ttoUpdate.Add(x + y * Run.Level.Width);\n\t\t}\n\n\t\tprotected virtual bool Check(Level level, int x, int y) {\n\t\t\treturn level.IsInside(x, y) && (level.Get(x, y).Matches(TileFlags.Solid)/* || level.CheckFor(x, y, TileFlags.Solid, true)*/);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/LevelTiler.cs",
    "content": "using BurningKnight.level.tile;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level {\n\tpublic class LevelTiler {\n\t\tpublic static void TileUp(Level level, bool full = false) {\n\t\t\tfor (var i = 0; i < level.Variants.Length; i++) {\n\t\t\t\tlevel.Variants[i] = 0;\n\t\t\t\tlevel.LiquidVariants[i] = 0;\n\t\t\t}\n\n\t\t\tif (full) {\n\t\t\t\tfor (var i = 0; i < level.Variants.Length; i++) {\n\t\t\t\t\tlevel.Light[i] = 0;\n\t\t\t\t\tlevel.WallDecor[i] = 0;\n\t\t\t\t}\t\n\t\t\t\t\n\t\t\t\tlevel.CreatePassable();\n\t\t\t}\n\t\t\t\n\t\t\tfor (int y = 0; y < level.Height; y++) {\n\t\t\t\tfor (int x = 0; x < level.Width; x++) {\n\t\t\t\t\tTileUp(level, level.ToIndex(x, y));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void TileUp(Level level, int index) {\n\t\t\tif (index < 0 || index >= level.Size) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar liquid = level.Liquid[index];\n\t\t\tvar x = level.FromIndexX(index);\n\t\t\tvar y = level.FromIndexY(index);\n\t\t\t\n\t\t\tif (((Tile) liquid).Matches(Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\tlevel.LiquidVariants[index] = (byte) Rnd.Int(4);\n\t\t\t} else {\n\t\t\t\tbyte lmask = 0;\n\n\t\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\t\tvar m = PathFinder.Circle4[i];\n\t\t\t\t\tvar v = PathFinder.VCircle4[i];\n\t\t\t\t\tvar n = index + m;\n\n\t\t\t\t\tif (!level.IsInside(x + (int) v.X, y + (int) v.Y) ||\n\t\t\t\t\t    level.IsInside(n) && ShouldTile(liquid, level.Tiles[n], level.Liquid[n])) {\n\t\t\t\t\t\tlmask |= (byte) (1 << i);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlevel.LiquidVariants[index] = lmask;\n\t\t\t}\n\n\t\t\tbyte mask = 0;\n\t\t\tvar tile = level.Tiles[index];\n\t\t\tvar t = (Tile) tile;\n\n\t\t\tif (t == Tile.Transition) {\n\t\t\t\tforeach (var d in MathUtils.AllDirections) {\n\t\t\t\t\tvar xx = x + (int) d.X;\n\t\t\t\t\tvar yy = y + (int) d.Y;\n\n\t\t\t\t\tif (level.IsInside(xx, yy) && !level.Get(xx, yy).IsWall()) {\n\t\t\t\t\t\tt = Tile.WallA;\n\t\t\t\t\t\n\t\t\t\t\t\tlevel.Variants[index] = 0;\n\t\t\t\t\t\tlevel.Tiles[index] = tile = (byte) t;\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (t.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD, Tile.EvilFloor, Tile.GrannyFloor)) {\n\t\t\t\tif (level.Variants[index] != 0 && level.Variants[index] < 16) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar v = Rnd.Int(9);\n\n\t\t\t\tif (v == 8 || v == 9) {\n\t\t\t\t\tif (level.IsInside(index + level.Width + 1) && level.Tiles[index + 1] == tile && level.Tiles[index + level.Width] == tile && level.Tiles[index + 1 + level.Width] == tile \n\t\t\t\t\t    && level.Variants[index + 1] == 0 && level.Variants[index + level.Width] == 0 && level.Variants[index + 1 + level.Width] == 0) {\n\n\t\t\t\t\t\tvar st = v == 8 ? 8 : 10; \n\t\t\t\t\t\t\n\t\t\t\t\t\tlevel.Variants[index] = (byte) st;\n\t\t\t\t\t\tlevel.Variants[index + 1] = (byte) (st + 1);\n\t\t\t\t\t\tlevel.Variants[index + level.Width] = (byte) (st + 4);\n\t\t\t\t\t\tlevel.Variants[index + 1 + level.Width] = (byte) (st + 5);\n\t\t\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tv = Rnd.Int(8);\n\t\t\t\t}\n\n\t\t\t\tlevel.Variants[index] = (byte) v;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!(t.Matches(TileFlags.LiquidLayer) || t.Matches(TileFlags.Solid) || t == Tile.PistonDown)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\tvar m = PathFinder.Circle4[i];\n\t\t\t\tvar v = PathFinder.VCircle4[i];\n\t\t\t\tvar n = index + m;\n\t\t\t\t\n\t\t\t\tif (!level.IsInside(x + (int) v.X, y + (int) v.Y) || level.IsInside(n) && ShouldTile(tile, level.Tiles[n], level.Liquid[n])) {\n\t\t\t\t\tmask |= (byte) (1 << i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (t.IsWall() || t == Tile.PistonDown) {\n\t\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\t\tvar m = PathFinder.Corner[i];\n\t\t\t\t\tvar v = PathFinder.VCorner[i];\n\t\t\t\t\tvar n = index + m;\n\t\t\t\t\n\t\t\t\t\tif (!level.IsInside(x + (int) v.X, y + (int) v.Y) || level.IsInside(n) && ShouldTile(tile, level.Tiles[n], level.Liquid[n])) {\n\t\t\t\t\t\tmask |= (byte) (1 << (4 + i));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tlevel.Variants[index] = mask;\n\t\t}\n\n\t\tpublic static bool ShouldTile(byte tile, byte to, byte l) {\n\t\t\tvar t = (Tile) tile;\n\t\t\tvar tt = (Tile) to;\n\t\t\tvar ll = (Tile) l;\n\n\t\t\tif (t == Tile.Planks) {\n\t\t\t\treturn tt == Tile.Planks;\n\t\t\t}\n\n\t\t\tif (t == Tile.WallA || t == Tile.Piston || t == Tile.GrannyWall || t == Tile.EvilWall) {\n\t\t\t\treturn tt == Tile.WallA || tt == Tile.Planks || tt == Tile.Crack || tt == Tile.Piston || tt == Tile.Transition || tt == Tile.GrannyWall || tt == Tile.EvilWall;\n\t\t\t}\n\t\t\t\n\t\t\tif (t == Tile.WallB) {\n\t\t\t\t// || tt == Tile.Transition \n\t\t\t\treturn tt == Tile.WallB || tt == Tile.Planks || tt == Tile.Crack || tt == Tile.GrannyWall || tt == Tile.EvilWall;\n\t\t\t}\n\n\t\t\tif (t == Tile.Transition) {\n\t\t\t\treturn tt == Tile.Transition;\n\t\t\t}\n\n\t\t\tif (t == Tile.PistonDown) {\n\t\t\t\treturn tt == Tile.PistonDown;\n\t\t\t}\n\t\t\t\n\t\t\tif (t.IsWall() && t != Tile.Planks) {\n\t\t\t\treturn tt.IsWall();\n\t\t\t}\n\t\t\t\n\t\t\tif (t == Tile.Grass || t == Tile.HighGrass) {\n\t\t\t\treturn ll == Tile.Grass || ll == Tile.HighGrass || tt.IsWall();\n\t\t\t}\n\n\t\t\tif (t == Tile.Dirt) {\n\t\t\t\treturn tt.IsSimpleWall() || tt == Tile.Chasm || ll == Tile.Grass || ll == Tile.HighGrass || ll == Tile.Dirt;\n\t\t\t}\n\n\t\t\tif (t.Matches(TileFlags.LiquidLayer)) {\n\t\t\t\treturn tt.IsSimpleWall() || (t.Matches(Tile.Lava, Tile.Water, Tile.Venom) && tt == Tile.Chasm) || ll == t;\n\t\t\t}\n\t\t\t\n\t\t\treturn tile == to || tile == l;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/Painter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.prefabs;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.entities.plant;\nusing BurningKnight.level.paintings;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.secret;\nusing BurningKnight.level.rooms.treasure;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level {\n\tpublic class Painter {\n\t\tpublic static bool AllGold;\n\n\t\tpublic float Cobweb = 0.2f;\n\t\tpublic float Dirt = 0.4f;\n\t\tpublic float Grass = 0.4f;\n\t\tpublic float Water = 0.4f;\n\t\tpublic float Fireflies = 1f;\n\t\tpublic float FirefliesChance = 60f;\n\t\tpublic List<Action<Level, RoomDef>> RoomModifiers = new List<Action<Level, RoomDef>>();\n\t\tpublic List<Action<Level, RoomDef, int, int>> Modifiers = new List<Action<Level, RoomDef, int, int>>();\n\t\tpublic static Rect Clip;\n\t\tpublic Tile DirtTile = Tile.Dirt;\n\t\tpublic Action<List<MobInfo>> ModifyMobs;\n\n\t\tpublic Painter() {\n\t\t\tAllGold = false;\n\t\t\t\n\t\t\t// All the rocks, that have not full neighbours will become metal blocks (33% chance)\n\t\t\tRoomModifiers.Add((l, r) => {\n\t\t\t\tif (Rnd.Chance(66)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var y = r.Top; y <= r.Bottom; y++) {\n\t\t\t\t\tfor (var x = r.Left; x <= r.Right; x++) {\n\t\t\t\t\t\tvar index = l.ToIndex(x, y);\n\n\t\t\t\t\t\tif (l.Get(index, true) == Tile.Rock) {\n\t\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours8) {\n\t\t\t\t\t\t\t\tvar n = dir + index;\n\n\t\t\t\t\t\t\t\tif (l.IsInside(n) && (TileFlags.Matches(l.Tiles[n], TileFlags.Solid) ||\n\t\t\t\t\t\t\t\t                      TileFlags.Matches(l.Liquid[n], TileFlags.HalfWall))) {\n\t\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (sum > 0 && sum < 8) {\n\t\t\t\t\t\t\t\tl.Set(index, Tile.MetalBlock);\n\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\t// Small chance to replace rock with a tinted rock or with a barrel\n\t\t\tModifiers.Add((l, rm, x, y) => {\n\t\t\t\tvar index = l.ToIndex(x, y);\n\n\t\t\t\tif (l.Get(index, true) == Tile.Rock) {\n\t\t\t\t\tvar r = Rnd.Float();\n\n\t\t\t\t\tif (r <= 0.05f) {\n\t\t\t\t\t\tl.Set(index, Tile.TintedRock);\n\t\t\t\t\t} else if (Run.Depth > 0 && r <= 0.1f && !(rm is TreasureRoom)) {\n\t\t\t\t\t\tl.Set(index, Tile.BarrelTmp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t\n\t\tprivate void InspectRoom(RoomDef room) {\n\t\t\tforeach (var r in room.Connected.Keys) {\n\t\t\t\tif (r.Distance == -1) {\n\t\t\t\t\tr.Distance = room.Distance + 1;\n\t\t\t\t\tInspectRoom(r);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool Paint(Level Level, List<RoomDef> Rooms) {\n\t\t\tif (Rooms == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tLevel.Rains = Run.Depth > 0 && Rnd.Chance(15);\n\n\t\t\tif (Level.Biome.Id == Biome.Ice) {\n\t\t\t\tLevel.Snows = true;\n\t\t\t\tLevel.Rains = false;\n\t\t\t} else if (Level.Biome.Id == Biome.Castle) {\n\t\t\t\tLevel.Snows = Run.Depth > 0 && Rnd.Chance(10);\n\t\t\t} else if (Level.Biome.Id == Biome.Desert) {\n\t\t\t\tLevel.Rains = false;\n\t\t\t}\n\n\t\t\t// Level.Dark = Run.Depth > 1 && Rnd.Chance(5);\n\n\t\t\tif (Run.Depth == 5 && LevelSave.GenerateMarket && Run.Loop == 0) {\n\t\t\t\tLevel.Dark = true;\n\t\t\t}\n\t\t\t\n\t\t\tRoomDef current = null;\n\n\t\t\tforeach (var r in Rooms) {\n\t\t\t\tif (r is ExitRoom) {\n\t\t\t\t\tcurrent = r;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (current == null) {\n\t\t\t\tLog.Error(\"Failed to find the exit room\");\n\t\t\t} else {\n\t\t\t\tcurrent.Distance = 0;\n\t\t\t\tInspectRoom(current);\n\t\t\t}\n\n\t\t\tvar LeftMost = int.MaxValue;\n\t\t\tvar TopMost = int.MaxValue;\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tif (R.Left < LeftMost) {\n\t\t\t\t\tLeftMost = R.Left;\n\t\t\t\t}\n\n\t\t\t\tif (R.Top < TopMost) {\n\t\t\t\t\tTopMost = R.Top;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tLeftMost--;\n\t\t\tTopMost--;\n\t\t\tvar Sz = Level.GetPadding();\n\t\t\tLeftMost -= Sz;\n\t\t\tTopMost -= Sz;\n\t\t\tvar RightMost = 0;\n\t\t\tvar BottomMost = 0;\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tR.Shift(-LeftMost, -TopMost);\n\n\t\t\t\tif (R.Right > RightMost) {\n\t\t\t\t\tRightMost = R.Right;\n\t\t\t\t}\n\n\t\t\t\tif (R.Bottom > BottomMost) {\n\t\t\t\t\tBottomMost = R.Bottom;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tRightMost++;\n\t\t\tBottomMost++;\n\t\t\tRightMost += Sz;\n\t\t\tBottomMost += Sz;\n\t\t\t\n\t\t\tLog.Info($\"Setting level size to {(1 + RightMost)}:{(BottomMost + 1)}\");\n\t\t\t\n\t\t\tLevel.Width = RightMost + 1;\n\t\t\tLevel.Height = BottomMost + 1;\n\t\t\t\n\t\t\tLevel.Setup();\n\n\t\t\tvar tile = Level.GetFilling();\n\t\t\tvar liquid = tile.Matches(TileFlags.LiquidLayer);\n\n\t\t\tif (liquid) {\n\t\t\t\tvar t = (byte) Tile.FloorA;\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < Level.Size; i++) {\n\t\t\t\t\tLevel.Tiles[i] = t;\n\t\t\t\t\tLevel.Liquid[i] = (byte) tile;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (int i = 0; i < Level.Size; i++) {\n\t\t\t\t\tLevel.Tiles[i] = (byte) tile;\n\t\t\t\t}\t\n\t\t\t}\n\n\t\t\tif (Level.Biome is IceBiome || (Run.Depth > 0 && tile == Tile.Chasm)) {\n\t\t\t\tvar z = Level.Biome is IceBiome ? Tile.WallB : Tile.WallA;\n\t\t\t\t\n\t\t\t\tfor (var x = 0; x < Level.Width; x++) {\n\t\t\t\t\tfor (var y = 0; y < 5; y++) {\n\t\t\t\t\t\tif (y == 0 || Rnd.Chance((5 - y) * 20)) {\n\t\t\t\t\t\t\tSet(Level, x, y, z);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (var y = Level.Height - 6; y < Level.Height; y++) {\n\t\t\t\t\t\tif (y == Level.Height - 1 || Rnd.Chance((y - Level.Height + 5) * 20)) {\n\t\t\t\t\t\t\tSet(Level, x, y, z);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var y = 0; y < Level.Height; y++) {\n\t\t\t\t\tfor (var x = 0; x < 5; x++) {\n\t\t\t\t\t\tif (x == 0 || Rnd.Chance((5 - x) * 20)) {\n\t\t\t\t\t\t\tSet(Level, x, y, z);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (var x = Level.Width - 6; x < Level.Width; x++) {\n\t\t\t\t\t\tif (x == Level.Width - 1 || Rnd.Chance((x - Level.Width + 5) * 20)) {\n\t\t\t\t\t\t\tSet(Level, x, y, z);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar tr = Level.GetFilling();\n\t\t\tRoomDef exit = null;\n\t\t\tRoomDef entrance = null;\n\n\t\t\tfor (var i = Rooms.Count - 1; i >= 0; i--) {\n\t\t\t\tvar Room = Rooms[i];\n\t\t\t\tPlaceDoors(Room);\n\n\t\t\t\tif (Room is EntranceRoom) {\n\t\t\t\t\tentrance = Room;\n\t\t\t\t} else if (Room is ExitRoom) {\n\t\t\t\t\texit = Room;\n\t\t\t\t}\n\n\t\t\t\tforeach (var d in Room.Connected.Values) {\n\t\t\t\t\tif (d.Type != DoorPlaceholder.Variant.Empty && d.Type != DoorPlaceholder.Variant.Secret &&\n\t\t\t\t\t    d.Type != DoorPlaceholder.Variant.Maze) {\n\n\t\t\t\t\t\tif (d.X == Room.Left || d.X == Room.Right) {\n\t\t\t\t\t\t\tSet(Level, d.X, d.Y - 1, tr);\n\t\t\t\t\t\t\tSet(Level, d.X, d.Y + 1, tr);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSet(Level, d.X - 1, d.Y, tr);\n\t\t\t\t\t\t\tSet(Level, d.X + 1, d.Y, tr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Not checking lib cuz teleporters\n\t\t\tvar check = Run.Depth > 0 && !(LevelSave.BiomeGenerated is LibraryBiome);\n\n\t\t\tif (check && (exit == null || entrance == null)) {\n\t\t\t\tLog.Error(\"Exit or entrance not found, aborting\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar fl = Level.GetFilling() == Tile.WallB ? Tile.WallB : Tile.WallA;\n\n\t\t\tfor (var i = Rooms.Count - 1; i >= 0; i--) {\n\t\t\t\tvar Room = Rooms[i];\n\t\t\t\n\t\t\t\tif (!(Room is ConnectionRoom)) {\n\t\t\t\t\tRect(Level, Room, 0, LevelSave.BiomeGenerated is IceBiome ? Tile.WallB : fl);\n\t\t\t\t}\n\n\t\t\t\tClip = Room.Shrink();\n\n\t\t\t\tRoom.PaintFloor(Level);\n\t\t\t\tRoom.Paint(Level);\n\n\t\t\t\tif (Room is SecretRoom) {\n\t\t\t\t\tfor (var Y = Room.Top + 1; Y < Room.Bottom; Y++) {\n\t\t\t\t\t\tfor (var X = Room.Left + 1; X < Room.Right; X++) {\n\t\t\t\t\t\t\tif (Rnd.Chance(Run.Depth * 5)) {\n\t\t\t\t\t\t\t\tLevel.MatrixLeak[Level.ToIndex(X, Y)] = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!(Room is TreasureRoom)) {\n\t\t\t\t\tforeach (var d in Room.Connected.Values) {\n\t\t\t\t\t\tif (d.Type != DoorPlaceholder.Variant.Secret) {\n\t\t\t\t\t\t\tvar a = d.X == Room.Left || d.X == Room.Right;\n\t\t\t\t\t\t\tvar w = a ? 2 : 1;\n\t\t\t\t\t\t\tvar h = a ? 1 : 2;\n\t\t\t\t\t\t\tvar f = Tiles.RandomFloor();\n\n\t\t\t\t\t\t\tCall(Level, d.X - w, d.Y - h, w * 2 + 1, h * 2 + 1, (x, y) => {\n\t\t\t\t\t\t\t\tif (Level.Get(x, y).Matches(TileFlags.Danger)) {\n\t\t\t\t\t\t\t\t\tLevel.Set(x, y, f);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tClip = null;\n\t\t\t\t\n\t\t\t\tRoom.SetupDoors(Level);\n\n\t\t\t\tforeach (var m in RoomModifiers) {\n\t\t\t\t\tm(Level, Room);\n\t\t\t\t}\n\n\t\t\t\tfor (var Y = Room.Top; Y <= Room.Bottom; Y++) {\n\t\t\t\t\tfor (var X = Room.Left; X <= Room.Right; X++) {\n\t\t\t\t\t\tforeach (var m in Modifiers) {\n\t\t\t\t\t\t\tm(Level, Room, X, Y);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tReplaceTiles(Level, Room);\n\t\t\t}\n\n\t\t\tPathFinder.SetMapSize(Level.Width, Level.Height);\n\n\t\t\tif (Run.Depth > -1) {\n\t\t\t\tif (Dirt > 0) {\n\t\t\t\t\tPaintDirt(Level, Rooms);\n\t\t\t\t}\n\n\t\t\t\tif (Grass > 0) {\n\t\t\t\t\tPaintGrass(Level, Rooms);\n\t\t\t\t}\n\n\t\t\t\tif (Cobweb > 0) {\n\t\t\t\t\tPaintCobweb(Level, Rooms);\n\t\t\t\t}\n\n\t\t\t\tif (Water > 0) {\n\t\t\t\t\tPaintWater(Level, Rooms);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPaintDoors(Level, Rooms);\n\t\t\tDecorate(Level, Rooms);\n\n\t\t\tUpdateTransition(Level);\n\n\t\t\tif (check) {\n\t\t\t\tvar c = exit.GetCenter();\n\t\t\t\tLevel.CreatePassable(true);\n\t\t\t\tPathFinder.SetMapSize(Level.Width, Level.Height);\n\t\t\t\tvar i1 = Level.ToIndex(c.X, c.Y);\n\t\t\t\t\n\t\t\t\tPathFinder.BuildDistanceMap(i1, Level.Passable);\n\t\t\t\tc = entrance.GetCenter();\n\n\t\t\t\tvar i2 = Level.ToIndex(c.X, c.Y);\n\t\t\t\tif (PathFinder.Distance[i2] == Int32.MaxValue) {\n\t\t\t\t\tLog.Error(\"Generated unpassable level, aborting\");\n\t\t\t\t//\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar rooms = new List<RoomDef>();\n\n\t\t\tforeach (var rr in Rooms) {\n\t\t\t\tif (rr is RegularRoom || rr is EntranceRoom) {\n\t\t\t\t\trooms.Add(rr);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar rrms = new List<RoomDef>();\n\n\t\t\tforeach (var rm in rooms) {\n\t\t\t\tif (rm is RegularRoom) {\n\t\t\t\t\trrms.Add(rm);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (rrms.Count > 0) {\n\t\t\t\tforeach (var type in Level.ItemsToSpawn) {\n\t\t\t\t\tvar item = Items.CreateAndAdd(type, Level.Area);\n\n\t\t\t\t\tif (item == null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\titem.Center = (rrms[Rnd.Int(rrms.Count)].GetRandomFreeCell() * 16) + new Vector2(8, 8);\n\t\t\t\t}\n\n\t\t\t\tif (Run.Depth == 1) {\n\t\t\t\t\tvar crystal = new Crystal();\n\t\t\t\t\tcrystal.Center = (rrms[Rnd.Int(rrms.Count)].GetRandomFreeCell() * 16) + new Vector2(8, 8) + Rnd.Vector(-4, 4);\n\t\t\t\t\tLevel.Area.Add(crystal);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.Error(\"Failed to place items\");\n\t\t\t}\n\n\t\t\tLevel.ItemsToSpawn = null;\n\n\t\t\tvar rms = new List<Room>();\n\t\t\t\n\t\t\tforeach (var def in Rooms) {\n\t\t\t\tif (!def.ConvertToEntity()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar room = new Room();\n\n\t\t\t\troom.Type = RoomDef.DecideType(def, def.GetType());\n\t\t\t\troom.MapX = def.Left;\n\t\t\t\troom.MapY = def.Top;\n\t\t\t\troom.MapW = def.GetWidth();\n\t\t\t\troom.MapH = def.GetHeight();\n\t\t\t\troom.Parent = def;\n\t\t\t\t\n\t\t\t\tLevel.Area.Add(room);\n\t\t\t\trms.Add(room);\n\n\t\t\t\tdef.ModifyRoom(room);\n\n\t\t\t\troom.Generate();\n\t\t\t}\n\t\t\t\n\t\t\tPlaceMobs(Level, rms, ModifyMobs);\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic static void ReplaceTiles(Level Level, RoomDef Room) {\n\t\t\tfor (var Y = Room.Top; Y <= Room.Bottom; Y++) {\n\t\t\t\tfor (var X = Room.Left; X <= Room.Right; X++) {\n\t\t\t\t\tvar I = Level.ToIndex(X, Y);\n\n\t\t\t\t\tvar rs = !Level.Biome.HasSpikes();\n\n\t\t\t\t\tif (rs) {\n\t\t\t\t\t\tvar tl = (Tile) Level.Tiles[I];\n\n\t\t\t\t\t\tif (tl.Matches(Tile.SensingSpikeTmp, Tile.SpikeOnTmp, Tile.SpikeOffTmp, Tile.FireTrapTmp)) {\n\t\t\t\t\t\t\tLevel.Set(I, Tile.FloorA);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (Level.Tiles[I] == (byte) Tile.SensingSpikeTmp) {\n\t\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\n\t\t\t\t\t\t\tvar spikes = new SensingSpikes();\n\n\t\t\t\t\t\t\tspikes.X = X * 16;\n\t\t\t\t\t\t\tspikes.Y = Y * 16;\n\n\t\t\t\t\t\t\tLevel.Area.Add(spikes);\n\t\t\t\t\t\t} else if (Level.Tiles[I] == (byte) Tile.SpikeOffTmp) {\n\t\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\n\t\t\t\t\t\t\tvar spikes = new Spikes();\n\n\t\t\t\t\t\t\tspikes.X = X * 16;\n\t\t\t\t\t\t\tspikes.Y = Y * 16;\n\n\t\t\t\t\t\t\tLevel.Area.Add(spikes);\n\t\t\t\t\t\t} else if (Level.Tiles[I] == (byte) Tile.FireTrapTmp) {\n\t\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\n\t\t\t\t\t\t\tvar trap = new FireTrap();\n\n\t\t\t\t\t\t\ttrap.X = X * 16;\n\t\t\t\t\t\t\ttrap.Y = Y * 16;\n\n\t\t\t\t\t\t\tLevel.Area.Add(trap);\n\t\t\t\t\t\t} else if (Level.Tiles[I] == (byte) Tile.SpikeOnTmp) {\n\t\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\n\t\t\t\t\t\t\tvar spikes = new AlwaysOnSpikes();\n\n\t\t\t\t\t\t\tspikes.X = X * 16;\n\t\t\t\t\t\t\tspikes.Y = Y * 16;\n\n\t\t\t\t\t\t\tLevel.Area.Add(spikes);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tif (Level.Tiles[I] == (byte) Tile.Plate) {\n\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar plate = new PreasurePlate();\n\n\t\t\t\t\t\tplate.X = X * 16;\n\t\t\t\t\t\tplate.Y = Y * 16;\n\n\t\t\t\t\t\tLevel.Area.Add(plate);\n\t\t\t\t\t} else if (Level.Tiles[I] == (byte) Tile.BarrelTmp) {\n\t\t\t\t\t\tLevel.Tiles[I] = (byte) Tile.FloorA;\n\t\t\t\t\t\tLevel.Liquid[I] = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar barrel = new ExplodingBarrel();\n\t\t\t\t\t\tLevel.Area.Add(barrel);\n\n\t\t\t\t\t\tbarrel.CenterX = X * 16 + 8;\n\t\t\t\t\t\tbarrel.Bottom = Y * 16 + 16;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void UpdateTransition(Level Level) {\n\t\t\tfor (var y = 6; y < Level.Height - 5; y++) {\n\t\t\t\tfor (var x = 6; x < Level.Width - 5; x++) {\n\t\t\t\t\tif (Level.Get(x, y) == Tile.WallA) {\n\t\t\t\t\t\tvar a = (y == 0 || y == Level.Height - 1 || x == 0 || x == Level.Width - 1);\n\n\t\t\t\t\t\tif (!a) {\n\t\t\t\t\t\t\ta = true;\n\n\t\t\t\t\t\t\tforeach (var d in MathUtils.AllDirections) {\n\t\t\t\t\t\t\t\tif (!Level.Get(x + (int) d.X, y + (int) d.Y).Matches(Tile.WallA, Tile.Transition)) {\n\t\t\t\t\t\t\t\t\ta = false;\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (a) {\n\t\t\t\t\t\t\tLevel.Set(x, y, Tile.Transition);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PlaceMobs(Level level, Room room, Action<List<MobInfo>> modifier = null) {\n\t\t\tvar parent = room.Parent;\n\t\t\tvar w = parent.GetWidth() - 2;\n\t\t\tvar h = parent.GetHeight() - 2;\n\t\t\tvar mobs = new List<MobInfo>(MobRegistry.Current);\n\t\t\t\n\t\t\tparent.ModifyMobList(mobs);\n\n\t\t\tif (mobs.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar chances = new List<float>();\n\n\t\t\tfor (var i = 0; i < mobs.Count; i++) {\n\t\t\t\tchances.Add(parent.WeightMob(mobs[i], mobs[i].GetChanceFor(level.Biome.Id)));\n\t\t\t}\n\n\t\t\tvar types = new List<MobInfo>();\n\t\t\tvar spawnChances = new List<float>();\n\t\t\tvar curseOfBlood = Scourge.IsEnabled(Scourge.OfBlood);\n\n\t\t\tif (level.Biome.SpawnAllMobs()) {\n\t\t\t\ttypes.AddRange(mobs);\n\t\t\t\tspawnChances.AddRange(chances);\n\t\t\t} else {\n\t\t\t\tfor (int i = 0; i < Rnd.Int(2, 6) * (curseOfBlood ? 2 : 1); i++) {\n\t\t\t\t\tvar ind = Rnd.Chances(chances);\n\t\t\t\t\tvar type = mobs[ind];\n\n\t\t\t\t\tmobs.RemoveAt(ind);\n\t\t\t\t\tchances.RemoveAt(ind);\n\t\t\t\t\ttypes.Add(type);\n\t\t\t\t\tspawnChances.Add(type.Chance);\n\n\t\t\t\t\tif (mobs.Count == 0) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmodifier?.Invoke(types);\n\n\t\t\t// A hack to get around RaveCaveVariant having just crab in there\n\t\t\twhile (spawnChances.Count > types.Count) {\n\t\t\t\tspawnChances.RemoveAt(spawnChances.Count - 1);\n\t\t\t}\n\n\t\t\tif (types.Count == 0) {\n\t\t\t\tLog.Warning($\"No mobs detected to spawn in {level.Biome.Id} biome\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar points = new List<Dot>();\n\t\t\tvar wallFreePoints = new List<Dot>();\n\t\t\tvar wallPoints = new List<Dot>();\n\t\t\tvar size = w * h;\n\t\t\tvar patch = new bool[size];\n\n\t\t\tFunc<int, int, int> toIndex = (x, y) => (x - parent.Left - 1) + (y - parent.Top - 1) * w;\n\n\t\t\tfor (var y = parent.Top + 1; y < parent.Bottom; y++) {\n\t\t\t\tfor (var x = parent.Left + 1; x < parent.Right; x++) {\n\t\t\t\t\tpatch[toIndex(x, y)] = !Run.Level.IsPassable(x, y, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar hasDoors = parent.Connected.Count > 0;\n\t\t\tDot start = null;\n\t\t\t\n\t\t\tif (hasDoors) {\n\t\t\t\tPathFinder.SetMapSize(w, h);\n\n\t\t\t\tvar door = parent.Connected.Values.First();\n\t\t\t\tstart = new Dot(door.X, door.Y);\n\n\t\t\t\tif ((int) start.X == parent.Left) {\n\t\t\t\t\tstart.X++;\n\t\t\t\t} else if ((int) start.Y == parent.Top) {\n\t\t\t\t\tstart.Y++;\n\t\t\t\t} else if ((int) start.X == parent.Right) {\n\t\t\t\t\tstart.X--;\n\t\t\t\t} else if ((int) start.Y == parent.Bottom) {\n\t\t\t\t\tstart.Y--;\n\t\t\t\t}\n\n\t\t\t\tPathFinder.BuildDistanceMap(toIndex(start.X, start.Y), BArray.Not(patch, null));\n\t\t\t}\n\n\t\t\tfor (var y = parent.Top + 1; y < parent.Bottom; y++) {\n\t\t\t\tfor (var x = parent.Left + 1; x < parent.Right; x++) {\n\t\t\t\t\tif (hasDoors) {\n\t\t\t\t\t\tvar i = toIndex(x, y);\n\n\t\t\t\t\t\tif (patch[i] || PathFinder.Distance[i] == Int32.MaxValue) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar found = false;\n\n\t\t\t\t\t\tforeach (var dr in parent.Connected.Values) {\n\t\t\t\t\t\t\tvar dx = (int) (dr.X - x);\n\t\t\t\t\t\t\tvar dy = (int) (dr.Y - y);\n\t\t\t\t\t\t\tvar d = (float) Math.Sqrt(dx * dx + dy * dy);\n\n\t\t\t\t\t\t\tif (d < 4) {\n\t\t\t\t\t\t\t\tfound = true;\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (found) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (room.Type == RoomType.Boss) {\n\t\t\t\t\t\tvar c = parent.GetCenter();\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar dx = (int) (c.X - x);\n\t\t\t\t\t\tvar dy = (int) (c.Y - y);\n\t\t\t\t\t\tvar d = (float) Math.Sqrt(dx * dx + dy * dy);\n\n\t\t\t\t\t\tif (d < 3) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvar dt = new Dot(x, y);\n\n\t\t\t\t\tif ((Run.Level.IsPassable(x - 1, y) || Run.Level.IsPassable(x + 1, y)) && (Run.Level.IsPassable(x, y + 1) || Run.Level.IsPassable(x, y - 1))) {\n\t\t\t\t\t\tpoints.Add(dt);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (Run.Level.IsPassable(x - 1, y) && Run.Level.IsPassable(x + 1, y) && Run.Level.IsPassable(x, y + 1) && Run.Level.IsPassable(x, y - 1)) {\n\t\t\t\t\t\t\twallFreePoints.Add(dt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Run.Level.Get(x - 1, y).IsWall() || Run.Level.Get(x + 1, y).IsWall() || Run.Level.Get(x, y - 1).IsWall() || Run.Level.Get(x , y + 1).IsWall()) {\n\t\t\t\t\t\twallPoints.Add(dt);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (points.Count + wallPoints.Count == 0) {\n\t\t\t\tLog.Error(\"Did not find any placeable spots for mobs\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tPathFinder.SetMapSize(level.Width, level.Height);\n\n\t\t\tvar count = room.Parent.GetPassablePoints(level).Count;\n\t\t\tvar weight = (count / 19f + Rnd.Float(0f, 1f)) * room.Parent.GetWeightModifier() * (curseOfBlood ? 2 : 1);\n\n\t\t\tif (Run.Loop > 0) {\n\t\t\t\tweight *= Run.Loop * 1.5f + 1f;\n\t\t\t}\n\t\t\t\n\t\t\twhile (weight > 0 && (points.Count > 0 || wallPoints.Count > 0)) {\n\t\t\t\tvar id = Rnd.Chances(spawnChances);\n\n\t\t\t\tif (id == -1) {\n\t\t\t\t\tLog.Error(\"Failed to generate mobs :O\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar type = types[id];\n\t\t\t\tDot point = null;\n\n\t\t\t\tif (type.NearWall) {\n\t\t\t\t\tif (wallPoints.Count == 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = Rnd.Int(wallPoints.Count);\n\t\t\t\t\tpoint = wallPoints[index];\n\t\t\t\t\twallPoints.RemoveAt(index);\n\t\t\t\t} else if (type.AwayFromWall) {\n\t\t\t\t\tif (wallFreePoints.Count == 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = Rnd.Int(wallFreePoints.Count);\n\t\t\t\t\tpoint = wallFreePoints[index];\n\t\t\t\t\twallFreePoints.RemoveAt(index);\n\t\t\t\t} else {\n\t\t\t\t\tif (points.Count == 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = Rnd.Int(points.Count);\n\t\t\t\t\tpoint = points[index];\n\t\t\t\t\tpoints.RemoveAt(index);\n\t\t\t\t}\n\n\t\t\t\tif (point == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar mob = (Mob) Activator.CreateInstance(type.Type);\n\t\t\t\t\n\t\t\t\tweight -= type.Weight;\n\t\t\t\tlevel.Area.Add(mob);\n\t\t\t\t\n\t\t\t\tif (type.NearWall) {\n\t\t\t\t\tmob.Position = new Vector2(point.X * 16, point.Y * 16 - 8);\n\t\t\t\t} else {\n\t\t\t\t\tmob.BottomCenter = new Vector2(point.X * 16 + 8 + Rnd.Float(-2, 2), point.Y * 16 + 8 + Rnd.Float(-2, 2));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmob.GeneratePrefix();\n\n\t\t\t\tif (type.Single) {\n\t\t\t\t\ttypes.RemoveAt(id);\n\t\t\t\t\tspawnChances.RemoveAt(id);\n\n\t\t\t\t\tif (types.Count == 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void PlaceMobs(Level level, List<Room> rooms, Action<List<MobInfo>> modifier = null) {\n\t\t\tMobRegistry.SetupForBiome(level.Biome.Id);\n\t\t\t// level.CreatePassable(true);\n\t\t\t\n\t\t\tforeach (var room in rooms) {\n\t\t\t\tif (room.Parent.ShouldSpawnMobs()) {\n\t\t\t\t\tPlaceMobs(level, room, modifier);\n\t\t\t\t}\n\t\t\t}\t\n\t\t}\n\t\t\n\t\tprivate void PlaceDoors(RoomDef R) {\n\t\t\tvar connected = new Dictionary<RoomDef, DoorPlaceholder>();\n\n\t\t\tforeach (var pair in R.Connected) {\n\t\t\t\tconnected[pair.Key] = pair.Value;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var N in connected.Keys) {\n\t\t\t\tvar Door = connected[N];\n\n\t\t\t\tif (Door == null) {\n\t\t\t\t\tvar I = R.Intersect(N);\n\t\t\t\t\tvar DoorSpots = new List<Dot>();\n\n\t\t\t\t\tforeach (var P in I.GetPoints()) {\n\t\t\t\t\t\tif (R.CanConnect(N, P) && N.CanConnect(R, P)) {\n\t\t\t\t\t\t\tDoorSpots.Add(P);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (DoorSpots.Count > 0) {\n\t\t\t\t\t\tDoor = new DoorPlaceholder(DoorSpots[Rnd.Int(DoorSpots.Count)]);\n\t\t\t\t\t\tR.Connected[N] = Door;\n\t\t\t\t\t\tN.Connected[R] = Door;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tR.Connected.Remove(N);\n\t\t\t\t\t\tN.Connected.Remove(R);\n\n\t\t\t\t\t\tthrow new Exception($\"Failed to connect rooms {R.GetType().Name} and {N.GetType().Name}\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PaintWater(Level Level, List<RoomDef> Rooms) {\n\t\t\tvar Lake = Patch.Noise(Water);\n\t\t\tvar Ice = Level.Biome is IceBiome;\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tif (R is IceConnectionRoom) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar placed = false;\n\t\t\t\t\n\t\t\t\tforeach (var P in R.GetWaterPlaceablePoints()) {\n\t\t\t\t\tvar I = Level.ToIndex((int) P.X, (int) P.Y);\n\t\t\t\t\tvar T = (Tile) Level.Tiles[I];\n\n\t\t\t\t\tif (Lake[I] && T.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD) && Level.Liquid[I] == 0) {\n\t\t\t\t\t\tLevel.Set(I, Ice ? Tile.Ice : Tile.Water);\n\t\t\t\t\t\tplaced = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!placed) {\n\t\t\t\t\tvar v = R.GetRandomFreeCell();\n\n\t\t\t\t\tif (v != null) {\n\t\t\t\t\t\tSetBold(Level, v.X, v.Y, Ice ? Tile.Ice : Tile.Water);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PaintCobweb(Level Level, List<RoomDef> Rooms) {\n\t\t\tvar Lake = Patch.Noise(Cobweb);\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tforeach (var P in R.GetWaterPlaceablePoints()) {\n\t\t\t\t\tvar I = Level.ToIndex((int) P.X, (int) P.Y);\n\t\t\t\t\tvar T = (Tile) Level.Tiles[I];\n\t\t\t\t\t\n\t\t\t\t\tif (Lake[I] && T.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC) && Level.Liquid[I] == 0) {\n\t\t\t\t\t\tLevel.Set(I, Tile.Cobweb);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PaintDirt(Level Level, List<RoomDef> Rooms) {\n\t\t\tvar Grass = Patch.Noise(Dirt);\n\t\t\tvar tile = Level.Biome is DesertBiome ? Tile.Sand : DirtTile;\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tforeach (var P in R.GetGrassPlaceablePoints()) {\n\t\t\t\t\tif (!Level.IsInside(P.X, P.Y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar I = Level.ToIndex((int) P.X, (int) P.Y);\n\n\t\t\t\t\t\n\t\t\t\t\tvar T = (Tile) Level.Tiles[I];\n\t\t\t\t\t\n\t\t\t\t\tif (Grass[I] && T.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC) && Level.Liquid[I] == 0) {\n\t\t\t\t\t\tLevel.Set(I, tile);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PaintGrass(Level Level, List<RoomDef> Rooms) {\n\t\t\tvar Grass = Patch.Noise(this.Grass);\n\t\t\tvar Cells = new List<int>();\n\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tforeach (var P in R.GetGrassPlaceablePoints()) {\n\t\t\t\t\tvar I = Level.ToIndex((int) P.X, (int) P.Y);\n\t\t\t\t\tvar T = (Tile) Level.Tiles[I];\n\t\t\t\t\t\n\t\t\t\t\tif (Grass[I] && T.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC) && Level.Liquid[I] == 0) {\n\t\t\t\t\t\tCells.Add(I);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var I in Cells) {\n\t\t\t\tvar Count = 1;\n\n\t\t\t\tforeach (var N in PathFinder.Neighbours8) {\n\t\t\t\t\tvar K = I + N;\n\n\t\t\t\t\tif (Level.IsInside(K) && Grass[K]) {\n\t\t\t\t\t\tCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tLevel.Set(I, Tile.Grass);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PlaceTrees(Level Level, RoomDef Room) {\n\t\t\tfor (var Y = Room.Top - 1; Y < Room.Bottom - 1; Y++) {\n\t\t\t\tfor (var X = Room.Left - 1; X < Room.Right - 1; X++) {\n\t\t\t\t\tif (Level.Get(X, Y).IsWall() && Level.Get(X, Y - 1).IsWall() &&\n\t\t\t\t\t    Level.Get(X - 1, Y).IsWall() && Level.Get(X + 1, Y).IsWall()\n\t\t\t\t\t    && !Room.HasDoorsNear(X, Y, 3)\n\t\t\t\t\t    && Rnd.Chance(10)) {\n\n\t\t\t\t\t\tX += 2;\n\t\t\t\t\t\tvar plant = new Tree {\n\t\t\t\t\t\t\tHigh = true\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tLevel.Area.Add(plant);\n\n\t\t\t\t\t\tplant.BottomCenter = new Vector2(X * 16 + 8 + Rnd.Float(-4, 4), Y * 16 + 8 + Rnd.Float(-4, 4));\n\t\t\t\t\t} else if (Level.Get(X, Y).IsPassable() && Level.Get(X, Y - 1).IsPassable() &&\n\t\t\t\t\t           Level.Get(X - 1, Y).IsPassable() && Level.Get(X - 1, Y - 1).IsPassable() &&\n\t\t\t\t\t           Level.Get(X + 1, Y).IsPassable() && Level.Get(X + 1, Y - 1).IsPassable() &&\n\t\t\t\t\t           Level.Get(X - 1, Y - 2).IsPassable() && Level.Get(X + 1, Y - 2).IsPassable()\n\t\t\t\t\t           && !Room.HasDoorsNear(X, Y, 3)\n\t\t\t\t\t           && Rnd.Chance(6)) {\n\n\t\t\t\t\t\tX += 3;\n\t\t\t\t\t\tvar plant = new Tree();\n\t\t\t\t\t\tLevel.Area.Add(plant);\n\n\t\t\t\t\t\tplant.BottomCenter = new Vector2(X * 16 + 8 + Rnd.Float(-4, 4), Y * 16 + 8 + Rnd.Float(-4, 4));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PlacePlants(Level Level, RoomDef Room) {\n\t\t\tfor (var Y = Room.Top; Y <= Room.Bottom; Y++) {\n\t\t\t\tfor (int X = Room.Left; X <= Room.Right; X++) {\n\t\t\t\t\tif ((Level.Get(X, Y, true).Matches(Tile.Grass, Tile.Dirt) && Rnd.Chance(20)) || (Level.Get(X, Y).Matches(TileFlags.Passable) && Rnd.Chance(5))) {\n\t\t\t\t\t\tvar plant = new Plant();\n\t\t\t\t\t\tLevel.Area.Add(plant);\n\n\t\t\t\t\t\tplant.BottomCenter = new Vector2(X * 16 + 8 + Rnd.Float(-4, 4), Y * 16 + 8 + Rnd.Float(-4, 4));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected void Decorate(Level Level, List<RoomDef> Rooms) {\n\t\t\tforeach (var Room in Rooms) {\n\t\t\t\t// Tnt\n\n\t\t\t\tif (Level.Biome.HasTnt()) {\n\t\t\t\t\tif ((Room is RegularRoom) && Rnd.Chance(20)) {\n\t\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 4); i++) {\n\t\t\t\t\t\t\tvar p = Room.GetRandomDoorFreeCell();\n\n\t\t\t\t\t\t\tif (p != null) {\n\t\t\t\t\t\t\t\tvar barrel = new ExplodingBarrel();\n\t\t\t\t\t\t\t\tLevel.Area.Add(barrel);\n\t\t\t\t\t\t\t\tbarrel.Center = p * 16 + new Vector2(8);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Plants\n\t\t\t\tif (Level.Biome.HasPlants()) {\n\t\t\t\t\tPlacePlants(Level, Room);\n\t\t\t\t}\n\n\t\t\t\tif (Events.Halloween) {\n\t\t\t\t\tfor (var Y = Room.Top; Y <= Room.Bottom; Y++) {\n\t\t\t\t\t\tfor (int X = Room.Left; X <= Room.Right; X++) {\n\t\t\t\t\t\t\tif ((Level.Get(X, Y, true).Matches(Tile.Grass, Tile.Dirt) && Rnd.Chance(20)) || (Level.Get(X, Y).Matches(TileFlags.Passable) && Rnd.Chance(0.5f))) {\n\t\t\t\t\t\t\t\tvar plant = new Plant();\n\t\t\t\t\t\t\t\tLevel.Area.Add(plant);\n\t\t\t\t\t\t\t\tplant.Variant = 255;\n\t\t\t\t\t\t\t\tplant.BottomCenter = new Vector2(X * 16 + 8 + Rnd.Float(-4, 4), Y * 16 + 8 + Rnd.Float(-4, 4));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!(Room is HiveRoom) && Level.Biome.HasTrees()) {\n\t\t\t\t\tPlaceTrees(Level, Room);\n\t\t\t\t}\n\n\t\t\t\t// Fireflies\n\t\t\t\tif (Level.Dark || Rnd.Chance(FirefliesChance)) {\n\t\t\t\t\tfor (var I = 0; I < (!Level.Dark && Rnd.Chance() ? 1 : Rnd.Int(3, 6)) * Fireflies; I++) {\n\t\t\t\t\t\tLevel.Area.Add(new Firefly {\n\t\t\t\t\t\t\tX = (Room.Left + 2) * 16 + Rnd.Float((Room.GetWidth() - 4) * 16),\n\t\t\t\t\t\t\tY = (Room.Top + 2) * 16 + Rnd.Float((Room.GetHeight() - 4) * 16)\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Cobweb\n\t\t\t\tif (!(Room is BossRoom) && Level.Biome.HasCobwebs()) {\n\t\t\t\t\tfor (var Y = Room.Top; Y <= Room.Bottom; Y++) {\n\t\t\t\t\t\tfor (int X = Room.Left; X <= Room.Right; X++) {\n\t\t\t\t\t\t\tif (Level.Get(X, Y).IsSimpleWall()) {\n\t\t\t\t\t\t\t\tif (Y > Room.Top && X > Room.Left && Level.Get(X - 1, Y - 1).IsSimpleWall() && !Level.Get(X, Y - 1).IsSimpleWall() && Rnd.Chance(20)) {\n\t\t\t\t\t\t\t\t\tLevel.Area.Add(new SlicedProp(\"cobweb_c\", Layers.WallDecor) {\n\t\t\t\t\t\t\t\t\t\tX = X * 16,\n\t\t\t\t\t\t\t\t\t\tY = Y * 16 - 24\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else if (Y > Room.Top && X < Room.Right && Level.Get(X + 1, Y - 1).IsSimpleWall() && !Level.Get(X, Y - 1).IsSimpleWall() && Rnd.Chance(20)) {\n\t\t\t\t\t\t\t\t\tLevel.Area.Add(new SlicedProp(\"cobweb_d\", Layers.WallDecor) {\n\t\t\t\t\t\t\t\t\t\tX = X * 16,\n\t\t\t\t\t\t\t\t\t\tY = Y * 16 - 24\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else if (Y < Room.Bottom - 1 && X > Room.Left && Level.Get(X - 1, Y + 1).IsSimpleWall() && !Level.Get(X, Y + 1).IsSimpleWall() && Rnd.Chance(20)) {\n\t\t\t\t\t\t\t\t\tLevel.Area.Add(new SlicedProp(\"cobweb_a\", Layers.WallDecor) {\n\t\t\t\t\t\t\t\t\t\tX = X * 16,\n\t\t\t\t\t\t\t\t\t\tY = Y * 16 + 8\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else if (Y < Room.Bottom - 1 && X < Room.Right && Level.Get(X + 1, Y + 1).IsSimpleWall() && !Level.Get(X, Y + 1).IsSimpleWall() && Rnd.Chance(20)) {\n\t\t\t\t\t\t\t\t\tLevel.Area.Add(new SlicedProp(\"cobweb_b\", Layers.WallDecor) {\n\t\t\t\t\t\t\t\t\t\tX = X * 16,\n\t\t\t\t\t\t\t\t\t\tY = Y * 16 + 8\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t\n\t\t\t\tif (!(Room is SecretRoom || Room is TreasureRoom || Room is RegularRoom || Room is EntranceRoom || Room is ConnectionRoom) || Run.Depth < 1) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Paintings && Torches\n\t\t\t\tvar ht = Level.Biome.HasTorches();\n\t\t\t\tvar hp = Level.Biome.HasPaintings();\n\t\t\t\t\n\t\t\t\tif (ht || hp) {\n\t\t\t\t\tfor (int X = Room.Left + 1; X < Room.Right; X++) {\n\t\t\t\t\t\tvar s = Room is SecretRoom;\n\t\t\t\t\t\tvar t = Level.Get(X, Room.Top);\n\n\t\t\t\t\t\tif (t != Tile.Crack && t.IsWall() && !Level.Get(X, Room.Top + 1).IsWall() && Rnd.Chance(s ? 50 : 30)) {\n\t\t\t\t\t\t\tif (!s && Rnd.Chance()) {\n\t\t\t\t\t\t\t\tif (ht) {\n\t\t\t\t\t\t\t\t\tvar torch = new WallTorch();\n\t\t\t\t\t\t\t\t\tLevel.Area.Add(torch);\n\t\t\t\t\t\t\t\t\ttorch.CenterX = X * 16 + 8 + Rnd.Float(-1, 1);\n\t\t\t\t\t\t\t\t\ttorch.CenterY = Room.Top * 16 + 13;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (hp) {\n\t\t\t\t\t\t\t\tvar painting = PaintingRegistry.Generate(Level.Biome);\n\t\t\t\t\t\t\t\tLevel.Area.Add(painting);\n\n\t\t\t\t\t\t\t\tpainting.CenterX = X * 16 + 8 + Rnd.Float(-1, 1);\n\t\t\t\t\t\t\t\tpainting.Bottom = Room.Top * 16 + 17;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!Level.Biome.HasBrekables() || Room is SecretRoom || Room is TreasureRoom || Room is ConnectionRoom || Room is EntranceRoom) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar types = new List<string>();\n\t\t\t\tvar infos = Level.Biome is IceBiome ? BreakableProp.IceInfos : BreakableProp.Infos;\n\n\t\t\t\tfor (var i = 0; i < Rnd.Int(2, 3); i++) {\n\t\t\t\t\ttypes.Add(infos[Rnd.Int(infos.Length)]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < Rnd.IntCentred(2, 7); i++) {\n\t\t\t\t\tvar prop = new BreakableProp {\n\t\t\t\t\t\tSprite = types[Rnd.Int(types.Count)]\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tvar point = Room.GetRandomDoorFreeCell();\n\n\t\t\t\t\tif (point == null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tLevel.Area.Add(prop);\n\t\t\t\t\tprop.Center = new Vector2(point.X * 16 + 8 + Rnd.Float(-3, 3), point.Y * 16 + 8 + Rnd.Float(-3, 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PaintDoor(Level Level, RoomDef R) {\n\t\t\tforeach (var N in R.Connected.Keys) {\n\t\t\t\tvar D = R.Connected[N];\n\t\t\t\tPlaceDoor(Level, R, D, N);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PlaceDoor(Level Level, RoomDef R, DoorPlaceholder D, RoomDef from) {\n\t\t\tvar T = Level.Get(D.X, D.Y);\n\t\t\tvar type = D.Type;\n\n\t\t\tvar gt = type != DoorPlaceholder.Variant.Empty && type != DoorPlaceholder.Variant.Maze && type != DoorPlaceholder.Variant.Secret;\n\t\t\tvar vertical = Level.Get(D.X, D.Y + 1).IsWall() && Level.Get(D.X, D.Y - 1).IsWall();\n\t\t\t\n\t\t\tif (gt && !T.Matches(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD, Tile.Crack)) {\n\t\t\t\tDoor door = null;\n\n\t\t\t\tswitch (type) {\n\t\t\t\t\tcase DoorPlaceholder.Variant.Locked: \n\t\t\t\t\t\tdoor = new SpecialDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Red: \n\t\t\t\t\t\tdoor = new RedDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Boss: \n\t\t\t\t\t\tdoor = new BossDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Treasure:\n\t\t\t\t\t\tdoor = new TreasureDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Scourged:\n\t\t\t\t\t\tdoor = new ScourgedDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Payed:\n\t\t\t\t\t\tdoor = new PayedDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Head:\n\t\t\t\t\t\t// door = new HeadDoor();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Spiked:\n\t\t\t\t\t\tdoor = new SpikedDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Challenge:\n\t\t\t\t\t\tdoor = new ChallengeDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcase DoorPlaceholder.Variant.Shop:\n\t\t\t\t\t\tdoor = new ShopDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t\tdefault: \n\t\t\t\t\t\tdoor = new LockableDoor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdoor.Vertical = vertical;\n\t\t\t\tLevel.Area.Add(door);\n\n\t\t\t\tvar offset = door.GetOffset();\n\n\t\t\t\tdoor.CenterX = D.X * 16 + 8 + offset.X;\n\t\t\t\tdoor.Bottom = D.Y * 16 + 17.01f + offset.Y - (door is CustomDoor ? (door.Vertical ? 0 : 8) : 0); // .1f so that it's depth sorted to the front of the wall\n\n\t\t\t\tif (!(door is HeadDoor)) {\n\t\t\t\t\tif (door.Vertical) {\n\t\t\t\t\t\tif (type != DoorPlaceholder.Variant.Hidden) {\n\t\t\t\t\t\t\tif (!Level.Get(D.X + 1, D.Y).Matches(TileFlags.Passable)) {\n\t\t\t\t\t\t\t\tLevel.Set(D.X + 1, D.Y, Tiles.RandomFloor());\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!Level.Get(D.X - 1, D.Y).Matches(TileFlags.Passable)) {\n\t\t\t\t\t\t\t\tLevel.Set(D.X - 1, D.Y, Tiles.RandomFloor());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (type != DoorPlaceholder.Variant.Hidden) {\n\t\t\t\t\t\t\tif (!Level.Get(D.X, D.Y + 1).Matches(TileFlags.Passable)) {\n\t\t\t\t\t\t\t\tLevel.Set(D.X, D.Y + 1, Tiles.RandomFloor());\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!Level.Get(D.X, D.Y - 1).Matches(TileFlags.Passable)) {\n\t\t\t\t\t\t\t\tLevel.Set(D.X, D.Y - 1, Tiles.RandomFloor());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tLevel.Set(D.X, D.Y, Tiles.RandomFloor());\n\t\t\t\t}\n\t\t\t} else if (type == DoorPlaceholder.Variant.Hidden) {\n\t\t\t\tLevel.Set(D.X, D.Y, Level.Biome is IceBiome ? Tile.WallB : Tile.WallA);\n\t\t\t} else if (type == DoorPlaceholder.Variant.Secret) {\n\t\t\t\tLevel.Set(D.X, D.Y, Tile.Crack);\n\t\t\t\t\n\t\t\t\tif (vertical) {\n\t\t\t\t\tif (Level.Get(D.X + 1, D.Y).Matches(Tile.WallA, Tile.WallB, Tile.Planks, Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\t\t\tLevel.Set(D.X + 1, D.Y, Tiles.RandomFloor());\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!Level.Get(D.X - 1, D.Y).Matches(Tile.WallA, Tile.WallB, Tile.Planks, Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\t\t\tLevel.Set(D.X - 1, D.Y, Tiles.RandomFloor());\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!Level.Get(D.X, D.Y + 1).Matches(Tile.WallA, Tile.WallB, Tile.Planks, Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\t\t\tLevel.Set(D.X, D.Y + 1, Tiles.RandomFloor());\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!Level.Get(D.X, D.Y - 1).Matches(Tile.WallA, Tile.WallB, Tile.Planks, Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\t\t\tLevel.Set(D.X, D.Y - 1, Tiles.RandomFloor());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (type == DoorPlaceholder.Variant.Empty) { \n\t\t\t\tLevel.Set(D.X, D.Y, Tiles.RandomFloor());\n\t\t\t}\n\t\t}\n\n\t\tprivate void PaintDoors(Level Level, List<RoomDef> Rooms) {\n\t\t\tforeach (var R in Rooms) {\n\t\t\t\tPaintDoor(Level, R);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Set(Level Level, int cell, Tile Value) {\n\t\t\tif (Clip != null && !Clip.Contains(Level.FromIndexX(cell), Level.FromIndexY(cell))) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLevel.Set(cell, Value);\n\t\t}\n\n\t\tpublic static void Set(Level Level, int X, int Y, Tile Value, bool bold = false, bool walls = false) {\n\t\t\tif (bold) {\n\t\t\t\tSetBold(Level, X, Y, Value, walls);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tSet(Level, Level.ToIndex(X, Y), Value);\n\t\t}\n\n\t\tpublic static void SetBold(Level Level, int X, int Y, Tile Value, bool walls = false) {\n\t\t\tfor (var Yy = Y - 1; Yy < Y + 2; Yy++) {\n\t\t\t\tfor (var Xx = X - 1; Xx < X + 2; Xx++) {\n\t\t\t\t\tif (!Level.IsInside(Xx, Yy)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (Xx != X || Yy != Y) {\n\t\t\t\t\t\tif (!walls && Level.Get(Xx, Yy).IsWall()) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tSet(Level, Xx, Yy, Value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Set(Level Level, Dot P, Tile Value) {\n\t\t\tSet(Level, (int) P.X, (int) P.Y, Value);\n\t\t}\n\t\t\n\t\tpublic static void Call(Level Level, int X, int Y, int W, int H, Action<int, int> callback) {\n\t\t\tfor (var Yy = Y; Yy < Y + H; Yy++) {\n\t\t\t\tfor (var Xx = X; Xx < X + W; Xx++) {\n\t\t\t\t\tcallback(Xx, Yy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Call(Level level, Rect rect, int m, Action<int, int> callback) {\n\t\t\trect = rect.Shrink(m);\n\t\t\tCall(level, rect.Left, rect.Top, rect.GetWidth(), rect.GetHeight(), callback);\n\t\t}\n\n\t\tpublic static void Fill(Level Level, int X, int Y, int W, int H, Tile Value) {\n\t\t\tfor (var Yy = Y; Yy < Y + H; Yy++) {\n\t\t\t\tfor (var Xx = X; Xx < X + W; Xx++) {\n\t\t\t\t\tSet(Level, Xx, Yy, Value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Rect(Level level, Rect rect, int m, Tile value, bool bold = false) {\n\t\t\trect = rect.Shrink(m);\n\t\t\tRect(level, rect.Left, rect.Top, rect.GetWidth(), rect.GetHeight(), value, bold);\n\t\t}\n\n\t\tpublic static void Rect(Level level, int X, int Y, int W, int H, Tile value, bool bold = false) {\n\t\t\tDrawLine(level, new Dot(X, Y), new Dot(X + W, Y), value, bold);\n\t\t\tDrawLine(level, new Dot(X, Y + H), new Dot(X + W, Y + H), value, bold);\n\t\t\tDrawLine(level, new Dot(X, Y), new Dot(X, Y + H), value, bold);\n\t\t\tDrawLine(level, new Dot(X + W, Y), new Dot(X + W, Y + H), value, bold);\n\t\t}\n\n\t\tpublic static void Triangle(Level Level, Dot From, Dot P1, Dot P2, Tile V) {\n\t\t\tif ((int) P1.X != (int) P2.X) {\n\t\t\t\tfor (var X = P1.X; X < P2.X; X++) {\n\t\t\t\t\tDrawLine(Level, From, new Dot(X, P1.Y), V);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (var Y = P1.Y; Y < P2.Y; Y++) {\n\t\t\t\t\tDrawLine(Level, From, new Dot(P1.X, Y), V);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Fill(Level Level, Rect Rect, Tile Value) {\n\t\t\tFill(Level, Rect.Left, Rect.Top, Rect.GetWidth(), Rect.GetHeight(), Value);\n\t\t}\n\n\t\tpublic static void Fill(Level Level, Rect Rect, int M, Tile Value) {\n\t\t\tFill(Level, Rect.Left + M, Rect.Top + M, Rect.GetWidth() - M * 2, Rect.GetHeight() - M * 2, Value);\n\t\t}\n\n\t\tpublic static void Fill(Level Level, Rect Rect, int L, int T, int R, int B, Tile Value) {\n\t\t\tFill(Level, Rect.Left + L, Rect.Top + T, Rect.GetWidth() - (L + R), Rect.GetHeight() - (T + B), Value);\n\t\t}\n\n\t\tpublic static void DrawLine(Level Level, Dot From, Dot To, Tile Value, bool Bold = false) {\n\t\t\tfloat X = From.X;\n\t\t\tfloat Y = From.Y;\n\t\t\tfloat Dx = To.X - From.X;\n\t\t\tfloat Dy = To.Y - From.Y;\n\t\t\tvar MovingbyX = Math.Abs(Dx) >= Math.Abs(Dy);\n\n\t\t\tif (MovingbyX) {\n\t\t\t\tDy /= Math.Abs(Dx);\n\t\t\t\tDx /= Math.Abs(Dx);\n\t\t\t} else {\n\t\t\t\tDx /= Math.Abs(Dy);\n\t\t\t\tDy /= Math.Abs(Dy);\n\t\t\t}\n\n\t\t\tif (Bold) {\n\t\t\t\tSetBold(Level, (int) Math.Round(X), (int) Math.Round(Y), Value);\n\t\t\t} else {\n\t\t\t\tSet(Level, (int) Math.Round(X), (int) Math.Round(Y), Value);\n\t\t\t}\n\n\t\t\twhile (MovingbyX && (int) To.X != (int) X || !MovingbyX && (int) To.Y != (int) Y) {\n\t\t\t\tX += Dx;\n\t\t\t\tY += Dy;\n\n\t\t\t\tif (Bold) {\n\t\t\t\t\tSetBold(Level, (int) Math.Round(X), (int) Math.Round(Y), Value);\n\t\t\t\t} else {\n\t\t\t\t\tSet(Level, (int) Math.Round(X), (int) Math.Round(Y), Value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void FillEllipse(Level Level, Rect Rect, Tile Value) {\n\t\t\tFillEllipse(Level, Rect.Left, Rect.Top, Rect.GetWidth(), Rect.GetHeight(), Value);\n\t\t}\n\n\t\tpublic static void FillEllipse(Level Level, Rect Rect, int M, Tile Value) {\n\t\t\tRect = Rect.Shrink(M);\n\t\t\tFillEllipse(Level, Rect.Left, Rect.Top, Rect.GetWidth(), Rect.GetHeight(), Value);\n\t\t}\n\n\t\tpublic static void FillEllipse(Level Level, int X, int Y, int W, int H, Tile Value) {\n\t\t\tdouble RadH = H / 2f;\n\t\t\tdouble RadW = W / 2f;\n\n\t\t\tfor (var I = 0; I < H; I++) {\n\t\t\t\tvar RowY = -RadH + 0.5 + I;\n\t\t\t\tvar RowW = 2.0 * Math.Sqrt(RadW * RadW * (1.0 - RowY * RowY / (RadH * RadH)));\n\n\t\t\t\tif (W % 2 == 0) {\n\t\t\t\t\tRowW = Math.Round(RowW / 2.0) * 2.0;\n\t\t\t\t} else {\n\t\t\t\t\tRowW = Math.Floor(RowW / 2.0) * 2.0;\n\t\t\t\t\tRowW++;\n\t\t\t\t}\n\n\t\t\t\tvar Cell = X + (W - (int) RowW) / 2 + (Y + I) * Level.Width;\n\n\t\t\t\tfor (var J = Cell; J < Cell + RowW; J++) {\n\t\t\t\t\tLevel.Set(J, Value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Ellipse(Level Level, Rect Rect, int m, Tile Value, bool bold = false) {\n\t\t\tRect = Rect.Shrink(m);\n\t\t\tEllipse(Level, Rect.Left, Rect.Top, Rect.GetWidth(), Rect.GetHeight(), Value, bold);\n\t\t}\n\t\t\n\t\tpublic static void Ellipse(Level Level, Rect Rect, Tile Value, bool bold = false) {\n\t\t\tEllipse(Level, Rect.Left, Rect.Top, Rect.GetWidth(), Rect.GetHeight(), Value, bold);\n\t\t}\n\t\t\n\t\t// To be tested\n\t\tpublic static void Ellipse(Level Level, int X, int Y, int W, int H, Tile Value, bool bold) {\n\t\t\tdouble RadH = H / 2f;\n\t\t\tdouble RadW = W / 2f;\n\n\t\t\tfor (var I = 0; I < H; I++) {\n\t\t\t\tvar RowY = -RadH + 0.5 + I;\n\t\t\t\tvar RowW = 2.0 * Math.Sqrt(RadW * RadW * (1.0 - RowY * RowY / (RadH * RadH)));\n\n\t\t\t\tif (W % 2 == 0) {\n\t\t\t\t\tRowW = Math.Round(RowW / 2.0) * 2.0;\n\t\t\t\t} else {\n\t\t\t\t\tRowW = Math.Floor(RowW / 2.0) * 2.0;\n\t\t\t\t\tRowW++;\n\t\t\t\t}\n\n\t\t\t\tvar Cell = X + (W - (int) RowW) / 2 + (Y + I) * Level.Width;\n\t\t\t\tvar CellB = (int) (Cell + RowW - 1);\n\n\t\t\t\tif (I == 0 || I == H - 1) {\n\t\t\t\t\tfor (var J = Cell - 1; J <= Cell + RowW; J++) {\n\t\t\t\t\t\tif (bold) {\n\t\t\t\t\t\t\tSetBold(Level, Level.FromIndexX(J), Level.FromIndexY(J), Value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tLevel.Set(J, Value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (bold) {\n\t\t\t\t\t\tSetBold(Level, Level.FromIndexX(Cell), Level.FromIndexY(Cell), Value);\n\t\t\t\t\t\tSetBold(Level, Level.FromIndexX(CellB), Level.FromIndexY(CellB), Value);\t\n\t\t\t\t\t} else {\n\t\t\t\t\t\tLevel.Set(Cell, Value);\n\t\t\t\t\t\tLevel.Set(CellB, Value);\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Prefab(Level level, string id, int x, int y) {\n\t\t\tvar prefab = Prefabs.Get(id);\n\n\t\t\tif (prefab == null) {\n\t\t\t\tLog.Error($\"Unknown prefab {id}\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tprefab.Place(level, x, y);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/Patch.cs",
    "content": "using BurningKnight.state;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level {\n\tpublic class Patch {\n\t\tpublic static bool[] Generate(float Seed, int Octaves) {\n\t\t\treturn Generate(Run.Level.Width, Run.Level.Height, Seed, Octaves);\n\t\t}\n\n\t\tpublic static bool[] Noise(float seed, float s = 0.1f) {\n\t\t\treturn Noise(Run.Level.Width, Run.Level.Height, seed, s);\n\t\t}\n\n\t\tpublic static bool[] Noise(int w, int h, float seed, float s) {\n\t\t\tseed = 1 - seed;\n\t\t\tseed *= 2;\n\t\t\tseed -= 1;\n\n\t\t\tvar mx = Rnd.Float(100f);\n\t\t\tvar my = Rnd.Float(100f);\n\t\t\tvar array = new bool[w * h];\n\t\t\t\n\t\t\tfor (int y = 0; y < h; y++) {\n\t\t\t\tfor (int x = 0; x < w; x++) {\n\t\t\t\t\tvar n = Lens.util.Noise.Fbm(new Vector2(x * s + mx, y * s + my), 3);\n\t\t\t\t\tarray[x + y * w] = n >= seed;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn array;\n\t\t}\n\n\t\tpublic static bool[] GenerateWithNoise(int W, int H, float Seed, float h, float scale = 1f) {\n\t\t\tvar a = new bool[W * H];\n\n\t\t\tfor (var y = 0; y < H; y++) {\n\t\t\t\tfor (var x = 0; x < W; x++) {\n\t\t\t\t\ta[x + y * W] = Lens.util.Noise.Generate((x + Seed) * scale, (y + Seed) * scale) > h;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn a;\n\t\t}\n\n\t\tpublic static bool[] Generate(int W, int H, float Seed, int Octaves) {\n\t\t\tvar Cur = new bool[W * H];\n\t\t\tvar Off = new bool[W * H];\n\n\t\t\tfor (var I = 0; I < W * H; I++) Off[I] = Rnd.Float() < Seed;\n\n\t\t\tfor (var I = 0; I < Octaves; I++) {\n\t\t\t\tfor (var Y = 1; Y < H - 1; Y++)\n\t\t\t\tfor (var X = 1; X < W - 1; X++) {\n\t\t\t\t\tvar Pos = X + Y * W;\n\t\t\t\t\tvar Count = 0;\n\n\t\t\t\t\tif (Off[Pos - W - 1]) Count++;\n\n\t\t\t\t\tif (Off[Pos - W]) Count++;\n\n\t\t\t\t\tif (Off[Pos - W + 1]) Count++;\n\n\t\t\t\t\tif (Off[Pos - 1]) Count++;\n\n\t\t\t\t\tif (Off[Pos + 1]) Count++;\n\n\t\t\t\t\tif (Off[Pos + W - 1]) Count++;\n\n\t\t\t\t\tif (Off[Pos + W]) Count++;\n\n\t\t\t\t\tif (Off[Pos + W + 1]) Count++;\n\n\t\t\t\t\tif (!Off[Pos] && Count >= 5)\n\t\t\t\t\t\tCur[Pos] = true;\n\t\t\t\t\telse\n\t\t\t\t\t\tCur[Pos] = Off[Pos] && Count >= 4;\n\t\t\t\t}\n\n\t\t\t\tvar Tmp = Cur;\n\t\t\t\tCur = Off;\n\t\t\t\tOff = Tmp;\n\t\t\t}\n\n\t\t\treturn Off;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/ProjectileBodyComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.util;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace BurningKnight.level {\n\tpublic class ProjectileBodyComponent : LevelBodyComponent {\n\t\tprotected override void RecreateChunk(int cx, int cy) {\n\t\t\tvar level = Level;\n\t\t\t\n\t\t\tvar body = BodyFactory.CreateBody(Physics.World, Vector2.Zero);\n\t\t\tbody.FixedRotation = true;\n\t\t\tbody.UserData = this;\n\n\t\t\tvar i = cx + cy * cw;\n\t\t\tvar c = chunks[i];\n\n\t\t\tif (c != null) {\n\t\t\t\tPhysics.RemoveBody(c);\n\t\t\t}\n\t\t\t\n\t\t\tchunks[i] = body;\n\n\t\t\tvar list = new List<Vector2>();\n\n\t\t\tfor (int y = cy * ChunkSize; y < (cy + 1) * ChunkSize; y++) {\n\t\t\t\tfor (int x = cx * ChunkSize; x < (cx + 1) * ChunkSize; x++) {\n\t\t\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar index = level.ToIndex(x, y);\n\n\t\t\t\t\tvar tile = level.Tiles[index];\n\t\t\t\t\tvar side = x == 0 || y == 0 || x == level.Width - 1 || y == level.Height - 1;\n\n\t\t\t\t\tif (side || TileFlags.Matches(tile, TileFlags.Solid)) {\n\t\t\t\t\t\tvar sum = 0;\n\n\t\t\t\t\t\tif (!side) {\n\t\t\t\t\t\t\tforeach (var dir in PathFinder.Neighbours8) {\n\t\t\t\t\t\t\t\tvar n = dir + index;\n\n\t\t\t\t\t\t\t\tif (level.IsInside(n) && (TileFlags.Matches(level.Tiles[n], TileFlags.Solid))) {\n\t\t\t\t\t\t\t\t\tsum++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sum == 8) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar xx = (x) * 16;\n\t\t\t\t\t\tvar yy = (y) * 16 - 8;\n\n\t\t\t\t\t\tlist.Clear();\n\n\t\t\t\t\t\tvar t = Check(level, x, y - 1);\n\t\t\t\t\t\tvar b = Check(level, x, y + 1);\n\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 4, yy + (t ? 0 : 7)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 12, yy + (t ? 0 : 7)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 12, yy + (b ? 16 : 8)));\n\t\t\t\t\t\tlist.Add(new Vector2(xx + 4, yy + (b ? 16 : 8)));\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tFixtureFactory.AttachPolygon(new Vertices(list), 1f, body);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tforeach (var p in list) {\n\t\t\t\t\t\t\t\tLog.Info($\"{p.X - xx}:{p.Y - yy}\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/ProjectileLevelBody.cs",
    "content": "using BurningKnight.assets.particle;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.pet;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level {\n\tpublic class ProjectileLevelBody : Entity, CollisionFilterEntity {\n\t\tpublic Level Level;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddComponent(new ProjectileBodyComponent {\n\t\t\t\tLevel = Level\n\t\t\t});\n\t\t}\n\n\t\tpublic bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Projectile || entity is DiagonalPet;\n\t\t}\n\n\t\tpublic bool Break(float x, float y) {\n\t\t\ty += 8;\n\t\t\tvar a = Check((int) (x / 16), (int) (y / 16));\n\t\t\t\n\t\t\ta = Check((int) (x / 16 - 0.5f), (int) (y / 16)) || a;\n\t\t\ta = Check((int) (x / 16 + 0.5f), (int) (y / 16)) || a;\n\t\t\ta = Check((int) (x / 16), (int) (y / 16 - 0.5f)) || a;\n\t\t\ta = Check((int) (x / 16), (int) (y / 16 + 0.5f)) || a;\n\t\t\ta = Check((int) (x / 16 - 0.5f), (int) (y / 16 + 0.5f)) || a;\n\t\t\ta = Check((int) (x / 16 + 0.5f), (int) (y / 16 + 0.5f)) || a;\n\t\t\ta = Check((int) (x / 16 - 0.5f), (int) (y / 16 - 0.5f)) || a;\n\t\t\ta = Check((int) (x / 16 + 0.5f), (int) (y / 16 - 0.5f)) || a;\n\n\t\t\treturn a;\n\t\t}\n\n\t\tprivate bool Check(int x, int y) {\n\t\t\tvar t = Level.Get(x, y);\n\t\t\n\t\t\tif (t == Tile.WallA || t == Tile.Transition) {\n\t\t\t\tLevel.Set(x, y, Tile.Ice);\n\t\t\t\tLevel.UpdateTile(x, y);\n\t\t\t\tLevel.ReTileAndCreateBodyChunks(x, y, 2, 2);\n\t\t\t\t\n\t\t\t\tLevel.Area.Add(new TileFx {\n\t\t\t\t\tX = x * 16,\n\t\t\t\t\tY = y * 16 - 8\n\t\t\t\t});\n\t\t\t\n\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = new Vector2(x * 16 + 8, y * 16 + 8);\n\t\t\t\t\tLevel.Area.Add(part);\n\t\t\t\t}\n\t\t\n\t\t\t\tEngine.Instance.Freeze = 0.5f;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static void Mine(Level level, float x, float y) {\n\t\t\ty += 8;\n\t\t\t\n\t\t\tCheckMine(level, (int) (x / 16), (int) (y / 16));\n\t\t\tCheckMine(level, (int) (x / 16 - 0.5f), (int) (y / 16));\n\t\t\tCheckMine(level, (int) (x / 16 + 0.5f), (int) (y / 16));\n\t\t\tCheckMine(level, (int) (x / 16), (int) (y / 16 - 0.5f));\n\t\t\tCheckMine(level, (int) (x / 16), (int) (y / 16 + 0.5f));\n\t\t}\n\n\t\tprivate static void CheckMine(Level level, int x, int y) {\n\t\t\tif (level.Get(x, y) == Tile.Planks) {\n\t\t\t\tlevel.Set(x, y, Tile.Ember);\n\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\n\t\t\t\tCamera.Instance.ShakeMax(3);\n\n\t\t\t\tLevel.Animate(level.Area, x, y);\n\t\t\t} else if (level.Get(x, y, true).Matches(Tile.Rock, Tile.TintedRock, Tile.MetalBlock)) {\n\t\t\t\tlevel.Set(x, y, Tile.Ember);\n\t\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\tlevel.ReCreateBodyChunk(x, y);\n\n\t\t\t\tCamera.Instance.ShakeMax(3);\n\t\t\t\t\n\t\t\t\tExplosionMaker.BreakRock(level, new Dot(x * 16 + 8, y * 16 + 8), x, y, level.Get(x, y, true));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/RegularLevel.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.challenge;\nusing BurningKnight.level.rooms.darkmarket;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.rooms.payed;\nusing BurningKnight.level.rooms.preboss;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.scourged;\nusing BurningKnight.level.rooms.secret;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.level.rooms.shop.sub;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.rooms.special.minigame;\nusing BurningKnight.level.rooms.special.shop;\nusing BurningKnight.level.rooms.spiked;\nusing BurningKnight.level.rooms.trap;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.variant;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.util;\nusing Lens.util.math;\nusing MonoGame.Extended.Collections;\nusing Builder = BurningKnight.level.builders.Builder;\n\nnamespace BurningKnight.level {\n\tpublic class RegularLevel : Level {\n\t\tprivate List<RoomDef> rooms;\n\n\t\tpublic RegularLevel(BiomeInfo biome) : base(biome) {\n\t\t\t\n\t\t}\n\n\t\tpublic RegularLevel() : base(null) {\n\t\t\t\n\t\t}\n\n\t\tpublic override int GetPadding() {\t\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic bool Generate() {\n\t\t\tRun.Level = this;\n\t\t\trooms = null;\n\t\t\tItemsToSpawn = new List<string>();\n\t\t\tVariant = VariantRegistry.Generate(LevelSave.BiomeGenerated.Id);\n\n\t\t\tif (Variant == null) {\n\t\t\t\tVariant = new RegularLevelVariant();\n\t\t\t}\n\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tvar c = Rnd.Int(1, Run.Depth);\n\n\t\t\t\tif (Run.Level.Biome is CaveBiome) {\n\t\t\t\t\tc = Rnd.Int(5, 15);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\tItemsToSpawn.Add(\"bk:emerald\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tBuild();\n\n\t\t\tif (!Paint()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (rooms == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tTileUp();\n\t\t\tCreateBody();\n\t\t\tCreateDestroyableBody();\n\t\t\tLoadPassable();\n\n\t\t\tLevelSave.ResetGen();\n\t\t\tLog.Info(\"Done!\");\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected bool Paint() {\n\t\t\tLog.Info(\"Painting...\");\n\t\t\tvar p = GetPainter();\n\t\t\tLevelSave.BiomeGenerated.ModifyPainter(this, p);\n\t\t\t\n\t\t\treturn p.Paint(this, rooms);\n\t\t}\n\n\t\tprotected void Build() {\n\t\t\tvar Builder = GetBuilder();\n\t\t\tvar Rooms = CreateRooms();\n\n\t\t\tRooms = (List<RoomDef>) Rooms.Shuffle(Rnd.Generator);\n\n\t\t\tvar Attempt = 0;\n\n\t\t\tdo {\n\t\t\t\tLog.Info($\"Generating (attempt {Attempt}, seed {Rnd.Seed})...\");\n\n\t\t\t\tforeach (var Room in Rooms) {\n\t\t\t\t\tRoom.Connected.Clear();\n\t\t\t\t\tRoom.Neighbours.Clear();\n\t\t\t\t} \n\n\t\t\t\tvar Rm = new List<RoomDef>();\n\t\t\t\tRm.AddRange(Rooms);\n\t\t\t\trooms = Builder.Build(Rm);\n\n\t\t\t\tvar a = rooms == null;\n\t\t\t\tvar b = false;\n\t\t\t\t\n\t\t\t\tif (!a) {\n\t\t\t\t\tforeach (var r in Rm) {\n\t\t\t\t\t\tif (r.IsEmpty()) {\n\t\t\t\t\t\t\tLog.Error(\"Found an empty room!\");\n\t\t\t\t\t\t\tb = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (a || b) {\n\t\t\t\t\trooms = null;\n\t\t\t\t\n\t\t\t\t\tLog.Error($\"Failed! {Builder.GetType().Name}\");\n\t\t\t\t\tArea.Destroy();\n\t\t\t\t\tArea.Add(Run.Level);\n\t\t\t\t\tLevelSave.FailedAttempts++;\n\t\t\t\t\tBuilder = GetBuilder();\n\n\t\t\t\t\tif (Attempt >= 10) {\n\t\t\t\t\t\tLog.Error(\"Too many attempts to generate a level! Trying a different room set!\");\n\t\t\t\t\t\tAttempt = 0;\n\t\t\t\t\t\tRooms = CreateRooms();\n\t\t\t\t\t\tRooms = (List<RoomDef>) Rooms.Shuffle(Rnd.Generator);\n\t\t\t\t\t}\n\n\t\t\t\t\tAttempt++;\n\t\t\t\t}\n\t\t\t} while (rooms == null);\n\t\t}\n\n\t\tprivate bool IsFinal() {\n\t\t\treturn Run.Depth == Run.ContentEndDepth;\n\t\t}\n\n\t\tprotected virtual List<RoomDef> CreateRooms() {\n\t\t\tvar rooms = new List<RoomDef>();\n\t\t\tvar biome = LevelSave.BiomeGenerated;\n\t\t\tvar final = IsFinal();\n\t\t\tvar rush = Run.Type == RunType.BossRush;\n\t\t\tvar first = Run.Depth % 2 == 1;\n\t\t\tvar loop = Run.Loop > 0;\n\t\t\tvar cave = biome is CaveBiome;\n\n\t\t\tif (!rush && biome is DesertBiome) {\n\t\t\t\trooms.Add(new DesertWellRoom());\n\t\t\t}\n\n\t\t\tif (cave) {\n\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));\n\t\t\t}\n\n\t\t\tif (final) {\n\t\t\t\tLog.Info(\"Prepare for the final!\");\n\t\t\t}\n\t\t\t\n\t\t\tLog.Info($\"Generating a level for {biome.Id} biome\");\n\t\t\t\n\t\t\trooms.Add(new EntranceRoom());\n\t\t\t\n\t\t\tif (Run.Depth == 5 && LevelSave.GenerateMarket && Run.Loop == 0) {\n\t\t\t\trooms.Add(new ShopRoom());\n\t\t\t\trooms.Add(new ExitRoom());\n\n\t\t\t\tif (GlobalSave.IsTrue(ShopNpc.Gobetta) && Rnd.Chance(10)) {\n\t\t\t\t\trooms.Add(new GobettaShopRoom());\n\t\t\t\t}\n\n\t\t\t\tif (Rnd.Chance(2)) {\n\t\t\t\t\trooms.Add(new TrashGoblinRoom());\n\t\t\t\t}\n\n\t\t\t\tif (Rnd.Chance(3)) {\n\t\t\t\t\trooms.Add(new ChestMinigameRoom());\n\t\t\t\t}\n\n\t\t\t\tif (Rnd.Chance(4)) {\n\t\t\t\t\trooms.Add(new VendingRoom());\n\t\t\t\t}\n\n\t\t\t\tif (GlobalSave.IsTrue(ShopNpc.Roger) && Rnd.Chance(10)) {\n\t\t\t\t\trooms.Add(new RogerShopRoom());\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Secret, biome));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\trooms.Add(new EmptyRoom());\n\t\t\t\treturn rooms;\n\t\t\t}\n\n\t\t\tif (!rush && !loop) {\n\t\t\t\tif (Run.Depth == 2) {\n\t\t\t\t\trooms.Add(new SecretKeyRoom());\n\t\t\t\t} else if (Run.Depth == 4) {\n\t\t\t\t\trooms.Add(new ClawMinigameRoom());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!final) {\n\t\t\t\tvar cn = LevelSave.XL ? 2 : 1;\n\n\t\t\t\tvar regular = rush || final ? 0 : biome.GetNumRegularRooms() * cn;\n\t\t\t\tvar special = rush || final ? 0 : biome.GetNumSpecialRooms() * cn;\n\t\t\t\tvar trap = rush || final ? 0 : biome.GetNumTrapRooms();\n\t\t\t\tvar connection = rush || final ? 1 : GetNumConnectionRooms();\n\t\t\t\tvar secret = rush || final ? 0 : biome.GetNumSecretRooms() * cn;\n\n\t\t\t\tLog.Info($\"Creating r{regular} sp{special} c{connection} sc{secret} t{trap} rooms\");\n\n\t\t\t\tfor (var I = 0; I < regular; I++) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Regular, biome));\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < trap; i++) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Trap, biome));\n\t\t\t\t}\n\n\t\t\t\tfor (var I = 0; I < special; I++) {\n\t\t\t\t\tvar room = RoomRegistry.Generate(RoomType.Special, biome);\n\t\t\t\t\tif (room != null) rooms.Add(room);\n\t\t\t\t}\n\n\t\t\t\tfor (var I = 0; I < connection; I++) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Connection, biome));\n\t\t\t\t}\n\n\t\t\t\tif (!rush && !final && Run.Type != RunType.Challenge) {\n\t\t\t\t\tif (!loop && !LevelSave.GenerateShops && first) {\n\t\t\t\t\t\tif (LevelSave.XL) {\n\t\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!LevelSave.GenerateTreasure && (!first || LevelSave.GenerateShops)) {\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Shop, biome));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!LevelSave.GenerateShops && LevelSave.GenerateTreasure && !first) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));\n\t\t\t\t}\n\n\t\t\t\tif (!LevelSave.GenerateShops && loop && Run.Depth == 1 && Run.Type != RunType.Challenge) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));\n\t\t\t\t}\n\n\t\t\t\tif (rush) {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));\n\t\t\t\t\trooms.Add(new PrebossRoom());\n\n\t\t\t\t\tif (Run.Depth < 11) {\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Connection, biome));\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Shop, biome));\n\t\t\t\t\t}\n\t\t\t\t} else if (first) {\n\t\t\t\t\trooms.Add(new ExitRoom());\n\t\t\t\t} else {\n\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));\n\t\t\t\t\trooms.Add(new PrebossRoom());\n\n\t\t\t\t\tif (Run.Depth < 10) {\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Granny, biome));\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.OldMan, biome));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (biome is CaveBiome && Rnd.Chance(5)) {\n\t\t\t\t\trooms.Add(new SecretEmeraldGolemRoom());\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!rush) {\n\t\t\t\t\tif (Rnd.Chance(95)) {\n\t\t\t\t\t\tif (Rnd.Chance(2 + Run.Scourge * 5)) {\n\t\t\t\t\t\t\trooms.Add(new ScourgedRoom());\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\t\t\t\trooms.Add(new ChallengeRoom());\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\trooms.Add(new SpikedRoom());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvar addDarkMarket = (Run.Depth > 2 && Rnd.Chance(10) && GameSave.IsFalse(\"saw_blackmarket\"));\n\n\t\t\t\t\tif (addDarkMarket) {\n\t\t\t\t\t\trooms.Add(new DarkMarketEntranceRoom());\n\t\t\t\t\t\trooms.Add(new DarkMarketRoom());\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!addDarkMarket && Rnd.Chance(1)) {\n\t\t\t\t\t\tsecret--;\n\t\t\t\t\t\trooms.Add(new SecretDarkMarketEntranceRoom());\n\t\t\t\t\t\trooms.Add(new DarkMarketRoom());\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var I = 0; I < secret; I++) {\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Secret, biome));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.SubShop, biome));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (NpcSaveRoom.ShouldBeAdded()) {\n\t\t\t\t\t\trooms.Add(new NpcSaveRoom());\n\t\t\t\t\t\trooms.Add(new NpcKeyRoom());\n\t\t\t\t\t}\n\n\t\t\t\t\tTombRoom.Insert(rooms);\n\t\t\t\t\tbiome.ModifyRooms(rooms);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));\n\t\t\t\trooms.Add(new PrebossRoom());\n\t\t\t}\n\n\t\t\treturn rooms;\n\t\t}\n\n\t\tprotected virtual Painter GetPainter() {\n\t\t\treturn new Painter();\n\t\t}\n\n\t\tprotected virtual Builder GetBuilder() {\n\t\t\tBuilder builder;\n\n\t\t\tif (IsFinal() || Run.Type == RunType.BossRush) {\n\t\t\t\tbuilder = new LineBuilder();\n\t\t\t} else {\n\t\t\t\tbuilder = LevelSave.BiomeGenerated.GetBuilder();\n\n\t\t\t\tif (builder is RegularBuilder b) {\n\t\t\t\t\tif (LevelSave.BiomeGenerated.Id == Biome.Ice) {\n\t\t\t\t\t\tb.SetTunnelLength(new float[] {4, 6, 4}, new float[] {1, 3, 1});\n\t\t\t\t\t} else if (GetFilling() == Tile.Chasm) {\n\t\t\t\t\t\tb.SetTunnelLength(new float[] {4, 3, 4}, new float[] {1, 3, 1});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn builder;\n\t\t}\n\n\t\tprotected int GetNumConnectionRooms() {\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/Weather.cs",
    "content": "using System;\nusing BurningKnight.state;\nusing Lens.util.math;\n\nnamespace BurningKnight.level {\n\tpublic static class Weather {\n\t\tpublic static float Time;\n\t\tpublic static float RainAngle = (float) Math.PI * 0.5f + Rnd.Float(-0.5f, 0.5f);\n\t\tpublic static float TimeOfDay => Time % 24;\n\t\tpublic static bool IsNight {\n\t\t\tset {\n\t\t\t\tTime = value ? 0 : 8;\n\t\t\t}\n\t\t\t\n\t\t\tget {\n\t\t\t\treturn TimeOfDay < 7 || TimeOfDay >= 21;\n\t\t\t}\n\t\t}\n\n\t\tpublic static bool IsDay => !IsNight;\n\n\t\tpublic static bool Rains;\n\t\tpublic static bool Snows;\n\n\t\tprivate static float t;\n\t\tpublic static float RainLeft;\n\n\t\tpublic static void Init() {\n\t\t\tt = Rnd.Float(1000);\n\t\t\tTime = Rnd.Float(24);\n\n\t\t\tif (Events.XMas && Run.Depth == 0) {\n\t\t\t\tSnows = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\tif (!Events.XMas && Rnd.Chance(90)) {\n\t\t\t\t\tRains = true;\n\t\t\t\t} else {\n\t\t\t\t\tSnows = true;\n\t\t\t\t}\n\n\t\t\t\tRainLeft = Rnd.Float(12f, 128f);\n\t\t\t} else {\n\t\t\t\tRainLeft = Rnd.Float(1f, 48f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void Update(float dt) {\n\t\t\tvar d = dt * 0.01f;\n\t\t\t\n\t\t\tt += dt;\n\t\t\tRainLeft -= d;\n\t\t\tTime += d;\n\n\t\t\tif (RainLeft <= 0) {\n\t\t\t\tvar rained = Rains || Snows;\n\t\t\t\tRainLeft = rained ? Rnd.Float(12f, 128f) : Rnd.Float(1f, 48f);\n\n\t\t\t\tif (!(Events.XMas && Run.Depth == 0)) {\n\t\t\t\t\tif (rained) {\n\t\t\t\t\t\tRains = Snows = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (Rnd.Chance(90)) {\n\t\t\t\t\t\t\tRains = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSnows = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tRainAngle = (float) (Math.PI * 0.5f + Math.Sin(t * 0.01f) * 0.5f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/Biome.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.variant;\nusing BurningKnight.state;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class Biome {\n\t\tpublic const string Castle = \"castle\";\n\t\tpublic const string Hub = \"hub\";\n\t\tpublic const string Library = \"library\";\n\t\tpublic const string Desert = \"desert\";\n\t\tpublic const string Ice = \"ice\";\n\t\tpublic const string Jungle = \"jungle\";\n\t\tpublic const string Tech = \"tech\";\n\t\tpublic const string Cave = \"cave\";\n\t\t\n\t\tpublic readonly string Music;\n\t\tpublic readonly string Id;\n\t\tpublic readonly string Tileset;\n\t\tpublic readonly Color Bg;\n\n\t\tpublic Biome(string music, string id, string tileset, Color bg) {\n\t\t\tMusic = music;\n\t\t\tId = id;\n\t\t\tTileset = tileset;\n\t\t\tBg = bg;\n\t\t}\n\n\t\tpublic bool IsPresent(string[] biomes) {\n\t\t\treturn IsPresent(Id, biomes);\n\t\t}\n\n\t\tpublic virtual string GetMusic() {\n\t\t\treturn Music;\n\t\t}\n\n\t\tpublic static bool IsPresent(string id, string[] biomes) {\n\t\t\tif (biomes == null || biomes.Length == 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tforeach (var b in biomes) {\n\t\t\t\tif (b == id) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic virtual void Apply() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void ModifyPainter(Level level, Painter painter) {\n\t\t\tlevel?.Variant?.ModifyPainter(painter);\n\t\t}\n\n\t\tpublic virtual void ModifyRooms(List<RoomDef> rooms) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool SpawnAllMobs() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic virtual Builder GetBuilder() {\n\t\t\tvar R = Rnd.Float();\n\n\t\t\tif (R < 0.33f) {\n\t\t\t\treturn new LineBuilder().SetPathLength(0.5f, new float[] { 1, 2, 3 });\n\t\t\t}\n\n\t\t\tif (R < 0.66f) {\n\t\t\t\treturn new LoopBuilder().SetShape(2,\n\t\t\t\t\tRnd.Float(0.4f, 0.7f),\n\t\t\t\t\tRnd.Float(0f, 0.5f));\n\t\t\t}\n\t\t\t\n\t\t\treturn new CastleBuilder();\n\t\t}\n\n\t\tpublic virtual Tile GetFilling() {\n\t\t\treturn Run.Level.Variant.Id == LevelVariant.Chasm ? Tile.Chasm : Tile.WallA;\n\t\t}\n\n\t\tpublic virtual bool HasCobwebs() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual bool HasPaintings() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual bool HasTorches() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual bool HasSpikes() {\n\t\t\treturn Run.Type != RunType.BossRush;\n\t\t}\n\n\t\tpublic virtual bool HasBrekables() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual bool HasTnt() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual bool HasPlants() {\n\t\t\treturn Run.Level.Variant.Id == LevelVariant.Forest;\n\t\t}\n\n\t\tpublic virtual bool HasTrees() {\n\t\t\treturn Run.Level.Variant.Id == LevelVariant.Forest;\n\t\t}\n\t\t\n\t\tpublic virtual int GetNumRegularRooms() {\n\t\t\treturn Run.Depth + 2;\n\t\t}\n\n\t\tpublic virtual int GetNumTrapRooms() {\n\t\t\treturn Rnd.Chance(60) ? 1 : 0;\n\t\t}\n\n\t\tpublic virtual int GetNumSpecialRooms() {\n\t\t\treturn 1;\n\t\t}\n\n\t\tpublic virtual int GetNumSecretRooms() {\n\t\t\treturn Run.Depth <= 0 || Rnd.Chance() ? 0 : 1;\n\t\t}\n\n\t\tpublic string GetDefaultStepSound(Tile tile) {\n\t\t\treturn \"player_step_default_1\";\n\t\t}\n\n\t\tpublic virtual string GetStepSound(Tile tile) {\n\t\t\tswitch (tile) {\n\t\t\t\tcase Tile.Water: return $\"player_step_water_{Rnd.Int(1, 4)}\";\n\t\t\t\tcase Tile.Grass: return $\"player_step_grass_{Rnd.Int(1, 4)}\";\n\t\t\t\tcase Tile.Sand: case Tile.Dirt: return $\"player_step_sand_{Rnd.Int(1, 4)}\";\n\t\t\t\tcase Tile.Snow: return $\"player_step_snow_{Rnd.Int(1, 4)}\"; \n\t\t\t\tcase Tile.Ice: return $\"player_step_ice_{Rnd.Int(1, 4)}\";\n\t\t\t\tcase Tile.FloorD: return $\"player_step_gold_{Rnd.Int(1, 4)}\";\n\n\t\t\t\tcase Tile.FloorA: \n\t\t\t\tcase Tile.FloorB:\n\t\t\t\tcase Tile.FloorC: {\n\t\t\t\t\treturn $\"player_step_stone_{Rnd.Int(1, 4)}\";\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn GetDefaultStepSound(tile);\n\t\t}\n\t\t\n\t\tprivate static Color mapColor = new Color(101, 115, 146);\n\n\t\tpublic virtual Color GetMapColor() {\n\t\t\treturn mapColor;\n\t\t}\n\n\t\tpublic virtual string GetItemUnlock() {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/BiomeAssets.cs",
    "content": "﻿using System;\nusing BurningKnight.level.tile;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class BiomeAssets {\n\t\tpublic TextureRegion DirtPattern;\n\t\tpublic TextureRegion[] Dirt;\n\t\t\n\t\tpublic TextureRegion LavaPattern;\n\t\tpublic TextureRegion[] Lava;\n\t\t\n\t\tpublic TextureRegion WaterPattern;\n\t\tpublic TextureRegion[] Water;\n\t\t\n\t\tpublic TextureRegion IcePattern;\n\t\tpublic TextureRegion[] Ice;\n\t\t\n\t\tpublic TextureRegion VenomPattern;\n\t\tpublic TextureRegion[] Venom;\n\t\t\n\t\tpublic TextureRegion GrassPattern;\n\t\tpublic TextureRegion[] Grass;\n\t\t\n\t\tpublic TextureRegion CobwebPattern;\n\t\tpublic TextureRegion[] Cobweb;\n\t\t\n\t\tpublic TextureRegion ObsidianPattern;\n\t\tpublic TextureRegion[] Obsidian;\n\t\t\n\t\tpublic TextureRegion PathPattern;\n\t\tpublic TextureRegion[] Path;\n\t\t\n\t\tpublic TextureRegion SandPattern;\n\t\tpublic TextureRegion[] Sand;\n\t\t\n\t\tpublic TextureRegion SnowPattern;\n\t\tpublic TextureRegion[] Snow;\n\t\t\n\t\tpublic TextureRegion ChasmPattern;\n\t\tpublic TextureRegion[] ChasmTop = new TextureRegion[3];\n\t\tpublic TextureRegion[] ChasmBottom = new TextureRegion[3];\n\t\tpublic TextureRegion[] ChasmLeft = new TextureRegion[3];\n\t\tpublic TextureRegion[] ChasmRight = new TextureRegion[3];\n\t\tpublic TextureRegion[] ChasmSide = new TextureRegion[3];\n\t\t\n\t\tpublic TextureRegion EmberPattern;\n\t\tpublic TextureRegion Collider;\n\t\t\n\t\tpublic TextureRegion[][] Edges = new TextureRegion[(int) Tile.Total][];\n\t\tpublic TextureRegion[] Patterns = new TextureRegion[(int) Tile.Total];\n\n\t\tpublic TextureRegion[] Planks = new TextureRegion[12];\n\t\tpublic TextureRegion[] PlankTops = new TextureRegion[36];\n\t\tpublic TextureRegion[] PlankSides = new TextureRegion[3];\n\t\tpublic TextureRegion PlanksTop;\n\n\t\tpublic TextureRegion[] EvilWall = new TextureRegion[12];\n\t\tpublic TextureRegion[] EvilWallTops = new TextureRegion[36];\n\t\tpublic TextureRegion[] EvilWallSides = new TextureRegion[3];\n\t\t\n\t\tpublic TextureRegion[] GrannyWall = new TextureRegion[12];\n\t\tpublic TextureRegion[] GrannyWallTops = new TextureRegion[36];\n\t\tpublic TextureRegion[] GrannyWallSides = new TextureRegion[3];\n\t\t\n\t\tpublic TextureRegion[] GrannyFloor = new TextureRegion[16];\n\t\tpublic TextureRegion[] EvilFloor = new TextureRegion[16];\n\t\t\n\t\tpublic TextureRegion[] PlanksExtensions = new TextureRegion[4];\n\t\tpublic TextureRegion[] GrannyExtensions = new TextureRegion[4];\n\t\tpublic TextureRegion[] EvilExtensions = new TextureRegion[4];\n\n\t\tpublic TextureRegion[] Light;\n\n\t\tpublic BiomeAssets() {\n\t\t\tvar anim = Animations.Get(\"biome_assets\");\n\t\t\tLight = GetEdge(anim, 272, 192, 32);\n\n\t\t\tPatterns[(int) Tile.Dirt] = DirtPattern = new TextureRegion(anim.Texture, new Rectangle(0, 0, 64, 64));\n\t\t\tEdges[(int) Tile.Dirt] = Dirt = GetEdge(anim, 64, 0);\n\n\t\t\tPatterns[(int) Tile.Lava] = LavaPattern = new TextureRegion(anim.Texture, new Rectangle(0, 64, 64, 64));\n\t\t\tEdges[(int) Tile.Lava] = Lava = GetEdge(anim, 64, 64);\n\n\t\t\tvar spooky = Events.Halloween;\n\t\t\t\n\t\t\tPatterns[(int) Tile.Water] = WaterPattern = new TextureRegion(anim.Texture, new Rectangle(0, spooky ? 256 : 192, 64, 64));\n\t\t\tEdges[(int) Tile.Water] = Water = GetEdge(anim, 64, spooky ? 256 : 192);\n\n\t\t\tPatterns[(int) Tile.Ice] = IcePattern = new TextureRegion(anim.Texture, new Rectangle(128, 64, 64, 64));\n\t\t\tEdges[(int) Tile.Ice] = Ice = GetEdge(anim, 192, 64);\n\n\t\t\tPatterns[(int) Tile.Venom] = VenomPattern = new TextureRegion(anim.Texture, new Rectangle(0, 256, 64, 64));\n\t\t\tEdges[(int) Tile.Venom] = Venom = GetEdge(anim, 64, 256);\n\n\t\t\tPatterns[(int) Tile.Obsidian] = ObsidianPattern = new TextureRegion(anim.Texture, new Rectangle(0, 128, 64, 64));\n\t\t\tEdges[(int) Tile.Obsidian] = Obsidian = GetEdge(anim, 64, 128);\n\t\t\t\n\t\t\tPatterns[(int) Tile.Path] = PathPattern = new TextureRegion(anim.Texture, new Rectangle(400, 368, 64, 64));\n\t\t\tEdges[(int) Tile.Path] = Path = GetEdge(anim, 464, 368);\n\n\t\t\tPatterns[(int) Tile.Sand] = PathPattern = new TextureRegion(anim.Texture, new Rectangle(400, 304, 64, 64));\n\t\t\tEdges[(int) Tile.Sand] = Path = GetEdge(anim, 464, 304);\n\n\t\t\tPatterns[(int) Tile.Snow] = PathPattern = new TextureRegion(anim.Texture, new Rectangle(400, 240, 64, 64));\n\t\t\tEdges[(int) Tile.Snow] = Path = GetEdge(anim, 464, 240);\n\n\t\t\tPatterns[(int) Tile.HighGrass] = Patterns[(int) Tile.Grass] =\n\t\t\t\tGrassPattern = new TextureRegion(anim.Texture, new Rectangle(128, 0, 64, 64));\n\n\t\t\tEdges[(int) Tile.HighGrass] = Edges[(int) Tile.Grass] = Grass = GetEdge(anim, 192, 0);\n\n\t\t\tPatterns[(int) Tile.Cobweb] = CobwebPattern = new TextureRegion(anim.Texture, new Rectangle(128, 192, 64, 64));\n\t\t\tEdges[(int) Tile.Cobweb] = Cobweb = GetEdge(anim, 192, 192);\n\n\t\t\tPatterns[(int) Tile.Chasm] = ChasmPattern = new TextureRegion(anim.Texture, new Rectangle(288, 32, 16, 16));\n\t\t\tPatterns[(int) Tile.Ember] = EmberPattern = new TextureRegion(anim.Texture, new Rectangle(128, 128, 64, 64));\n\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\tChasmTop[i] = new TextureRegion(anim.Texture, new Rectangle(272 + i * 16, 0, 16, 16));\n\t\t\t\tChasmBottom[i] = new TextureRegion(anim.Texture, new Rectangle(272 + i * 16, 64, 16, 16));\n\t\t\t\tChasmLeft[i] = new TextureRegion(anim.Texture, new Rectangle(256, 16 + i * 16, 16, 16));\n\t\t\t\tChasmRight[i] = new TextureRegion(anim.Texture, new Rectangle(320, 16 + i * 16, 16, 16));\n\n\t\t\t\tChasmSide[i] = new TextureRegion(anim.Texture, new Rectangle(256 + i * 16, 80, 16, 16));\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tPlanksExtensions[0] = new TextureRegion(anim.Texture, new Rectangle(352, 104, 16, 8));\n\t\t\t\t\tPlanksExtensions[1] = new TextureRegion(anim.Texture, new Rectangle(368, 112, 8, 16));\n\t\t\t\t\tPlanksExtensions[2] = new TextureRegion(anim.Texture, new Rectangle(352, 128, 16, 8));\n\t\t\t\t\tPlanksExtensions[3] = new TextureRegion(anim.Texture, new Rectangle(344, 112, 8, 16));\n\t\t\t\t} else if (i == 1) {\n\t\t\t\t\tEvilExtensions[0] = new TextureRegion(anim.Texture, new Rectangle(80, 392, 16, 8));\n\t\t\t\t\tEvilExtensions[1] = new TextureRegion(anim.Texture, new Rectangle(96, 400, 8, 16));\n\t\t\t\t\tEvilExtensions[2] = new TextureRegion(anim.Texture, new Rectangle(80, 416, 16, 8));\n\t\t\t\t\tEvilExtensions[3] = new TextureRegion(anim.Texture, new Rectangle(72, 400, 8, 16));\n\t\t\t\t} else {\n\t\t\t\t\tGrannyExtensions[0] = new TextureRegion(anim.Texture, new Rectangle(272, 392, 16, 8));\n\t\t\t\t\tGrannyExtensions[1] = new TextureRegion(anim.Texture, new Rectangle(288, 400, 8, 16));\n\t\t\t\t\tGrannyExtensions[2] = new TextureRegion(anim.Texture, new Rectangle(272, 416, 16, 8));\n\t\t\t\t\tGrannyExtensions[3] = new TextureRegion(anim.Texture, new Rectangle(264, 400, 8, 16));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int j = 0; j < 12; j++) {\n\t\t\t\t\tvar n = j > 5 ? j + 1 : j;\n\n\t\t\t\t\tPlankTops[i * 12 + j] =\n\t\t\t\t\t\tnew TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40 + 208, n / 5 * 8 + 136, 8, 8));\n\n\t\t\t\t\tEvilWallTops[i * 12 + j] =\n\t\t\t\t\t\tnew TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40, n / 5 * 8 + 320, 8, 8));\n\n\t\t\t\t\tGrannyWallTops[i * 12 + j] =\n\t\t\t\t\t\tnew TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40 + 192, n / 5 * 8 + 320, 8, 8));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < 12; i++) {\n\t\t\t\tPlanks[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16 + 208, 160, 16, 16));\n\t\t\t\tEvilWall[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16, 344, 16, 16));\n\t\t\t\tGrannyWall[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16 + 192, 344, 16, 16));\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\tPlankSides[i] = new TextureRegion(anim.Texture, new Rectangle(344 + i * 16, 176, 16, 16));\n\t\t\t\tEvilWallSides[i] = new TextureRegion(anim.Texture, new Rectangle(64 + i * 16, 368, 16, 16));\n\t\t\t\tGrannyWallSides[i] = new TextureRegion(anim.Texture, new Rectangle(256 + i * 16, 368, 16, 16));\n\t\t\t}\n\n\t\t\tfor (int i = 0; i < 16; i++) {\n\t\t\t\tEvilFloor[i] = new TextureRegion(anim.Texture, new Rectangle(i % 4 * 16, 368 + i / 4 * 16, 16, 16));\n\t\t\t\tGrannyFloor[i] = new TextureRegion(anim.Texture, new Rectangle(192 + i % 4 * 16, 368 + i / 4 * 16, 16, 16));\n\t\t\t}\n\t\t\t\n\t\t\tPlanksTop = new TextureRegion(anim.Texture, new Rectangle(384, 144, 16, 16));\n\t\t\tCollider = PlanksTop; // new TextureRegion(anim.Texture, new Rectangle(304, 96, 16, 16));\n\t\t}\n\n\t\tprivate static Vector2[] Positions = {\n\t\t\tnew Vector2(0, 3), new Vector2(0, 2), new Vector2(1, 3), new Vector2(1, 2),\n\t\t\tnew Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 0), new Vector2(1, 1),\n\t\t\tnew Vector2(3, 3), new Vector2(3, 2), new Vector2(2, 3), new Vector2(2, 2),\n\t\t\tnew Vector2(3, 0), new Vector2(3, 1), new Vector2(2, 0), new Vector2(2, 1)\n\t\t};\n\n\t\tprivate TextureRegion[] GetEdge(AnimationData animation, int x, int y, int sz = 16) {\n\t\t\tvar edge = new TextureRegion[16];\n\n\t\t\tfor (int i = 0; i < 16; i++) {\n\t\t\t\tedge[i] = new TextureRegion(animation.Texture, new Rectangle(x + (int) Positions[i].X * sz, y + (int) Positions[i].Y * sz, sz, sz));\n\t\t\t}\n\t\t\t\n\t\t\treturn edge;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/BiomeInfo.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace BurningKnight.level.biome {\n\tpublic class BiomeInfo {\n\t\tpublic readonly Type Type;\n\t\tpublic readonly string Id;\n\t\tpublic readonly List<int> Depths = new List<int>();\n\t\tpublic readonly List<float> Chances = new List<float>();\n\n\t\tpublic BiomeInfo(Type type, string id) {\n\t\t\tType = type;\n\t\t\tId = id;\n\t\t}\n\n\t\tpublic static BiomeInfo New<T>(string id, params float[] types) where T : Biome {\n\t\t\treturn new BiomeInfo(typeof(T), id);\n\t\t}\n\n\t\tpublic BiomeInfo Add(int depth, float chance) {\n\t\t\tDepths.Add(depth);\n\t\t\tChances.Add(chance);\n\n\t\t\treturn this;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/BiomeRegistry.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.state;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.biome {\n\tpublic static class BiomeRegistry {\n\t\tpublic static Dictionary<string, BiomeInfo> Defined = new Dictionary<string, BiomeInfo>();\n\t\tpublic static Dictionary<string, BiomeInfo> BossRushDefined = new Dictionary<string, BiomeInfo>();\n\n\t\tstatic BiomeRegistry() {\n\t\t\tvar jungle = BiomeInfo.New<JungleBiome>(Biome.Jungle).Add(5, 1f).Add(6, 1f);\n\t\t\t\n\t\t\t// Just to make old levels load properly, jungle used to be called forest\n\t\t\tDefined[\"forest\"] = jungle;\n\t\t\t\n\t\t\tBiomeInfo[] infos = {\n\t\t\t\tBiomeInfo.New<HubBiome>(Biome.Hub).Add(0, 1f),\n\n\t\t\t\tBiomeInfo.New<CastleBiome>(Biome.Castle).Add(1, 1f).Add(2, 1f).Add(-2, 1f).Add(-1, 1f),\n\t\t\t\tBiomeInfo.New<DesertBiome>(Biome.Desert).Add(3, 1f).Add(4, 1f),\n\t\t\t\tjungle,\n\t\t\t\tBiomeInfo.New<IceBiome>(Biome.Ice).Add(7, 1f).Add(8, 1f),\n\t\t\t\tBiomeInfo.New<LibraryBiome>(Biome.Library).Add(9, 1f).Add(10, 1f),\n\n\t\t\t\tBiomeInfo.New<TechBiome>(Biome.Tech).Add(11, 1f).Add(12, 1f),\n\t\t\t\tBiomeInfo.New<CaveBiome>(Biome.Cave).Add(13, 1f),\n\t\t\t};\n\t\t\t\n\t\t\tforeach (var info in infos) {\n\t\t\t\tAdd(info);\n\t\t\t}\n\t\t\t\n\t\t\tBiomeInfo[] bossRushInfos = {\n\t\t\t\tBiomeInfo.New<CastleBiome>(Biome.Castle).Add(1, 1f),\n\t\t\t\tBiomeInfo.New<DesertBiome>(Biome.Desert).Add(2, 1f),\n\t\t\t\tBiomeInfo.New<JungleBiome>(Biome.Jungle).Add(3, 1f),\n\t\t\t\tBiomeInfo.New<IceBiome>(Biome.Ice).Add(4, 1f),\n\t\t\t\tBiomeInfo.New<LibraryBiome>(Biome.Library).Add(5, 1f)\n\t\t\t};\n\t\t\t\n\t\t\tforeach (var info in bossRushInfos) {\n\t\t\t\tAddBossRush(info);\n\t\t\t}\n\t\t}\n\n\t\tpublic static BiomeInfo Get(string id) {\n\t\t\treturn Defined[id];\n\t\t}\n\n\t\tpublic static BiomeInfo GenerateForDepth(int depth) {\n\t\t\tvar list = new List<BiomeInfo>();\n\t\t\tvar chances = new List<float>();\n\t\t\tvar array = Run.Type == RunType.BossRush && depth > 0 ? BossRushDefined : Defined;\n\n\t\t\tforeach (var b in array.Values) {\n\t\t\t\tif (b.Depths.Contains(depth)) {\n\t\t\t\t\tlist.Add(b);\n\t\t\t\t\tchances.Add(b.Chances[b.Depths.IndexOf(depth)]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar index = Rnd.Chances(chances);\n\n\t\t\tif (index == -1) {\n\t\t\t\tLog.Error($\"Failed to generate a biome for the depth {depth}\");\n\t\t\t\treturn array.Values.First();\n\t\t\t}\n\n\t\t\treturn list[index];\n\t\t}\n\t\t\n\t\tpublic static void Add(BiomeInfo info) {\n\t\t\tDefined[info.Id] = info;\n\t\t}\n\t\t\n\t\tpublic static void AddBossRush(BiomeInfo info) {\n\t\t\tBossRushDefined[info.Id] = info;\n\t\t}\n\n\t\tpublic static void Remove(string id) {\n\t\t\tDefined.Remove(id);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/CastleBiome.cs",
    "content": "﻿using BurningKnight.assets.particle.custom;\nusing BurningKnight.level.rooms.trap;\nusing BurningKnight.level.rooms.treasure;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.variant;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class CastleBiome : Biome {\n\t\tpublic CastleBiome() : base(\"Born to do rogueries\", Biome.Castle, \"castle_biome\", new Color(14, 7, 27)) {\n\t\t\n\t\t}\n\n\t\tpublic override string GetMusic() {\n\t\t\tif (Run.AlternateMusic) {\n\t\t\t\treturn \"chip\";\n\t\t\t}\n\n\t\t\treturn base.GetMusic();\n\t\t}\n\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\n\t\t\tbase.ModifyPainter(level, painter);\n\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (rm is TrapRoom) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar f = Run.Depth == 1;\n\t\t\t\t\n\t\t\t\tvar r = (byte) (f ? Tiles.RandomFloor() : Tile.Chasm);\n\t\t\t\t\n\t\t\t\tif (l.Get(x, y, true) == Tile.Lava || (!(rm is TreasureRoom) && f && l.Get(x, y) == Tile.Chasm)) {\n\t\t\t\t\tvar i = l.ToIndex(x, y);\n\t\t\t\t\t\n\t\t\t\t\tl.Liquid[i] = 0;\n\t\t\t\t\tl.Tiles[i] = r;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic override Tile GetFilling() {\n\t\t\treturn Run.Level.Variant.Id == LevelVariant.Gold ? Tile.WallB : base.GetFilling();\n\t\t}\n\n\t\tpublic override string GetStepSound(Tile tile) {\n\t\t\tif (tile == Tile.FloorB) {\n\t\t\t\treturn $\"player_step_wood_{Rnd.Int(1, 4)}\";\n\t\t\t}\n\t\t\t\n\t\t\treturn base.GetStepSound(tile);\n\t\t}\n\n\t\tpublic override int GetNumRegularRooms() {\n\t\t\treturn (int) (base.GetNumRegularRooms() * 2f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/CaveBiome.cs",
    "content": "using BurningKnight.assets.lighting;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class CaveBiome : Biome {\n\t\tpublic CaveBiome() : base(\"Cursed legend\", Biome.Cave, \"cave_biome\", new Color(61, 61, 61)) {}\n\n\t\tpublic override void Apply() {\n\t\t\tbase.Apply();\n\n\t\t\tvar v = 0f;\n\t\t\tLights.ClearColor = new Color(v, v, v, 1f);\n\t\t}\n\n\t\tpublic override bool HasBrekables() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasCobwebs() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HasPaintings() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasTorches() {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprivate static Color mapColor = new Color(61, 61, 61);\n\n\t\tpublic override Color GetMapColor() {\n\t\t\treturn mapColor;\n\t\t}\n\n\t\tpublic override bool HasPlants() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\n\t\t\tbase.ModifyPainter(level, painter);\n\n\t\t\tpainter.Grass = 0;\n\t\t\tpainter.Water = 0.1f;\n\t\t\tpainter.Dirt = 0.35f;\n\t\t\tpainter.Cobweb = 0.1f;\n\t\t}\n\n\t\tpublic override int GetNumSpecialRooms() {\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/DesertBiome.cs",
    "content": "using BurningKnight.level.rooms.trap;\r\nusing BurningKnight.level.tile;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.biome {\r\n\tpublic class DesertBiome : Biome {\r\n\t\tpublic DesertBiome() : base(\"Believer\", Biome.Desert, \"desert_biome\", new Color(28, 18, 28)) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\r\n\t\t\tbase.ModifyPainter(level, painter);\r\n\t\t\t\r\n\t\t\tpainter.Water = 0;\r\n\t\t\tpainter.Grass = 0;\r\n\t\t\tpainter.Dirt = 0.45f;\r\n\t\t\t\r\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\r\n\t\t\t\tif (l.Get(x, y, true).Matches(Tile.Dirt, Tile.Lava)) {\r\n\t\t\t\t\tl.Set(x, y, Tile.Sand);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n\t\t/*public override void ModifyRooms(List<RoomDef> rooms) {\r\n\t\t\tbase.ModifyRooms(rooms);\r\n\t\t\trooms.Add(new DesertWellRoom());\r\n\t\t}*/\r\n\t\t\r\n\t\tprivate static Color mapColor = new Color(191, 111, 74);\r\n\r\n\t\tpublic override Color GetMapColor() {\r\n\t\t\treturn mapColor;\r\n\t\t}\r\n\r\n\t\tpublic override string GetItemUnlock() {\r\n\t\t\treturn \"bk:fire_ring\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/biome/HubBiome.cs",
    "content": "using BurningKnight.level.tile;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.biome {\r\n\tpublic class HubBiome : Biome {\r\n\t\tpublic HubBiome() : base(\"Outsider\", Biome.Hub, Events.Halloween ? \"spooky_biome\" : (Events.XMas ? \"xmas_biome\" : \"hub_biome\"), new Color(30, 111, 80)) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\r\n\t\t\tbase.ModifyPainter(level, painter);\r\n\r\n\t\t\tpainter.Fireflies = 10;\r\n\t\t\tpainter.FirefliesChance = 100f;\r\n\t\t}\r\n\r\n\t\tpublic override string GetStepSound(Tile tile) {\r\n\t\t\tif (tile == Tile.FloorB) {\r\n\t\t\t\treturn $\"player_step_wood_{Rnd.Int(1, 4)}\";\r\n\t\t\t} else if (tile == Tile.FloorD) {\r\n\t\t\t\treturn $\"player_step_grass_{Rnd.Int(1, 4)}\";\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.GetStepSound(tile);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/biome/IceBiome.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class IceBiome : Biome {\n\t\tpublic IceBiome() : base(\"Frozen to the bones\", Biome.Ice, \"ice_biome\", new Color(146, 161, 185)) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Apply() {\n\t\t\tbase.Apply();\n\n\t\t\tLights.ClearColor = new Color(0.2f, 0.45f, 1f, 1f);\n\t\t}\n\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\n\t\t\tbase.ModifyPainter(level, painter);\n\n\t\t\tpainter.Grass = 0;\n\t\t\tpainter.Water = 0.45f;\n\t\t\tpainter.Dirt = 0.45f;\n\t\t\tpainter.Cobweb = 0;\n\n\t\t\tpainter.DirtTile = Tile.Snow;\n\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (l.Get(x, y, true) == Tile.Water) {\n\t\t\t\t\tl.Set(x, y, Tile.Ice);\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tvar r = (byte) (Tiles.RandomFloor());\n\t\t\t\t\n\t\t\t\tif (l.Get(x, y, true) == Tile.Lava) {\n\t\t\t\t\tvar i = l.ToIndex(x, y);\n\t\t\t\t\t\n\t\t\t\t\tl.Liquid[i] = 0;\n\t\t\t\t\tl.Tiles[i] = r;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (l.Get(x, y, true) == Tile.Dirt) {\n\t\t\t\t\tl.Set(x, y, Tile.Snow);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic override string GetStepSound(Tile tile) {\n\t\t\tif (tile == Tile.FloorA || tile == Tile.FloorC) {\n\t\t\t\treturn $\"player_step_snow_{Rnd.Int(1, 4)}\";\n\t\t\t} else if (tile == Tile.FloorB) {\n\t\t\t\treturn $\"player_step_wood_{Rnd.Int(1, 4)}\";\n\t\t\t}\n\t\t\t\n\t\t\treturn base.GetStepSound(tile);\n\t\t}\n\n\t\tpublic override bool HasPaintings() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasBrekables() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HasCobwebs() {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprivate static Color mapColor = new Color(146, 161, 185);\n\n\t\tpublic override Color GetMapColor() {\n\t\t\treturn mapColor;\n\t\t}\n\n\t\tpublic override int GetNumRegularRooms() {\n\t\t\treturn (int) (base.GetNumRegularRooms() * 0.7f);\n\t\t}\n\n\t\tpublic override string GetItemUnlock() {\n\t\t\treturn \"bk:ice_ring\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/JungleBiome.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.trap;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.biome {\n\tpublic class JungleBiome : Biome {\n\t\tpublic JungleBiome() : base(\"Botanical Expedition\", Biome.Jungle, \"jungle_biome\", new Color(30, 111, 80)) {}\n\n\t\tpublic override void Apply() {\n\t\t\tbase.Apply();\n\n\t\t\tvar v = 0.5f;\n\t\t\tLights.ClearColor = new Color(v, v, v, 1f);\n\t\t}\n\n\t\tpublic override void ModifyRooms(List<RoomDef> rooms) {\n\t\t\tbase.ModifyRooms(rooms);\n\n\t\t\tif (Run.Type == RunType.BossRush) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\trooms.Add(new HiveRoom());\n\n\t\t\tfor (var i = 0; i < (Run.Depth % 2 == 0 ? 2 : 1); i++) {\n\t\t\t\trooms.Add(new JungleRoom());\n\t\t\t}\n\t\t}\n\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\n\t\t\tbase.ModifyPainter(level, painter);\n\n\t\t\tpainter.Water = 0.4f;\n\t\t\tpainter.Grass = 0.4f;\n\t\t\tpainter.Dirt = 0f;\n\t\t\tpainter.Cobweb = 0f;\n\t\t\tpainter.Fireflies = 4;\n\t\t\tpainter.FirefliesChance = 100;\n\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (rm is TrapRoom) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar f = Tiles.RandomFloor();\n\t\t\t\t\n\t\t\t\tif (l.Get(x, y, true) == Tile.Lava || l.Get(x, y).Matches(Tile.Chasm, Tile.SpikeOffTmp, Tile.SpikeOnTmp, Tile.SensingSpikeTmp, Tile.FireTrapTmp)) {\n\t\t\t\t\tvar i = l.ToIndex(x, y);\n\t\t\t\t\t\n\t\t\t\t\tl.Liquid[i] = 0;\n\t\t\t\t\tl.Tiles[i] = (byte) f;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic override int GetNumRegularRooms() {\n\t\t\treturn (int) (base.GetNumRegularRooms() * 0.25f);\n\t\t}\n\t\t\n\t\tpublic override int GetNumTrapRooms() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override bool HasTorches() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool SpawnAllMobs() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HasPaintings() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasTnt() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasCobwebs() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasBrekables() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HasPlants() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override bool HasTrees() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override string GetStepSound(Tile tile) {\n\t\t\tif (tile == Tile.FloorA || tile == Tile.FloorC) {\n\t\t\t\treturn $\"player_step_sand_{Rnd.Int(1, 4)}\";\n\t\t\t}\n\t\t\t\n\t\t\treturn base.GetStepSound(tile);\n\t\t}\n\t\t\n\t\tprivate static Color mapColor = new Color(51, 152, 75);\n\n\t\tpublic override Color GetMapColor() {\n\t\t\treturn mapColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/biome/LibraryBiome.cs",
    "content": "using System.Collections.Generic;\r\nusing BurningKnight.level.builders;\r\nusing BurningKnight.level.rooms;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.state;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.biome {\r\n\tpublic class LibraryBiome : Biome {\r\n\t\tpublic LibraryBiome() : base(\"Hidden knowledge\", Biome.Library, \"library_biome\", new Color(28, 18, 28)) {\r\n\t\t}\r\n\r\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\r\n\t\t\tbase.ModifyPainter(level, painter);\r\n\r\n\t\t\tpainter.Grass = 0;\r\n\t\t\tpainter.Water = 0;\r\n\t\t\tpainter.Dirt = 0;\r\n\t\t\tpainter.Cobweb = 0.3f;\r\n\t\t\t\r\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\r\n\t\t\t\tvar r = (byte) (Tiles.RandomFloor());\r\n\t\t\t\tvar t = l.Get(x, y, true);\r\n\t\t\t\t\r\n\t\t\t\tif (t == Tile.Lava) {\r\n\t\t\t\t\tvar i = l.ToIndex(x, y);\r\n\t\t\t\t\t\r\n\t\t\t\t\tl.Liquid[i] = 0;\r\n\t\t\t\t\tl.Tiles[i] = r;\r\n\t\t\t\t} else if (t.IsRock() || t == Tile.MetalBlock) {\r\n\t\t\t\t\tvar i = l.ToIndex(x, y);\r\n\r\n\t\t\t\t\tl.Liquid[i] = 0;\r\n\t\t\t\t\tl.Tiles[i] = (byte) Tile.Chasm;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\t\t\t\r\n\r\n\t\tpublic override int GetNumRegularRooms() {\r\n\t\t\treturn (int) (base.GetNumRegularRooms() * 1.4f);\r\n\t\t}\r\n\r\n\t\tpublic override Builder GetBuilder() {\r\n\t\t\tvar builder = new LoopBuilder().SetShape(2,\r\n\t\t\t\tRnd.Float(0.4f, 0.7f),\r\n\t\t\t\tRnd.Float(0f, 0.5f));\r\n\r\n\t\t\treturn builder;\r\n\t\t}\r\n\r\n\t\tpublic override string GetStepSound(Tile tile) {\r\n\t\t\tif (tile == Tile.FloorA || tile == Tile.FloorC) {\r\n\t\t\t\treturn $\"player_step_wood_{Rnd.Int(1, 4)}\";\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.GetStepSound(tile);\r\n\t\t}\r\n\t\t\r\n\t\tprivate static Color mapColor = new Color(138, 72, 54);\r\n\r\n\t\tpublic override Color GetMapColor() {\r\n\t\t\treturn mapColor;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/biome/TechBiome.cs",
    "content": "using BurningKnight.level.builders;\r\nusing BurningKnight.level.rooms.trap;\r\nusing BurningKnight.level.rooms.treasure;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.state;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.biome {\r\n\tpublic class TechBiome: Biome {\r\n\t\tpublic TechBiome() : base(\"Pirate Bay\", Biome.Tech, \"tech_biome\", new Color(27, 27, 27)) {\r\n\t\t\r\n\t\t}\r\n\r\n\t\tpublic override void ModifyPainter(Level level, Painter painter) {\r\n\t\t\tbase.ModifyPainter(level, painter);\r\n\r\n\t\t\tpainter.Grass = 0;\r\n\t\t\tpainter.Water = 0;\r\n\t\t\tpainter.Dirt = 0;\r\n\t\t\tpainter.Cobweb = 0;\r\n\t\t\r\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\r\n\t\t\t\tif (rm is TrapRoom) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (l.Get(x, y, true) == Tile.Lava) {\r\n\t\t\t\t\tvar i = l.ToIndex(x, y);\r\n\t\t\t\t\t\r\n\t\t\t\t\tl.Liquid[i] = 0;\r\n\t\t\t\t\tl.Tiles[i] = (byte) Tile.Chasm;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic override bool HasTorches() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tpublic override bool HasPaintings() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tpublic override bool HasBrekables() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tpublic override int GetNumRegularRooms() {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tpublic override int GetNumSecretRooms() {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tpublic override int GetNumSpecialRooms() {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tpublic override int GetNumTrapRooms() {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tpublic override Builder GetBuilder() {\r\n\t\t\treturn new LoopBuilder();\r\n\t\t}\r\n\r\n\t\tpublic override bool HasCobwebs() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tpublic override bool HasTnt() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/builders/Builder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.builders {\n\tpublic class Builder {\n\t\tprivate const double A = 180 / Math.PI;\n\n\t\tprotected static void FindNeighbours(List<RoomDef> Rooms) {\n\t\t\tfor (var I = 0; I < Rooms.Count - 1; I++) {\n\t\t\t\tfor (var J = I + 1; J < Rooms.Count; J++) {\n\t\t\t\t\tRooms[I].ConnectTo(Rooms[J]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected static Rect FindFreeSpace(Vector2 Start, List<RoomDef> Collision, int MaxSize) {\n\t\t\tvar Space = new Rect((int) (Start.X - MaxSize), (int) (Start.Y - MaxSize), (int) (Start.X + MaxSize), (int) (Start.Y + MaxSize));\n\t\t\tvar Colliding = new List<RoomDef>(Collision);\n\n\t\t\tdo {\n\t\t\t\tfor (var I = Colliding.Count - 1; I >= 0; I--) {\n\t\t\t\t\tvar Room = Colliding[I];\n\n\t\t\t\t\tif (Room.IsEmpty() || Math.Max(Space.Left, Room.Left) >= Math.Min(Space.Right, Room.Right) || Math.Max(Space.Top, Room.Top) >= Math.Min(Space.Bottom, Room.Bottom)) {\n\t\t\t\t\t\tColliding.RemoveAt(I);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tRoomDef closestRoomDef = null;\n\t\t\t\tvar ClosestDiff = int.MaxValue;\n\t\t\t\tvar Inside = true;\n\t\t\t\tvar CurDiff = 0;\n\n\t\t\t\tforeach (var CurRoom in Colliding) {\n\t\t\t\t\tif (Start.X <= CurRoom.Left) {\n\t\t\t\t\t\tInside = false;\n\t\t\t\t\t\tCurDiff += CurRoom.Left - (int) Start.X;\n\t\t\t\t\t} else if (Start.X >= CurRoom.Right) {\n\t\t\t\t\t\tInside = false;\n\t\t\t\t\t\tCurDiff += (int) Start.X - CurRoom.Right;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Start.Y <= CurRoom.Top) {\n\t\t\t\t\t\tInside = false;\n\t\t\t\t\t\tCurDiff += CurRoom.Top - (int) Start.Y;\n\t\t\t\t\t} else if (Start.Y >= CurRoom.Bottom) {\n\t\t\t\t\t\tInside = false;\n\t\t\t\t\t\tCurDiff += (int) Start.Y - CurRoom.Bottom;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Inside) {\n\t\t\t\t\t\tSpace.Set(new Rect((int) Start.X, (int) Start.Y, (int) Start.X, (int) Start.Y));\n\t\t\t\t\t\treturn Space;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (CurDiff < ClosestDiff) {\n\t\t\t\t\t\tClosestDiff = CurDiff;\n\t\t\t\t\t\tclosestRoomDef = CurRoom;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tint WDiff;\n\t\t\t\tint HDiff;\n\n\t\t\t\tif (closestRoomDef != null) {\n\t\t\t\t\tWDiff = Int32.MaxValue;\n\n\t\t\t\t\tif (closestRoomDef.Left >= Start.X) {\n\t\t\t\t\t\tWDiff = (Space.Right - closestRoomDef.Left) * (Space.GetHeight() + 1);\n\t\t\t\t\t} else if (closestRoomDef.Right <= Start.X) {\n\t\t\t\t\t\tWDiff = (closestRoomDef.Right - Space.Left) * (Space.GetHeight() + 1);\n\t\t\t\t\t}\n\n\t\t\t\t\tHDiff = Int32.MaxValue;\n\n\t\t\t\t\tif (closestRoomDef.Top >= Start.Y) {\n\t\t\t\t\t\tHDiff = (Space.Bottom - closestRoomDef.Top) * (Space.GetWidth() + 1);\n\t\t\t\t\t} else if (closestRoomDef.Bottom <= Start.Y) {\n\t\t\t\t\t\tHDiff = (closestRoomDef.Bottom - Space.Top) * (Space.GetWidth() + 1);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (WDiff < HDiff || WDiff == HDiff && Rnd.Int(2) == 0) {\n\t\t\t\t\t\tif (closestRoomDef.Left >= Start.X && closestRoomDef.Left < Space.Right) {\n\t\t\t\t\t\t\tSpace.Right = closestRoomDef.Left;\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif (closestRoomDef.Right <= Start.X && closestRoomDef.Right > Space.Left) {\n\t\t\t\t\t\t\tSpace.Left = closestRoomDef.Right;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (closestRoomDef.Top >= Start.Y && closestRoomDef.Top < Space.Bottom) {\n\t\t\t\t\t\t\tSpace.Bottom = closestRoomDef.Top;\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif (closestRoomDef.Bottom <= Start.Y && closestRoomDef.Bottom > Space.Top) {\n\t\t\t\t\t\t\tSpace.Top = closestRoomDef.Bottom;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\n\t\t\t\t\tColliding.Remove(closestRoomDef);\n\t\t\t\t} else {\n\t\t\t\t\tColliding.Clear();\n\t\t\t\t}\n\t\t\t} while (Colliding.Count != 0);\n\n\t\t\treturn Space;\n\t\t}\n\n\t\tprotected static float AngleBetweenRooms(RoomDef From, RoomDef To) {\n\t\t\tvar FromCenter = new Vector2((From.Left + From.Right) / 2f, (From.Top + From.Bottom) / 2f);\n\t\t\tvar ToCenter = new Vector2((To.Left + To.Right) / 2f, (To.Top + To.Bottom) / 2f);\n\n\t\t\treturn AngleBetweenPoints(FromCenter, ToCenter);\n\t\t}\n\n\t\tprotected static float AngleBetweenPoints(Vector2 From, Vector2 To) {\n\t\t\tdouble M = (To.Y - From.Y) / (To.X - From.X);\n\t\t\tvar Angle = (float) (A * (Math.Atan(M) + Math.PI / 2.0));\n\n\t\t\tif (From.X > To.X) {\n\t\t\t\tAngle -= 180f;\n\t\t\t}\n\n\t\t\treturn Angle;\n\t\t}\n\n\t\tprotected Rect LastSpace;\n\t\t\n\t\tprotected virtual float PlaceRoom(List<RoomDef> Collision, RoomDef Prev, RoomDef Next, float Angle) {\n\t\t\tLastSpace = null;\n\t\t\t\n\t\t\tif (Next == null) {\n\t\t\t\tLog.Error(\"Null next room\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t\n\t\t\tAngle %= 360f;\n\n\t\t\tif (Angle < 0) {\n\t\t\t\tAngle += 360f;\n\t\t\t}\n\n\t\t\tvar PrevCenter = new Vector2((Prev.Left + Prev.Right) / 2f, (Prev.Top + Prev.Bottom) / 2f);\n\t\t\tvar M = Math.Tan(Angle / A + Math.PI / 2.0);\n\t\t\tvar B = PrevCenter.Y - M * PrevCenter.X;\n\t\t\tVector2 Start;\n\t\t\tRoomDef.Connection Direction;\n\n\t\t\tif (Math.Abs(M) >= 1) {\n\t\t\t\tif (Angle < 90 || Angle > 270) {\n\t\t\t\t\tDirection = RoomDef.Connection.Top;\n\t\t\t\t\tStart = new Vector2((int) Math.Round((Prev.Top - B) / M), Prev.Top);\n\t\t\t\t} else {\n\t\t\t\t\tDirection = RoomDef.Connection.Bottom;\n\t\t\t\t\tStart = new Vector2((int) Math.Round((Prev.Bottom - B) / M), Prev.Bottom);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Angle < 180) {\n\t\t\t\t\tDirection = RoomDef.Connection.Right;\n\t\t\t\t\tStart = new Vector2(Prev.Right, (int) Math.Round(M * Prev.Right + B));\n\t\t\t\t} else {\n\t\t\t\t\tDirection = RoomDef.Connection.Left;\n\t\t\t\t\tStart = new Vector2(Prev.Left, (int) Math.Round(M * Prev.Left + B));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Direction == RoomDef.Connection.Top || Direction == RoomDef.Connection.Bottom) {\n\t\t\t\tStart.X = (int) MathUtils.Clamp(Prev.Left + 1, Prev.Right - 1, Start.X);\n\t\t\t} else {\n\t\t\t\tStart.Y = (int) MathUtils.Clamp(Prev.Top + 1, Prev.Bottom - 1, Start.Y);\n\t\t\t}\n\n\t\t\tvar Space = LastSpace = FindFreeSpace(Start, Collision, Math.Max(Next.GetMaxWidth(), Next.GetMaxHeight()));\n\n\t\t\tif (!Next.SetSizeWithLimit(Space.GetWidth() + 1, Space.GetHeight() + 1)) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tvar TargetCenter = new Dot();\n\n\t\t\tif (Direction == RoomDef.Connection.Top) {\n\t\t\t\tTargetCenter.Y = (int) (Prev.Top - (Next.GetHeight() - 1) / 2f);\n\t\t\t\tTargetCenter.X = (int) ((TargetCenter.Y - B) / M);\n\t\t\t\tNext.SetPos((int) Math.Round(TargetCenter.X - (Next.GetWidth() - 1) / 2f), Prev.Top - (Next.GetHeight() - 1));\n\t\t\t} else if (Direction == RoomDef.Connection.Bottom) {\n\t\t\t\tTargetCenter.Y = (int) (Prev.Bottom + (Next.GetHeight() - 1) / 2f);\n\t\t\t\tTargetCenter.X = (int) ((TargetCenter.Y - B) / M);\n\t\t\t\tNext.SetPos((int) Math.Round(TargetCenter.X - (Next.GetWidth() - 1) / 2f), Prev.Bottom);\n\t\t\t} else if (Direction == RoomDef.Connection.Right) {\n\t\t\t\tTargetCenter.X = (int) (Prev.Right + (Next.GetWidth() - 1) / 2f);\n\t\t\t\tTargetCenter.Y = (int) (M * TargetCenter.X + B);\n\t\t\t\tNext.SetPos(Prev.Right, (int) Math.Round(TargetCenter.Y - (Next.GetHeight() - 1) / 2f));\n\t\t\t} else if (Direction == RoomDef.Connection.Left) {\n\t\t\t\tTargetCenter.X = (int) (Prev.Left - (Next.GetWidth() - 1) / 2f);\n\t\t\t\tTargetCenter.Y = (int) (M * TargetCenter.X + B);\n\t\t\t\tNext.SetPos(Prev.Left - (Next.GetWidth() - 1), (int) Math.Round(TargetCenter.Y - (Next.GetHeight() - 1) / 2f));\n\t\t\t}\n\n\t\t\tif (Direction == RoomDef.Connection.Top || Direction == RoomDef.Connection.Bottom) {\n\t\t\t\tif (Next.Right < Prev.Left + 2) {\n\t\t\t\t\tNext.Shift(Prev.Left + 2 - Next.Right, 0);\n\t\t\t\t} else if (Next.Left > Prev.Right - 2) {\n\t\t\t\t\tNext.Shift(Prev.Right - 2 - Next.Left, 0);\n\t\t\t\t}\n\n\t\t\t\tif (Next.Right > Space.Right) {\n\t\t\t\t\tNext.Shift(Space.Right - Next.Right, 0);\n\t\t\t\t} else if (Next.Left < Space.Left) {\n\t\t\t\t\tNext.Shift(Space.Left - Next.Left, 0);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Next.Bottom < Prev.Top + 2) {\n\t\t\t\t\tNext.Shift(0, Prev.Top + 2 - Next.Bottom);\n\t\t\t\t} else if (Next.Top > Prev.Bottom - 2) {\n\t\t\t\t\tNext.Shift(0, Prev.Bottom - 2 - Next.Top);\n\t\t\t\t}\n\n\t\t\t\tif (Next.Bottom > Space.Bottom) {\n\t\t\t\t\tNext.Shift(0, Space.Bottom - Next.Bottom);\n\t\t\t\t} else if (Next.Top < Space.Top) {\n\t\t\t\t\tNext.Shift(0, Space.Top - Next.Top);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Next.ConnectWithRoom(Prev)) {\n\t\t\t\tif (Next is ConnectionRoom || Next is BossRoom || Next is ShopRoom) {\n\t\t\t\t\tNext.Id = Prev.Id;\n\t\t\t\t} else {\n\t\t\t\t\tNext.Id = Prev.Id + 1;\n\t\t\t\t}\n\n\n\t\t\t\treturn AngleBetweenRooms(Prev, Next);\n\t\t\t}\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tpublic virtual List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/CastleBuilder.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.rooms;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.builders {\n\tpublic class CastleBuilder : RegularBuilder {\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\tSetupRooms(Init);\n\n\t\t\tif (Entrance == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar Branchable = new List<RoomDef>();\n\t\t\tEntrance.SetSize();\n\t\t\tEntrance.SetPos(0, 0);\n\t\t\t\n\t\t\tBranchable.Add(Entrance);\n\t\t\tvar RoomsToBranch = new List<RoomDef>(MultiConnection);\n\n\t\t\tif (Exit != null) {\n\t\t\t\tRoomsToBranch.Add(Exit);\n\t\t\t}\n\n\t\t\tRoomsToBranch.AddRange(SingleConnection);\n\n\t\t\tif (!CreateBranches(Init, Branchable, RoomsToBranch, BranchTunnelChances)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar a = Rnd.Angle() - 90;\n\t\t\tvar i = 0;\n\n\t\t\tif (Boss != null) {\n\t\t\t\twhile (true) {\n\t\t\t\t\tvar an = PlaceRoom(Init, Exit, Boss, a);\n\n\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\ti++;\n\n\t\t\t\t\tif (i > 36) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\ta += 10;\n\t\t\t\t}\n\n\t\t\t\ta = Rnd.Angle();\n\t\t\t\ti = 0;\n\n\t\t\t\tif (Granny != null) {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tvar an = PlaceRoom(Init, Boss, Granny, a);\n\n\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ta += 5;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ta = Rnd.Angle();\n\t\t\t\ti = 0;\n\n\t\t\t\tif (OldMan != null) {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tvar an = PlaceRoom(Init, Boss, OldMan, a);\n\n\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ta += 5;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tFindNeighbours(Init);\n\n\t\t\tforeach (RoomDef R in Init) {\n\t\t\t\tforeach (RoomDef N in R.Neighbours) {\n\t\t\t\t\tif (!N.Connected.ContainsKey(R) && Rnd.Float() < ExtraConnectionChance) {\n\t\t\t\t\t\tR.ConnectWithRoom(N);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Init;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/InfinityBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.rooms;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.builders {\n\tpublic class InfinityBuilder : RegularBuilder {\n\t\tprivate RoomDef landmarkRoom;\n\t\tprivate int curveExponent;\n    private float curveIntensity = 1;\n    private float curveOffset;\n    \n    \n\t\tprivate List<RoomDef> firstLoop;\n\t\tprivate List<RoomDef> secondLoop;\n\t\tprivate Vector2 firstLoopCenter;\n\t\tprivate Vector2 secondLoopCenter;\n    \n    public InfinityBuilder SetLoopShape(int exponent, float intensity, float offset){\n    \tcurveExponent = Math.Abs(exponent);\n    \tcurveIntensity = intensity % 1f;\n    \tcurveOffset = offset % 0.5f;\n    \treturn this;\n    }\n\t\t\n\t\tprivate float getTargetAngle(float percentAlong){\n\t\t\tpercentAlong += curveOffset;\n\t\t\treturn 360f * (float)(\n\t\t\t\t       curveIntensity * curveEquation(percentAlong)\n\t\t\t\t       + (1-curveIntensity)*(percentAlong)\n\t\t\t\t       - curveOffset);\n\t\t}\n\t\t\n\t\tprivate double curveEquation(double x){\n\t\t\treturn Math.Pow(4, 2*curveExponent)\n\t\t\t       *(Math.Pow((x % 0.5f )-0.25, 2*curveExponent + 1))\n\t\t\t       + 0.25 + 0.5*Math.Floor(2*x);\n\t\t}\n\t\t\n\t\tpublic override List<RoomDef> Build(List<RoomDef> rooms) {\n\t\t\tSetupRooms(rooms);\n\t\t\t\n\t\t\tif (landmarkRoom == null) {\n\t\t\t\tlandmarkRoom = MultiConnection[Rnd.Int(MultiConnection.Count)];\n\t\t\t}\n\t\t\t\n\t\t\tif (MultiConnection.Contains(landmarkRoom)){\n\t\t\t\tMultiConnection.Remove(landmarkRoom);\n\t\t\t}\n\t\t\t\n\t\t\tvar startAngle = Rnd.Float(0, 180);\n\t\t\t\n\t\t\tvar roomsOnLoop = (int) (MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);\n\t\t\troomsOnLoop = Math.Min(roomsOnLoop, MultiConnection.Count);\n\t\t\t\n\t\t\tvar roomsOnFirstLoop = roomsOnLoop / 2;\n\n\t\t\tif (roomsOnLoop % 2 == 1) {\n\t\t\t\troomsOnFirstLoop += Rnd.Int(2);\n\t\t\t}\n\t\t\t\n\t\t\tfirstLoop = new List<RoomDef>();\n\t\t\tvar pathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\t\t\t\n\t\t\tfor (var i = 0; i <= roomsOnFirstLoop; i++){\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tfirstLoop.Add(landmarkRoom);\n\t\t\t\t} else {\n\t\t\t\t\tfirstLoop.Add(MultiConnection[0]);\n\t\t\t\t\tMultiConnection.RemoveAt(0);\n\t\t\t\t}\n\n\t\t\t\tvar tunnels = Rnd.Chances(pathTunnels);\n\t\t\t\t\n\t\t\t\tif (tunnels == -1){\n\t\t\t\t\tpathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\t\t\t\t\ttunnels = Rnd.Chances(pathTunnels);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tpathTunnels[tunnels]--;\n\t\t\t\t\n\t\t\t\tfor (var j = 0; j < tunnels; j++){\n\t\t\t\t\tfirstLoop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Entrance != null) {\n\t\t\t\tfirstLoop.Insert((firstLoop.Count + 1) / 2, Entrance);\n\t\t\t}\n\t\t\t\n\t\t\tvar roomsOnSecondLoop = roomsOnLoop - roomsOnFirstLoop;\n\t\t\tsecondLoop = new List<RoomDef>();\n\t\t\t\n\t\t\tfor (var i = 0; i <= roomsOnSecondLoop; i++){\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tsecondLoop.Add(landmarkRoom);\n\t\t\t\t} else {\n\t\t\t\t\tsecondLoop.Add(MultiConnection[0]);\n\t\t\t\t\tMultiConnection.RemoveAt(0);\n\t\t\t\t}\n\n\t\t\t\tvar tunnels = Rnd.Chances(pathTunnels);\n\t\t\t\t\n\t\t\t\tif (tunnels == -1){\n\t\t\t\t\tpathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\t\t\t\t\ttunnels = Rnd.Chances(pathTunnels);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tpathTunnels[tunnels]--;\n\t\t\t\t\n\t\t\t\tfor (var j = 0; j < tunnels; j++){\n\t\t\t\t\tsecondLoop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Exit != null) {\n\t\t\t\tsecondLoop.Insert((secondLoop.Count + 1) / 2, Exit);\n\t\t\t}\n\t\t\t\n\t\t\tlandmarkRoom.SetSize();\n\t\t\tlandmarkRoom.SetPos(0, 0);\n\t\t\t\n\t\t\tvar prev = landmarkRoom;\n\t\t\tfloat targetAngle;\n\t\t\t\n\t\t\tfor (var i = 1; i < firstLoop.Count; i++){\n\t\t\t\tvar r = firstLoop[i];\n\t\t\t\ttargetAngle = startAngle + getTargetAngle(i / (float) firstLoop.Count);\n\t\t\t\t\n\t\t\t\tif ((int) PlaceRoom(rooms, prev, r, targetAngle) != -1) {\n\t\t\t\t\tprev = r;\n\n\t\t\t\t\tif (!rooms.Contains(prev)) {\n\t\t\t\t\t\trooms.Add(prev);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\twhile (!prev.ConnectWithRoom(landmarkRoom)){\n\t\t\t\tvar c = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);\n\n\t\t\t\tif ((int) PlaceRoom(rooms, prev, c, AngleBetweenRooms(prev, landmarkRoom)) == -1){\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfirstLoop.Add(c);\n\t\t\t\trooms.Add(c);\n\t\t\t\tprev = c;\n\t\t\t}\n\t\t\t\n\t\t\tprev = landmarkRoom;\n\t\t\tstartAngle += 180f;\n\t\t\t\n\t\t\t/*for (var i = 1; i < secondLoop.Count; i++){\n\t\t\t\tvar r = secondLoop[i];\n\t\t\t\ttargetAngle = startAngle + getTargetAngle(i / (float)secondLoop.Count);\n\t\t\t\t\n\t\t\t\tif ((int) PlaceRoom(rooms, prev, r, targetAngle) != -1) {\n\t\t\t\t\tprev = r;\n\n\t\t\t\t\tif (!rooms.Contains(prev)) {\n\t\t\t\t\t\trooms.Add(prev);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\twhile (!prev.ConnectWithRoom(landmarkRoom)) {\n\t\t\t\tvar c = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);\n\t\t\t\t\n\t\t\t\tif ((int) PlaceRoom(rooms, prev, c, AngleBetweenRooms(prev, landmarkRoom)) == -1){\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsecondLoop.Add(c);\n\t\t\t\trooms.Add(c);\n\t\t\t\tprev = c;\n\t\t\t}*/\n\t\t\t\n\t\t\tfirstLoopCenter = new Vector2();\n\t\t\t\n\t\t\tforeach (var r in firstLoop) {\n\t\t\t\tfirstLoopCenter.X += (r.Left + r.Right) / 2f;\n\t\t\t\tfirstLoopCenter.Y += (r.Top + r.Bottom) / 2f;\n\t\t\t}\n\t\t\t\n\t\t\tfirstLoopCenter.X /= firstLoop.Count;\n\t\t\tfirstLoopCenter.Y /= firstLoop.Count;\n\t\t\t\n\t\t\tsecondLoopCenter = new Vector2();\n\t\t\t\n\t\t\tforeach (var r in secondLoop) {\n\t\t\t\tsecondLoopCenter.X += (r.Left + r.Right) / 2f;\n\t\t\t\tsecondLoopCenter.Y += (r.Top + r.Bottom) / 2f;\n\t\t\t}\n\t\t\t\n\t\t\tsecondLoopCenter.X /= secondLoop.Count;\n\t\t\tsecondLoopCenter.Y /= secondLoop.Count;\n\t\t\t\n\t\t\tvar branchable = new List<RoomDef>(firstLoop);\n\t\t\tbranchable.AddRange(secondLoop);\n\t\t\tbranchable.Remove(landmarkRoom);\n\t\t\t\n\t\t\tvar roomsToBranch = new List<RoomDef>();\n\t\t\troomsToBranch.AddRange(MultiConnection);\n\t\t\troomsToBranch.AddRange(SingleConnection);\n\t\t\tWeightRooms(branchable);\n\t\t\tCreateBranches(rooms, branchable, roomsToBranch, BranchTunnelChances);\n\t\t\t\n\t\t\tFindNeighbours(rooms);\n\t\t\t\n\t\t\tforeach (var r in rooms) {\n\t\t\t\tforeach (var n in r.Neighbours) {\n\t\t\t\t\tif (!n.Connected.ContainsKey(r) && Rnd.Float() < ExtraConnectionChance){\n\t\t\t\t\t\tr.ConnectWithRoom(n);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn rooms;\n\t\t}\n\t\t\n\t\tprotected override float RandomBranchAngle( RoomDef r ) {\n\t\t\tVector2 center;\n\t\t\t\n\t\t\tif (firstLoop.Contains(r)){\n\t\t\t\tcenter = firstLoopCenter;\n\t\t\t} else {\n\t\t\t\tcenter = secondLoopCenter;\n\t\t\t}\n\t\t\t\n\t\t\tfloat toCenter = AngleBetweenPoints( new Vector2((r.Left + r.Right)/2f, (r.Top + r.Bottom)/2f), center);\n\n\t\t\tif (toCenter < 0) {\n\t\t\t\ttoCenter += 360f;\n\t\t\t}\n\t\t\n\t\t\tfloat currAngle = Rnd.Float(360f);\n\t\t\t\n\t\t\tfor(var i = 0; i < 4; i ++){\n\t\t\t\tfloat newAngle = Rnd.Float(360f);\n\t\t\t\tif (Math.Abs(toCenter - newAngle) < Math.Abs(toCenter - currAngle)){\n\t\t\t\t\tcurrAngle = newAngle;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn currAngle;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/LineBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.rooms;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.builders {\n\tpublic class LineBuilder : RegularBuilder {\n\t\tprivate float Direction;\n\n\t\tpublic LineBuilder() {\n\t\t\tDirection = Rnd.Angle();\n\t\t}\n\t\t\n\t\tpublic LineBuilder SetAngle(float Angle) {\n\t\t\tDirection = Angle % 360f;\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate bool PlaceBoss(List<RoomDef> Init, RoomDef R) {\n\t\t\tvar a = Direction;\n\t\t\tvar i = 0;\n\t\t\t\t\t\t\n\t\t\twhile (true) {\n\t\t\t\tvar an = PlaceRoom(Init, R, Boss, a);\n\t\t\t\t\t\t\t\n\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\ti++;\n\n\t\t\t\tif (i > 36) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\ta += 10;\n\t\t\t}\n\n\t\t\tif (Granny != null) {\n\t\t\t\ta = Rnd.Angle();\n\t\t\t\ti = 0;\n\n\t\t\t\twhile (true) {\n\t\t\t\t\tvar an = PlaceRoom(Init, Boss, Granny, a);\n\n\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\ti++;\n\n\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\ta += 5;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (OldMan != null) {\n\t\t\t\ta = Rnd.Angle();\n\t\t\t\ti = 0;\n\n\t\t\t\twhile (true) {\n\t\t\t\t\tvar an = PlaceRoom(Init, Boss, OldMan, a);\n\n\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\ti++;\n\n\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\ta += 5;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\tSetupRooms(Init);\n\n\t\t\tif (Entrance == null) {\n\t\t\t\tLog.Error(\"No entrance!\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar Branchable = new List<RoomDef>();\n\t\t\t\n\t\t\tEntrance.SetSize();\n\t\t\tEntrance.SetPos(0, 0);\n\t\t\tBranchable.Add(Entrance);\n\n\t\t\tif (MultiConnection.Count == 0) {\n\t\t\t\tPlaceRoom(Init, Entrance, Exit, Rnd.Angle());\n\n\t\t\t\tif (Boss != null && !PlaceBoss(Init, Exit)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn Init;\n\t\t\t}\n\n\t\t\tvar RoomsOnPath = (int) (MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);\n\t\t\tRoomsOnPath = Math.Min(RoomsOnPath, MultiConnection.Count);\n\t\t\tRoomDef Curr = Entrance;\n\t\t\tvar PathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\n\t\t\tfor (var I = 0; I <= RoomsOnPath; I++) {\n\t\t\t\tif (I == RoomsOnPath && Exit == null) continue;\n\n\t\t\t\tvar Tunnels = Rnd.Chances(PathTunnels);\n\n\t\t\t\tif (Tunnels == -1) {\n\t\t\t\t\tPathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\t\t\t\t\tTunnels = Rnd.Chances(PathTunnels);\n\t\t\t\t}\n\n\t\t\t\tPathTunnels[Tunnels]--;\n\n\t\t\t\tif (I != 0 && Run.Depth != 0)\n\t\t\t\t\tfor (var J = 0; J < Tunnels; J++) {\n\t\t\t\t\t\tvar T = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);\n\n\t\t\t\t\t\tif (Math.Abs(PlaceRoom(Init, Curr, T, Direction + Rnd.Float(-PathVariance, PathVariance)) - (-1)) < 0.01f) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tBranchable.Add(T);\n\t\t\t\t\t\tInit.Add(T);\n\t\t\t\t\t\tCurr = T;\n\t\t\t\t\t}\n\n\t\t\t\tvar R = I == RoomsOnPath ? Exit : MultiConnection[I];\n\n\n\t\t\t\tif (Math.Abs(PlaceRoom(Init, Curr, R, Direction + Rnd.Float(-PathVariance, PathVariance)) - (-1)) < 0.01f) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (R == Exit && Boss != null && !PlaceBoss(Init, R)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tBranchable.Add(R);\n\t\t\t\tCurr = R;\n\t\t\t}\n\n\t\t\tvar RoomsToBranch = new List<RoomDef>();\n\n\t\t\tfor (var I = RoomsOnPath; I < MultiConnection.Count; I++) {\n\t\t\t\tRoomsToBranch.Add(MultiConnection[I]);\n\t\t\t}\n\n\t\t\tRoomsToBranch.AddRange(SingleConnection);\n\n\t\t\tWeightRooms(Branchable);\n\n\t\t\tif (!CreateBranches(Init, Branchable, RoomsToBranch, BranchTunnelChances)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tFindNeighbours(Init);\n\n\t\t\tforeach (var R in Init) {\n\t\t\t\tforeach (var N in R.Neighbours) {\n\t\t\t\t\tif (!N.Connected.ContainsKey(R) && Rnd.Float() < ExtraConnectionChance) {\n\t\t\t\t\t\tR.ConnectWithRoom(N);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Init;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/LoopBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.builders {\n\tpublic class LoopBuilder : RegularBuilder {\n\t\tprivate int Exponent;\n\t\tprivate float Intensity = 1;\n\t\tprivate Vector2 LoopCenter;\n\t\tprivate float Offset;\n\n\t\tpublic LoopBuilder SetShape(int Exponent, float Intensity, float Offset) {\n\t\t\tthis.Exponent = Math.Abs(Exponent);\n\t\t\tthis.Intensity = Intensity % 1;\n\t\t\tthis.Offset = Offset % 0.5f;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate float TargetAngle(float PercentAlong) {\n\t\t\tPercentAlong += Offset;\n\n\t\t\treturn 345f * (float) (Intensity * CurveEquation(PercentAlong) + (1 - Intensity) * PercentAlong - Offset);\n\t\t}\n\n\t\tprivate double CurveEquation(double X) {\n\t\t\treturn Math.Pow(4, 2 * Exponent) * Math.Pow(X % 0.5f - 0.25, 2 * Exponent + 1) + 0.25 + 0.5 * Math.Floor(2 * X);\n\t\t}\n\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\tSetupRooms(Init);\n\n\t\t\tif (Entrance == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tEntrance.SetPos(0, 0);\n\t\t\tEntrance.SetSize();\n\t\t\tvar StartAngle = Rnd.Angle();\n\t\t\tvar Loop = new List<RoomDef>();\n\t\t\t\n\t\t\tvar RoomsOnLoop = (int) (MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);\n\t\t\tRoomsOnLoop = Math.Min(RoomsOnLoop, MultiConnection.Count);\n\t\t\tRoomsOnLoop++;\n\t\t\tvar PathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\n\t\t\tfor (var i = MultiConnection.Count - 1; i >= 0; i--) {\n\t\t\t\tvar r = MultiConnection[i];\n\n\t\t\t\tif (r is ConnectionRoom) {\n\t\t\t\t\tLoop.Add(r);\n\t\t\t\t\tMultiConnection.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (var I = 0; I < RoomsOnLoop; I++) {\n\t\t\t\tif (I == 0) {\n\t\t\t\t\tLoop.Add(Entrance);\n\t\t\t\t} else {\n\t\t\t\t\tLoop.Add(MultiConnection[0]);\n\t\t\t\t\tMultiConnection.RemoveAt(0);\n\t\t\t\t}\n\n\t\t\t\tvar Tunnels = Rnd.Chances(PathTunnels);\n\n\t\t\t\tif (Tunnels == -1) {\n\t\t\t\t\tPathTunnels = ArrayUtils.Clone(PathTunnelChances);\n\t\t\t\t\tTunnels = Rnd.Chances(PathTunnels);\n\t\t\t\t}\n\n\t\t\t\tPathTunnels[Tunnels]--;\n\n\t\t\t\tfor (var J = 0; J < Tunnels; J++) {\n\t\t\t\t\tLoop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Exit != null) {\n\t\t\t\tLoop.Insert((Loop.Count + 1) / 2, Exit);\n\t\t\t}\n\n\t\t\tif (LevelSave.BiomeGenerated is LibraryBiome) {\n\t\t\t\tvar c = (Loop.Count + 1);\n\t\t\t\t\n\t\t\t\tLoop.Insert(c / 4, new LibraryConnectionRoom());\n\t\t\t\tLoop.Insert(c / 4 * 3, new LibraryConnectionRoom {\n\t\t\t\t\tBottomHalf = true\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tRoomDef Prev = Entrance;\n\t\t\tfloat TargetAngle;\n\n\t\t\tfor (var I = 1; I < Loop.Count; I++) {\n\t\t\t\tvar R = Loop[I];\n\t\t\t\tTargetAngle = StartAngle + this.TargetAngle(I / (float) Loop.Count);\n\n\t\t\t\tif ((int) PlaceRoom(Init, Prev, R, TargetAngle) != -1) {\n\t\t\t\t\tPrev = R;\n\n\t\t\t\t\tif (!Init.Contains(Prev)) {\n\t\t\t\t\t\tInit.Add(Prev);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (R == Exit && Boss != null) {\n\t\t\t\t\t\tvar a = TargetAngle - 90;\n\t\t\t\t\t\tvar i = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\tvar an = PlaceRoom(Init, R, Boss, a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\t\tif (i > 36) {\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ta += 10;\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\ta = Rnd.Angle();\n\t\t\t\t\t\ti = 0;\n\n\t\t\t\t\t\tif (Granny != null) {\n\t\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\t\tvar an = PlaceRoom(Init, Boss, Granny, a);\n\n\t\t\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ta += 5;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ta = Rnd.Angle();\n\t\t\t\t\t\ti = 0;\n\n\t\t\t\t\t\tif (OldMan != null) {\n\t\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\t\tvar an = PlaceRoom(Init, Boss, OldMan, a);\n\n\t\t\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\t\t\tif (i > 72) {\n\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ta += 5;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twhile (!Prev.ConnectTo(Entrance)) {\n\t\t\t\tvar C = RoomRegistry.Generate(RoomType.Regular, LevelSave.BiomeGenerated);\n\n\t\t\t\tif ((int) PlaceRoom(Loop, Prev, C, AngleBetweenRooms(Prev, Entrance)) == -1) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tLoop.Add(C);\n\t\t\t\tInit.Add(C);\n\t\t\t\tPrev = C;\n\t\t\t}\n\n\t\t\tLoopCenter = new Vector2();\n\n\t\t\tforeach (var R in Loop) {\n\t\t\t\tLoopCenter.X += (R.Left + R.Right) / 2f;\n\t\t\t\tLoopCenter.Y += (R.Top + R.Bottom) / 2f;\n\t\t\t}\n\n\t\t\tLoopCenter.X /= Loop.Count;\n\t\t\tLoopCenter.Y /= Loop.Count;\n\t\t\tvar Branchable = new List<RoomDef>(Loop);\n\t\t\tvar RoomsToBranch = new List<RoomDef>();\n\t\t\tRoomsToBranch.AddRange(MultiConnection);\n\t\t\tRoomsToBranch.AddRange(SingleConnection);\n\t\t\tWeightRooms(Branchable);\n\n\t\t\tif (!CreateBranches(Init, Branchable, RoomsToBranch, BranchTunnelChances)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tFindNeighbours(Init);\n\n\t\t\tforeach (var R in Init)\n\t\t\tforeach (var N in R.Neighbours) {\n\t\t\t\tif (!N.Connected.ContainsKey(R) && Rnd.Float() < ExtraConnectionChance) {\n\t\t\t\t\tR.ConnectWithRoom(N);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!Prev.Connected.ContainsKey(Entrance)) {\n\t\t\t\tPrev.Neighbours.Add(Entrance);\n\t\t\t\tEntrance.Neighbours.Add(Prev);\n\t\t\t\tPrev.Connected[Entrance] = null;\n\t\t\t\tEntrance.Connected[Prev] = null;\n\t\t\t}\n\n\t\t\treturn Init;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/RegularBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.level.rooms.shop.sub;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.builders {\n\tpublic class RegularBuilder : Builder {\n\t\tprotected float[] BranchTunnelChances = {1, 0, 0};\n\t\tprotected EntranceRoom Entrance;\n\t\tprotected ExitRoom Exit;\n\t\tprotected BossRoom Boss;\n\t\tprotected GrannyRoom Granny;\n\t\tprotected OldManRoom OldMan;\n\t\tprotected List<RoomDef> SubShop = new List<RoomDef>();\n\t\tprotected float ExtraConnectionChance = 0.2f;\n\t\tprotected List<RoomDef> MultiConnection = new List<RoomDef>();\n\t\tprotected float PathLength = 0.5f;\n\t\tprotected float[] PathLenJitterChances = {0, 1, 0};\n\t\tprotected float[] PathTunnelChances = {1, 3, 1};\n\t\tprotected float PathVariance = 45f;\n\t\tprotected List<RoomDef> SingleConnection = new List<RoomDef>();\n\n\t\tpublic void SetupRooms(List<RoomDef> Rooms) {\n\t\t\tEntrance = null;\n\t\t\tExit = null;\n\t\t\tBoss = null;\n\t\t\tGranny = null;\n\t\t\tOldMan = null;\n\t\t\tMultiConnection.Clear();\n\t\t\tSingleConnection.Clear();\n\t\t\tSubShop.Clear();\n\n\t\t\tforeach (var Room in Rooms) {\n\t\t\t\tRoom.SetEmpty();\n\t\t\t}\n\n\t\t\tforeach (var Room in Rooms) {\n\t\t\t\tif (Room is BossRoom b) {\n\t\t\t\t\tBoss = b;\n\t\t\t\t} else if (Room is OldManRoom) {\n\t\t\t\t\tOldMan = (OldManRoom) Room;\n\t\t\t\t} else if (Room is GrannyRoom) {\n\t\t\t\t\tGranny = (GrannyRoom) Room;\n\t\t\t\t} else if (Room is EntranceRoom) {\n\t\t\t\t\tEntrance = (EntranceRoom) Room;\n\t\t\t\t} else if (Room is ExitRoom) {\n\t\t\t\t\tExit = (ExitRoom) Room;\n\t\t\t\t} else if (Room is SubShopRoom) {\n\t\t\t\t\tSubShop.Add(Room);\n\t\t\t\t} else if (Room.GetMaxConnections(RoomDef.Connection.All) == 1) {\n\t\t\t\t\tSingleConnection.Add(Room);\n\t\t\t\t} else if (Room.GetMaxConnections(RoomDef.Connection.All) > 1) {\n\t\t\t\t\tMultiConnection.Add(Room);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tWeightRooms(MultiConnection);\n\t\t\tMultiConnection = new List<RoomDef>(MultiConnection);\n\t\t}\n\n\t\tprotected void WeightRooms(List<RoomDef> Rooms) {\n\t\t\t/*foreach (var Room in Rooms) {\n\t\t\t\tif (Room is RegularRoom room) {\n\t\t\t\t\tfor (var I = 1; I < room.GetSize().GetConnectionWeight(); I++) {\n\t\t\t\t\t\tRooms.Add(room);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tRooms.Add(room);\n\t\t\t\t}\n\t\t\t}*/\n\t\t}\n\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\treturn Init;\n\t\t}\n\n\t\tpublic RegularBuilder SetPathVariance(float Var) {\n\t\t\tPathVariance = Var;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic RegularBuilder SetPathLength(float Len, float[] Jitter) {\n\t\t\tPathLength = Len;\n\t\t\tPathLenJitterChances = Jitter;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic RegularBuilder SetTunnelLength(float[] Path, float[] Branch) {\n\t\t\tPathTunnelChances = Path;\n\t\t\tBranchTunnelChances = Branch;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic RegularBuilder SetExtraConnectionChance(float Chance) {\n\t\t\tExtraConnectionChance = Chance;\n\t\t\treturn this;\n\t\t}\n\n\t\tprotected bool CreateBranches(List<RoomDef> Rooms, List<RoomDef> Branchable, List<RoomDef> RoomsToBranch, float[] ConnChances) {\n\t\t\tvar I = 0;\n\t\t\tvar N = 0;\n\t\t\tfloat Angle;\n\t\t\tint Tries;\n\t\t\tRoomDef Curr;\n\t\t\t\n\t\t\tvar ConnectingRoomsThisBranch = new List<RoomDef>();\n\t\t\tvar ConnectionChances = ArrayUtils.Clone(ConnChances);\n\t\t\t\n\t\t\twhile (I < RoomsToBranch.Count) {\n\t\t\t\tvar R = RoomsToBranch[I];\n\t\t\t\tN++;\n\t\t\t\tConnectingRoomsThisBranch.Clear();\n\n\t\t\t\tdo {\n\t\t\t\t\tCurr = Branchable[Rnd.Int(Branchable.Count)];\n\t\t\t\t} while (Curr is ConnectionRoom);\n\n\t\t\t\tvar ConnectingRooms = Rnd.Chances(ConnectionChances);\n\n\t\t\t\tif (ConnectingRooms == -1) {\n\t\t\t\t\tConnectionChances = ArrayUtils.Clone(ConnChances);\n\t\t\t\t\tConnectingRooms = Rnd.Chances(ConnectionChances);\n\t\t\t\t}\n\n\t\t\t\tConnectionChances[ConnectingRooms]--;\n\n\t\t\t\tfor (var J = 0; J < ConnectingRooms; J++) {\n\t\t\t\t\tvar T = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);\n\t\t\t\t\tTries = 3;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tAngle = PlaceRoom(Rooms, Curr, T, RandomBranchAngle(Curr));\n\t\t\t\t\t\tTries--;\n\t\t\t\t\t} while (Math.Abs(Angle - (-1)) < 0.01f && Tries > 0);\n\n\t\t\t\t\tif (Math.Abs(Angle - (-1)) < 0.01f) {\n\t\t\t\t\t\tforeach (var C in ConnectingRoomsThisBranch) {\n\t\t\t\t\t\t\tC.ClearConnections();\n\t\t\t\t\t\t\tRooms.Remove(C);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tConnectingRoomsThisBranch.Clear();\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tConnectingRoomsThisBranch.Add(T);\n\t\t\t\t\tRooms.Add(T);\n\n\n\t\t\t\t\tCurr = T;\n\t\t\t\t}\n\n\t\t\t\tif (ConnectingRoomsThisBranch.Count != ConnectingRooms) {\n\t\t\t\t\tif (N > 30) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tTries = 10;\n\n\t\t\t\tdo {\n\t\t\t\t\tAngle = PlaceRoom(Rooms, Curr, R, RandomBranchAngle(Curr));\n\t\t\t\t\tTries--;\n\t\t\t\t} while (Math.Abs(Angle - (-1)) < 0.01f && Tries > 0);\n\n\t\t\t\tif (Math.Abs(Angle - (-1)) < 0.01f) {\n\t\t\t\t\tforeach (var T in ConnectingRoomsThisBranch) {\n\t\t\t\t\t\tT.ClearConnections();\n\t\t\t\t\t\tRooms.Remove(T);\n\t\t\t\t\t}\n\n\t\t\t\t\tConnectingRoomsThisBranch.Clear();\n\n\t\t\t\t\tif (N > 30) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tforeach (var AConnectingRoomsThisBranch in ConnectingRoomsThisBranch) {\n\t\t\t\t\tif (Rnd.Int(3) <= 1) {\n\t\t\t\t\t\tBranchable.Add(AConnectingRoomsThisBranch);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (R.GetMaxConnections(RoomDef.Connection.All) > 1 && Rnd.Int(3) == 0) {\n\t\t\t\t\tif (R is RegularRoom room) {\n\t\t\t\t\t\t/*for (var J = 0; J < room.GetSize().GetConnectionWeight(); J++) {\n\t\t\t\t\t\t\tBranchable.Add(room);\n\t\t\t\t\t\t}*/\n\t\t\t\t\t\t\n\t\t\t\t\t\tBranchable.Add(room);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tBranchable.Add(R);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tI++;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual float RandomBranchAngle(RoomDef R) {\n\t\t\treturn Rnd.Angle();\n\t\t}\n\n\t\tprotected override float PlaceRoom(List<RoomDef> Collision, RoomDef Prev, RoomDef Next, float Angle) {\n\t\t\tvar v = base.PlaceRoom(Collision, Prev, Next, Angle);\n\n\t\t\tif (v > -1 && Next is ShopRoom) {\n\t\t\t\tLog.Info(\"Placing sub shop rooms\");\n\t\t\t\t\n\t\t\t\tforeach (var r in SubShop) {\n\t\t\t\t\tvar a = Rnd.Angle();\n\t\t\t\t\tvar i = 0;\n\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tvar an = PlaceRoom(Collision, Next, r, a % 360);\n\n\t\t\t\t\t\tif ((int) an != -1) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ti++;\n\n\t\t\t\t\t\tif (i > 36) {\n\t\t\t\t\t\t\tLog.Error(\"Failed.\");\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ta += 10;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/*if (SubShop.Count > 0) {\n\t\t\t\t\tfor (var i = 0; i < SubShop.Count - 1; i++) {\n\t\t\t\t\t\tfor (var j = i + 1; j < SubShop.Count; j++) {\n\t\t\t\t\t\t\tSubShop[i].ConnectTo(SubShop[j]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}*/\n\n\t\t\t\tLog.Info(\"Failed to fail.\");\n\t\t\t}\n\n\t\t\treturn v;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/builders/SingleRoomBuilder.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.rooms;\n\nnamespace BurningKnight.level.builders {\n\tpublic class SingleRoomBuilder : Builder {\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\n\t\t\tvar Room = Init[0];\n\t\t\t\n\t\t\tRoom.SetSize();\n\t\t\tRoom.SetPos(0, 0);\n\n\t\t\treturn Init;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/challenge/BombOnlyChallenge.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.level.challenge {\n\tpublic class BombOnlyChallenge : Challenge {\n\t\tpublic override void Apply(Player player) {\n\t\t\tvar inventory = player.GetComponent<InventoryComponent>();\n\t\t\tvar area = player.Area;\n\t\t\t\n\t\t\t// Fixme: this is super weak\n\t\t\tinventory.Pickup(Items.CreateAndAdd(\"bk:blindfold\", area), false);\n\t\t\tinventory.Pickup(Items.CreateAndAdd(\"bk:tnt\", area), false);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/challenge/Challenge.cs",
    "content": "using BurningKnight.entity.creature.player;\n\nnamespace BurningKnight.level.challenge {\n\tpublic abstract class Challenge {\n\t\tpublic abstract void Apply(Player player);\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/challenge/ChallengeRegistry.cs",
    "content": "using System.Collections.Generic;\n\nnamespace BurningKnight.level.challenge {\n\tpublic static class ChallengeRegistry {\n\t\tprivate static List<Challenge> challenges = new List<Challenge>();\n\n\t\tstatic ChallengeRegistry() {\n\t\t\tAdd(new BombOnlyChallenge());\n\t\t}\n\n\t\tpublic static void Add(Challenge challenge) {\n\t\t\tchallenges.Add(challenge);\n\t\t}\n\n\t\tpublic static Challenge Get(byte id) {\n\t\t\tif (challenges.Count > id - 1 && id > 0) {\n\t\t\t\treturn challenges[id - 1];\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/cutscene/CutsceneLevel.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.hall;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tutorial;\nusing BurningKnight.state;\n\nnamespace BurningKnight.level.cutscene {\n\tpublic class CutsceneLevel : RegularLevel {\n\t\tpublic CutsceneLevel() : base(BiomeRegistry.Get(Biome.Castle)) {\n\n\t\t}\n\n\t\tprotected override List<RoomDef> CreateRooms() { \n\t\t\treturn new List<RoomDef> {\n\t\t\t\tnew CutsceneRoom(Math.Abs(Run.Depth) - 3)\n\t\t\t};\n\t\t}\n\n\t\tpublic override int GetPadding() {\n\t\t\treturn 1;\n\t\t}\n\n\t\tprotected override Builder GetBuilder() {\n\t\t\treturn new HallBuilder();\n\t\t}\n\n\t\tprotected override Painter GetPainter() {\n\t\t\treturn new Painter {\n\t\t\t\tWater = 0,\n\t\t\t\tCobweb = 0,\n\t\t\t\tGrass = 0,\n\t\t\t\tDirt = 0\n\t\t\t};\n\t\t}\n\n\t\tpublic override string GetMusic() {\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/cutscene/CutsceneRoom.cs",
    "content": "using BurningKnight.assets.prefabs;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.tile;\n\nnamespace BurningKnight.level.cutscene {\n\tpublic class CutsceneRoom : ExitRoom {\n\t\tprivate Prefab prefab;\n\t\tprivate string prefabId;\n\n\t\tpublic CutsceneRoom(int id) {\n\t\t\tprefabId = $\"cutscene_{id}\";\n\t\t\tprefab = Prefabs.Get(prefabId);\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Prefab(level, prefabId, Left + 1, Top + 1);\n\t\t}\n\n\t\tpublic override bool ConvertToEntity() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn prefab.Level.Width;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn prefab.Level.Width + 1;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn prefab.Level.Height;\n\t\t}\n\t\t\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn prefab.Level.Height + 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/AchievementStatue.cs",
    "content": "using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing BurningKnight.ui.dialog;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class AchievementStatue : Prop {\n\t\tprivate string id = \"bk:rip\";\n\t\tprivate Achievement achievement;\n\t\tprivate TextureRegion achievementTexture;\n\t\tprivate float offset;\n\t\tprivate bool hidden;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\toffset = Rnd.Float(1);\n\t\t\t\n\t\t\tWidth = 24;\n\t\t\tHeight = 32;\n\t\t\t\n\t\t\tAddComponent(new DialogComponent());\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => !hidden\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"achievement_statue\"));\n\t\t\tAddComponent(new RectBodyComponent(0, 13, 24, 19, BodyType.Static));\n\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 30;\n\t\t\t\n\t\t\tAddTag(Tags.Statue);\n\n\t\t\tArea.Add(new RenderTrigger(this, RenderTop, Layers.FlyingMob));\n\t\t\t\n\t\t\tAchievements.UnlockedCallback += UpdateState;\n\t\t\tAchievements.LockedCallback += UpdateState;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tAchievements.UnlockedCallback -= UpdateState;\n\t\t\tAchievements.LockedCallback -= UpdateState;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tSetupSprite();\n\t\t\tUpdateState();\n\t\t}\n\t\t\n\t\tprivate bool Interact(Entity e) {\n\t\t\tforeach (var s in Area.Tagged[Tags.Statue]) {\n\t\t\t\tif (s.TryGetComponent<DialogComponent>(out var d)) {\n\t\t\t\t\td.Close();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstring state;\n\n\t\t\tif (achievement != null && achievement.Unlocked) {\n\t\t\t\tvar d = achievement.CompletionDate;\n\n\t\t\t\tif (d == \"???\") {\n\t\t\t\t\td = \"~~???~~\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tstate = $\"[sp 2][cl orange]{Locale.Get($\"ach_{id}\")}[cl]\\n{Locale.Get($\"ach_{id}_desc\")}\\n[cl gray]{Locale.Get(\"completed_on\")} {d}[cl]\";\n\t\t\t} else {\n\t\t\t\tstate = $\"[sp 2][cl orange]{Locale.Get($\"ach_{id}\")}[cl]\";\n\n\t\t\t\tif (achievement.Max > 0) {\n\t\t\t\t\tvar p = GlobalSave.GetInt($\"ach_{id}\", 0);\n\t\t\t\t\tstate += $\"\\n[cl gray]{MathUtils.Clamp(0, achievement.Max, p)}/{achievement.Max} {Locale.Get(\"complete\")}[cl]\";\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Start(state);\n\t\t\treturn true; \n\t\t}\n\n\t\tprivate void SetupSprite() {\n\t\t\tachievementTexture = Animations.Get(\"achievements\").GetSlice(id);\n\t\t}\n\n\t\tprivate void UpdateState(string i = null) {\n\t\t\tachievement = Achievements.Get(id);\n\n\t\t\tif (achievement == null || Engine.EditingLevel) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!achievement.Unlocked && achievement.Secret) {\n\t\t\t\thidden = true;\n\t\t\t\tGetComponent<RectBodyComponent>().Body.IsSensor = true;\n\t\t\t} else {\n\t\t\t\thidden = false;\n\t\t\t\tGetComponent<RectBodyComponent>().Body.IsSensor = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tid = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(id);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Render();\n\t\t}\n\n\t\tpublic void RenderShadow() {\n\t\t\tif (hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tpublic void RenderTop() {\n\t\t\tif (!hidden && achievement != null && achievement.Unlocked) {\n\t\t\t\tGraphics.Render(achievementTexture, Position + new Vector2(2, (float) Math.Cos(Engine.Time * 1.5f + offset) * 2.5f - 2.5f));\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (ImGui.InputText(\"Id\", ref id, 128)) {\n\t\t\t\tSetupSprite();\n\t\t\t\tUpdateState();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Belt.cs",
    "content": "using BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.room.controllable;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Belt : Support {\n\t\tprivate const float Speed = 24;\n\n\t\tprivate static Vector2[] velocities = {\n\t\t\tnew Vector2(0, -Speed), new Vector2(0, Speed),\n\t\t\tnew Vector2(-Speed, 0), new Vector2(Speed, 0)\n\t\t};\n\t\t\n\t\tprivate Vector2 velocity;\n\t\tprotected Direction Direction = Direction.Left;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(-1, -1, 18, 18, BodyType.Static));\n\t\t\t\n\t\t\tDepth = Layers.Entrance;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tvelocity = velocities[(int) Direction];\n\n\t\t\tswitch (Direction) {\n\t\t\t\tcase Direction.Left: {\n\t\t\t\t\tAddComponent(new AnimationComponent(\"belt\"));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase Direction.Right: {\n\t\t\t\t\tAddComponent(new AnimationComponent(\"belt\"));\n\t\t\t\t\tGraphicsComponent.Flipped = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase Direction.Up: {\n\t\t\t\t\tAddComponent(new AnimationComponent(\"belt_up\"));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase Direction.Down: {\n\t\t\t\t\tAddComponent(new AnimationComponent(\"belt_down\"));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tGetComponent<AnimationComponent>().Animation.Frame = (uint) (Engine.Time * 24) % 4;\n\t\t}\n\n\t\tpublic override void Apply(Entity e, float dt) {\n\t\t\tvar b = e.GetAnyComponent<BodyComponent>();\n\n\t\t\tif (b == null || !ShouldMove(e)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Apply(e, dt);\n\t\t\tb.Position += velocity * dt;\n\t\t}\n\n\t\tprotected virtual bool ShouldMove(Entity e) {\n\t\t\treturn !(e is Creature c && c.InAir()) && !Engine.EditingLevel;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tDirection = (Direction) stream.ReadByte();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte((byte) Direction);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/BreakableProp.cs",
    "content": "using System;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.editor;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities {\n\tpublic class BreakableProp : SolidProp, PlaceableEntity {\n\t\tpublic static string[] Infos = {\n\t\t\t\"pot_a\",\n\t\t\t\"pot_b\",\n\t\t\t\"pot_c\",\n\t\t\t\"pot_d\",\n\t\t\t\"pot_e\",\n\n\t\t\t\"cup\",\n\t\t\t\n\t\t\t\"chair_a\",\n\t\t\t\"chair_b\",\n\t\t\t\"chair_c\",\n\t\t\t\n\t\t\t\"crate_a\",\n\t\t\t\"crate_b\"\n\t\t};\n\t\t\n\t\tpublic static string[] IceInfos = {\n\t\t\t\"cup\",\n\t\t\t\n\t\t\t\"gift_a\",\n\t\t\t\"gift_b\",\n\t\t\t\"gift_c\"\n\t\t};\n\n\t\tprivate Entity from;\n\t\tprivate bool hurts;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new HealthComponent {\n\t\t\t\tInitMaxHealth = 1,\n\t\t\t\tRenderInvt = true,\n\t\t\t\tAutoKill = false\n\t\t\t});\n\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\tvar rect = GetComponent<SliceComponent>().Sprite.Source;\n\n\t\t\t/*if (Sprite.Contains(\"pot\") || Sprite.Contains(\"crate\")) {\n\t\t\t\tAddComponent(new PoolDropsComponent(ItemPool.Crate, 0.3f, 1, 3));\n\t\t\t}*/\n\t\t\t\n\t\t\thurts = Sprite == \"cactus\";\n\n\t\t\tWidth = rect.Width;\n\t\t\tHeight = rect.Height;\n\t\t\t\n\t\t\treturn new Rectangle(hurts ? 2 : 0, 0, (int) (hurts ? Width - 4 : Width), (int) (hurts ? Height - 6 : Height));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent ev) {\n\t\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\t\t\n\t\t\t\tif (Math.Abs(h.Health + ev.Amount) < 0.1f) {\n\t\t\t\t\tfrom = ev.From;\n\t\t\t\t}\n\t\t\t} else if (e is CollisionStartedEvent c && hurts) {\n\t\t\t\tif (c.Entity is Player) {\n\t\t\t\t\tc.Entity.GetComponent<HealthComponent>().ModifyHealth(-1, this);\n\t\t\t\t\tc.Entity.GetAnyComponent<BodyComponent>().KnockbackFrom(this, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (from != null && TryGetComponent<HealthComponent>(out var h) && h.InvincibilityTimer <= 0.45f) {\n\t\t\t\tDone = true;\n\n\t\t\t\tif (!Camera.Instance.Overlaps(this)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (TryGetComponent<PoolDropsComponent>(out var pool)) {\n\t\t\t\t\tpool.SpawnDrops();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = Center;\n\t\t\t\t\tpart.Particle.Scale = Lens.util.math.Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\t\n\t\t\t\t\tArea.Add(part);\n\t\t\t\t}\n\n\t\t\t\tvar d = AudioEmitterComponent.Dummy(Area, Center);\n\t\t\t\t\n\t\t\t\tif (Sprite == \"cup\" || Sprite.StartsWith(\"pot\")) {\n\t\t\t\t\td.EmitRandomizedPrefixed(\"level_cup\", 2, 0.75f);\n\t\t\t\t} else {\n\t\t\t\t\td.EmitRandomizedPrefixed(\"level_chair_break\", 2, 0.75f);\n\t\t\t\t}\n\n\t\t\t\tParticles.BreakSprite(Area, GetComponent<SliceComponent>().Sprite, Position);\n\t\t\t\tCamera.Instance.Shake(2f);\n\t\t\t\tEngine.Instance.Freeze = 1f;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn entity is Level || entity is Chasm || entity is SolidProp || entity is HalfWall || entity is ItemStand;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Campfire.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Campfire : Prop {\n\t\tprivate float lastFlame;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 17;\n\t\t\tHeight = 11;\n\t\t\t\n\t\t\tAddComponent(new SliceComponent(\"props\", \"campfire\"));\n\t\t\tAddComponent(new LightComponent(this, 32, new Color(1f, 1f, 0f, 1f)));\n\t\t\tAddComponent(new RectBodyComponent(Width / 4, 0, Width / 2, Height - 5, BodyType.Static));\n\t\t\tAddComponent(new RoomComponent());\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tlastFlame += dt;\n\n\t\t\tif (lastFlame > 0.1f) {\n\t\t\t\tlastFlame = 0;\n\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (Run.Depth < 1 || (room != null && room.Tagged[Tags.Player].Count > 0)) {\n\t\t\t\t\tArea.Add(new FireParticle {\n\t\t\t\t\t\tX = CenterX + Rnd.Float(-4, 4),\n\t\t\t\t\t\tY = CenterY\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Claw.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Claw : Entity {\n\t\tprivate const float TopZ = 32;\n\t\tprivate const float OpenAngle = (float) Math.PI * 0.25f;\n\t\t\n\t\tprivate static Vector2 origin = new Vector2(15f / 2, 1);\n\t\tprivate static Vector2 rightOrigin = new Vector2(-0.5f, 1);\n\t\tprivate static Vector2 topOrigin = new Vector2(7 / 2f, 31);\n\n\t\tprivate TextureRegion leftClaw;\n\t\tprivate TextureRegion rightClaw;\n\t\tprivate TextureRegion top;\n\t\tprivate float angle;\n\t\tprivate float z = TopZ;\n\t\tprivate RoundItem grabbed;\n\t\tinternal Vector2 start;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 15;\n\t\t\tDepth = Layers.FlyingMob;\n\n\t\t\tvar body = new SensorBodyComponent(-origin.X, -origin.Y, 15, 14);\n\t\t\tAddComponent(body);\n\n\t\t\tbody.Body.LinearDamping = 10;\n\n\t\t\tvar animation = CommonAse.Props;\n\n\t\t\tleftClaw = animation.GetSlice(\"left_claw\");\n\t\t\trightClaw = animation.GetSlice(\"right_claw\");\n\t\t\ttop = animation.GetSlice(\"claw_hand\");\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(() => {\n\t\t\t\tSimpleRender(true);\n\t\t\t}));\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tstart = Position;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tSimpleRender(false);\n\t\t}\n\n\t\tprivate void SimpleRender(bool shadow) {\n\t\t\tvar p = Position;\n\n\t\t\tif (!shadow) {\n\t\t\t\tp.Y -= z;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(leftClaw, p, angle, origin);\n\t\t\tGraphics.Render(rightClaw, p, -angle, rightOrigin);\n\t\t\tGraphics.Render(top, p, 0, topOrigin);\n\t\t}\n\n\t\tprivate bool CheckGrab() {\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\t\t\tvar p = Position + new Vector2(0, 10);\n\t\t\tvar min = 12f;\n\t\t\tRoundItem item = null;\n\t\t\tgrabbed = null;\n\n\t\t\tforeach (var i in room.Tagged[Tags.Item]) {\n\t\t\t\tif (i is RoundItem r) {\n\t\t\t\t\tvar d = r.DistanceTo(p);\n\n\t\t\t\t\tif (d < min) {\n\t\t\t\t\t\tmin = d;\n\t\t\t\t\t\titem = r;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (item != null) {\n\t\t\t\tgrabbed = item;\n\t\t\t\tgrabbed.Transparent = true;\n\t\t\t\t\n\t\t\t\tAnimationUtil.Poof(item.Center);\n\t\t\t\tAnimationUtil.Confetti(item.Center);\n\t\t\t\tAudio.PlaySfx(\"level_cleared\");\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlaySfx(\"item_nocash\");\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (grabbed != null) {\n\t\t\t\tgrabbed.Center = Position + new Vector2(0, 10 - z);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Grab(Action<bool, bool> a) {\n\t\t\tAudio.PlaySfx(\"level_claw_open\");\n\n\t\t\tTween.To(OpenAngle, angle, x => angle = x, 0.5f, Ease.Linear).OnEnd = () => {\n\t\t\t\tvar t5 = Tween.To(0, z, x => z = x, 0.8f, Ease.Linear);\n\n\t\t\t\tt5.Delay = 0.5f;\n\t\t\t\tt5.OnStart = () => {\n\t\t\t\t\tAudio.PlaySfx(\"level_claw_move\");\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tt5.OnEnd = () => {\n\t\t\t\t\tvar t1 = Tween.To(0, angle, x => angle = x, 0.5f, Ease.Linear);\n\n\t\t\t\t\tt1.Delay = 0.5f;\n\t\t\t\t\tt1.OnStart = () => {\n\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_close\");\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tt1.OnEnd = () => {\n\t\t\t\t\t\tvar good = CheckGrab();\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar t2 = Tween.To(TopZ, z, x => z = x, 0.8f, Ease.Linear);\n\n\t\t\t\t\t\tt2.Delay = 0.5f;\n\t\t\t\t\t\tt2.OnStart = () => {\n\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_move\");\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\n\t\t\t\t\t\tt2.OnEnd = () => {\n\t\t\t\t\t\t\tTween.To(start.Y, Y, x => Y = x, 1.2f, Ease.Linear);\n\t\t\t\t\t\t\tvar t6 = Tween.To(start.X, X, x => X = x, 1.2f, Ease.Linear);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tt6.OnStart = () => {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_start\");\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tt6.OnEnd = () => {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_stop\");\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (good) {\n\t\t\t\t\t\t\t\t\tvar t3 = Tween.To(10, z, x => z = x, 0.8f, Ease.Linear);\n\t\t\t\t\t\t\t\t\tt3.Delay = 0.5f;\n\t\t\t\t\t\t\t\t\tt3.OnStart = () => {\n\t\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_move\");\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\tt3.OnEnd = () => {\n\t\t\t\t\t\t\t\t\t\tvar t9 = Tween.To(OpenAngle, angle, x => angle = x, 0.5f, Ease.Linear);\n\t\t\t\t\t\t\t\t\t\tt9.Delay = 0.5f;\n\t\t\t\t\t\t\t\t\t\tt9.OnStart = () => {\n\t\t\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_open\");\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tt9.OnEnd = () => {\n\t\t\t\t\t\t\t\t\t\t\tvar mega = grabbed.Id == \"bk:pass\";\n\n\t\t\t\t\t\t\t\t\t\t\tif (grabbed is RandomItem r) {\n\t\t\t\t\t\t\t\t\t\t\t\tr.Prevent = true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tgrabbed.Won = true;\n\t\t\t\t\t\t\t\t\t\t\tgrabbed.Transparent = false;\n\t\t\t\t\t\t\t\t\t\t\tgrabbed = null;\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\tvar t7 = Tween.To(0, angle, x => angle = x, 0.5f, Ease.Linear);\n\t\t\t\t\t\t\t\t\t\t\tt7.Delay = 0.5f;\n\t\t\t\t\t\t\t\t\t\t\tt7.OnStart = () => {\n\t\t\t\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_close\");\n\t\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\t\tt7.OnEnd = () => {\n\t\t\t\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"level_claw_move\");\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\tTween.To(TopZ, z, x => z = x, 0.8f, Ease.Linear).OnEnd = () => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ta(true, mega);\n\t\t\t\t\t\t\t\t\t\t\t\t\t}, 0.5f);\n\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\t\t\t\ta(false, false);\n\t\t\t\t\t\t\t\t\t}, 0.5f);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/ClawControll.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class ClawControll : Prop {\n\t\tprivate Claw claw;\n\t\tprivate Entity interacting;\n\t\tpublic bool Payed;\n\t\tprivate Maanex2 maanex;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"claw_controll\"));\n\t\t\tAddComponent(new RectBodyComponent(0, 0, 13, 15, BodyType.Static));\n\t\t\tAddComponent(new SensorBodyComponent(-4, -4, 13 + 8, 14 + 8, BodyType.Static));\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => Payed\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RoomComponent());\n\t\t}\n\n\t\tprivate InteractFx ia;\n\t\tprivate InteractFx ib;\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tif (!Payed) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlaySfx(\"level_claw_pc\");\n\t\t\t\n\t\t\te.RemoveComponent<PlayerInputComponent>();\n\t\t\tinteracting = e;\n\t\t\tinteracting.GetComponent<StateComponent>().Become<Player.SittingState>();\n\t\t\t\n\t\t\tvar region = CommonAse.Ui.GetSlice(\"key_right\");\n\t\t\tEngine.Instance.State.Ui.Add(ia = new InteractFx(this, null, region, -5));\n\t\t\tregion = CommonAse.Ui.GetSlice(\"button_x\");\n\t\t\tEngine.Instance.State.Ui.Add(ib = new InteractFx(this, null, region, 5));\n\t\t\t\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tCamera.Instance.Follow(claw, 1f);\n\t\t\tPayed = false;\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool grabbing;\n\t\tprivate bool wasDown;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (maanex == null) {\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tforeach (var n in room.Tagged[Tags.Npc]) {\n\t\t\t\t\tif (n is Maanex2 m) {\n\t\t\t\t\t\tmaanex = m;\n\t\t\t\t\t\tmaanex.clawControll = this;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (interacting == null || grabbing) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar controller = GamepadComponent.Current;\n\n\t\t\tif (Input.WasPressed(Controls.UiSelect, controller)) {\n\t\t\t\tgrabbing = true;\n\n\t\t\t\tia.Close();\n\t\t\t\tib.Close();\n\t\t\t\tia = ib = null;\n\t\t\t\t\n\t\t\t\tGetComponent<InteractableComponent>().CurrentlyInteracting?.GetComponent<InteractorComponent>()?.EndInteraction();\n\n\t\t\t\tclaw.Grab((won, mega) => {\n\t\t\t\t\tinteracting.AddComponent(new PlayerInputComponent());\n\t\t\t\t\tinteracting = null;\n\t\t\t\t\tgrabbing = false;\n\n\t\t\t\t\tif (won) {\n\t\t\t\t\t\tmaanex.GetComponent<DialogComponent>().StartAndClose(Locale.Get(mega ? \"m2_0\" : \"m2_1\"), 2);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmaanex.GetComponent<DialogComponent>().StartAndClose(\"F\", 2);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\n\t\t\t\t});\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar body = claw.GetComponent<SensorBodyComponent>().Body;\n\t\t\tvar speed = 420 * dt;\n\n\t\t\tvar wdown = wasDown;\n\n\t\t\tif (Input.IsDown(Controls.Right, controller) || Input.IsDown(Controls.UiRight, controller)) {\n\t\t\t\twasDown = true;\n\t\t\t\tbody.LinearVelocity += new Vector2(speed, 0);\n\t\t\t} else {\n\t\t\t\twasDown = false;\n\t\t\t}\n\n\t\t\tif (wdown != wasDown) {\n\t\t\t\tif (wasDown) {\n\t\t\t\t\tAudio.PlaySfx(\"level_claw_start\");\n\t\t\t\t} else {\n\t\t\t\t\tAudio.PlaySfx(\"level_claw_stop\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (claw.X > claw.start.X + 96) {\n\t\t\t\tclaw.X = claw.start.X + 96;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tclaw = new Claw {\n\t\t\t\tPosition = new Vector2(((int) Math.Floor(CenterX / 16) - 0.5f) * 16, (int) (Math.Floor(CenterY / 16) - 3) * 16)\n\t\t\t};\n\n\t\t\tArea.Add(claw);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/ContinueRun.cs",
    "content": "using BurningKnight.entity.creature.player;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.util;\r\n\r\nnamespace BurningKnight.level.entities {\r\n\tpublic class ContinueRun : Exit {\r\n\t\tpublic ContinueRun() {\r\n\t\t\tif (Engine.EditingLevel) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar a = SaveManager.ExistsAndValid(SaveType.Game);\r\n\t\t\tvar b = SaveManager.ExistsAndValid(SaveType.Level, null, $\"{SaveManager.SlotDir}level-1.lvl\");\r\n\t\t\tvar c = SaveManager.ExistsAndValid(SaveType.Player);\r\n\r\n\t\t\tif (a && b && c) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tDone = true;\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!Engine.EditingLevel && Run.LastSavedDepth == 0) {\r\n\t\t\t\tDone = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected override bool Interact(Entity entity) {\r\n\t\t\tLog.Error($\"Go to runs last saved depth to {Run.LastSavedDepth}\");\r\n\t\t\tRun.Depth = Run.LastSavedDepth;\r\n\t\t\tentity.RemoveComponent<PlayerInputComponent>();\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tprotected override string GetFxText() {\r\n\t\t\treturn Locale.Get(\"continue_run\");\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/Crystal.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Crystal : SaveableEntity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tDepth = Layers.Entrance;\n\t\t\t\n\t\t\tAddComponent(new SliceComponent(\"props\", \"crystal\"));\n\t\t\tAddComponent(new ExplodableComponent());\n\n\t\t\tWidth = 5;\n\t\t\tHeight = 5;\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 32, new Color(0.5f, 1f, 0.4f)));\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent ee) {\n\t\t\t\tif (ee.Origin.DistanceTo(this) < 32) {\n\t\t\t\t\tDone = true;\n\n\t\t\t\t\tvar exit = new Exit();\n\t\t\t\t\texit.To = 13;\n\t\t\t\t\tArea.Add(exit);\n\t\t\t\t\t\n\t\t\t\t\tvar x = (int) Math.Floor(CenterX / 16);\n\t\t\t\t\tvar y = (int) Math.Floor(CenterY / 16);\n\t\t\t\t\tvar p = new Vector2(x * 16 + 8, y * 16 + 8);\n\t\t\t\n\t\t\t\t\texit.Center = p;\n\n\t\t\t\t\tPainter.Fill(Run.Level, x - 1, y - 1, 3, 3, Tiles.RandomFloor());\n\t\t\t\t\tRun.Level.ReTileAndCreateBodyChunks(x - 1, y - 1, 3, 3);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/DailySign.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.util;\n\nnamespace BurningKnight.level.entities {\n\tpublic class DailySign : Sign {\n\t\tpublic DailySign() {\n\t\t\tRegion = \"sign_daily\";\n\t\t}\n\n\t\tprivate string GetTime(TimeSpan span) {\n\t\t\tif ((int) span.TotalHours > 1) {\n\t\t\t\treturn $\"{(int) span.TotalHours} {Locale.Get(\"hours\")}\";\n\t\t\t}\n\n\t\t\tif (span.Minutes > 1) {\n\t\t\t\treturn $\"{span.Minutes} {Locale.Get(\"minutes\")}\";\n\t\t\t}\n\t\t\t\n\t\t\treturn $\"{span.Seconds} {Locale.Get(\"seconds\")}\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tGetComponent<CloseDialogComponent>().DecideVariant = (e) => {\n\t\t\t\tvar d = DateTime.UtcNow;\n\t\t\t\tvar dd = d.AddDays(1);\n\t\t\t\t\n\t\t\t\tvar next = new DateTime(dd.Year, dd.Month, dd.Day, 0, 0, 0, DateTimeKind.Utc);\n\n\t\t\t\treturn $\"[sp 3]{Locale.Get(\"run_daily\")} #{Run.CalculateDailyId()}\\n{Locale.Get(\"next_daily_in\")}\\n{GetTime(next.Subtract(d))}\";\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/DownBelt.cs",
    "content": "using BurningKnight.util;\n\nnamespace BurningKnight.level.entities {\n\tpublic class DownBelt : Belt {\n\t\tpublic DownBelt() {\n\t\t\tDirection = Direction.Down;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Entrance.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.fx;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.editor;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.util.file;\r\nusing VelcroPhysics.Dynamics;\r\n\r\nnamespace BurningKnight.level.entities {\r\n\tpublic class Entrance : SaveableEntity, PlaceableEntity {\r\n\t\tpublic int To;\r\n\t\t\r\n\t\tprivate bool Interact(Entity entity) {\r\n\t\t\tRun.Depth = 0;\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tprivate bool CanInteract(Entity e) {\r\n\t\t\treturn Run.Depth == -1;\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tTo = 0; // Run.Depth - 1;\r\n\t\t\t\r\n\t\t\tWidth = 14;\r\n\t\t\tHeight = 15;\r\n\t\t\t\r\n\t\t\tAddTag(Tags.Entrance);\r\n\t\t\t\r\n\t\t\tAddComponent(new InteractableComponent(Interact) {\r\n\t\t\t\tOnStart = entity => {\r\n\t\t\t\t\tif (entity is LocalPlayer) {\r\n\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, Locale.Get(\"ascend\")));\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\t\r\n\t\t\t\tCanInteract = CanInteract\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, true));\r\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"entrance\"));\r\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\r\n\t\t}\r\n\r\n\t\tprivate void RenderShadow() {\r\n\t\t\tGraphicsComponent.Render(true);\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\tTo = stream.ReadInt16();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\tstream.WriteInt16((short) To);\r\n\t\t}\r\n\r\n\t\tpublic override void RenderImDebug() {\r\n\t\t\tImGui.InputInt(\"To\", ref To);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/Exit.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing BurningKnight.level.entities.exit;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.file;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Exit : SaveableEntity, PlaceableEntity {\n\t\tpublic int To;\n\t\tpublic static Exit Instance;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tDepth = Layers.Entrance;\n\t\t\tInstance = this;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Instance == this) {\n\t\t\t\tInstance = null;\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool CanUse() {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprotected virtual bool Interact(Entity entity) {\n\t\t\tif (!CanUse()) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tentity.RemoveComponent<PlayerInputComponent>();\n\t\t\tentity.GetComponent<HealthComponent>().Unhittable = true;\n\t\t\t\n\t\t\tif (Run.Depth == Run.ContentEndDepth || (Run.Type == RunType.BossRush && Run.Depth == 5)) {\n\t\t\t\tif (Run.Type == RunType.Regular || Run.Type == RunType.Twitch) {\n\t\t\t\t\tRun.ActualDepth = -1;\n\t\t\t\t\tRun.Depth = 1;\n\t\t\t\t\tRun.Loop++;\n\t\t\t\t\t\n\t\t\t\t\tAchievements.Unlock(\"bk:loop\");\n\t\t\t\t} else {\n\t\t\t\t\tRun.Win();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t((InGameState) Engine.Instance.State).TransitionToBlack(entity.Center, () => {\n\t\t\t\t\tRun.NumPlayers = 0;\n\t\t\t\t\tDescend();\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tAudio.PlaySfx(\"player_descending\");\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprotected virtual void Descend() {\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\tAchievements.Unlock(\"bk:tutorial\");\n\t\t\t\tGlobalSave.Put(\"finished_tutorial\", true);\n\t\t\t\tRun.Depth = 0;\n\t\t\t} else if (To == 1 || this is BossRushExit) {\n\t\t\t\tRun.NumPlayers = Area.Tagged[Tags.Player].Count;\n\t\t\t\tRun.StartNew();\n\t\t\t\t// Caves secret location\n\t\t\t} else if (Run.Depth == 13) {\n\t\t\t\tRun.Depth = 4;\n\t\t\t} else {\n\t\t\t\tRun.Depth = To;\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual string GetFxText() {\n\t\t\treturn Locale.Get(Run.Depth == 0 ? \"new_run\" : \"descend\");\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 16;\n\t\t\tHeight = 14;\n\n\t\t\tif (To != 13) {\n\t\t\t\tTo = Run.Depth + 1;\n\t\t\t}\n\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tOnStart = entity => {\n\t\t\t\t\tif (entity is LocalPlayer && Run.Depth != -2) {\n\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, GetFxText()));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tCanInteract = CanInteract\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, true));\n\t\t}\n\n\t\tprotected virtual bool CanInteract(Entity e) {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", GetSlice()));\n\t\t}\n\n\t\tprotected virtual string GetSlice() {\n\t\t\treturn To == 13 ? \"emerald_exit\" : \"exit\";\n\t\t}\n\t\t\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tTo = stream.ReadInt16();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteInt16((short) To);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tImGui.InputInt(\"To\", ref To);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/ExplodingBarrel.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.entity.component.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class ExplodingBarrel : SolidProp {\n\t\tprivate float tillExplode;\n\t\tprivate Entity trigger;\n\t\t\n\t\tpublic ExplodingBarrel() {\n\t\t\tSprite = \"exploding_barrel\";\n\t\t}\n\n\t\tprotected override BodyComponent CreateBody() {\n\t\t\tvar collider = GetCollider();\n\t\t\tvar body = new RectBodyComponent(collider.X, collider.Y, collider.Width, collider.Height, BodyType.Static);\n\n\t\t\t//body.Body.LinearDamping = 6f;\n\t\t\t//body.KnockbackModifier = 0.1f;\n\t\t\t//body.Body.Mass = 0.1f;\n\t\t\t\n\t\t\treturn body;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tvar h = new HealthComponent();\n\t\t\t\n\t\t\tAddComponent(h);\n\t\t\tAddTag(Tags.Bomb);\n\n\t\t\th.InitMaxHealth = 1; // 3;\n\t\t\th.RenderInvt = true;\n\t\t\t\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tvar s = GetComponent<ScalableSliceComponent>();\n\n\t\t\ts.Origin.Y = s.Sprite.Height;\n\t\t\ts.ShadowZ = -6;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent || e is DiedEvent) {\n\t\t\t\tif (!Done) {\n\t\t\t\t\tif (e is ExplodedEvent ee && ee.Who != this) {\n\t\t\t\t\t\ttrigger = ee.Who;\n\t\t\t\t\t}\n\n\t\t\t\t\tPrepareToExplode();\n\t\t\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\t\t\th.InvincibilityTimer = h.InvincibilityTimerMax;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t} else if (e is HealthModifiedEvent hme) {\n\t\t\t\tif (TryGetComponent<RoomComponent>(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\thme.Amount = -1;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprivate bool added;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!added) {\n\t\t\t\tadded = true;\n\t\t\t\t\n\t\t\t\tvar x = (int) Math.Floor(CenterX / 16);\n\t\t\t\tvar y = (int) Math.Floor(CenterY / 16);\n\n\t\t\t\tif (Run.Level.IsInside(x, y)) {\n\t\t\t\t\tRun.Level.Passable[Run.Level.ToIndex(x, y)] = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tillExplode > 0) {\n\t\t\t\ttillExplode -= dt;\n\n\t\t\t\tif (tillExplode <= 0) {\n\t\t\t\t\tExplode();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PrepareToExplode() {\n\t\t\ttillExplode = 0.5f;\n\n\t\t\tvar a = GetComponent<ScalableSliceComponent>();\n\t\t\t\n\t\t\tTween.To(1.4f, a.Scale.X, x => a.Scale.X = x, 0.4f);\n\t\t\tTween.To(0.7f, a.Scale.Y, x => a.Scale.Y = x, 0.4f);\n\n\t\t\tif (!HasComponent<AudioEmitterComponent>()) {\n\t\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\t}\n\t\t\t\n\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomized(\"level_tnt\");\n\t\t}\n\n\t\tprotected override GraphicsComponent CreateGraphicsComponent() {\n\t\t\treturn new ScalableSliceComponent(CommonAse.Props, Sprite);\n\t\t}\n\n\t\tpublic void Explode() {\n\t\t\tif (Done) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tDone = true;\n\t\t\tExplosionMaker.Make(this, 32f);\n\n\t\t\tvar who = trigger;\n\t\t\tvar count = 0;\n\n\t\t\twhile (who != null && who is ExplodingBarrel b) {\n\t\t\t\twho = b.trigger;\n\t\t\t\tcount++;\n\t\t\t}\n\n\t\t\tif (count >= 2) {\n\t\t\t\tAchievements.Unlock(\"bk:boom\");\n\t\t\t}\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 0, 16, 15);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Gramophone.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.events;\nusing Lens.entity;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.controller;\nusing BurningKnight.assets.particle.renderer;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Gramophone : Prop {\n\t\tprivate TextureRegion top;\n\t\tprivate TextureRegion bottom;\n\t\tprivate TextureRegion tdisk;\n\t\tprivate float t;\n\t\tprivate float tillNext;\n\t\tprivate bool broken;\n\t\tprivate int disk = 10;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tdisk = GlobalSave.GetInt(\"disk\");\n\n\t\t\ttop = CommonAse.Props.GetSlice(\"player_top\");\n\t\t\tbottom = CommonAse.Props.GetSlice(\"player\");\n\t\t\ttdisk = CommonAse.Props.GetSlice(\"disk\");\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tdisk = stream.ReadByte();\n\t\t\tbroken = GetComponent<HealthComponent>().HasNoHealth;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte((byte) disk);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tWidth = 16;\n\t\t\tHeight = 23;\n\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new ShadowComponent(RenderWithShadow));\n\t\t\tAddComponent(new RectBodyComponent(0, 17, 16, 6, BodyType.Static, false));\n\t\t\tAddComponent(new SensorBodyComponent(-2, -2, Width + 4, Height + 4, BodyType.Static));\n\t\t\t//AddComponent(new InteractableComponent(Interact));\n\t\t\t\n\t\t\tAddComponent(new HealthComponent {\n\t\t\t\tInitMaxHealth = 5\n\t\t\t});\n\t\t}\n\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tvar h = entity.TryGetComponent<ActiveWeaponComponent>(out var c);\n\t\t\tvar l = h && c.Item != null && c.Item.Id.StartsWith(\"bk:disk_\");\n\t\t\tvar hd = false;\n\n\t\t\tif (disk > 0) {\n\t\t\t\tif (h) {\n\t\t\t\t\thd = true;\n\t\t\t\t} else {\n\t\t\t\t\tDropDisk();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (l) {\n\t\t\t\ttry {\n\t\t\t\t\tvar id = byte.Parse(c.Item.Id.Replace(\"bk:disk_\", \"\"));\n\t\t\t\t\tvar old = c.Item;\n\n\t\t\t\t\tif (hd) {\n\t\t\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd($\"bk:disk_{disk}\", Area));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.Set(null, false);\n\t\t\t\t\t}\n\n\t\t\t\t\tdisk = id;\n\t\t\t\t\t\n\t\t\t\t\told.Done = true;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t} else if (hd) {\n\t\t\t\tentity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd($\"bk:disk_{disk}\", Area));\n\t\t\t\tdisk = 0;\n\t\t\t}\n\t\t\t\n\t\t\tGlobalSave.Put(\"disk\", disk);\n\t\t\t\n\t\t\tSendEvent();\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tt += dt;\n\n\t\t\tif (GetComponent<HealthComponent>().HasNoHealth || disk == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\ttillNext -= dt;\n\n\t\t\tif (tillNext <= 0) {\n\t\t\t\ttillNext = Rnd.Float(1, 3f);\n\t\t\t\t\n\t\t\t\tvar part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($\"note_{Rnd.Int(1, 3)}\"))));\n\t\t\t\tpart.Position = Center;\n\t\t\t\tArea.Add(part);\n\t\t\t\t\n\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(40, 66));\n\t\t\t\tpart.Particle.Angle = 0;\n\t\t\t\tpart.Depth = Layers.InGameUi;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tRealRender();\n\t\t}\n\n\t\tprivate void RealRender(bool shadow = false) {\n\t\t\tif (shadow) {\n\t\t\t\tGraphics.Render(bottom, Position + new Vector2(0, 34), 0, Vector2.Zero, MathUtils.InvertY);\n\n\t\t\t\tif (broken) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Render(top, Position + new Vector2(9, 28), (float) Math.Cos(t) * -0.1f, new Vector2(9, 14),\n\t\t\t\t\tnew Vector2((float) Math.Cos(t * 2f) * 0.05f + 1f, (float) Math.Sin(t * 2f) * -0.05f - 1f));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/*var c = GetComponent<InteractableComponent>();\n\t\t\t\n\t\t\tif (c.OutlineAlpha > 0.05f) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(c.OutlineAlpha);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(bottom, Position + new Vector2(0, 12) + d);\n\n\t\t\t\t\tif (!broken) {\n\t\t\t\t\t\tGraphics.Render(top, Position + new Vector2(9, 14) + d, (float) Math.Cos(t) * 0.1f, new Vector2(9, 14),\n\t\t\t\t\t\t\tnew Vector2((float) Math.Cos(t * 2f) * 0.05f + 1f, (float) Math.Sin(t * 2f) * 0.05f + 1f));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tShaders.End();\n\t\t\t}*/\n\n\t\t\tvar stopShader = false;\n\t\t\tvar h = GetComponent<HealthComponent>();\n\t\t\t\n\t\t\tif (h.RenderInvt) {\n\t\t\t\tvar i = h.InvincibilityTimer;\n\n\t\t\t\tif (i > h.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) {\n\t\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\t\tshader.Parameters[\"flash\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(ColorUtils.White);\n\t\t\t\t\t\n\t\t\t\t\tstopShader = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Render(bottom, Position + new Vector2(0, 12));\n\n\t\t\tif (disk > 0) {\n\t\t\t\tGraphics.Render(tdisk, Position + new Vector2(2, 13));\n\t\t\t}\n\n\t\t\tif (!broken) {\n\t\t\t\tGraphics.Render(top, Position + new Vector2(9, 14), (float) Math.Cos(t) * 0.1f, new Vector2(9, 14),\n\t\t\t\t\tnew Vector2((float) Math.Cos(t * 2f) * 0.05f + 1f, (float) Math.Sin(t * 2f) * 0.05f + 1f));\n\t\t\t}\n\t\t\t\n\t\t\tif (stopShader) {\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t}\n\n\t\tprivate void RenderWithShadow() {\n\t\t\tRealRender(true);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is PostHealthModifiedEvent) {\n\t\t\t\tif (GetComponent<HealthComponent>().HasNoHealth) {\n\t\t\t\t\tif (!broken) {\n\t\t\t\t\t\tHandleEvent(new GramophoneBrokenEvent {\n\t\t\t\t\t\t\tGramophone = this\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tDropDisk();\n\t\t\t\t\t\tSendEvent();\n\t\t\t\t\t\tbroken = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate void DropDisk() {\n\t\t\tif (disk == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar item = Items.CreateAndAdd($\"bk:disk_{disk}\", Area);\n\t\t\titem.CenterX = CenterX;\n\t\t\titem.Y = Bottom + 4;\n\n\t\t\tdisk = 0;\n\t\t\tGlobalSave.Put(\"disk\", disk);\n\t\t}\n\n\t\tprivate void SendEvent() {\n\t\t\tHandleEvent(new DiskChangedEvent {\n\t\t\t\tGramophone = this,\n\t\t\t\tDisk = disk\n\t\t\t});\n\t\t}\n\n\t\tpublic string GetTune() {\n\t\t\tif (disk == 0) {\n\t\t\t\treturn null;\n\t\t\t} else if (disk == 10) {\n\t\t\t\treturn Run.Depth == 0 ? \"Hub\" : \"Shopkeeper\";\n\t\t\t}\n\n\t\t\treturn $\"Disk {disk}\";\n\t\t}\n\t\t\n\t\tpublic class DiskChangedEvent : Event {\n\t\t\tpublic Gramophone Gramophone;\n\t\t\tpublic int Disk;\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tImGui.InputInt(\"Disk\", ref disk);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/HiddenEntrance.cs",
    "content": "using BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class HiddenEntrance : SaveableEntity, PlaceableEntity {\n\t\tinternal string id;\n\t\t\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tforeach (var e in Area.Tagged[Tags.HiddenEntrance]) {\n\t\t\t\tif (e is HiddenExit h && h.id == id) {\n\t\t\t\t\tvar state = (InGameState) Engine.Instance.State;\n\t\t\t\t\tAudio.PlaySfx(\"player_descending\");\t\t\t\n\n\t\t\t\t\tstate.TransitionToBlack(Center, () => {\n\t\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tp.BottomCenter = e.BottomCenter + new Vector2(0, 2);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstate.ResetFollowing();\n\t\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\t\tstate.TransitionToOpen();\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate bool CanInteract(Entity e) {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tDepth = Layers.Entrance;\n\t\t\tAddTag(Tags.HiddenEntrance);\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tOnStart = entity => {\n\t\t\t\t\tif (entity is LocalPlayer) {\n\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, Locale.Get(\"descend\")));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tCanInteract = CanInteract\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, true));\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"dark_market\"));\n\t\t}\n\n\t\tprivate bool set;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!set) {\n\t\t\t\tset = true;\n\n\t\t\t\tif (Run.Depth > 0) {\n\t\t\t\t\tGameSave.Put(\"saw_blackmarket\", true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tid = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tif (id == null) {\n\t\t\t\tid = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tstream.WriteString(id);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (id == null) {\n\t\t\t\tid = \"\";\n\t\t\t}\n\n\t\t\tImGui.InputText(\"Id\", ref id, 64);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/HiddenExit.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.fx;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class HiddenExit : SaveableEntity, PlaceableEntity {\n\t\tinternal string id;\n\t\t\n\t\tprivate bool Interact(Entity entity) {\n\t\t\tforeach (var e in Area.Tagged[Tags.HiddenEntrance]) {\n\t\t\t\tif (e is HiddenEntrance h && h.id == id) {\n\t\t\t\t\tvar state = (InGameState) Engine.Instance.State;\n\t\t\t\t\tAudio.PlaySfx(\"player_descending\");\t\t\t\n\n\t\t\t\t\tstate.TransitionToBlack(Center, () => {\n\t\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\t\tp.Center = e.Center;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstate.ResetFollowing();\n\t\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\t\tstate.TransitionToOpen();\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate bool CanInteract(Entity e) {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 12;\n\t\t\tHeight = 15;\n\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tOnStart = entity => {\n\t\t\t\t\tif (entity is LocalPlayer) {\n\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, Locale.Get(\"ascend\")));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tCanInteract = CanInteract\n\t\t\t});\n\t\t\t\n\t\t\tAddTag(Tags.HiddenEntrance);\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, true));\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"ladder\"));\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tid = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tif (id == null) {\n\t\t\t\tid = \"\";\n\t\t\t}\n\t\t\t\n\t\t\tstream.WriteString(id);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (id == null) {\n\t\t\t\tid = \"\";\n\t\t\t}\n\n\t\t\tImGui.InputText(\"Id\", ref id, 64);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Portal.cs",
    "content": "using BurningKnight.save;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Portal : SaveableEntity {\n\t\t/*private static TextureRegion Region;\n\t\tpublic static LadderFx ExitFx;\n\t\tpublic static float Al;\n\n\t\tprivate Body Body;\n\t\tprivate LadderFx Fx;\n\t\tprivate float Last;\n\t\tprivate PointLight Light;\n\t\tprivate bool NoSpawn;\n\t\tprivate List<Particle> Parts = new List<>();\n\t\tprivate byte Type;\n\n\t\tpublic void SetType(byte Type) {\n\t\t\tthis.Type = Type;\n\t\t}\n\n\t\tpublic byte GetType() {\n\t\t\treturn Type;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tDepth = -1;\n\t\t\tBody = World.CreateSimpleBody(this, 4, 4, 8, 8, BodyDef.BodyType.DynamicBody, true);\n\n\t\t\tif (Body != null) World.CheckLocked(Body).SetTransform(this.X, this.Y, 0);\n\n\t\t\tLight = World.NewLight(64, new Color(1, 1, 1, 1), 64, 0, 0);\n\t\t\tLight.SetPosition(this.X + 8, this.Y + 8);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tBody = World.RemoveBody(Body);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.StartAlphaShape();\n\t\t\tfloat Dt = Gdx.Graphics.GetDeltaTime();\n\n\t\t\tif (!Dungeon.Game.GetState().IsPaused())\n\t\t\t\tfor (var I = Parts.Size() - 1; I >= 0; I--) {\n\t\t\t\t\tParticle P = Parts.Get(I);\n\t\t\t\t\tP.A += P.Av * Dt * 1.5f;\n\t\t\t\t\tP.Av += Dt * 3;\n\t\t\t\t\tP.D -= P.Junk ? Dt * 15 : Dt * 10;\n\t\t\t\t\tP.Rad -= Dt * 1f;\n\t\t\t\t\tP.T += Dt;\n\n\t\t\t\t\tif (P.Rad <= 0 || P.D <= 0) Parts.Remove(I);\n\n\t\t\t\t\tP.ReadPosition();\n\t\t\t\t\tP.Al = Math.Min(0.6f, P.Al + Dt);\n\t\t\t\t}\n\n\t\t\tLight.SetColor(ColorUtils.HSV_to_RGB(Dungeon.Time * 20 % 360, 360, 360));\n\n\t\t\tforeach (Particle P in Parts)\n\t\t\t\tif (!P.Junk) {\n\t\t\t\t\tif (P.Black) {\n\t\t\t\t\t\tGraphics.Shape.SetColor(0, 0, 0, P.Al);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tColor Cl = ColorUtils.HSV_to_RGB(Dungeon.Time * 20 % 360 - P.D, 360, 360);\n\t\t\t\t\t\tfloat V = Math.Max(0.1f, 1.2f - P.T * 0.7f);\n\t\t\t\t\t\tGraphics.Shape.SetColor(Cl.R * V, Cl.G * V, Cl.B * V, P.Al);\n\t\t\t\t\t}\n\n\n\t\t\t\t\tGraphics.Shape.Circle(P.X, P.Y, P.Rad);\n\t\t\t\t}\n\n\t\t\tforeach (Particle P in Parts)\n\t\t\t\tif (P.Junk) {\n\t\t\t\t\tvar Size = P.Rad;\n\t\t\t\t\tvar A = P.A * 10f;\n\t\t\t\t\tGraphics.Shape.SetColor(1, 1, 1, P.Al * 0.5f);\n\t\t\t\t\tGraphics.Shape.Rect(P.X - Size / 2, P.Y - Size / 2, Size / 2, Size / 2, Size, Size, 1, 1, A);\n\t\t\t\t\tGraphics.Shape.SetColor(1, 1, 1, P.Al);\n\t\t\t\t\tGraphics.Shape.Rect(P.X - Size / 2, P.Y - Size / 2, Size / 2, Size / 2, Size, Size, 0.5f, 0.5f, A);\n\t\t\t\t}\n\n\t\t\tGraphics.EndAlphaShape();\n\t\t}\n\n\t\tpublic override void Update(float Dt) {\n\t\t\tbase.Update(Dt);\n\t\t\tT += Dt;\n\t\t\tLast += Dt;\n\n\t\t\tif (!NoSpawn && Last >= 0.01f) {\n\t\t\t\tLast = 0;\n\t\t\t\tParts.Add(new Particle(this));\n\t\t\t\tParts.Add(new Particle(this));\n\t\t\t\tParts.Add(new Particle(this));\n\t\t\t}\n\n\t\t\tfloat Dx = Player.Instance.X - this.X - 2;\n\t\t\tfloat Dy = Player.Instance.Y - this.Y - 4;\n\t\t\tvar D = (float) Math.Sqrt(Dx * Dx + Dy * Dy);\n\t\t\tvar Dd = 32f;\n\n\t\t\tif (D < Dd) {\n\t\t\t\tMainMenuState.VoidMusic.Play();\n\t\t\t\tvar F = (Dd - D) / Dd;\n\t\t\t\tMainMenuState.VoidMusic.SetVolume(F * Settings.Music);\n\t\t\t\tPlayer.Instance.Velocity.X -= Dx / D * Dt * 2400 * F;\n\t\t\t\tPlayer.Instance.Velocity.Y -= Dy / D * Dt * 2400 * F;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tMainMenuState.VoidMusic.SetVolume(0);\n\t\t\t\tMainMenuState.VoidMusic.Pause();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader Reader) {\n\t\t\tbase.Load(Reader);\n\t\t\tType = Reader.ReadByte();\n\t\t\tWorld.CheckLocked(Body).SetTransform(this.X, this.Y, 0);\n\t\t\tLight.SetPosition(this.X + 8, this.Y + 8);\n\t\t}\n\n\t\tpublic override void Save(FileWriter Writer) {\n\t\t\tbase.Save(Writer);\n\t\t\tWriter.WriteByte(Type);\n\t\t}\n\n\t\tpublic override void OnCollision(Entity Entity) {\n\t\t\tif (T >= 0.3f && Entity is Player && !Player.Sucked) {\n\t\t\t\tPlayer.Sucked = true;\n\t\t\t\tPlayer.Instance.SetUnhittable(true);\n\t\t\t\tCamera.Shake(3);\n\t\t\t\tDungeon.DarkR = Dungeon.MAX_R;\n\t\t\t\tPlayer.Instance.Rotating = true;\n\t\t\t\tPlayer.Instance.SetUnhittable(true);\n\t\t\t\tCamera.Follow(null);\n\t\t\t\tVector3 Vec = Camera.Game.Project(new Vector3(Player.Instance.X, Player.Instance.Y + 8, 0));\n\t\t\t\tCamera.NoMove = true;\n\t\t\t\tVec = Camera.Ui.Unproject(Vec);\n\t\t\t\tVec.Y = Display.Height - Vec.Y / Display.UI_SCALE;\n\t\t\t\tDungeon.DarkX = Vec.X / Display.UI_SCALE;\n\t\t\t\tDungeon.DarkY = Vec.Y;\n\t\t\t\tNoSpawn = true;\n\t\t\t\tDungeon.Area.Add(new Smoke(X + 8, Y + 8));\n\t\t\t\tInGameState.StartTween = true;\n\t\t\t\tInGameState.Portal = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void OnCollisionEnd(Entity Entity) {\n\t\t\tif (Entity is Player && Fx != null) {\n\t\t\t\tFx.Remove();\n\t\t\t\tFx = null;\n\t\t\t\tExitFx = null;\n\t\t\t}\n\t\t}\n\n\t\tprivate class Particle {\n\t\t\tpublic float A;\n\t\t\tpublic float Al;\n\t\t\tpublic float Av;\n\t\t\tpublic bool Black;\n\t\t\tpublic float D;\n\t\t\tpublic bool Junk;\n\t\t\tpublic float Rad;\n\t\t\tpublic float Sx;\n\t\t\tpublic float Sy;\n\t\t\tpublic float T;\n\t\t\tpublic float X;\n\t\t\tpublic float Y;\n\n\t\t\tpublic Particle(Portal Portal) {\n\t\t\t\tAl = 0;\n\t\t\t\tA = Random.NewFloat(Math.PI * 2);\n\t\t\t\tvar V = (float) Math.PI;\n\t\t\t\tBlack = A % V > V * 0.5f;\n\t\t\t\tJunk = Random.Chance(1f);\n\t\t\t\tD = Junk ? Random.NewFloat(16, 32f) : 16f;\n\t\t\t\tRad = Junk ? 6f : 3f;\n\t\t\t\tSx = Portal.X;\n\t\t\t\tSy = Portal.Y;\n\t\t\t\tReadPosition();\n\t\t\t}\n\n\t\t\tpublic void ReadPosition() {\n\t\t\t\tX = Sx + 8 + Math.Cos(A) * D;\n\t\t\t\tY = Sy + 8 + Math.Sin(A) * D;\n\t\t\t}\n\t\t}*/\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Prop.cs",
    "content": "using BurningKnight.save;\r\nusing BurningKnight.ui.editor;\r\n\r\nnamespace BurningKnight.level.entities {\r\n\tpublic class Prop : SaveableEntity, PlaceableEntity {\r\n\t\t\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/RightBelt.cs",
    "content": "using BurningKnight.util;\n\nnamespace BurningKnight.level.entities {\n\tpublic class RightBelt : Belt {\n\t\tpublic RightBelt() {\n\t\t\tDirection = Direction.Right;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Safe.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Safe : SolidProp {\n\t\tprivate bool broken;\n\t\t\n\t\tpublic Safe() {\n\t\t\tSprite = \"safe\";\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 6, 19, 17);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 19;\n\t\t\tHeight = 23;\n\t\t\t\n\t\t\tAddComponent(new HealthComponent {\n\t\t\t\tRenderInvt = true,\n\t\t\t\tInitMaxHealth = Rnd.Int(2, 5)\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tvar drops = new DropsComponent();\n\t\t\tAddComponent(drops);\n\t\t\tdrops.Add(\"bk:safe\");\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tif (GetComponent<HealthComponent>().HasNoHealth) {\n\t\t\t\tBreak(false);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Break(bool spawnLoot = true) {\n\t\t\tif (broken) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbroken = true;\n\t\t\t\n\t\t\tGetComponent<SliceComponent>().Sprite = CommonAse.Props.GetSlice(\"safe_broken\");\n\t\t\tGetComponent<HealthComponent>().RenderInvt = false;\n\n\t\t\tif (spawnLoot) {\n\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (!broken) {\n\t\t\t\tif (e is HealthModifiedEvent ev) {\n\t\t\t\t\tif (ev.Type != DamageType.Explosive) {\n\t\t\t\t\t\tev.Amount = 0;\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tev.Amount = -1;\n\t\t\t\t} else if (e is DiedEvent) {\n\t\t\t\t\tBreak();\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tbroken = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(broken);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/ShadowedProp.cs",
    "content": "using BurningKnight.entity.component;\n\nnamespace BurningKnight.level.entities {\n\tpublic class ShadowedProp : SlicedProp {\n\t\tpublic ShadowedProp() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic ShadowedProp(string slice = null, int depth = 0) : base(slice, depth) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Sign.cs",
    "content": "using BurningKnight.entity.component;\r\nusing BurningKnight.ui.dialog;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.level.entities {\r\n\tpublic class Sign : Prop {\r\n\t\tpublic string Region = \"sign\";\r\n\t\tpublic bool DemoOnly;\r\n\t\t\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\t\r\n\t\t\tvar d = GetComponent<CloseDialogComponent>(); \r\n\t\t\tstream.WriteString(d.Variants.Length == 0 ? \"\" : d.Variants[0]);\r\n\t\t\tstream.WriteString(Region);\r\n\t\t\tstream.WriteBoolean(DemoOnly);\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\t\r\n\t\t\tSetMessage(stream.ReadString());\r\n\t\t\tRegion = stream.ReadString() ?? \"sign\";\r\n\t\t\tDemoOnly = stream.ReadBoolean();\r\n\t\t}\r\n\r\n\t\tpublic void SetMessage(string m) {\r\n\t\t\tGetComponent<CloseDialogComponent>().Variants = new [] { m };\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tAddComponent(new DialogComponent());\r\n\t\t\tAddComponent(new CloseDialogComponent());\r\n\t\t\tAddComponent(new ShadowComponent());\r\n\t\t\t\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 30;\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\t\t\tUpdateSprite();\r\n\r\n\t\t\tif (!Engine.EditingLevel && DemoOnly && !BK.Demo) {\r\n\t\t\t\tDone = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void UpdateSprite() {\r\n\t\t\tif (HasComponent<SliceComponent>()) {\r\n\t\t\t\tRemoveComponent<SliceComponent>();\r\n\t\t\t}\r\n\r\n\t\t\tvar c = new SliceComponent(\"props\", Region);\r\n\t\t\tAddComponent(c);\r\n\t\t\t\r\n\t\t\tWidth = c.Sprite.Width;\r\n\t\t\tHeight = c.Sprite.Height;\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void RenderImDebug() {\r\n\t\t\tvar d = GetComponent<CloseDialogComponent>();\r\n\t\t\tvar m = d.Variants.Length == 0 ? \"\" : d.Variants[0];\r\n\r\n\t\t\tif (m == null) {\r\n\t\t\t\tm = \"\";\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Message\", ref m, 128)) {\r\n\t\t\t\tSetMessage(m);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Sprite\", ref Region, 128)) {\r\n\t\t\t\tUpdateSprite();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Checkbox(\"Demo only\", ref DemoOnly);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/SlicedProp.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.save;\nusing BurningKnight.ui.editor;\nusing Lens.entity.component.graphics;\nusing Lens.util.file;\n\nnamespace BurningKnight.level.entities {\n\tpublic class SlicedProp : Prop {\n\t\tpublic string Sprite;\n\t\t\n\t\tpublic SlicedProp(string slice = null, int depth = 0) {\n\t\t\tSprite = slice;\n\t\t\tDepth = depth;\n\t\t}\n\n\t\t// Used for loading\n\t\tpublic SlicedProp() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tInsertGraphics();\n\t\t}\n\n\t\tprotected virtual GraphicsComponent CreateGraphicsComponent() {\n\t\t\treturn HasComponent<InteractableComponent>()\n\t\t\t\t\t? new InteractableSliceComponent(\"props\", Sprite)\n\t\t\t\t\t: new SliceComponent(\"props\", Sprite);\n\t\t}\n\n\t\tprotected virtual void InsertGraphics() {\n\t\t\tAddComponent(CreateGraphicsComponent());\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(Sprite);\n\t\t\tstream.WriteSbyte((sbyte) Depth);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tSprite = stream.ReadString();\n\t\t\tDepth = stream.ReadSbyte();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/SolidProp.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.util;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.physics;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class SolidProp : SlicedProp, CollisionFilterEntity {\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tAddComponent(CreateBody());\n\t\t}\n\n\t\tprotected virtual BodyComponent CreateBody() {\n\t\t\tvar collider = GetCollider();\n\t\t\treturn new RectBodyComponent(collider.X, collider.Y, collider.Width, collider.Height, BodyType.Static);\n\t\t}\n\n\t\tprotected virtual Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 0, 32, 32);\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Creature c && c.InAir());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Stand.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Stand : SolidProp {\n\t\tprivate static int[] heights = {22, 17, 14};\n\t\t\n\t\tprivate int id;\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, (int) heights[id] - 8, 13, 8);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tSprite = $\"stand_{id}\";\n\n\t\t\tbase.PostInit();\n\t\t\tvar s = GetComponent<InteractableSliceComponent>().Sprite;\n\n\t\t\tWidth = s.Width;\n\t\t\tHeight = s.Height;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tvar r = GetCollider();\n\t\t\t\n\t\t\tAddComponent(new SensorBodyComponent(r.X - 2, r.Y - Npc.Padding, r.Width + 4, r.Height + Npc.Padding * 2, BodyType.Static));\n\t\t\tAddComponent(new DialogComponent());\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tvar p = $\"top_{(int) id}\";\n\t\t\t\n\t\t\tif (!GlobalSave.Exists(p) || GlobalSave.GetString($\"{p}_data\") == null) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"no_score_yet\", 3);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tGlobalSave.GetJson($\"{p}_data\");\n\t\t\t} catch (Exception ex) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"no_score_yet\", 3);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar s = (InGameState) Engine.Instance.State;\n\n\t\t\ts.InStats = true;\n\t\t\ts.Paused = true;\n\t\t\t\n\t\t\ts.ReturnFromStats = () => {\n\t\t\t\ts.Paused = false;\n\t\t\t\ts.InStats = false;\n\t\t\t};\n\n\t\t\ts.ShowStats(id, p);\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tid = stream.ReadInt32();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteInt32(id);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (ImGui.InputInt(\"Id\", ref id)) {\n\t\t\t\tRemoveComponent<InteractableSliceComponent>();\n\t\t\t\tInsertGraphics();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/StatDisplay.cs",
    "content": "using BurningKnight.assets.achievements;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens;\nusing Lens.entity;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class StatDisplay : SolidProp {\n\t\tprivate string board;\n\t\tprivate int challengeId;\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 6, 17, 4);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tSprite = \"stat_display\";\n\t\t\tbase.PostInit();\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 17;\n\t\t\tHeight = 10;\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t\tAddComponent(new ShadowComponent());\n\n\t\t\tAddComponent(new SensorBodyComponent(-2, -Npc.Padding, Width + 4, Height + Npc.Padding * 2, BodyType.Static));\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tvar s = (InGameState) Engine.Instance.State;\n\n\t\t\ts.InStats = true;\n\t\t\ts.Paused = true;\n\t\t\t\n\t\t\ts.ReturnFromLeaderboard = () => {\n\t\t\t\ts.InStats = false;\n\t\t\t};\n\n\t\t\tvar b = board;\n\n\t\t\tif (board == \"daily\") {\n\t\t\t\tb = $\"daily_{Run.CalculateDailyId()}\";\n\t\t\t} else if (board == \"challenge\") {\n\t\t\t\tb = $\"challenge_{challengeId}\";\n\t\t\t}\n\n\t\t\ts.ShowLeaderboard(b, board);\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate bool ch;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!Engine.EditingLevel && !ch) {\n\t\t\t\tch = true;\n\t\t\t\t\n\t\t\t\tif (InGameState.SetupLeaderboard == null || (board == \"daily\" && !GlobalSave.IsTrue($\"daily_{Run.CalculateDailyId()}\"))) {\n\t\t\t\t\tDone = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\tboard = stream.ReadString();\n\n\t\t\tif (board == \"challenge\") {\n\t\t\t\tchallengeId = stream.ReadInt32();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(board);\n\n\t\t\tif (board == \"challenge\") {\n\t\t\t\tstream.WriteInt32(challengeId);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tif (board == null) {\n\t\t\t\tboard = \"\";\n\t\t\t}\n\n\t\t\tImGui.InputText(\"Board\", ref board, 128);\n\t\t\t\n\t\t\tif (board == \"challenge\") {\n\t\t\t\tImGui.InputInt(\"Challenge Id\", ref challengeId);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Teleporter.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.save;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities {\n\tpublic class Teleporter : SaveableEntity {\n\t\tpublic string Id = \"a\";\n\t\tprivate bool ignoreCollision;\n\t\tprivate bool played;\n\n\t\tpublic static string[] Ids = {\n\t\t\t\"b\", \"c\", \"d\", \"e\", \n\t\t\t\"f\", \"i\", \"g\"\n\t\t};\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tDepth = Layers.Entrance;\n\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tAddTag(Tags.Teleport);\n\t\t\t\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new SensorBodyComponent(1, 1, 14, 14, BodyType.Static));\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 64, ProjectileColor.Purple));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tAddComponent(new SliceComponent(\"props\", $\"teleport_{Id}\"));\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(Id);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tId = stream.ReadString();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity is Player) {\n\t\t\t\t\tignoreCollision = false;\n\t\t\t\t\tplayed = false;\n\t\t\t\t}\n\t\t\t} else if (e is CollisionStartedEvent cse && cse.Entity is Player c) {\n\t\t\t\tif (ignoreCollision || played) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\tplayed = true;\n\t\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\n\t\t\t\tif (Id != \"a\" && room == null) {\n\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t}\n\n\t\t\t\tvar l = Id == \"a\" ? Area.Tagged[Tags.Teleport] : room.Tagged[Tags.Teleport];\n\t\t\t\t\n\t\t\t\tforeach (var t in l) {\n\t\t\t\t\tvar tr = (Teleporter) t;\n\t\t\t\t\t\n\t\t\t\t\tif (tr != this && tr.Id == Id) {\n\t\t\t\t\t\tAudio.PlaySfx(\"level_teleport_send\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tAnimationUtil.TeleportAway(c, () => {\n\t\t\t\t\t\t\ttr.ignoreCollision = true;\n\t\t\t\t\t\t\tc.BottomCenter = tr.Center;\n\t\t\t\t\t\t\tCamera.Instance.Jump();\n\t\t\t\t\t\t\tc.GetComponent<HealthComponent>().InvincibilityTimer = 1;\n\t\t\t\t\t\t\tAudio.PlaySfx(\"level_teleport_arrive\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tAnimationUtil.TeleportIn(c);\n\t\t\t\t\t\t});\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn base.HandleEvent(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tLog.Error($\"Failed to teleport to {Id}\");\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/Tombstone.cs",
    "content": "using System;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.entity;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.npc;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.fx;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.dialog;\r\nusing BurningKnight.ui.inventory;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.input;\r\nusing Lens.util.camera;\r\nusing Lens.util.file;\r\nusing Microsoft.Xna.Framework;\r\nusing VelcroPhysics.Dynamics;\r\n\r\nnamespace BurningKnight.level.entities {\r\n\tpublic class Tombstone : Prop {\r\n\t\tpublic string Item;\r\n\t\tpublic bool DisableDialog;\r\n\t\tpublic byte Index;\r\n\t\tpublic bool HasPlayer;\r\n\t\tpublic bool WasGamepad;\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tWidth = 12;\r\n\t\t\t\r\n\t\t\tAddComponent(new RoomComponent());\r\n\t\t\tAddComponent(new DialogComponent());\r\n\r\n\t\t\tif (!DisableDialog) {\r\n\t\t\t\tAddComponent(new CloseDialogComponent(\"tomb_0\") {\r\n\t\t\t\t\tCanTalk = e => Item != null\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tAddComponent(new RectBodyComponent(0, 2, 12, 14, BodyType.Static));\r\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\r\n\t\t\t\r\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"tombstone\"));\r\n\r\n\t\t\tAddComponent(new ShadowComponent());\r\n\t\t\tAddComponent(new HealthComponent {\r\n\t\t\t\tRenderInvt = !DisableDialog,\r\n\t\t\t\tInitMaxHealth = 3\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAddComponent(new LightComponent(this, 64, new Color(0.7f, 0.6f, 0.3f, 1f)));\r\n\t\t\t\r\n\t\t\tSubscribe<RoomChangedEvent>();\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 30;\r\n\t\t}\r\n\r\n\t\tpublic static Player CreatePlayer(Area area, byte index, bool gamepad, Vector2 where) {\r\n\t\t\tInGameState.Multiplayer = true;\r\n\t\t\t\r\n\t\t\tPlayer p;\r\n\t\t\tvar input = area.Add(p = new LocalPlayer()).GetComponent<InputComponent>();\r\n\t\t\t\r\n\t\t\tinput.Index = index;\r\n\t\t\tinput.KeyboardEnabled = !gamepad;\r\n\t\t\tinput.GamepadEnabled = gamepad;\r\n\t\t\t\r\n\t\t\tp.BottomCenter = where;\r\n\t\t\t\r\n\t\t\tvar cursor = new Cursor {\r\n\t\t\t\tPlayer = p\r\n\t\t\t};\r\n\r\n\t\t\tvar u = new UiInventory(p, true);\r\n\r\n\t\t\tu.ForceUpdate = true;\r\n\t\t\t\r\n\t\t\t((InGameState) Engine.Instance.State).Ui.Add(u);\r\n\t\t\t((InGameState) Engine.Instance.State).TopUi.Add(cursor);\r\n\r\n\t\t\tp.GetComponent<CursorComponent>().Cursor = cursor;\r\n\t\t\t\r\n\t\t\tAnimationUtil.Poof(where, 1);\r\n\t\t\tCamera.Instance.Shake(16);\r\n\t\t\t\r\n\t\t\treturn p;\r\n\t\t}\r\n\r\n\t\tpublic bool Revive(Entity e) {\r\n\t\t\tItem = null;\r\n\t\t\tUpdateSprite();\r\n\t\t\tvar p = CreatePlayer(Area, Index, WasGamepad, BottomCenter + new Vector2(0, 2));\r\n\t\t\tIndex = 255;\r\n\r\n\t\t\tvar h1 = e.GetComponent<HealthComponent>();\r\n\t\t\tvar hr1 = e.GetComponent<HeartsComponent>();\r\n\t\t\tvar h2 = p.GetComponent<HealthComponent>();\r\n\t\t\tvar hr2 = p.GetComponent<HeartsComponent>();\r\n\t\t\t\r\n\t\t\tp.GetComponent<ActiveWeaponComponent>().Set(Items.CreateAndAdd(Items.Generate(ItemPool.StartingWeapon), Area));\r\n\r\n\t\t\th1.InvincibilityTimer = 0;\r\n\t\t\th1.Unhittable = false;\r\n\t\t\th2.InvincibilityTimer = 0;\r\n\t\t\th2.Unhittable = false;\r\n\t\t\t\r\n\t\t\tif (h1.Health > 0) {\r\n\t\t\t\tvar half = (int) Math.Max(1, Math.Floor(h1.Health / 2f));\r\n\r\n\t\t\t\th1.SetHealth(half, e, true, DamageType.Custom);\r\n\t\t\t\th2.SetHealth(half, e, true, DamageType.Custom);\r\n\t\t\t} else if (hr1.ShieldHalfs > 0) {\r\n\t\t\t\tvar half = (int) Math.Max(1, Math.Floor(hr1.ShieldHalfs / 2f));\r\n\t\t\t\thr1.ModifyShields(-(hr1.ShieldHalfs - half), e);\r\n\t\t\t\thr2.ModifyShields(-(hr2.ShieldHalfs - half), e);\r\n\t\t\t} else {\r\n\t\t\t\tvar half = (int) Math.Max(1, Math.Floor(hr1.Bombs / 2f));\r\n\t\t\t\thr2.BombsMax = hr1.BombsMax;\r\n\r\n\t\t\t\thr1.ModifyBombs(-(hr1.Bombs - half), e);\r\n\t\t\t\thr2.ModifyBombs(-(hr2.Bombs - half), e);\r\n\t\t\t}\r\n\r\n\t\t\tif (p.GetComponent<InputComponent>().Index == 0) {\r\n\t\t\t\tvar minIndex = 1024;\r\n\t\t\t\tPlayer pl = null;\r\n\r\n\t\t\t\tforeach (var pr in Area.Tagged[Tags.Player]) {\r\n\t\t\t\t\tvar i = pr.GetComponent<InputComponent>().Index;\r\n\r\n\t\t\t\t\tif (p != pr && i < minIndex) {\r\n\t\t\t\t\t\tminIndex = i;\r\n\t\t\t\t\t\tpl = (Player) pr;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pl != null) {\r\n\t\t\t\t\tvar c = pl.ForceGetComponent<ConsumablesComponent>();\r\n\t\t\t\t\tc.Entity = p;\r\n\t\t\t\t\tpl.Components.Remove(typeof(ConsumablesComponent));\r\n\t\t\t\t\tp.Components[typeof(ConsumablesComponent)] = c;\r\n\t\t\t\t\tpl.AddComponent(new ConsumablesComponent());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tif (HasPlayer) {\r\n\t\t\t\tAddComponent(new InteractableComponent(Revive) {\r\n\t\t\t\t\tCanInteract = e => Index != 255,\r\n\t\t\t\t\tOnStart = entity => {\r\n\t\t\t\t\t\tif (entity is LocalPlayer) {\r\n\t\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, Locale.Get(\"revive\")));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t},\r\n\t\t\t\t});\r\n\t\t\t} else if (!DisableDialog) {\r\n\t\t\t\tAddComponent(new InteractableComponent(Interact) {\r\n\t\t\t\t\tCanInteract = e => Item != null\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is DiedEvent d) {\r\n\t\t\t\tInteract(d.From);\r\n\t\t\t\treturn true;\r\n\t\t\t} else if (e is RoomChangedEvent rce) {\r\n\t\t\t\tif (rce.Who is Player && rce.New == GetComponent<RoomComponent>().Room) {\r\n\t\t\t\t\t// Daddy? What did they do with you?!?!\r\n\t\t\t\t\t// rce.Who.GetComponent<DialogComponent>().StartAndClose(\"player_0\", 3f);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tprivate bool Interact(Entity entity) {\r\n\t\t\tif (Item == null) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\r\n\t\t\tvar i = Items.CreateAndAdd(Item, entity.Area);\r\n\r\n\t\t\tif (i != null) {\r\n\t\t\t\ti.CenterX = CenterX;\r\n\t\t\t\ti.Y = Bottom;\r\n\t\t\t\ti.Scourged = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tItem = null;\r\n\t\t\tUpdateSprite();\r\n\t\t\tRun.AddScourge(true);\r\n\r\n\t\t\tGetComponent<DialogComponent>().Close();\r\n\t\t\t\r\n\t\t\tAnimationUtil.Poof(Center);\r\n\t\t\tCamera.Instance.Shake(16);\r\n\t\t\t\r\n\t\t\t// fixme: spawn ghosts, dialog should not appear when player is ded\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\t\r\n\t\t\tItem = stream.ReadString();\r\n\t\t\tUpdateSprite();\r\n\r\n\t\t\tWasGamepad = stream.ReadBoolean();\r\n\r\n\t\t\tif (stream.ReadBoolean()) {\r\n\t\t\t\tHasPlayer = true;\r\n\t\t\t\tIndex = stream.ReadByte();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\t\r\n\t\t\tstream.WriteString(Item);\r\n\t\t\tstream.WriteBoolean(WasGamepad);\r\n\t\t\tstream.WriteBoolean(HasPlayer);\r\n\t\t\t\r\n\t\t\tif (HasPlayer) {\r\n\t\t\t\tstream.WriteByte(Index);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void RenderImDebug() {\r\n\t\t\tbase.RenderImDebug();\r\n\r\n\t\t\tvar has = Item != null;\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Has item\", ref has)) {\r\n\t\t\t\tItem = has ? \"\" : null;\r\n\t\t\t\tUpdateSprite();\r\n\t\t\t}\r\n\r\n\t\t\tif (has) {\r\n\t\t\t\tImGui.InputText(\"Item##itm\", ref Item, 128);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void UpdateSprite() {\r\n\t\t\tGetComponent<InteractableSliceComponent>().Set(\"props\", Item == null ? \"broken_tombstone\" : \"tombstone\");\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/UpBelt.cs",
    "content": "using BurningKnight.util;\n\nnamespace BurningKnight.level.entities {\n\tpublic class UpBelt : Belt {\n\t\tpublic UpBelt() {\n\t\t\tDirection = Direction.Up;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/building/House.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.assets;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.building {\n\tpublic class House : SolidProp {\n\t\tprivate TextureRegion shadow;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 141;\n\t\t\tHeight = 164;\n\t\t\tSprite = \"house\";\n\n\t\t\tshadow = Animations.Get(\"buildings\").GetSlice(\"house_shadow\");\n\t\t\t\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t}\n\n\t\tprotected override GraphicsComponent CreateGraphicsComponent() {\n\t\t\treturn new SliceComponent(\"buildings\", Sprite);\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(4, 84, 132, 75);\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphics.Render(shadow, Position + new Vector2(0,  Height + shadow.Height - 5), 0, Vector2.Zero, MathUtils.InvertY);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/building/Thing.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.graphics;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities.building {\n\tpublic class Thing : Prop, CollisionFilterEntity {\n\t\tprivate TextureRegion shadow;\n\t\tprivate bool separateShadow;\n\t\tprivate bool hasShadow = true;\n\t\tprivate string file = \"\";\n\t\tprivate string sprite = \"\";\n\t\tprivate bool hasBody = true;\n\t\tprivate Rectangle collider;\n\n\t\tprivate bool displayCollider = true;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (file != null && sprite != null) {\n\t\t\t\tAddComponent(new SliceComponent(file, sprite));\n\t\t\t}\n\n\t\t\tif (!Engine.EditingLevel && hasBody) {\n\t\t\t\tAddComponent(new RectBodyComponent(collider.X, collider.Y, collider.Width, collider.Height, BodyType.Static));\n\t\t\t}\n\t\t}\n\n\t\tprivate void UpdateSprite() {\n\t\t\tvar f = Animations.Get(file);\n\n\t\t\tif (f == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar sp = f.GetSlice(sprite);\n\n\t\t\tif (!HasComponent<SliceComponent>()) {\n\t\t\t\tAddComponent(new SliceComponent(file, sprite));\n\t\t\t} else {\n\t\t\t\tGetComponent<SliceComponent>().Sprite = sp;\n\t\t\t}\n\n\t\t\tif (sp != null) {\n\t\t\t\tWidth = sp.Width;\n\t\t\t\tHeight = sp.Height;\n\t\t\t}\n\t\t\t\n\t\t\tif (separateShadow) {\n\t\t\t\tshadow = f.GetSlice($\"{sprite}_shadow\");\n\t\t\t}\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tif (!hasShadow) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (separateShadow) {\n\t\t\t\tGraphics.Render(shadow, Position + new Vector2(0,  Height + shadow.Height), 0, Vector2.Zero, MathUtils.InvertY);\n\t\t\t} else {\n\t\t\t\tGraphicsComponent?.Render(true);\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Creature c && c.InAir());\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (Engine.EditingLevel && displayCollider && hasBody) {\n\t\t\t\tGraphics.Batch.DrawRectangle(new RectangleF(X + collider.X, Y + collider.Y, collider.Width, collider.Height), Color.Red);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tif (ImGui.InputText(\"File\", ref file, 128)) {\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\t\t\n\t\t\tif (ImGui.InputText(\"Slice\", ref sprite, 128)) {\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Has shadow\", ref hasShadow);\n\t\t\tImGui.Checkbox(\"Custom shadow sprite\", ref separateShadow);\n\t\t\tImGui.Separator();\n\t\t\tImGui.Checkbox(\"Has body\", ref hasBody);\n\t\t\t\n\t\t\tif (hasBody) {\n\t\t\t\tvar x = collider.X;\n\t\t\t\tvar y = collider.Y;\n\t\t\t\tvar w = collider.Width;\n\t\t\t\tvar h = collider.Height;\n\n\t\t\t\tif (ImGui.InputInt(\"X\", ref x)) {\n\t\t\t\t\tcollider.X = x;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.InputInt(\"Y\", ref y)) {\n\t\t\t\t\tcollider.Y = y;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.InputInt(\"W\", ref w)) {\n\t\t\t\t\tcollider.Width = w;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.InputInt(\"H\", ref h)) {\n\t\t\t\t\tcollider.Height = h;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tImGui.Checkbox(\"Display collider\", ref displayCollider);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\thasShadow = stream.ReadBoolean();\n\t\t\thasBody = stream.ReadBoolean();\n\n\t\t\tif (hasBody) {\n\t\t\t\tcollider.X = stream.ReadInt16();\n\t\t\t\tcollider.Y = stream.ReadInt16();\n\t\t\t\tcollider.Width = stream.ReadInt16();\n\t\t\t\tcollider.Height = stream.ReadInt16();\n\t\t\t}\n\n\t\t\tfile = stream.ReadString();\n\t\t\tsprite = stream.ReadString();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteBoolean(hasShadow);\n\t\t\tstream.WriteBoolean(hasBody);\n\n\t\t\tif (hasBody) {\n\t\t\t\tstream.WriteInt16((short) collider.X);\n\t\t\t\tstream.WriteInt16((short) collider.Y);\n\t\t\t\tstream.WriteInt16((short) collider.Width);\n\t\t\t\tstream.WriteInt16((short) collider.Height);\n\t\t\t}\n\t\t\t\n\t\t\tstream.WriteString(file);\n\t\t\tstream.WriteString(sprite);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/AnimatedChest.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens.util.tween;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class AnimatedChest : Chest {\n\t\tprotected override void AddGraphics() {\n\t\t\tAddComponent(new AnimationComponent(GetSprite()));\n\t\t}\n\n\t\tprotected override void UpdateSprite(bool open = true) {\n\t\t\tGetComponent<AnimationComponent>().Animation.Tag = open ? \"open\" : \"idle\";\n\t\t}\n\t\t\n\t\tprotected override void Animate() {\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\n\t\t\ta.Scale.X = 0.6f * Scale;\n\t\t\ta.Scale.Y = 1.7f * Scale;\n\t\t\t\t\t\n\t\t\tTween.To(1.8f * Scale, a.Scale.X, x => a.Scale.X = x, 0.15f);\n\t\t\tTween.To(0.2f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.15f).OnEnd = () => {\n\t\t\t\tTween.To(Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\tTween.To(Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t};\n\t\t}\n\n\t\tprotected override void Animate(Action callback) {\n\t\t\tvar a = GetComponent<AnimationComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(1.8f * Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\tTween.To(0.2f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tcallback();\n\t\t\t\t\n\t\t\t\tTween.To(0.6f * Scale, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(1.7f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\t\tTween.To(Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/Chest.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.physics;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class Chest : Prop, CollisionFilterEntity {\n\t\tprotected bool open;\n\t\tprotected internal float Scale = 1;\n\t\tprivate bool transitioning;\n\n\t\tpublic bool CanOpen = true;\n\t\tpublic bool Empty;\n\t\t\n\t\tprotected virtual Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, (int) (5 * Scale), (int) (Math.Max(1, 17 * Scale)), (int) (Math.Max(1, 8 * Scale)));\n\t\t}\n\t\t\n\t\tprotected virtual BodyComponent CreateBody() {\n\t\t\tvar collider = GetCollider();\n\t\t\treturn new RectBodyComponent(collider.X, collider.Y, collider.Width, collider.Height);\n\t\t}\n\n\t\tprotected virtual float GetWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tprotected virtual float GetHeight() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tWidth = GetWidth() * Scale;\n\t\t\tHeight = GetHeight() * Scale;\n\n\t\t\tAddGraphics();\n\t\t\tAddComponent(new SensorBodyComponent(-2, -2, Width + 4, Height + 4));\n\t\t\tAddComponent(new DropsComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => CanOpen && ShouldOpen()\n\t\t\t});\n\t\t\t\n\t\t\tAddTag(Tags.Chest);\n\t\t\tAddTag(Tags.Item);\n\t\t\t\n\t\t\tDefineDrops();\n\t\t}\n\n\t\tprotected virtual bool ShouldOpen() {\n\t\t\treturn !open;\n\t\t}\n\n\t\tprotected virtual void AddGraphics() {\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", GetSprite()));\n\t\t}\n\n\t\tprotected virtual void DefineDrops() {\n\t\t\tvar p = GetPool();\n\n\t\t\tif (p != null) {\n\t\t\t\tGetComponent<DropsComponent>().Add(p);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tAddComponent(CreateBody());\n\n\t\t\tif (open) {\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\n\t\t\tvar body = GetComponent<RectBodyComponent>().Body;\n\n\t\t\tbody.LinearDamping = 100;\n\t\t\tbody.Mass = 1000000;\n\n\t\t\tGetComponent<RectBodyComponent>().KnockbackModifier = 0.1f;\n\t\t\tAnimate();\n\t\t}\n\t\t\n\t\tprotected virtual void Animate() {\n\t\t\tvar a = GetComponent<InteractableSliceComponent>();\n\n\t\t\ta.Scale.X = 0.6f * Scale;\n\t\t\ta.Scale.Y = 1.7f * Scale;\n\t\t\t\t\t\n\t\t\tTween.To(1.8f * Scale, a.Scale.X, x => a.Scale.X = x, 0.15f);\n\t\t\tTween.To(0.2f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.15f).OnEnd = () => {\n\t\t\t\tTween.To(Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\tTween.To(Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t};\n\t\t}\n\n\t\tpublic virtual string GetSprite() {\n\t\t\treturn \"chest\";\n\t\t}\n\n\t\tpublic virtual string GetPool() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprotected virtual void UpdateSprite(bool open = true) {\n\t\t\tGetComponent<InteractableSliceComponent>().Sprite = CommonAse.Props.GetSlice($\"{GetSprite()}{(open ? \"_open\" : \"\")}\");\n\t\t}\n\n\t\tpublic void Open(Entity who) {\n\t\t\tif (open || transitioning) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\topen = true;\n\t\t\ttransitioning = true;\n\t\t\t\n\t\t\tAnimate(() => {\n\t\t\t\ttransitioning = false;\n\t\t\t\t\n\t\t\t\tUpdateSprite();\n\t\t\t\tSpawnDrops();\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomized(\"level_chest_open\");\n\t\t\t});\n\n\t\t\tHandleEvent(new OpenedEvent {\n\t\t\t\tChest = this,\n\t\t\t\tWho = who\n\t\t\t});\n\t\t}\n\n\t\tpublic void Close() {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransitioning = true;\n\t\t\t\n\t\t\tAnimate(() => {\n\t\t\t\topen = false;\n\t\t\t\ttransitioning = false;\n\t\t\t\tUpdateSprite(false);\n\n\t\t\t\t// GetComponent<AudioEmitterComponent>().EmitRandomized(\"level_chest_open\");\n\t\t\t});\n\t\t}\n\n\t\tprotected virtual void Animate(Action callback) {\n\t\t\tvar a = GetComponent<InteractableSliceComponent>();\n\t\t\t\t\t\n\t\t\tTween.To(1.8f * Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\tTween.To(0.2f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => {\n\t\t\t\tcallback();\n\t\t\t\t\n\t\t\t\tTween.To(0.6f * Scale, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\tTween.To(1.7f * Scale, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => {\n\t\t\t\t\tTween.To(Scale, a.Scale.X, x => a.Scale.X = x, 0.2f);\n\t\t\t\t\tTween.To(Scale, a.Scale.Y, x => a.Scale.Y = x, 0.2f);\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\t\t\n\t\tprotected virtual void SpawnDrops() {\n\t\t\tif (!Empty) {\n\t\t\t\tEmpty = true;\n\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool Interact(Entity entity) {\n\t\t\tif (open || !CanOpen) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (TryOpen(entity)) {\n\t\t\t\tOpen(entity);\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected virtual bool TryOpen(Entity entity) {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteBoolean(open);\n\t\t\tstream.WriteFloat(Scale);\n\t\t\tstream.WriteBoolean(Empty);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\topen = stream.ReadBoolean();\n\t\t\tScale = stream.ReadFloat();\n\t\t\tEmpty = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\n\t\t\tImGui.Checkbox(\"Empty\", ref Empty);\n\t\t\tImGui.Checkbox(\"Can open\", ref CanOpen);\n\t\t}\n\n\t\tpublic class OpenedEvent : Event {\n\t\t\tpublic Chest Chest;\n\t\t\tpublic Entity Who;\n\t\t}\n\n\t\tpublic virtual bool ShouldCollide(Entity entity) {\n\t\t\treturn !(entity is Creature c && c.InAir());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/ChestRegistry.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.pool;\nusing BurningKnight.save;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class ChestRegistry : Pool<Type> {\n\t\tpublic static ChestRegistry Instance = new ChestRegistry();\n\n\t\tstatic ChestRegistry() {\n\t\t\tInstance.Add(typeof(WoodenChest), 1f);\n\t\t\tInstance.Add(typeof(ScourgedChest), 0.9f);\n\t\t\tInstance.Add(typeof(DoubleChest), 0.1f);\n\t\t\tInstance.Add(typeof(TripleChest), 0.02f);\n\t\t\tInstance.Add(typeof(StoneChest), 1f);\n\t\t\tInstance.Add(typeof(GoldChest), 1f);\n\t\t\tInstance.Add(typeof(RedChest), 0.5f);\n\t\t\tInstance.Add(typeof(GlassChest), 0.5f);\n\t\t}\n\n\t\tpublic static Entity PlaceRandom(Vector2 where, Area area) {\n\t\t\ttry {\n\t\t\t\tvar chest = (Chest) Activator.CreateInstance(Instance.Generate());\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tif (!(chest is GlassChest || chest is ProtoChest) && Rnd.Chance(LevelSave.MimicChance)) {\n\t\t\t\t\tvar mimic = new Mimic {\n\t\t\t\t\t\tKind = chest.GetSprite(),\n\t\t\t\t\t\tPool = chest.GetPool()\n\t\t\t\t\t};\n\n\t\t\t\t\tarea.Add(mimic);\n\t\t\t\t\tmimic.BottomCenter = where;\n\t\t\t\t\t\n\t\t\t\t\treturn mimic;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tarea.Add(chest);\n\t\t\t\tchest.BottomCenter = where;\n\n\t\t\t\treturn chest;\n\t\t\t} catch (Exception ex) {\n\t\t\t\tLog.Error(ex);\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/DoubleChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class DoubleChest : GoldChest {\n\t\tpublic DoubleChest() {\n\t\t\tKeysRequired = 2;\n\t\t}\n\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"double_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:double_chest\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/DuckChest.cs",
    "content": "using BurningKnight.entity.component;\nusing Lens.entity;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class DuckChest : Chest {\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"duck_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:duck_chest\";\n\t\t}\n\n\t\tprotected override bool TryOpen(Entity entity) {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/GlassChest.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class GlassChest : Chest {\n\t\tprivate Item item;\n\t\tprivate float t;\n\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"glass_chest\";\n\t\t}\n\n\t\tprotected override void DefineDrops() {\n\t\t\t\n\t\t}\n\n\t\tprotected override bool TryOpen(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var c) || c.Keys < 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tc.Keys -= 1;\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t}\n\n\t\tprotected override void SpawnDrops() {\n\t\t\titem.AddDroppedComponents();\n\t\t\titem.TopCenter = BottomCenter;\n\t\t\titem = null;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tvar id = stream.ReadString();\n\n\t\t\tif (id != null) {\n\t\t\t\titem = Items.CreateAndAdd(id, Area);\n\t\t\t\titem.RemoveDroppedComponents();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(item?.Id);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (item != null) {\n\t\t\t\tvar region = item.Region;\n\t\t\t\tvar s = Math.Min(13f / region.Width, 13f / region.Height);\n\t\t\t\t\n\t\t\t\tGraphics.Render(region, Center + new Vector2(0, ItemGraphicsComponent.CalculateMove(t) / 5.5f), (float) Math.Cos(t * 1.8f) * 0.2f, region.Center, new Vector2(s, s));\n\t\t\t}\n\n\t\t\tbase.Render();\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (!open && item == null) {\n\t\t\t\titem = Items.CreateAndAdd(Items.Generate(ItemPool.GoldChest), Area);\n\t\t\t\titem.RemoveDroppedComponents();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/GoldChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class GoldChest : Chest {\n\t\tprotected byte KeysRequired = 1;\n\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"gold_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:gold_chest\";\n\t\t}\n\n\t\tprotected override bool TryOpen(Entity entity) {\n\t\t\tif (!entity.TryGetComponent<ConsumablesComponent>(out var c) || c.Keys < KeysRequired) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tc.Keys -= KeysRequired;\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected override void SpawnDrops() {\n\t\t\tif (!Empty && Rnd.Chance(2.5f)) {\n\t\t\t\tvar chest = Rnd.Chance(60) ? (Chest) new WoodenChest {\n\t\t\t\t\tScale = Scale * 0.9f\n\t\t\t\t} : (Chest) new GoldChest {\n\t\t\t\t\tScale = Scale * 0.9f\n\t\t\t\t};\n\n\t\t\t\tArea.Add(chest);\n\t\t\t\tchest.TopCenter = BottomCenter;\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.SpawnDrops();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/ProtoChest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class ProtoChest : AnimatedChest {\n\t\tprivate List<Player> colling = new List<Player>();\n\t\tprivate InteractFx fx;\n\t\tprivate TextureRegion itemRegion;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new ItemComponent {\n\t\t\t\tDontSave = true\n\t\t\t});\n\t\t\t\n\t\t\tvar i = GetComponent<InteractableComponent>();\n\t\t\t\n\t\t\ti.CanInteract = e => e.GetComponent<ActiveWeaponComponent>().Item != null && !e.GetComponent<ActiveWeaponComponent>().Item.Scourged;\n\t\t\ti.OnStart = e => AddFx();\n\t\t\t\n\t\t\ttry {\n\t\t\t\tvar id = GlobalSave.GetString(\"proto_chest\", LevelSave.MeleeOnly ? \"bk:ancient_sword\" : \"bk:ancient_revolver\");\n\n\t\t\t\tif (id != null) {\n\t\t\t\t\tvar item = Items.CreateAndAdd(id, Area);\n\t\t\t\t\tGetComponent<ItemComponent>().Set(item, false);\n\t\t\t\t\titemRegion = item.Region;\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tGlobalSave.Put(\"proto_chest\", GetComponent<ItemComponent>().Item?.Id);\n\t\t\tbase.Destroy();\n\t\t}\n\n\t\tprivate void AddFx() {\n\t\t\tif (fx != null && !fx.Done) {\n\t\t\t\tfx.Close();\n\t\t\t}\n\t\t\t\n\t\t\tvar i = GetComponent<ItemComponent>().Item;\n\t\t\tEngine.Instance.State.Ui.Add(fx = new InteractFx(this, i == null ? Locale.Get(\"place_an_item\") : i.Name));\n\t\t}\n\n\t\tprotected override float GetWidth() {\n\t\t\treturn 19;\n\t\t}\n\n\t\tprotected override float GetHeight() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"proto_chest\";\n\t\t}\n\n\t\tprotected override void SpawnDrops() {\n\t\t\t\n\t\t}\n\n\t\tprotected override bool ShouldOpen() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected override bool Interact(Entity entity) {\n\t\t\tvar w = entity.GetComponent<ActiveWeaponComponent>();\n\t\t\tGetComponent<ItemComponent>().Exchange(w);\n\n\t\t\tif (w.Item != null) {\n\t\t\t\tAudio.PlaySfx(w.Item.Data.WeaponType.GetSwapSfx());\n\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().AnimateSwap();\n\t\t\t} else if (entity.GetComponent<WeaponComponent>().Item != null) {\n\t\t\t\tw.RequestSwap();\n\t\t\t}\n\t\t\t\n\t\t\titemRegion = GetComponent<ItemComponent>().Item.Region;\n\t\t\tAddFx();\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\topen = false;\n\t\t\tbase.Save(stream);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (cse.Entity is Player p) {\n\t\t\t\t\tcolling.Add(p);\n\t\t\t\t\tOpen(p);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tif (cee.Entity is Player p) {\n\t\t\t\t\tcolling.Remove(p);\n\t\t\t\t\tif (colling.Count == 0) {\n\t\t\t\t\t\tClose();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tif (open && itemRegion != null) {\n\t\t\t\tGraphics.Render(itemRegion, Position + new Vector2(10, 7), 0, itemRegion.Center, GetComponent<AnimationComponent>().Scale);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/RedChest.cs",
    "content": "using BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.player;\nusing Lens.entity;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class RedChest : Chest {\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"red_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:red_chest\";\n\t\t}\n\n\t\tprotected override bool TryOpen(Entity entity) {\n\t\t\tif (entity.GetComponent<HealthComponent>().Health + entity.GetComponent<HeartsComponent>().Total < 3) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tentity.GetComponent<HealthComponent>().ModifyHealth(-2, this, DamageType.Custom);\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/ScourgedChest.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.timer;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class ScourgedChest : Chest, DropModifier {\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"scourged_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:scourged_chest\";\n\t\t}\n\n\t\tprotected override bool TryOpen(Entity entity) {\n\t\t\tvar item = Scourge.GenerateItemId();\n\n\t\t\tif (item != null) {\n\t\t\t\tTimer.Add(() => entity.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(item, entity.Area)), 0.3f);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic void ModifyDrops(List<Item> drops) {\n\t\t\tforeach (var d in drops) {\n\t\t\t\td.Scourged = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/StoneChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.events;\nusing Lens.entity;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class StoneChest : Chest {\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"stone_chest\";\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tCanOpen = false;\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:stone_chest\";\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent ex) {\n\t\t\t\tOpen(ex.Who);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/TreasureChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class TreasureChest : Chest {\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"treasure_chest\";\n\t\t}\n\n\t\tprotected override void DefineDrops() {\n\t\t\tGetComponent<DropsComponent>().Add(new SimpleDrop(1, 1, 1, \"bk:treasure_key\"));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/TripleChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class TripleChest : GoldChest {\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:triple_chest\";\n\t\t}\n\n\t\tpublic override string GetSprite() {\n\t\t\treturn \"triple_chest\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/chest/WoodenChest.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.drop;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.entities.chest {\n\tpublic class WoodenChest : Chest {\n\t\tpublic override string GetSprite() {\n\t\t\tif (Events.Halloween) {\n\t\t\t\treturn \"spooky_chest\";\n\t\t\t}\n\t\t\t\n\t\t\treturn Events.XMas ? \"xmas_chest\" : \"wooden_chest\";\n\t\t}\n\n\t\tpublic override string GetPool() {\n\t\t\treturn \"bk:wooden_chest\";\n\t\t}\n\n\t\tprotected override void SpawnDrops() {\n\t\t\tif (!Empty && Rnd.Chance(5)) {\n\t\t\t\tvar chest = Rnd.Chance() ? (Chest) new WoodenChest {\n\t\t\t\t\tScale = Scale * 0.9f\n\t\t\t\t} : (Chest) new GoldChest {\n\t\t\t\t\tScale = Scale * 0.9f\n\t\t\t\t};\n\n\t\t\t\tArea.Add(chest);\n\t\t\t\tchest.TopCenter = BottomCenter;\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.SpawnDrops();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/BurningStatue.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.particle;\r\nusing BurningKnight.assets.particle.custom;\r\nusing BurningKnight.entity;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.bk;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens;\r\nusing Lens.entity;\r\nusing Lens.entity.component.logic;\r\nusing Lens.util;\r\nusing Lens.util.camera;\r\nusing Lens.util.file;\r\nusing Lens.util.timer;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.entities.decor {\r\n\tpublic class BurningStatue : SolidProp {\r\n\t\tpublic bool Broken;\r\n\t\tprivate FireEmitter fea;\r\n\t\tprivate FireEmitter feb;\r\n\t\tprivate SpawnTrigger trigger;\r\n\t\tprivate float XSpread = 0.1f;\r\n\t\tprivate Vector2? target;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tWidth = 14;\r\n\t\t\tHeight = 28;\r\n\t\t\tSprite = \"burning_statue\";\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tSubscribe<RoomChangedEvent>();\r\n\t\t\tSubscribe<SpawnTrigger.TriggeredEvent>();\r\n\t\t\t\t\r\n\t\t\tAddComponent(new RoomComponent());\r\n\t\t\t\r\n\t\t\tAddComponent(new ShadowComponent());\r\n\t\t\tAddComponent(new InteractableComponent(Interact) {\r\n\t\t\t\tCanInteract = e => !Broken && !busy\r\n\t\t\t});\r\n\r\n\t\t\tvar h = new HealthComponent {\r\n\t\t\t\tRenderInvt = true\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tAddComponent(h);\r\n\r\n\t\t\th.InitMaxHealth = 3;\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (fea != null) {\r\n\t\t\t\tfea.Done = true;\r\n\t\t\t\tfeb.Done = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tUpdateSprite();\r\n\r\n\t\t\tif (!Broken) {\r\n\t\t\t\tArea.Add(fea = new FireEmitter {\r\n\t\t\t\t\tDepth = Depth + 1,\r\n\t\t\t\t\tPosition = new Vector2(X + 11, Y + 15),\r\n\t\t\t\t\tScale = 0.8f\r\n\t\t\t\t});\r\n\t\t\t\r\n\t\t\t\tArea.Add(feb = new FireEmitter {\r\n\t\t\t\t\tDepth = Depth + 1,\r\n\t\t\t\t\tPosition = new Vector2(X + 4, Y + 15),\r\n\t\t\t\t\tScale = 0.8f\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t\tAddComponent(new LightComponent(this, 32f, new Color(1f, 0.5f, 0f, 1f)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate bool Interact(Entity e) {\r\n\t\t\tif (Broken || busy) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\r\n\t\t\tRun.AddScourge(true);\r\n\t\t\t\r\n\t\t\tif (trigger != null) {\r\n\t\t\t\ttrigger.Interrupted = true;\r\n\t\t\t}\r\n\r\n\t\t\tHandleEvent(new BrokenEvent {\r\n\t\t\t\tBurningStatue = this\r\n\t\t\t});\r\n\r\n\t\t\tXSpread = 1;\r\n\t\t\t\r\n\t\t\tTween.To(1f, Camera.Instance.Zoom, xx => Camera.Instance.Zoom = xx, 0.2f);\r\n\t\t\tTween.To(1.4f, Camera.Instance.TextureZoom, xx => Camera.Instance.TextureZoom = xx, 0.5f);\r\n\t\t\tCamera.Instance.GetComponent<ShakeComponent>().Amount = 0;\r\n\t\t\tGameSave.Put(\"statue_broken\", true);\r\n\r\n\t\t\t/*var torches = GetComponent<RoomComponent>().Room.Tagged[Tags.Torch];\r\n\r\n\t\t\tforeach (var t in torches) { \r\n\t\t\t\tvar tr = (Torch) t;\r\n\r\n\t\t\t\ttr.XSpread = 0.1f;\r\n\t\t\t\ttr.On = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tTimer.Add(() => {\r\n\t\t\t\tfor (var i = 0; i < torches.Count; i++) {\r\n\t\t\t\t\tvar i1 = i;\r\n\t\t\t\t\t\r\n\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\tvar t = (Torch) torches[i1];\r\n\r\n\t\t\t\t\t\tt.Break();\r\n\t\t\t\t\t\tCamera.Instance.Shake(5);\r\n\t\t\t\t\t}, i);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\tParticles.BreakSprite(Area, GetComponent<InteractableSliceComponent>().Sprite, Position);\r\n\t\t\t\t\tBroken = true;\r\n\t\t\t\t\r\n\t\t\t\t\tCamera.Instance.Unfollow(this);\r\n\t\t\t\t\tCamera.Instance.Shake(10);\r\n\r\n\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\tCamera.Instance.GetComponent<ShakeComponent>().Amount = 0;\r\n\t\t\t\t\t}, 0.5f);\r\n\r\n\t\t\t\t\tCamera.Instance.Targets.Clear();\r\n\t\t\t\t\tCamera.Instance.Follow(this, 0.5f);\r\n\t\t\t\r\n\t\t\t\t\tUpdateSprite();\r\n\t\t\t\t\tRemoveComponent<LightComponent>();\r\n\t\t\t\r\n\t\t\t\t\tvar exit = new Exit();\r\n\t\t\t\t\tArea.Add(exit);\r\n\t\t\t\t\r\n\t\t\t\t\texit.To = Run.Depth + 1;\r\n\r\n\t\t\t\t\tvar x = (int) Math.Floor(CenterX / 16);\r\n\t\t\t\t\tvar y = (int) Math.Floor(Bottom / 16 + 0.6f);\r\n\t\t\t\t\tvar p = new Vector2(x * 16 + 8, y * 16 + 8);\r\n\t\t\t\r\n\t\t\t\t\texit.Center = p;\r\n\r\n\t\t\t\t\tPainter.Fill(Run.Level, x - 1, y - 1, 3, 3, Tiles.RandomFloor());\r\n\t\t\t\t\tPainter.Fill(Run.Level, x - 1, y - 3, 3, 3, Tiles.RandomFloor());\r\n\r\n\t\t\t\t\tRun.Level.TileUp();\r\n\t\t\t\t\tRun.Level.CreateBody();\r\n\t\t\t\r\n\t\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t\tTween.To(1f, Camera.Instance.TextureZoom, xx => Camera.Instance.TextureZoom = xx, 0.8f);\r\n\t\t\t\t\t\t((InGameState) BK.Instance.State).ResetFollowing();\r\n\t\t\t\t\t}, 1f);\r\n\t\t\t\t}, torches.Count + 1);\r\n\t\t\t}, 1f);*/\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tprivate void UpdateSprite() {\r\n\t\t\tif (Broken) {\r\n\t\t\t\tvar s = GetComponent<InteractableSliceComponent>();\r\n\r\n\t\t\t\ts.Sprite = CommonAse.Props.GetSlice(\"broken_statue\");\r\n\t\t\t\ts.Offset.Y = Height - s.Sprite.Height;\r\n\r\n\t\t\t\tif (fea != null) {\r\n\t\t\t\t\tfea.Done = true;\r\n\t\t\t\t\tfeb.Done = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\tBroken = stream.ReadBoolean();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\tstream.WriteBoolean(Broken);\r\n\t\t}\r\n\r\n\t\tprivate float lastFlame;\r\n\t\tprivate bool busy;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (Area.Tagged[Tags.BurningKnight].Count > 0) {\r\n\t\t\t\tDone = true;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (Broken) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (trigger != null && trigger.ReadyToSpawn) {\r\n\t\t\t\ttrigger.ReadyToSpawn = false;\r\n\t\t\t\tSetupSpawn();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tlastFlame += dt;\r\n\r\n\t\t\tif (lastFlame > 0.3f) {\r\n\t\t\t\tArea.Add(new FireParticle {\r\n\t\t\t\t\tX = X + 11,\r\n\t\t\t\t\tY = Y + 15,\r\n\t\t\t\t\tXChange = XSpread,\r\n\t\t\t\t\tTarget = target\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t\tArea.Add(new FireParticle {\r\n\t\t\t\t\tX = X + 4,\r\n\t\t\t\t\tY = Y + 15,\r\n\t\t\t\t\tXChange = XSpread,\r\n\t\t\t\t\tTarget = target\r\n\t\t\t\t});\r\n\r\n\t\t\t\tlastFlame = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void SetupSpawn() {\r\n\t\t\tbusy = true;\r\n\t\t\t\r\n\t\t\t/*var torches = GetComponent<RoomComponent>().Room.Tagged[Tags.Torch];\r\n\t\t\ttarget = new Vector2(CenterX, Y - 4);\r\n\r\n\t\t\tforeach (var t in torches) { \r\n\t\t\t\tvar tr = (Torch) t;\r\n\r\n\t\t\t\ttr.XSpread = 1;\r\n\t\t\t\ttr.On = true;\r\n\t\t\t\ttr.Target = target;\r\n\t\t\t}\r\n\r\n\t\t\tTimer.Add(() => {\r\n\t\t\t\tvar bk = new entity.creature.bk.BurningKnight();\r\n\t\t\t\tArea.Add(bk);\r\n\t\t\t\tbk.Center = target.Value;\r\n\t\t\t\t\r\n\t\t\t\tCamera.Instance.Targets.Clear();\r\n\t\t\t\tCamera.Instance.Follow(bk, 0.1f);\r\n\t\t\t\t\t\r\n\t\t\t\tTimer.Add(() => {\r\n\t\t\t\t\t((InGameState) Engine.Instance.State).ResetFollowing();\r\n\t\t\t\t}, 2f);\r\n\t\t\t\t\t\r\n\t\t\t\tCamera.Instance.Shake(10);\r\n\r\n\t\t\t\tforeach (var t in torches) {\r\n\t\t\t\t\tt.Done = true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tDone = true;\r\n\t\t\t}, 2f);*/\r\n\t\t}\r\n\r\n\t\tprotected override Rectangle GetCollider() {\r\n\t\t\treturn new Rectangle(2, 8, 10, 14);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is RoomChangedEvent rce) {\r\n\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\t\tif (rce.Who is LocalPlayer) {\r\n\t\t\t\t\tif (rce.New == r) {\r\n\t\t\t\t\t\tCamera.Instance?.Follow(this, 0.3f);\r\n\t\t\t\t\t} else if (rce.Old == r) {\r\n\t\t\t\t\t\tCamera.Instance?.Unfollow(this);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (e is SpawnTrigger.TriggeredEvent stte) {\r\n\t\t\t\ttrigger = stte.Trigger;\r\n\t\t\t} else if (e is DiedEvent de) {\r\n\t\t\t\tInteract(de.Who);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tpublic class BrokenEvent : Event {\r\n\t\t\tpublic BurningStatue BurningStatue;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/GrannyDecor.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.decor {\n\tpublic class GrannyDecor : SolidProp {\n\t\tpublic GrannyDecor() {\n\t\t\tSprite = \"granny\";\n\t\t}\n\t\t\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 8, 60, 14);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/Lamp.cs",
    "content": "using System;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.decor {\n\tpublic class Lamp : SlicedProp {\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tWidth = 8;\n\t\t\tHeight = 12;\n\t\t\tSprite = \"lamp\";\n\t\t\tAlwaysActive = true;\n\t\t\t\n\t\t\tt = Rnd.Float(6);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new LightComponent(this, 32f, new Color(1f, 0.8f, 0.3f, 1f)));\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tprivate float t;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t\tGetComponent<LightComponent>().Light.Radius = 32f + (float) Math.Cos(t) * 6;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/Torch.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.particle;\r\nusing BurningKnight.assets.particle.custom;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util.file;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.entities.decor {\r\n\tpublic class Torch : SolidProp {\r\n\t\tpublic bool On = true;\r\n\t\tpublic float XSpread = 1f;\r\n\t\tpublic Vector2? Target;\r\n\t\t\r\n\t\tprivate bool broken;\r\n\t\tprivate FireEmitter emitter;\r\n\t\tprivate float t;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tWidth = 10;\r\n\t\t\tSprite = \"torch\";\r\n\t\t\tt = Rnd.Float(6);\r\n\t\t\tAlwaysActive = Run.Depth < 1;\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tAddComponent(new LightComponent(this, 32f, new Color(1f, 0.8f, 0.3f, 1f)));\r\n\t\t\tAddComponent(new ShadowComponent());\r\n\t\t\tAddComponent(new RoomComponent());\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (emitter != null) {\r\n\t\t\t\temitter.Done = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tif (!broken) {\r\n\t\t\t\tArea.Add(emitter = new FireEmitter {\r\n\t\t\t\t\tDepth = Depth + 1,\r\n\t\t\t\t\tPosition = new Vector2(CenterX, Y + 3),\r\n\t\t\t\t\tScale = 0.5f\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\tUpdateSprite();\r\n\t\t}\r\n\r\n\t\tprivate void UpdateSprite() {\r\n\t\t\tif (broken) {\r\n\t\t\t\tvar s = GetComponent<SliceComponent>();\r\n\r\n\t\t\t\ts.Sprite = CommonAse.Props.GetSlice(\"broken_torch\");\r\n\t\t\t\ts.Offset = new Vector2(0, 5);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void Break() {\r\n\t\t\tif (broken) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tOn = false;\r\n\t\t\tbroken = true;\r\n\r\n\t\t\tif (emitter != null) {\r\n\t\t\t\temitter.Done = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tAnimationUtil.Poof(Center);\r\n\t\t\tParticles.BreakSprite(Area, GetComponent<SliceComponent>().Sprite, Position);\r\n\t\t\t\r\n\t\t\tUpdateSprite();\r\n\t\t}\r\n\t\t\r\n\t\tprivate float lastFlame;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!On) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tt += dt * 0.5f;\r\n\t\t\tGetComponent<LightComponent>().Light.Radius = 38f + (float) Math.Cos(t) * 6;\r\n\t\t\tlastFlame += dt;\r\n\r\n\t\t\tif (lastFlame > 0.1f) {\r\n\t\t\t\tArea.Add(new FireParticle {\r\n\t\t\t\t\tX = CenterX,\r\n\t\t\t\t\tY = Y + 2,\r\n\t\t\t\t\tTarget = Target,\r\n\t\t\t\t\tXChange = XSpread\r\n\t\t\t\t});\r\n\r\n\t\t\t\tlastFlame = 0;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected override Rectangle GetCollider() {\r\n\t\t\treturn new Rectangle(2, 5, 6, 5);\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\tbroken = stream.ReadBoolean();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\tstream.WriteBoolean(broken);\r\n\t\t}\r\n\r\n\t\tpublic override bool ShouldCollide(Entity entity) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/Tree.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.mob.jungle;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.level.entities.plant;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.entities.decor {\n\tpublic class Tree : Prop {\n\t\tprivate byte type;\n\t\tprivate List<Entity> colliding = new List<Entity>();\n\t\tpublic bool High;\n\t\tpublic bool AlwaysShow;\n\n\t\tpublic byte Id {\n\t\t\tget => type;\n\t\t\tset {\n\t\t\t\ttype = value;\n\t\t\t}\n\t\t}\n\n\t\tpublic Tree() {\n\t\t\ttype = (byte) Rnd.Int(0, 7);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (High) {\n\t\t\t\tDepth = Layers.Wall + 1;\n\t\t\t}\n\n\t\t\tUpdateSprite();\n\n\t\t\tif (Depth > 0 && Width > 14 && !AlwaysShow) {\n\t\t\t\tAddComponent(new SensorBodyComponent(4, 4, Width - 4, Height - 4));\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void UpdateSprite() {\n\t\t\tif (GraphicsComponent != null) {\n\t\t\t\tRemoveComponent<PlantGraphicsComponent>();\n\t\t\t}\n\t\t\t\n\t\t\tvar s = new PlantGraphicsComponent(\"props\", type != 4 && Events.Halloween ? $\"spooky_tree_{type}\" : $\"tree_{type}\");\n\t\t\ts.RotationModifier = 0.03f;\n\t\t\ts.Flipped = type != 5 && Rnd.Chance();\n\t\t\t\n\t\t\tAddComponent(s);\n\n\t\t\tWidth = s.Sprite.Width;\n\t\t\tHeight = s.Sprite.Height;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\t\n\t\t\ttype = stream.ReadByte();\n\t\t\tHigh = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte(type);\n\t\t\tstream.WriteBoolean(High);\n\t\t}\n\n\t\tprivate bool ShouldCollide(Entity e) {\n\t\t\tif (e is BeeHive) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn e is Creature || e is Spikes;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tvar s = GetComponent<PlantGraphicsComponent>();\n\n\t\t\ts.Alpha += ((colliding.Count > 0 ? 0.2f : 1) - s.Alpha) * dt * 5;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is CollisionStartedEvent cse) {\n\t\t\t\tif (ShouldCollide(cse.Entity)) {\n\t\t\t\t\tcolliding.Add(cse.Entity);\n\t\t\t\t}\n\t\t\t} else if (e is CollisionEndedEvent cee) {\n\t\t\t\tcolliding.Remove(cee.Entity);\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tvar v = (int) type;\n\n\t\t\tif (ImGui.InputInt(\"Id\", ref v)) {\n\t\t\t\ttype = (byte) v;\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/decor/WallTorch.cs",
    "content": "using System;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.particle.custom;\r\nusing BurningKnight.entity;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.state;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.entities.decor {\r\n\tpublic class WallTorch : SlicedProp {\r\n\t\tpublic bool On = true;\r\n\t\tpublic float XSpread = 0.5f;\r\n\t\tpublic Vector2? Target;\r\n\t\t\r\n\t\tprivate FireEmitter emitter;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tWidth = 5;\r\n\t\t\tHeight = 7;\r\n\t\t\tSprite = Run.Level != null && Run.Level.Biome is CaveBiome ? \"cave_torch\" : \"wall_torch\";\r\n\t\t\tt = Rnd.Float(6);\r\n\t\t\tAlwaysActive = Run.Depth < 1;\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tif (Run.Level != null && Run.Level.Biome is CaveBiome) {\r\n\t\t\t\tAddComponent(new LightComponent(this, 64f, new Color(0.2f, 1, 0.8f, 1f)));\r\n\t\t\t} else {\r\n\t\t\t\tAddComponent(new LightComponent(this, 64f, new Color(1f, 0.8f, 0.2f, 1f)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\temitter.Done = true;\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tArea.Add(emitter = new FireEmitter {\r\n\t\t\t\tDepth = Layers.Wall + 1,\r\n\t\t\t\tPosition = new Vector2(CenterX, Y + 1),\r\n\t\t\t\tScale = 0.5f\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n\t\tprivate float lastFlame;\r\n\r\n\r\n\t\tprivate float t;\r\n\t\t\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (!On) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tt += dt * 0.5f;\r\n\t\t\tGetComponent<LightComponent>().Light.Radius = 38f + (float) Math.Cos(t) * 6;\r\n\t\t\t\r\n\t\t\tlastFlame += dt;\r\n\r\n\t\t\tif (lastFlame > 0.3f) {\r\n\t\t\t\tArea.Add(new FireParticle {\r\n\t\t\t\t\tX = CenterX,\r\n\t\t\t\t\tY = Y + 1,\r\n\t\t\t\t\tTarget = Target,\r\n\t\t\t\t\tDepth = Layers.Wall + 1,\r\n\t\t\t\t\tXChange = XSpread\r\n\t\t\t\t});\r\n\r\n\t\t\t\tlastFlame = 0;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/exit/BossRushExit.cs",
    "content": "using BurningKnight.entity.creature.npc;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.level.entities.exit {\n\tpublic class BossRushExit : Exit {\n\t\tprotected override void Descend() {\n\t\t\tRun.StartNew(1, RunType.BossRush);\n\t\t}\n\n\t\tprotected override bool Interact(Entity entity) {\n\t\t\tif (GlobalSave.Emeralds < 3) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\n\t\t\t\tforeach (var n in Area.Tagged[Tags.Npc]) {\n\t\t\t\t\tif (n is Mike) {\n\t\t\t\t\t\tn.GetComponent<DialogComponent>().Start(\"mike_0\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tGlobalSave.Emeralds -= 3;\n\t\t\treturn base.Interact(entity);\n\t\t}\n\n\t\tprotected override string GetFxText() {\n\t\t\treturn Locale.Get(\"boss_rush\");\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn !InGameState.Multiplayer;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/exit/ChallengeExit.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.file;\n\nnamespace BurningKnight.level.entities.exit {\n\tpublic class ChallengeExit : Exit {\n\t\tprivate byte id;\n\t\t\n\t\tprotected override void Descend() {\n\t\t\tRun.ChallengeId = id;\n    \tRun.StartNew(1, RunType.Challenge);\n    }\n\n    protected override string GetFxText() {\n    \treturn Locale.Get($\"challenge_{id}\");\n    }\n\n    public override void Load(FileReader stream) {\n\t    base.Load(stream);\n\t    id = stream.ReadByte();\n    }\n\n    public override void Save(FileWriter stream) {\n\t    base.Save(stream);\n\t    stream.WriteByte(id);\n    }\n\n    public override void RenderImDebug() {\n\t    base.RenderImDebug();\n\t    var v = (int) id;\n\n\t    if (ImGui.InputInt(\"Id\", ref v)) {\n\t\t    id = (byte) v;\n\t    }\n    }\n\n    public override void Render() {\n\t    base.Render();\n\n\t    if (Engine.EditingLevel) {\n\t\t    Graphics.Print(id.ToString(), Font.Small, Position);\n\t    }\n    }\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/exit/DailyRunExit.cs",
    "content": "using BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity;\n\nnamespace BurningKnight.level.entities.exit {\n\tpublic class DailyRunExit : Exit {\n\t\tprivate bool hidden;\n\t\t\n\t\tprotected override void Descend() {\n\t\t\tRun.StartNew(1, RunType.Daily);\n\t\t\tGlobalSave.Put($\"daily_{Run.DailyId}\", true);\n\t\t}\n\n\t\tprotected override string GetFxText() {\n\t\t\treturn Locale.Get(\"daily_run\");\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\thidden = GlobalSave.IsTrue($\"daily_{Run.CalculateDailyId()}\");\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.Render();\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn !InGameState.Multiplayer && !hidden;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/exit/ShortcutExit.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.level.biome;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.file;\n\nnamespace BurningKnight.level.entities.exit {\n\tpublic class ShortcutExit : Exit {\n\t\tprivate byte id;\n    private bool broken;\n\n    public override void PostInit() {\n      if (!Engine.EditingLevel && GlobalSave.IsFalse($\"shortcut_{id}\")) {\n        broken = true;\n      }\n      \n      base.PostInit();\n    }\n\n    protected override string GetSlice() {\n      return id == 0 ? base.GetSlice() : (broken ? $\"shortcut_broken_{id}\" : $\"shortcut_{id}\");\n    }\n\n    protected override bool CanUse() {\n      return !broken;\n    }\n\n    protected override void Descend() {\n      Run.StartNew(id);\n    }\n\n    protected override string GetFxText() {\n      return Locale.Get(broken ? \"shortcut_is_broken\" : BiomeRegistry.GenerateForDepth(id).Id);\n    }\n\n    public override void Load(FileReader stream) {\n      base.Load(stream);\n      id = stream.ReadByte();\n    }\n\n    public override void Save(FileWriter stream) {\n      base.Save(stream);\n      stream.WriteByte(id);\n    }\n\n    public override void RenderImDebug() {\n      base.RenderImDebug();\n      var v = (int) id;\n\n      if (ImGui.InputInt(\"To depth\", ref v)) {\n    \t  id = (byte) v;\n      }\n    }\n\n    public override void Render() {\n      base.Render();\n\n      if (Engine.EditingLevel) {\n    \t  Graphics.Print(id.ToString(), Font.Small, Position);\n      }\n    }\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/exit/TutorialExit.cs",
    "content": "using BurningKnight.state;\nusing Lens.assets;\n\nnamespace BurningKnight.level.entities.exit {\n\tpublic class TutorialExit : Exit {\n\t\tprotected override void Descend() {\n\t\t\tRun.GoToTutorial();\n\t\t}\n\n\t\tprotected override string GetFxText() {\n\t\t\treturn Locale.Get(\"tutorial\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/machine/Charger.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.machine {\n\tpublic class Charger : SolidProp {\n\t\tprivate int timesUsed;\n\t\tprivate int noMoneyAttempt;\n\t\tprivate bool broken;\n\n\t\tpublic Charger() {\n\t\t\tSprite = \"charger\";\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 6, 19, 17);\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 19;\n\t\t\tHeight = 23;\n\t\t\t\n\t\t\tAddComponent(new DialogComponent());\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2));\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = e => !broken\n\t\t\t});\n\n\t\t\tvar drops = new DropsComponent();\n\t\t\tAddComponent(drops);\n\t\t\tdrops.Add(\"bk:charger\");\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 10;\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(broken);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tbroken = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (broken) {\n\t\t\t\tBreak();\n\t\t\t}\n\t\t}\n\n\t\tpublic void Break(bool spawnLoot = true) {\n\t\t\tbroken = true;\n\t\t\t\n\t\t\tGetComponent<InteractableSliceComponent>().Sprite = CommonAse.Props.GetSlice(\"charger_broken\");\n\n\t\t\tif (spawnLoot) {\n\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void Animate() {\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.Y = 0.4f;\n\t\t\tTween.To(1, 0.4f, x => GetComponent<InteractableSliceComponent>().Scale.Y = x, 0.2f);\n\t\t\t\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.X = 1.3f;\n\t\t\tTween.To(1, 1.3f, x => GetComponent<InteractableSliceComponent>().Scale.X = x, 0.2f);\n\t\t}\n\n\t\tprivate bool Interact(Entity e) {\n\t\t\tAnimate();\n\t\t\t\n\t\t\tvar p = e ?? LocalPlayer.Locate(Area);\n\t\t\tvar active = p.GetComponent<ActiveItemComponent>();\n\t\t\t\n\t\t\tif (active.Item == null) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"charger_0\", 3);\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tif (active.Item.Delay <= 0.02f) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"charger_1\", 3);\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (e != null) {\n\t\t\t\tvar component = p.GetComponent<ConsumablesComponent>();\n\n\t\t\t\tif (component.Coins == 0) {\n\t\t\t\t\tif (noMoneyAttempt == 0) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"charger_2\", 3);\n\t\t\t\t\t} else if (noMoneyAttempt == 1) {\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"charger_3\", 3);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar hp = p.GetComponent<HealthComponent>();\n\t\t\t\t\t\thp.ModifyHealth(-1, this);\n\t\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"charger_{(hp.HasNoHealth ? 5 : 4)}\", 3);\n\t\t\t\t\t}\n\n\t\t\t\t\tnoMoneyAttempt++;\n\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tnoMoneyAttempt = 0;\n\t\t\t\tcomponent.Coins -= 1;\n\t\t\t}\n\n\t\t\ttimesUsed += e == null ? 4 : 1;\n\n\t\t\tactive.Charge(Rnd.Int(1, 3));\n\t\t\tAudio.PlaySfx(\"item_charge\");\n\t\t\t\n\t\t\tif (Rnd.Float(100) < timesUsed * 2 - Run.Luck * 0.5f) {\n\t\t\t\tBreak(false);\n\t\t\t\tExplosionMaker.Make(p);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent && !broken) {\n\t\t\t\tInteract(null);\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/machine/RerollMachine.cs",
    "content": "using BurningKnight.assets;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.npc;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.dialog;\r\nusing BurningKnight.util;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.util.file;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing VelcroPhysics.Dynamics;\r\n\r\nnamespace BurningKnight.level.entities.machine {\r\n\tpublic class RerollMachine : Prop {\r\n\t\tprivate int coinsConsumed;\r\n\t\tprivate int numRolled;\r\n\t\tprivate bool broken;\r\n\r\n\t\tprivate static ItemType[] ignoredTypes = {\r\n\t\t\tItemType.Mana, ItemType.Heart, ItemType.Coin, ItemType.Battery, ItemType.Key, ItemType.Bomb\r\n\t\t};\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tWidth = 18;\r\n\t\t\tHeight = 26;\r\n\t\t\t\r\n\t\t\tAddComponent(new InteractableComponent(Interact) {\r\n\t\t\t\tCanInteract = (e) => !broken\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tAddComponent(new ExplodableComponent());\r\n\t\t\tAddComponent(new RoomComponent());\r\n\t\t\tAddComponent(new RectBodyComponent(0, 17, 18, 8, BodyType.Static));\r\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\r\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\r\n\t\t\tAddComponent(new DialogComponent());\r\n\t\t\t\r\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"reroll_machine\"));\r\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 10;\r\n\t\t}\r\n\r\n\t\tprotected bool Interact(Entity entity) {\r\n\t\t\tReroll(entity, true);\r\n\t\t\treturn broken;\r\n\t\t}\r\n\r\n\t\tprivate void Animate() {\r\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.Y = 0.4f;\r\n\t\t\tTween.To(1, 0.4f, x => GetComponent<InteractableSliceComponent>().Scale.Y = x, 0.2f);\r\n\t\t\t\r\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.X = 1.3f;\r\n\t\t\tTween.To(1, 1.3f, x => GetComponent<InteractableSliceComponent>().Scale.X = x, 0.2f);\r\n\t\t}\r\n\r\n\t\tpublic void Reroll(Entity entity, bool consumeCoin) {\r\n\t\t\tif (broken) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\r\n\r\n\t\t\tif (room == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tAnimate();\r\n\r\n\t\t\tif (consumeCoin) {\r\n\t\t\t\tvar component = entity.GetComponent<ConsumablesComponent>();\r\n\r\n\t\t\t\tif (component.Coins == 0) {\r\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"machine_0\", 3);\r\n\t\t\t\t\tAnimationUtil.ActionFailed();\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\r\n\r\n\t\t\t\t// todo: animate coin going in\r\n\t\t\t\tcomponent.Coins -= 1;\r\n\t\t\t\tcoinsConsumed++;\r\n\r\n\t\t\t\tif (Rnd.Float(100) > (coinsConsumed + Run.Luck) * 30) {\r\n\t\t\t\t\treturn; // Did not pay enough :P\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tGetComponent<DialogComponent>().Close();\r\n\t\t\tItems.Unlock(\"bk:d6\");\r\n\t\t\t\r\n\t\t\t// Reset the luck for the next uses\r\n\t\t\tcoinsConsumed = 0;\r\n\t\t\tReroller.Reroll(entity.Area, room, true, false, true, ignoredTypes);\r\n\r\n\t\t\tnumRolled += (consumeCoin ? 1 : 2);\r\n\t\t\tAudio.PlaySfx(\"level_vending_machine\");\r\n\r\n\t\t\tif (numRolled > 1 && Rnd.Float(100) < numRolled * 15 - Run.Luck * 2) {\r\n\t\t\t\tBreak();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void Break() {\r\n\t\t\tif (broken) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tbroken = true;\r\n\t\t\t\r\n\t\t\tAnimationUtil.Poof(Center);\r\n\t\t\tAnimationUtil.Explosion(Center);\r\n\r\n\t\t\tUpdateSprite();\r\n\r\n\t\t\tHandleEvent(new BrokenEvent {\r\n\t\t\t\tMachine = this\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tif (broken) {\r\n\t\t\t\tUpdateSprite();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void UpdateSprite() {\r\n\t\t\tvar component = GetComponent<InteractableSliceComponent>();\r\n\r\n\t\t\tcomponent.Sprite = CommonAse.Props.GetSlice(\"reroll_machine_broken\");\r\n\t\t\tcomponent.Offset.Y += Height - 14;\r\n\t\t\t\r\n\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"level_explosion\", 3);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (e is ExplodedEvent ee) {\r\n\t\t\t\tReroll(ee.Who, false);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn base.HandleEvent(e);\r\n\t\t}\r\n\r\n\t\tprivate void RenderShadow() {\r\n\t\t\tGraphicsComponent.Render(true);\r\n\t\t}\r\n\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tbase.Load(stream);\r\n\t\t\tbroken = stream.ReadBoolean();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tbase.Save(stream);\r\n\t\t\tstream.WriteBoolean(broken);\r\n\t\t}\r\n\t\t\r\n\t\tpublic class BrokenEvent : Event {\r\n\t\t\tpublic RerollMachine Machine;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/entities/machine/VendingMachine.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.drop;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.entities.machine {\n\tpublic class VendingMachine : Prop {\n\t\tprivate int coinsConsumed;\n\t\tprivate bool broken;\n\t\tprivate int spawnedCount;\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 18;\n\t\t\tHeight = 27;\n\n\t\t\tvar drops = new DropsComponent();\n\t\t\tAddComponent(drops);\n\t\t\tdrops.Add(\"bk:vending_machine\");\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = (e) => !broken\n\t\t\t});\n\t\t\t\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new RoomComponent());\n\t\t\tAddComponent(new RectBodyComponent(0, 6, 18, 20, BodyType.Static));\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static));\n\t\t\tAddComponent(new ShadowComponent(RenderShadow));\n\t\t\tAddComponent(new DialogComponent());\n\t\t\t\n\t\t\tAddComponent(new InteractableSliceComponent(\"props\", \"vending_machine\"));\n\t\t\tGetComponent<DialogComponent>().Dialog.Voice = 10;\n\t\t}\n\n\t\tprotected bool Interact(Entity entity) {\n\t\t\tif (broken) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tvar room = GetComponent<RoomComponent>().Room;\n\t\t\t\n\t\t\tif (room == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tAnimate();\n\n\t\t\tvar component = entity.GetComponent<ConsumablesComponent>();\n\n\t\t\tif (component.Coins == 0) {\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"machine_0\", 3);\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tGetComponent<DialogComponent>().Close();\n\n\t\t\tcomponent.Coins -= 1;\n\t\t\tcoinsConsumed++;\n\n\t\t\tif (Rnd.Float(100) > (coinsConsumed + Run.Luck - Run.Scourge) * 2) {\n\t\t\t\tAudio.PlaySfx(\"level_vending_machine_coin\");\n\n\t\t\t\treturn false; // Did not pay enough :P\n\t\t\t}\n\n\t\t\t// Reset the luck for the next uses\n\t\t\tcoinsConsumed = 0;\n\n\t\t\tvar item = Items.Generate(ItemPool.Shop);\n\n\t\t\tif (item == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar e = Items.CreateAndAdd(item, Area);\n\t\t\t\n\t\t\te.CenterX = CenterX;\n\t\t\te.CenterY = Bottom;\n\n\t\t\te.GetAnyComponent<BodyComponent>().Velocity = new Vector2(0, 128);\n\n\t\t\tspawnedCount++;\n\n\t\t\tAudio.PlaySfx(\"level_vending_machine\");\n\n\t\t\tif (spawnedCount > 1 && Rnd.Float(100) < spawnedCount * 30 - Run.Luck * 2) {\n\t\t\t\tBreak(false);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void Animate() {\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.Y = 0.7f;\n\t\t\tTween.To(1, 0.7f, x => GetComponent<InteractableSliceComponent>().Scale.Y = x, 0.2f);\n\t\t\t\n\t\t\tGetComponent<InteractableSliceComponent>().Scale.X = 1.3f;\n\t\t\tTween.To(1, 1.3f, x => GetComponent<InteractableSliceComponent>().Scale.X = x, 0.2f);\n\t\t}\n\n\t\tprivate void Break(bool spawn = true) {\n\t\t\tif (!broken) {\n\t\t\t\tUpdateSprite();\n\t\t\t\tAnimationUtil.Poof(Center);\n\t\t\t\tAnimationUtil.Explosion(Center);\n\t\t\t\tbroken = true;\n\t\t\t\tGetComponent<AudioEmitterComponent>().EmitRandomizedPrefixed(\"level_explosion\", 3);\n\n\t\t\t\tif (spawn) {\n\t\t\t\t\tGetComponent<DropsComponent>().SpawnDrops();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ExplodedEvent) {\n\t\t\t\tBreak();\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (broken) {\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\t\t}\n\n\t\tprivate void UpdateSprite() {\n\t\t\tvar component = GetComponent<InteractableSliceComponent>();\n\n\t\t\tcomponent.Sprite = CommonAse.Props.GetSlice(\"vending_machine_broken\");\n\t\t\tcomponent.Offset.Y += Height - 15;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tbroken = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(broken);\n\t\t}\n\n\t\tprivate void RenderShadow() {\n\t\t\tGraphicsComponent.Render(true);\n\t\t}\n\t\t\n\t\tpublic class BrokenEvent : Event {\n\t\t\tpublic VendingMachine Machine;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/plant/Plant.cs",
    "content": "using BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.biome;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.plant {\n\tpublic class Plant : Prop {\n\t\tprivate static string[] variants = {\n\t\t\t\"plant_a\", \"plant_b\", \"plant_c\", \"plant_d\", \"plant_e\", \"plant_f\",\n\t\t\t\"plant_i\", \"plant_j\", \"plant_k\", \"plant_l\", \"plant_m\", \"plant_n\", \"plant_o\" \n\t\t};\n\n\t\tpublic byte Variant;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (GraphicsComponent == null) {\n\t\t\t\tvar s = variants[Variant % variants.Length];\n\t\t\t\tvar g = Variant == 255 ? new PlantGraphicsComponent(\"props\", Events.Halloween ? \"pumpkin\" : \"cabbadge\")\n\t\t\t\t\t: new PlantGraphicsComponent($\"{Run.Level.Biome.Id}_biome\", $\"{s}{(Variant >= variants.Length ? \"s\" : \"\")}\");\n\t\t\t\t\n\t\t\t\tAddComponent(g);\n\t\t\t\tg.Flipped = Rnd.Chance();\n\n\t\t\t\tWidth = g.Sprite.Width;\n\t\t\t\tHeight = g.Sprite.Height;\n\n\t\t\t\tvar caves = Run.Level.Biome is CaveBiome;\n\n\t\t\t\tif (Variant != 255 && (caves || Run.Depth != 0 || (s != \"plant_k\" && s != \"plant_m\"))) {\n\t\t\t\t\tif (caves) {\n\t\t\t\t\t\tAddComponent(new LightComponent(this, Rnd.Int(16, 32), new Color(0.4f, 0.1f, 0.4f, 1f)));\n\t\t\t\t\t} else if (s == \"plant_m\") {\n\t\t\t\t\t\tAddComponent(new LightComponent(this, 24, new Color(0.4f, 0.4f, 1f, 1f)));\n\t\t\t\t\t} else if (s == \"plant_k\") {\n\t\t\t\t\t\tAddComponent(new LightComponent(this, 24, new Color(1f, 0.4f, 0.4f, 1f)));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\tAddComponent(new ShadowComponent());\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tVariant = (byte) Rnd.Int(variants.Length * 2);\n\n\t\t\tif (Events.Halloween && Rnd.Chance(10)) {\n\t\t\t\tVariant = 255;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tVariant = stream.ReadByte();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte(Variant);\n\t\t}\n\n\t\tpublic override void RenderImDebug() {\n\t\t\tbase.RenderImDebug();\n\t\t\tvar v = (int) Variant;\n\n\t\t\tif (ImGui.InputInt(\"Id\", ref v)) {\n\t\t\t\tVariant = (byte) v;\n\t\t\t\tRemoveComponent<PlantGraphicsComponent>();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/plant/PlantGraphicsComponent.cs",
    "content": "using System;\nusing BurningKnight.entity.component;\nusing Lens;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.level.entities.plant {\n\tpublic class PlantGraphicsComponent : SliceComponent {\n\t\tpublic float RotationModifier = 1f;\n\t\tpublic float Alpha = 1f;\n\t\t\n\t\tpublic PlantGraphicsComponent(string image, string slice) : base(image, slice) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tvar tm = Engine.Instance.State.Time;\n\t\t\tvar a = (float) (Math.Cos(tm - Entity.Y / 16 * Math.PI * 0.25f) * Math.Sin(tm * 0.9f + Entity.X / 16 * Math.PI * 0.3f) * (Sprite.Height * 0.05f)) * RotationModifier;\n\t\t\tvar origin = new Vector2(Sprite.Width / 2, Sprite.Height);\n\n\t\t\tif (!shadow) {\n\t\t\t\tGraphics.Color.A = (byte) (Alpha * 255f);\n\t\t\t}\n\n\t\t\tGraphics.Render(Sprite, Entity.Position + origin, shadow ? -a : a, origin, shadow ? MathUtils.InvertY : Vector2.One, Flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None);\n\t\t\tGraphics.Color.A = 255;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/ChestStatue.cs",
    "content": "using System;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.level.entities.chest;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class ChestStatue : Statue {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"chest_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 26;\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 11, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tif (e.GetComponent<HealthComponent>().ModifyHealth(-4, this, DamageType.Custom)) {\n\t\t\t\ttry {\n\t\t\t\t\tChestRegistry.PlaceRandom(BottomCenter + new Vector2(0, 12), Area);\n\t\t\t\t\tAudio.PlaySfx(\"level_summon_chest\");\n\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\tLog.Error(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/DiceStatue.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class DiceStatue : Statue {\n\t\t// todo: if effect does nothing alter to another effect\n\t\t// fixme: hp up/down is not saved\n\t\tpublic static Dictionary<string, Func<Statue, Entity, bool>> Effects =\n\t\t\tnew Dictionary<string, Func<Statue, Entity, bool>> {\n\t\t\t\t// + Hp up\n\n\t\t\t\t{\n\t\t\t\t\t\"buffed\", (s, e) => {\n\t\t\t\t\t\te.GetComponent<HealthComponent>().MaxHealth += 2;\n\t\t\t\t\t\tTextParticle.Add(e, Locale.Get(\"max_hp\"), 2, true);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// - Hp down\n\t\t\t\t{\n\t\t\t\t\t\"nerfed\", (s, e) => {\n\t\t\t\t\t\tif (e.GetComponent<HeartsComponent>().Total > 2) {\n\t\t\t\t\t\t\te.GetComponent<HealthComponent>().ModifyHealth(-2, s, DamageType.Custom);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\te.GetComponent<HealthComponent>().MaxHealth -= 2;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tTextParticle.Add(e, Locale.Get(\"max_hp\"), 2, true, true);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// + Heal\n\t\t\t\t{\n\t\t\t\t\t\"restored\", (s, e) => {\n\t\t\t\t\t\tvar c = Rnd.Int(1, 3);\n\t\t\t\t\t\te.GetComponent<HealthComponent>().ModifyHealth(c, s);\n\t\t\t\t\t\tTextParticle.Add(e, \"HP\", c, true);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// - Hurt\n\t\t\t\t{\n\t\t\t\t\t\"damaged\", (s, e) => {\n\t\t\t\t\t\tvar c = Rnd.Int(1, 3);\n\t\t\t\t\t\te.GetComponent<HealthComponent>().ModifyHealth(-c, s);\n\t\t\t\t\t\tTextParticle.Add(e, \"HP\", c, true, true);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// + Clear Scourge\n\t\t\t\t{\n\t\t\t\t\t\"cleansed\", (s, e) => {\n\t\t\t\t\t\tRun.RemoveScourge();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// - Add Scourge\n\t\t\t\t{\n\t\t\t\t\t\"scourged\", (s, e) => {\n\t\t\t\t\t\tRun.AddScourge(true);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// + Give coins\n\t\t\t\t{\n\t\t\t\t\t\"gifted\", (s, e) => {\n\t\t\t\t\t\tvar c = Rnd.Int(10, 21);\n\t\t\t\t\t\te.GetComponent<ConsumablesComponent>().Coins += c;\n\t\t\t\t\t\tTextParticle.Add(e, Locale.Get(\"coins\"), c, true);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// - Remove coins\n\t\t\t\t{\n\t\t\t\t\t\"robbed\", (s, e) => {\n\t\t\t\t\t\tvar c = e.GetComponent<ConsumablesComponent>();\n\t\t\t\t\t\tvar cn = (int) Math.Ceiling(c.Coins * Rnd.Float(0.2f, 0.5f));\n\t\t\t\t\t\te.GetComponent<ConsumablesComponent>().Coins -= cn;\n\t\t\t\t\t\tTextParticle.Add(e, Locale.Get(\"coins\"), cn, true, true);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// + Give chest\n\t\t\t\t{\n\t\t\t\t\t\"lucky\", (s, e) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tChestRegistry.PlaceRandom(s.BottomCenter + new Vector2(0, 12), s.Area);\n\t\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\t\tLog.Error(ex);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// - Remove weapon\n\t\t\t\t{\n\t\t\t\t\t\"unlucky\", (s, e) => {\n\t\t\t\t\t\tvar c = e.GetComponent<ActiveWeaponComponent>();\n\t\t\t\t\t\tvar item = c.Item;\n\t\t\t\t\t\tTextParticle.Add(e, item.Name, 1, true, true);\n\n\t\t\t\t\t\tc.Drop();\n\t\t\t\t\t\titem.Done = true;\n\n\t\t\t\t\t\tif (e.GetComponent<WeaponComponent>().Item == null) {\n\t\t\t\t\t\t\tc.Set(Items.CreateAndAdd(LevelSave.MeleeOnly || item.Data.WeaponType == WeaponType.Melee ? \"bk:ancient_sword\" : \"bk:ancient_revolver\", s.Area));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tc.RequestSwap();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\tprotected byte TimesUsed;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"dice_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 27;\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 12, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tTimesUsed++;\n\n\t\t\tvar keys = Effects.Keys;\n\t\t\tvar key = keys.ElementAt(Rnd.Int(keys.Count));\n\t\t\tvar bad = false;\n\n\t\t\tTextParticle.Add(this, Locale.Get(key));\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tbad = Effects[key](this, e);\n\n\t\t\t\tif (!Broken) {\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(bad ? \"item_dice_good\" : \"item_dice_bad\");\n\t\t\t\t}\n\t\t\t}, 1f);\n\n\t\t\tif (TimesUsed >= 3) {\n\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"item_dice_break\");\n\t\t\t\t\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tGetComponent<AudioEmitterComponent>().Emit(bad ? \"item_dice_good\" : \"item_dice_bad\");\n\t\t\t\t}, 0.6f);\n\t\t\t\t\n\t\t\t\tBreak();\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tTimesUsed = stream.ReadByte();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteByte(TimesUsed);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/Fountain.cs",
    "content": "using BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class Fountain : Statue {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"fountain\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 26;\n\t\t\t\n\t\t\tAddComponent(new DialogComponent {\n\t\t\t\tAnimateTyping = false\n\t\t\t});\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 11, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tif (Run.Scourge > 0) {\n\t\t\t\tvar c = e.GetComponent<ConsumablesComponent>();\n\n\t\t\t\tif (c.Coins < 5) {\n\t\t\t\t\t// Dude where ma money?\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"fountain_0\", 5);\n\t\t\t\t} else {\n\t\t\t\t\tc.Coins -= 5;\n\t\t\t\t\tRun.RemoveScourge();\n\t\t\t\t\t\n\t\t\t\t\t// You've been cleaned completely/a bit\n\t\t\t\t\tGetComponent<DialogComponent>().StartAndClose($\"fountain_{(Run.Scourge == 0 ? 2 : 1)}\", 5);\n\n\t\t\t\t\tif (Run.Scourge == 0) {\n\t\t\t\t\t\te.GetComponent<ActiveWeaponComponent>().Cleanse();\n\t\t\t\t\t\te.GetComponent<WeaponComponent>().Cleanse();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// You are free from scourges\n\t\t\t\tGetComponent<DialogComponent>().StartAndClose(\"fountain_3\", 5);\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/GamepadStatue.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.input;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class GamepadStatue : Statue {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"gamepad_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 20;\n\t\t}\n\n\t\tprotected override string GetFxText() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\treturn Area.Tagged[Tags.Player].Count < 2 && base.CanInteract(e);\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(2, 5, 16, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprotected override void AddSensor() {\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding * 9, -Npc.Padding * 9, Width + Npc.Padding * 18, Height + Npc.Padding * 18));\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar with = GetComponent<InteractableComponent>().CurrentlyInteracting;\n\n\t\t\tif (with == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var gamepad in Input.Gamepads) {\n\t\t\t\tif (gamepad.AnythingIsDown() && !gamepad.AnythingIsDown(gamepad.PreviousState)) {\n\t\t\t\t\tvar index = ((int) gamepad.PlayerIndex) + 1;\n\t\t\t\t\tvar found = false;\n\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\tvar i = p.GetComponent<InputComponent>();\n\t\t\t\t\t\n\t\t\t\t\t\tif (i.Index == index) {\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (found) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\t\t\tvar i = p.GetComponent<InputComponent>();\n\n\t\t\t\t\t\tif (i.Index == 0 && i.KeyboardEnabled) {\n\t\t\t\t\t\t\ti.GamepadEnabled = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\twith.GetComponent<InteractorComponent>().EndInteraction();\n\t\t\t\t\tTombstone.CreatePlayer(Area, (byte) index, true, with.BottomCenter + new Vector2(0, 2));\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/ScourgeStatue.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.item;\nusing Lens.assets;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class ScourgeStatue : Statue {\n\t\tprotected override string GetFxText() {\n\t\t\treturn \"break\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"scourge_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 30;\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 15, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tvar c = e.GetComponent<HealthComponent>();\n\t\t\tc.ModifyHealth(c.MaxHealth, this);\n\t\t\t\n\t\t\te.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(Scourge.Generate(), Area));\n\t\t\tBreak();\n\t\t\tAudio.PlaySfx(\"level_scourge_statue\");\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/Statue.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.file;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class Statue : SolidProp {\n\t\tprotected bool Broken;\n\n\t\tprotected virtual string GetFxText() {\n\t\t\treturn \"touch\";\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new InteractableComponent(Interact) {\n\t\t\t\tCanInteract = CanInteract,\n\t\t\t\tOnStart = (e) => {\n\t\t\t\t\tif (GetFxText() != null) {\n\t\t\t\t\t\tEngine.Instance.State.Ui.Add(new InteractFx(this, Locale.Get(GetFxText())));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\tAddComponent(new ShadowComponent());\n\t\t}\n\n\t\tprotected virtual bool CanInteract(Entity e) {\n\t\t\treturn !Broken;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (Broken) {\n\t\t\t\tUpdateSprite();\n\t\t\t}\n\n\t\t\tAddSensor();\n\n\t\t\tif (TryGetComponent<DialogComponent>(out var c)) {\n\t\t\t\tc.Dialog.Voice = 30;\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void AddSensor() {\n\t\t\tAddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2));\n\t\t}\n\n\t\tprotected virtual bool Interact(Entity e) {\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected void Break() {\n\t\t\tif (Broken) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCamera.Instance.Shake(8);\n\t\t\tBroken = true;\n\t\t\tUpdateSprite();\n\n\t\t\tGetComponent<AudioEmitterComponent>().Emit(GetSfx());\n\t\t}\n\n\t\tprotected virtual string GetSfx() {\n\t\t\treturn \"level_statue_break\";\n\t\t}\n\n\t\tprotected virtual void UpdateSprite() {\n\t\t\tGetComponent<InteractableSliceComponent>().Sprite = CommonAse.Props.GetSlice($\"broken_{Sprite}\");\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tBroken = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteBoolean(Broken);\n\t\t}\n\n\t\tpublic override bool ShouldCollide(Entity entity) {\n\t\t\treturn base.ShouldCollide(entity) && !(entity is Projectile);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/StoneStatue.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing Lens.assets;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class StoneStatue : Statue {\n\t\tprotected override string GetFxText() {\n\t\t\treturn \"break\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"stone_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 26;\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 11, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tItems.Unlock(\"bk:broken_stone\");\n\n\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\te.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:broken_stone\", Area));\n\t\t\t}\n\t\t\t\n\t\t\tBreak();\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected override string GetSfx() {\n\t\t\treturn \"level_stone_statue_break\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/SwordStatue.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.state;\nusing Lens.assets;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class SwordStatue : Statue {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"sword_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 33;\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 18, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tvar h = e.GetComponent<HealthComponent>();\n\n\t\t\tif (h.Health > 1) {\n\t\t\t\tTextParticle.Add(this, \"HP\", (int) h.Health - 1, true, true);\n\t\t\t}\n\t\t\t\n\t\t\th.SetHealth(1, this, type: DamageType.Custom);\n\t\t\te.GetComponent<InventoryComponent>().Pickup(Items.CreateAndAdd(\"bk:broken_heart\", Area, true));\n\t\t\t\n\t\t\tRun.AddScourge(true);\n\t\t\tBreak();\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/WarriorStatue.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.save;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class WarriorStatue : Statue {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"warrior_statue\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 34;\n\t\t}\n\n\t\tprotected override bool CanInteract(Entity e) {\n\t\t\tif (Broken) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (base.CanInteract(e)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar i = e.GetComponent<ActiveWeaponComponent>().Item;\n\t\t\treturn i != null && i.Id != \"bk:ancient_revolver\" && i.Id != \"bk:ancient_sword\";\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 19, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tvar c = e.GetComponent<ActiveWeaponComponent>();\n\t\t\tvar item = c.Item;\n\n\t\t\tc.Drop();\n\t\t\titem.Done = true;\n\n\t\t\tif (e.GetComponent<WeaponComponent>().Item == null) {\n\t\t\t\tc.Set(Items.CreateAndAdd(LevelSave.MeleeOnly || item.Data.WeaponType == WeaponType.Melee ? \"bk:ancient_sword\" : \"bk:ancient_revolver\", Area));\t\t\t\t\n\t\t\t} else {\n\t\t\t\tc.RequestSwap();\n\t\t\t}\n\n\t\t\tc.GetComponent<HealthComponent>().ModifyHealth(6, this);\n\t\t\tBreak();\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/entities/statue/Well.cs",
    "content": "using System.Linq;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.util;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.entities.statue {\n\tpublic class Well : Statue {\n\t\tprotected override string GetFxText() {\n\t\t\treturn \"throw_coin\";\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tSprite = \"well\";\n\t\t\tWidth = 20;\n\t\t\tHeight = 30;\n\t\t\t\n\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t}\n\n\t\tprotected override Rectangle GetCollider() {\n\t\t\treturn new Rectangle(0, 15, 20, 15);\n\t\t}\n\n\t\tprotected override bool Interact(Entity e) {\n\t\t\tvar c = e.GetComponent<ConsumablesComponent>();\n\n\t\t\tif (c.Coins < 1) {\n\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\tTextParticle.Add(e, Locale.Get(\"no_coins\"));\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tGetComponent<AudioEmitterComponent>().Emit(\"level_well_coin\");\n\n\t\t\tc.Coins--;\n\t\t\t\n\t\t\tvar keys = DiceStatue.Effects.Keys;\n\t\t\tvar key = keys.ElementAt(Rnd.Int(keys.Count));\n\t\t\t\n\t\t\tTextParticle.Add(this, Locale.Get(key));\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tDiceStatue.Effects[key](this, e);\n\t\t\t}, 1f);\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/BathFloor.cs",
    "content": "using BurningKnight.level.biome;\r\nusing BurningKnight.level.rooms;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.save;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.level.floors {\r\n\tpublic class BathFloor : FloorPainter {\r\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\r\n\t\t\tFloorRegistry.Paint(level, room, -1, gold);\r\n\r\n\t\t\tvar m = Rnd.Int(2, 4);\r\n\t\t\tvar a = gold && Rnd.Chance();\r\n\t\t\t\r\n\t\t\tPainter.Fill(level, room, m, a ? Tile.FloorD : Tiles.RandomFloor());\r\n\t\t\tPainter.Fill(level, room, m + 1, !a && gold && Rnd.Chance() ? Tile.FloorD : Tiles.RandomNewFloor());\r\n\t\t\tPainter.Fill(level, room, m + 1, LevelSave.BiomeGenerated is DesertBiome ? Tiles.RandomNewFloor() : Tile.Water);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/floors/ChessFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class ChessFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\t\t\t\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\t\t\tvar start = Rnd.Float();\n\t\t\tvar size = (float) Rnd.Int(1, 4); // Cast to float for division later on\n\t\t\t\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tPainter.Set(level, x, y, (int) ((int) (x / size) + (int) (y / size) + start) % 2 == 0 ? a : b);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// todo: some random rects in the center?\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/DiagonalFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class DiagonalFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\t\t\t\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\t\t\tvar start = Rnd.Float();\n\t\t\tvar sign = Rnd.Chance() ? 1 : -1;\n\t\t\tvar size = (float) Rnd.Int(1, 4); // Cast to float for division later on\n\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tPainter.Set(level, x, y, (int) (x / size + sign * (y / size) + start) % 2 == 0 ? a : b);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/FancyFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class FancyFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\t\t\tvar c = Tiles.RandomNewFloor();\n\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tvar z = (x + y * 3) % 5;\n\t\t\t\t\tPainter.Set(level, x, y, z == 0 ? a : ((z < 3) ^ (y % 2 == 0)) ? b : c);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/FloorPainter.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.floors {\n\tpublic class FloorPainter {\n\t\tpublic virtual void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tPainter.Fill(level, room, 1, gold ? Tile.FloorD : Tiles.RandomFloor());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/FloorRegistry.cs",
    "content": "using BurningKnight.entity.pool;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.floors {\n\tpublic class FloorRegistry : Pool<FloorPainter> {\n\t\tpublic static FloorRegistry Instance = new FloorRegistry();\n\n\t\tpublic FloorRegistry() {\n\t\t\tAdd(new FloorPainter(), 1f);\n\t\t\tAdd(new ChessFloor(), 1f);\n\t\t\tAdd(new DiagonalFloor(), 1f);\n\t\t\tAdd(new GeometryFloor(), 1f);\n\t\t\tAdd(new MazeFloor(), 1f);\n\t\t\tAdd(new TrippleFloor(), 1f);\n\t\t\tAdd(new LineFloor(), 1f);\n\t\t\tAdd(new BathFloor(), 1f);\n\t\t\tAdd(new PatchFloor(), 1f);\n\t\t\tAdd(new FancyFloor(), 1f);\n\t\t\tAdd(new HoneycombFloor(), 1f);\n\t\t}\n\n\t\tpublic static void Paint(Level level, RoomDef room, int i = -1, bool gold = false) {\n\t\t\tvar painter = i == -1 ? Instance.Generate() : Instance.Get(i);\n\t\t\tpainter.Paint(level, room, new Rect(room.Left + 1, room.Top + 1, \n\t\t\t\troom.Left + 1 + room.GetWidth() - 2, room.Top + 1 + room.GetHeight() - 2), gold);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/GeometryFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class GeometryFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor(gold));\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.FillEllipse(level, inside, gold && Rnd.Chance(30) ? Tile.FloorD : Tiles.RandomNewFloor());\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(20)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, gold ? Tile.FloorD : Tiles.RandomNewFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, inside, gold ? Tile.FloorD : Tiles.RandomNewFloor());\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance(40)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, gold && Rnd.Chance(30) ? Tile.FloorD : Tiles.RandomNewFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, inside, gold && Rnd.Chance(30) ? Tile.FloorD : Tiles.RandomNewFloor());\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/HoneycombFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class HoneycombFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tPainter.Set(level, x, y, (x + y * 2) % 4 == 0 ? a : b);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/LineFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class LineFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\t\t\t\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\t\t\tvar vert = Rnd.Chance();\n\t\t\tvar size = Rnd.Int(1, 4);\n\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tPainter.Set(level, x, y, (int) ((float) (vert ? y : x) / size) % 2 == 0 ? a : b);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/MazeFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class MazeFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t}\n\n\t\t\tvar a = gold ? Tile.FloorD : Tiles.RandomFloor();\n\t\t\tvar b = Tiles.RandomNewFloor();\n\n\t\t\tvar maze = Maze.Generate(inside);\n\t\t\t\n\t\t\tfor (int y = 0; y < inside.GetHeight(); y++) {\n\t\t\t\tfor (int x = 0; x < inside.GetWidth(); x++) {\n\t\t\t\t\tPainter.Set(level, x + inside.Left, y + inside.Top, maze[x][y] ? a : b);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/PatchFloor.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.floors {\n\tpublic class PatchFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tPainter.Fill(level, room, 1, Tiles.RandomFloor());\n\t\t\t\n\t\t\tvar w = room.GetWidth() - 2;\n\t\t\tvar h = room.GetHeight() - 2;\n\t\t\tvar fill = 0.25f + (room.GetWidth() * room.GetHeight()) / 1024f;\n\t\t\tvar f = gold ? Tile.FloorD : Tiles.RandomNewFloor();\n\t\t\t\n\t\t\tvar patch = Patch.Generate(w, h, fill, 4);\n\n\t\t\tfor (var y = 0; y < room.GetHeight() - 2; y++) {\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tif (patch[x + y * w]) {\n\t\t\t\t\t\tlevel.Set(room.Left + x + 1, room.Top + y + 1, f);\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/floors/TrippleFloor.cs",
    "content": "using System.Linq;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.floors {\n\tpublic class TrippleFloor : FloorPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside, bool gold) {\n\t\t\tvar tiles = new[] {\n\t\t\t\tTile.FloorA, Tile.FloorB, Tile.FloorC\n\t\t\t};\n\n\t\t\tif (gold) {\n\t\t\t\ttiles[Rnd.Int(3)] = Tile.FloorD;\n\t\t\t}\n\n\t\t\ttiles = tiles.OrderBy(x => Rnd.Generator.Next()).ToArray();\n\t\t\t\n\t\t\tvar a = tiles[0];\n\t\t\tvar b = tiles[1];\n\t\t\tvar c = Rnd.Chance() ? a : tiles[2];\n\t\t\tvar start = Rnd.Float();\n\t\t\tvar size = Rnd.Int(1, 4);\n\t\t\tvar two = Rnd.Chance();\n\t\t\t\t\t\t\n\t\t\tfor (int y = inside.Top; y < inside.Bottom; y++) {\n\t\t\t\tfor (int x = inside.Left; x < inside.Right; x++) {\n\t\t\t\t\tint val;\n\t\t\t\t\t\n\t\t\t\t\tif (two) {\n\t\t\t\t\t\tval = ((int) (x + start) % size == 0 ? 1 : ((int) (y + start)) % size == 0 ? 1 : 0) % 3;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval = (((int) (x + start) % size == 0 ? 1 : 0) + ((int) (y + start) % size == 0 ? 1 : 0)) % 3;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar tile = a;\n\n\t\t\t\t\tif (val == 1) {\n\t\t\t\t\t\ttile = b;\n\t\t\t\t\t} else if (val == 2) {\n\t\t\t\t\t\ttile = c;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPainter.Set(level, x, y, tile);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/hall/HallBuilder.cs",
    "content": "using System.Collections.Generic;\r\nusing BurningKnight.level.builders;\r\nusing BurningKnight.level.rooms;\r\n\r\nnamespace BurningKnight.level.hall {\r\n\tpublic class HallBuilder : RegularBuilder {\r\n\t\tpublic override List<RoomDef> Build(List<RoomDef> Init) {\r\n\t\t\tSetupRooms(Init);\r\n\r\n\t\t\tExit.SetSize();\r\n\t\t\tExit.SetPos(0, 0);\r\n\t\t\t\r\n\t\t\t// PlaceRoom(Init, Entrance, Exit, 95);\r\n\t\t\t\r\n\t\t\treturn Init;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/hall/HallLevel.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\n\nnamespace BurningKnight.level.hall {\n\tpublic class HallLevel : RegularLevel {\n\t\tpublic HallLevel() : base(BiomeRegistry.Get(Biome.Hub)) {\n\n\t\t}\n\n\t\tprotected override List<RoomDef> CreateRooms() { \n\t\t\treturn new List<RoomDef> {\n\t\t\t\tnew HallRoom()\n\t\t\t};\n\t\t}\n\n\t\tprotected override Builder GetBuilder() {\n\t\t\treturn new HallBuilder();\n\t\t}\n\n\t\tprotected override Painter GetPainter() {\n\t\t\treturn new Painter {\n\t\t\t\tWater = 0,\n\t\t\t\tCobweb = 0,\n\t\t\t\tGrass = 0,\n\t\t\t\tDirt = 0\n\t\t\t};\n\t\t}\n\n\t\tpublic override int GetPadding() {\n\t\t\treturn 15;\n\t\t}\n\n\t\tpublic override Tile GetFilling() {\n\t\t\treturn Tile.Chasm;\n\t\t}\n\n\t\tpublic override string GetMusic() {\n\t\t\treturn \"Hub\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/hall/HallRoom.cs",
    "content": "using BurningKnight.assets.prefabs;\r\nusing BurningKnight.level.rooms.entrance;\r\nusing BurningKnight.level.tile;\r\n\r\nnamespace BurningKnight.level.hall {\r\n\tpublic class HallRoom : ExitRoom {\r\n\t\tpublic const string PrefabName = \"hub\";\r\n\t\tprivate Prefab prefab;\r\n\r\n\t\tpublic HallRoom() {\r\n\t\t\tprefab = Prefabs.Get(PrefabName);\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Clip = null;\r\n\t\t\tPainter.Fill(level, this, Tile.Chasm);\r\n\t\t\tPainter.Prefab(level, PrefabName, Left + 1, Top + 1);\r\n\t\t}\r\n\r\n\t\tpublic override void PaintFloor(Level level) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn prefab.Level.Width;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn prefab.Level.Width + 1;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn prefab.Level.Height;\r\n\t\t}\r\n\t\t\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn prefab.Level.Height + 1;\r\n\t\t}\r\n\r\n\t\tpublic override bool ConvertToEntity() {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/paintings/AnimatedPainting.cs",
    "content": "using BurningKnight.entity.component;\r\nusing Lens;\r\nusing Lens.graphics;\r\n\r\nnamespace BurningKnight.level.paintings {\r\n\tpublic class AnimatedPainting : Painting {\r\n\t\tpublic override void PostInit() {\r\n\t\t\tAddComponent(new AnimationComponent(Id));\r\n\t\t\tbase.PostInit();\r\n\t\t}\r\n\r\n\t\tprotected override TextureRegion GetRegion() {\r\n\t\t\tGetComponent<AnimationComponent>().Update(Engine.Delta);\r\n\t\t\treturn GetComponent<AnimationComponent>().Animation.GetCurrentTexture();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/paintings/Painting.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.level.paintings {\n\tpublic class Painting : SaveableEntity {\n\t\tprivate const float Padding = 64f;\n\t\t\n\t\tpublic string Id;\n\t\tpublic string Author;\n\t\t\n\t\tprivate Entity from;\n\t\tprivate float scale;\n\t\tprivate float uiY;\n\n\t\tprivate string name;\n\t\tprivate string author;\n\t\t\n\t\tprivate float nameWidth;\n\t\tprivate float authorWidth;\n\n\t\tprivate TextureRegion big;\n\t\t\n\t\tprotected virtual TextureRegion GetRegion() {\n\t\t\treturn big;\n\t\t}\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddComponent(new HealthComponent {\n\t\t\t\tInitMaxHealth = 1,\n\t\t\t\tRenderInvt = true,\n\t\t\t\tAutoKill = false\n\t\t\t});\n\n\t\t\tAddComponent(new ExplodableComponent());\n\t\t\tAddComponent(new InteractableComponent(Interact));\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tif (!HasComponent<AnimationComponent>()) {\n\t\t\t\tbig = Animations.Get(\"paintings\").GetSlice(Id);\n\t\t\t}\n\t\t\t\n\t\t\tAddComponent(new InteractableSliceComponent(\"paintings\", $\"{Id}_small\"));\n\t\t\tvar region = GetComponent<InteractableSliceComponent>().Sprite;\n\n\t\t\tWidth = region.Width;\n\t\t\tHeight = region.Height;\n\t\t\t\n\t\t\tAddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, true));\n\n\t\t\tDepth = Layers.Door;\n\t\t\t\n\t\t\tname = Locale.Get($\"painting_{Id}\");\n\t\t\tauthor = $\"{Locale.Get(\"by\")} {Author}\";\n\n\t\t\tnameWidth = Font.Medium.MeasureString(name).Width;\n\t\t\tauthorWidth = Font.Small.MeasureString(author).Width;\n\t\t}\n\n\t\tprotected virtual bool Interact(Entity entity) {\n\t\t\t((InGameState) Engine.Instance.State).CurrentPainting = this;\n\n\t\t\tuiY = Display.UiHeight;\n\t\t\t\n\t\t\tTween.To(1, 0, x => scale = x, 1.1f, Ease.BackOut);\n\t\t\tTween.To(0, uiY, x => uiY = x, 0.8f, Ease.BackOut);\n\n\t\t\tif (Id == \"cat\") {\n\t\t\t\tAchievements.Unlock(\"bk:cat_without_a_hat\");\n\t\t\t}\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic void Remove() {\n\t\t\tif (uiY > 1f) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTween.To(0, 1, x => scale = x, 0.2f);\n\t\t\tTween.To(Display.Height, uiY, x => uiY = x, 0.2f).OnEnd = () => {\n\t\t\t\t((InGameState) Engine.Instance.State).CurrentPainting = null;\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\tstream.WriteString(Id);\n\t\t\tstream.WriteString(Author);\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\t\t\tId = stream.ReadString();\n\t\t\tAuthor = stream.ReadString();\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is HealthModifiedEvent ev) {\n\t\t\t\tif (TryGetComponent<RoomComponent>(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tvar h = GetComponent<HealthComponent>();\n\n\t\t\t\tif (h.Health + ev.Amount == 0) {\n\t\t\t\t\tif (Id != \"egor\") {\n\t\t\t\t\t\tfrom = ev.From;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (from != null && TryGetComponent<HealthComponent>(out var h) && h.InvincibilityTimer <= 0.45f) {\n\t\t\t\tDone = true;\n\n\t\t\t\tif (from is Player) {\n\t\t\t\t\tvar count = GlobalSave.GetInt(\"paintings_destroyed\", 0) + 1;\n\n\t\t\t\t\tif (count >= 100) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:van_no_gogh\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tGlobalSave.Put(\"paintings_destroyed\", count);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\n\t\t\t\t\t\t\n\t\t\t\t\tpart.Position = Center;\n\t\t\t\t\tpart.Particle.Scale = Lens.util.math.Rnd.Float(0.4f, 0.8f);\n\t\t\t\t\t\n\t\t\t\t\tArea.Add(part);\n\n\t\t\t\t\tpart.Depth = Depth;\n\t\t\t\t}\n\n\t\t\t\tif (!HasComponent<AudioEmitterComponent>()) {\n\t\t\t\t\tAddComponent(new AudioEmitterComponent());\n\t\t\t\t}\n\t\t\t\n\t\t\t\tAudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed(\"level_chair_break\", 2, 0.5f);\n\t\t\t\t\n\t\t\t\tParticles.BreakSprite(Area, GetComponent<InteractableSliceComponent>().Sprite, Position, Depth);\n\t\t\t\tCamera.Instance.Shake(2f);\n\t\t\t\tEngine.Instance.Freeze = 1f;\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void RenderUi() {\n\t\t\tvar region = GetRegion();\n\t\t\tvar sc = (float) Math.Max(\n\t\t\t\t1, \n\t\t\t\tMath.Floor(\n\t\t\t\t\tMath.Min(\n\t\t\t\t\t\t(Display.UiWidth - Padding) / region.Width, \n\t\t\t\t\t\t(Display.UiHeight - Padding) / region.Height)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\n\t\t\tGraphics.Render(region, new Vector2(Display.UiWidth / 2f, Display.UiHeight / 2f + uiY), \n\t\t\t\t(float) (Math.Cos(Engine.Time) * 0.1f),\n\t\t\t\tregion.Center, new Vector2(scale * sc));\n\t\t\t\n\t\t\tGraphics.Print(name, Font.Medium, \n\t\t\t\tnew Vector2(Display.UiWidth / 2f, Display.UiHeight / 2f + uiY + region.Height * 0.5f * sc + 16f), 0,\n\t\t\t\tnew Vector2(nameWidth / 2, 8), new Vector2(scale));\n\t\t\t\n\t\t\tGraphics.Print(author, Font.Small, \n\t\t\t\tnew Vector2(Display.UiWidth / 2f, Display.UiHeight / 2f + uiY + region.Height * 0.5f * sc + 28f), 0,\n\t\t\t\tnew Vector2(authorWidth / 2, 8), new Vector2(scale));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/paintings/PaintingRegistry.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.paintings {\n\tpublic static class PaintingRegistry {\n\t\tprivate static List<Info> paintings = new List<Info>();\n\n\t\tstatic PaintingRegistry() {\n\t\t\tAdd(\"rexcellent\", \"egordorichev\", 0.1f);\n\t\t\tAdd(\"grannylisa\", \"DSF100\");\n\t\t\tAdd(\"maanex\", \"DSF100\", 0.1f);\n\t\t\tAdd(\"bk\", \"Mate\");\n\t\t\tAdd(\"failpositive\", \"Jusiv_\", 0.1f);\n\t\t\tAdd(\"old_man\", \"???\");\n\t\t\tAdd(\"arthouse\", \"xD\");\n\t\t\tAdd(\"black\", \"!!!\");\n\t\t\tAdd(\"milt\", \"egordorichev\");\n\t\t\tAdd(\"skyscraper\", \"egordorichev\");\n\t\t\tAdd(\"egor\", \"egordorichev\", 0.25f);\n\t\t\tAdd(\"null\", \"SEGFAULT\", 0.5f);\n\t\t\tAdd(\"lamp\", \"Brastin\");\n\t\t\tAdd(\"badosz\", \"DSF100\", 1f, null, true);\n\t\t\tAdd(\"tv\", \"ANIVIRE\");\n\t\t\tAdd(\"company\", \"ANIVIRE\");\n\t\t\tAdd(\"trasevol\", \"TRASEVOL_DOG\");\n\t\t\tAdd(\"scream\", \"???\");\n\t\t\tAdd(\"stars\", \"???\");\n\t\t\tAdd(\"fog\", \"???\");\n\t\t\tAdd(\"cat\", \"Brastin\", 0.1f);\n\t\t\tAdd(\"dungeon\", \"Johan Peitz\", 0.2f);\n\t\t\tAdd(\"goose\", \"Jaxetly\");\n\t\t\tAdd(\"chess\", \"Nikithn\");\n\t\t\tAdd(\"guitar\", \"Nikithn\", 0.5f);\n\t\t\tAdd(\"peach\", \"unije\");\n\t\t\tAdd(\"agency\", \"smashy\", 0.01f);\n\t\t\tAdd(\"ducktective\", \"smashy\", 0.1f);\n\t\t\tAdd(\"beet_boys\", \"Gaziter\");\n\t\t\tAdd(\"moonshine\", \"Gaziter\");\n\t\t\tAdd(\"void\", \"Gaziter\");\n\t\t\tAdd(\"esty\", \"???\", 0.1f);\n\t\t\tAdd(\"nat\", \"MateCziner\");\n\t\t\tAdd(\"totemori\", \"MateCziner\");\n\t\t\tAdd(\"horatio\", \"MateCziner\");\n\t\t\tAdd(\"coce\", \"MateCziner\");\n\t\t\tAdd(\"no_idea\", \"MateCziner\");\n\t\t\tAdd(\"tinkerer\", \"MateCziner\");\n\t\t\tAdd(\"totemori_redux\", \"MateCziner\");\n\t\t\tAdd(\"raj\", \"MateCziner\");\n\t\t\tAdd(\"plank\", \"MateCziner\");\n\t\t\tAdd(\"qrilin\", \"MateCziner\");\n\t\t\tAdd(\"in_loving_memory_of_ali\", \"MateCziner\");\n\t\t\tAdd(\"happy_accident\", \"MateCziner\");\n\t\t\tAdd(\"observing_cheese\", \"MateCziner\");\n\t\t\tAdd(\"kobra_throne\", \"MateCziner\");\n\t\t\tAdd(\"chicken_enemy_unknown\", \"MateCziner\");\n\t\t\tAdd(\"mori\", \"MateCziner\");\n\t\t\tAdd(\"balbo\", \"MateCziner\");\n\t\t\tAdd(\"know_stuff\", \"MateCziner\");\n\t\t\tAdd(\"olpi\", \"MateCziner\");\n\t\t\tAdd(\"one_knight_stand\", \"MateCziner\");\n\t\t\tAdd(\"ne_furdje_le\", \"MateCziner\");\n\t\t\tAdd(\"sushi_sushi\", \"MateCziner\");\n\t\t\tAdd(\"hoop_gang\", \"MateCziner\");\n\t\t\tAdd(\"riveting_view\", \"MateCziner\");\n\t\t\tAdd(\"gang\", \"MateCziner\");\n\t\t\tAdd(\"zweihandler\", \"MateCziner\");\n\t\t\tAdd(\"whoops\", \"MateCziner\");\n\t\t\tAdd(\"too_lake\", \"MateCziner\");\n\t\t\tAdd(\"cauliflower\", \"MateCziner\");\n\t\t\tAdd(\"raise_volcano\", \"MateCziner\");\n\t\t\tAdd(\"mahula\", \"MateCziner\");\n\t\t\tAdd(\"step_through\", \"MateCziner\");\n\t\t\tAdd(\"thats_a_moon\", \"MateCziner\");\n\t\t\tAdd(\"totem\", \"MateCziner\");\n\t\t\tAdd(\"too_late\", \"MateCziner\");\n\t\t\tAdd(\"whipped_cream\", \"MateCziner\");\n\t\t\tAdd(\"tofulama\", \"Didu\");\n\t\t\tAdd(\"peasants\", \"Diego Rivera\", 0.1f);\n\t\t\tAdd(\"code\", \"egordorichev\");\n\t\t\tAdd(\"eye\", \"Nirak03\", 0.1f);\n\t\t\tAdd(\"bug\", \"NeverCookFirst\", 0.02f);\n\t\t\tAdd(\"new\", \"Janky\", 0.1f);\n\t\t\tAdd(\"bgang\", \"Friendship\", 0.1f);\n\t\t}\n\t\t\n\t\tpublic static void Add(string id, string author, float chance = 1f, string[] biomes = null, bool animated = false) {\n\t\t\tpaintings.Add(new Info {\n\t\t\t\tId = id,\n\t\t\t\tAuthor = author,\n\t\t\t\tChance = chance,\n\t\t\t\tBiomes = biomes,\n\t\t\t\tAnimated = animated\n\t\t\t});\n\t\t}\n\n\t\tpublic static Painting Generate(Biome biome) {\n\t\t\tvar length = paintings.Count;\n\t\t\tfloat sum = 0;\n\n\t\t\tforeach (var info in paintings) {\n\t\t\t\tif (biome.IsPresent(info.Biomes)) {\n\t\t\t\t\tsum += info.Chance;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfloat value = Rnd.Float(sum);\n\t\t\tsum = 0;\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tvar info = paintings[i];\n\n\t\t\t\tif (!biome.IsPresent(info.Biomes)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tsum += info.Chance;\n\n\t\t\t\tif (value < sum) {\n\t\t\t\t\tif (info.Animated) {\n\t\t\t\t\t\treturn new AnimatedPainting {\n\t\t\t\t\t\t\tId = info.Id,\n\t\t\t\t\t\t\tAuthor = info.Author\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn new Painting {\n\t\t\t\t\t\tId = info.Id,\n\t\t\t\t\t\tAuthor = info.Author\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate class Info {\n\t\t\tpublic string Id;\n\t\t\tpublic string Author;\n\t\t\tpublic float Chance;\n\t\t\tpublic string[] Biomes;\n\t\t\tpublic bool Animated;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/RoomDef.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.floors;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.challenge;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.level.rooms.darkmarket;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.rooms.payed;\nusing BurningKnight.level.rooms.scourged;\nusing BurningKnight.level.rooms.secret;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.level.rooms.shop.sub;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.rooms.spiked;\nusing BurningKnight.level.rooms.trap;\nusing BurningKnight.level.rooms.treasure;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.walls;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms {\n\tpublic abstract class RoomDef : Rect {\n\t\tpublic enum Connection {\n\t\t\tAll,\n\t\t\tLeft,\n\t\t\tRight,\n\t\t\tTop,\n\t\t\tBottom\n\t\t}\n\n\t\tpublic Dictionary<RoomDef, DoorPlaceholder> Connected = new Dictionary<RoomDef, DoorPlaceholder>();\n\t\tpublic int Id;\n\t\tpublic int Distance = -1;\n\n\t\tpublic List<RoomDef> Neighbours = new List<RoomDef>();\n\t\tprivate List<Dot> Busy = new List<Dot>();\n\n\t\tpublic virtual int GetMinWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic virtual int GetMinHeight() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic virtual int GetMaxWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tpublic virtual int GetMaxHeight() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tpublic abstract int GetMaxConnections(Connection Side);\n\n\t\tpublic abstract int GetMinConnections(Connection Side);\n\n\t\tpublic virtual void PaintFloor(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tFloorRegistry.Paint(level, this, -1, Painter.AllGold);\n\t\t}\n\t\t\n\t\tpublic virtual void Paint(Level level) {\n\t\t\tWallRegistry.Paint(level, this);\n\t\t}\n\n\t\tpublic virtual void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Regular;\n\t\t\t}\n\t\t}\n\n\t\tpublic int GetCurrentConnections(Connection Direction) {\n\t\t\tif (Direction == Connection.All) {\n\t\t\t\treturn Connected.Count;\n\t\t\t}\n\n\t\t\tvar Total = 0;\n\n\t\t\tforeach (var R in Connected.Keys) {\n\t\t\t\tvar I = Intersect(R);\n\n\t\t\t\tif (Direction == Connection.Left && I.GetWidth() == 0 && I.Left == Left) {\n\t\t\t\t\tTotal++;\n\t\t\t\t} else if (Direction == Connection.Top && I.GetHeight() == 0 && I.Top == Top) {\n\t\t\t\t\tTotal++;\n\t\t\t\t} else if (Direction == Connection.Right && I.GetWidth() == 0 && I.Right == Right) {\n\t\t\t\t\tTotal++;\n\t\t\t\t} else if (Direction == Connection.Bottom && I.GetHeight() == 0 && I.Bottom == Bottom) {\n\t\t\t\t\tTotal++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Total;\n\t\t}\n\n\t\tpublic int GetLastConnections(Connection Direction) {\n\t\t\tif (GetCurrentConnections(Connection.All) >= GetMaxConnections(Connection.All)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn GetMaxConnections(Direction) - GetCurrentConnections(Direction);\n\t\t}\n\n\t\tpublic virtual bool CanConnect(RoomDef r, Dot p) {\n\t\t\treturn ((int) p.X == Left || (int) p.X == Right) != ((int) p.Y == Top || (int) p.Y == Bottom);\n\t\t}\n\n\t\tpublic virtual bool CanConnect(Connection direction) {\n\t\t\tvar Cnt = GetLastConnections(direction);\n\n\t\t\treturn Cnt > 0;\n\t\t}\n\n\t\tpublic virtual bool CanConnect(RoomDef r) {\n\t\t\tvar I = Intersect(r);\n\t\t\tvar FoundPoint = false;\n\n\t\t\tforeach (var P in I.GetPoints()) {\n\t\t\t\tif (CanConnect(r, P) && r.CanConnect(r, P)) {\n\t\t\t\t\tFoundPoint = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!FoundPoint) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (I.GetWidth() == 0 && I.Left == Left) {\n\t\t\t\treturn CanConnect(Connection.Left) && r.CanConnect(Connection.Left);\n\t\t\t}\n\n\t\t\tif (I.GetHeight() == 0 && I.Top == Top) {\n\t\t\t\treturn CanConnect(Connection.Top) && r.CanConnect(Connection.Top);\n\t\t\t}\n\n\t\t\tif (I.GetWidth() == 0 && I.Right == Right) {\n\t\t\t\treturn CanConnect(Connection.Right) && r.CanConnect(Connection.Right);\n\t\t\t}\n\n\t\t\tif (I.GetHeight() == 0 && I.Bottom == Bottom) {\n\t\t\t\treturn CanConnect(Connection.Bottom) && r.CanConnect(Connection.Bottom);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool ConnectTo(RoomDef Other) {\n\t\t\tif (Neighbours.Contains(Other)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar I = Intersect(Other);\n\t\t\tvar W = I.GetWidth();\n\t\t\tvar H = I.GetHeight();\n\n\t\t\tif ((W == 0 && H >= 2) || (H == 0 && W >= 2)) {\n\t\t\t\tNeighbours.Add(Other);\n\t\t\t\tOther.Neighbours.Add(this);\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool ConnectWithRoom(RoomDef roomDef) {\n\t\t\tif ((Neighbours.Contains(roomDef) || ConnectTo(roomDef)) && !Connected.ContainsKey(roomDef) && CanConnect(roomDef)) {\n\t\t\t\tConnected[roomDef] = null;\n\t\t\t\troomDef.Connected[this] = null;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic Dot GetRandomCell() {\n\t\t\treturn new Dot(Rnd.Int(Left + 1, Right), Rnd.Int(Top + 1, Bottom));\n\t\t}\n\t\t\n\t\tpublic Dot GetRandomCellWithWalls() {\n\t\t\treturn new Dot(Rnd.Int(Left, Right + 1), Rnd.Int(Top, Bottom + 1));\n\t\t}\n\n\t\tpublic Dot GetRandomFreeCell() {\n\t\t\tvar passable = new List<Dot>();\n\n\t\t\tfor (var x = Left + 1; x < Right; x++) {\n\t\t\t\tfor (var y = Top + 1; y < Bottom; y++) {\n\t\t\t\t\tif (Run.Level.IsPassable(x, y)) {\n\t\t\t\t\t\tpassable.Add(new Dot(x, y));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passable.Count == 0) {\n\t\t\t\tLog.Error($\"Failed to find a free cell ({GetType().Name})\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn passable[Rnd.Int(passable.Count)];\n\t\t}\n\t\t\n\t\tpublic bool HasDoorsNear(int x, int y, int r) {\n\t\t\tforeach (var Door in Connected.Values) {\n\t\t\t\tvar Dx = (Door.X - x);\n\t\t\t\tvar Dy = (Door.Y - y);\n\t\t\t\tvar D = (float) Math.Sqrt(Dx * Dx + Dy * Dy);\n\n\t\t\t\tif (D < r) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic Dot GetRandomDoorFreeCell() {\n\t\t\tvar passable = new List<Dot>();\n\n\t\t\tfor (var x = Left + 1; x < Right; x++) {\n\t\t\t\tfor (var y = Top + 1; y < Bottom; y++) {\n\t\t\t\t\tif (Run.Level.IsPassable(x, y)) {\n\t\t\t\t\t\tvar found = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var Door in Connected.Values) {\n\t\t\t\t\t\t\tvar Dx = (int) (Door.X - x);\n\t\t\t\t\t\t\tvar Dy = (int) (Door.Y - y);\n\t\t\t\t\t\t\tvar D = (float) Math.Sqrt(Dx * Dx + Dy * Dy);\n\n\t\t\t\t\t\t\tif (D < 4) {\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!found) {\n\t\t\t\t\t\t\tpassable.Add(new Dot(x, y));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (passable.Count == 0) {\n\t\t\t\tLog.Error($\"Failed to find a free cell ({GetType().Name})\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn passable[Rnd.Int(passable.Count)];\n\t\t}\n\t\t\n\t\tpublic bool SetSize() {\n\t\t\treturn SetSize(GetMinWidth(), GetMaxWidth(), GetMinHeight(), GetMaxHeight());\n\t\t}\n\n\t\tprotected virtual int ValidateWidth(int W) {\n\t\t\treturn W;\n\t\t}\n\n\t\tprotected virtual int ValidateHeight(int H) {\n\t\t\treturn H;\n\t\t}\n\n\t\tprotected bool SetSize(int MinW, int MaxW, int MinH, int MaxH) {\n\t\t\tif (MinW < GetMinWidth() || MaxW > GetMaxWidth() || MinH < GetMinHeight() || MaxH > GetMaxHeight() || MinW > MaxW || MinH > MaxH) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (Quad()) {\n\t\t\t\tvar V = Math.Min(ValidateWidth(Rnd.Int(MinW, MaxW) - 1), ValidateHeight(Rnd.Int(MinH, MaxH) - 1));\n\t\t\t\tResize(V, V);\n\t\t\t} else {\n\t\t\t\tResize(ValidateWidth(Rnd.Int(MinW, MaxW) - 1), ValidateHeight(Rnd.Int(MinH, MaxH) - 1));\n\t\t\t}\n\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual bool Quad() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool SetSizeWithLimit(int W, int H) {\n\t\t\tif (W < GetMinWidth() || H < GetMinHeight()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tSetSize();\n\n\t\t\tif (GetWidth() > W || GetHeight() > H) {\n\t\t\t\tvar Ww = ValidateWidth(Math.Min(GetWidth(), W) - 1);\n\t\t\t\tvar Hh = ValidateHeight(Math.Min(GetHeight(), H) - 1);\n\n\t\t\t\tif (Ww >= W || Hh >= H) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tResize(Ww, Hh);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic void ClearConnections() {\n\t\t\tforeach (var R in Neighbours) {\n\t\t\t\tR.Neighbours.Remove(this);\n\t\t\t}\n\n\t\t\tNeighbours.Clear();\n\n\t\t\tforeach (var R in Connected.Keys) {\n\t\t\t\tR.Connected.Remove(this);\n\t\t\t}\n\n\t\t\tConnected.Clear();\n\t\t}\n\n\t\tpublic bool CanPlaceWater(Dot P) {\n\t\t\treturn Inside(P);\n\t\t}\n\n\t\tpublic List<Dot> GetWaterPlaceablePoints() {\n\t\t\tvar Points = new List<Dot>();\n\n\t\t\tfor (var I = Left + 1; I <= Right - 1; I++) {\n\t\t\t\tfor (var J = Top + 1; J <= Bottom - 1; J++) {\n\t\t\t\t\tvar P = new Dot(I, J);\n\n\t\t\t\t\tif (CanPlaceWater(P)) {\n\t\t\t\t\t\tPoints.Add(P);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Points;\n\t\t}\n\n\t\tpublic bool CanPlaceGrass(Dot P) {\n\t\t\treturn Inside(P);\n\t\t}\n\n\t\tpublic List<Dot> GetGrassPlaceablePoints() {\n\t\t\tvar Points = new List<Dot>();\n\n\t\t\tfor (var I = Left + 1; I <= Right - 1; I++) {\n\t\t\t\tfor (var J = Top + 1; J <= Bottom - 1; J++) {\n\t\t\t\t\tvar P = new Dot(I, J);\n\n\t\t\t\t\tif (CanPlaceGrass(P)) {\n\t\t\t\t\t\tPoints.Add(P);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Points;\n\t\t}\n\t\t\n\t\tpublic List<Dot> GetPassablePoints(Level level) {\n\t\t\tvar Points = new List<Dot>();\n\n\t\t\tfor (var I = Left + 1; I <= Right - 1; I++) {\n\t\t\t\tfor (var J = Top + 1; J <= Bottom - 1; J++) {\n\t\t\t\t\tif (level.IsPassable(I, J)) {\n\t\t\t\t\t\tPoints.Add(new Dot(I, J));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Points;\n\t\t}\n\n\t\tpublic override int GetWidth() {\n\t\t\treturn base.GetWidth() + 1;\n\t\t}\n\n\t\tpublic override int GetHeight() {\n\t\t\treturn base.GetHeight() + 1;\n\t\t}\n\n\t\tpublic Dot GetCenter() {\n\t\t\treturn new Dot(Left + GetWidth() / 2, Top + GetHeight() / 2);\n\t\t}\n\n\t\tpublic Dot GetTileCenter() {\n\t\t\treturn new Dot(Left + (int) (GetWidth() / 2f), Top + (int) (GetHeight() / 2f));\n\t\t}\n\t\t\n\t\tpublic Vector2 GetCenterVector() {\n\t\t\treturn new Vector2((Left + GetWidth() / 2f) * 16, (Top + GetHeight() / 2f) * 16);\n\t\t}\n\t\t\n\t\tpublic Rect GetCenterRect() {\n\t\t\tvar x = (int) (Left + GetWidth() / 2f); \n\t\t\tvar y = (int) (Top + GetHeight() / 2f);\n\t\t\treturn new Rect(x, y, x + 1, y + 1);\n\t\t}\n\n\t\tpublic virtual Rect GetConnectionSpace() {\n\t\t\tvar C = GetDoorCenter();\n\t\t\treturn new Rect(C.X, C.Y, C.X, C.Y);\n\t\t}\n\n\t\tprotected Dot GetDoorCenter() {\n\t\t\tvar DoorCenter = new Dot(0, 0);\n\n\t\t\tforeach (var Door in Connected.Values) {\n\t\t\t\tDoorCenter.X += Door.X;\n\t\t\t\tDoorCenter.Y += Door.Y;\n\t\t\t}\n\n\t\t\tvar N = Connected.Count;\n\t\t\tvar C = new Dot(DoorCenter.X / N, DoorCenter.Y / N);\n\n\t\t\tif (Rnd.Float() < DoorCenter.X % 1) {\n\t\t\t\tC.X++;\n\t\t\t}\n\n\t\t\tif (Rnd.Float() < DoorCenter.Y % 1) {\n\t\t\t\tC.Y++;\n\t\t\t}\n\n\t\t\tC.X = (int) MathUtils.Clamp(Left + 1, Right - 1, C.X);\n\t\t\tC.Y = (int) MathUtils.Clamp(Top + 1, Bottom - 1, C.Y);\n\n\t\t\treturn C;\n\t\t}\n\n\t\tpublic void PaintTunnel(Level Level, Tile Floor, Rect space = null, bool Bold = false, bool shift = true, bool randomRect = true, RoomDef defTo = null, DoorPlaceholder to = null) {\n\t\t\tif (Connected.Count == 0) {\n\t\t\t\tLog.Error(\"Invalid connection room\");\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar C = space ?? GetConnectionSpace();\n\t\t\tvar minLeft = C.Left;\n\t\t\tvar maxRight = C.Right;\n\t\t\tvar minTop = C.Top;\n\t\t\tvar maxBottom = C.Bottom;\n\n\t\t\tvar doors = to == null\n\t\t\t\t? Connected\n\t\t\t\t: new Dictionary<RoomDef, DoorPlaceholder>() {\n\t\t\t\t\t{ defTo, to }\n\t\t\t\t};\n\n\t\t\tforeach (var pair in doors) {\n\t\t\t\tif (pair.Key is GrannyRoom || pair.Key is OldManRoom) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar Door = pair.Value;\n\t\t\t\tvar Start = new Dot(Door.X, Door.Y);\n\t\t\t\tDot Mid;\n\t\t\t\tDot End;\n\n\t\t\t\tif (shift) {\n\t\t\t\t\tif ((int) Start.X == Left) {\n\t\t\t\t\t\tStart.X++;\n\t\t\t\t\t} else if ((int) Start.Y == Top) {\n\t\t\t\t\t\tStart.Y++;\n\t\t\t\t\t} else if ((int) Start.X == Right) {\n\t\t\t\t\t\tStart.X--;\n\t\t\t\t\t} else if ((int) Start.Y == Bottom) {\n\t\t\t\t\t\tStart.Y--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tint RightShift;\n\t\t\t\tint DownShift;\n\n\t\t\t\tif (Start.X < C.Left) {\n\t\t\t\t\tRightShift = (int) (C.Left - Start.X);\n\t\t\t\t} else if (Start.X > C.Right) {\n\t\t\t\t\tRightShift = (int) (C.Right - Start.X);\n\t\t\t\t} else {\n\t\t\t\t\tRightShift = 0;\n\t\t\t\t}\n\n\t\t\t\tif (Start.Y < C.Top) {\n\t\t\t\t\tDownShift = (int) (C.Top - Start.Y);\n\t\t\t\t} else if (Start.Y > C.Bottom) {\n\t\t\t\t\tDownShift = (int) (C.Bottom - Start.Y);\n\t\t\t\t} else {\n\t\t\t\t\tDownShift = 0;\n\t\t\t\t}\n\n\t\t\t\tif (Door.X == Left || Door.X == Right) {\n\t\t\t\t\tMid = new Dot(MathUtils.Clamp(Left + 1, Right - 1, Start.X + RightShift), MathUtils.Clamp(Top + 1, Bottom - 1, Start.Y));\n\t\t\t\t\tEnd = new Dot(MathUtils.Clamp(Left + 1, Right - 1, Mid.X), MathUtils.Clamp(Top + 1, Bottom - 1, Mid.Y + DownShift));\n\t\t\t\t} else {\n\t\t\t\t\tMid = new Dot(MathUtils.Clamp(Left + 1, Right - 1, Start.X), MathUtils.Clamp(Top + 1, Bottom - 1, Start.Y + DownShift));\n\t\t\t\t\tEnd = new Dot(MathUtils.Clamp(Left + 1, Right - 1, Mid.X + RightShift), MathUtils.Clamp(Top + 1, Bottom - 1, Mid.Y));\n\t\t\t\t}\n\n\t\t\t\tPainter.DrawLine(Level, Start, Mid, Floor, Bold);\n\t\t\t\tPainter.DrawLine(Level, Mid, End, Floor, Bold);\n\n\t\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\t\tPainter.Set(Level, End, Tiles.RandomFloor());\n\t\t\t\t}\n\n\t\t\t\tminLeft = Math.Min(minLeft, End.X);\n\t\t\t\tminTop = Math.Min(minTop, End.Y);\n\t\t\t\tmaxRight = Math.Max(maxRight, End.X);\n\t\t\t\tmaxBottom = Math.Max(maxBottom, End.Y);\n\t\t\t}\n\n\t\t\tif (randomRect && Rnd.Chance(20)) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tminLeft--;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tminTop--;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tmaxRight++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tmaxBottom++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tminLeft = MathUtils.Clamp(Left + 1, Right - 1, minLeft);\n\t\t\tminTop = MathUtils.Clamp(Top + 1, Bottom - 1, minTop);\n\t\t\tmaxRight = MathUtils.Clamp(Left + 1, Right - 1, maxRight);\n\t\t\tmaxBottom = MathUtils.Clamp(Top + 1, Bottom - 1, maxBottom);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloorOrSpike());\n\t\t\t} else {\n\t\t\t\tPainter.Rect(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloorOrSpike());\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual float WeightMob(MobInfo info, SpawnChance chance) {\n\t\t\treturn chance.Chance;\n\t\t}\n\n\t\tpublic virtual void ModifyMobList(List<MobInfo> infos) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool ShouldSpawnMobs() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static RoomType DecideType(RoomDef r, Type room) {\n\t\t\tif (typeof(TrapRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Trap;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(SubShopRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.SubShop;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(DarkMarketRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.DarkMarket;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(PayedRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Payed;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(ScourgedRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Scourged;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(ChallengeRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Challenge;\n\t\t\t}\n\n\t\t\tif (typeof(SpikedRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Spiked;\n\t\t\t}\n\n\t\t\tif (typeof(BossRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Boss;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(GrannyRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Granny;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(OldManRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.OldMan;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(EntranceRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Entrance;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(ExitRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Exit;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(SecretRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Secret;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(TreasureRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Treasure;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(ShopRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Shop;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(SpecialRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Special;\n\t\t\t}\n\t\t\t\n\t\t\tif (typeof(ConnectionRoom).IsAssignableFrom(room)) {\n\t\t\t\treturn RoomType.Connection;\n\t\t\t}\n\t\t\t\n\t\t\treturn RoomType.Regular;\n\t\t}\n\n\t\tpublic virtual void ModifyRoom(Room room) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool ConvertToEntity() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic virtual float GetWeightModifier() {\n\t\t\treturn 1f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/RoomInfo.cs",
    "content": "using System;\n\nnamespace BurningKnight.level.rooms {\n\tpublic class RoomInfo {\n\t\tpublic Type Room;\n\t\tpublic float Chance;\n\t\tpublic RoomType Type;\n\t\tpublic string[] Biomes;\n\t\tpublic Func<bool> CanAppear;\n\n\t\tpublic static RoomInfo New<T>(float chance, params string[] biomes) where T : RoomDef {\n\t\t\treturn New<T>(chance, null, biomes);\n\t\t}\n\n\t\tpublic static RoomInfo New<T>(float chance, Func<bool> callback, params string[] biomes) where T : RoomDef {\n\t\t\treturn new RoomInfo {\n\t\t\t\tChance = chance,\n\t\t\t\tCanAppear = callback,\n\t\t\t\tType = RoomDef.DecideType(null, typeof(T)),\n\t\t\t\tRoom = typeof(T),\n\t\t\t\tBiomes = biomes\n\t\t\t};\n\t\t}\n\t\t\n\t\tpublic static RoomInfo Typed<T>(RoomType type, float chance, params string[] biomes) where T : RoomDef {\n\t\t\treturn new RoomInfo {\n\t\t\t\tChance = chance,\n\t\t\t\tType = type,\n\t\t\t\tRoom = typeof(T),\n\t\t\t\tBiomes = biomes\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/RoomRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities.statue;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.connection;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.secret;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.level.rooms.shop.sub;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.rooms.special.minigame;\nusing BurningKnight.level.rooms.special.npc;\nusing BurningKnight.level.rooms.special.shop;\nusing BurningKnight.level.rooms.special.statue;\nusing BurningKnight.level.rooms.trap;\nusing BurningKnight.level.rooms.treasure;\nusing BurningKnight.level.walls;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms {\n\tpublic static class RoomRegistry {\n\t\tpublic static List<RoomInfo> All = new List<RoomInfo>();\n\t\tpublic static Dictionary<RoomType, List<RoomInfo>> ByType = new Dictionary<RoomType, List<RoomInfo>>();\n\n\t\tpublic static readonly RoomType[] TypesByIndex = {\n\t\t\tRoomType.Regular,\n\t\t\tRoomType.Secret,\n\t\t\tRoomType.Connection,\n\t\t\tRoomType.Boss,\n\t\t\tRoomType.Exit,\n\t\t\tRoomType.Special,\n\t\t\tRoomType.Shop,\n\t\t\tRoomType.Spiked,\n\t\t\tRoomType.Challenge,\n\t\t\tRoomType.Scourged,\n\t\t\tRoomType.Payed,\n\t\t\tRoomType.DarkMarket,\n\t\t\tRoomType.Treasure,\n\t\t\tRoomType.Entrance,\n\t\t\tRoomType.Trap,\n\t\t\tRoomType.Granny,\n\t\t\tRoomType.OldMan,\n\t\t\tRoomType.SubShop,\n\t\t\tRoomType.Hidden\n\t\t};\n\t\t\n\t\tpublic static readonly string[] Names = {\n\t\t\t\"Regular\",\n\t\t\t\"Secret\",\n\t\t\t\"Connection\",\n\t\t\t\"Boss\",\n\t\t\t\"Exit\",\n\t\t\t\"Special\",\n\t\t\t\"Shop\",\n\t\t\t\"Spiked\",\n\t\t\t\"Challenge\",\n\t\t\t\"Scourged\",\n\t\t\t\"Payed\",\n\t\t\t\"DarkMarket\",\n\t\t\t\"Treasure\",\n\t\t\t\"Entrance\",\n\t\t\t\"Trap\",\n\t\t\t\"Granny\",\n\t\t\t\"OldMan\",\n\t\t\t\"SubShop\",\n\t\t\t\"Hidden\"\n\t\t};\n\t\t\n\t\tpublic static RoomType FromIndex(int i) {\n\t\t\treturn TypesByIndex[i];\n\t\t}\n\n\t\tpublic static int FromType(RoomType type) {\n\t\t\tfor (var i = 0; i < TypesByIndex.Length; i++) {\n\t\t\t\tif (TypesByIndex[i] == type) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\t\t\n\t\tstatic RoomRegistry() {\n\t\t\tRoomInfo[] infos = {\n\t\t\t\t// Secret\n\t\t\t\tRoomInfo.New<SecretMachineRoom>(1f),\n\t\t\t\tRoomInfo.New<SecretChasmRoom>(1f),\n\t\t\t\tRoomInfo.New<SecretItemRoom>(1f),\n\t\t\t\tRoomInfo.New<GrannySecretRoom>(0.01f),\n\t\t\t\tRoomInfo.New<SecretChestRoom>(1f),\n\t\t\t\tRoomInfo.New<SecretScourgeRoom>(0.3f),\n\t\t\t\tRoomInfo.New<BirdSecretRoom>(0.01f),\n\t\t\t\tRoomInfo.New<SecretEmeraldGolemRoom>(0.3f),\n\n\t\t\t\t// Regular\n\t\t\t\tRoomInfo.New<RegularRoom>(WallRegistry.Instance.Size),\n\t\t\t\tRoomInfo.New<VerticalRegularRoom>(WallRegistry.Instance.Size),\n\t\t\t\tRoomInfo.New<ItemTrollRoom>(0.2f),\n\t\t\t\t\n\t\t\t\t// Desert only room designs\n\t\t\t\tRoomInfo.New<PlatformLineRoom>(4f, Biome.Desert),\n\t\t\t\tRoomInfo.New<TwoSidesRoom>(4f, Biome.Desert),\n\t\t\t\tRoomInfo.New<PlatformRingRoom>(4f, Biome.Desert),\n\t\t\t\t// RoomInfo.New<PlatformChaosRoom>(1f + 100f, Biome.Desert),\n\n\t\t\t\t// Entrance\n\t\t\t\tRoomInfo.New<EntranceRoom>(1f),\n\t\t\t\t\n\t\t\t\t// Exit\n\t\t\t\tRoomInfo.Typed<EntranceRoom>(RoomType.Exit, 1f),\n\t\t\t\t\n\t\t\t\t// Treasure\n\t\t\t\tRoomInfo.New<HoleTreasureRoom>(1f), // 4 stands\n\t\t\t\tRoomInfo.New<PlatformTreasureRoom>(0.8f), // 2-4 stands\n\t\t\t\tRoomInfo.New<PadTreasureRoom>(2f), // 4 stands\n\t\t\t\tRoomInfo.New<TwoDiagonalTreasureRoom>(0.5f), // 2 stands\n\t\t\t\tRoomInfo.New<AcrossTreasureRoom>(3f), // 2-5 stands\n\t\t\t\t\n\t\t\t\t// Trap\n\t\t\t\tRoomInfo.New<RollingSpikesRoom>(1f),\n\t\t\t\tRoomInfo.New<SpikePassageRoom>(1f),\n\t\t\t\tRoomInfo.New<TurretTrapRoom>(1f),\n\t\t\t\tRoomInfo.New<SpikeMazeRoom>(1f),\n\t\t\t\tRoomInfo.New<DangerousPadsRoom>(1f),\n\t\t\t\tRoomInfo.New<TurretPassageRoom>(1f),\n\t\t\t\tRoomInfo.New<VerticalTurretPassageRoom>(1f),\n\t\t\t\tRoomInfo.New<CrossTurretPassageRoom>(1f),\n\t\t\t\tRoomInfo.New<FollowingSpikeBallRoom>(1f),\n\n\t\t\t\t// Shop\n\t\t\t\tRoomInfo.New<ShopRoom>(1f),\n\t\t\t\t\n\t\t\t\t// Sub shop\n\t\t\t\tRoomInfo.New<ProtoShopRoom>(0.2f),\n\t\t\t\tRoomInfo.New<StorageRoom>(1f),\n\t\t\t\tRoomInfo.New<SnekShopRoom>(1f, () => GlobalSave.IsTrue(ShopNpc.Snek)),\n\t\t\t\tRoomInfo.New<VampireShopRoom>(1f, () => GlobalSave.IsTrue(ShopNpc.Vampire)),\n\t\t\t\t\n\t\t\t\t// Connection\n\t\t\t\tRoomInfo.New<CabbadgeConnectionRoom>(0.05f),\n\t\t\t\tRoomInfo.New<TunnelRoom>(4f),\n\t\t\t\tRoomInfo.New<ComplexTunnelRoom>(1f),\n\t\t\t\tRoomInfo.New<MazeConnectionRoom>(0.2f),\n\t\t\t\tRoomInfo.New<RingConnectionRoom>(1f),\n\t\t\t\tRoomInfo.New<IntersectionConnectionRoom>(0.5f),\n\t\t\t\tRoomInfo.New<HoleConnectionRoom>(0.3f),\n\t\t\t\t\n\t\t\t\t// Special\n\t\t\t\tRoomInfo.New<IdolTrapRoom>(1f),\n\t\t\t\tRoomInfo.New<HeartRoom>(4f, Biome.Desert, Biome.Ice, Biome.Library),\n\t\t\t\tRoomInfo.New<SafeRoom>(1f),\n\t\t\t\tRoomInfo.New<ChargerRoom>(1f),\n\t\t\t\tRoomInfo.New<ChestMinigameRoom>(1f),\n\t\t\t\tRoomInfo.New<VendingRoom>(1f),\n\t\t\t\t\n\t\t\t\tRoomInfo.New<ChestStatueRoom>(0.8f),\n\t\t\t\tRoomInfo.New<FountainRoom>(1f),\n\t\t\t\tRoomInfo.New<DiceStatueRoom>(1f),\n\t\t\t\tRoomInfo.New<ScourgeStatueRoom>(0.5f),\n\t\t\t\tRoomInfo.New<StoneStatueRoom>(1f),\n\t\t\t\tRoomInfo.New<SwordStatueRoom>(1f),\n\t\t\t\tRoomInfo.New<WarriorStatueRoom>(1f),\n\t\t\t\tRoomInfo.New<WellRoom>(0.3f),\n\t\t\t\tRoomInfo.New<ProtoChestRoom>(0.1f),\n\t\t\t\t\n\t\t\t\tRoomInfo.New<RogerShopRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Roger)),\n\t\t\t\tRoomInfo.New<BoxyShopRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Boxy)),\n\t\t\t\tRoomInfo.New<TrashGoblinRoom>(1f),\n\t\t\t\tRoomInfo.New<DuckRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Duck)),\n\t\t\t\tRoomInfo.New<NurseRoom>(1f, () => GlobalSave.IsTrue(ShopNpc.Nurse)),\n\t\t\t\tRoomInfo.New<ElonRoom>(1f, () => GlobalSave.IsTrue(ShopNpc.Elon)),\n\t\t\t\tRoomInfo.New<GobettaShopRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Gobetta)),\n\t\t\t\tRoomInfo.New<SnekRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Snek)),\n\t\t\t\tRoomInfo.New<VampireRoom>(1f, () => Run.Loop == 0 && GlobalSave.IsTrue(ShopNpc.Vampire)),\n\n\t\t\t\t// Boss\n\t\t\t\tRoomInfo.New<CollumnsBossRoom>(1f, Biome.Castle),\n\t\t\t\tRoomInfo.New<BossRoom>(1f, Biome.Jungle, Biome.Ice, Biome.Library, Biome.Tech),\n\t\t\t\tRoomInfo.New<ChasmBossRoom>(1f, Biome.Desert),\n\t\t\t\t\n\t\t\t\t// Granny\n\t\t\t\tRoomInfo.New<GrannyRoom>(1f),\n\t\t\t\t\n\t\t\t\t// Old Man\n\t\t\t\tRoomInfo.New<OldManRoom>(1f),\n\t\t\t};\n\n\t\t\tforeach (var info in infos) {\n\t\t\t\tAdd(info);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Add(RoomInfo info) {\n\t\t\tAll.Add(info);\n\n\t\t\tif (ByType.TryGetValue(info.Type, out var rooms)) {\n\t\t\t\trooms.Add(info);\n\t\t\t} else {\n\t\t\t\trooms = new List<RoomInfo>();\n\t\t\t\trooms.Add(info);\n\t\t\t\t\n\t\t\t\tByType[info.Type] = rooms;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Remove(RoomInfo info) {\n\t\t\tAll.Remove(info);\n\t\t\tByType[info.Type].Remove(info);\n\t\t}\n\n\t\tpublic static RoomDef Generate(RoomType type, Biome biome) {\n\t\t\tif (biome is IceBiome && type == RoomType.Connection && Run.Type != RunType.BossRush) {\n\t\t\t\treturn new IceConnectionRoom();\n\t\t\t}\n\t\t\t\n\t\t\tif (!ByType.TryGetValue(type, out var types)) {\n\t\t\t\tLog.Error($\"No rooms registered with type {type}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar list = new List<RoomInfo>();\n\t\t\tfloat sum = 0;\n\n\t\t\tforeach (var t in types) {\n\t\t\t\tif (biome.IsPresent(t.Biomes) && (t.CanAppear == null || t.CanAppear())) {\n\t\t\t\t\tsum += t.Chance;\n\t\t\t\t\tlist.Add(t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar length = list.Count;\n\n\t\t\tfloat value = Rnd.Float(sum);\n\t\t\tsum = 0;\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tvar t = list[i];\n\t\t\t\tsum += t.Chance;\n\n\t\t\t\tif (value < sum) {\n\t\t\t\t\treturn (RoomDef) Activator.CreateInstance(t.Room);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tLog.Error($\"Failed to generate a room with type {type}\");\n\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/RoomType.cs",
    "content": "namespace BurningKnight.level.rooms {\n\t// Keep in sync with RoomRegistry::byIndex and RoomRegistry::names!!\n\tpublic enum RoomType {\n\t\tRegular,\n\t\tSecret,\n\t\tConnection,\n\t\tBoss,\n\t\tExit,\n\t\tSpecial,\n\t\tShop,\n\t\tSpiked,\n\t\tChallenge,\n\t\tScourged,\n\t\tPayed,\n\t\tDarkMarket,\n\t\tTreasure,\n\t\tEntrance,\n\t\tTrap,\n\t\tGranny,\n\t\tOldMan,\n\t\tSubShop,\n\t\tHidden\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/RoomTypeHelper.cs",
    "content": "using BurningKnight.assets;\nusing Lens.graphics;\n\nnamespace BurningKnight.level.rooms {\n\tpublic static class RoomTypeHelper {\n\t\tpublic static TextureRegion[] Icons;\n\n\t\tstatic RoomTypeHelper() {\n\t\t\tIcons = new TextureRegion[(int) RoomType.Hidden + 1];\n\t\t\t\n\t\t\tLoadIcon(RoomType.Shop, \"shop\");\n\t\t\tLoadIcon(RoomType.Secret, \"secret\");\n\t\t\tLoadIcon(RoomType.Boss, \"boss\");\n\t\t\tLoadIcon(RoomType.Exit, \"exit\");\n\t\t\tLoadIcon(RoomType.Entrance, \"entrance\");\n\t\t\tLoadIcon(RoomType.Challenge, \"challenge\");\n\t\t\tLoadIcon(RoomType.Spiked, \"spiked\");\n\t\t\tLoadIcon(RoomType.Scourged, \"scourged\");\n\t\t\tLoadIcon(RoomType.Treasure, \"treasure\");\n\t\t}\n\n\t\tprivate static void LoadIcon(RoomType type, string id) {\n\t\t\tIcons[(int) type] = CommonAse.Ui.GetSlice(id);\n\t\t}\n\t\t\n\t\tpublic static bool ShouldBeDisplayOnMap(RoomType type) {\n\t\t\treturn type == RoomType.Shop || type == RoomType.Secret || type == RoomType.Boss || type == RoomType.Exit ||\n\t\t\t       type == RoomType.Entrance || type == RoomType.Challenge || type == RoomType.Spiked ||\n\t\t\t       type == RoomType.Scourged || type == RoomType.Treasure;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/boss/BossRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.creature.bk;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.rooms.granny;\nusing BurningKnight.level.rooms.oldman;\nusing BurningKnight.level.rooms.preboss;\nusing BurningKnight.level.rooms.shop;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.boss {\n\tpublic class BossRoom : RoomDef {\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn Display.Width / 16;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn Display.Width / 16;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn Display.Width / 16 + 1;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn Display.Width / 16 + 1;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\treturn Run.Depth >= 10 ? 1 : 3;\n\t\t}\n\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\tif (R is GrannyRoom || R is OldManRoom || R is PrebossRoom || R is ShopRoom) {\n\t\t\t\treturn base.CanConnect(R);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (R is PrebossRoom) {\n\t\t\t\tvar x = (int) P.X;\n\t\t\t\tvar y = (int) P.Y;\n\n\t\t\t\tif ((x == Left || x == Right)) { // && y != Top + GetHeight() / 2) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif ((y == Bottom || y == Top) && x != Left + GetWidth() / 2) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar t = Tiles.RandomFloor();\n\t\t\t\n\t\t\tPainter.Call(level, this, 1, (x, y) => {\n\t\t\t\tif (level.Get(x, y).Matches(Tile.SpikeOffTmp, Tile.SensingSpikeTmp)) {\n\t\t\t\t\tlevel.Set(x, y, t);\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tPaintRoom(level);\n\n\t\t\tif (LevelSave.BiomeGenerated is LibraryBiome && !BK.Version.Dev) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar boss = BossRegistry.Generate();\n\n\t\t\tif (boss == null) {\n\t\t\t\tif (BK.Version.Dev) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar exit = new Exit();\n\t\t\t\tlevel.Area.Add(exit);\n\t\t\t\texit.Center = GetCenterVector();\n\n\t\t\t\tLog.Error(\"Failed to generate the boss!\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlevel.Area.Add(boss);\n\t\t\tboss.Center = GetCenterVector();\n\n\t\t\t/*var trigger = new SpawnTrigger();\n\t\t\tvar w = GetWidth() - 2;\n\t\t\tvar h = GetHeight() - 2;\n\t\t\tvar s = w * h;\n\t\t\t\n\t\t\ttrigger.Tiles = new byte[s];\n\t\t\ttrigger.Liquid = new byte[s];\n\t\t\ttrigger.RoomX = (ushort) (Left + 1);\n\t\t\ttrigger.RoomY = (ushort) (Top + 1);\n\t\t\ttrigger.RoomWidth = (byte) w;\n\t\t\ttrigger.RoomHeight = (byte) h;\n\n\t\t\tfor (var y = 0; y < h; y++) {\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tvar li = level.ToIndex(Left + 1 + x, Top + 1 + y);\n\t\t\t\t\tvar i = x + y * w;\n\n\t\t\t\t\ttrigger.Tiles[i] = level.Tiles[li];\n\t\t\t\t\ttrigger.Liquid[i] = level.Liquid[li];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, this, 1, Tile.WallA);\n\n\t\t\tvar c = GetCenterRect();\n\t\t\tc.Resize(1, 1);\n\t\t\t\n\t\t\tPainter.Fill(level, c, -3, Tiles.RandomFloor());\n\t\t\tPaintTunnel(level, Tile.FloorD, c);\n\t\t\tPainter.Fill(level, c, -2, Tiles.RandomFloor());\n\n\t\t\tvar x = (c.Left - 2) * 16;\n\t\t\tvar y = (c.Top - 2) * 16;\n\t\t\t\n\t\t\tvar ta = new Torch();\n\t\t\tlevel.Area.Add(ta);\n\t\t\tta.CenterX = x + 8;\n\t\t\tta.Bottom = y + 12;\n\t\t\t\n\t\t\tta = new Torch();\n\t\t\tlevel.Area.Add(ta);\n\t\t\tta.CenterX = x + 4 * 16 + 8;\n\t\t\tta.Bottom = y + 12;\n\t\t\t\n\t\t\tta = new Torch();\n\t\t\tlevel.Area.Add(ta);\n\t\t\tta.CenterX = x + 8;\n\t\t\tta.Bottom = y + 4 * 16 + 12;\n\n\t\t\tta = new Torch();\n\t\t\tlevel.Area.Add(ta);\n\t\t\tta.CenterX = x + 4 * 16 + 8;\n\t\t\tta.Bottom = y + 4 * 16 + 12;\n\n\t\t\tvar st = new BkStand();\n\t\t\tlevel.Area.Add(st);\n\n\t\t\tst.CenterX = c.Left * 16 + 8;\n\t\t\tst.CenterY = c.Top * 16 + 8;\n\t\t\tst.SetItem(Items.CreateAndAdd(\"bk:the_key\", level.Area), null);\n\n\t\t\tPainter.Fill(level, c, -2, Tile.FloorD);\n\t\t\tPainter.Fill(level, c, -1, Tiles.RandomFloor());*/\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\td.Type = DoorPlaceholder.Variant.Boss;\n\t\t\t}\n\t\t}\n\n\t\tpublic override Rect GetConnectionSpace() {\n\t\t\treturn GetCenterRect();\n\t\t}\n\t\t\n\t\tprotected virtual void PaintRoom(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:boss_room\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/boss/ChasmBossRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.boss {\n\tpublic class ChasmBossRoom : BossRoom {\n\t\tprotected override void PaintRoom(Level level) {\n\t\t\tvar m = 1;\n\t\t\t\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Fill(level, this, m, Tile.Chasm);\n\n\t\t\tm += Rnd.Int(0, 2);\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.FillEllipse(level, this, m, Tiles.RandomFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, this, m, Tiles.RandomFloor());\n\t\t\t}\n\n\t\t\tm++;\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.FillEllipse(level, this, m, Tiles.RandomNewFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, this, m, Tiles.RandomNewFloor());\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect(), true);\n\t\t\t}\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn Display.Width / 16 - 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn Display.Width / 16 - 3;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn Display.Width / 16 - 5;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn Display.Width / 16 - 2;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/boss/CollumnsBossRoom.cs",
    "content": "using System;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.boss {\n\tpublic class CollumnsBossRoom : BossRoom {\n\t\tprotected override void PaintRoom(Level level) {\n\t\t\tvar minDim = Math.Min(GetWidth(), GetHeight());\n\t\t\tvar circ = Rnd.Chance();\n\n\t\t\tvar left = Left;\n\t\t\tvar top = Top;\n\t\t\tvar right = Right;\n\t\t\tvar bottom = Bottom;\n\n\t\t\tvar a = Tile.WallA;\n\t\t\tvar b = a;\n\t\t\tvar af = Tiles.Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD);\n\t\t\tvar bf = Rnd.Chance() ? af : Tiles.Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD);\n\t\t\t\n\t\t\tvar o = Rnd.Chance();\n\t\t\tint pillarInset = Rnd.Int(1, 3);\n\t\t\tint pillarSize = 2;\n\n\t\t\tint pillarX, pillarY;\n\n\t\t\tif (Rnd.Int(2) == 0) {\n\t\t\t\tpillarX = Rnd.Int(left + 1 + pillarInset, right - pillarSize - pillarInset);\n\t\t\t\tpillarY = top + 1 + pillarInset;\n\t\t\t} else {\n\t\t\t\tpillarX = left + 1 + pillarInset;\n\t\t\t\tpillarY = Rnd.Int(top + 1 + pillarInset, bottom - pillarSize - pillarInset);\n\t\t\t}\n\n\t\t\tif (circ) {\n\t\t\t\tif (o) {\n\t\t\t\t\tPainter.FillEllipse(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, af);\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\tPainter.FillEllipse(level, pillarX, pillarY, pillarSize, pillarSize, a);\n\t\t\t} else {\n\t\t\t\tif (o) {\n\t\t\t\t\tPainter.Fill(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, af);\n\t\t\t\t}\n\n\t\t\t\tPainter.Fill(level, pillarX, pillarY, pillarSize, pillarSize, a);\n\t\t\t}\n\n\t\t\tpillarX = right - (pillarX - left + pillarSize - 1);\n\t\t\tpillarY = bottom - (pillarY - top + pillarSize - 1);\n\n\t\t\tif (circ) {\n\t\t\t\tif (o) {\n\t\t\t\t\tPainter.FillEllipse(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, bf);\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\tPainter.FillEllipse(level, pillarX, pillarY, pillarSize, pillarSize, b);\n\t\t\t} else {\n\t\t\t\tif (o) {\n\t\t\t\t\tPainter.Fill(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, bf);\n\t\t\t\t}\n\n\t\t\t\tPainter.Fill(level, pillarX, pillarY, pillarSize, pillarSize, b);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/boss/FireTrapBossRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.boss {\n\tpublic class FireTrapBossRoom : BossRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tprotected override void PaintRoom(Level level) {\n\t\t\tPainter.Fill(level, this, 1, Tile.FireTrapTmp);\n\n\t\t\tvar w = GetWidth();\n\t\t\tvar a = Tiles.RandomFloor();\n\t\t\tvar b = Rnd.Chance() ? a : Tiles.RandomNewFloor(); \n\t\t\tvar collumnSize = (int) (w / 6f);\n\t\t\t\n\t\t\tPainter.Fill(level, Left + w / 4 - collumnSize, Top + w / 4 - collumnSize, collumnSize * 2, collumnSize * 2, a);\n\t\t\tPainter.Fill(level, Right - w / 4 - collumnSize, Top + w / 4 - collumnSize, collumnSize * 2, collumnSize * 2, b);\n\t\t\tPainter.Fill(level, Left + w / 4 - collumnSize, Bottom - w / 4 - collumnSize, collumnSize * 2, collumnSize * 2, b);\n\t\t\tPainter.Fill(level, Right - w / 4 - collumnSize, Bottom - w / 4 - collumnSize, collumnSize * 2, collumnSize * 2, a);\n\n\t\t\tvar c = GetCenter();\n\t\t\t\n\t\t\tPainter.Fill(level, c.X - 1, c.Y - 1, 3, 3, Tiles.RandomNewFloor());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/challenge/ChallengeRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended.Collections;\n\nnamespace BurningKnight.level.rooms.challenge {\n\tpublic class ChallengeRoom : SpecialRoom {\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Challenge;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (LevelSave.BiomeGenerated is IceBiome) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tvar center = GetCenter() * 16 + new Vector2(8);\n\t\t\t\n\t\t\tif (Rnd.Chance(20)) {\n\t\t\t\tvar stand = new ItemStand();\n\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\tstand.Center = center;\n\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Treasure), level.Area), null);\n\t\t\t} else {\n\t\t\t\tvar chests = new List<Chest>();\n\t\t\t\tvar i = Rnd.Int(4);\n\n\t\t\t\tswitch (i) {\n\t\t\t\t\tcase 0: {\n\t\t\t\t\t\tfor (var k = 0; k < 2; k++) {\n\t\t\t\t\t\t\tchests.Add(new RedChest());\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 1: {\n\t\t\t\t\t\tfor (var k = 0; k < 4; k++) {\n\t\t\t\t\t\t\tchests.Add(new GoldChest());\t\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 2: {\n\t\t\t\t\t\tfor (var k = 0; k < 3; k++) {\n\t\t\t\t\t\t\tchests.Add(new WoodenChest());\t\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tchests.Add(new GoldChest());\t\n\t\t\t\t\t\tchests.Add(new WoodenChest());\t\n\t\t\t\t\t\tchests.Add(new RedChest());\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tchests.Shuffle(Rnd.Generator);\n\t\t\t\t\n\t\t\t\tvar j = 0;\n\t\t\t\tvar cn = chests.Count;\n\t\t\t\t\n\t\t\t\tforeach (var c in chests) {\n\t\t\t\t\tlevel.Area.Add(c);\n\t\t\t\t\tc.Center = center + new Vector2((j - cn / 2f) * 16, 0);\n\t\t\t\t\t\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:challenge\");\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 21;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 21;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/CabbadgeConnectionRoom.cs",
    "content": "using BurningKnight.level.entities.plant;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class CabbadgeConnectionRoom : ConnectionRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar skip = 2;\n\t\t\t\n\t\t\tPainter.Fill(level, this, 1, Tiles.RandomFloor());\n\t\t\tvar f = Rnd.Chance() ? Tiles.RandomNewFloor() : Tile.Dirt;\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tfor (var x = Left + 1; x < Right - 1; x += skip) {\n\t\t\t\t\tPainter.DrawLine(level, new Dot(x, Top + 1), new Dot(x, Bottom - 1), f);\n\t\t\t\t\t\n\t\t\t\t\tfor (var y = Top + 1; y < Bottom; y++) {\n\t\t\t\t\t\tvar p = new Plant();\n\t\t\t\t\t\tlevel.Area.Add(p);\n\t\t\t\t\t\tp.Variant = 255; // Cabbadge\n\t\t\t\t\t\tp.Position = new Vector2(x * 16 + 1, y * 16 - 2) + Rnd.Vector(-2, 2);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (var y = Top + 1; y < Bottom - 1; y += skip) {\n\t\t\t\t\tPainter.DrawLine(level, new Dot(Left + 1, y), new Dot(Right - 1, y), f);\n\t\t\t\t\t\n\t\t\t\t\tfor (var x = Left + 1; x < Right; x++) {\n\t\t\t\t\t\tvar p = new Plant();\n\t\t\t\t\t\tlevel.Area.Add(p);\n\t\t\t\t\t\tp.Variant = 255; // Cabbadge\n\t\t\t\t\t\tp.Position = new Vector2(x * 16 + 1, y * 16 - 2) + Rnd.Vector(-2, 2);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 13;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/ComplexTunnelRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class ComplexTunnelRoom : ConnectionRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar fl = Rnd.Chance() ? Tiles.RandomFloorOrSpike() : Tiles.RandomSolid();\n\t\t\tvar w = GenerateSpot();\n\t\t\t\n\t\t\tPaintTunnel(level, fl, w, true);\n\n\t\t\tif (fl == Tile.Lava) {\n\t\t\t\tPaintTunnel(level, Tiles.RandomFloorOrSpike(), w);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPaintTunnel(level, Tiles.RandomFloorOrSpike(), w, true);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPaintTunnel(level, fl.Matches(Tile.Dirt, Tile.Lava) ? Rnd.Chance() ? \n\t\t\t\t\tTile.Water : Tile.Dirt : Tiles.RandomFloorOrSpike(), GenerateSpot());\n\t\t\t}\n\t\t\t\n\t\t\tPaintTunnel(level, fl.Matches(Tile.Dirt, Tile.Lava) ? Rnd.Chance() ? \n\t\t\t\tTile.Water : Tile.Dirt : Tiles.RandomFloorOrSpike(), w);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/ConnectionRoom.cs",
    "content": "using BurningKnight.entity.room.controllable.spikes;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class ConnectionRoom : RoomDef {\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 3;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 3;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 10;\n\t\t}\n\t\t\n\t\tprotected Rect GenerateSpot(bool noGetConnectionSpace = false) {\n\t\t\tif (noGetConnectionSpace) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\treturn GetCenterRect();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar r = Rnd.Float();\n\n\t\t\t\tif (r < 0.33f) {\n\t\t\t\t\treturn GetConnectionSpace();\n\t\t\t\t} else if (r < 0.66f) {\n\t\t\t\t\treturn GetCenterRect();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new Rect(new Dot(Rnd.Int(Left + 2, Right - 2), Rnd.Int(Top + 2, Bottom - 2)));\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 16;\n\t\t\treturn 4;\n\t\t}\n\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 2;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tif (level.GetFilling() == Tile.Chasm) {\n\t\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Empty;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbase.SetupDoors(level);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/HoleConnectionRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class HoleConnectionRoom : ConnectionRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Fill(level, this, 1, Tiles.RandomFloorOrSpike());\n\t\t\tPainter.Fill(level, Left + 2, Top + 2, GetWidth() - 4, GetHeight() - 4, Tiles.RandomSolid());\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/IceConnectionRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class IceConnectionRoom : ConnectionRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar old = Painter.Clip;\n\t\t\t\n\t\t\tPainter.Clip = null;\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Clip = old;\n\t\t\t\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tvar sx = Rnd.Int(3, 7);\n\t\t\t\tvar sy = Rnd.Int(3, 7);\n\t\t\t\tPainter.FillEllipse(level, door.X - sx / 2, door.Y - sy / 2, sx, sy, Tiles.RandomFloor());\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Empty;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 22;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/IntersectionConnectionRoom.cs",
    "content": "using BurningKnight.level.tile;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.connection {\r\n\tpublic class IntersectionConnectionRoom : ConnectionRoom {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Fill(level, this, Tile.WallA);\r\n\t\t\tPainter.Fill(level, this, 1, Tiles.RandomSolid());\r\n\r\n\t\t\tvar b = Rnd.Chance();\r\n\t\t\tvar a = Rnd.Chance();\r\n\r\n\t\t\tvar left = false;\r\n\t\t\tvar right = false;\r\n\t\t\tvar top = false;\r\n\t\t\tvar bottom = false;\r\n\r\n\t\t\tforeach (var d in Connected.Values) {\r\n\t\t\t\tDot to;\r\n\t\t\t\tDot from;\r\n\r\n\t\t\t\tif (d.X == Left) {\r\n\t\t\t\t\tleft = true;\r\n\t\t\t\t\tto = new Dot(Right - 1, d.Y);\r\n\t\t\t\t\tfrom = new Dot(d.X + 1, d.Y);\r\n\t\t\t\t} else if (d.X == Right) {\r\n\t\t\t\t\tright = true;\r\n\t\t\t\t\tto = new Dot(Left + 1, d.Y);\r\n\t\t\t\t\tfrom = new Dot(d.X - 1, d.Y);\r\n\t\t\t\t} else if (d.Y == Top) {\r\n\t\t\t\t\ttop = true;\r\n\t\t\t\t\tto = new Dot(d.X, Bottom - 1);\r\n\t\t\t\t\tfrom = new Dot(d.X, d.Y + 1);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tbottom = true;\r\n\t\t\t\t\tto = new Dot(d.X, Top + 1);\r\n\t\t\t\t\tfrom = new Dot(d.X, d.Y - 1);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tPainter.DrawLine(level, from, to, Tiles.RandomFloor(), b && (a || Rnd.Chance()));\r\n\t\t\t}\r\n\r\n\t\t\tif ((right || left) && !(bottom || top)) {\r\n\t\t\t\tvar x = Rnd.Int(Left + 1, Right - 1);\r\n\t\t\t\tPainter.DrawLine(level, new Dot(x, Top + 1), new Dot(x, Bottom - 1), Tile.FloorD, b && (a || Rnd.Chance()));\r\n\t\t\t} else if ((top || bottom) && !(left || right)) {\r\n\t\t\t\tvar y = Rnd.Int(Top + 1, Bottom - 1);\r\n\t\t\t\tPainter.DrawLine(level, new Dot(Left + 1, y), new Dot(Right - 1, y), Tile.FloorD, b && (a || Rnd.Chance()));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 5;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 5;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/LibraryConnectionRoom.cs",
    "content": "using System.Linq;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class LibraryConnectionRoom : ConnectionRoom {\n\t\tpublic bool BottomHalf;\n\t\tprivate bool doorZero;\n\t\t\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar old = Painter.Clip;\n\t\t\t\n\t\t\tPainter.Clip = null;\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Clip = old;\n\n\t\t\tvar doors = Connected.Values.ToArray();\n\t\t\tvar rooms = Connected.Keys.ToArray();\n\t\t\tvar spot = doorZero ? doors[0] : doors[1];\n\n\t\t\tvar dot = new Dot(spot.X, spot.Y);\n\t\t\t\n\t\t\tif (dot.X == Left) {\n\t\t\t\tdot.X += 4;\n\t\t\t} else if (dot.Y == Top) {\n\t\t\t\tdot.Y += 4;\n\t\t\t} else if (dot.X == Right) {\n\t\t\t\tdot.X -= 4;\n\t\t\t} else if (dot.Y == Bottom) {\n\t\t\t\tdot.Y -= 4;\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, dot.X - 2, dot.Y - 2, 5, 5, Tiles.RandomFloor());\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\t\t\tPainter.Set(level, dot.X, dot.Y, Tile.FloorD);\n\n\t\t\tvar t = new Teleporter {\n\t\t\t\tId = \"a\"\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(t);\n\t\t\tt.Position = dot * 16;\n\t\t}\n\n\t\tprivate bool InvestigateDoor(RoomDef room, DoorPlaceholder cameFrom) {\n\t\t\tif (room is LibraryConnectionRoom && room != this) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var door in room.Connected) {\n\t\t\t\tif (door.Value != cameFrom) {\n\t\t\t\t\treturn InvestigateDoor(door.Key, door.Value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tvar pair = Connected.First();\n\t\t\tvar doors = Connected.Values.ToArray();\n\n\t\t\tdoorZero = !BottomHalf || InvestigateDoor(pair.Key, pair.Value);\n\t\t\t\n\t\t\tif (!doorZero) {\n\t\t\t\tdoors[0].Type = DoorPlaceholder.Variant.Regular;\n\t\t\t\tdoors[1].Type = DoorPlaceholder.Variant.Hidden;\n\t\t\t} else {\n\t\t\t\tdoors[1].Type = DoorPlaceholder.Variant.Regular;\n\t\t\t\tdoors[0].Type = DoorPlaceholder.Variant.Hidden;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 21;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 21;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.GetMaxConnections(Side);\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef r, Dot p) {\n\t\t\tif (p.X == Left + 1 || p.X == Right - 1 || p.Y == Top + 1 || p.Y == Bottom - 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(r, p);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/MazeConnectionRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class MazeConnectionRoom : ConnectionRoom {\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 7;\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar maze = Maze.Generate(this);\n\t\t\tvar wall = Tiles.RandomSolid();\n\t\t\tvar spikes = Rnd.Chance(30);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tvar v = true; // Rnd.Chance();\n\t\t\t\tvar k = Rnd.Int(1, 4);\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < k; i++) {\n\t\t\t\t\tvar nmaze = new bool[maze.Length][];\n\n\t\t\t\t\tfor (var j = 0; j < maze.Length; j++) {\n\t\t\t\t\t\tnmaze[j] = new bool[maze[0].Length];\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (int x = 0; x < maze.Length; x++) {\n\t\t\t\t\t\tfor (int y = 0; y < maze[0].Length; y++) {\n\t\t\t\t\t\t\tnmaze[x][y] = maze[x][y];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (int x = 1; x < maze.Length - 1; x++) {\n\t\t\t\t\t\tfor (int y = 1; y < maze[0].Length - 1; y++) {\n\t\t\t\t\t\t\tif (maze[x][y] == v) {\n\t\t\t\t\t\t\t\tvar n = 0;\n\n\t\t\t\t\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\t\t\t\t\tvar xx = x + (int) d.X;\n\t\t\t\t\t\t\t\t\tvar yy = y + (int) d.Y;\n\n\t\t\t\t\t\t\t\t\tif (maze[xx][yy] == v) {\n\t\t\t\t\t\t\t\t\t\tn++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (n < 2) {\n\t\t\t\t\t\t\t\t\tnmaze[x][y] = !v;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tmaze = nmaze;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (int x = 1; x < maze.Length - 1; x++) {\n\t\t\t\tfor (int y = 1; y < maze[0].Length - 1; y++) {\n\t\t\t\t\tif (maze[x][y]) {\n\t\t\t\t\t\tPainter.Set(level, x + Left, y + Top, wall);\n\t\t\t\t\t} else if (spikes && Rnd.Chance(20)) {\n\t\t\t\t\t\tPainter.Set(level, x + Left, y + Top, Tile.SensingSpikeTmp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/RingConnectionRoom.cs",
    "content": "using System;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class RingConnectionRoom : ConnectionRoom {\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Fill(level, this, 1, Tiles.RandomSolid());\n\n\t\t\tvar ring = GetConnectionSpace();\n\t\t\tvar b = Rnd.Chance();\n\t\t\tvar d = b && Rnd.Chance();\n\t\t\t\n\t\t\tPaintTunnel(level, d ? Tiles.Pick(Tiles.RandomSolid(), Tiles.RandomFloor(), Tile.FloorD) : Tiles.RandomFloorOrSpike(), ring, b); \n\n\t\t\tif (d || Rnd.Chance()) {\n\t\t\t\tPaintTunnel(level, Tiles.RandomFloorOrSpike(), ring);\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, ring.Left - 1, ring.Top - 1, 3, 3, Tiles.RandomFloorOrSpike());\n\t\t\tPainter.Set(level, ring.Left, ring.Top, Tiles.RandomSolid());\n\t\t}\n\n\t\tprivate Rect space;\n\n\t\tpublic override Rect GetConnectionSpace() {\n\t\t\tif (space == null) {\n\t\t\t\tspace = GenerateSpot();\n\t\t\t\tspace.Left = (int) MathUtils.Clamp(Left + 2, Right - 2, space.Left);\n\t\t\t\tspace.Top = (int) MathUtils.Clamp(Top + 2, Bottom - 2, space.Top);\n\t\t\t\tspace.Right = space.Left + 1;\n\t\t\t\tspace.Bottom = space.Top + 1;\n\t\t\t}\n\n\t\t\treturn space;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/connection/TunnelRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.connection {\n\tpublic class TunnelRoom : ConnectionRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (level.GetFilling() == Tile.Chasm || Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\t}\n\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloorOrSpike(),  GenerateSpot());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/darkmarket/DarkMarketRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.darkmarket {\n\tpublic class DarkMarketRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (LevelSave.BiomeGenerated is IceBiome) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Rect(level, this, 1, Tile.WallA);\n\n\t\t\tvar exit = new HiddenExit {\n\t\t\t\tid = \"dm\"\n\t\t\t};\n\t\t\tlevel.Area.Add(exit);\n\t\t\texit.BottomCenter = GetCenter() * 16 + new Vector2(8, 8);\n\t\t\t\n\t\t\tvar points = new List<Vector2>();\n\t\t\tvar a = false;\n\t\t\t\n\t\t\tif (Rnd.Chance(60)) {\n\t\t\t\ta = true;\n\t\t\t\tpoints.Add(new Vector2(Left + 4.5f, Top + 4.5f) * 16);\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance(60)) {\n\t\t\t\ta = true;\n\t\t\t\tpoints.Add(new Vector2(Right - 3.5f, Bottom - 4f) * 16);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(60)) {\n\t\t\t\ta = true;\n\t\t\t\tpoints.Add(new Vector2(Right - 3.5f, Top + 4.5f) * 16);\n\t\t\t}\n\n\t\t\tif (!a || Rnd.Chance(60)) {\n\t\t\t\tpoints.Add(new Vector2(Left + 4.5f, Bottom - 4f) * 16);\n\t\t\t}\n\n\t\t\tvar types = new List<byte> {\n\t\t\t\t/*0, 1, 2, 3,*/ 4 /*5, 6, 7, 8*/\n\t\t\t};\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Roger)) {\n\t\t\t\ttypes.Add(0);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Boxy)) {\n\t\t\t\ttypes.Add(1);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Snek)) {\n\t\t\t\ttypes.Add(2);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Vampire)) {\n\t\t\t\ttypes.Add(5);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Nurse)) {\n\t\t\t\ttypes.Add(6);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Elon)) {\n\t\t\t\ttypes.Add(7);\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(ShopNpc.Duck)) {\n\t\t\t\ttypes.Add(8);\n\t\t\t}\n\n\t\t\tforeach (var p in points) {\n\t\t\t\tvar i = Rnd.Int(types.Count);\n\t\t\t\tvar tp = types[i];\n\t\t\t\ttypes.RemoveAt(i);\n\n\t\t\t\tswitch (tp) {\n\t\t\t\t\tcase 0: {\n\t\t\t\t\t\tRoger.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 1: {\n\t\t\t\t\t\tBoxy.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 2: {\n\t\t\t\t\t\tSnek.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 3: {\n\t\t\t\t\t\tGobetta.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 4: {\n\t\t\t\t\t\tTrashGoblin.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 5: {\n\t\t\t\t\t\tVampire.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 6: {\n\t\t\t\t\t\tNurse.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 7: {\n\t\t\t\t\t\tDungeonElon.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase 8: {\n\t\t\t\t\t\tDungeonDuck.Place(p, level.Area);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (types.Count == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Head;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 17;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 15;\n\t\t}\n\t\t\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t\t\n\t\tprotected override int ValidateHeight(int H) {\n\t\t\treturn H % 2 == 0 ? H : H - 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/entrance/EntranceRoom.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.decor;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.walls;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.entrance {\n\tpublic class EntranceRoom : RoomDef {\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 16;\n\t\t\treturn 4;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (IceDemoRoom()) {\n\t\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\t\tPainter.FillEllipse(level, this, 3, Tiles.RandomFloor());\n\t\t\t\t\n\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\tPosition = GetTileCenter() * 16 + new Vector2(32, 0),\n\t\t\t\t\tStartingAngle = 0\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tWallRegistry.Paint(level, this, EntranceWallPool.Instance);\n\t\t\t}\n\t\t\t\n\t\t\tvar prop = new Entrance {\n\t\t\t\tTo = Run.Depth + 1\n\t\t\t};\n\n\t\t\tvar where = GetCenter();\n\t\t\t\n\t\t\tPainter.Fill(level, where.X - 1, where.Y - 1, 3, 3, Tiles.RandomFloor());\n\n\t\t\tlevel.Area.Add(prop);\n\t\t\tprop.Center = (where * 16 + new Vector2(8));\n\n\t\t\tMakeSafe(level);\n\n\t\t\ttry {\n\t\t\t\tif (Builder.ShouldAppear()) {\n\t\t\t\t\tvar b = new Builder();\n\t\t\t\t\tb.BottomCenter = where * 16 + new Vector2(8 + Rnd.Float(-16, 16), 20);\n\t\t\t\t\tlevel.Area.Add(b);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Type == RunType.BossRush && Run.Depth > 1) {\n\t\t\t\tvar item = Items.CreateAndAdd(\"bk:battery\", level.Area);\n\t\t\t\t\n\t\t\t\titem.Center = where * 16 + new Vector2(8 + Rnd.Float(-16, 16), Rnd.Float(-16, 16));\n\t\t\t}\n\t\t}\n\n\t\tprotected void MakeSafe(Level level) {\n\t\t\tvar t = Tiles.RandomFloor();\n\t\t\t\n\t\t\tPainter.Call(level, this, 1, (x, y) => {\n\t\t\t\tif (level.Get(x, y).Matches(Tile.SpikeOffTmp, Tile.SensingSpikeTmp, Tile.Chasm, Tile.Lava)) {\n\t\t\t\t\tlevel.Set(x, y, t);\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\t/*if (Run.Depth == Run.ContentEndDepth) {\n\t\t\t\tvar om = new OldMan();\n\t\t\t\tlevel.Area.Add(om);\n\t\t\t\tom.Center = ((GetRandomDoorFreeCell() ?? GetTileCenter()) * 16 + new Dot(8)).ToVector();\n\t\t\t}*/\n\t\t}\n\n\t\tprivate static bool IceDemoRoom() {\n\t\t\treturn Run.Type == RunType.Regular && LevelSave.BiomeGenerated is IceBiome && Run.Depth % 2 == 1;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn IceDemoRoom() ? 16 : 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn IceDemoRoom() ? 10 : 5;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn IceDemoRoom() ? 17 : 13;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 13;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/entrance/EntranceWallPool.cs",
    "content": "using BurningKnight.level.walls;\n\nnamespace BurningKnight.level.rooms.entrance {\n\tpublic class EntranceWallPool : WallRegistry {\n\t\tpublic static EntranceWallPool Instance = new EntranceWallPool();\n\t\t\n\t\tprotected override void SetupRooms() {\n\t\t\tAdd(new WallPainter(), 1f);\n\t\t\t\n\t\t\tAdd(new EllipseWalls(), 1f);\n\t\t\tAdd(new PatchWall(), 1);\n\t\t\tAdd(new SegmentedWall(), 1f);\n\t\t\tAdd(new RuinsWall(), 1f);\n\t\t\tAdd(new CollumsWall(), 1f);\n\t\t\tAdd(new PlatformWall(), 1f);\n\t\t\tAdd(new TempleWalls(), 1f);\n\t\t\tAdd(new CornerWall(), 1f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/entrance/ExitRoom.cs",
    "content": "using BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.walls;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.entrance {\n\tpublic class ExitRoom : RoomDef {\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 16;\n\t\t\treturn 4;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tWallRegistry.Paint(level, this, EntranceWallPool.Instance);\n\t\t\t\n\t\t\tvar prop = new Exit {\n\t\t\t\tTo = Run.Depth + 1\n\t\t\t};\n\n\t\t\tvar where = GetCenter();\n\t\t\t\n\t\t\tPainter.Fill(level, where.X - 1, where.Y - 1, 3, 3, Tiles.RandomFloor());\n\n\t\t\tlevel.Area.Add(prop);\n\t\t\tprop.Center = (where * 16 + new Vector2(8));\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\treturn base.CanConnect(R) && !(R is EntranceRoom && !(LevelSave.BiomeGenerated is TechBiome));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/entrance/PortalEntranceRoom.cs",
    "content": "using BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.door;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.entrance {\n\tpublic class PortalEntranceRoom : EntranceRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\t// WallRegistry.Paint(level, this, EntranceWallPool.Instance);\n\n\t\t\tvar w = GetTileCenter();\n\t\t\tvar d = w + new Dot(0, -2);\n\t\t\t\n\t\t\tPainter.Fill(level, d.X - 1, d.Y - 1, 3, 3, Tile.WallA);\n\t\t\tPainter.Set(level, d.X, d.Y, Tiles.RandomFloor());\n\t\t\tPainter.Set(level, d.X, d.Y + 1, Tiles.RandomFloor());\n\n\t\t\tvar door = new LevelDoor();\n\t\t\tlevel.Area.Add(door);\n\n\t\t\tdoor.X = d.X * 16;\n\t\t\tdoor.Y = d.Y * 16 + 16;\n\n\t\t\tPlaceExit(level, d);\n\t\t\tPlaceEntrance(level, w + new Dot(0, 1));\n\n\t\t\tMakeSafe(level);\n\t\t}\n\n\t\tprivate void PlaceExit(Level level, Dot where) {\n\t\t\tvar prop = new Exit {\n\t\t\t\tTo = Run.Depth + 1\n\t\t\t};\n\n\t\t\tlevel.Area.Add(prop);\n\t\t\tprop.Center = (where * 16 + new Vector2(8));\n\t\t}\n\n\t\tprivate void PlaceEntrance(Level level, Dot where) {\n\t\t\tvar prop = new Entrance {\n\t\t\t\tTo = -1\n\t\t\t};\n\n\t\t\tlevel.Area.Add(prop);\n\t\t\tprop.Center = (where * 16 + new Vector2(8));\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/granny/GrannyRoom.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.granny {\n\tpublic class GrannyRoom : SpecialRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Hidden;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tPainter.Rect(level, this, 1, Tile.GrannyWall);\n\t\t\tPainter.Fill(level, this, 2, Tile.GrannyFloor);\n\t\t\t\n\t\t\tPaintTunnel(level, Tile.GrannyFloor, GetCenterRect(), false, false, false);\n\t\t\t\n\t\t\tvar granny = new Granny();\n\t\t\tlevel.Area.Add(granny);\n\t\t\tgranny.BottomCenter = new Vector2(Left + GetWidth() / 2 + 0.5f, Top + 3) * 16;\n\n\t\t\tvar count = Math.Ceiling((GetWidth() - 6) / 2f);\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Granny));\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar stand = new GrannyStand();\n\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\tstand.Center = new Vector2(Left + 3.5f + i * 2, Top + 4.5f) * 16;\n\t\t\t\t\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.GenerateAndRemove(pool), level.Area), null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\treturn R is BossRoom;\n\t\t}\n\t\t\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/oldman/OldManRoom.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.oldman {\n\tpublic class OldManRoom : SpecialRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Hidden;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tPainter.Rect(level, this, 1, Tile.EvilWall);\n\t\t\tPainter.Fill(level, this, 2, Tile.EvilFloor);\n\t\t\t\n\t\t\tPaintTunnel(level, Tile.EvilFloor, GetCenterRect(), false, false, false);\n\t\t\t\n\t\t\tvar dm = new DarkMage();\n\t\t\tlevel.Area.Add(dm);\n\n\t\t\tvar w = new Vector2(GetCenterVector().X, (Top + 3) * 16);\n\t\t\tdm.BottomCenter = w;\n\n\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\tvar campfire = new Campfire();\n\t\t\t\tlevel.Area.Add(campfire);\n\t\t\t\tcampfire.BottomCenter = w + new Vector2(24 * (i == 0 ? -1 : 1), 0);\n\t\t\t}\n\n\t\t\tvar count = Math.Ceiling((GetWidth() - 6) / 2f);\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.OldMan));\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar stand = new DarkMageStand();\n\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\tstand.Center = new Vector2(Left + 3.5f + i * 2, Top + 4.5f) * 16;\n\t\t\t\t\n\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.GenerateAndRemove(pool), level.Area, false), null);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\treturn R is BossRoom;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 9;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 9;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/payed/PayedRoom.cs",
    "content": "using BurningKnight.level.rooms.special;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.rooms.payed {\n\tpublic class PayedRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Payed;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/preboss/PrebossRoom.cs",
    "content": "using BurningKnight.level.entities.decor;\nusing BurningKnight.level.rooms.boss;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.preboss {\n\tpublic class PrebossRoom : ExitRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\n\t\t\tforeach (var p in Connected) {\n\t\t\t\tvar d = p.Value;\n\t\t\t\tvar g = p.Key is BossRoom;\n\n\t\t\t\tif (g) {\n\t\t\t\t\tDot a;\n\t\t\t\t\tDot b;\n\n\t\t\t\t\tif (d.X == Left) {\n\t\t\t\t\t\ta = new Dot(Left + 4, Top + 4);\n\t\t\t\t\t\tb = new Dot(Left + 4, Top + 6);\n\t\t\t\t\t} else if (d.X == Right) {\n\t\t\t\t\t\ta = new Dot(Right - 4, Top + 4);\n\t\t\t\t\t\tb = new Dot(Right - 4, Top + 6);\n\t\t\t\t\t} else if (d.Y == Top) {\n\t\t\t\t\t\ta = new Dot(Left + 4, Top + 4);\n\t\t\t\t\t\tb = new Dot(Left + 6, Top + 4);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ta = new Dot(Left + 4, Bottom - 4);\n\t\t\t\t\t\tb = new Dot(Left + 6, Bottom - 4);\n\t\t\t\t\t}\n\n\t\t\t\t\tvar ta = new Torch();\n\t\t\t\t\tlevel.Area.Add(ta);\n\t\t\t\t\tta.CenterX = a.X * 16 + 8;\n\t\t\t\t\tta.Bottom = a.Y * 16 + 12;\n\t\t\t\t\t\n\t\t\t\t\tvar tb = new Torch();\n\t\t\t\t\tlevel.Area.Add(tb);\n\t\t\t\t\ttb.CenterX = b.X * 16 + 8;\n\t\t\t\t\ttb.Bottom = b.Y * 16 + 12;\n\t\t\t\t\t\n\t\t\t\t}\n\n\t\t\t\tDot from;\n\t\t\t\tDot to;\n\n\t\t\t\tif (d.X == Left) {\n\t\t\t\t\tto = new Dot(Left + 3, Top + 5);\n\t\t\t\t\tfrom = new Dot(d.X + 1, d.Y);\n\t\t\t\t} else if (d.X == Right) {\n\t\t\t\t\tto = new Dot(Right - 3, Top + 5);\n\t\t\t\t\tfrom = new Dot(d.X - 1, d.Y);\n\t\t\t\t} else if (d.Y == Top) {\n\t\t\t\t\tto = new Dot(Left + 5, Top + 3);\n\t\t\t\t\tfrom = new Dot(d.X, d.Y + 1);\n\t\t\t\t} else {\n\t\t\t\t\tto = new Dot(Left + 5, Bottom - 3);\n\t\t\t\t\tfrom = new Dot(d.X, d.Y - 1);\n\t\t\t\t}\n\n\t\t\t\tvar f = g ? Tile.FloorD : Tiles.RandomFloor();\n\n\t\t\t\tif (d.X == Left || d.X == Right) {\n\t\t\t\t\tvar n = new Dot(from.X, to.Y);\n\t\t\t\t\t\n\t\t\t\t\tPainter.DrawLine(level, from, n, f);\n\t\t\t\t\tPainter.DrawLine(level, n, to, f);\n\t\t\t\t} else {\n\t\t\t\t\tvar n = new Dot(to.X, from.Y);\n\t\t\t\t\t\n\t\t\t\t\tPainter.DrawLine(level, from, n, f);\n\t\t\t\t\tPainter.DrawLine(level, n, to, f);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, this, 3, Tile.FloorB);\n\t\t\tPainter.Fill(level, this, 4, Tile.FloorD);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/EmptyRoom.cs",
    "content": "namespace BurningKnight.level.rooms.regular {\n\tpublic class EmptyRoom : RegularRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override bool ShouldSpawnMobs() {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/HiveRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.jungle;\nusing BurningKnight.level.tile;\nusing BurningKnight.util;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class HiveRoom : JungleRoom {\n\t\tpublic HiveRoom() {\n\t\t\tFloor = Tile.FloorD;\n\t\t\tFloor2 = Tile.FloorD;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\n\t\t\tvar center = GetCenter();\n\t\t\tvar cx = center.X;\n\t\t\tvar cy = center.Y;\n\t\t\tvar xm = (float) GetHeight() / GetWidth();\n\t\t\tvar bound = Math.Min(GetWidth(), GetHeight()) / 2f - 3f;\n\t\t\tvar f = Tiles.RandomFloor();\n\t\t\t\n\t\t\tfor (var x = Left + 1; x < Right - 1; x++) {\n\t\t\t\tfor (var y = Top + 1; y < Bottom - 1; y++) {\n\t\t\t\t\tvar t = level.Get(x, y);\n\t\t\t\t\t\n\t\t\t\t\tif (t != Tile.WallA && t != Tile.FloorD) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar dx = cx - x;\n\t\t\t\t\tvar dy = cy - y;\n\t\t\t\t\tvar d = MathUtils.Distance(dx * xm, dy);\n\n\t\t\t\t\tif (d < bound + Rnd.Float(0, 3f)) {\n\t\t\t\t\t\tif (t == Tile.WallA) {\n\t\t\t\t\t\t\tlevel.Set(x, y, Tile.WallB);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (t != Tile.WallA){\n\t\t\t\t\t\tlevel.Set(x, y, f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void ModifyMobList(List<MobInfo> infos) {\n\t\t\tbase.ModifyMobList(infos);\n\t\t\tArrayUtils.Remove(infos, i => i.Type == typeof(BeeHive));\n\t\t}\n\n\t\tpublic override float WeightMob(MobInfo info, SpawnChance chance) {\n\t\t\tif (info.Type == typeof(Bee) || info.Type == typeof(Explobee)) {\n\t\t\t\treturn info.Chance * 2;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.WeightMob(info, chance);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/ItemTrollRoom.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class ItemTrollRoom : RegularRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar w = GetWidth();\n\t\t\tvar h = GetHeight();\n\t\t\tvar s = Math.Min(w, h);\n\n\t\t\ts = Math.Max(5, Rnd.Int(5, s - 5));\n\n\t\t\tvar center = GetTileCenter();\n\t\t\tvar stand = new ItemStand();\n\t\t\t\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = center * 16 + new Vector2(8, 8);\n\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Treasure), level.Area), null);\n\n\t\t\tvar c = (int) Math.Floor(s / 2f);\n\t\t\tvar t = Rnd.Chance() ? Tile.Rock : Tile.MetalBlock;\n\n\t\t\tfor (var x = center.X - c; x <= center.X + c; x++) {\n\t\t\t\tfor (var y = center.Y - c; y <= center.Y + c; y++) {\n\t\t\t\t\tif (Math.Abs(x - center.X) + Math.Abs(y - center.Y) <= c && (center.X != x || center.Y != y)) {\n\t\t\t\t\t\tPainter.Set(level, new Dot(x, y), t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Rect(level, this, 1, Tiles.RandomFloor());\n\t\t}\n\n\t\tpublic override bool ShouldSpawnMobs() {\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\n\t\tprotected override int ValidateHeight(int H) {\n\t\t\treturn H % 2 == 0 ? H : H - 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/JungleRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.level.tile;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class JungleRoom : RegularRoom {\n\t\tpublic static int DeathCondition = 4;\n\t\tpublic static int BirthCondition = 4;\n\n\t\tprotected Tile Floor = Tile.FloorA;\n\t\tprotected Tile Floor2 = Tile.FloorB;\n\t\tprotected Tile Wall = Tile.WallA;\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tprotected void Pass(Action<int, int> callback) {\n\t\t\tfor (var y = Top; y < Bottom; y++) {\n\t\t\t\tfor (var x = Left; x < Right; x++) {\n\t\t\t\t\tcallback(x, y);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\tif (P.Y - Top < 3 || Bottom - P.Y < 3) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (P.X - Left < 3 || Right - P.X < 3) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar w = GetWidth();\n\t\t\tvar h = GetHeight();\n\t\t\t\n\t\t\tvar old = Painter.Clip;\n\t\t\tPainter.Clip = null;\n\t\t\tPainter.Fill(level, this, Wall);\n\t\t\tPainter.Clip = old;\n\t\t\t\n\t\t\tPainter.FillEllipse(level, this, 3, Tile.FloorA);\n\t\t\tPainter.FillEllipse(level, this, (int) (Math.Min(w, h) / 2f - 2), Tile.FloorD);\n\n\t\t\tvar r = GetCenterRect();\n\t\t\t\n\t\t\tPaintTunnel(level, Tile.FloorA, r, true);\n\t\t\tPaintTunnel(level, Tile.FloorD, r);\n\n\t\t\tPass((x, y) => {\n\t\t\t\tvar t = level.Get(x, y);\n\t\t\t\t\n\t\t\t\tif (t != Tile.FloorD || Rnd.Chance(30)) {\n\t\t\t\t\tif (t == Tile.WallA && Rnd.Chance(10)) {\n\t\t\t\t\t\tPainter.Set(level, x, y, Tile.FloorA);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar sz = Rnd.Int(2, 4);\n\n\t\t\t\tfor (var xx = -sz; xx <= sz; xx++) {\n\t\t\t\t\tfor (var yy = -sz; yy <= sz; yy++) {\n\t\t\t\t\t\tif (level.Get(x + xx, y + yy) != Tile.FloorD) {\n\t\t\t\t\t\t\tPainter.Set(level, x + xx, y + yy, Rnd.Chance(30) ? Tile.WallA : Tile.FloorA);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar array = new byte[w, h];\n\t\t\tvar oldArray = new byte[w, h];\n\t\t\t\n\t\t\tPass((x, y) => {\n\t\t\t\tvar t = level.Get(x, y);\n\t\t\t\t\n\t\t\t\tif (t == Tile.FloorA && Rnd.Float() > 0.55f - (float) (Math.Cos(x / 16f) * 0.02f + Math.Cos(y / 16f) * 0.1f)) {\n\t\t\t\t\tt = Tile.WallA;\n\t\t\t\t\tPainter.Set(level, x, y, t);\n\t\t\t\t}\n\n\t\t\t\tvar v = t == Tile.FloorA ? 0 : 1;\n\n\t\t\t\tif (t == Tile.FloorD) {\n\t\t\t\t\tv = 2;\n\t\t\t\t}\n\n\t\t\t\tarray[x - Left, y - Top] = (byte) v;\n\t\t\t\toldArray[x - Left, y - Top] = (byte) v;\n\t\t\t});\n\n\t\t\tfor (var i = 0; i < 5; i++) {\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tfor (var y = 0; y < h; y++) {\n\t\t\t\t\t\tvar c = oldArray[x, y];\n\t\t\t\t\t\tvar n = 0;\n\n\t\t\t\t\t\tforeach (var d in MathUtils.AllDirections) {\n\t\t\t\t\t\t\tvar xx = x + (int) d.X;\n\t\t\t\t\t\t\tvar yy = y + (int) d.Y;\n\n\t\t\t\t\t\t\tif (xx < 0 || xx >= w || yy < 0 || yy >= h) {\n\t\t\t\t\t\t\t\tn++;\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (oldArray[xx, yy] == 1) {\n\t\t\t\t\t\t\t\tn++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (c != 2) {\n\t\t\t\t\t\t\tif (n < DeathCondition) {\n\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t} else if (n > BirthCondition) {\n\t\t\t\t\t\t\t\tc = 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tarray[x, y] = c;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tfor (var y = 0; y < h; y++) {\n\t\t\t\t\t\toldArray[x, y] = array[x, y];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tAction<int, int> fill = null;\n\t\t\tvar queue = new Queue<Dot>();\n\t\t\tvar m = 0;\n\n\t\t\tfill = (x, y) => {\n\t\t\t\tif (x < 0 || y < 0 || x >= w || y >= h) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar v = array[x, y];\n\t\t\t\t\n\t\t\t\tif (v == 1 || v == 3) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tm++;\n\t\t\t\tarray[x, y] = 3;\n\n\t\t\t\tqueue.Enqueue(new Dot(x - 1, y));\n\t\t\t\tqueue.Enqueue(new Dot(x + 1, y));\n\t\t\t\tqueue.Enqueue(new Dot(x, y - 1));\n\t\t\t\tqueue.Enqueue(new Dot(x, y + 1));\n\t\t\t};\n\n\t\t\tvar painted = false;\n\t\t\t\n\t\t\tforeach (var dr in Connected.Values) {\n\t\t\t\tvar st = new Dot(dr.X, dr.Y);\n\n\t\t\t\tif (dr.X == Left) {\n\t\t\t\t\tst = new Dot(dr.X + 1, dr.Y);\n\t\t\t\t} else if (dr.X == Right) {\n\t\t\t\t\tst = new Dot(dr.X - 1, dr.Y);\n\t\t\t\t} else if (dr.Y == Top) {\n\t\t\t\t\tst = new Dot(dr.X, dr.Y + 1);\n\t\t\t\t} else if (dr.Y == Bottom) {\n\t\t\t\t\tst = new Dot(dr.X, dr.Y - 1);\n\t\t\t\t}\n\n\t\t\t\tfill(st.X - Left, st.Y - Top);\n\n\t\t\t\tif (queue.Count != 0) {\n\t\t\t\t\tpainted = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!painted) {\n\t\t\t\tLog.Error(\"Did not spot a spot in the jungle room!\");\n\t\t\t\tPaint(level);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile (queue.Count > 0) {\n\t\t\t\tvar d = queue.Dequeue();\n\t\t\t\tfill(d.X, d.Y);\n\t\t\t}\n\n\t\t\tvar start = 0;\n\n\t\t\tvar ww = GetWidth();\n\t\t\tvar hh = GetHeight();\n\t\t\t\n\t\t\tFunc<int, int, int> toIndex = (x, y) => (x - Left) + (y - Top) * ww;\n\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif (d.X == Left) {\n\t\t\t\t\tstart = toIndex(d.X + 1, d.Y);\n\t\t\t\t} else if (d.X == Right) {\n\t\t\t\t\tstart = toIndex(d.X - 1, d.Y);\n\t\t\t\t} else if (d.Y == Top) {\n\t\t\t\t\tstart = toIndex(d.X, d.Y + 1);\n\t\t\t\t} else if (d.Y == Bottom) {\n\t\t\t\t\tstart = toIndex(d.X, d.Y - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPass((x, y) => {\n\t\t\t\tif (x > Left && x < Right && y > Top && y < Bottom) {\n\t\t\t\t\tPainter.Set(level, x, y, array[x - Left, y - Top] == 3 ? Floor : Wall);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar patch = new bool[ww * hh];\n\n\t\t\tfor (var y = 0; y < hh; y++) {\n\t\t\t\tfor (var x = 0; x < ww; x++) {\n\t\t\t\t\tpatch[y * ww + x] = !level.Get(Left + x, Top + y).IsPassable();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPathFinder.SetMapSize(ww, hh);\n\t\t\tPathFinder.BuildDistanceMap(start, BArray.Not(patch, null));\n\t\t\tvar valid = true;\n\n\t\t\tfor (var i = 0; i < patch.Length; i++) {\n\t\t\t\tif (!patch[i] && PathFinder.Distance[i] == Int32.MaxValue) {\n\t\t\t\t\tvalid = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// level.Set(Left + start % ww, Top + start / ww, Tile.Cobweb);\n\t\t\tPathFinder.SetMapSize(level.Width, level.Height);\n\n\t\t\tif (!valid) {\n\t\t\t\tLog.Error(\"Failed to build path\");\n\t\t\t\tPaint(level);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t \n\t\t\tpatch = Patch.GenerateWithNoise(w, h, Rnd.Float(10000), 0.25f, 0.1f);\n\n\t\t\tif (Floor2 != Floor) {\n\t\t\t\tPass((x, y) => {\n\t\t\t\t\tif (level.Get(x, y) == Floor && patch[(x - Left) + (y - Top) * w]) {\n\t\t\t\t\t\tPainter.Set(level, x, y, Floor2);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn (10 + 2) * 2;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn (8 + 2) * 2;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn (18 + 6) * 2;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn (12 + 2) * 2;\n\t\t}\n\n\t\tpublic override float GetWeightModifier() {\n\t\t\treturn 0.75f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/PlatformChaosRoom.cs",
    "content": "using BurningKnight.entity.room.controllable.platform;\r\nusing BurningKnight.entity.room.controllable.turret;\r\nusing BurningKnight.level.tile;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.regular {\r\n\tpublic class PlatformChaosRoom : RegularRoom {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Fill(level, this, 3, Tile.Chasm);\r\n\r\n\t\t\tvar c = Rnd.Int(2, 4);\r\n\t\t\tvar p = Rnd.Chance(30);\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < c; i++) {\r\n\t\t\t\tvar platform = new MovingPlatform();\r\n\r\n\t\t\t\tplatform.X = Rnd.Int(Left + 4, Right - 4) * 16;\r\n\t\t\t\tplatform.Y = Rnd.Int(Top + 4, Bottom - 4) * 16;\r\n\t\t\t\tplatform.Controller = Rnd.Chance() ? PlatformController.ClockWise : PlatformController.CounterClockWise;\r\n\r\n\t\t\t\tlevel.Area.Add(platform);\r\n\t\t\t\t\r\n\t\t\t\tif (p && Rnd.Chance()) {\r\n\t\t\t\t\tvar turret = new RotatingTurret();\r\n\t\t\t\t\tlevel.Area.Add(turret);\r\n\t\t\t\t\tturret.Center = platform.Position + new Vector2(16, 12);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 12;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn 20;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn 18;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/PlatformLineRoom.cs",
    "content": "using BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class PlatformLineRoom : RegularRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tvar x = Rnd.Int(Left + 1, Right - 2);\n\t\t\t\t\n\t\t\t\tPainter.Fill(level, new Rect().Setup(x, Top + 1, 2, Bottom - 1), Tile.Chasm);\n\t\t\t\t\n\t\t\t\tvar platform = new MovingPlatform();\n\n\t\t\t\tplatform.X = x * 16;\n\t\t\t\tplatform.Y = (Rnd.Int(Top + 1, Bottom - 2)) * 16;\n\t\t\t\tplatform.Controller = PlatformController.UpDown;\n\n\t\t\t\tlevel.Area.Add(platform);\n\t\t\t} else {\n\t\t\t\tvar y = Rnd.Int(Top + 1, Bottom - 2);\n\t\t\t\t\n\t\t\t\tPainter.Fill(level, new Rect().Setup(Left + 1, y, Right - 1, 2), Tile.Chasm);\n\t\t\t\t\n\t\t\t\tvar platform = new MovingPlatform();\n\n\t\t\t\tplatform.X = (Rnd.Int(Left + 1, Right - 2)) * 16;\n\t\t\t\tplatform.Y = y * 16;\n\t\t\t\tplatform.Controller = PlatformController.LeftRight;\n\n\t\t\t\tlevel.Area.Add(platform);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/PlatformRingRoom.cs",
    "content": "using System;\r\nusing BurningKnight.entity.room.controllable.platform;\r\nusing BurningKnight.level.tile;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.regular {\r\n\tpublic class PlatformRingRoom : RegularRoom {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Rect(level, this, 3, Tile.Chasm);\r\n\t\t\tPainter.Rect(level, this, 4, Tile.Chasm);\r\n\r\n\t\t\tvar c = Rnd.Int(1, 3);\r\n\t\t\tvar d = Rnd.Chance() ? PlatformController.ClockWise : PlatformController.CounterClockWise;\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < c; i++) {\r\n\t\t\t\tvar platform = new MovingPlatform();\r\n\t\t\t\tplatform.StartingStep = i;\r\n\r\n\t\t\t\tif (i == 0) {\r\n\t\t\t\t\tplatform.Position = new Vector2(Left + 3, Top + 3) * 16;\r\n\t\t\t\t} else if (i == 2 || (i == 1 && c == 2)) { // For symetry\r\n\t\t\t\t\tplatform.Position = new Vector2(Right - 4, Bottom - 4) * 16;\r\n\t\t\t\t\tplatform.StartingStep = 2;\r\n\t\t\t\t} else if (i == 1) {\r\n\t\t\t\t\tplatform.Position = new Vector2(Right - 4, Top + 3) * 16;\r\n\t\t\t\t} else if (i == 3) {\r\n\t\t\t\t\tplatform.Position = new Vector2(Left + 3, Bottom - 4) * 16;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tplatform.Controller = d;\r\n\r\n\t\t\t\tlevel.Area.Add(platform);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 12;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 12;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/RegularRoom.cs",
    "content": "using BurningKnight.state;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class RegularRoom : RoomDef {\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var Door in Connected.Values) {\n\t\t\t\tDoor.Type = DoorPlaceholder.Variant.Enemy;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) {\n\t\t\t\treturn 16;\n\t\t\t}\n\n\t\t\treturn 4;\n\t\t}\n\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override bool ShouldSpawnMobs() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected bool SmallerRooms() {\n\t\t\treturn Run.Depth <= 2;\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn SmallerRooms() ? 8 : 12;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn SmallerRooms() ? 8 : 10;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn SmallerRooms() ? 16 : 24;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn SmallerRooms() ? 12 : 14;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/TwoSidesRoom.cs",
    "content": "using BurningKnight.entity.room.controllable.platform;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.regular {\n\tpublic class TwoSidesRoom : RegularRoom {\n\t\tprivate Rect rect;\n\t\tprivate bool vertical;\n\n\t\tpublic TwoSidesRoom() {\n\t\t\tvertical = Rnd.Chance();\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tSetupRect();\n\t\t\tPainter.Fill(level, rect, Tile.Chasm);\n\n\t\t\tvar platform = new MovingPlatform();\n\n\t\t\tplatform.X = vertical ? (Rnd.Int(Left + 2, Right - 2)) * 16 : (Left + GetWidth() / 2) * 16;\n\t\t\tplatform.Y = vertical ? (Top + GetHeight() / 2) * 16 : (Rnd.Int(Top + 2, Bottom - 2)) * 16;\n\t\t\tplatform.Controller = Rnd.Chance(40) ? (Rnd.Chance() ? PlatformController.ClockWise : PlatformController.CounterClockWise) : (vertical ? PlatformController.UpDown : PlatformController.LeftRight);\n\n\t\t\tlevel.Area.Add(platform);\n\n\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\tvar turret = new RotatingTurret();\n\t\t\t\tlevel.Area.Add(turret);\n\t\t\t\tturret.Center = platform.Position + new Vector2(16, 12);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tvar x = (int) P.X;\n\t\t\tvar y = (int) P.Y;\n\t\t\t\n\t\t\tif (vertical) {\n\t\t\t\tif ((x == Left || x == Right) && (y > Top + 3 && y < Bottom - 4)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\t\n\t\t\t} else {\n\t\t\t\tif ((y == Top || y == Bottom) && (x > Left + 3 && x < Right - 4)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tprivate void SetupRect() {\n\t\t\tif (rect != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\trect = new Rect();\n\t\t\t\n\t\t\tif (!vertical) {\n\t\t\t\trect.Top = Top + 1;\n\t\t\t\trect.Bottom = Bottom;\n\n\t\t\t\trect.Left = Left + 5 + Rnd.Int(3);\n\t\t\t\trect.Right = Right - 4 - Rnd.Int(3);\n\t\t\t} else {\n\t\t\t\trect.Left = Left + 1;\n\t\t\t\trect.Right = Right;\n\t\t\t\t\n\t\t\t\trect.Top = Top + 5 + Rnd.Int(3);\n\t\t\t\trect.Bottom = Bottom - 4 - Rnd.Int(3);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn vertical ? 8 : 15;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn vertical ? 15 : 8;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn vertical ? 15 : 23;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn vertical ? 23 : 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/regular/VerticalRegularRoom.cs",
    "content": "namespace BurningKnight.level.rooms.regular {\n\tpublic class VerticalRegularRoom : RegularRoom {\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn SmallerRooms() ? 10 : 12;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn SmallerRooms() ? 8 : 10;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn SmallerRooms() ? 16 : 24;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn SmallerRooms() ? 12 : 14;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/scourged/ScourgedRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.scourged {\n\tpublic class ScourgedRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (LevelSave.BiomeGenerated is IceBiome) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tvar t = Tiles.Pick(Tile.Chasm, Tile.WallA, Tile.WallB, Tile.Planks);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Set(level, new Dot(Left + 1, Top + 1), t);\n\t\t\t\tPainter.Set(level, new Dot(Right - 1, Bottom - 1), t);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Set(level, new Dot(Right - 1, Top + 1), t);\n\t\t\t\tPainter.Set(level, new Dot(Left + 1, Bottom - 1), t);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(10 + Run.Scourge * 5)) {\n\t\t\t\tvar cn = GetCenter() * 16;\n\t\t\t\tvar c = Rnd.Int(2, 4);\n\n\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\tvar stand = new ScourgedStand();\n\t\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\t\tstand.Center = cn + new Vector2(16 + (i - c / 2f) * 32, 8);\n\n\t\t\t\t\tstand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), level.Area), stand);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar center = GetCenter() * 16 + new Vector2(8);\n\n\t\t\tif (Rnd.Chance(5)) {\n\t\t\t\tvar chest = new ProtoChest();\n\t\t\t\tlevel.Area.Add(chest);\n\t\t\t\tchest.BottomCenter = center;\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tswitch (Rnd.Int(GlobalSave.IsTrue(ShopNpc.Gobetta) ? 6 : 5)) {\n\t\t\t\tcase 0: {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 3); i++) {\n\t\t\t\t\t\tItems.CreateAndAdd(\"bk:heart\", level.Area).Center = center;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 1: {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 4); i++) {\n\t\t\t\t\t\tItems.CreateAndAdd(\"bk:shield\", level.Area).Center = center;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 2: {\n\t\t\t\t\tvar stand = new ItemStand();\n\t\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\t\tstand.BottomCenter = center;\n\t\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Treasure), level.Area), null);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 3: {\n\t\t\t\t\tvar a = Rnd.Chance();\n\t\t\t\t\tvar c = Rnd.Int(1, a ? 3 : 4);\n\n\t\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\t\tvar chest = a ? (Chest) new StoneChest() : new RedChest();\n\t\t\t\t\t\tlevel.Area.Add(chest);\n\t\t\t\t\t\tchest.BottomCenter = center - new Vector2((c / 2f - i) * 20, 0);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase 4: {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(6, 12); i++) {\n\t\t\t\t\t\tItems.CreateAndAdd(\"bk:coin\", level.Area).Center = center;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 5: {\n\t\t\t\t\tGobetta.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Scourged;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right || P.X == Left + 1 || P.X == Right - 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn Rnd.Chance();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/BirdSecretRoom.cs",
    "content": "using BurningKnight.entity.creature.npc;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class BirdSecretRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar c = GetTileCenter();\n\t\t\tvar npc = new Bird();\n\t\t\tlevel.Area.Add(npc);\n\t\t\tnpc.BottomCenter = c * 16 + new Vector2(8, 8);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/GrannySecretRoom.cs",
    "content": "namespace BurningKnight.level.rooms.secret {\r\n\tpublic class GrannySecretRoom : SecretRoom {\r\n\t\tpublic override void PaintFloor(Level level) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Prefab(level, \"granny\", Left, Top);\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 8;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 5;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn 9;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn 6;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretChasmRoom.cs",
    "content": "using System;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretChasmRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.Fill(level, this, (int) (Math.Min(GetWidth(), GetHeight()) / 2f) - 1, Tiles.RandomFloor());\n\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tPainter.Fill(level, d.X - 1, d.Y - 1, 3, 3, Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = 0; i < Rnd.Int(1, 5); i++) {\n\t\t\t\tvar item = Items.CreateAndAdd(Items.Generate(ItemPool.Consumable), level.Area);\n\t\t\t\titem.Center = GetCenter() * 16 + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\n\t\t\t}\n\n\t\t\tif (GlobalSave.IsTrue(\"saved_npc\")) {\n\t\t\t\tfor (var i = 0; i < Rnd.Int(1, Run.Depth); i++) {\n\t\t\t\t\tvar item = Items.CreateAndAdd(\"bk:emerald\", level.Area);\n\t\t\t\t\titem.Center = GetCenter() * 16 + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretChestRoom.cs",
    "content": "using System;\nusing BurningKnight.level.entities.chest;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretChestRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tEntity chest = null;\n\n\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\tchest = new ProtoChest();\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tchest = ChestRegistry.PlaceRandom(Vector2.Zero, level.Area);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t\tchest = new WoodenChest();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlevel.Area.Add(chest);\n\t\t\tchest.BottomCenter = GetCenter() * 16 + new Vector2(8, 8);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretDarkMarketEntranceRoom.cs",
    "content": "using BurningKnight.level.entities;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretDarkMarketEntranceRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\n\t\t\tvar entrance = new HiddenEntrance {\n\t\t\t\tid = \"dm\"\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(entrance);\n\t\t\tentrance.Position = new Vector2(Left + (int) ((GetWidth() - 1) / 2f), Top + (int) ((GetHeight() - 1) / 2f)) * 16;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t\t\n\t\tprotected override int ValidateHeight(int H) {\n\t\t\treturn H % 2 == 0 ? H : H - 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretEmeraldGolemRoom.cs",
    "content": "using BurningKnight.entity.creature.npc;\nusing BurningKnight.level.walls;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretEmeraldGolemRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tnew EllipseWalls().Paint(level, this, Shrink());\n\t\t\t\n\t\t\tvar golem = new EmeraldGolem();\n\t\t\tlevel.Area.Add(golem);\n\t\t\tgolem.BottomCenter = GetCenter() * 16 + new Vector2(8, 0);\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretItemRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretItemRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar c = GetTileCenter();\n\t\t\tvar stand = new ItemStand();\n\t\t\t\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = c * 16 + new Vector2(8, 16);\n\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Secret), level.Area), null);\n\n\t\t\tvar npc = new OldMan {\n\t\t\t\tRickRoll = Rnd.Chance(5)\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(npc);\n\t\t\tnpc.BottomCenter = c * 16 + new Vector2(8, -8);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretKeyRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item.stand;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretKeyRoom : SecretRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar c = GetTileCenter();\n\t\t\tvar stand = new ItemStand();\n\t\t\t\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = c * 16 + new Vector2(8);\n\t\t\tstand.SetItem(Items.CreateAndAdd(\"bk:treasure_key\", level.Area), null);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 6;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretMachineRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.machine;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretMachineRoom : SecretRoom {\n\t\tpublic override void Paint(Level Level) {\n\t\t\tbase.Paint(Level);\n\n\t\t\tEntity prop;\n\t\t\tvar r = Rnd.Int(3);\n\n\t\t\tif (r == 0) {\n\t\t\t\tprop = new VendingMachine();\n\t\t\t} else if (r == 1) {\n       \tprop = new Charger();\n      } else {\n\t\t\t\tprop = new Safe();\n\t\t\t}\n\n\t\t\tLevel.Area.Add(prop);\n\t\t\tprop.Center = GetCenter() * 16 + new Vector2(Rnd.Float(-8, 8), Rnd.Float(-8, 8));\n\t\t\t\n\t\t\tfor (var i = 0; i < Rnd.Int(1, Run.Depth); i++) {\n\t\t\t\tvar item = Items.CreateAndAdd(\"bk:emerald\", Level.Area);\n\t\t\t\titem.Center = GetRandomFreeCell() * 16 + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretRoom.cs",
    "content": "using BurningKnight.level.rooms.connection;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretRoom : RoomDef {\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, 1, Tile.FloorD);\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Secret;\n\t\t\t}\t\t\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\treturn !(R is ConnectionRoom) && base.CanConnect(R);\n\t\t}\n\n\t\tpublic override bool ShouldSpawnMobs() {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/secret/SecretScourgeRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.secret {\n\tpublic class SecretScourgeRoom : SecretRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, 1, Tile.EvilFloor);\n\n\t\t\tvar stand = new ScourgedStand();\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = GetCenter() * 16 + new Vector2(8);\n\n\t\t\tstand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), level.Area), stand);\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn Rnd.Chance();\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 11;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/ShopRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.machine;\nusing BurningKnight.level.rooms.shop.sub;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.shop {\n\tpublic class ShopRoom : LockedRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (LevelSave.BiomeGenerated is IceBiome) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tvar scourged = Rnd.Chance(Run.Scourge + 1);\n\t\t\n\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\tvar t = Tiles.Pick(Tile.FloorC, Tile.FloorD);\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPainter.FillEllipse(level, this, 3, t);\n\t\t\t\t} else {\n\t\t\t\t\tPainter.Fill(level, this, 3, t);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tt = Tiles.Pick(Tile.FloorC, Tile.FloorD);\n\n\t\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\t\tPainter.FillEllipse(level, this, 4, t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tPainter.Fill(level, this, 4, t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect(), true);\n\t\t\t\t\tPaintTunnel(level, Tiles.RandomNewFloor(), GetCenterRect());\n\t\t\t\t} else {\n\t\t\t\t\tPaintTunnel(level, Tiles.RandomNewFloor(), GetCenterRect(), Rnd.Chance());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (GameSave.IsTrue(\"sk_enraged\")) {\n\t\t\t\tvar rp = GetCenter();\n\t\t\t\tvar rsk = new ShopKeeper();\n\n\t\t\t\tlevel.Area.Add(rsk);\n\t\t\t\trsk.Center = new Vector2(rp.X * 16 + 8, rp.Y * 16 + 16);\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar stands = ValidateStands(level, GenerateStands());\n\n\t\t\tif (stands.Count < 4) {\n\t\t\t\tPainter.Fill(level, this, 1, Tile.FloorD);\n\t\t\t\tPaint(level);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (scourged) {\n\t\t\t\tvar f = Tiles.RandomFloor();\n\t\t\t\t\n\t\t\t\tfor (var m = Left + 1; m <= Right - 1; m++) {\n\t\t\t\t\tfor (var j = Top + 1; j <= Bottom - 1; j++) {\n\t\t\t\t\t\tvar t = level.Get(m, j);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (t.IsPassable() && t != f) {\n\t\t\t\t\t\t\tlevel.Set(m, j, Tile.EvilFloor);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(Run.Type == RunType.BossRush ? ItemPool.BossRush : ItemPool.Shop));\n\t\t\tvar consumablePool = Items.GeneratePool(Items.GetPool(ItemPool.ShopConsumable));\n\n\t\t\tvar con = Math.Max(1, Math.Ceiling(stands.Count / 4f));\n\t\t\tvar i = 0;\n\t\t\tvar g = (Run.Depth == 5 && Run.Loop == 0 && LevelSave.GenerateMarket) ? Rnd.Int(stands.Count) : -1;\n\n\t\t\tforeach (var s in stands) {\n\t\t\t\tvar stand = new ShopStand();\n\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\tstand.Center = new Vector2(s.X * 16 + 8, s.Y * 16 + 8);\n\n\t\t\t\tvar id = g == i ? \"bk:bucket\" : Items.GenerateAndRemove(i < con && consumablePool.Count > 0 ? consumablePool : pool, null, true);\n\t\t\t\tvar item = Items.CreateAndAdd(id, level.Area, false);\n\n\t\t\t\tif (scourged) {\n\t\t\t\t\titem.Scourged = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tstand.SetItem(item, null);\n\n\t\t\t\tif (pool.Count == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tvar p = stands[Rnd.Int(stands.Count)];\n\t\t\tvar sk = new ShopKeeper();\n\n\t\t\tlevel.Area.Add(sk);\n\t\t\tsk.Center = new Vector2(p.X * 16 + 8, p.Y * 16 + 16);\n\n\t\t\t// Painter.DrawLine(level, new Dot(Left + 1, Top + 1), new Dot(Right - 1, Top + 1), Tiles.RandomFloor());\n\t\t\t\n\t\t\tvar points = new List<Point>();\n\n\t\t\tfor (var x = Left + 2; x < Right - 1; x++) {\n\t\t\t\tvar found = false;\n\n\t\t\t\tforeach (var c in Connected.Values) {\n\t\t\t\t\tif (c.X == x && c.Y == Top) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!found) {\n\t\t\t\t\tpoints.Add(new Point(x, Top + 2));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar props = new List<Entity> {\n\t\t\t\tnew Gramophone()\n\t\t\t};\n\n\t\t\tif (Rnd.Chance(40 + Run.Luck * 7)) {\n\t\t\t\tprops.Add(new RerollMachine());\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(40 + Run.Luck * 7)) {\n\t\t\t\tprops.Add(new VendingMachine());\n\t\t\t}\n\n\t\t\tforeach (var prop in props) {\n\t\t\t\tvar pl = points[Rnd.Int(points.Count)];\n\t\t\t\tpoints.Remove(pl);\n\t\t\t\t\n\t\t\t\tlevel.Area.Add(prop);\n\t\t\t\tprop.CenterX = pl.X * 16 + 8 + Rnd.Int(-4, 4);\n\t\t\t\tprop.Bottom = pl.Y * 16;\n\n\t\t\t\tif (points.Count == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar tt = Tiles.RandomFloor();\n\t\t\t\n\t\t\tPainter.Call(level, this, 1, (x, y) => {\n\t\t\t\tif (level.Get(x, y).Matches(Tile.SpikeOffTmp, Tile.SensingSpikeTmp, Tile.Chasm, Tile.Lava)) {\n\t\t\t\t\tlevel.Set(x, y, tt);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar letters = new[] {'a', 'b', 'c'};\n\t\t\tvar spr = $\"mat_{letters[Rnd.Int(letters.Length)]}\";\n\t\t\t\n\t\t\tforeach (var pair in Connected) {\n\t\t\t\tif (pair.Key is SubShopRoom) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar door = pair.Value;\n\t\t\t\tvar mat = new SlicedProp(spr, Layers.Entrance);\n\t\t\t\tlevel.Area.Add(mat);\n\n\t\t\t\tif (door.X == Left) {\n\t\t\t\t\tPlaceSign(level, new Vector2(door.X * 16 - 8, door.Y * 16 - 5));\n\t\t\t\t\tmat.Center = new Vector2(door.X * 16 - 8, door.Y * 16 + 8);\n\t\t\t\t} else if (door.X == Right) {\n\t\t\t\t\tPlaceSign(level, new Vector2(door.X * 16 + 24, door.Y * 16 - 5));\n\t\t\t\t\tmat.Center = new Vector2(door.X * 16 + 24, door.Y * 16 + 8);\n\t\t\t\t} else if (door.Y == Top) {\n\t\t\t\t\tmat.Center = new Vector2(door.X * 16 + 8, door.Y * 16 - 8);\n\t\t\t\t} else {\n\t\t\t\t\tmat.Center = new Vector2(door.X * 16 + 8, door.Y * 16 + 24);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PlaceSign(Level level, Vector2 where) {\n\t\t\tvar sign = new ShadowedProp(\"shop_sign\");\n\t\t\tlevel.Area.Add(sign);\n\t\t\tsign.BottomCenter = where;\n\t\t}\n\n\t\tprotected List<Point> ValidateStands(Level level, List<Point> stands) {\n\t\t\tvar list = new List<Point>();\n\n\t\t\tfor (var i = 0; i < stands.Count; i++) {\n\t\t\t\tvar found = false;\n\t\t\t\tvar p = stands[i];\n\t\t\t\tvar t = level.Get(p.X, p.Y);\n\t\t\t\t\n\t\t\t\tif (t.IsWall() || t == Tile.Chasm) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var j = i + 1; j < stands.Count; j++) {\n\t\t\t\t\tvar s = stands[j];\n\n\t\t\t\t\t// Check if 2 stands are on the same tile\n\t\t\t\t\tif (s.X == p.X && s.Y == p.Y) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if 2 stands are too close\n\t\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\t\tif (s.X + (int) d.X == p.X && s.Y + (int) d.Y == p.Y) {\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\tlist.Add(p);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn list;\n\t\t}\n\n\t\tprotected virtual List<Point> GenerateStands() {\n\t\t\tvar list = new List<Point>();\n\n\t\t\tvar sides = new bool[4];\n\t\t\tvar count = 0;\n\n\t\t\twhile (count < 2) {\n\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\tif (Rnd.Chance(80)) {\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t\tsides[i] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var x = Left + (Rnd.Chance() ? 2 : 3); x < Right - 2; x += 2) {\n\t\t\t\tif (sides[0]) {\n\t\t\t\t\tlist.Add(new Point(x, Top + 3));\n\t\t\t\t}\n\n\t\t\t\tif (sides[1]) {\n\t\t\t\t\tlist.Add(new Point(x, Bottom - 2));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (var y = Top + (Rnd.Chance() ? 3 : 4); y < Bottom - 2; y += 2) {\n\t\t\t\tif (sides[2]) {\n\t\t\t\t\tlist.Add(new Point(Left + 2, y));\n\t\t\t\t}\n\n\t\t\t\tif (sides[3]) {\n\t\t\t\t\tlist.Add(new Point(Right - 2, y));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn list;\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected) {\n\t\t\t\tdoor.Value.Type = door.Key is SubShopRoom || (Run.Depth == 5 && Run.Loop == 0 && LevelSave.GenerateMarket) || Run.Type == RunType.BossRush || Rnd.Chance(2) ? DoorPlaceholder.Variant.Enemy : DoorPlaceholder.Variant.Shop;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(Connection direction) {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/sub/ProtoShopRoom.cs",
    "content": "using BurningKnight.level.entities.chest;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.shop.sub {\n\tpublic class ProtoShopRoom : SubShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.Fill(level, this, Rnd.Int(2, 4), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\n\t\t\tvar chest = new ProtoChest();\n\t\t\tlevel.Area.Add(chest);\n\t\t\tchest.BottomCenter = GetTileCenter() * 16 + new Vector2(8);\n\t\t}\n\t\t\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/sub/SnekShopRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.shop.sub {\n\tpublic class SnekShopRoom : SubShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tSnek.Place(GetTileCenter() * 16 + new Vector2(8, 0), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/sub/StorageRoom.cs",
    "content": "using System;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.shop.sub {\n\tpublic class StorageRoom : SubShopRoom {\n\t\tprivate static string[] infos = {\n\t\t\t\"box_a\",\n\t\t\t\"box_b\",\n\t\t\t\"crate_a\",\n\t\t\t\"crate_b\"\n\t\t};\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tvar spot = new Dot(Rnd.Int(Left + 2, Right - 2), Rnd.Int(Top + 2, Bottom - 2));\n\n\t\t\ttry {\n\t\t\t\tChestRegistry.PlaceRandom(spot * 16 + new Vector2(8, 12), level.Area);\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tfor (var x = Left + 1; x < Right - 1; x++) {\n\t\t\t\tfor (var y = Top + 1; y < Bottom - 1; y++) {\n\t\t\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar prop = new BreakableProp {\n\t\t\t\t\t\tSprite = infos[Rnd.Int(infos.Length)]\n\t\t\t\t\t};\n\n\t\t\t\t\tlevel.Area.Add(prop);\n\t\t\t\t\tprop.BottomCenter = new Vector2(x + 0.5f, y + 1f) * 16 + Rnd.Vector(-4, 4);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, spot, Tile.FloorD);\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Locked;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/sub/SubShopRoom.cs",
    "content": "using BurningKnight.level.rooms.special;\n\nnamespace BurningKnight.level.rooms.shop.sub {\n\tpublic class SubShopRoom : SpecialRoom {\n\t\n\t\tpublic override bool CanConnect(RoomDef R) {\n\t\t\tif (!(R is ShopRoom || R is SubShopRoom)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 8;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/shop/sub/VampireShopRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.shop.sub {\n\tpublic class VampireShopRoom : SubShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tVampire.Place(GetTileCenter() * 16 + new Vector2(8), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/ChargerRoom.cs",
    "content": "using BurningKnight.level.entities;\nusing BurningKnight.level.entities.machine;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class ChargerRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar charger = new Charger();\n\t\t\tlevel.Area.Add(charger);\n\t\t\tcharger.BottomCenter = GetCenterVector();\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 10;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/DarkMarketEntranceRoom.cs",
    "content": "using BurningKnight.entity.door;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class DarkMarketEntranceRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar hw = (int) ((GetWidth() - 1) / 2f);\n\n\t\t\tvar entrance = new HiddenEntrance {\n\t\t\t\tid = \"dm\"\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(entrance);\n\t\t\tentrance.Position = new Vector2(Left + hw, Top + 2) * 16;\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, new Rect(Left + 1, Top + 1).Resize(GetWidth() - 2, 3), Tiles.Pick(Tile.WallA, Tile.Chasm, Tile.Planks, Tile.WallB));\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, new Rect(Left + hw - 1, Top + 1).Resize(3, 3), Rnd.Chance(10) ? Tile.FloorD : Tiles.RandomFloor());\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Top + 4), new Dot(Right - 1, Top + 4), LevelSave.BiomeGenerated is IceBiome ? Tile.WallB : Tile.WallA);\n\n\t\t\tvar d = new Dot(Left + hw, Top + 4);\n\t\t\tPainter.Set(level, d, Tiles.RandomFloor());\n\n\t\t\tvar door = new HeadDoor();\n\t\t\t\n\t\t\tlevel.Area.Add(door);\n\n\t\t\tvar offset = door.GetOffset();\n\n\t\t\tdoor.CenterX = d.X * 16 + 8 + offset.X;\n\t\t\tdoor.Bottom = d.Y * 16 + 17.01f + offset.Y - 8; // .1f so that it's depth sorted to the front of the wall\n\n\t\t\tvar sign = new Sign();\n\t\t\tlevel.Area.Add(sign);\n\t\t\tsign.SetMessage(\"darkmarket_tip\");\n\t\t\tsign.Bottom = d.Y * 16 + 24;\n\t\t\tsign.CenterX = d.X * 16 - 16;\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right || P.Y == Top) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\t\t\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 15;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/DesertWellRoom.cs",
    "content": "using System;\r\nusing BurningKnight.level.rooms.regular;\r\nusing BurningKnight.level.tile;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.level.rooms.special {\r\n\tpublic class DesertWellRoom : RegularRoom {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tPainter.Fill(level, this, Tile.Grass);\r\n\r\n\t\t\tif (GetWidth() * GetHeight() < 25) {\r\n\t\t\t\tPainter.Set(level, GetCenter(), Tile.Water);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar smallest = Math.Min(GetWidth(), GetHeight());\r\n\t\t\tvar floorW = (int) Math.Sqrt(smallest);\r\n\t\t\tvar edgeFloorChance = (float) Math.Sqrt(smallest) % 1;\r\n\r\n\t\t\tedgeFloorChance = (edgeFloorChance + (floorW - 1) * 0.5f) / (float) floorW;\r\n\r\n\t\t\tfor (var y = Top + 2; y < Bottom - 2; y++) {\r\n\t\t\t\tfor (var x = Left + 2; x < Right - 2; x++) {\r\n\t\t\t\t\tvar v = Math.Min(y - Top, Bottom - y);\r\n\t\t\t\t\tvar h = Math.Min(x - Left, Right - x);\r\n\r\n\t\t\t\t\tif (Math.Min(v, h) > floorW || (Math.Min(v, h) == floorW && Rnd.Float() > edgeFloorChance)) {\r\n\t\t\t\t\t\tPainter.Set(level, x, y, Tile.Water);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tPainter.PlacePlants(level, this);\r\n\t\t\tPainter.PlaceTrees(level, this);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/HeartRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class HeartRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tPainter.Fill(level, this, Tiles.Pick(Tile.WallA, Tile.Chasm));\n\n\t\t\tvar c = GetTileCenter();\n\t\t\tvar s = (GetWidth() - 1) / 2;\n\n\t\t\tvar f = Tiles.RandomFloor();\n\t\t\t\n\t\t\tPainter.Triangle(level, new Dot(c.X, Bottom - 1), new Dot(Left + 1, c.Y), new Dot(Right, c.Y), f);\n\t\t\tPainter.FillEllipse(level, c.X - s + 1, c.Y - s / 2 - 1, s, s, f);\n\t\t\tPainter.FillEllipse(level, c.X, c.Y - s / 2 - 1, s, s, f);\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomNewFloor(), GetCenterRect());\n\t\t\t\n\t\t\tvar stand = new HealthStand();\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = c * 16 + new Vector2(8);\n\t\t\t\n\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemType.Artifact, data => data.Quality == ItemQuality.Wooden && data.Id != \"bk:pass\"), level.Area), null);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t\t\n\t\tprotected override int ValidateHeight(int H) {\n\t\t\treturn H % 2 == 0 ? H : H - 1;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/IdolTrapRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.tile;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class IdolTrapRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Rect(level, this, 2, Tile.FloorD);\n\n\t\t\tvar stand = new ItemStand();\n\t\t\tlevel.Area.Add(stand);\n\t\t\t\n\t\t\tstand.BottomCenter = GetCenterVector();\n\t\t\tstand.SetItem(Items.CreateAndAdd(\"bk:idol\", level.Area), null);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/LockedRoom.cs",
    "content": "namespace BurningKnight.level.rooms.special {\n\tpublic class LockedRoom : SpecialRoom {\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Locked;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/NpcKeyRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item.stand;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class NpcKeyRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar stand = new ItemStand();\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = GetTileCenter() * 16 + new Vector2(8);\n\t\t\t\n\t\t\tstand.SetItem(Items.CreateAndAdd(\"bk:cage_key\", level.Area), null);\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 6;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/NpcSaveRoom.cs",
    "content": "using System;\r\nusing System.Linq;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.entity.creature.npc;\r\nusing BurningKnight.entity.creature.npc.dungeon;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.special {\r\n\tpublic class NpcSaveRoom : SpecialRoom {\r\n\t\tprivate class NpcData {\r\n\t\t\tpublic NpcData(byte d, string i) {\r\n\t\t\t\tDepth = d;\r\n\t\t\t\tId = i;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tpublic byte Depth;\r\n\t\t\tpublic string Id;\r\n\t\t}\r\n\t\t\r\n\t\tprivate static NpcData[] npcs = {\r\n\t\t\tnew NpcData(2, ShopNpc.HatTrader),\r\n\t\t\tnew NpcData(2, ShopNpc.AccessoryTrader),\r\n\t\t\tnew NpcData(3, ShopNpc.ActiveTrader),\r\n\t\t\tnew NpcData(3, ShopNpc.WeaponTrader),\r\n\t\t\tnew NpcData(4, ShopNpc.Snek),\r\n\t\t\tnew NpcData(4, ShopNpc.Boxy),\r\n\t\t\tnew NpcData(5, ShopNpc.Duck),\r\n\t\t\tnew NpcData(6, ShopNpc.Vampire),\r\n\t\t\tnew NpcData(7, ShopNpc.Elon),\r\n\t\t\tnew NpcData(8, ShopNpc.Gobetta),\r\n\t\t\tnew NpcData(9, ShopNpc.Nurse),\r\n\t\t\tnew NpcData(10, ShopNpc.Roger),\r\n\t\t\tnew NpcData(10, ShopNpc.Mike)\r\n\t\t};\r\n\t\t\r\n\t\tpublic override int GetMaxConnections(Connection Side) {\r\n\t\t\treturn 1;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinConnections(Connection Side) {\r\n\t\t\treturn Side == Connection.All ? 1 : 0;\r\n\t\t}\r\n\r\n\t\tpublic override bool CanConnect(RoomDef R) {\r\n\t\t\treturn base.CanConnect(R) && !(R is NpcKeyRoom);\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tprivate static bool DefeatedBosses() {\r\n\t\t\treturn Achievements.IsComplete(\"bk:democracy\") && Achievements.IsComplete(\"bk:mummified\") && Achievements.IsComplete(\"bk:ice_boss\") && Achievements.IsComplete(\"bk:bk_no_more\") && Achievements.IsComplete(\"bk:sting_operation\");\r\n\t\t}\r\n\r\n\t\tprivate static string GenerateNpc() {\r\n\t\t\tvar d = Run.Depth;\r\n\r\n\t\t\tforeach (var info in npcs) {\r\n\t\t\t\tif (info.Depth == d && GlobalSave.IsFalse(info.Id)) {\r\n\t\t\t\t\tif (info.Id == ShopNpc.Mike && !DefeatedBosses()) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tLog.Info($\"Npc {info.Id} should be generated\");\r\n\t\t\t\t\treturn info.Id;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tLog.Info($\"No npc should be generated\");\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tvar ice = LevelSave.BiomeGenerated is IceBiome;\r\n\t\t\r\n\t\t\tif (ice) {\r\n\t\t\t\tvar clip = Painter.Clip;\r\n\t\t\t\tPainter.Clip = null;\r\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\r\n\t\t\t\tPainter.Clip = clip;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar id = GenerateNpc();\r\n\r\n\t\t\tif (id == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tGameSave.Put(\"npc_appeared\", true);\r\n\r\n\t\t\tvar d = Connected.Values.First();\r\n\t\t\tvar npc = ShopNpc.FromId(id);\r\n\t\t\tlevel.Area.Add(npc);\r\n\r\n\t\t\tvar fl = Tiles.RandomFloorOrSpike();\r\n\t\t\t\r\n\t\t\tif (d.X == Left || d.X == Right) {\r\n\t\t\t\tvar w = (int) (GetWidth() / 2f + Rnd.Int(-1, 1));\r\n\t\t\t\tvar door = new Dot(Left + w, Rnd.Int(Top + 2, Bottom - 2));\r\n\t\t\t\t\r\n\t\t\t\tPainter.DrawLine(level, new Dot(Left + w, Top), new Dot(Left + w, Bottom), ice ? Tile.WallB : Tile.WallA);\r\n\t\t\t\tPainter.Set(level, door, fl);\r\n\t\t\t\t\r\n\t\t\t\tnpc.Center = new Dot(Left + w + (d.X == Left ? 2 : -2), Rnd.Int(Top + 2, Bottom - 3)) * 16 + new Vector2(8);\r\n\r\n\t\t\t\tvar dr = new CageDoor {\r\n\t\t\t\t\tVertical = true\r\n\t\t\t\t};\r\n\t\t\t\t\r\n\t\t\t\tdr.Center = door * 16 + new Vector2(12, 0);\r\n\t\t\t\tlevel.Area.Add(dr);\r\n\t\t\t\t\r\n\t\t\t\tvar v = (d.X == Left ? -1 : 1);\r\n\t\t\t\t\r\n\t\t\t\tPainter.DrawLine(level, new Dot(Left + w + v, Top + 1), new Dot(Left + w + v, Bottom - 1), Tiles.Pick(Tile.Chasm, Tile.Lava, Tile.SensingSpikeTmp));\r\n\t\t\t\tPainter.Set(level, door + new Dot(v, 0), fl);\r\n\t\t\t} else if (true) {\r\n\t\t\t\tvar h = (int) (GetHeight() / 2f + Rnd.Int(-1, 1));\r\n\t\t\t\tvar door = new Dot(Rnd.Int(Left + 2, Right - 2), Top + h);\r\n\r\n\t\t\t\tPainter.DrawLine(level, new Dot(Left, Top + h), new Dot(Right, Top + h), Tile.WallA);\r\n\t\t\t\tPainter.Set(level, door, fl);\r\n\t\t\t\t\r\n\t\t\t\tnpc.Center = new Dot(Rnd.Int(Left + 2, Right - 2), Top + h + (d.Y == Top ? 2 : -2)) * 16 + new Vector2(8);\r\n\t\t\t\t\r\n\t\t\t\tvar dr = new CageDoor();\r\n\t\t\t\tdr.Center = door * 16 + new Vector2(7, 8);\r\n\t\t\t\tlevel.Area.Add(dr);\r\n\r\n\t\t\t\tvar v = (d.Y == Top ? -1 : 1);\r\n\t\t\t\t\r\n\t\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Top + h + v), new Dot(Right - 1, Top + h + v), Tiles.Pick(Tile.Chasm, Tile.Lava, Tile.SensingSpikeTmp));\r\n\t\t\t\tPainter.Set(level, door + new Dot(0, v), fl);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static bool ShouldBeAdded() {\r\n\t\t\tif (Run.Type != RunType.Regular || GameSave.IsTrue(\"npc_appeared\")) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\treturn GenerateNpc() != null;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/ProtoChestRoom.cs",
    "content": "using BurningKnight.level.entities.chest;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class ProtoChestRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.Fill(level, this, Rnd.Int(2, 4), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\n\t\t\tvar chest = new ProtoChest();\n\t\t\tlevel.Area.Add(chest);\n\t\t\tchest.BottomCenter = GetTileCenter() * 16 + new Vector2(8);\n\t\t}\n\t\t\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/SafeRoom.cs",
    "content": "using BurningKnight.level.entities;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class SafeRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar safe = new Safe();\n\t\t\tlevel.Area.Add(safe);\n\t\t\tsafe.BottomCenter = GetCenterVector();\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 10;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/SpecialRoom.cs",
    "content": "using BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class SpecialRoom : RoomDef {\n\t\tpublic override void Paint(Level level) {\n\t\t\tvar ice = LevelSave.BiomeGenerated is IceBiome;\n\t\t\n\t\t\tif (ice) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 8;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxConnections(Connection Side) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tpublic override int GetMinConnections(Connection Side) {\n\t\t\tif (Side == Connection.All) return 1;\n\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/TombRoom.cs",
    "content": "using System.Collections.Generic;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.special {\r\n\tpublic class TombRoom : SpecialRoom {\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 7;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn 8;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 7;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn 8;\r\n\t\t}\r\n\r\n\t\tpublic static void Insert(List<RoomDef> rooms) {\r\n\t\t\tif ((Run.Type == RunType.Regular || Run.Type == RunType.Twitch) && !Run.CustomSeed && GlobalSave.GetInt(\"tomb_depth\") == Run.Depth) {\r\n\t\t\t\tLog.Info(\"Adding tombstone\");\r\n\t\t\t\trooms.Add(new TombRoom());\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tbase.Paint(level);\r\n\t\t\t\r\n\t\t\tvar tomb = new Tombstone();\r\n\r\n\t\t\ttomb.Item = GlobalSave.GetString(\"next_tomb\") ?? \"bk:coin\";\r\n\t\t\tGlobalSave.Put(\"tomb_depth\", 0);\r\n\t\t\t\r\n\t\t\tlevel.Area.Add(tomb);\r\n\t\t\ttomb.Center = GetCenter() * 16 + new Vector2(8);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/VendingRoom.cs",
    "content": "using BurningKnight.level.entities.machine;\n\nnamespace BurningKnight.level.rooms.special {\n\tpublic class VendingRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar machine = new VendingMachine();\n\t\t\tlevel.Area.Add(machine);\n\t\t\tmachine.BottomCenter = GetCenterVector();\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 10;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/minigame/ChestMinigameRoom.cs",
    "content": "using BurningKnight.entity.creature.npc;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.floors;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.minigame {\n\tpublic class ChestMinigameRoom : SpecialRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\tFloorRegistry.Paint(level, this, -1, true);\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\t/*\n\t\t\t * todo: a rare variant that spawns below certaint depth with rainbow chests and the cost set to constant 69\n\t\t\t */\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tvar tt = Tiles.RandomFloor();\n\t\t\t\t\t\n\t\t\t\t\tPainter.Set(level, Left + 2, Top + 2, tt, true);\n\t\t\t\t\tPainter.Set(level, Right - 2, Top + 2, tt, true);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar t = Tiles.Pick(Tile.WallA, Tile.Chasm, Tile.SensingSpikeTmp, Tile.Planks);\n\t\t\t\t\n\t\t\t\tPainter.Set(level, Left + 2, Top + 2, t);\n\t\t\t\tPainter.Set(level, Right - 2, Top + 2, t);\n\t\t\t}\n\n\t\t\tvar maanex = new Maanex();\n\t\t\tlevel.Area.Add(maanex);\n\t\t\tmaanex.BottomCenter = new Vector2(Left + 4.5f, Top + 2) * 16;\n\n\t\t\tvar prize = Rnd.Int(4);\n\t\t\t\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tvar chest = new WoodenChest();\n\t\t\t\tlevel.Area.Add(chest);\n\n\t\t\t\tchest.Empty = i != prize;\n\t\t\t\tchest.BottomCenter = new Vector2(Left + 2.5f + i * 2, Bottom - 1.5f) * 16;\n\t\t\t}\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 9;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 10;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 8;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/minigame/ClawMinigameRoom.cs",
    "content": "using BurningKnight.assets.prefabs;\nusing BurningKnight.level.tile;\n\nnamespace BurningKnight.level.rooms.special.minigame {\n\tpublic class ClawMinigameRoom : SpecialRoom {\n\t\tprivate const string PrefabName = \"mclaw\";\n\t\tprivate Prefab prefab;\n\n\t\tpublic ClawMinigameRoom() {\n\t\t\tprefab = Prefabs.Get(PrefabName);\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tvar clip = Painter.Clip;\n\t\t\t\n\t\t\tPainter.Clip = null;\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Clip = clip;\n\t\t\t\n\t\t\tPainter.Prefab(level, PrefabName, Left + 1, Top + 1);\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn prefab.Level.Width + 2;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn prefab.Level.Width + 3;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn prefab.Level.Height + 2;\n\t\t}\n\t\t\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn prefab.Level.Height + 3;\n\t\t}\n\t\t\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\td.Type = DoorPlaceholder.Variant.Red;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/npc/DuckRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\n\nnamespace BurningKnight.level.rooms.special.npc {\n\tpublic class DuckRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tDungeonDuck.Place(GetCenter() * 16, level.Area);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 5;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 6;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/npc/ElonRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\n\nnamespace BurningKnight.level.rooms.special.npc {\n\tpublic class ElonRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tDungeonElon.Place(GetCenter() * 16, level.Area);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 11;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/npc/NurseRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\n\nnamespace BurningKnight.level.rooms.special.npc {\n\tpublic class NurseRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tNurse.Place(GetCenter() * 16, level.Area);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 6;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 7;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/npc/VampireRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.npc {\n\tpublic class VampireRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tVampire.Place(GetTileCenter() * 16 + new Vector2(8), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/BoxyShopRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.shop {\n\tpublic class BoxyShopRoom : NpcShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tBoxy.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/GobettaShopRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.shop {\n\tpublic class GobettaShopRoom : NpcShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tGobetta.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/NpcShopRoom.cs",
    "content": "namespace BurningKnight.level.rooms.special.shop {\n\tpublic class NpcShopRoom : SpecialRoom {\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 7;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/RogerShopRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.shop {\n\tpublic class RogerShopRoom : NpcShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tRoger.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/SnekRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.shop {\n\tpublic class SnekRoom: NpcShopRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tSnek.Place(GetTileCenter() * 16 + new Vector2(8, 0), level.Area);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/shop/TrashGoblinRoom.cs",
    "content": "using BurningKnight.entity.creature.npc.dungeon;\nusing BurningKnight.level.entities;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.shop {\n\tpublic class TrashGoblinRoom : NpcShopRoom {\n\t\tprivate static string[] infos = {\n\t\t\t\"box_a\",\n\t\t\t\"box_b\",\n\t\t\t\"box_c\",\n\t\t\t\"box_d\",\n\t\t\t\"crate_a\",\n\t\t\t\"crate_b\"\n\t\t};\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tTrashGoblin.Place(GetTileCenter() * 16 + new Vector2(8, 8), level.Area);\n\t\t\t\n\t\t\tfor (var x = Left + 1; x < Right - 1; x++) {\n\t\t\t\tfor (var y = Top + 1; y < Bottom - 1; y++) {\n\t\t\t\t\tif (Rnd.Chance(50)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar prop = new BreakableProp {\n\t\t\t\t\t\tSprite = infos[Rnd.Int(infos.Length)]\n\t\t\t\t\t};\n\n\t\t\t\t\tlevel.Area.Add(prop);\n\t\t\t\t\tprop.BottomCenter = new Vector2(x + 0.5f, y + 1f) * 16 + Rnd.Vector(-4, 4);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/ChestStatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class ChestStatueRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new ChestStatue();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/DiceStatueRoom.cs",
    "content": "namespace BurningKnight.level.rooms.special.statue {\n\tpublic class DiceStatueRoom : StatueRoom {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/FountainRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class FountainRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new Fountain();\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/ScourgeStatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class ScourgeStatueRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new ScourgeStatue();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/StatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class StatueRoom : SpecialRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\t\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.Fill(level, this, Rnd.Int(2, 4), Tiles.RandomFloor());\n\t\t\t\n\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\n\t\t\tvar statue = GetStatue();\n\t\t\tlevel.Area.Add(statue);\n\t\t\tstatue.BottomCenter = GetTileCenter() * 16 + new Vector2(8);\n\t\t}\n\n\t\tprotected virtual Statue GetStatue() {\n\t\t\treturn new DiceStatue();\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 13;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 16;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 16;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/StoneStatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class StoneStatueRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new StoneStatue();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/SwordStatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class SwordStatueRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new SwordStatue();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/WarriorStatueRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class WarriorStatueRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new WarriorStatue();\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/special/statue/WellRoom.cs",
    "content": "using BurningKnight.level.entities.statue;\n\nnamespace BurningKnight.level.rooms.special.statue {\n\tpublic class WellRoom : StatueRoom {\n\t\tprotected override Statue GetStatue() {\n\t\t\treturn new Well();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/spiked/SpikedRoom.cs",
    "content": "using BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.entities.chest;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.spiked {\n\tpublic class SpikedRoom : SpecialRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tif (LevelSave.BiomeGenerated is IceBiome) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, this, 1, Tile.EvilWall);\n\t\t\tPainter.Fill(level, this, 2, Tile.EvilFloor);\n\t\t\t\n\t\t\tPaintTunnel(level, Tile.EvilFloor);\n\n\t\t\tvar center = GetCenter() * 16 + new Vector2(8);\n\n\t\t\tswitch (Rnd.Int(4)) {\n\t\t\t\tcase 0: {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 3); i++) {\n\t\t\t\t\t\tItems.CreateAndAdd(\"bk:heart\", level.Area).Center = center;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 1: {\n\t\t\t\t\tfor (var i = 0; i < Rnd.Int(1, 4); i++) {\n\t\t\t\t\t\tItems.CreateAndAdd(\"bk:shield\", level.Area).Center = center;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 2: {\n\t\t\t\t\tvar stand = new ItemStand();\n\t\t\t\t\tlevel.Area.Add(stand);\n\t\t\t\t\tstand.BottomCenter = center;\n\t\t\t\t\tstand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.SpikedRoom), level.Area), null);\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 3: {\n\t\t\t\t\tvar a = Rnd.Chance();\n\t\t\t\t\tvar c = Rnd.Int(1, a ? 3 : 4);\n\n\t\t\t\t\tfor (var i = 0; i < c; i++) {\n\t\t\t\t\t\tvar chest = a ? (Chest) new StoneChest() : new RedChest();\n\t\t\t\t\t\tlevel.Area.Add(chest);\n\t\t\t\t\t\tchest.BottomCenter = center - new Vector2((c / 2f - i) * 20, 0);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = DoorPlaceholder.Variant.Spiked;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right || P.X == Left + 1 || P.X == Right - 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/CrossTurretPassageRoom.cs",
    "content": "using System;\nusing System.Linq;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class CrossTurretPassageRoom : TrapRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:trap\");\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 22;\n\t\t}\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void Line(Level level, Dot a, Dot b) {\n\t\t\tPainter.DrawLine(level, a, b, Tiles.RandomFloor(), true);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.DrawLine(level, a, b, Tiles.RandomFloor());\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\n\t\t\tvar tx = Left + GetWidth() / 2;\n\t\t\tvar ty = Top + GetHeight() / 2;\n\n\t\t\tLine(level, new Dot(tx, Top + 2), new Dot(tx, Bottom - 2));\n\t\t\tLine(level, new Dot(Left + 2, ty), new Dot(Right - 2, ty));\n\n\t\t\tvar a = Rnd.Chance();\n\n\t\t\tif (a) {\n\t\t\t\tPlaceButton(level, new Dot(Left + 2, ty));\n\t\t\t\tPlaceButton(level, new Dot(Right - 2, ty));\n\t\t\t}\n\n\t\t\tif (!a || Rnd.Chance()) {\n\t\t\t\tPlaceButton(level, new Dot(tx, Top + 2));\n\t\t\t\tPlaceButton(level, new Dot(tx, Bottom - 2));\n\t\t\t}\n\n\t\t\tvar s = 2; // Rnd.Int(2, 4);\n\t\t\tvar cx = Left + GetWidth() / 2;\n\t\t\tvar cy = Top + GetHeight() / 2;\n\n\t\t\t#region Wave Generator\n\t\t\tvar xsmooth = Rnd.Chance(30);\n\t\t\tvar xmod = Rnd.Float(s * 8, s * 16);\n\t\t\tvar ysmooth = Rnd.Chance(30);\n\t\t\tvar ymod = Rnd.Chance(30) ? xmod : Rnd.Float(s * 32, s * 64);\n\n\t\t\tvar fn = new Func<int, int, float>((x, y) => {\n\t\t\t\tvar t = 0f;\n\n\t\t\t\tif (!xsmooth) {\n\t\t\t\t\tt += (float) Math.Cos(x / xmod);\n\t\t\t\t}\n\n\t\t\t\tif (!ysmooth) {\n\t\t\t\t\tt += (float) Math.Sin(y / ymod);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn MathUtils.Mod(t * 3, 3);\n\t\t\t});\n\t\t\t#endregion\n\n\t\t\tvar p = 1;\n\t\t\t\n\t\t\tfor (var x = Left + 3; x < Right - 2; x += s) {\n\t\t\t\tif (x >= cx - p && x <= cx + p) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPlace(level, x, Top + 1, 2, fn(x, Top + 1));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Left + 3; x < Right - 2; x += s) {\n\t\t\t\tif (x >= cx - p && x <= cx + p) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPlace(level, x, Bottom - 1, 6, fn(x, Bottom - 1));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Top + 3; x < Bottom - 2; x += s) {\n\t\t\t\tif (x >= cy - p && x <= cy + p) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPlace(level, Left + 1, x, 0, fn(x, Left + 1));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Top + 3; x < Bottom - 2; x += s) {\n\t\t\t\tif (x >= cy - p && x <= cy + p) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPlace(level, Right - 1, x, 4, fn(x, Right - 1));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\tif (Math.Abs(P.Y - (Top + GetHeight() / 2)) > 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Math.Abs(P.X - (Left + GetWidth() / 2)) > 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tprivate bool Place(Level level, int x, int y, uint a, float offset) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif ((d.X == x && (d.Y == y + 1 || d.Y == y - 1)) || (d.Y == y && (d.X == x + 1 || d.X == x - 1))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, x, y, Tile.FloorA);\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(x, y) * 16,\n\t\t\t\tStartingAngle = a,\n\t\t\t\tTimingOffset = offset,\n\t\t\t\tSpeed = 1.5f\n\t\t\t});\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void PlaceButton(Level level, Dot where) {\n\t\t\tPainter.Set(level, where, Tiles.RandomFloor());\n\n\t\t\tvar input = new Button();\n\t\t\tinput.Position = where * 16;\n\t\t\tlevel.Area.Add(input);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/DangerousPadsRoom.cs",
    "content": "using System;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class DangerousPadsRoom : TrapRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\n\t\t\tvar gap = 2;\n\t\t\t\n\t\t\tvar xcollumn = Rnd.Int(2, 5);\n\t\t\tvar ycollumn = Rnd.Chance(20) ? Rnd.Int(2, 5) : xcollumn;\n\t\t\tvar w = GetWidth();\n\t\t\tvar h = GetHeight();\n\t\t\tvar gx = (gap + xcollumn);\n\t\t\tvar gy = (gap + ycollumn);\n\n\t\t\tvar xcount = (int) Math.Ceiling((w - (float) xcollumn) / gx);\n\t\t\tvar ycount = (int) Math.Ceiling((h - (float) ycollumn) / gy);\n\n\t\t\tvar xw = xcount * gx - xcollumn;\n\t\t\tvar yw = ycount * gy - ycollumn;\n\n\t\t\tvar xo = (int) Math.Min(Math.Floor((w - xw) / 2f), 2);\n\t\t\tvar yo = (int) Math.Min(Math.Floor((h - yw) / 2f), 2);\n\t\t\t\n\t\t\tfor (var x = 0; x < xcount; x++) {\n\t\t\t\tfor (var y = 0; y < ycount; y++) {\n\t\t\t\t\tPainter.Fill(level, new Rect(\n\t\t\t\t\t\tLeft + xo + x * gx, \n\t\t\t\t\t\tTop + yo + y * gy\n\t\t\t\t\t).Resize(xcollumn, ycollumn), Rnd.Chance(5) ? Tiles.RandomFloor() : Tile.SensingSpikeTmp);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tPainter.Fill(level, new Rect(d.X - 2, d.Y - 2, d.X + 3, d.Y + 3), Tiles.RandomFloor());\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 20;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 28;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 28;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/FollowingSpikeBallRoom.cs",
    "content": "using BurningKnight.entity.room;\r\nusing BurningKnight.entity.room.input;\r\nusing BurningKnight.level.tile;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.level.rooms.trap {\r\n\tpublic class FollowingSpikeBallRoom : TrapRoom {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\tbase.Paint(level);\r\n\t\t\tPainter.Fill(level, this, 1, Tile.SpikeOffTmp);\r\n\r\n\t\t\tif (Rnd.Chance()) {\r\n\t\t\t\tvar c = GetTileCenter();\r\n\t\t\t\tPainter.Set(level, c, Tiles.RandomFloor());\r\n\r\n\t\t\t\tlevel.Area.Add(new Button {\r\n\t\t\t\t\tPosition = c * 16\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void ModifyRoom(Room room) {\r\n\t\t\tbase.ModifyRoom(room);\r\n\t\t\troom.AddController(\"bk:following_spike_ball\");\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/RollingSpikesRoom.cs",
    "content": "using BurningKnight.entity.room.controllable;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class RollingSpikesRoom : TrapRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tvar a = 0;\n\t\t\t\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif (d.Type != DoorPlaceholder.Variant.Secret) {\n\t\t\t\t\tvar w = 2;\n\t\t\t\t\tvar h = 2;\n\t\t\t\t\t\n\t\t\t\t\tPainter.Fill(level, d.X - w, d.Y - w, w * 2 + 1, h * 2 + 1, Tile.Chasm);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tfor (var i = Left + 2; i < Right - 1; i += 2) {\n\t\t\t\t\tvar y = a % 2 == 0 ? Top + 2 : Bottom - 3;\n\t\t\t\t\t\n\t\t\t\t\tif (!level.Get(i, y).IsPassable()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar spike = new RollingSpike();\n\n\t\t\t\t\tspike.Center = new Vector2(i, y) * 16 + new Vector2(8, 8);\n\t\t\t\t\tspike.StartVelocity = new Vector2(0, (a % 2 == 0 ? 1 : -1) * 32);\n\t\t\t\t\n\t\t\t\t\tlevel.Area.Add(spike);\n\t\t\t\t\n\t\t\t\t\ta++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (var i = Top + 2; i < Bottom - 1; i += 2) {\n\t\t\t\t\tvar x = a % 2 == 0 ? Left + 2 : Right - 3;\n\t\t\t\t\t\n\t\t\t\t\tif (!level.Get(x, i).IsPassable()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar spike = new RollingSpike();\n\n\t\t\t\t\tspike.Center = new Vector2(x, i) * 16 + new Vector2(8, 8);\n\t\t\t\t\tspike.StartVelocity = new Vector2((a % 2 == 0 ? 1 : -1) * 32, 0);\n\t\t\t\t\n\t\t\t\t\tlevel.Area.Add(spike);\n\t\t\t\t\n\t\t\t\t\ta++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/SpikeMazeRoom.cs",
    "content": "using BurningKnight.entity.room;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing BurningKnight.util;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class SpikeMazeRoom : TrapRoom {\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:trap\");\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tvar maze = Maze.Generate(this);\n\t\t\t\n\t\t\tfor (int y = 1; y < maze[0].Length - 1; y++) {\n\t\t\t\tfor (int x = 1; x < maze.Length - 1; x++) {\n\t\t\t\t\tif (maze[x][y]) {\n\t\t\t\t\t\tPainter.Set(level, x + Left, y + Top, Tile.SpikeOnTmp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar where = GetTileCenter();\n\t\t\tPainter.Set(level, where, Tiles.RandomFloor());\n\n\t\t\tlevel.Area.Add(new Button {\n\t\t\t\tPosition = where * 16\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/SpikePassageRoom.cs",
    "content": "using BurningKnight.entity.room;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class SpikePassageRoom : TrapRoom {\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tvar m = 1;\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Fill(level, this, m, Tile.Chasm);\n\t\t\t\tm += Rnd.Int(1, 3);\n\t\t\t\tPainter.Fill(level, this, m, Tiles.RandomFloor());\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect(), true);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPaintTunnel(level, Tiles.RandomFloor(), GetCenterRect());\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.FillEllipse(level, this, m, Tile.SpikeOffTmp);\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, this, m, Tile.SpikeOffTmp);\n\t\t\t}\n\n\t\t\tm += Rnd.Int(2, 5);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.FillEllipse(level, this, m, Tiles.RandomFloor());\n\t\t\t} else {\n\t\t\t\tPainter.Fill(level, this, m, Tiles.RandomFloor());\n\t\t\t}\n\n\t\t\tvar c = GetTileCenter();\n\t\t\tPainter.Set(level, c, Tiles.RandomFloor());\n\t\t\t\n\t\t\tvar input = new Button();\n\t\t\tinput.Position = c * 16;\n\t\t\tlevel.Area.Add(input);\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:spike_field\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/TrapRoom.cs",
    "content": "using BurningKnight.level.biome;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.save;\r\n\r\nnamespace BurningKnight.level.rooms.trap {\r\n\tpublic class TrapRoom : RoomDef {\r\n\t\tpublic override void Paint(Level level) {\r\n\t\t\t// Empty to make sure that we dont paint a regular room wall here\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxConnections(Connection Side) {\r\n\t\t\tif (Side == Connection.All) {\r\n\t\t\t\treturn 16;\r\n\t\t\t}\r\n\r\n\t\t\treturn 4;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinConnections(Connection Side) {\r\n\t\t\tif (Side == Connection.All) {\r\n\t\t\t\treturn 2;\r\n\t\t\t}\r\n\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/TurretPassageRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class TurretPassageRoom : TrapRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:trap\");\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Top + 1), new Dot(Left + 1, Bottom - 1), Tiles.RandomFloor(), true);\n\t\t\tPainter.DrawLine(level, new Dot(Right - 1, Top + 1), new Dot(Right - 1, Bottom - 1), Tiles.RandomFloor(), true);\n\n\t\t\tvar ty = Rnd.Int(Top + 2, Bottom - 2);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tty = Top + GetHeight() / 2;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tvar tty = Rnd.Int(Top + 2, Bottom - 2);\n\t\t\t\t\tPainter.DrawLine(level, new Dot(Left + 1, tty), new Dot(Right - 1, tty), Tile.FloorD);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, ty), new Dot(Right - 1, ty), Tiles.RandomFloor(), true);\n\n\t\t\tif (Connected.Count == 1) {\n\t\t\t\tty = Rnd.Int(Top + 2, Bottom - 2);\n\n\t\t\t\tif (Connected.Values.First().X == Left) {\n\t\t\t\t\tPlaceButton(level, new Dot(Right - 1, ty));\n\t\t\t\t} else {\n\t\t\t\t\tPlaceButton(level, new Dot(Left + 1, ty));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar s = Rnd.Int(2, 4);\n\t\t\tvar xm = Rnd.Int(0, s);\n\n\t\t\t#region Wave Generator\n\t\t\tvar xsmooth = Rnd.Chance(30);\n\t\t\tvar xmod = Rnd.Float(s * 8, s * 16);\n\t\t\tvar ysmooth = Rnd.Chance(30);\n\t\t\tvar ymod = Rnd.Chance(30) ? xmod : Rnd.Float(s * 32, s * 64);\n\n\t\t\tvar fn = new Func<int, int, float>((x, y) => {\n\t\t\t\tvar t = 0f;\n\n\t\t\t\tif (!xsmooth) {\n\t\t\t\t\tt += (float) Math.Cos(x / xmod);\n\t\t\t\t}\n\n\t\t\t\tif (!ysmooth) {\n\t\t\t\t\tt += (float) Math.Sin(y / ymod);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn MathUtils.Mod(t * 3, 3);\n\t\t\t});\n\t\t\t#endregion\n\t\t\t\n\t\t\tfor (var x = Left + 3 + xm; x < Right - 2; x += s) {\n\t\t\t\tPlace(level, x, Top + 1, 2, fn(x, Top + 1));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Left + 3 + xm; x < Right - 2; x += s) {\n\t\t\t\tPlace(level, x, Bottom - 1, 6, fn(x, Bottom - 1));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\tif (P.Y == Top + 1 || P.Y == Bottom - 1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else \tif (P.Y == Top || P.Y == Bottom) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tprivate bool Place(Level level, int x, int y, uint a, float offset) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif ((d.X == x && (d.Y == y + 1 || d.Y == y - 1)) || (d.Y == y && (d.X == x + 1 || d.X == x - 1))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, x, y, Tile.FloorA);\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(x, y) * 16,\n\t\t\t\tStartingAngle = a,\n\t\t\t\tTimingOffset = offset,\n\t\t\t\tSpeed = 1.5f\n\t\t\t});\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void PlaceButton(Level level, Dot where) {\n\t\t\tPainter.Set(level, where, Tiles.RandomFloor());\n\n\t\t\tvar input = new Button();\n\t\t\tinput.Position = where * 16;\n\t\t\tlevel.Area.Add(input);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/TurretTrapRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class TurretTrapRoom : TrapRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:trap\");\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.Fill(level, this, 2, Tiles.RandomFloor());\n\n\t\t\tvar s = Rnd.Int(2, 4);\n\t\t\tvar f = Tiles.RandomNewFloor();\n\t\t\tvar ft = Rnd.Chance() ? f : Tiles.RandomNewFloor();\n\t\t\tvar spots = new List<Dot>();\n\t\t\tvar p = Rnd.Int(0, 2);\n\t\t\tvar xm = Rnd.Int(0, s);\n\t\t\tvar ym = Rnd.Int(0, s);\n\n\t\t\tvar xsmooth = Rnd.Chance(30);\n\t\t\tvar xmod = Rnd.Float(s * 8, s * 16);\n\t\t\tvar ysmooth = Rnd.Chance(30);\n\t\t\tvar ymod = Rnd.Chance(30) ? xmod : Rnd.Float(s * 32, s * 64);\n\n\t\t\tvar fn = new Func<int, int, float>((x, y) => {\n\t\t\t\tvar t = 0f;\n\n\t\t\t\tif (!xsmooth) {\n\t\t\t\t\tt += (float) Math.Cos(x / xmod);\n\t\t\t\t}\n\n\t\t\t\tif (!ysmooth) {\n\t\t\t\t\tt += (float) Math.Sin(y / ymod);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn MathUtils.Mod(t * 3, 3);\n\t\t\t});\n\t\t\t\n\t\t\tfor (var x = Left + 2 + xm; x < Right - 2; x += s) {\n\t\t\t\tPainter.DrawLine(level, new Dot(x, Top + 1), new Dot(x, Bottom - 1), f);\n\n\t\t\t\tif (Place(level, x, Top + 1, 2, fn(x, Top + 1))) {\n\t\t\t\t\tspots.Add(new Dot(x, Top + 2 + p));\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Left + 2 + xm; x < Right - 2; x += s) {\n\t\t\t\tif (Place(level, x, Bottom - 1, 6, fn(x, Bottom - 1))) {\n\t\t\t\t\tspots.Add(new Dot(x, Bottom - 2 - p));\n\t\t\t\t}\t\t\n\t\t\t}\n\t\t\t\n\t\t\tfor (var y = Top + 2 + ym; y < Bottom - 2; y += s) {\n\t\t\t\tPainter.DrawLine(level, new Dot(Left + 1, y), new Dot(Right - 1, y), ft);\n\t\t\t\t\n\t\t\t\tif (Place(level, Left + 1, y, 0, fn(Left + 1, y))) {\n\t\t\t\t\tspots.Add(new Dot(Left + 2 + p, y));\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t\n\t\t\tfor (var y = Top + 2 + ym; y < Bottom - 2; y += s) {\n\t\t\t\tif (Place(level, Right - 1, y, 4, fn(Right - 1, y))) {\n\t\t\t\t\tspots.Add(new Dot(Right - 2 - p, y));\n\t\t\t\t}\t\n\t\t\t}\n\n\t\t\tif (Connected.Count > 1 && Rnd.Chance(20)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPlaceButton(level, GetTileCenter());\n\t\t\t} else {\n\t\t\t\tfor (var i = 0; i < Rnd.Int(1, Math.Min(spots.Count, 4)); i++) {\n\t\t\t\t\tvar j = Rnd.Int(spots.Count);\n\n\t\t\t\t\tPlaceButton(level, spots[j]);\n\t\t\t\t\tspots.RemoveAt(j);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PlaceButton(Level level, Dot where) {\n\t\t\tPainter.Set(level, where, Tiles.RandomFloor());\n\n\t\t\tvar input = new Button();\n\t\t\tinput.Position = where * 16;\n\t\t\tlevel.Area.Add(input);\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.X == Left || P.X == Right) {\n\t\t\t\tif (P.Y == Top + 1 || P.Y == Bottom - 1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else \tif (P.X == Left + 1 || P.X == Right - 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tprivate bool Place(Level level, int x, int y, uint a, float offset) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif ((d.X == x && (d.Y == y + 1 || d.Y == y - 1)) || (d.Y == y && (d.X == x + 1 || d.X == x - 1))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, x, y, Tile.FloorA);\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(x, y) * 16,\n\t\t\t\tStartingAngle = a,\n\t\t\t\tTimingOffset = offset\n\t\t\t});\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/trap/VerticalTurretPassageRoom.cs",
    "content": "using System;\nusing System.Linq;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.entity.room.input;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.trap {\n\tpublic class VerticalTurretPassageRoom : TrapRoom {\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyRoom(Room room) {\n\t\t\tbase.ModifyRoom(room);\n\t\t\troom.AddController(\"bk:trap\");\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 14;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 22;\n\t\t}\n\n\t\tpublic override void Paint(Level level) {\n\t\t\tbase.Paint(level);\n\t\t\tPainter.Fill(level, this, 1, Tile.Chasm);\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Top + 1), new Dot(Right - 1, Top + 1), Tiles.RandomFloor(), true);\n\t\t\tPainter.DrawLine(level, new Dot(Left + 1, Bottom - 1), new Dot(Right - 1, Bottom - 1), Tiles.RandomFloor(), true);\n\n\t\t\tvar ty = Rnd.Int(Left + 2, Right - 2);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tty = Left + GetWidth() / 2;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 2; i++) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tvar tty = Rnd.Int(Left + 2, Right - 2);\n\t\t\t\t\tPainter.DrawLine(level, new Dot(tty, Top + 1), new Dot(tty, Bottom - 1), Tile.FloorD);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPainter.DrawLine(level, new Dot(ty, Top + 1), new Dot(ty, Bottom - 1), Tiles.RandomFloor(), true);\n\n\t\t\tif (Connected.Count == 1) {\n\t\t\t\tty = Rnd.Int(Left + 2, Right - 2);\n\n\t\t\t\tif (Connected.Values.First().Y == Top) {\n\t\t\t\t\tPlaceButton(level, new Dot(ty, Bottom - 1));\n\t\t\t\t} else {\n\t\t\t\t\tPlaceButton(level, new Dot(ty, Top + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar s = Rnd.Int(2, 4);\n\t\t\tvar xm = Rnd.Int(0, s);\n\n\t\t\t#region Wave Generator\n\t\t\tvar xsmooth = Rnd.Chance(30);\n\t\t\tvar xmod = Rnd.Float(s * 8, s * 16);\n\t\t\tvar ysmooth = Rnd.Chance(30);\n\t\t\tvar ymod = Rnd.Chance(30) ? xmod : Rnd.Float(s * 32, s * 64);\n\n\t\t\tvar fn = new Func<int, int, float>((x, y) => {\n\t\t\t\tvar t = 0f;\n\n\t\t\t\tif (!xsmooth) {\n\t\t\t\t\tt += (float) Math.Cos(x / xmod);\n\t\t\t\t}\n\n\t\t\t\tif (!ysmooth) {\n\t\t\t\t\tt += (float) Math.Sin(y / ymod);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn MathUtils.Mod(t * 3, 3);\n\t\t\t});\n\t\t\t#endregion\n\t\t\t\n\t\t\tfor (var x = Top + 3 + xm; x < Bottom - 2; x += s) {\n\t\t\t\tPlace(level, Left + 1, x, 0, fn(Left + 1, x));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var x = Top + 3 + xm; x < Bottom - 2; x += s) {\n\t\t\t\tPlace(level, Right - 1, x, 4, fn(x, Right - 1));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(RoomDef R, Dot P) {\n\t\t\tif (P.Y == Bottom || P.Y == Top) {\n\t\t\t\tif (P.X == Left + 1 || P.X == Right - 1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else \tif (P.X == Left || P.X == Right) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn base.CanConnect(R, P);\n\t\t}\n\n\t\tprivate bool Place(Level level, int x, int y, uint a, float offset) {\n\t\t\tforeach (var d in Connected.Values) {\n\t\t\t\tif ((d.X == x && (d.Y == y + 1 || d.Y == y - 1)) || (d.Y == y && (d.X == x + 1 || d.X == x - 1))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Set(level, x, y, Tile.FloorA);\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(x, y) * 16,\n\t\t\t\tStartingAngle = a,\n\t\t\t\tTimingOffset = offset,\n\t\t\t\tSpeed = 1.5f\n\t\t\t});\n\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate void PlaceButton(Level level, Dot where) {\n\t\t\tPainter.Set(level, where, Tiles.RandomFloor());\n\n\t\t\tvar input = new Button();\n\t\t\tinput.Position = where * 16;\n\t\t\tlevel.Area.Add(input);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/AcrossTreasureRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.treasure {\n\tpublic class AcrossTreasureRoom : TreasureRoom {\n\t\tpublic override void PaintInside(Level level) {\n\t\t\tvar w = (GetWidth() - 1) / 2;\n\t\t\tvar h = (GetHeight() - 1) / 2;\n\n\t\t\tvar vr = Rnd.Chance();\n\t\t\tvar hr = !vr || Rnd.Chance();\n\t\t\tvar a = Rnd.Chance();\n\n\t\t\tif (!a && Rnd.Chance()) {\n\t\t\t\tPainter.Set(level, GetTileCenter(), Tiles.RandomSolid());\n\t\t\t}\n\n\t\t\tif (vr) {\n\t\t\t\tPlaceStand(level, new Dot(Left + w, Top + 3));\n\t\t\t\tPlaceStand(level, new Dot(Left + w, Bottom - 3));\n\t\t\t}\n\n\t\t\tif (hr) {\n\t\t\t\tPlaceStand(level, new Dot(Right - 3, Top + h));\n\t\t\t\tPlaceStand(level, new Dot(Left + 3, Top + h));\n\t\t\t}\n\n\t\t\tif (a) {\n\t\t\t\tPlaceStand(level, new Dot(Left + w, Top + h));\t\n\t\t\t}\n\n\t\t\tSetupStands(level);\n\t\t}\n\t\t\n\t\tprotected override int ValidateWidth(int W) {\n\t\t\treturn W % 2 == 0 ? W : W - 1;\n\t\t}\n\t\t\n\t\tprotected override int ValidateHeight(int H) {\n\t\t\treturn H % 2 == 0 ? H : H - 1;\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 9;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 9;\n\t\t}\n\t\t\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn Rnd.Chance();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/HoleTreasureRoom.cs",
    "content": "using System;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.treasure {\r\n\tpublic class HoleTreasureRoom : TreasureRoom {\r\n\t\tpublic override void PaintInside(Level level) {\r\n\t\t\tvar m = Rnd.Int(4, 6);\r\n\t\t\tPainter.Fill(level, this, m, Tiles.RandomSolid());\r\n\r\n\t\t\tm = Math.Max(3, m - (Rnd.Chance() ? 1 : 2));\r\n\r\n\t\t\tvar v = Rnd.Chance();\r\n\t\t\tvar h = !v || Rnd.Chance();\r\n\r\n\t\t\tif (v) {\r\n\t\t\t\tPlaceStand(level, new Dot(Left + m, Top + m));\r\n\t\t\t\tPlaceStand(level, new Dot(Right - m, Bottom - m));\r\n\t\t\t}\r\n\r\n\t\t\tif (h) {\r\n\t\t\t\tPlaceStand(level, new Dot(Left + m, Bottom - m));\r\n\t\t\t\tPlaceStand(level, new Dot(Right - m, Top + m));\r\n\t\t\t}\r\n\r\n\t\t\tSetupStands(level);\r\n\t\t}\r\n\t\t\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxWidth() {\r\n\t\t\treturn 14;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMaxHeight() {\r\n\t\t\treturn 14;\r\n\t\t}\r\n\t\t\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/PadTreasureRoom.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.treasure {\n\tpublic class PadTreasureRoom : TreasureRoom {\n\t\tprivate List<Dot> rects = new List<Dot>();\n\t\tprivate List<Rect> rs = new List<Rect>();\n\t\t\n\t\tpublic override void PaintInside(Level level) {\n\t\t\tPainter.Fill(level, this, 1, Rnd.Chance() ? Tiles.RandomFloor() : Tile.Chasm);\n\n\t\t\tvar m = Rnd.Int(2, 3);\n\t\t\tvar rect = Shrink(m);\n\t\t\t\n\t\t\tvar w = Rnd.Int(3, rect.GetWidth() / 2);\n\t\t\tvar h = Rnd.Int(3, rect.GetHeight() / 2);\n\t\t\t\n\t\t\tPlacePad(level, new Rect(Left + m, Top + m).Resize(w, h));\n\t\t\tPlacePad(level, new Rect(Right - m - w + 1, Top + m).Resize(w, h));\n\t\t\tPlacePad(level, new Rect(Right - m - w + 1, Bottom - m - h + 1).Resize(w, h));\n\t\t\tPlacePad(level, new Rect(Left + m, Bottom - m - h + 1).Resize(w, h));\n\n\t\t\tvar a = Rnd.Chance();\n\n\t\t\tif (!a) {\n\t\t\t\tDisableBarrier = true;\n\t\t\t}\n\t\t\t\n\t\t\tvar missing = a ? -1 : Rnd.Int(4);\n\t\t\tvar rr = Rnd.Chance();\n\t\t\tvar f = Tiles.RandomFloor();\n\t\t\t\n\t\t\tfor (var i = 0; i < rects.Count; i++) {\n\t\t\t\tif (missing == i) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar r = rects[i];\n\t\t\t\tvar n = rects[(i + 1) % rects.Count];\n\t\t\t\t\n\t\t\t\tPainter.DrawLine(level, r, n, rr ? Tiles.RandomFloor() : f);\n\t\t\t}\n\n\t\t\tforeach (var r in rs) {\n\t\t\t\tPainter.Fill(level, r, Tile.FloorD);\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var r in rects) {\n\t\t\t\tPlaceStand(level, r);\n\t\t\t}\n\t\t\t\n\t\t\tSetupStands(level);\n\t\t}\n\n\t\tprivate void PlacePad(Level level, Rect rect) {\n\t\t\tvar c = new Dot(rect.Left + rect.GetWidth() / 2, rect.Top + rect.GetHeight() / 2);\n\t\t\trects.Add(c);\n\t\t\trs.Add(rect);\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 12;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/PlatformTreasureRoom.cs",
    "content": "using BurningKnight.level.tile;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.level.rooms.treasure {\r\n\tpublic class PlatformTreasureRoom : TreasureRoom {\r\n\t\tpublic override void PaintInside(Level level) {\r\n\t\t\tPainter.Fill(level, this, 1, Rnd.Chance() ? Tile.Chasm : Tiles.RandomSolid());\r\n\r\n\t\t\tvar f = Tiles.RandomFloor();\r\n\t\t\tvar m = Rnd.Int(2, 4);\r\n\t\t\t\r\n\t\t\tPainter.Fill(level, this, m, f);\r\n\r\n\t\t\tif ((GetWidth() > m * 2 + 1 && GetHeight() > m * 2 + 1)) {\r\n\t\t\t\tm++;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tPaintTunnel(level, Rnd.Chance(30) ? f : Tiles.RandomFloor(), GetCenterRect());\r\n\r\n\t\t\tPlaceStand(level, new Dot(Left + m, Top + m));\r\n\t\t\tPlaceStand(level, new Dot(Right - m, Top + m));\r\n\t\t\tPlaceStand(level, new Dot(Left + m, Bottom - m));\r\n\t\t\tPlaceStand(level, new Dot(Right - m, Bottom - m));\r\n\r\n\t\t\tSetupStands(level);\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinWidth() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\r\n\t\tpublic override int GetMinHeight() {\r\n\t\t\treturn 10;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/TreasureRoom.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.floors;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.rooms.special;\nusing BurningKnight.level.tile;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.rooms.treasure {\n\tpublic class TreasureRoom : SpecialRoom {\n\t\tprivate List<ItemStand> stands = new List<ItemStand>();\n\t\tprivate List<Dot> standPositions = new List<Dot>();\n\t\tprotected bool SpawnedBarrier;\n\t\tprotected bool DisableBarrier;\n\n\t\tprivate bool scourged;\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tif ((LevelSave.BiomeGenerated is JungleBiome && Rnd.Chance(50))) {\n\t\t\t\tvar clip = Painter.Clip;\n\t\t\t\tPainter.Clip = null;\n\t\t\t\tPainter.Rect(level, this, 0, Tile.WallB);\n\t\t\t\tPainter.Clip = clip;\n\t\t\t}\n\t\t\t\n\t\t\tscourged = Rnd.Chance(Run.Scourge * 2 + 2);\n\t\t\tPaintInside(level);\n\n\t\t\tif (scourged) {\n\t\t\t\tfor (var i = Left + 1; i <= Right - 1; i++) {\n\t\t\t\t\tfor (var j = Top + 1; j <= Bottom - 1; j++) {\n\t\t\t\t\t\tif (level.Get(i, j) == Tile.FloorD) {\n\t\t\t\t\t\t\tlevel.Set(i, j, Tile.EvilFloor);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void PaintInside(Level level) {\n\t\t\tvar c = GetCenter() * 16;\n\t\t\t\n\t\t\tPlaceStand(level, c - new Dot(32, 0));\n\t\t\tPlaceStand(level, c);\n\t\t\tPlaceStand(level, c + new Dot(32, 0));\n\t\t}\n\n\t\tprotected void SetupStands(Level level) {\n\t\t\tif (stands.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tFunc<ItemData, bool> filter = null;\n\n\t\t\tif (Rnd.Chance(10)) {\n\t\t\t\tfilter = (i) => i.Type == ItemType.Weapon;\n\t\t\t}\n\n\t\t\tvar id = Rnd.Int(stands.Count);\n\t\t\tvar st = stands[id];\n\n\t\t\tvar stnd = stands[id] = Rnd.Chance(30) ? new ShieldChoiceStand() : new HealChoiceStand();\n\t\t\tlevel.Area.Add(stnd);\n\t\t\tstnd.Center = st.Center;\n\n\t\t\tst.Done = true;\n\t\t\t\n\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Treasure), filter);\n\n\t\t\tforeach (var s in stands) {\n\t\t\t\tif (s is HealChoiceStand) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar item = Items.CreateAndAdd(Items.GenerateAndRemove(pool, null, true), level.Area, false);\n\n\t\t\t\tif (scourged) {\n\t\t\t\t\titem.Scourged = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ts.SetItem(item, null);\n\n\t\t\t\tif (pool.Count == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var s in standPositions) {\n\t\t\t\tif (level.Get(s.X, s.Y).Matches(TileFlags.Danger) || level.Get(s.X, s.Y, true).Matches(TileFlags.Danger)\n\t\t\t\t     || level.Get(s.X, s.Y).Matches(TileFlags.Solid) || level.Get(s.X, s.Y, true).Matches(TileFlags.Solid)) {\n\t\t\t\t\t\n\t\t\t\t\tPainter.Set(level, s, Tile.FloorD);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected void PlaceStand(Level level, Dot where) {\n\t\t\tvar stand = new SingleChoiceStand();\n\t\t\tlevel.Area.Add(stand);\n\t\t\tstand.Center = where * 16 + new Vector2(8, 8);\n\t\t\t\n\t\t\tstands.Add(stand);\n\t\t\tstandPositions.Add(where);\n\n\t\t\tif (!DisableBarrier && !SpawnedBarrier && Rnd.Chance(20)) {\n\t\t\t\tSpawnedBarrier = true;\n\t\t\t\tvar t = Tiles.Pick(Tile.SpikeOnTmp, Tile.Rock);\n\n\t\t\t\tPainter.Set(level, where + new Dot(-1, 0), t);\n\t\t\t\tPainter.Set(level, where + new Dot(1, 0), t);\n\t\t\t\tPainter.Set(level, where + new Dot(0, -1), t);\n\t\t\t\tPainter.Set(level, where + new Dot(0, 1), t);\n\n\t\t\t\tif (t == Tile.Rock) {\n\t\t\t\t\tt = Tile.Rock; // Tiles.Pick(Tile.Chasm, Tile.Rock);\n\t\t\t\t\t\n\t\t\t\t\tPainter.Set(level, where + new Dot(-1, 1), t);\n\t\t\t\t\tPainter.Set(level, where + new Dot(1, 1), t);\n\t\t\t\t\tPainter.Set(level, where + new Dot(1, -1), t);\n\t\t\t\t\tPainter.Set(level, where + new Dot(-1, -1), t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\tFloorRegistry.Paint(level, this, -1, true);\n\t\t\tPainter.Rect(level, this, 1, Tile.FloorD);\n\t\t}\n\n\t\tpublic override void SetupDoors(Level level) {\n\t\t\tvar rude = Rnd.Chance(5); // Hehe\n\t\t\t\n\t\t\tforeach (var door in Connected.Values) {\n\t\t\t\tdoor.Type = rude ? DoorPlaceholder.Variant.Locked : DoorPlaceholder.Variant.Treasure;\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool CanConnect(RoomDef r) {\n\t\t\tif (Run.Type != RunType.BossRush && LevelSave.BiomeGenerated is JungleBiome && !(r is HiveRoom)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(r);\n\t\t}\n\t\t\n\t\tpublic override bool CanConnect(RoomDef r, Dot p) {\n\t\t\tif (p.X == Left + 1 || p.X == Right - 1 || p.Y == Top + 1 || p.Y == Bottom - 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.CanConnect(r, p);\n\t\t}\n\n\t\tpublic override bool ShouldSpawnMobs() {\n\t\t\treturn false;// Random.Chance(10);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/rooms/treasure/TwoDiagonalTreasureRoom.cs",
    "content": "using BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.rooms.treasure {\n\tpublic class TwoDiagonalTreasureRoom : TreasureRoom {\n\t\tpublic override void PaintInside(Level level) {\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tvar t = Rnd.Chance(30) ? Tile.FloorD : Tiles.RandomFloor();\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPainter.Rect(level, new Rect(Left + 2, Top + 2, Right - 2, Bottom - 2), Rnd.Int(0, 2), t);\n\t\t\t\t} else {\n\t\t\t\t\tPainter.Rect(level, new Rect(Left + 2, Top + 2, Right - 2, Bottom - 2), Rnd.Int(0, 2), t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar a = Rnd.Chance();\n\n\t\t\tif (!a && Rnd.Chance()) {\n\t\t\t\tPainter.Set(level, GetTileCenter(), Tiles.RandomSolid());\n\t\t\t}\n\t\t\t\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPlaceStand(level, new Dot(Left + 3, Top + 3));\n\t\t\t\tPlaceStand(level, new Dot(Right - 3, Bottom - 3));\t\n\t\t\t} else {\n\t\t\t\tPlaceStand(level, new Dot(Right - 3, Top + 3));\n\t\t\t\tPlaceStand(level, new Dot(Left + 3, Bottom - 3));\t\n\t\t\t}\n\n\t\t\tif (a && !SpawnedBarrier) {\n\t\t\t\tDisableBarrier = true;\n\t\t\t\tPlaceStand(level, GetTileCenter());\t\n\t\t\t}\n\t\t\t\n\t\t\tSetupStands(level);\n\t\t}\n\t\t\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn 9;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn 9;\n\t\t}\n\t\t\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn 12;\n\t\t}\n\n\t\tprotected override bool Quad() {\n\t\t\treturn Rnd.Chance();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tile/Tile.cs",
    "content": "namespace BurningKnight.level.tile {\n\tpublic enum Tile {\n\t\tWallA = 1,\n\t\tWallB,\n\t\tCrack,\n\t\tDirt,\n\t\tFloorA,\n\t\tFloorB,\n\t\tFloorC,\n\t\tFloorD,\n\t\tWater,\n\t\tChasm,\n\t\tLava,\n\t\tGrass,\n\t\tHighGrass,\n\t\tIce,\n\t\tObsidian,\n\t\tEmber,\n\t\tCobweb,\n\t\tVenom,\n\t\tPlanks,\n\t\tPiston,\n\t\tPistonDown,\n\t\t\n\t\t// Not an actual tile, used just for placement with painter\n\t\tSpikeOffTmp,\n\t\tSensingSpikeTmp,\n\t\tPlate,\n\t\tTransition,\n\t\tSpikeOnTmp,\n\t\tBarrelTmp,\n\t\t\n\t\t// Regular tiles\n\t\tMetalBlock,\n\t\tRock,\n\t\tTintedRock,\n\t\tEvilWall,\n\t\tEvilFloor,\n\t\tGrannyWall,\n\t\tGrannyFloor,\n\t\t\n\t\t// Not an actual tile, used just for placement with painter\n\t\tFireTrapTmp,\n\t\t\n\t\tPath,\n\t\tSand,\n\t\tSnow,\n\t\tCollider,\n\t\t\n\t\tTotal\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tile/TileFlags.cs",
    "content": "namespace BurningKnight.level.tile {\n\tpublic static class TileFlags {\n\t\tprivate static int[] flags = new int[(int) Tile.Total];\n\t\t\n\t\tpublic static int Passable = 0x1;\n\t\tpublic static int Solid = 0x2;\n\t\tpublic static int Hole = 0x4;\n\t\tpublic static int Burns = 0x8;\n\t\tpublic static int BreaksView = 0x10;\n\t\tpublic static int FloorLayer = 0x20;\n\t\tpublic static int LiquidLayer = 0x40;\n\t\tpublic static int WallLayer = 0x80;\n\t\tpublic static int Danger = 0x100;\n\t\tpublic static int HalfWall = 0x200;\n\n\t\tstatic TileFlags() {\n\t\t\tflags[(int) Tile.Chasm] = Hole | FloorLayer;\n\t\t\tflags[(int) Tile.Dirt] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Sand] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Snow] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Grass] = Passable | Burns | LiquidLayer;\n\t\t\tflags[(int) Tile.FloorA] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.WallA] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.WallB] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.Transition] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.Collider] = Solid | LiquidLayer;\n\t\t\tflags[(int) Tile.Crack] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.Water] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Venom] = LiquidLayer | Danger;\n\t\t\tflags[(int) Tile.FloorB] = Passable | Burns | FloorLayer;\n\t\t\tflags[(int) Tile.FloorC] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.FloorD] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.Path] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.SpikeOffTmp] = FloorLayer | Danger;\n\t\t\tflags[(int) Tile.SpikeOnTmp] = FloorLayer | Danger;\n\t\t\tflags[(int) Tile.SensingSpikeTmp] = FloorLayer | Danger;\n\t\t\tflags[(int) Tile.Lava] = LiquidLayer | Danger;\n\t\t\tflags[(int) Tile.Ice] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.HighGrass] = Passable | Burns | LiquidLayer;\n\t\t\tflags[(int) Tile.Obsidian] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Ember] = Passable | LiquidLayer;\n\t\t\tflags[(int) Tile.Cobweb] = Passable | LiquidLayer | Burns;\n\t\t\tflags[(int) Tile.Planks] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.EvilWall] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.EvilFloor] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.GrannyWall] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.GrannyFloor] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.Piston] = Solid | WallLayer | BreaksView;\n\t\t\tflags[(int) Tile.PistonDown] = Passable | FloorLayer;\n\t\t\tflags[(int) Tile.Rock] = Solid | LiquidLayer | BreaksView | HalfWall;\n\t\t\tflags[(int) Tile.TintedRock] = Solid | LiquidLayer | BreaksView | HalfWall;\n\t\t\tflags[(int) Tile.MetalBlock] = Solid | LiquidLayer | BreaksView | HalfWall;\n\t\t}\n\t\n\t\tpublic static bool Matches(this Tile tile, int flag) {\n\t\t\treturn (flags[(int) tile] & flag) == flag;\n\t\t}\n\t\t\n\t\tpublic static bool Matches(byte tile, int flag) {\n\t\t\treturn (flags[tile] & flag) == flag;\n\t\t}\n\t\n\t\tpublic static bool Matches(this Tile tile, params Tile[] tiles) {\n\t\t\tforeach (var type in tiles) {\n\t\t\t\tif (type == tile) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static bool IsPassable(this Tile tile) {\n\t\t\treturn Matches(tile, Passable);\n\t\t}\n\t\t\n\t\tpublic static bool IsWall(this Tile tile) {\n\t\t\treturn IsSimpleWall(tile) || tile == Tile.Piston;\n\t\t}\n\t\t\n\t\tpublic static bool IsRock(this Tile tile) {\n\t\t\treturn tile == Tile.Rock || tile == Tile.TintedRock;\n\t\t}\n\n\t\tpublic static bool IsSimpleWall(this Tile tile) {\n\t\t\treturn tile == Tile.WallA || tile == Tile.WallB || tile == Tile.Crack || tile == Tile.Planks || tile == Tile.Transition || tile == Tile.GrannyWall || tile == Tile.EvilWall;\n\t\t}\n\t\t\n\t\tpublic static bool IsHalfWall(this Tile tile) {\n\t\t\treturn tile == Tile.Rock || tile == Tile.TintedRock || tile == Tile.MetalBlock;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tile/Tiles.cs",
    "content": "using BurningKnight.save;\nusing BurningKnight.state;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.tile {\n\tpublic static class Tiles {\n\t\tprivate static Tile lastFloor;\n\t\tprivate static Tile lastWall;\n\t\t\n\t\tpublic static Tile Pick(params Tile[] tiles) {\n\t\t\treturn tiles[Rnd.Int(tiles.Length)];\n\t\t}\n\n\t\tpublic static Tile RandomFloor(bool gold = false) {\n\t\t\tif (gold) {\n\t\t\t\treturn lastFloor = Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD);\n\t\t\t}\n\t\t\t\n\t\t\treturn lastFloor = Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC);\n\t\t}\n\t\t\n\t\tpublic static Tile RandomFloorOrSpike() {\n\t\t\treturn lastFloor = (LevelSave.BiomeGenerated?.HasSpikes() ?? true) && Rnd.Chance(20) ? Tile.SensingSpikeTmp : Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC);\n\t\t}\n\t\t\n\t\tpublic static Tile RandomWall() {\n\t\t\treturn lastWall = Pick(Tile.WallA, Tile.Rock, Tile.MetalBlock);\n\t\t}\n\t\t\n\t\tpublic static Tile RandomSolid() {\n\t\t\treturn lastWall = Pick(Tile.WallA, Tile.Rock, Tile.MetalBlock, Tile.Planks, Tile.Lava, Tile.Planks, (LevelSave.BiomeGenerated?.HasSpikes() ?? true) ? Tile.SensingSpikeTmp : Tile.WallA);\n\t\t}\n\t\t\n\t\tpublic static Tile RandomFillWall() {\n\t\t\treturn lastWall = Pick(Tile.WallA, Tile.Rock, Tile.MetalBlock, Tile.Planks);\n\t\t}\n\t\t\n\t\tpublic static Tile RandomNewWall() {\n\t\t\tswitch (lastWall) {\n\t\t\t\tcase Tile.WallA: return Pick(Tile.Planks, Tile.MetalBlock, Tile.Rock);\n\t\t\t\tcase Tile.Planks: return Pick(Tile.WallA, Tile.MetalBlock, Tile.Rock);\n\t\t\t\tcase Tile.MetalBlock: return Pick(Tile.WallA, Tile.Planks, Tile.Rock);\n\t\t\t\tcase Tile.Rock: default: return Pick(Tile.WallA, Tile.MetalBlock, Tile.Planks);\n\t\t\t}\n\t\t}\n\n\t\tpublic static Tile RandomNewFloor() {\n\t\t\tvar tiles = new Tile[2];\n\n\t\t\tswitch (lastFloor) {\n\t\t\t\tcase Tile.FloorA: {\n\t\t\t\t\ttiles[0] = Tile.FloorB;\n\t\t\t\t\ttiles[1] = Tile.FloorC;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase Tile.FloorB: {\n\t\t\t\t\ttiles[0] = Tile.FloorA;\n\t\t\t\t\ttiles[1] = Tile.FloorC;\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\ttiles[0] = Tile.FloorA;\n\t\t\t\t\ttiles[1] = Tile.FloorB;\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn tiles[Rnd.Int(2)];\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tile/Tileset.cs",
    "content": "﻿using System;\nusing Lens.assets;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.tile {\n\tpublic class Tileset {\n\t\tpublic TextureRegion[] WallA = new TextureRegion[12];\n\t\tpublic TextureRegion[] WallB = new TextureRegion[12];\n\t\tpublic TextureRegion[] WallAExtensions = new TextureRegion[4];\n\t\tpublic TextureRegion[] WallBExtensions = new TextureRegion[4];\n\t\tpublic TextureRegion WallTopA;\n\t\tpublic TextureRegion WallTopB;\n\t\tpublic TextureRegion WallTopADecor;\n\t\tpublic TextureRegion WallTopBDecor;\n\t\tpublic TextureRegion WallCrackA;\n\t\tpublic TextureRegion WallCrackB;\n\t\tpublic TextureRegion[] WallTopsA = new TextureRegion[36];\n\t\tpublic TextureRegion[] WallTopsB = new TextureRegion[36];\n\t\tpublic TextureRegion[] WallTopsTransition = new TextureRegion[36];\n\t\tpublic TextureRegion[] WallSidesA = new TextureRegion[3];\n\t\tpublic TextureRegion[] WallSidesB = new TextureRegion[3];\n\t\t\n\t\tpublic TextureRegion[] FloorA = new TextureRegion[16];\n\t\tpublic TextureRegion[] FloorB = new TextureRegion[16];\n\t\tpublic TextureRegion[] FloorC = new TextureRegion[16];\n\t\tpublic TextureRegion[] FloorD = new TextureRegion[16];\n\t\t\n\t\tpublic TextureRegion[] FloorSidesA = new TextureRegion[4];\n\t\tpublic TextureRegion[] FloorSidesB = new TextureRegion[4];\n\t\tpublic TextureRegion[] FloorSidesC = new TextureRegion[4];\n\t\tpublic TextureRegion[] FloorSidesD = new TextureRegion[4];\n\t\t\n\t\tpublic TextureRegion[] WallVariants = new TextureRegion[8];\n\t\t\n\t\tpublic TextureRegion[] MetalBlock = new TextureRegion[4];\n\t\tpublic TextureRegion[] Rock = new TextureRegion[4];\n\t\tpublic TextureRegion[] TintedRock = new TextureRegion[4];\n\t\tpublic TextureRegion MetalBlockShadow;\n\t\t\n\t\tpublic TextureRegion[][] Tiles = new TextureRegion[(int) Tile.Total][];\n\n\t\tpublic static int[] WallMap = { -1, -1, -1, 9, -1, -1, 0, 5, -1, 11, -1, 10, 2, 6, 1, -1 };\n\t\tpublic static int[] WallMapExtra = { -1, 7, 3, -1, 4, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1 };\n\t\t\n\t\tpublic void Load(string id) {\n\t\t\tvar anim = Animations.Get(id);\n\t\t\t\n\t\t\tWallVariants = new TextureRegion[8];\n\t\t\t\n\t\t\tfor (int i = 0; i < 8; i++) {\n\t\t\t\tWallVariants[i] = new TextureRegion(anim.Texture, new Rectangle(128 + i % 4 * 16, 160 + (int) Math.Floor(i / 4f) * 16, 16, 16));\n\t\t\t}\n\t\t\t\n\t\t\tfor (int w = 0; w < 3; w++) {\n\t\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\t\tfor (int j = 0; j < 12; j++) {\n\t\t\t\t\t\tvar n = j > 5 ? j + 1 : j;\n\n\t\t\t\t\t\tif (w == 0) {\n\t\t\t\t\t\t\tWallTopsA[i * 12 + j] = new TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40, n / 5 * 8, 8, 8));\n\t\t\t\t\t\t} else if (w == 1) {\n\t\t\t\t\t\t\tWallTopsB[i * 12 + j] = new TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40, 40 + n / 5 * 8, 8, 8));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tWallTopsTransition[i * 12 + j] = new TextureRegion(anim.Texture, new Rectangle(n % 5 * 8 + i * 40, 240 + n / 5 * 8, 8, 8));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (w == 0) {\n\t\t\t\t\tWallAExtensions[0] = new TextureRegion(anim.Texture, new Rectangle(208, 0, 16, 8));\n\t\t\t\t\tWallAExtensions[1] = new TextureRegion(anim.Texture, new Rectangle(224, 8, 8, 16));\n\t\t\t\t\tWallAExtensions[2] = new TextureRegion(anim.Texture, new Rectangle(208, 24, 16, 8));\n\t\t\t\t\tWallAExtensions[3] = new TextureRegion(anim.Texture, new Rectangle(200, 8, 8, 16));\n\t\t\t\t} else {\n\t\t\t\t\tWallBExtensions[0] = new TextureRegion(anim.Texture, new Rectangle(208, 40, 16, 8));\n\t\t\t\t\tWallBExtensions[1] = new TextureRegion(anim.Texture, new Rectangle(224, 48, 8, 16));\n\t\t\t\t\tWallBExtensions[2] = new TextureRegion(anim.Texture, new Rectangle(208, 64, 16, 8));\n\t\t\t\t\tWallBExtensions[3] = new TextureRegion(anim.Texture, new Rectangle(200, 48, 8, 16));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < 12; i++) {\n\t\t\t\t\tif (w == 0) {\n\t\t\t\t\t\tWallA[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16, 24, 16, 16));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tWallB[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16, 64, 16, 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\t\tif (w == 0) {\n\t\t\t\t\t\tWallSidesA[i] = new TextureRegion(anim.Texture, new Rectangle(128 + i * 16, 80, 16, 16));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tWallSidesB[i] = new TextureRegion(anim.Texture, new Rectangle(128 + i * 16, 96, 16, 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tWallTopADecor = new TextureRegion(anim.Texture, new Rectangle(128, 0, 16, 16));\n\t\t\tWallTopBDecor = new TextureRegion(anim.Texture, new Rectangle(144, 0, 16, 16));\n\n\t\t\tTiles[(int) Tile.PistonDown] = Tiles[(int) Tile.Piston] = Tiles[(int) Tile.WallA] = new[] {\n\t\t\t\tWallTopA = new TextureRegion(anim.Texture, new Rectangle(160, 8, 16, 16))\n\t\t\t};\n\t\t\t\n\t\t\tTiles[(int) Tile.WallB] = new[] {\n\t\t\t\tWallTopB = new TextureRegion(anim.Texture, new Rectangle(160, 48, 16, 16))\n\t\t\t};\n\t\t\t\n\t\t\tTiles[(int) Tile.Crack] = new[] {\n\t\t\t\tWallCrackA = new TextureRegion(anim.Texture, new Rectangle(176, 8, 16, 16))\n\t\t\t};\n\t\t\t\n\t\t\tWallCrackB = new TextureRegion(anim.Texture, new Rectangle(176, 48, 16, 16));\n\n\t\t\tfor (int f = 0; f < 3; f++) {\n\t\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\t\tif (f == 0) {\n\t\t\t\t\t\tMetalBlock[i] = new TextureRegion(anim.Texture, new Rectangle(128 + i % 2 * 16, 192 + i / 2 * 16, 16, 16));\n\t\t\t\t\t} else if (f == 1) {\n\t\t\t\t\t\tRock[i] = new TextureRegion(anim.Texture, new Rectangle(160 + i % 2 * 16, 192 + i / 2 * 16, 16, 16));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tTintedRock[i] = new TextureRegion(anim.Texture, new Rectangle(160 + i % 2 * 16, 224 + i / 2 * 16, 16, 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMetalBlockShadow = new TextureRegion(anim.Texture, new Rectangle(128, 224, 16, 16));\n\n\t\t\tfor (int f = 0; f < 4; f++) {\n\t\t\t\tfor (int i = 0; i < 16; i++) {\n\t\t\t\t\tif (f == 0) {\n\t\t\t\t\t\tFloorA[i] = new TextureRegion(anim.Texture, new Rectangle(i % 4 * 16, 80 + i / 4 * 16, 16, 16));\n\t\t\t\t\t} else if (f == 1) {\n\t\t\t\t\t\tFloorB[i] = new TextureRegion(anim.Texture, new Rectangle(64 + i % 4 * 16, 80 + i / 4 * 16, 16, 16));\n\t\t\t\t\t} else if (f == 2) {\n\t\t\t\t\t\tFloorC[i] = new TextureRegion(anim.Texture, new Rectangle(i % 4 * 16, 160 + i / 4 * 16, 16, 16));\n\t\t\t\t\t} else if (f == 3) {\n\t\t\t\t\t\tFloorD[i] = new TextureRegion(anim.Texture, new Rectangle(64 + i % 4 * 16, 160 + i / 4 * 16, 16, 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\t\tif (f == 0) {\n\t\t\t\t\t\tFloorSidesA[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16, 144, 16, 16));\n\t\t\t\t\t} else if (f == 1) {\n\t\t\t\t\t\tFloorSidesB[i] = new TextureRegion(anim.Texture, new Rectangle(64 + i * 16, 144, 16, 16));\n\t\t\t\t\t} else if (f == 2) {\n\t\t\t\t\t\tFloorSidesC[i] = new TextureRegion(anim.Texture, new Rectangle(i * 16, 224, 16, 16));\n\t\t\t\t\t} else if (f == 3) {\n\t\t\t\t\t\tFloorSidesD[i] = new TextureRegion(anim.Texture, new Rectangle(64 + i * 16, 224, 16, 16));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tTiles[(int) Tile.FloorA] = FloorA;\n\t\t\tTiles[(int) Tile.FloorB] = FloorB;\n\t\t\tTiles[(int) Tile.FloorC] = FloorC;\n\t\t\tTiles[(int) Tile.FloorD] = FloorD;\n\t\t\t\n\t\t\tTiles[(int) Tile.Rock] = Rock;\n\t\t\tTiles[(int) Tile.TintedRock] = TintedRock;\n\t\t\tTiles[(int) Tile.MetalBlock] = MetalBlock;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tile/Tilesets.cs",
    "content": "﻿using System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing Lens.assets;\nusing Lens.util;\n\nnamespace BurningKnight.level.tile {\n\tpublic class Tilesets {\n\t\tpublic static Dictionary<string, Tileset> Loaded = new Dictionary<string, Tileset>();\n\t\tpublic static BiomeAssets Biome;\n\n\t\tpublic static void Load() {\n\t\t\tif (Biome == null) {\n\t\t\t\tBiome = new BiomeAssets();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Update() {\n\t\t\tif (Animations.Reload) {\n\t\t\t\tforeach (var set in Loaded) {\n\t\t\t\t\tLog.Debug($\"Reloading {set.Key} tileset\");\n\t\t\t\t\tset.Value.Load(set.Key);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tLog.Debug(\"Reloading biome assets\");\n\t\t\t\tBiome = new BiomeAssets();\n\t\t\t}\n\t\t}\n\n\t\tpublic static Tileset Get(string id) {\n\t\t\tTileset tileset;\n\t\t\t\n\t\t\tif (Loaded.TryGetValue(id, out tileset)) {\n\t\t\t\treturn tileset;\n\t\t\t}\n\t\t\t\n\t\t\ttileset = new Tileset();\n\t\t\ttileset.Load(id);\n\t\t\tLoaded[id] = tileset;\n\t\t\t\n\t\t\treturn tileset;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tutorial/TutorialLevel.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.builders;\nusing BurningKnight.level.hall;\nusing BurningKnight.level.rooms;\n\nnamespace BurningKnight.level.tutorial {\n\tpublic class TutorialLevel : RegularLevel {\n\t\tpublic TutorialLevel() : base(BiomeRegistry.Get(Biome.Castle)) {\n\n\t\t}\n\n\t\tprotected override List<RoomDef> CreateRooms() { \n\t\t\treturn new List<RoomDef> {\n\t\t\t\t\tnew TutorialRoom()\n\t\t\t};\n\t\t}\n\n\t\tprotected override Builder GetBuilder() {\n\t\t\treturn new HallBuilder();\n\t\t}\n\n\t\tprotected override Painter GetPainter() {\n\t\t\treturn new Painter {\n\t\t\t\t\tWater = 0,\n\t\t\t\t\tCobweb = 0,\n\t\t\t\t\tGrass = 0,\n\t\t\t\t\tDirt = 0\n\t\t\t};\n\t\t}\n\n\t\tpublic override string GetMusic() {\n\t\t\treturn \"Gobbeon\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tutorial/TutorialRoom.cs",
    "content": "using BurningKnight.assets.prefabs;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms.entrance;\nusing BurningKnight.level.tile;\n\nnamespace BurningKnight.level.tutorial {\n\tpublic class TutorialRoom : ExitRoom {\n\t\tprivate Prefab prefab;\n\n\t\tpublic TutorialRoom() {\n\t\t\tprefab = Prefabs.Get(\"tutorial\");\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level) {\n\t\t\tPainter.Fill(level, this, Tile.WallA);\n\t\t\tPainter.Prefab(level, \"tutorial\", Left + 1, Top + 1);\n\t\t}\n\n\t\tpublic override bool ConvertToEntity() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void PaintFloor(Level level) {\n\t\t\t\n\t\t}\n\n\t\tpublic override int GetMinWidth() {\n\t\t\treturn prefab.Level.Width;\n\t\t}\n\n\t\tpublic override int GetMaxWidth() {\n\t\t\treturn prefab.Level.Width + 1;\n\t\t}\n\n\t\tpublic override int GetMinHeight() {\n\t\t\treturn prefab.Level.Height;\n\t\t}\n\t\t\n\t\tpublic override int GetMaxHeight() {\n\t\t\treturn prefab.Level.Height + 1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/tutorial/TutorialStand.cs",
    "content": "using BurningKnight.entity.component;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens.entity;\nusing Lens.util.camera;\nusing Lens.util.tween;\n\nnamespace BurningKnight.level.tutorial {\n\tpublic class TutorialStand : ItemStand {\n\t\tprivate bool set;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!set) {\n\t\t\t\tset = true;\n\n\t\t\t\tif (Item != null) {\n\t\t\t\t\tforeach (var c in GetComponent<RoomComponent>().Room.Controllable) {\n\t\t\t\t\t\tc.TurnOff();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemTakenEvent) {\n\t\t\t\tCamera.Instance.Shake(8);\n\t\t\t\tvar r = GetComponent<RoomComponent>().Room;\n\t\t\t\t\n\t\t\t\tforeach (var c in r.Controllable) {\n\t\t\t\t\tc.TurnOn();\n\t\t\t\t\tAnimationUtil.Poof(c.Center);\n\t\t\t\t}\n\n\t\t\t\tforeach (var n in r.Tagged[Tags.Npc]) {\n\t\t\t\t\tif (n is OldMan) {\n\t\t\t\t\t\tn.GetComponent<DialogComponent>().Start(\"old_man_5\");\n\t\t\t\t\t\tn.RemoveComponent<CloseDialogComponent>();\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/ChasmLevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class ChasmLevelVariant : LevelVariant {\n\t\tpublic ChasmLevelVariant() : base(LevelVariant.Chasm) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/FloodedLevelVariant.cs",
    "content": "using Lens.util.math;\n\nnamespace BurningKnight.level.variant {\n\tpublic class FloodedLevelVariant : LevelVariant {\n\t\tpublic FloodedLevelVariant() : base(LevelVariant.Flooded) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\tpainter.Water = 0.8f;\n\t\t}\n\t\t\n\t\tpublic override void PostInit(Level level) {\n\t\t\tbase.PostInit(level);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tlevel.Rains = true;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/ForestLevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class ForestLevelVariant : LevelVariant {\n\t\tpublic ForestLevelVariant() : base(LevelVariant.Forest) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\tpainter.Grass = 0.4f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/GoldLevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class GoldLevelVariant : LevelVariant {\n\t\tpublic GoldLevelVariant() : base(LevelVariant.Gold) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\tPainter.AllGold = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/LevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class LevelVariant {\n\t\tpublic static string Regular = \"regular\";\n\t\tpublic static string Sand = \"sand\";\n\t\tpublic static string Flooded = \"flooded\";\n\t\tpublic static string Webbed = \"webbed\";\n\t\tpublic static string Snow = \"snow\";\n\t\tpublic static string Chasm = \"chasm\";\n\t\tpublic static string Gold = \"gold\";\n\t\tpublic static string Forest = \"forest\";\n\t\tpublic static string RaveCave = \"rave_cave\";\n\t\t\n\t\tprivate string id;\n\n\t\tpublic string Id => id;\n\n\t\tpublic LevelVariant(string id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\tpublic virtual void ModifyPainter(Painter painter) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PostInit(Level level) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/RaveCaveVariant.cs",
    "content": "using BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.castle;\n\nnamespace BurningKnight.level.variant {\n\tpublic class RaveCaveVariant : LevelVariant {\n\t\tpublic RaveCaveVariant() : base(LevelVariant.RaveCave) {\n\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\n\t\t\tpainter.ModifyMobs = mobs => {\n\t\t\t\tmobs.Clear();\n\t\t\t\tmobs.Add(MobRegistry.FindFor(typeof(Crab)));\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/RegularLevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class RegularLevelVariant : LevelVariant {\n\t\tpublic RegularLevelVariant() : base(LevelVariant.Regular) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/SandLevelVariant.cs",
    "content": "using BurningKnight.level.tile;\n\nnamespace BurningKnight.level.variant {\n\tpublic class SandLevelVariant : LevelVariant {\n\t\tpublic SandLevelVariant() : base(LevelVariant.Sand) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\t\n\t\t\tpainter.Dirt = 0.5f;\n\t\t\tpainter.DirtTile = Tile.Sand;\n\t\t\t\t\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (l.Get(x, y, true) == Tile.Dirt) {\n\t\t\t\t\tl.Set(x, y, Tile.Sand);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/SnowLevelVariant.cs",
    "content": "using BurningKnight.level.tile;\n\nnamespace BurningKnight.level.variant {\n\tpublic class SnowLevelVariant  : LevelVariant {\n\t\tpublic SnowLevelVariant() : base(LevelVariant.Snow) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\t\n\t\t\tpainter.Dirt = 0.5f;\n\t\t\tpainter.DirtTile = Tile.Snow;\n\n\t\t\tpainter.Modifiers.Add((l, rm, x, y) => {\n\t\t\t\tif (l.Get(x, y, true) == Tile.Dirt) {\n\t\t\t\t\tl.Set(x, y, Tile.Snow);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic override void PostInit(Level level) {\n\t\t\tbase.PostInit(level);\n\t\t\tlevel.Snows = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/VariantInfo.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic struct VariantInfo {\n\t\tpublic float Chance;\n\t\tpublic LevelVariant Variant;\n\t\tpublic string[] Biomes;\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/VariantRegistry.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing BurningKnight.state;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.variant {\n\tpublic static class VariantRegistry {\n\t\tprivate static List<VariantInfo> defined = new List<VariantInfo>();\n\n\t\tstatic VariantRegistry() {\n\t\t\tDefine(new RegularLevelVariant(), 1f, Biome.Castle, Biome.Desert, Biome.Jungle, Biome.Ice, Biome.Library, Biome.Cave);\n\t\t\tDefine(new ChasmLevelVariant(), 0.2f, Biome.Castle, Biome.Desert, Biome.Library);\n\t\t\tDefine(new SandLevelVariant(), 0.15f, Biome.Castle, Biome.Jungle, Biome.Ice, Biome.Library);\n\t\t\tDefine(new FloodedLevelVariant(), 0.15f, Biome.Castle, Biome.Desert, Biome.Jungle, Biome.Ice, Biome.Library, Biome.Cave);\n\t\t\tDefine(new SnowLevelVariant(), 0.05f, Biome.Castle);\n\t\t\tDefine(new ForestLevelVariant(), 0.03f, Biome.Castle);\n\t\t\tDefine(new WebbedLevelVariant(), 0.02f, Biome.Castle, Biome.Desert, Biome.Jungle, Biome.Ice, Biome.Library);\n\t\t\tDefine(new SandLevelVariant(), 0.05f, Biome.Castle, Biome.Desert, Biome.Jungle, Biome.Ice, Biome.Library);\n\t\t\tDefine(new GoldLevelVariant(), 0.005f, Biome.Castle);\n\t\t\tDefine(new RaveCaveVariant(), 0.01f, Biome.Castle);\n\t\t}\n\n\t\tpublic static void Define(LevelVariant variant, float chance, params string[] biomes) {\n\t\t\tdefined.Add(new VariantInfo {\n\t\t\t\tChance = chance,\n\t\t\t\tVariant = variant,\n\t\t\t\tBiomes = biomes\n\t\t\t});\n\t\t}\n\n\t\tpublic static LevelVariant Create(string id) {\n\t\t\tforeach (var variant in defined) {\n\t\t\t\tif (variant.Variant.Id == id) {\n\t\t\t\t\treturn variant.Variant;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn new RegularLevelVariant();\n\t\t}\n\n\t\tpublic static LevelVariant Generate(string biome) {\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\treturn new RegularLevelVariant();\n\t\t\t}\n\t\t\t\n\t\t\tvar variants = new List<LevelVariant>();\n\t\t\tvar chances = new List<float>();\n\n\t\t\tforeach (var variant in defined) {\n\t\t\t\tforeach (var b in variant.Biomes) {\n\t\t\t\t\tif (b == biome) {\n\t\t\t\t\t\tvariants.Add(variant.Variant);\n\t\t\t\t\t\tchances.Add(variant.Chance);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (variants.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar index = Rnd.Chances(chances);\n\n\t\t\tif (index == -1) {\n\t\t\t\treturn new RegularLevelVariant();\n\t\t\t}\n\n\t\t\treturn variants[index];\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/variant/WebbedLevelVariant.cs",
    "content": "namespace BurningKnight.level.variant {\n\tpublic class WebbedLevelVariant : LevelVariant {\n\t\tpublic WebbedLevelVariant() : base(LevelVariant.Webbed) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void ModifyPainter(Painter painter) {\n\t\t\tbase.ModifyPainter(painter);\n\t\t\tpainter.Cobweb = 0.6f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/CollumnWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.walls {\n\tpublic class CollumnWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar s = Math.Min(inside.GetWidth(), inside.GetHeight());\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tinside = inside.Shrink(s / 3);\n\t\t\t} else {\n\t\t\t\tvar c = room.GetTileCenter();\n\t\t\t\tvar sz = s / 2;\n\t\t\t\tinside = new Rect(c.X - sz / 2, c.Y - sz / 2).Resize(sz, sz);\n\t\t\t}\n\t\t\t\n\t\t\tPainter.Fill(level, inside, Tiles.Pick(Tile.WallA, Tile.WallB, Tile.Planks));\n\n\t\t\tif (Rnd.Chance(80)) {\n\t\t\t\tvar p = Rnd.Chance(30);\n\t\t\t\tvar tile = p ? Tiles.RandomFloor() : Tiles.RandomWall();\n\n\t\t\t\tif (tile == Tile.Lava) {\n\t\t\t\t\tPainter.Fill(level, inside, 1, Tiles.RandomFloor());\n\t\t\t\t} else if (tile == Tile.SensingSpikeTmp) {\n\t\t\t\t\ttile = Tile.FloorA;\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPainter.Fill(level, inside, 1, tile);\n\n\t\t\t\tif (p || Rnd.Chance(70)) {\n\t\t\t\t\tvar m = false;\n\t\t\t\t\tvar f = Tiles.RandomFloorOrSpike();\n\t\t\t\t\tvar i = Rnd.Chance();\n\t\t\t\t\tvar fi = Rnd.Chance() ? f : Tiles.RandomFloorOrSpike();\n\n\t\t\t\t\tPainter.Fill(level, inside, 2, Tiles.RandomFloor());\n\n\t\t\t\t\tif (Rnd.Chance(40)) {\n\t\t\t\t\t\tm = true;\n\n\t\t\t\t\t\tif (i) {\n\t\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + 2, inside.Top + inside.GetHeight() / 2), fi);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + 1, inside.Top + inside.GetHeight() / 2), f);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Rnd.Chance(40)) {\n\t\t\t\t\t\tm = true;\n\t\t\t\t\t\n\t\t\t\t\t\tif (i) {\n\t\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Right - 3, inside.Top + inside.GetHeight() / 2), fi);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Right - 2, inside.Top + inside.GetHeight() / 2), f);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (Rnd.Chance(40)) {\n\t\t\t\t\t\tm = true;\n\n\t\t\t\t\t\tif (i) {\n\t\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Top + 2), fi);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Top + 1), f);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!m || Rnd.Chance(40)) {\n\t\t\t\t\t\tif (i) {\n\t\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Bottom - 3), fi);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Bottom - 2), f);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar fr = Tiles.RandomFloor();\n\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Bottom - 1), fr);\n\t\t\t\tPainter.Set(level, new Dot(inside.Left + inside.GetWidth() / 2, inside.Top), fr);\n\t\t\t\tPainter.Set(level, new Dot(inside.Left, inside.Top + inside.GetHeight() / 2), fr);\n\t\t\t\tPainter.Set(level, new Dot(inside.Right - 1, inside.Top + inside.GetHeight() / 2), fr);\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(30)) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), room.GetCenterRect(), true);\n\t\t\t\t}\n\n\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), room.GetCenterRect());\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/level/walls/CollumsWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class CollumsWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tbase.Paint(level, room, inside);\n\n\t\t\tvar minDim = Math.Min(room.GetWidth(), room.GetHeight());\n\t\t\tvar circ = Rnd.Chance(50);\n\n\t\t\tvar left = room.Left;\n\t\t\tvar top = room.Top;\n\t\t\tvar right = room.Right;\n\t\t\tvar bottom = room.Bottom;\n\n\t\t\tvar same = Rnd.Chance();\n\t\t\tvar a = Tiles.RandomSolid();\n\t\t\tvar b = same ? a : Tiles.RandomSolid();\n\t\t\tvar af = Tiles.Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD);\n\t\t\tvar bf = a == b ? af : Tiles.Pick(Tile.FloorA, Tile.FloorB, Tile.FloorC, Tile.FloorD);\n\t\t\t\n\t\t\tvar o = Rnd.Chance();\n\n\t\t\tif (minDim == 7 || Rnd.Int(2) == 0) {\n\t\t\t\tint pillarInset = minDim >= 11 ? 2 : 1;\n\t\t\t\tint pillarSize = ((minDim - 3) / 2) - pillarInset;\n\n\t\t\t\tint pillarX, pillarY;\n\n\t\t\t\tif (Rnd.Int(2) == 0) {\n\t\t\t\t\tpillarX = Rnd.Int(left + 1 + pillarInset, right - pillarSize - pillarInset);\n\t\t\t\t\tpillarY = top + 1 + pillarInset;\n\t\t\t\t} else {\n\t\t\t\t\tpillarX = left + 1 + pillarInset;\n\t\t\t\t\tpillarY = Rnd.Int(top + 1 + pillarInset, bottom - pillarSize - pillarInset);\n\t\t\t\t}\n\n\t\t\t\tif (circ) {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.FillEllipse(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, af);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPainter.FillEllipse(level, pillarX, pillarY, pillarSize, pillarSize, a);\n\t\t\t\t} else {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.Fill(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, af);\n\t\t\t\t\t}\n\n\t\t\t\t\tPainter.Fill(level, pillarX, pillarY, pillarSize, pillarSize, a);\n\t\t\t\t}\n\n\t\t\t\tpillarX = right - (pillarX - left + pillarSize - 1);\n\t\t\t\tpillarY = bottom - (pillarY - top + pillarSize - 1);\n\n\t\t\t\tif (circ) {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.FillEllipse(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, bf);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPainter.FillEllipse(level, pillarX, pillarY, pillarSize, pillarSize, b);\n\t\t\t\t} else {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.Fill(level, pillarX - 1, pillarY - 1, pillarSize + 2, pillarSize + 2, bf);\n\t\t\t\t\t}\n\n\t\t\t\t\tPainter.Fill(level, pillarX, pillarY, pillarSize, pillarSize, b);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tint pillarInset = minDim >= 12 ? 2 : 1;\n\t\t\t\tint pillarSize = (minDim - 6) / (pillarInset + 1);\n\n\t\t\t\tfloat xSpaces = room.GetWidth() - 2 * pillarInset - pillarSize - 2;\n\t\t\t\tfloat ySpaces = room.GetHeight() - 2 * pillarInset - pillarSize - 2;\n\t\t\t\tfloat minSpaces = Math.Min(xSpaces, ySpaces);\n\n\t\t\t\tfloat percentSkew = (float) (Math.Round(Rnd.Float() * minSpaces) / minSpaces);\n\n\t\t\t\tif (circ) {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.FillEllipse(level, left + pillarInset + (int) Math.Round(percentSkew * xSpaces), top + pillarInset,\n\t\t\t\t\t\t\tpillarSize + 2, pillarSize + 2, af);\n\n\t\t\t\t\t\tPainter.FillEllipse(level, right - pillarSize - pillarInset - 1,\n\t\t\t\t\t\t\ttop + pillarInset + (int) Math.Round(percentSkew * ySpaces), pillarSize + 2, pillarSize + 2, bf);\n\n\t\t\t\t\t\tPainter.FillEllipse(level, right - pillarSize - pillarInset - (int) Math.Round(percentSkew * xSpaces) - 1,\n\t\t\t\t\t\t\tbottom - pillarSize - pillarInset - 1, pillarSize + 2, pillarSize + 2, af);\n\n\t\t\t\t\t\tPainter.FillEllipse(level, left + pillarInset,\n\t\t\t\t\t\t\tbottom - pillarSize - pillarInset - (int) Math.Round(percentSkew * ySpaces) - 1, pillarSize + 2, pillarSize + 2,\n\t\t\t\t\t\t\tbf);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPainter.FillEllipse(level, left + 1 + pillarInset + (int) Math.Round(percentSkew * xSpaces), top + 1 + pillarInset,\n\t\t\t\t\t\tpillarSize, pillarSize, a);\n\n\t\t\t\t\tPainter.FillEllipse(level, right - pillarSize - pillarInset,\n\t\t\t\t\t\ttop + 1 + pillarInset + (int) Math.Round(percentSkew * ySpaces), pillarSize, pillarSize, b);\n\n\t\t\t\t\tPainter.FillEllipse(level, right - pillarSize - pillarInset - (int) Math.Round(percentSkew * xSpaces),\n\t\t\t\t\t\tbottom - pillarSize - pillarInset, pillarSize, pillarSize, a);\n\n\t\t\t\t\tPainter.FillEllipse(level, left + 1 + pillarInset,\n\t\t\t\t\t\tbottom - pillarSize - pillarInset - (int) Math.Round(percentSkew * ySpaces), pillarSize, pillarSize,\n\t\t\t\t\t\tb);\n\t\t\t\t} else {\n\t\t\t\t\tif (o) {\n\t\t\t\t\t\tPainter.Fill(level, left + pillarInset + (int) Math.Round(percentSkew * xSpaces), top + pillarInset,\n\t\t\t\t\t\t\tpillarSize + 2, pillarSize + 2, af);\n\n\t\t\t\t\t\tPainter.Fill(level, right - pillarSize - pillarInset - 1,\n\t\t\t\t\t\t\ttop + pillarInset + (int) Math.Round(percentSkew * ySpaces), pillarSize + 2, pillarSize + 2, bf);\n\n\t\t\t\t\t\tPainter.Fill(level, right - pillarSize - pillarInset - (int) Math.Round(percentSkew * xSpaces) - 1,\n\t\t\t\t\t\t\tbottom - pillarSize - pillarInset - 1, pillarSize + 2, pillarSize + 2, af);\n\n\t\t\t\t\t\tPainter.Fill(level, left + pillarInset,\n\t\t\t\t\t\t\tbottom - pillarSize - pillarInset - (int) Math.Round(percentSkew * ySpaces) - 1, pillarSize + 2, pillarSize + 2,\n\t\t\t\t\t\t\tbf);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPainter.Fill(level, left + 1 + pillarInset + (int) Math.Round(percentSkew * xSpaces), top + 1 + pillarInset,\n\t\t\t\t\t\tpillarSize, pillarSize, a);\n\n\t\t\t\t\tPainter.Fill(level, right - pillarSize - pillarInset,\n\t\t\t\t\t\ttop + 1 + pillarInset + (int) Math.Round(percentSkew * ySpaces), pillarSize, pillarSize, b);\n\n\t\t\t\t\tPainter.Fill(level, right - pillarSize - pillarInset - (int) Math.Round(percentSkew * xSpaces),\n\t\t\t\t\t\tbottom - pillarSize - pillarInset, pillarSize, pillarSize, a);\n\n\t\t\t\t\tPainter.Fill(level, left + 1 + pillarInset,\n\t\t\t\t\t\tbottom - pillarSize - pillarInset - (int) Math.Round(percentSkew * ySpaces), pillarSize, pillarSize,\n\t\t\t\t\t\tb);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/CornerWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class CornerWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar t = Tiles.RandomFillWall();\n\t\t\tvar hw = room.GetWidth() / 2;\n\t\t\tvar hh = room.GetHeight() / 2;\n\t\t\tvar before = Rnd.Chance();\n\t\t\tvar frame = Rnd.Chance();\n\n\t\t\tif (before && frame) {\n\t\t\t\tPainter.Rect(level, room, 1, Tile.Chasm);\n\t\t\t}\n\t\t\t\n\t\t\tswitch (Rnd.Int(4)) {\n\t\t\t\tcase 0: {\n\t\t\t\t\tPainter.Fill(level, room.Left + 1, room.Top + 1, hw, hh, t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 1: {\n\t\t\t\t\tPainter.Fill(level, room.Right - hw, room.Top + 1, hw, hh, t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 2: {\n\t\t\t\t\tPainter.Fill(level, room.Left + 1, room.Bottom - hh, hw, hh, t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tPainter.Fill(level, room.Right - hw, room.Bottom - hh, hw, hh, t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tvar s = Math.Min(inside.GetWidth(), inside.GetHeight());\n\t\t\t\tvar c = room.GetTileCenter();\n\t\t\t\tvar sz = s / 3;\n\t\t\t\tinside = new Rect(c.X - sz / 2, c.Y - sz / 2).Resize(sz, sz);\n\t\t\t\t\n\t\t\t\tPainter.Fill(level, inside, Tiles.Pick(Tile.Chasm, Tiles.RandomFillWall()));\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t\t\tPainter.Fill(level, inside, Tiles.Pick(Tile.Chasm, Tiles.RandomFillWall()));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!before && frame) {\n\t\t\t\tPainter.Rect(level, room, 1, Tile.Chasm);\n\t\t\t}\n\t\t\t\n\t\t\troom.PaintTunnel(level, Tiles.RandomFloor(), room.GetCenterRect(), Rnd.Chance(30));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/CorneredTurretWall.cs",
    "content": "using BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.walls {\n\tpublic class CorneredTurretWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tbase.Paint(level, room, inside);\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(room.Left + 2, room.Top + 2) * 16,\n\t\t\t\tStartingAngle = 1\n\t\t\t});\n\t\t\t\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(room.Right - 2, room.Top + 2) * 16,\n\t\t\t\tStartingAngle = 3\n\t\t\t});\n\t\t\t\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(room.Right - 2, room.Bottom - 2) * 16,\n\t\t\t\tStartingAngle = 5\n\t\t\t});\n\n\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\tPosition = new Vector2(room.Left + 2, room.Bottom - 2) * 16,\n\t\t\t\tStartingAngle = 7\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/EllipseWalls.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class EllipseWalls : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tPainter.Fill(level, room, Tiles.RandomWall());\n\n\t\t\tvar t = Tiles.RandomSolid();\n\n\t\t\tif (t == Tile.Lava) {\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFloor());\n\t\t\t}\n\n\t\t\tPainter.Fill(level, inside, t);\n\t\t\tPainter.FillEllipse(level, inside, Tiles.RandomFloor());\n\n\t\t\t// fixme: breaks custom floors\n\t\t\t\n\t\t\tvar before = Rnd.Chance();\n\n\t\t\tif (before) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), new Rect(room.GetCenter()), true);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), new Rect(room.GetCenter()));\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.Ellipse(level, inside,Tiles.RandomFloor());\n\t\t\t}\n\t\t\t\n\t\t\tif (!before) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), new Rect(room.GetCenter()), true);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\troom.PaintTunnel(level, Tiles.RandomNewFloor(), new Rect(room.GetCenter()));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/MazeWall.cs",
    "content": "using BurningKnight.level.rooms;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.util;\r\nusing BurningKnight.util.geometry;\r\nusing Lens.util.math;\r\n\r\nnamespace BurningKnight.level.walls {\r\n\tpublic class MazeWall : WallPainter {\r\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\r\n\t\t\tvar w = Tiles.RandomSolid();\r\n\t\t\tvar s = Rnd.Chance(40);\r\n\r\n\t\t\tvar maze = Maze.Generate(room);\r\n\t\t\t\r\n\t\t\tfor (int y = 1; y < maze[0].Length - 1; y++) {\r\n\t\t\t\tfor (int x = 1; x < maze.Length - 1; x++) {\r\n\t\t\t\t\tif (maze[x][y]) {\r\n\t\t\t\t\t\tPainter.Set(level, x + room.Left, y + room.Top, w);\r\n\t\t\t\t\t} else if (s && Rnd.Chance(20)) {\r\n\t\t\t\t\t\tPainter.Set(level, x + room.Left, y + room.Top, Tile.SensingSpikeTmp);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/level/walls/PatchWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.util;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class PatchWall : WallPainter {\n\t\tprotected bool[] Patch;\n\n\t\tprotected int ToIndex(RoomDef room, int x, int y) {\n\t\t\treturn (x - room.Left - 1) + (y - room.Top - 1) * (room.GetWidth() - 2);\n\t\t}\n\n\t\tprotected void Setup(Level level, RoomDef room, float fill, int clustering, bool ensurePath) {\n\t\t\tRun.Level = level;\n\t\t\tvar w = room.GetWidth() - 2;\n\t\t\tvar h = room.GetHeight() - 2;\n\t\t\t\n\t\t\tif (ensurePath) {\n\t\t\t\tPathFinder.SetMapSize(w, h);\n\t\t\t\t\n\t\t\t\tvar valid = false;\n\t\t\t\tvar attempt = 0;\n\n\t\t\t\tdo {\n\t\t\t\t\tPatch = BurningKnight.level.Patch.Generate(w, h, fill, clustering);\n\t\t\t\t\tvar start = 0;\n\n\t\t\t\t\tforeach (var d in room.Connected.Values) {\n\t\t\t\t\t\tif (d.X == room.Left) {\n\t\t\t\t\t\t\tstart = ToIndex(room, d.X + 1, d.Y);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X + 1, d.Y)] = false;\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X + 2, d.Y)] = false;\n\t\t\t\t\t\t} else if (d.X == room.Right) {\n\t\t\t\t\t\t\tstart = ToIndex(room, d.X - 1, d.Y);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X - 1, d.Y)] = false;\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X - 2, d.Y)] = false;\n\t\t\t\t\t\t} else if (d.Y == room.Top) {\n\t\t\t\t\t\t\tstart = ToIndex(room, d.X, d.Y + 1);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X, d.Y + 1)] = false;\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X, d.Y + 2)] = false;\n\t\t\t\t\t\t} else if (d.Y == room.Bottom) {\n\t\t\t\t\t\t\tstart = ToIndex(room, d.X, d.Y - 1);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X, d.Y - 1)] = false;\n\t\t\t\t\t\t\tPatch[ToIndex(room, d.X, d.Y - 2)] = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tPathFinder.BuildDistanceMap(start, BArray.Not(Patch, null));\n\t\t\t\t\tvalid = true;\n\n\t\t\t\t\tfor (var i = 0; i < Patch.Length; i++) {\n\t\t\t\t\t\tif (!Patch[i] && PathFinder.Distance[i] == Int32.MaxValue) {\n\t\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (!valid && fill > 0.1f) {\n\t\t\t\t\t\tfill -= 0.01f;\n\t\t\t\t\t}\n\t\t\t\t} while (attempt++ < 1000 && !valid);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tLog.Error(\"Failed to generate patch\");\n\n\t\t\t\t\tfor (var i = 0; i < Patch.Length; i++) {\n\t\t\t\t\t\tPatch[i] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPathFinder.SetMapSize(level.Width, level.Height);\n\t\t\t} else {\n\t\t\t\tPatch = BurningKnight.level.Patch.Generate(w, h, fill, clustering);\n\t\t\t}\n\t\t}\n\n\t\tprotected void PaintPatch(Level level, RoomDef room, Tile tile) {\n\t\t\tvar w = room.GetWidth() - 2;\n\t\t\t\n\t\t\tfor (var y = 0; y < room.GetHeight() - 2; y++) {\n\t\t\t\tfor (var x = 0; x < w; x++) {\n\t\t\t\t\tif (Patch[x + y * w]) {\n\t\t\t\t\t\tlevel.Set(room.Left + x + 1, room.Top + y + 1, Tile.FloorA);\t\t\t\t\t\t\n\t\t\t\t\t\tlevel.Set(room.Left + x + 1, room.Top + y + 1, tile);\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprotected void CleanDiagonalEdges(RoomDef room) {\n\t\t\tif (Patch == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar w = room.GetWidth() - 2;\n\n\t\t\tfor (var i = 0; i < Patch.Length - w - 1; i++) {\n\t\t\t\tif (!Patch[i]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (i % w != 0) {\n\t\t\t\t\tif (Patch[i - 1 + w] && !(Patch[i - 1] || Patch[i + w])) {\n\t\t\t\t\t\tPatch[i - 1 + w] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ((i + 1) % w != 0) {\n\t\t\t\t\tif (Patch[i + 1 + w] && !(Patch[i + 1] || Patch[i + w])) {\n\t\t\t\t\t\tPatch[i + 1 + w] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void SimplePaint(Level level, RoomDef room) {\n\t\t\tvar fill = 0.25f + (room.GetWidth() * room.GetHeight()) / 1024f;\n\n\t\t\tSetup(level, room, fill, 4, true);\n\t\t\tCleanDiagonalEdges(room);\n\t\t\tPaintPatch(level, room, Tiles.RandomSolid());\n\t\t}\n\t\t\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar fill = 0.25f + (room.GetWidth() * room.GetHeight()) / 1024f;\n\t\t\tvar s = Rnd.Chance();\n\t\t\tbool[] oldPatch = null;\n\t\t\t\n\t\t\tif (s) {\n\t\t\t\tSetup(level, room, fill, 4, true);\n\t\t\t\tCleanDiagonalEdges(room);\n\t\t\t\tPaintPatch(level, room, Tiles.RandomSolid());\n\t\t\t\toldPatch = ArrayUtils.Clone(Patch);\n\t\t\t}\n\t\t\t\n\t\t\tSimplePaint(level, room);\n\n\t\t\tif (s) {\n\t\t\t\tPathFinder.SetMapSize(room.GetWidth() - 2, room.GetHeight() - 2);\n\t\t\t\tvar start = 0;\n\n\t\t\t\tforeach (var d in room.Connected.Values) {\n\t\t\t\t\tif (d.X == room.Left) {\n\t\t\t\t\t\tstart = ToIndex(room, d.X + 1, d.Y);\n\t\t\t\t\t} else if (d.X == room.Right) {\n\t\t\t\t\t\tstart = ToIndex(room, d.X - 1, d.Y);\n\t\t\t\t\t} else if (d.Y == room.Top) {\n\t\t\t\t\t\tstart = ToIndex(room, d.X, d.Y + 1);\n\t\t\t\t\t} else if (d.Y == room.Bottom) {\n\t\t\t\t\t\tstart = ToIndex(room, d.X, d.Y - 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < Patch.Length; i++) {\n\t\t\t\t\tif (oldPatch[i]) {\n\t\t\t\t\t\tPatch[i] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tPathFinder.BuildDistanceMap(start, BArray.Not(Patch, null));\n\t\t\t\tvar valid = true;\n\n\t\t\t\tfor (var i = 0; i < Patch.Length; i++) {\n\t\t\t\t\tif (!Patch[i] && PathFinder.Distance[i] == Int32.MaxValue) {\n\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tPathFinder.SetMapSize(level.Width, level.Height);\n\n\t\t\t\tif (!valid) {\n\t\t\t\t\tPainter.Fill(level, room, 1, Tiles.RandomFloor());\n\t\t\t\t\tSimplePaint(level, room);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/PlatformWall.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class PlatformWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tPainter.Fill(level, room, 1, Tiles.Pick(Tile.Chasm, Tile.SensingSpikeTmp));\n\n\t\t\tvar f = Tiles.RandomFloor();\n\t\t\tPainter.Fill(level, room, Rnd.Int(2, 4), f);\n\t\t\t\n\t\t\troom.PaintTunnel(level, Rnd.Chance(30) ? f : Tiles.RandomFloorOrSpike(), room.GetCenterRect());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/RuinsWall.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class RuinsWall : PatchWall {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar fill = 0.25f + (room.GetWidth() * room.GetHeight()) / 2048f;\n\t\t\tvar t = Rnd.Chance(20) ? Tile.Lava : Tiles.RandomFloorOrSpike();\n\t\t\t\n\t\t\tSetup(level, room, fill, 0, true);\n\t\t\tCleanDiagonalEdges(room);\n\n\t\t\tfor (var i = room.Top + 1; i < room.Bottom; i++) {\n\t\t\t\tfor (var j = room.Left + 1; j < room.Right; j++) {\n\t\t\t\t\tif (Patch[ToIndex(room, j, i)]) {\n\t\t\t\t\t\tlevel.Set(j, i, t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/SegmentedWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.walls {\n\tpublic class SegmentedWall : WallPainter {\n\t\tprivate bool fl;\n\t\t\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar t = Tiles.RandomSolid();\n\t\t\tfl = Rnd.Chance(10);\n\n\t\t\tCreateWalls(level, new Rect(room.Left + 1, room.Top + 1, room.Right - 1, room.Bottom - 1), t);\n\t\t}\n\n\t\tprivate void CreateWalls(Level level, Rect area, Tile tile) {\n\t\t\tvar w = area.GetWidth();\n\t\t\tvar h = area.GetHeight();\n\t\t\t\n\t\t\tif (Math.Max(w + 1, h + 1) < 5 ||\n\t\t\t    Math.Min(w + 1, h + 1) < 5) {\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar tries = 10;\n\n\t\t\tif (w > h || (w == h && Rnd.Chance())) {\n\t\t\t\tdo {\n\t\t\t\t\tvar splitX = Rnd.Int(area.Left + 2, area.Right - 2);\n\n\t\t\t\t\tif (level.Get(splitX, area.Top - 1) == tile && level.Get(splitX, area.Bottom + 1) == tile) {\n\t\t\t\t\t\ttries = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tPainter.DrawLine(level, new Dot(splitX, area.Top),\n\t\t\t\t\t\t\tnew Dot(splitX, area.Bottom), tile);\n\n\t\t\t\t\t\tvar space = Rnd.Int(area.Top, area.Bottom - 1);\n\t\t\t\t\t\tvar f = fl ? Tile.SensingSpikeTmp : Tiles.RandomFloorOrSpike();\n\t\t\t\t\t\t\n\t\t\t\t\t\tPainter.Set(level, splitX, space, f);\n\t\t\t\t\t\tPainter.Set(level, splitX, space + 1, f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tCreateWalls(level, new Rect(area.Left, area.Top, splitX - 1, area.Bottom), tile);\n\t\t\t\t\t\tCreateWalls(level, new Rect(splitX + 1, area.Top, area.Right, area.Bottom), tile);\n\t\t\t\t\t}\n\t\t\t\t} while (tries-- > 0);\n\t\t\t} else {\n\t\t\t\tdo {\n\t\t\t\t\tvar splitY = Rnd.Int(area.Top + 2, area.Bottom - 2);\n\n\t\t\t\t\tif (level.Get(area.Left - 1, splitY) == tile && level.Get(area.Right + 1, splitY) == tile) {\n\t\t\t\t\t\ttries = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tPainter.DrawLine(level, new Dot(area.Left, splitY), new Dot(area.Right, splitY), tile);\n\n\t\t\t\t\t\tvar space = Rnd.Int(area.Left, area.Right - 1);\n\t\t\t\t\t\tvar f = fl ? Tile.SensingSpikeTmp : Tiles.RandomFloorOrSpike();\n\t\t\t\t\t\t\n\t\t\t\t\t\tPainter.Set(level, space, splitY, f);\n\t\t\t\t\t\tPainter.Set(level, space + 1, splitY, f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tCreateWalls(level, new Rect(area.Left, area.Top, area.Right, splitY - 1), tile);\n\t\t\t\t\t\tCreateWalls(level, new Rect(area.Left, splitY + 1, area.Right, area.Bottom), tile);\n\t\t\t\t\t}\n\t\t\t\t} while (--tries > 0);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/SplitWall.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class SplitWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar m = Rnd.Chance();\n\t\t\t\n\t\t\tif (m) {\n\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + 1, room.Top + room.GetHeight() / 2), new Dot(room.Right - 1, room.Top + room.GetHeight() / 2), Tile.Chasm);\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + 1, room.Top + room.GetHeight() / 2 + 1), new Dot(room.Right - 1, room.Top + room.GetHeight() / 2 + 1), Tile.Chasm);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!m || Rnd.Chance()) {\n\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + room.GetWidth() / 2, room.Top + 1), new Dot(room.Left + room.GetWidth() / 2, room.Bottom - 1), Tile.Chasm);\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + room.GetWidth() / 2 + 1, room.Top + 1), new Dot(room.Left + room.GetWidth() / 2 + 1, room.Bottom - 1), Tile.Chasm);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tvar s = Math.Min(inside.GetWidth(), inside.GetHeight());\n\t\t\t\tvar c = room.GetTileCenter();\n\t\t\t\tvar sz = s / 2;\n\t\t\t\tinside = new Rect(c.X - sz / 2, c.Y - sz / 2).Resize(sz, sz);\n\t\t\t\t\n\t\t\t\tPainter.Fill(level, inside, Tiles.RandomFillWall());\n\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tinside = inside.Shrink(Rnd.Int(1, 3));\n\t\t\t\t\tPainter.Fill(level, inside, Tiles.Pick(Tile.Chasm, Tiles.RandomFillWall()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/TempleWalls.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls {\n\tpublic class TempleWalls : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tvar m = 2;\n\t\t\tvar f = Tiles.RandomFloorOrSpike();\n\t\t\tvar bold = Rnd.Chance(30);\n\n\t\t\tinside = inside.Shrink(m);\n\t\t\t\n\t\t\tPainter.Fill(level, inside, Tiles.RandomSolid());\n\t\t\tPainter.Fill(level, inside, 1, f);\n\n\t\t\tPainter.Set(level, inside.Left, inside.Top + inside.GetHeight() / 2, f);\n\t\t\tPainter.Set(level, inside.Right - 1, inside.Top + inside.GetHeight() / 2, f);\n\t\t\t\n\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2, inside.Top, f);\n\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2, inside.Bottom - 1, f);\n\n\t\t\tif (bold) {\n\t\t\t\tPainter.Set(level, inside.Left, inside.Top + inside.GetHeight() / 2 - 1, f);\n\t\t\t\tPainter.Set(level, inside.Right - 1, inside.Top + inside.GetHeight() / 2 - 1, f);\n\t\t\t\n\t\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2 - 1, inside.Top, f);\n\t\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2 - 1, inside.Bottom - 1, f);\n\t\t\t\t\n\t\t\t\tPainter.Set(level, inside.Left, inside.Top + inside.GetHeight() / 2 + 1, f);\n\t\t\t\tPainter.Set(level, inside.Right - 1, inside.Top + inside.GetHeight() / 2 + 1, f);\n\t\t\t\n\t\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2 + 1, inside.Top, f);\n\t\t\t\tPainter.Set(level, inside.Left + inside.GetWidth() / 2 + 1, inside.Bottom - 1, f);\n\t\t\t} else if (Rnd.Chance()) {\n\t\t\t\tf = Tiles.RandomFloor();\n\t\t\t\t\n\t\t\t\tPainter.Set(level, inside.Left, inside.Top, f);\n\t\t\t\tPainter.Set(level, inside.Right - 1, inside.Top, f);\n\t\t\t\n\t\t\t\tPainter.Set(level, inside.Left, inside.Bottom - 1, f);\n\t\t\t\tPainter.Set(level, inside.Right - 1, inside.Bottom - 1, f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/TurretWall.cs",
    "content": "using BurningKnight.entity.room.controllable.turret;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.level.walls {\n\tpublic class TurretWall : WallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tbase.Paint(level, room, inside);\n\n\t\t\tvar c = room.GetTileCenter() * 16;\n\t\t\tvar m = 16;\n\t\t\tvar r = Rnd.Chance();\n\t\t\tvar t = Rnd.Chance(30);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tlevel.Area.Add(new QuadRotatingTurret {\n\t\t\t\t\t\tPosition = c\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlevel.Area.Add(new QuadTurret {\n\t\t\t\t\t\tPosition = c\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (Rnd.Chance()) {\n\t\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\t\tPosition = c + new Vector2(m, m),\n\t\t\t\t\t\tStartingAngle = 1,\n\t\t\t\t\t\tReverseDirection = t ? !r : r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\t\tPosition = c + new Vector2(m, -m),\n\t\t\t\t\t\tStartingAngle = 7,\n\t\t\t\t\t\tReverseDirection = r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\t\tPosition = c + new Vector2(-m, m),\n\t\t\t\t\t\tStartingAngle = 3,\n\t\t\t\t\t\tReverseDirection = t ? !r : r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\t\tPosition = c + new Vector2(-m, -m),\n\t\t\t\t\t\tStartingAngle = 5,\n\t\t\t\t\t\tReverseDirection = r\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlevel.Area.Add(new Turret {\n\t\t\t\t\t\tPosition = c + new Vector2(m, m),\n\t\t\t\t\t\tStartingAngle = 1,\n\t\t\t\t\t\tReverseDirection = t ? !r : r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new RotatingTurret {\n\t\t\t\t\t\tPosition = c + new Vector2(m, -m),\n\t\t\t\t\t\tStartingAngle = 7,\n\t\t\t\t\t\tReverseDirection = r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new RotatingTurret {\n\t\t\t\t\t\tPosition = c + new Vector2(-m, m),\n\t\t\t\t\t\tStartingAngle = 3,\n\t\t\t\t\t\tReverseDirection = t ? !r : r\n\t\t\t\t\t});\n\n\t\t\t\t\tlevel.Area.Add(new RotatingTurret {\n\t\t\t\t\t\tPosition = c + new Vector2(-m, -m),\n\t\t\t\t\t\tStartingAngle = 5,\n\t\t\t\t\t\tReverseDirection = r\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/WallPainter.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.walls {\n\tpublic class WallPainter {\n\t\tpublic virtual void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/WallRegistry.cs",
    "content": "using BurningKnight.entity.pool;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.walls.library;\nusing BurningKnight.state;\nusing BurningKnight.util.geometry;\n\nnamespace BurningKnight.level.walls {\n\tpublic class WallRegistry : Pool<WallPainter> {\n\t\tpublic static WallRegistry Instance = new WallRegistry();\n\n\t\tpublic WallRegistry() {\n\t\t\tSetupRooms();\n\t\t}\n\n\t\tpublic void ResetForBiome(Biome biome) {\n\t\t\tClear();\n\t\t\tSetupRooms();\n\n\t\t\tif (Run.Type == RunType.BossRush) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (biome is JungleBiome || biome is CaveBiome) {\n\t\t\t\tAdd(new PatchWall(), 5f);\n\t\t\t} else if (biome is LibraryBiome) {\n\t\t\t\tAdd(new TeleportSplitWall(), 5f);\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void SetupRooms() {\n\t\t\tAdd(new WallPainter(), 1f);\n\n\t\t\tAdd(new CollumnWall(), 1f);\n\t\t\tAdd(new SplitWall(), 0.5f);\n\t\t\tAdd(new CornerWall(), 1f);\n\t\t\tAdd(new CollumsWall(), 1f);\n\t\t\tAdd(new PlatformWall(), 1f);\n\t\t\tAdd(new EllipseWalls(), 1f);\n\t\t\tAdd(new TempleWalls(), 1f);\n\t\t\tAdd(new SegmentedWall(), 1f);\n\t\t\tAdd(new RuinsWall(), 1f);\n\t\t\tAdd(new TurretWall(), 0.2f);\n\t\t\tAdd(new CorneredTurretWall(), 0.1f);\n\n\t\t\tAdd(new PatchWall(), 0.5f);\n\t\t}\n\n\t\tpublic static void Paint(Level level, RoomDef room, WallRegistry registry = null, int i = -1) {\n\t\t\tvar painter = i == -1 ? (registry ?? Instance).Generate() : (registry ?? Instance).Get(i);\n\t\t\tpainter.Paint(level, room, new Rect(room.Left + 1, room.Top + 1, \n\t\t\t\troom.Left + 1 + room.GetWidth() - 2, room.Top + 1 + room.GetHeight() - 2));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/library/LibraryWallPainter.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls.library {\n\tpublic class LibraryWallPainter : WallPainter {\n\t\tprivate List<string> unusedTeleporters = new List<string>();\n\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tbase.Paint(level, room, inside);\n\t\t\tunusedTeleporters.AddRange(Teleporter.Ids);\n\t\t}\n\n\t\tpublic void PlaceTeleporter(Level level, Dot a, Dot b) {\n\t\t\tvar index = Rnd.Int(unusedTeleporters.Count);\n\t\t\tvar id = unusedTeleporters[index];\n\n\t\t\tunusedTeleporters.RemoveAt(index);\n\n\t\t\tvar at = new Teleporter {\n\t\t\t\tId = id\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(at);\n\t\t\tat.Position = a * 16;\n\t\t\t\n\t\t\tPainter.Set(level, a, Tiles.RandomFloor());\n\t\t\t\n\t\t\tvar bt = new Teleporter {\n\t\t\t\tId = id\n\t\t\t};\n\t\t\t\n\t\t\tlevel.Area.Add(bt);\n\t\t\tbt.Position = b * 16;\n\t\t\t\n\t\t\tPainter.Set(level, b, Tiles.RandomFloor());\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/level/walls/library/TeleportSplitWall.cs",
    "content": "using BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.util.geometry;\nusing Lens.util.math;\n\nnamespace BurningKnight.level.walls.library {\n\tpublic class TeleportSplitWall : LibraryWallPainter {\n\t\tpublic override void Paint(Level level, RoomDef room, Rect inside) {\n\t\t\tbase.Paint(level, room, inside);\n\t\t\tvar t = Tiles.Pick(Tile.WallA, Tile.Planks);\n\n\t\t\tif (Rnd.Chance()) {\n\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + room.GetWidth() / 2, room.Top + 1), new Dot(room.Left + room.GetWidth() / 2, room.Bottom - 1), t);\n\t\t\t\tPlaceTeleporter(level, new Dot(room.Left + room.GetWidth() / 4, Rnd.Int(room.Top + 3, room.Bottom - 3)), new Dot(room.Left + room.GetWidth() / 4 * 3, Rnd.Int(room.Top + 3, room.Bottom - 3)));\n\t\t\t} else {\n\t\t\t\tPainter.DrawLine(level, new Dot(room.Left + 1, room.Top + room.GetHeight() / 2), new Dot(room.Right - 1, room.Top + room.GetHeight() / 2), t);\n\t\t\t\tPlaceTeleporter(level, new Dot(Rnd.Int(room.Left + 3, room.Right - 3), room.Top + room.GetHeight() / 4), new Dot(Rnd.Int(room.Left + 3, room.Right - 3), room.Top + room.GetHeight() / 4 * 3));\t\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Facepunch.Steamworks\" version=\"2.3.3\" targetFramework=\"net472\" />\n  <package id=\"ImGui.NET\" version=\"1.70.0\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Extended\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Content.Pipeline\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Graphics\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Tiled\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.Content.Pipeline.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Framework.DesktopGL.Core\" version=\"3.8.0.13\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n  <package id=\"Newtonsoft.Json\" version=\"12.0.3\" targetFramework=\"net472\" />\n  <package id=\"System.Buffers\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Numerics.Vectors\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.CompilerServices.Unsafe\" version=\"4.5.0-preview2-26406-04\" targetFramework=\"net472\" />\n  <package id=\"TextCopy\" version=\"1.7.1\" targetFramework=\"net471\" />\n</packages>"
  },
  {
    "path": "BurningKnight/physics/CollisionFilterEntity.cs",
    "content": "﻿using Lens.entity;\n\nnamespace BurningKnight.physics {\n\tpublic interface CollisionFilterEntity {\n\t\tbool ShouldCollide(Entity entity);\n\t}\n}"
  },
  {
    "path": "BurningKnight/physics/CollisionResult.cs",
    "content": "namespace BurningKnight.physics {\r\n\tpublic enum CollisionResult {\r\n\t\tEnable,\r\n\t\tDisable,\r\n\t\tDefault\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/physics/Physics.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing BurningKnight.entity.component;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Dynamics;\n\nnamespace BurningKnight.physics {\n\tpublic class Physics {\n\t\tpublic static World World;\n\t\tpublic static PhysicsDebugRenderer Debug;\n\t\tpublic static bool RenderDebug = false;\n\n\t\tpublic static Fixture Fixture;\n\n\t\tprivate static bool locked;\n\t\tprivate static List<Body> toRemove = new List<Body>();\n\n\t\tpublic static void Init() {\n\t\t\tWorld = new World(Vector2.Zero);\n\t\t\tDebug = new PhysicsDebugRenderer(World);\n\n\t\t\tWorld.ContactManager.PreSolve += PreSolve;\n\n\t\t\tWorld.ContactManager.BeginContact += BeginContact;\n\t\t\tWorld.ContactManager.EndContact += EndContact;\n\t\t}\n\n\t\t\n\t\t\n\t\tprivate static void RemoveBodies() {\n\t\t\tif (locked || World == null || toRemove.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var b in toRemove) {\n\t\t\t\ttry {\n\t\t\t\t\tWorld.RemoveBody(b);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttoRemove.Clear();\n\t\t}\n\n\t\tpublic static void RemoveBody(Body body) {\n\t\t\tif (!toRemove.Contains(body)) {\n\t\t\t\ttoRemove.Add(body);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void PreSolve(Contact contact, ref Manifold oldManifold) {\n\t\t\tvar a = contact.FixtureA.Body.UserData;\n\t\t\tvar b = contact.FixtureB.Body.UserData;\n\n\t\t\tif (a is BodyComponent ac && b is BodyComponent bc) {\n\t\t\t\tif (ac.Entity.TryGetComponent<CollisionFilterComponent>(out var af)) {\n\t\t\t\t\tvar v = af.Invoke(bc.Entity);\n\n\t\t\t\t\tif (v == CollisionResult.Disable) {\n\t\t\t\t\t\tcontact.Enabled = false;\n\t\t\t\t\t} else if (v == CollisionResult.Enable) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (bc.Entity.TryGetComponent<CollisionFilterComponent>(out var bf)) {\n\t\t\t\t\tvar v = bf.Invoke(ac.Entity);\n\n\t\t\t\t\tif (v == CollisionResult.Disable) {\n\t\t\t\t\t\tcontact.Enabled = false;\n\t\t\t\t\t} else if (v == CollisionResult.Enable) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!ac.ShouldCollide(bc.Entity) || !bc.ShouldCollide(ac.Entity)) {\n\t\t\t\t\tcontact.Enabled = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static bool BeginContact(Contact contact) {\n\t\t\tvar a = contact.FixtureA.Body.UserData;\n\t\t\tvar b = contact.FixtureB.Body.UserData;\n\t\t\t\n\t\t\tif (a is BodyComponent ac && b is BodyComponent bc) {\n\t\t\t\tFixture = contact.FixtureB;\n\t\t\t\tac.OnCollision(bc.Entity);\n\t\t\t\n\t\t\t\tFixture = contact.FixtureA;\n\t\t\t\tbc.OnCollision(ac.Entity);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic static void EndContact(Contact contact) {\n\t\t\tvar a = contact.FixtureA.Body.UserData;\n\t\t\tvar b = contact.FixtureB.Body.UserData;\n\n\t\t\tif (a is BodyComponent ac && b is BodyComponent bc) {\n\t\t\t\tac.OnCollisionEnd(bc.Entity);\n\t\t\t\tbc.OnCollisionEnd(ac.Entity);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Update(float dt) {\n\t\t\tif (World == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\ttry {\n\t\t\t\tRemoveBodies();\n\t\t\t\t\n\t\t\t\tlocked = true;\n\t\t\t\tWorld.Step(dt);\n\t\t\t\tlocked = false;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Render() {\n\t\t\tif (RenderDebug) {\n\t\t\t\tDebug.DrawDebugData();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tif (locked) {\n\t\t\t\tLog.Error(\"World was locked when destroying\");\n\t\t\t}\n\t\t\t\n\t\t\ttry {\n\t\t\t\tRemoveBodies();\n\t\t\t\tWorld?.Clear();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tWorld = null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/physics/PhysicsDebugRenderer.cs",
    "content": "﻿using System.Diagnostics;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace BurningKnight.physics {\n\tpublic class PhysicsDebugRenderer {\n\t\tprivate const float alpha = 0.7f;\n\n\t\tpublic Color DefaultShapeColor = new Color(0.9f, 0.7f, 0.7f, alpha);\n\t\tpublic Color InactiveShapeColor = new Color(0.5f, 0.5f, 0.3f, alpha);\n\t\tpublic Color KinematicShapeColor = new Color(0.5f, 0.5f, 0.9f, alpha);\n\t\tpublic Color SleepingShapeColor = new Color(0.6f, 0.6f, 0.6f, alpha);\n\t\tpublic Color StaticShapeColor = new Color(0.5f, 0.9f, 0.5f, alpha);\n\t\t\n\t\tprivate World world;\n\n\t\tpublic PhysicsDebugRenderer(World world) {\n\t\t\tthis.world = world;\n\t\t}\n\t\t\n\t\tpublic void DrawSolidPolygon(Vector2[] vertices, int count, Color color) {\n\t\t\tGraphics.Batch.DrawPolygon(Vector2.Zero, vertices, color);\n\t\t}\n\n\t\tpublic void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, Color color) {\n\t\t\tGraphics.Batch.DrawCircle(center, radius, 32, color);\n\t\t}\n\n\t\tpublic void DrawDebugData() {\n\t\t\tforeach (var b in world.BodyList) {\n\t\t\t\tb.GetTransform(out var xf);\n\t\t\t\t\n\t\t\t\tforeach (var f in b.FixtureList) {\n\t\t\t\t\tif (b.Enabled == false) {\n\t\t\t\t\t\tDrawShape(f, xf, InactiveShapeColor);\n\t\t\t\t\t} else if (b.BodyType == BodyType.Static) {\n\t\t\t\t\t\tDrawShape(f, xf, StaticShapeColor);\n\t\t\t\t\t} else if (b.BodyType == BodyType.Kinematic) {\n\t\t\t\t\t\tDrawShape(f, xf, KinematicShapeColor);\n\t\t\t\t\t} else if (b.Awake == false) {\n\t\t\t\t\t\tDrawShape(f, xf, SleepingShapeColor);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tDrawShape(f, xf, DefaultShapeColor);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void DrawShape(Fixture fixture, Transform xf, Color color) {\n\t\t\t// todo: dont draw if offscreen\n\t\t\tswitch (fixture.Shape.ShapeType) {\n\t\t\t\tcase ShapeType.Circle: {\n\t\t\t\t\tvar circle = (CircleShape) fixture.Shape;\n\n\t\t\t\t\tvar center = MathUtils.Mul(ref xf, circle.Position);\n\t\t\t\t\tvar radius = circle.Radius;\n\t\t\t\t\tvar axis = MathUtils.Mul(xf.q, new Vector2(1.0f, 0.0f));\n\n\t\t\t\t\tDrawSolidCircle(center, radius, axis, color);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase ShapeType.Polygon: {\n\t\t\t\t\tvar poly = (PolygonShape) fixture.Shape;\n\t\t\t\t\tvar vertexCount = poly.Vertices.Count;\n\t\t\t\t\tDebug.Assert(vertexCount <= VelcroPhysics.Settings.MaxPolygonVertices);\n\t\t\t\t\tvar _tempVertices = new Vector2[vertexCount];\n\n\t\t\t\t\tfor (var i = 0; i < vertexCount; ++i) {\n\t\t\t\t\t\t_tempVertices[i] = MathUtils.Mul(ref xf, poly.Vertices[i]);\n\t\t\t\t\t}\n\n\t\t\t\t\tDrawSolidPolygon(_tempVertices, vertexCount, color);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/EntitySaver.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.util;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.save {\r\n\tpublic abstract class EntitySaver : Saver {\r\n\t\tpublic class Comparer : IComparer<Entity> {\r\n\t\t\tpublic int Compare(Entity x, Entity y) {\r\n\t\t\t\treturn x.GetType().FullName.CompareTo(y.GetType().FullName);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static Comparer DefaultComparer;\r\n\t\tpublic static bool Loading;\r\n\t\t\r\n\t\tpublic void SmartSave(List<Entity> a, FileWriter writer) {\r\n\t\t\ta.Sort(DefaultComparer);\r\n\r\n\t\t\tvar all = new List<Entity>();\r\n\r\n\t\t\tforeach (var e in a) {\r\n\t\t\t\tif (e != null && !e.Done) {\r\n\t\t\t\t\tall.Add(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\twriter.WriteInt32(all.Count);\r\n\t\t\t\r\n\t\t\tSaveableEntity last = null;\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < all.Count; i++) {\r\n\t\t\t\tvar entity = (SaveableEntity) all[i];\r\n\r\n\t\t\t\tif (last != null && last.GetType().FullName == entity.GetType().FullName) {\r\n\t\t\t\t\twriter.WriteString(null);\r\n\t\t\t\t} else {\r\n\t\t\t\t\twriter.WriteString(entity.GetType().FullName.Replace(\"BurningKnight.\", \"\"));\r\n\t\t\t\t}\r\n\r\n\t\t\t\twriter.Cache = true;\r\n\t\t\t\tentity.Save(writer);\r\n\t\t\t\twriter.Cache = false;\r\n\r\n\t\t\t\twriter.WriteUint16((ushort) writer.CacheSize);\r\n\t\t\t\twriter.Flush();\r\n\t\t\t\t\r\n\t\t\t\tlast = entity;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Load(Area area, FileReader reader) {\r\n\t\t\tLoad(area, reader);\r\n\t\t}\r\n\r\n\t\tpublic void Load(Area area, FileReader reader, bool post = true) {\r\n\t\t\tvar count = reader.ReadInt32();\r\n\t\t\tvar lastType = \"\";\r\n\r\n\t\t\tLoading = true;\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < count; i++) {\r\n\t\t\t\tvar type = reader.ReadString();\r\n\r\n\t\t\t\tif (type == null) {\r\n\t\t\t\t\ttype = lastType;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tReadEntity(area, reader, type, post);\r\n\t\t\t\t\r\n\t\t\t\tlastType = type;\r\n\t\t\t}\r\n\r\n\t\t\tLoading = false;\r\n\t\t}\r\n\r\n\t\tprotected virtual void ReadEntity(Area area, FileReader reader, string type, bool post) {\r\n\t\t\tvar size = reader.ReadUint16();\r\n\t\t\tvar position = reader.Position;\r\n\r\n\t\t\ttry {\r\n\t\t\t\tvar entity = (SaveableEntity) Activator.CreateInstance(Type.GetType($\"BurningKnight.{type}\", true, false));\r\n\t\t\t\tarea.Add(entity, false);\r\n\r\n\t\t\t\tentity.Load(reader);\r\n\t\t\t\tvar sum = reader.Position - position - size;\r\n\r\n\t\t\t\tif (sum != 0) {\r\n\t\t\t\t\tLog.Error($\"Entity {entity.GetType().FullName} was expected to read {size} bytes but read {reader.Position - position}!\");\r\n\t\t\t\t\treader.Position -= sum;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (post) {\r\n\t\t\t\t\tentity.PostInit();\r\n\t\t\t\t}\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error($\"Failed to load {type}\");\r\n\t\t\t\tLog.Error(e);\r\n\r\n\t\t\t\treader.Position = position + size;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprotected EntitySaver(SaveType type) : base(type) {\r\n\t\t\t\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/save/GameSave.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.save {\n\tpublic class GameSave : Saver {\n\t\tpublic static Dictionary<string, string> Values = new Dictionary<string, string>();\n\n\t\tpublic static bool IsTrue(string Key, bool Def = false) {\n\t\t\tif (Values.TryGetValue(Key, out var Value)) {\n\t\t\t\treturn Value == \"1\";\n\t\t\t}\n\t\t\t\n\t\t\treturn Def;\n\t\t}\n\n\t\tpublic static bool IsFalse(string Key) {\n\t\t\treturn !IsTrue(Key);\n\t\t}\n\n\t\tpublic static void Put(string Key, object Val) {\n\t\t\tValues[Key] = Val?.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, int Val) {\n\t\t\tValues[Key] = Val.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, float Val) {\n\t\t\tValues[Key] = Val.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, bool Val) {\n\t\t\tValues[Key] = Val ? \"1\" : \"0\";\n\t\t}\n\n\t\tpublic static string GetString(string Key, string Def = null) {\n\t\t\treturn Values.TryGetValue(Key, out var Value) ? Value : Def;\n\t\t}\n\t\t\n\t\tpublic static int GetInt(string Key, int Def = 0) {\n\t\t\ttry {\n\t\t\t\treturn Values.TryGetValue(Key, out var Value) ? Int32.Parse(Value) : Def;\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Def;\n\t\t\t}\n\t\t}\n\n\t\tpublic static float GetFloat(string Key, float Def = 0) {\n\t\t\ttry {\t\t\t\n\t\t\t\treturn Values.TryGetValue(Key, out var Value) ? Single.Parse(Value) : Def;\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Def;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\twriter.WriteInt32(Values.Count);\n\n\t\t\tforeach (var Pair in Values) {\n\t\t\t\twriter.WriteString(Pair.Key);\n\t\t\t\twriter.WriteString(Pair.Value);\n\t\t\t}\n\t\t\n\t\t\twriter.WriteSbyte((sbyte) Run.Depth);\n\t\t\twriter.WriteInt32(Run.KillCount);\n\t\t\twriter.WriteFloat(Run.Time);\n\t\t\twriter.WriteByte((byte) Run.PermanentScourge);\n\t\t\twriter.WriteString(Run.Seed);\n\t\t\twriter.WriteString(Run.Type.ToString());\n\t\t\twriter.WriteInt32(Run.DailyId);\n\t\t\twriter.WriteInt32(Run.Loop);\n\t\t\twriter.WriteBoolean(Run.CustomSeed);\n\t\t}\n\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\treturn $\"{path}game.sv\";\n\t\t}\n\n\t\tpublic override void Load(Area area, FileReader reader) {\n\t\t\tif (Run.HasRun) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tValues.Clear();\n\t\t\tvar Count = reader.ReadInt32();\n\n\t\t\tfor (var I = 0; I < Count; I++) {\n\t\t\t\tvar Key = reader.ReadString();\n\t\t\t\tvar Val = reader.ReadString();\n\t\t\t\t\n\t\t\t\tValues[Key] = Val;\n\t\t\t}\n\n\t\t\tRun.HasRun = true;\n\t\t\tRun.LastSavedDepth = reader.ReadSbyte();\n\t\t\t\n\t\t\tRun.KillCount = reader.ReadInt32();\n\t\t\tRun.Time = reader.ReadFloat();\n\n\t\t\tRun.PermanentScourge = reader.ReadByte();\n\n\t\t\tvar seed = reader.ReadString();\n\t\t\tif (Run.LastSavedDepth > 0) {\n\t\t\t\tRnd.Seed = Run.Seed = seed;\n\t\t\t}\n\n\t\t\tif (Enum.TryParse<RunType>(reader.ReadString(), out var t)) {\n\t\t\t\tRun.Type = t;\n\t\t\t} else {\n\t\t\t\tRun.Type = RunType.Regular;\n\t\t\t}\n\n\t\t\tRun.DailyId = reader.ReadInt32();\n\t\t\tRun.Loop = reader.ReadInt32();\n\t\t\tRun.CustomSeed = reader.ReadBoolean();\n\t\t}\n\n\t\tpublic static int PeekDepth(FileReader reader) {\n\t\t\treturn reader.ReadSbyte();\n\t\t}\n\t\t\n\t\tpublic override void Generate(Area area) {\n\t\t\tValues.Clear();\n\t\t\tRun.ResetStats();\n\t\t\t\n\t\t\tif (GlobalSave.IsFalse(\"finished_tutorial\")) {\n\t\t\t\tif (BK.Version.Dev) {\n\t\t\t\t\tGlobalSave.Put(\"finished_tutorial\", true);\n\t\t\t\t} else if (Run.Depth != -2 && Run.Depth != -3) {\n\t\t\t\t\tRun.Depth = -3;\n\t\t\t\t\tRun.IntoMenu = true;\n\t\t\t\t\tLog.Info(\"Throwing the player into tutorial\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPut(\"mimic_chance\", 0.2f);\n\t\t}\n\n\t\tpublic GameSave() : base(SaveType.Game) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Delete() {\n\t\t\tbase.Delete();\n\t\t\tValues.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/GlobalSave.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.entity.creature.npc;\nusing Lens.entity;\nusing Lens.lightJson;\nusing Lens.util.file;\n\nnamespace BurningKnight.save {\n\tpublic class GlobalSave : Saver {\n\t\tpublic static Dictionary<string, string> Values = new Dictionary<string, string>();\n\t\tpublic static uint RunId;\n\t\tpublic static int Emeralds;\n\t\t\n\t\tpublic static bool IsTrue(string Key) {\n\t\t\treturn IsTrue(Key, false);\n\t\t}\n\n\t\tpublic static bool IsTrue(string Key, bool Def = false) {\n\t\t\tif (Values.TryGetValue(Key, out var Value)) {\n\t\t\t\treturn Value == \"1\";\n\t\t\t}\n\t\t\t\n\t\t\treturn Def;\n\t\t}\n\n\t\tpublic static bool IsFalse(string Key) {\n\t\t\treturn !IsTrue(Key);\n\t\t}\n\n\t\tpublic static void Put(string Key, object Val) {\n\t\t\tValues[Key] = Val?.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, int Val) {\n\t\t\tValues[Key] = Val.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, float Val) {\n\t\t\tValues[Key] = Val.ToString();\n\t\t}\n\n\t\tpublic static void Put(string Key, bool Val) {\n\t\t\tValues[Key] = Val ? \"1\" : \"0\";\n\t\t}\n\n\t\tpublic static bool Exists(string key) {\n\t\t\treturn Values.ContainsKey(key);\n\t\t}\n\n\t\tpublic static string GetString(string Key, string Def = null) {\n\t\t\treturn Values.TryGetValue(Key, out var Value) ? Value : Def;\n\t\t}\n\t\t\n\t\tpublic static JsonValue GetJson(string key) {\n\t\t\treturn Values.TryGetValue(key, out var Value) ? JsonValue.Parse(Value) : JsonValue.Null;\n\t\t}\n\n\t\tpublic static int GetInt(string Key, int Def = 0) {\n\t\t\ttry {\n\t\t\t\treturn Values.TryGetValue(Key, out var Value) ? Int32.Parse(Value) : Def;\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Def;\n\t\t\t}\n\t\t}\n\n\t\tpublic static float GetFloat(string Key, float Def = 0) {\n\t\t\ttry {\t\t\t\n\t\t\t\treturn Values.TryGetValue(Key, out var Value) ? Single.Parse(Value) : Def;\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Def;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Generate(Area area) {\n\t\t\tValues.Clear();\n\t\t\tSettings.Generate();\n\t\t\tRunId = 0;\n\t\t\t\n\t\t\tAchievements.LockAll();\n\t\t\tPut(\"disk\", 10);\n\t\t\tSetupDev();\n\t\t}\n\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\treturn $\"{path}global.sv\";\n\t\t}\n\n\t\tpublic override void Load(Area area, FileReader reader) {\n\t\t\tValues.Clear();\n\t\t\tvar Count = reader.ReadInt32();\n\n\t\t\tfor (var I = 0; I < Count; I++) {\n\t\t\t\tvar Key = reader.ReadString();\n\t\t\t\tvar Val = reader.ReadString();\n\t\t\t\t\n\t\t\t\tValues[Key] = Val;\n\t\t\t}\n\n\t\t\tRunId = reader.ReadUInt32();\n\t\t\tEmeralds = GetInt(\"emeralds\");\n\n\t\t\tSetupDev();\n\t\t\tSettings.Load();\n\t\t}\n\n\t\tprivate void SetupDev() {\n\t\t\tif (BK.Version.Dev) {\n\t\t\t\tPut(ShopNpc.AccessoryTrader, true);\n\t\t\t\tPut(ShopNpc.ActiveTrader, true);\n\t\t\t\tPut(ShopNpc.HatTrader, true);\n\t\t\t\tPut(ShopNpc.WeaponTrader, true);\n\t\t\t\tPut(ShopNpc.Mike, true);\n\n\t\t\t\tPut(ShopNpc.Snek, true);\n\t\t\t\tPut(ShopNpc.Boxy, true);\n\t\t\t\tPut(ShopNpc.Roger, true);\n\t\t\t\tPut(ShopNpc.Gobetta, true);\n\t\t\t\tPut(ShopNpc.Vampire, true);\n\t\t\t\tPut(ShopNpc.TrashGoblin, true);\n\t\t\t\tPut(ShopNpc.Duck, true);\n\t\t\t\tPut(ShopNpc.Nurse, true);\n\t\t\t\tPut(ShopNpc.Elon, true);\n\n\t\t\t\tPut(\"control_use\", true);\n\t\t\t\tPut(\"control_swap\", true);\n\t\t\t\tPut(\"control_roll\", true);\n\t\t\t\tPut(\"control_interact\", true);\n\t\t\t\tPut(\"control_duck\", true);\n\t\t\t\tPut(\"control_bomb\", true);\n\t\t\t\tPut(\"control_active\", true);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\tSettings.Save();\n\t\t\tPut(\"emeralds\", Emeralds);\n\t\t\t\n\t\t\twriter.WriteInt32(Values.Count);\n\n\t\t\tforeach (var Pair in Values) {\n\t\t\t\twriter.WriteString(Pair.Key);\n\t\t\t\twriter.WriteString(Pair.Value);\n\t\t\t}\n\t\t\t\n\t\t\twriter.WriteUInt32(RunId);\n\t\t}\n\t\t\n\t\tpublic override FileHandle GetHandle() {\n\t\t\treturn new FileHandle(GetPath(SaveManager.SaveDir));\n\t\t}\n\n\t\tpublic GlobalSave(SaveType type = SaveType.Global) : base(type) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic static void ResetControlKnowldge() {\n\t\t\tGlobalSave.Put(\"control_use\", false);\n\t\t\tGlobalSave.Put(\"control_swap\", false);\n\t\t\tGlobalSave.Put(\"control_roll\", false);\n\t\t\tGlobalSave.Put(\"control_interact\", false);\n\t\t\tGlobalSave.Put(\"control_duck\", false);\n\t\t\tGlobalSave.Put(\"control_bomb\", false);\n\t\t\tGlobalSave.Put(\"control_active\", false);\n\t\t}\n\n\t\tpublic override void Delete() {\n\t\t\tbase.Delete();\n\t\t\tValues.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/LevelSave.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.cutscene;\nusing BurningKnight.level.hall;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.tutorial;\nusing BurningKnight.level.walls;\nusing BurningKnight.physics;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.save {\n\tpublic class LevelSave : EntitySaver {\n\t\tpublic static int FailedAttempts;\n\t\tpublic static List<int> Fails = new List<int>();\n\t\tpublic static bool XL;\n\t\tpublic static float ChestRewardChance;\n\t\tpublic static float MimicChance;\n\t\tpublic static bool GenerateMarket;\n\t\tpublic static bool GenerateShops;\n\t\tpublic static bool GenerateTreasure;\n\t\tpublic static bool MeleeOnly;\n\t\tpublic static float MobDestructionChance;\n\n\t\tprivate static int I;\n\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\tSmartSave(area.Tagged[Tags.LevelSave], writer);\n\t\t\tvar d = (old ? Run.LastDepth : Run.Depth);\n\t\t\t\n\t\t\tif (d > 0) {\n\t\t\t\tRun.LastSavedDepth = d;\n\t\t\t\tLog.Error($\"Set run last saved depth to {Run.LastSavedDepth}\");\n\t\t\t}\n\t\t}\n\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\tif (path.EndsWith(\".lvl\")) {\n\t\t\t\treturn path;\n\t\t\t}\n\t\t\t\n\t\t\treturn $\"{path}level-{(old ? Run.LastDepth : Run.Depth)}-l{(old ? Run.LastLoop : Run.Loop)}.lvl\";\n\t\t}\n\n\t\tprivate RegularLevel CreateLevel() {\n\t\t\tif (Run.Depth < -2) {\n\t\t\t\treturn new CutsceneLevel();\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Depth == -2) {\n\t\t\t\treturn new TutorialLevel();\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\treturn new HallLevel();\n\t\t\t}\n\t\t\t\n\t\t\treturn new RegularLevel(BiomeRegistry.GenerateForDepth(Run.Depth));\n\t\t}\n\n\t\tpublic static Biome BiomeGenerated;\n\n\t\tprivate bool GenerationThread(string seed, Area area, int c = 0) {\n\t\t\tvar a = new Area();\n\t\t\tRnd.Seed = $\"{seed}{Run.Depth}{c}{Run.Loop}\";\n\t\t\tLog.Debug($\"Thread seed is {Rnd.Seed} (int {Rnd.IntSeed})\");\n\t\t\n\t\t\ttry {\n\t\t\t\tItems.GeneratedOnFloor.Clear();\n\t\t\t\t\n\t\t\t\tvar level = CreateLevel();\n\t\t\t\tBiomeGenerated = level.Biome;\n\t\t\t\tWallRegistry.Instance.ResetForBiome(BiomeGenerated);\n\n\t\t\t\ta.Add(level);\n\n\t\t\t\tif (!level.Generate()) {\n\t\t\t\t\tthrow new Exception(\"Failed to paint\");\n\t\t\t\t}\n\n\t\t\t\tforeach (var e in a.Entities.ToAdd) {\n\t\t\t\t\tarea.Add(e);\n\t\t\t\t}\n\n\t\t\t\tarea.EventListener.Copy(a.EventListener);\n\t\t\t\tarea.Entities.AddNew();\n\t\t\t\tI = 0;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t\tI++;\n\n\t\t\t\ta.Entities.AddNew();\n\t\t\t\ta.Destroy();\n\t\t\t\tRun.Level = null;\n\n\t\t\t\tif (I > 10) {\n\t\t\t\t\tI = 0;\n\t\t\t\t\treturn GenerationThread(seed, area, c + 1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn GenerationThread(seed, area);\n\t\t\t}\n\n\t\t\tBiomeGenerated = null;\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate string sd;\n\n\t\tpublic override void Generate(Area area) {\n\t\t\tif (sd == null) {\n\t\t\t\tsd = Run.Seed;\n\t\t\t}\n\n\t\t\tvar done = false;\n\t\t\tvar finished = false;\n\t\t\tvar aborted = false;\n\t\t\t\n\t\t\tvar thread = new Thread(() => {\n\t\t\t\ttry {\n\t\t\t\t\tdone = GenerationThread(sd, area);\n\t\t\t\t\tfinished = true;\n\t\t\t\t} catch (ThreadInterruptedException e) {\n\t\t\t\t\tPhysics.Destroy();\n\t\t\t\t\tPhysics.Init();\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tLog.Debug(\"Level gen thread started\");\n\t\t\tthread.Start();\n\t\t\tvar i = 0;\n\t\t\t\n\t\t\twhile (true) {\n\t\t\t\tThread.Sleep(500);\n\n\t\t\t\tif (finished) {\n\t\t\t\t\tLog.Debug(\"Thread finished\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\ti++;\n\n\t\t\t\tif (i >= 15f) {\n\t\t\t\t\tLog.Debug(\"Thread took too long, aborting :(\");\n\t\t\t\t\tthread.Interrupt();\n\t\t\t\t\tRnd.Seed = Run.Seed = Rnd.GenerateSeed();\n\t\t\t\t\taborted = true;\n\t\t\t\t\tFailedAttempts++;\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (aborted) {\n\t\t\t\tGenerate(area);\n\t\t\t} else {\n\t\t\t\tif (Run.Depth > 0) {\n\t\t\t\t\tFails.Add(FailedAttempts);\n\t\t\t\t}\n\n\t\t\t\tLog.Debug($\"Generation done, took {i} cycles, {FailedAttempts} failed attempts)\");\n\t\t\t\tFailedAttempts = 0;\n\t\t\t\tsd = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override FileHandle GetHandle() {\n\t\t\treturn new FileHandle(SaveManager.SlotDir);\n\t\t}\n\n\t\tpublic override void Delete() {\n\t\t\tvar handle = Run.Depth > 0 ? GetHandle() : new FileHandle(SaveManager.SaveDir);\n\n\t\t\tif (!handle.Exists()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\tif (file.Extension == \".lvl\" || file.Extension == \"lvl\") {\n\t\t\t\t\tfile.Delete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic LevelSave() : base(SaveType.Level) {\n\t\t\tResetGen();\n\t\t}\n\n\t\tpublic static void ResetGen() {\n\t\t\tXL = false;\n\t\t\tChestRewardChance = 5;\n\t\t\tMobDestructionChance = 0;\n\t\t\tMimicChance = 5;\n\t\t\tGenerateMarket = false;\n\t\t\tGenerateTreasure = false;\n\t\t\tGenerateShops = false;\n\t\t\tMeleeOnly = false;\n\t\t\tItem.Attact = false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/PlayerSave.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.twitch;\nusing BurningKnight.level.challenge;\nusing BurningKnight.save.statistics;\nusing BurningKnight.state;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace BurningKnight.save {\n\tpublic class PlayerSave : EntitySaver {\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\tSmartSave(area.Tagged[Tags.PlayerSave], writer);\n\t\t}\n\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\treturn $\"{path}player.sv\";\n\t\t}\n\n\t\tpublic override void Generate(Area area) {\n\t\t\tif (Run.Depth < -2) { // Cutscenes\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar player = new LocalPlayer();\n\t\t\tarea.Add(player);\n\t\t\t\n\t\t\tvar input = player.GetComponent<InputComponent>();\n\t\t\t\n\t\t\tinput.Index = 0;\n\t\t\tinput.KeyboardEnabled = true;\n\t\t\tinput.GamepadEnabled = Run.NumPlayers <= 1;\n\n\t\t\tfor (var i = 1; i < Run.NumPlayers; i++) {\n\t\t\t\tinput = area.Add(new LocalPlayer()).GetComponent<InputComponent>();\n\n\t\t\t\tinput.Index = (byte) i;\n\t\t\t\tinput.KeyboardEnabled = false;\n\t\t\t\tinput.GamepadEnabled = true;\n\t\t\t}\n\n\t\t\tRun.NumPlayers = 0;\n\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tif (Run.Type == RunType.Challenge) {\n\t\t\t\t\tvar c = ChallengeRegistry.Get(Run.ChallengeId);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tc?.Apply(player);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t} else if (Run.Type == RunType.Daily) {\n\t\t\t\t\tRnd.Seed = Run.Seed;\n\t\t\t\t\t\n\t\t\t\t\tvar count = Rnd.Int(1, 4);\n\n\t\t\t\t\tvar pool = Items.GeneratePool(Items.GetPool(ItemPool.Treasure), i => i.Type == ItemType.Artifact);\n\t\t\t\t\tLog.Debug($\"Pool count: {pool.Count}\");\n\t\t\t\t\tPlayer.DailyItems = new List<string>();\n\n\t\t\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\t\t\tPlayer.DailyItems.Add(Items.GenerateAndRemove(pool));\n\t\t\t\t\t}\n\n\t\t\t\t\tvar si = Rnd.Chance(70) ? Items.Generate(ItemType.Active) : null;\n\t\t\t\t\tvar sw = Items.Generate(ItemPool.Weapon);\n\t\t\t\t\tvar sl = Items.Generate(ItemType.Lamp);\n\n\t\t\t\t\tfor (var i = 0; i < Player.MaxPlayers; i++) {\n\t\t\t\t\t\tPlayer.StartingItems[i] = si;\n\t\t\t\t\t\tPlayer.StartingWeapons[i] = sw;\n\t\t\t\t\t\tPlayer.StartingLamps[i] = sl;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tarea.Add(new RunStatistics());\n\t\t\t\tarea.Add(new entity.creature.bk.BurningKnight());\n\t\t\t} else if (Run.Depth == -2) {\n\t\t\t\tarea.Add(new RunStatistics());\n\t\t\t}\n\t\t}\n\n\t\tpublic PlayerSave() : base(SaveType.Player) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/PrefabData.cs",
    "content": "using System;\n\nnamespace BurningKnight.save {\n\tpublic class PrefabData {\n\t\tpublic Type Type;\n\t\tpublic byte[] Data;\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/PrefabSaver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.save {\n\tpublic class PrefabSaver : LevelSave {\n\t\tpublic List<PrefabData> Datas = new List<PrefabData>();\n\n\t\tpublic override void Load(Area area, FileReader reader) {\n\t\t\tDatas.Clear();\n\t\t\tbase.Load(area, reader);\n\t\t}\n\n\t\tprotected override void ReadEntity(Area area, FileReader reader, string type, bool post) {\n\t\t\tif (type == \"level.rooms.Room\") {\n\t\t\t\ttype = \"entity.room.Room\";\n\t\t\t} else if (type == \"entity.item.ItemStand\") {\n\t\t\t\ttype = \"entity.item.stand.ItemStand\";\n\t\t\t}\n\t\t\n\t\t\tvar t = Type.GetType($\"BurningKnight.{type}\", true, false);\n\n\t\t\tif (typeof(Level).IsAssignableFrom(t)) {\n\t\t\t\tbase.ReadEntity(area, reader, type, post);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar prefab = new PrefabData();\n\t\t\tprefab.Type = t;\n\n\t\t\tvar size = reader.ReadInt16();\n\t\t\tprefab.Data = new byte[size];\n\t\t\t\n\t\t\tfor (var i = 0; i < size; i++) {\n\t\t\t\tprefab.Data[i] = reader.ReadByte();\n\t\t\t}\n\t\t\t\n\t\t\tDatas.Add(prefab);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/SaveDebug.cs",
    "content": "using BurningKnight.ui.imgui;\nusing ImGuiNET;\n\nnamespace BurningKnight.save {\n\tpublic static class SaveDebug {\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\n\t\tprivate static bool global;\n\t\t\n\t\tpublic static void RenderDebug() {\n\t\t\tif (!WindowManager.Save) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\n\t\t\tif (!ImGui.Begin(\"Save Debug\")) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfilter.Draw(\"Search##sd\");\n\t\t\tImGui.Checkbox(\"Global\", ref global);\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y;\n\t\t\tImGui.BeginChild(\"ScrollingRegionItems\", new System.Numerics.Vector2(0, -height), \n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\n\t\t\tvar k = (global ? GlobalSave.Values : GameSave.Values).Keys;\n\t\t\t\n\t\t\tforeach (var i in k) {\n\t\t\t\tImGui.PushID(i);\n\n\t\t\t\tif (filter.PassFilter(i)) {\n\t\t\t\t\tvar s = i;\n\t\t\t\t\tvar changed = false;\n\t\t\t\t\t\n\t\t\t\t\tImGui.PushItemWidth(100);\n\t\t\t\t\tif (ImGui.InputText($\"##{i}\", ref s, 128)) {\n\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tImGui.PopItemWidth();\n\t\t\t\t\t\n\t\t\t\t\tvar v = (global ? GlobalSave.Values : GameSave.Values)[i];\n\n\t\t\t\t\tif (v == null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.SameLine();\n\n\t\t\t\t\tif (ImGui.InputText($\"##v_v{i}\", ref v, 128) || changed) {\n\t\t\t\t\t\tif (global) {\n\t\t\t\t\t\t\tGlobalSave.Values.Remove(i);\n\t\t\t\t\t\t\tGlobalSave.Put(s, v);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tGameSave.Values.Remove(i);\n\t\t\t\t\t\t\tGameSave.Put(s, v);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tImGui.PopID();\n\t\t\t}\n\n\t\t\tImGui.EndChild();\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/SaveLock.cs",
    "content": "namespace BurningKnight.save {\r\n\tpublic class SaveLock {\r\n\t\tpublic bool Level { get; private set; }\r\n\t\tpublic bool Player { get; private set; }\r\n\t\tpublic bool Game { get; private set; }\r\n\t\tpublic bool Global { get; private set; }\r\n\r\n\t\tpublic bool Done { get; private set; }\r\n\r\n\t\tpublic void Check() {\r\n\t\t\tif (Level && Player && Game && Global) {\r\n\t\t\t\tDone = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void Reset() {\r\n\t\t\tLevel = false;\r\n\t\t\tPlayer = false;\r\n\t\t\tGame = false;\r\n\t\t\tGlobal = false;\r\n\t\t\tDone = false;\r\n\t\t}\r\n\r\n\t\tpublic void UnlockLevel() {\r\n\t\t\tLevel = true;\r\n\t\t\tCheck();\r\n\t\t}\r\n\t\t\r\n\t\tpublic void UnlockPlayer() {\r\n\t\t\tPlayer = true;\r\n\t\t\tCheck();\r\n\t\t}\r\n\t\t\r\n\t\tpublic void UnlockGame() {\r\n\t\t\tGame = true;\r\n\t\t\tCheck();\r\n\t\t}\r\n\t\t\r\n\t\tpublic void UnlockGlobal() {\r\n\t\t\tGlobal = true;\r\n\t\t\tCheck();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/save/SaveManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\nusing BurningKnight.save.cloud;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\nusing Steamworks;\n\nnamespace BurningKnight.save {\n\tpublic class SaveManager {\n\t\tpublic const string SaveDir = BK.Demo ? \"burning_knight_demo/\" : \"burning_knight/\";\n\t\tpublic const int MagicNumber = 894923782;\n\t\tpublic const short Version = 2;\n\n\t\tpublic static byte CurrentSlot = 0;\n\t\tpublic static string SlotDir = $\"{SaveDir}slot-{CurrentSlot}/\";\n\n\t\tpublic static string BackupDir =\n\t\t\t$\"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/.burning_knight/\";\n\n\t\tpublic static bool EnableCloudSave;\n\n\t\tpublic static Saver[] Savers;\n\n\t\tpublic static void Init() {\n\t\t\tLog.Info($\"Save directory is '{new FileHandle(SaveDir).FullPath}'\");\n\n\t\t\tSavers = new Saver[6];\n\t\t\tSavers[(int) SaveType.Global] = new GlobalSave();\n\t\t\tSavers[(int) SaveType.Game] = new GameSave();\n\t\t\tSavers[(int) SaveType.Level] = new LevelSave();\n\t\t\tSavers[(int) SaveType.Player] = new PlayerSave();\n\t\t\tSavers[(int) SaveType.Secret] = new SecretSave();\n\t\t\tSavers[(int) SaveType.Statistics] = new StatisticsSaver();\n\n\t\t\tvar saveDirectory = new FileHandle(SaveDir);\n\n\t\t\tif (!saveDirectory.Exists()) {\n\t\t\t\tsaveDirectory.MakeDirectory();\n\t\t\t\tLog.Info(\"Creating the save directory\");\n\n\t\t\t\tSecretSave.HadSaveBefore = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic static Saver ForType(SaveType type) {\n\t\t\treturn Savers[(int) type];\n\t\t}\n\n\t\tpublic static string GetSavePath(SaveType saveType, bool old = false, string path = null) {\n\t\t\treturn ForType(saveType).GetPath((path ?? (saveType == SaveType.Statistics || saveType == SaveType.Global ||\n\t\t\t                                           (saveType == SaveType.Level && (old ? Run.LastDepth : Run.Depth) < 1)\n\t\t\t\t? SaveDir\n\t\t\t\t: SlotDir)), old);\n\t\t}\n\n\t\tpublic static FileHandle GetFileHandle(string path) {\n\t\t\treturn new FileHandle(path);\n\t\t}\n\n\t\tprivate static FileWriter GetWriter(string path) {\n\t\t\treturn new FileWriter(path);\n\t\t}\n\n\t\tprivate static FileReader GetReader(string path) {\n\t\t\treturn new FileReader(path);\n\t\t}\n\n\t\tpublic static void Save(Area area, SaveType saveType, bool old = false, string path = null) {\n\t\t\tvar p = GetSavePath(saveType, old, path);\n\t\t\tvar file = new FileInfo(p);\n\n\t\t\tif (saveType != SaveType.Secret || Engine.Version.Dev) {\n\t\t\t\tLog.Info($\"Saving {saveType} {(old ? Run.LastDepth : Run.Depth)} to {file.FullName}\");\n\t\t\t}\n\n\t\t\tfile.Directory?.Create();\n\n\t\t\tvar stream = GetWriter(p);\n\n\t\t\tstream.WriteInt32(MagicNumber);\n\t\t\tstream.WriteInt16(Version);\n\t\t\tstream.WriteByte((byte) saveType);\n\n\t\t\tForType(saveType).Save(area, stream, old);\n\t\t\tstream.Close();\n\n\t\t\tif (saveType != SaveType.Secret) {\n\t\t\t\tSecretSave.HadSaveBefore = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void ThreadSave(Action callback, Area area, SaveType saveType, bool old = false, string path = null) {\n\t\t\t// new Thread(() => {\n\t\t\tSave(area, saveType, old, path);\n\t\t\tcallback?.Invoke();\n\n\t\t\t// }) {\n\t\t\t// \tPriority = ThreadPriority.Lowest\n\t\t\t// }.Start();\n\t\t}\n\n\t\tpublic static bool ExistsAndValid(SaveType saveType, Action<FileReader> action = null, string path = null) {\n\t\t\tvar save = GetFileHandle(GetSavePath(saveType, false, path));\n\n\t\t\tif (!save.Exists()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar stream = GetReader(save.FullPath);\n\n\t\t\tif (stream.ReadInt32() != MagicNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (stream.ReadInt16() > Version) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (stream.ReadByte() != (byte) saveType) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\taction?.Invoke(stream);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic static void Load(Area area, SaveType saveType, string path = null) {\n\t\t\tvar save = GetFileHandle(GetSavePath(saveType, false, path));\n\n\t\t\tif (!save.Exists()) {\n\t\t\t\tGenerate(area, saveType);\n\t\t\t} else {\n\t\t\t\tif (saveType != SaveType.Secret || Engine.Version.Dev) {\n\t\t\t\t\tLog.Info($\"Loading {saveType} {Run.Depth} l{Run.Loop}{(path == null ? $\" from {save.FullPath}\" : $\" from {path}\")}\");\n\t\t\t\t}\n\n\t\t\t\tvar stream = GetReader(save.FullPath);\n\n\t\t\t\tif (stream.ReadInt32() != MagicNumber) {\n\t\t\t\t\tLog.Error(\"Invalid magic number!\");\n\t\t\t\t\tGenerate(area, saveType);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar version = stream.ReadInt16();\n\n\t\t\t\tif (version > Version) {\n\t\t\t\t\tif (saveType != SaveType.Global && saveType != SaveType.Game) {\n\t\t\t\t\t\tLog.Error($\"Unknown version {version}, generating new\");\n\t\t\t\t\t\tGenerate(area, saveType);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} else if (version < Version) {\n\t\t\t\t\tif (saveType != SaveType.Global && saveType != SaveType.Game && !(path ?? save.FullPath).StartsWith(\"Content\")) {\n\t\t\t\t\t\tLog.Error($\"Old version {version}, generating new\");\n\t\t\t\t\t\tGenerate(area, saveType);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (stream.ReadByte() != (byte) saveType) {\n\t\t\t\t\tLog.Error(\"Save file did not match it's loader type!\");\n\t\t\t\t\tGenerate(area, saveType);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tForType(saveType).Load(area, stream);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Generate(Area area, SaveType saveType) {\n\t\t\tif (saveType != SaveType.Secret || Engine.Version.Dev) {\n\t\t\t\tLog.Info($\"Generating {saveType} {Run.Depth}\");\n\t\t\t}\n\n\t\t\tForType(saveType).Generate(area);\n\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tSave(area, saveType);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Delete(params SaveType[] types) {\n\t\t\tforeach (var type in types) {\n\t\t\t\tif (type != SaveType.Secret || Engine.Version.Dev) {\n\t\t\t\t\tLog.Info($\"Deleting {type} save\");\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tForType(type).Delete();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Backup() {\n\t\t\tif (true) {\n\t\t\t\tLog.Info(\"Backups are disabled, cause you cant restore anyway. Should I implement that?\");\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar backup = new FileHandle(BackupDir);\n\t\n\t\t\tif (!backup.Exists()) {\n\t\t\t\ttry {\n\t\t\t\t\tbackup.MakeDirectory();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar save = new FileHandle(SaveDir);\n\n\t\t\tif (!save.Exists()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLog.Info(\"Backing up the saves\");\n\n\t\t\tforeach (var folder in backup.ListDirectoryHandles()) {\n\t\t\t\ttry {\n\t\t\t\t\tfolder.Delete();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var file in backup.ListFileHandles()) {\n\t\t\t\ttry {\n\t\t\t\t\tfile.Delete();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var folder in save.ListDirectoryHandles()) {\n\t\t\t\ttry {\n\t\t\t\t\tDirectory.CreateDirectory($\"{backup.FullPath}{folder.Name}\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in folder.ListFileHandles()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tFile.Copy(file.FullPath, $\"{backup.FullPath}{folder.Name}/{file.Name}\", true);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var file in save.ListFileHandles()) {\n\t\t\t\ttry {\n\t\t\t\t\tFile.Copy(file.FullPath, $\"{backup.FullPath}{file.Name}\", true);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void DeleteCloudSaves() {\n\t\t\tif (!EnableCloudSave || !SteamRemoteStorage.IsCloudEnabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tforeach (var f in SteamRemoteStorage.Files) {\n\t\t\t\tSteamRemoteStorage.FileDelete(f);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void LoadCloudSaves() {\n\t\t\tif (!EnableCloudSave || !SteamRemoteStorage.IsCloudEnabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLog.Info(\"Loading data from cloud\");\n\n\t\t\tif (!SteamClient.IsLoggedOn) {\n\t\t\t\tLog.Error(\"Can't connect to steam servers\");\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (SteamRemoteStorage.FileCount > 0) {\n\t\t\t\tRemoveFile(new FileHandle(SaveDir), \"\");\n\t\t\t}\n\n\t\t\tforeach (var file in SteamRemoteStorage.Files) {\n\t\t\t\tvar to = $\"{SaveDir}{file}\";\n\t\t\t\tLog.Info($\"Loading file {file} to {to}\");\n\n\t\t\t\tvar handle = new FileHandle(to);\n\n\t\t\t\tif (!handle.Parent.Exists()) {\n\t\t\t\t\tLog.Info($\"Making the directory {handle.Parent.FullPath}\");\n\t\t\t\t\thandle.Parent.MakeDirectory();\n\t\t\t\t}\n\n\t\t\t\tFile.WriteAllBytes(to, SteamRemoteStorage.FileRead(file));\n\t\t\t}\n\t\t}\n\n\t\tprivate static void RemoveFile(FileHandle handle, string path) {\n\t\t\tif (handle.IsDirectory()) {\n\t\t\t\tpath += $\"{handle.Name}/\";\n\n\t\t\t\tforeach (var dir in handle.ListDirectoryHandles()) {\n\t\t\t\t\tRemoveFile(dir, path);\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\t\tRemoveFile(file, path);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpath = $\"{path}{handle.Name}\";\n\n\t\t\t\tif (!SteamRemoteStorage.Files.Contains(path)) {\n\t\t\t\t\tLog.Info($\"Removing file {path} from local saves\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void SaveCloudSaves() {\n\t\t\tif (!EnableCloudSave || !SteamRemoteStorage.IsCloudEnabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLog.Info(\"Saving data to cloud\");\n\n\t\t\tif (!SteamClient.IsLoggedOn) {\n\t\t\t\tLog.Error(\"Can't connect to steam servers\");\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar toRemove = new List<string>();\n\n\t\t\tforeach (var file in SteamRemoteStorage.Files) {\n\t\t\t\tvar handle = new FileHandle($\"{SaveDir}{file}\");\n\n\t\t\t\tif (!handle.Exists()) {\n\t\t\t\t\ttoRemove.Add(file);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var file in toRemove) {\n\t\t\t\tLog.Info($\"Removing cloud file {file}\");\n\t\t\t\tSteamRemoteStorage.FileDelete(file);\n\t\t\t}\n\n\t\t\tWriteFile(new FileHandle(SaveDir), \"\");\n\t\t}\n\n\t\tprivate static void WriteFile(FileHandle handle, string path) {\n\t\t\tif (handle.IsDirectory()) {\n\t\t\t\tpath += $\"{handle.Name}/\";\n\n\t\t\t\tforeach (var dir in handle.ListDirectoryHandles()) {\n\t\t\t\t\tWriteFile(dir, path);\n\t\t\t\t}\n\n\t\t\t\tforeach (var file in handle.ListFileHandles()) {\n\t\t\t\t\tWriteFile(file, path);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (handle.Extension != \".sv\" && handle.Extension != \".lvl\") {\n\t\t\t\t\tLog.Info($\"Ignoring file {handle.FullPath} cause of its extension {handle.Extension}\");\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tpath = $\"{path}{handle.Name}\";\n\t\t\t\tLog.Info($\"Saving file {path} from {handle.FullPath}\");\n\n\t\t\t\tSteamRemoteStorage.FileWrite(path, File.ReadAllBytes(handle.FullPath));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/SaveType.cs",
    "content": "namespace BurningKnight.save {\n\tpublic enum SaveType {\n\t\tPlayer,\n\t\tGame,\n\t\tLevel,\n\t\tGlobal,\n\t\t\n\t\tSecret,\n\t\tStatistics\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/SaveableEntity.cs",
    "content": "using System.Linq;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.util.file;\n\nnamespace BurningKnight.save {\n\tpublic class SaveableEntity : Entity {\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\t\n\t\t\tAddTag(Tags.LevelSave);\n\t\t}\n\n\t\tpublic virtual void Save(FileWriter stream) {\n\t\t\tstream.WriteInt32((int) X);\n\t\t\tstream.WriteInt32((int) Y);\n\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tif (component is SaveableComponent saveable) {\n\t\t\t\t\tsaveable.Save(stream);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void Load(FileReader stream) {\n\t\t\tX = stream.ReadInt32();\n\t\t\tY = stream.ReadInt32();\n\t\t\t\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// So that we can edit the components\n\t\t\t// Tho those new components wont get loaded\n\t\t\tvar values = Components.Values.ToArray();\n\t\t\t\n\t\t\tforeach (var component in values) {\n\t\t\t\tif (component is SaveableComponent saveable) {\n\t\t\t\t\tsaveable.Load(stream);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/Saver.cs",
    "content": "using Lens.entity;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.save {\r\n\tpublic abstract class Saver {\r\n\t\tpublic abstract string GetPath(string path, bool old = false);\r\n\t\tpublic abstract void Load(Area area, FileReader reader);\r\n\t\tpublic abstract void Save(Area area, FileWriter writer, bool old);\r\n\t\tpublic abstract void Generate(Area area);\r\n\r\n\t\tpublic readonly SaveType SaveType;\r\n\t\t\r\n\t\tpublic Saver(SaveType type) {\r\n\t\t\tSaveType = type;\r\n\t\t}\r\n\t\t\r\n\t\tpublic virtual FileHandle GetHandle() {\r\n\t\t\treturn new FileHandle(GetPath(SaveManager.SlotDir));\r\n\t\t}\r\n\r\n\t\tpublic virtual void Delete() {\r\n\t\t\tvar handle = GetHandle();\r\n\r\n\t\t\tif (handle.Exists()) {\r\n\t\t\t\thandle.Delete();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/save/SecretSave.cs",
    "content": "using System;\nusing Lens;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.file;\n\nnamespace BurningKnight.save {\n\tpublic class SecretSave : Saver {\n\t\tpublic static bool Loaded;\n\n\t\tpublic static void Load(Area area) {\n\t\t\tif (Loaded) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tLoaded = true;\n\t\t\t// SaveManager.Load(area, SaveType.Secret);\n\t\t}\n\t\t\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\treturn $\"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/.nothing.sv\";\n\t\t}\n\n\t\tpublic static bool HadSaveBefore = true;\n\t\tpublic static bool DeletedSave;\n\t\tpublic static bool WasATester;\n\t\t\n\t\tpublic override void Load(Area area, FileReader reader) {\n\t\t\t DeletedSave = reader.ReadBoolean();\n\t\t\t WasATester = reader.ReadBoolean();\n\n\t\t\tif (!HadSaveBefore) {\n\t\t\t\tDeletedSave = true;\n\t\t\t\tLog.Info(\"You think ya smart?\");\n\t\t\t}\n\n\t\t\tif (WasATester) {\n\t\t\t\tLog.Info(\"Thanks for being a tester!\");\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\tWasATester = false; // Engine.Version.Test;\n\t\t\t\n\t\t\twriter.WriteBoolean(DeletedSave);\n\t\t\twriter.WriteBoolean(WasATester);\n\t\t}\n\n\t\tpublic override void Generate(Area area) {\n\t\t\tDeletedSave = false;\n\t\t\tWasATester = false; // Engine.Version.Test;\n\t\t}\n\n\t\tpublic SecretSave() : base(SaveType.Secret) {\n\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/StatisticsSaver.cs",
    "content": "using BurningKnight.state;\nusing Lens.entity;\nusing Lens.util.file;\n\nnamespace BurningKnight.save {\n\tpublic class StatisticsSaver : Saver {\n\t\tpublic StatisticsSaver() : base(SaveType.Statistics) {\n\t\t\t\n\t\t}\n\n\t\tpublic override string GetPath(string path, bool old = false) {\n\t\t\treturn $\"{path}/stats/statistics-{GlobalSave.RunId}.sv\";\n\t\t}\n\n\t\tpublic override void Load(Area area, FileReader reader) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void Save(Area area, FileWriter writer, bool old) {\n\t\t\tif (Run.Statistics == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar statistics = Run.Statistics;\n\n\t\t\tstatistics.Frozen = true;\n\t\t\tstatistics.Save(writer);\n\t\t}\n\n\t\tpublic override void Generate(Area area) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/cloud/CloudFileReader.cs",
    "content": "using Lens.util.file;\nusing Steamworks;\n\nnamespace BurningKnight.save.cloud {\n\tpublic class CloudFileReader : FileReader {\n\t\tpublic CloudFileReader(string path) : base(path) {\n\t\t\t\n\t\t}\n\n\t\tprotected override void ReadData(string path) {\n\t\t\tread = SteamRemoteStorage.FileRead(path);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/save/cloud/CloudFileWriter.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\nusing Steamworks;\r\n\r\nnamespace BurningKnight.save.cloud {\r\n\tpublic class CloudFileWriter : FileWriter {\r\n\t\tprivate List<byte> data = new List<byte>();\r\n\t\tprivate string file;\r\n\r\n\t\tpublic CloudFileWriter(string path, bool append = false) : base(path, append) {\r\n\t\t}\r\n\r\n\t\tprotected override void OpenStream(string path, bool append) {\r\n\t\t\tif (append) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tvar d = new CloudFileReader(path).Data;\r\n\t\t\t\t\tdata.AddRange(d);\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tfile = path;\r\n\t\t}\r\n\r\n\t\tprotected override void Write(byte value) {\r\n\t\t\tdata.Add(value);\r\n\t\t}\r\n\r\n\t\tpublic override void Close() {\r\n\t\t\tSteamRemoteStorage.FileWrite(file, data.ToArray());\r\n\t\t\tdata.Clear();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/save/statistics/RunStatistics.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Numerics;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob;\r\nusing BurningKnight.entity.creature.mob.boss;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.entity.room;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.rooms;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.imgui;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\n\r\nnamespace BurningKnight.save.statistics {\r\n\tpublic class RunStatistics : SaveableEntity {\r\n\t\tprivate const byte Version = 0;\r\n\t\tpublic bool Frozen;\r\n\t\t\r\n\t\tpublic bool Won;\r\n\t\tpublic byte MaxDepth;\r\n\t\tpublic uint GameVersion;\r\n\r\n\t\tpublic List<string> Items = new List<string>();\r\n\t\tpublic List<string> Banned = new List<string>();\r\n\r\n\t\tpublic ushort CoinsObtained;\r\n\t\tpublic ushort BombsObtained;\r\n\t\tpublic ushort KeysObtained;\r\n\t\t\r\n\t\tpublic ushort HeartsCollected;\r\n\t\tpublic ushort MaxHealth;\r\n\r\n\t\tpublic uint DamageTaken;\r\n\t\tpublic uint DamageDealt;\r\n\t\tpublic uint MobsKilled;\r\n\r\n\t\tpublic uint RoomsExplored;\r\n\t\tpublic uint RoomsTotal;\r\n\t\tpublic uint SecretRoomsFound;\r\n\t\tpublic uint SecretRoomsTotal;\r\n\r\n\t\tpublic ushort Year;\r\n\t\tpublic ushort Day;\r\n\r\n\t\tpublic uint TilesWalked;\r\n\t\tpublic ushort PitsFallen;\r\n\r\n\t\tpublic ushort BossesDefeated;\r\n\t\tpublic ushort SpikesTriggered;\r\n\r\n\t\tprivate float leftOver;\r\n\t\t\r\n\t\tpublic override void Load(FileReader stream) {\r\n\t\t\tvar version = stream.ReadByte();\r\n\r\n\t\t\tif (version > Version) {\r\n\t\t\t\tLog.Error($\"Unknown stastics version {version}\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// Time ignored\r\n\t\t\tstream.ReadFloat();\r\n\t\t\tWon = stream.ReadBoolean();\r\n\t\t\tMaxDepth = stream.ReadByte();\r\n\t\t\tGameVersion = stream.ReadUInt32();\r\n\r\n\t\t\tvar count = stream.ReadUInt16();\r\n\t\t\tItems.Clear();\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < count; i++) {\r\n\t\t\t\tItems.Add(stream.ReadString());\r\n\t\t\t}\r\n\t\t\r\n\t\t\tcount = stream.ReadUInt16();\r\n\t\t\tBanned.Clear();\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < count; i++) {\r\n\t\t\t\tBanned.Add(stream.ReadString());\r\n\t\t\t}\r\n\r\n\t\t\tCoinsObtained = stream.ReadUInt16();\r\n\t\t\tBombsObtained = stream.ReadUInt16();\r\n\t\t\tKeysObtained = stream.ReadUInt16();\r\n\t\t\t\r\n\t\t\tHeartsCollected = stream.ReadUInt16();\r\n\t\t\tMaxHealth = stream.ReadUInt16();\r\n\r\n\t\t\tDamageTaken = stream.ReadUInt32();\r\n\t\t\tDamageDealt = stream.ReadUInt32();\r\n\t\t\tMobsKilled = stream.ReadUInt32();\r\n\r\n\t\t\tRoomsExplored = stream.ReadUInt32();\r\n\t\t\tRoomsTotal = stream.ReadUInt32();\r\n\t\t\tSecretRoomsFound = stream.ReadUInt32();\r\n\t\t\tSecretRoomsTotal = stream.ReadUInt32();\r\n\r\n\t\t\tYear = stream.ReadUInt16();\r\n\t\t\tDay = stream.ReadUInt16();\r\n\r\n\t\t\tTilesWalked = stream.ReadUInt32();\r\n\t\t\tPitsFallen = stream.ReadUInt16();\r\n\r\n\t\t\tBossesDefeated = stream.ReadUInt16();\r\n\t\t\tSpikesTriggered = stream.ReadUInt16();\r\n\t\t}\r\n\r\n\t\tpublic override void Save(FileWriter stream) {\r\n\t\t\tGameVersion = BK.Version.Id;\r\n\t\t\t\r\n\t\t\tstream.WriteByte(Version);\r\n\r\n\t\t\t// Time for older versions\r\n\t\t\tstream.WriteFloat(0);\r\n\t\t\tstream.WriteBoolean(Won);\r\n\t\t\tstream.WriteByte(MaxDepth);\r\n\t\t\tstream.WriteUInt32(GameVersion);\r\n\t\t\r\n\t\t\tstream.WriteUInt16((ushort) Items.Count);\r\n\r\n\t\t\tforeach (var item in Items) {\r\n\t\t\t\tstream.WriteString(item);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tstream.WriteUInt16((ushort) Banned.Count);\r\n\r\n\t\t\tforeach (var item in Banned) {\r\n\t\t\t\tstream.WriteString(item);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tstream.WriteUInt16(CoinsObtained);\r\n\t\t\tstream.WriteUInt16(BombsObtained);\r\n\t\t\tstream.WriteUInt16(KeysObtained);\r\n\t\t\r\n\t\t\tstream.WriteUInt16(HeartsCollected);\r\n\t\t\tstream.WriteUInt16(MaxHealth);\r\n\t\t\t\r\n\t\t\tstream.WriteUInt32(DamageTaken);\r\n\t\t\tstream.WriteUInt32(DamageDealt);\r\n\t\t\tstream.WriteUInt32(MobsKilled);\r\n\t\t\t\r\n\t\t\tstream.WriteUInt32(RoomsExplored);\r\n\t\t\tstream.WriteUInt32(RoomsTotal);\r\n\t\t\tstream.WriteUInt32(SecretRoomsFound);\r\n\t\t\tstream.WriteUInt32(SecretRoomsTotal);\r\n\t\t\t\r\n\t\t\tstream.WriteUInt16(Year);\r\n\t\t\tstream.WriteUInt16(Day);\r\n\t\t\t\r\n\t\t\tstream.WriteUInt32(TilesWalked);\r\n\t\t\tstream.WriteUInt16(PitsFallen);\r\n\t\t\tstream.WriteUInt16(BossesDefeated);\r\n\t\t\tstream.WriteUInt16(SpikesTriggered);\r\n\t\t}\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tvar data = DateTime.Now;\r\n\r\n\t\t\tYear = (ushort) data.Year;\r\n\t\t\tDay = (ushort) data.DayOfYear;\r\n\t\t\t\r\n\t\t\tSubscribe<RoomChangedEvent>();\r\n\t\t\tSubscribe<SecretRoomFoundEvent>();\r\n\t\t\tSubscribe<ItemAddedEvent>();\r\n\t\t\tSubscribe<PostHealthModifiedEvent>();\r\n\t\t\tSubscribe<DiedEvent>();\r\n\t\t\tSubscribe<ConsumableAddedEvent>();\r\n\t\t\tSubscribe<LostSupportEvent>();\r\n\t\t\tSubscribe<MaxHealthModifiedEvent>();\r\n\t\t\tSubscribe<NewLevelStartedEvent>();\r\n\t\t\tSubscribe<Boss.DefeatedEvent>();\r\n\t\t}\r\n\r\n\t\tpublic override void PostInit() {\r\n\t\t\tbase.PostInit();\r\n\r\n\t\t\tRun.Statistics = this;\r\n\t\t\tAlwaysActive = true;\r\n\t\t\t\r\n\t\t\tMaxDepth = (byte) Math.Max(MaxDepth, Run.Depth);\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (Frozen) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\r\n\t\t\t\tif (p.TryGetComponent<RectBodyComponent>(out var c)) {\r\n\t\t\t\t\tleftOver += (c.Velocity * dt).Length();\r\n\r\n\t\t\t\t\tvar amount = (uint) Math.Floor(leftOver / 16f);\r\n\t\t\t\t\tleftOver -= amount * 16;\r\n\t\t\t\t\tTilesWalked += amount;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (Frozen) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (e is RoomChangedEvent rce) {\r\n\t\t\t\tif (rce.Who is LocalPlayer && rce.JustDiscovered) {\r\n\t\t\t\t\tRoomsExplored++;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is SecretRoomFoundEvent) {\r\n\t\t\t\tSecretRoomsFound++;\r\n\t\t\t} else if (e is ItemAddedEvent iae) {\r\n\t\t\t\tif (!iae.Item.Touched && !Items.Contains(iae.Item.Id)) {\r\n\t\t\t\t\tvar t = iae.Item.Type;\r\n\r\n\t\t\t\t\tif (t != ItemType.Coin && t != ItemType.Heart && t != ItemType.Mana && t != ItemType.Key && t != ItemType.Bomb && t != ItemType.Battery) {\r\n\t\t\t\t\t\tItems.Add(iae.Item.Id);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (e is PostHealthModifiedEvent hme) {\r\n\t\t\t\tif (hme.Amount < 0) {\r\n\t\t\t\t\tif (!hme.PressedForBomb) {\r\n\t\t\t\t\t\tif (hme.From is Player) {\r\n\t\t\t\t\t\t\tDamageDealt += (uint) -hme.Amount;\r\n\t\t\t\t\t\t} else if (hme.Who is Player) {\r\n\t\t\t\t\t\t\tDamageTaken += (uint) -hme.Amount;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (hme.Amount > 0 && hme.Who is Player) {\r\n\t\t\t\t\tHeartsCollected += (ushort) hme.Amount;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is DiedEvent de) {\r\n\t\t\t\tif (de.Who is Player) {\r\n\t\t\t\t\tWon = false;\r\n\t\t\t\t} else if (de.Who is Mob) {\r\n\t\t\t\t\tMobsKilled++;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is ConsumableAddedEvent cae) {\r\n\t\t\t\tswitch (cae.Type) {\r\n\t\t\t\t\tcase ItemType.Coin: {\r\n\t\t\t\t\t\tCoinsObtained += (ushort) cae.Amount;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcase ItemType.Key: {\r\n\t\t\t\t\t\tKeysObtained += (ushort) cae.Amount;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase ItemType.Bomb: {\r\n\t\t\t\t\t\tBombsObtained += (ushort) cae.Amount;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (e is LostSupportEvent lse) {\r\n\t\t\t\tif (lse.Who is Player) {\r\n\t\t\t\t\tPitsFallen++;\r\n\t\t\t\t} \r\n\t\t\t} else if (e is MaxHealthModifiedEvent mhme) {\r\n\t\t\t\tif (mhme.Who is Player) {\r\n\t\t\t\t\tMaxHealth = (ushort) (MaxHealth + mhme.Amount);\r\n\t\t\t\t}\r\n\t\t\t} else if (e is NewLevelStartedEvent) {\r\n\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\r\n\t\t\t\t\tif (((Room) r).Type == RoomType.Secret) {\r\n\t\t\t\t\t\tSecretRoomsTotal++;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tRoomsTotal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (e is Boss.DefeatedEvent) {\r\n\t\t\t\tBossesDefeated++;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\t\t\t\r\n\t\t\tRemoveTag(Tags.LevelSave);\r\n\t\t\tAddTag(Tags.PlayerSave);\r\n\t\t}\r\n\r\n\t\tpublic static void RenderDebug() {\r\n\t\t\tif (!WindowManager.RunInfo) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetWindowPos(Vector2.Zero, ImGuiCond.Once);\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Run Info\")) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Run Type: {Run.Type}\");\r\n\r\n\t\t\tImGui.Text($\"World Time: {Weather.TimeOfDay}\");\r\n\t\t\tImGui.Text($\"Night: {Weather.IsNight}\");\r\n\r\n\t\t\tif (ImGui.Button(\"Set to day\")) {\r\n\t\t\t\tWeather.Time = 7f;\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\t\t\t\r\n\t\t\tif (ImGui.Button(\"Set to night\")) {\r\n\t\t\t\tWeather.Time = 21f;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Rain Left: {Weather.RainLeft}\");\r\n\t\t\tImGui.Text($\"Rains: {Weather.Rains}\");\r\n\t\t\tImGui.Text($\"Snows: {Weather.Snows}\");\r\n\r\n\t\t\tif (Weather.Rains && ImGui.Button(\"End rain\")) {\r\n\t\t\t\tWeather.RainLeft = 0;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (Weather.Snows && ImGui.Button(\"End snow\")) {\r\n\t\t\t\tWeather.RainLeft = 0;\r\n\t\t\t}\r\n\r\n\t\t\tif (!Weather.Rains && !Weather.Snows && ImGui.Button(\"Start rain or snow\")) {\r\n\t\t\t\tWeather.RainLeft = 0;\r\n\t\t\t}\r\n\r\n\t\t\tRun.Statistics?.RenderWindow();\r\n\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t\t\r\n\t\tpublic void RenderWindow() {\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Time: {Math.Floor(Run.Time / 3600f)}h {Math.Floor(Run.Time / 60f % 60f)}m {Math.Floor(Run.Time % 60f)}s\");\r\n\t\t\tImGui.Text($\"Won: {Won}\");\r\n\t\t\tImGui.Text($\"Loop: {Run.Loop}\");\r\n\t\t\tImGui.Text($\"Max Depth: {MaxDepth}\");\r\n\t\t\tImGui.Text($\"Game Version: {GameVersion}\");\r\n\t\t\tRun.CalculateScore();\r\n\t\t\tImGui.Text($\"Score: {Run.Score}\");\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tif (ImGui.TreeNode(\"Items\")) {\r\n\t\t\t\tforeach (var item in Items) {\r\n\t\t\t\t\tImGui.BulletText(item);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.TreePop();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.TreeNode(\"Banned items\")) {\r\n\t\t\t\tforeach (var item in Banned) {\r\n\t\t\t\t\tImGui.BulletText(item);\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.TreePop();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\tImGui.Text($\"Coins Collected: {CoinsObtained}\");\r\n\t\t\tImGui.Text($\"Keys Collected: {KeysObtained}\");\r\n\t\t\tImGui.Text($\"Bombs Collected: {BombsObtained}\");\r\n\t\t\tImGui.Text($\"Hearts Collected: {HeartsCollected}\");\r\n\t\t\tImGui.Text($\"Heart Containers Collected: {MaxHealth}\");\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Damage Taken: {DamageTaken}\");\r\n\t\t\tImGui.Text($\"Damage Dealt: {DamageDealt}\");\r\n\t\t\tImGui.Text($\"Mobs Killed: {MobsKilled}\");\r\n\t\t\tImGui.Text($\"Rooms Explored: {RoomsExplored} / {RoomsTotal}\");\r\n\t\t\tImGui.Text($\"Secret Rooms Explored: {SecretRoomsFound} / {SecretRoomsTotal}\");\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tImGui.Text($\"Date Started: {Day} {Year}\");\r\n\t\t\tImGui.Text($\"Tiles Walked: {TilesWalked}\");\r\n\t\t\tImGui.Text($\"Pits Fallen: {PitsFallen}\");\r\n\t\t\tImGui.Text($\"Bosses Defeated: {BossesDefeated}\");\r\n\t\t\tImGui.Text($\"Spikes Triggered: {SpikesTriggered}\");\r\n\t\t\tImGui.Text($\"Paintings Broke: {GlobalSave.GetInt(\"paintings_destroyed\")}\");\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\tImGui.Text($\"Luck: {Run.Luck}\");\r\n\t\t\tImGui.Text($\"Scourge: {Run.Scourge}\");\r\n\r\n\t\t\tif (ImGui.TreeNode(\"Scourges\")) {\r\n\t\t\t\tforeach (var curse in Scourge.Defined) {\r\n\t\t\t\t\tvar v = Scourge.IsEnabled(curse);\r\n\r\n\t\t\t\t\tif (ImGui.Checkbox(curse, ref v)) {\r\n\t\t\t\t\t\tif (v) {\r\n\t\t\t\t\t\t\tScourge.Enable(curse);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tScourge.Disable(curse);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.TreePop();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/AreaDebug.cs",
    "content": "using BurningKnight.assets.particle;\r\nusing BurningKnight.assets.particle.custom;\r\nusing BurningKnight.entity;\r\nusing BurningKnight.entity.fx;\r\nusing BurningKnight.entity.room;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.rooms;\r\nusing BurningKnight.ui.imgui;\r\nusing ImGuiNET;\r\nusing Lens.entity;\r\nusing Vector2 = System.Numerics.Vector2;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic static unsafe class AreaDebug {\r\n\t\tprivate static Vector2 defaultSize = new Vector2(400, 500);\r\n\t\tprivate static ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\r\n\t\tprivate static bool hideLevel = true;\r\n\t\tprivate static bool onlyOnScreen;\r\n\t\tprivate static Vector2 pos;\r\n\t\tprivate static Vector2 size;\r\n\t\tprivate static Entity selected;\r\n\t\tprivate static Entity toFocus;\r\n\t\t\r\n\t\tpublic static bool PassFilter(Entity e) {\r\n\t\t\treturn !(e is Level || e is RenderTrigger || e is Room || e is Chasm || e is ParticleEntity || e is ParticleSystem || e is ChasmFx || e is WaterfallFx || e is FireParticle);\r\n\t\t}\r\n\r\n\t\tpublic static Entity ToFocus {\r\n\t\t\tset {\r\n\t\t\t\tselected = value;\r\n\t\t\t\ttoFocus = value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate static void RenderWindow() {\r\n\t\t\r\n\t\t\tif (selected == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar open = true;\r\n\r\n\t\t\tif (!ImGui.Begin(\"Entity\", ref open, ImGuiWindowFlags.AlwaysAutoResize)) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!open) {\r\n\t\t\t\tselected = null;\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tRenderEntity(selected);\r\n\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Render(Area area) {\r\n\t\t\tif (!WindowManager.Entities) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tRenderWindow();\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowSize(defaultSize, ImGuiCond.Once);\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Entities\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\t\t\t\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Total {area.Entities.Entities.Count} entities\");\r\n\t\t\tfilter.Draw();\r\n\r\n\t\t\tImGui.Checkbox(\"Hide level helpers\", ref hideLevel);\r\n\t\t\tImGui.Checkbox(\"Show only on screen\", ref onlyOnScreen);\r\n\t\t\t\r\n\t\t\tvar sel = ImGui.Button(\"Jump to selected\");\r\n\r\n\t\t\tif (sel) {\r\n\t\t\t\tWindowManager.Entities = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Showing {id} entities\");\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeightWithSpacing() + 4;\r\n\t\t\tImGui.BeginChild(\"ScrollingRegionConsole\", new Vector2(0, -height), \r\n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\r\n\r\n\t\t\tid = 0; \r\n\r\n\t\t\tforeach (var e in (hasTag ? area.Tagged[BitTag.Tags[currentTag]] : area.Entities.Entities)) {\r\n\t\t\t\tif (filter.PassFilter(e.GetType().FullName) && (!onlyOnScreen || e.OnScreen) && (!hideLevel || PassFilter(e))) {\r\n\t\t\t\t\tvar s = selected == e;\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (s && (sel || toFocus == e)) {\r\n\t\t\t\t\t\tImGui.SetScrollHereY();\r\n\t\t\t\t\t\ttoFocus = null;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ImGui.Selectable($\"{e.GetType().Name}##{id}\", s)) {\r\n\t\t\t\t\t\tselected = e;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tid++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.EndChild();\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tImGui.Checkbox(\"Must have tag\", ref hasTag);\r\n\r\n\t\t\tif (hasTag) {\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\tImGui.Combo(\"Tag\", ref currentTag, Tags.AllTags, Tags.AllTags.Length);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\r\n\t\tprivate static int currentTag;\r\n\t\tprivate static bool hasTag;\r\n\t\tprivate static int id;\r\n\t\t\r\n\t\tprivate static void RenderEntity(Entity e) {\r\n\t\t\tImGui.Text(e.GetType().Name);\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tpos.X = e.X;\r\n\t\t\tpos.Y = e.Y;\r\n\r\n\t\t\tif (ImGui.DragFloat2(\"Position\", ref pos)) {\r\n\t\t\t\te.X = pos.X;\r\n\t\t\t\te.Y = pos.Y;\r\n\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\tsize.X = e.Width;\r\n\t\t\tsize.Y = e.Height;\r\n\r\n\t\t\tif (ImGui.DragFloat2(\"Size\", ref size)) {\r\n\t\t\t\te.Width = size.X;\r\n\t\t\t\te.Height = size.Y;\r\n\t\t\t}\r\n\r\n\t\t\tImGui.InputInt(\"Depth\", ref e.Depth);\r\n\r\n\t\t\tImGui.Checkbox(\"Always active\", ref e.AlwaysActive);\r\n\t\t\tImGui.SameLine();\r\n\t\t\tImGui.Checkbox(\"Always visible\", ref e.AlwaysVisible);\r\n\t\t\tImGui.Checkbox(\"On screen\", ref e.OnScreen);\r\n\t\t\tImGui.Checkbox(\"Done\", ref e.Done);\r\n\t\t\t\t\t\r\n\t\t\te.RenderImDebug();\r\n\t\t\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tif (ImGui.CollapsingHeader(\"Components\")) {\r\n\t\t\t\tforeach (var component in e.Components) {\r\n\t\t\t\t\tif (ImGui.TreeNode(component.Key.Name)) {\r\n\t\t\t\t\t\tcomponent.Value.RenderDebug();\r\n\t\t\t\t\t\tImGui.TreePop();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.CollapsingHeader(\"Tags\")) {\r\n\t\t\t\tfor (var i = 0; i < BitTag.Total; i++) {\r\n\t\t\t\t\tif (e.HasTag(BitTag.Tags[i])) {\r\n\t\t\t\t\t\tImGui.BulletText(BitTag.Tags[i].Name);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/AssetLoadState.cs",
    "content": "using System;\r\nusing System.Diagnostics;\r\nusing System.Threading;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.loot;\r\nusing BurningKnight.assets.mod;\r\nusing BurningKnight.assets.prefabs;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.physics;\r\nusing BurningKnight.save;\r\nusing BurningKnight.ui.str;\r\nusing BurningKnight.util;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.game;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic class AssetLoadState : GameState {\r\n\t\tprivate PhotoCard logoCard;\r\n\r\n\t\tprivate TextureRegion pixel;\r\n\t\t// private PhotoCard[] cards = new PhotoCard[3];\r\n\t\tprivate bool ready;\r\n\t\tprivate int progress;\r\n\t\tprivate Area gameArea;\r\n\t\tprivate float t;\r\n\t\tprivate bool added;\r\n\t\tprivate bool removed;\r\n\t\tprivate bool checkFullscreen;\r\n\t\tprivate float lastV;\r\n\t\tprivate UiString tipLabel;\r\n\t\tprivate bool exitTweenDone;\r\n\t\tprivate string currentlyLoadingLabel;\r\n\r\n\t\tprivate const bool SectionalLoadTimeLogging = false;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tpixel = new TextureRegion(Textures.FastLoad(\"Content/pixel.png\"));\r\n\t\t\t\r\n\t\t\tUi.Add(logoCard = new PhotoCard {\r\n\t\t\t\tRegion = new TextureRegion(Textures.FastLoad(\"Content/logo.png\")),\r\n\t\t\t\tUrl = \"https://twitter.com/rexcellentgames\",\r\n\t\t\t\tName = \"Rexcellent Games\",\r\n\t\t\t\tPosition = new Vector2(240, Display.UiHeight + 60),\r\n\t\t\t\tTarget = new Vector2(240, 115),\r\n\t\t\t\tScale = 1\r\n\t\t\t});\r\n\r\n\t\t\tUi.Add(tipLabel = new UiString(Font.Small));\r\n\t\t\t\r\n\t\t\tGenerateNewTip();\r\n\t\t\t\r\n\t\t\tlogoCard.Start.Y = -90;\r\n\t\t\tprogress = 0;\r\n\r\n\t\t\tvar thread = new Thread(() => {\r\n\t\t\t\tvar sw = Stopwatch.StartNew();\r\n\r\n\t\t\t\tLog.Info(\"Starting asset loading thread\");\r\n\r\n\t\t\t\tLoadSection(() => SaveManager.Load(gameArea, SaveType.Global), \"Global saves\");\r\n\t\t\t\t\r\n\t\t\t\tcheckFullscreen = true;\r\n\r\n\t\t\t\tif (Assets.LoadMusic) {\r\n\t\t\t\t\tLoadSection(() => Audio.ThreadLoad(\"Void\"), \"Audio\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tprogress++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tLoadSection(() => Assets.Load(ref progress), \"Assets\");\r\n\t\t\t\tprogress++;\r\n\r\n\t\t\t\tLoadSection(Dialogs.Load, \"Dialogs\");\r\n\r\n\t\t\t\tCommonAse.Load();\r\n\t\t\t\tprogress++;\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tImGuiHelper.BindTextures();\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprogress++;\r\n\t\t\t\t\r\n\t\t\t\tLoadSection(Shaders.Load, \"Shaders\");\r\n\t\t\t\tLoadSection(Prefabs.Load, \"Prefabs\");\r\n\t\t\t\tLoadSection(Items.Load, \"Items\");\r\n\t\t\t\tLoadSection(LootTables.Load, \"Loot tables\");\r\n\t\t\t\tLoadSection(Mods.Load, \"Mods\");\r\n\t\t\t\t\r\n\t\t\t\tLog.Info(\"Done loading assets! Loading level now.\");\r\n\t\t\t\r\n\t\t\t\tLoadSection(() => {\r\n\t\t\t\t\tLights.Init();\r\n\t\t\t\t\tPhysics.Init();\r\n\t\t\t\t}, \"Lights & physics\");\r\n\t\t\t\t\r\n\t\t\t\tgameArea = new Area();\r\n\t\t\t\tRun.Level = null;\r\n\r\n\t\t\t\tLoadSection(Tilesets.Load, \"Tilesets\");\r\n\t\t\t\tLoadSection(Achievements.Load, \"Achievements\");\r\n\t\t\t\t\r\n\t\t\t\tLoadSection(() => {\r\n\t\t\t\t\tSaveManager.Load(gameArea, SaveType.Game);\r\n\t\t\t\t}, \"Game saves\");\r\n\r\n\t\t\t\tRnd.Seed = $\"{Run.Seed}_{Run.Depth}\";\r\n\r\n\t\t\t\tLoadSection(() => {\r\n\t\t\t\t\tSaveManager.Load(gameArea, SaveType.Level);\r\n\t\t\t\t}, \"Level saves\");\r\n\t\t\t\t\r\n\t\t\t\tLoadSection(() => {\r\n\t\t\t\t\tif (Run.Depth > 0) {\r\n\t\t\t\t\t\tSaveManager.Load(gameArea, SaveType.Player);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tSaveManager.Generate(gameArea, SaveType.Player);\r\n\t\t\t\t\t}\r\n\t\t\t\t}, \"Player saves\");\r\n\r\n\t\t\t\tLog.Info($\"Done loading level in {sw.ElapsedMilliseconds} ms! Going to menu.\");\r\n\t\t\t\t\r\n\t\t\t\tready = true;\r\n\t\t\t});\r\n\r\n\t\t\tthread.Start();\r\n\t\t}\r\n\r\n\t\tprivate float tm;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tt += dt;\r\n\t\t\ttm -= dt;\r\n\r\n\t\t\tif (tm <= 0) {\r\n\t\t\t\ttm = 10f;\r\n\t\t\t\tGenerateNewTip();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (checkFullscreen) {\r\n\t\t\t\tcheckFullscreen = false;\r\n\t\t\t\t\r\n\t\t\t\tif (Settings.Fullscreen) {\r\n\t\t\t\t\tEngine.Instance.SetFullscreen();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tEngine.Instance.SetWindowed(Display.Width * 3, Display.Height * 3);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!tipLabel.Visible && logoCard.DoneLerping && !added) {\r\n\t\t\t\ttipLabel.Visible = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (added && tipLabel.Visible && exitTweenDone) {\r\n\t\t\t\ttipLabel.Visible = false;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (!added && ready && lastV >= 0.99f) {\r\n\t\t\t\tadded = true;\r\n\t\t\t\tlogoCard.GoAway = true;\r\n\r\n\t\t\t\t/*Timer.Add(() => {\r\n\t\t\t\t\tUi.Add(cards[0] = new PhotoCard {\r\n\t\t\t\t\t\tRegion = new TextureRegion(Textures.FastLoad(\"Content/egor.png\")),\r\n\t\t\t\t\t\tName = \"Egor Dorichev\",\r\n\t\t\t\t\t\tTasks = \"Code, Art, Sfx & Design\",\r\n\t\t\t\t\t\tUrl = \"https://twitter.com/egordorichev\",\r\n\t\t\t\t\t\tPosition = new Vector2(-350, 135),\r\n\t\t\t\t\t\tTarget = new Vector2(80, 135),\r\n\t\t\t\t\t\tAngle = 1f\r\n\t\t\t\t\t});\r\n\t\t\t\r\n\t\t\t\t\tUi.Add(cards[1] = new PhotoCard {\r\n\t\t\t\t\t\tRegion = new TextureRegion(Textures.FastLoad(\"Content/jose.png\")),\r\n\t\t\t\t\t\tName = \"Jose Ramon\",\r\n\t\t\t\t\t\tTasks = \"Music & Sfx\",\r\n\t\t\t\t\t\tUrl = \"https://twitter.com/BibikiGL\",\r\n\t\t\t\t\t\tPosition = new Vector2(240, 360),\r\n\t\t\t\t\t\tTarget = new Vector2(240, 135)\r\n\t\t\t\t\t});\r\n\t\t\t\r\n\t\t\t\t\tcards[1].Start.Y = -160;\r\n\t\t\t\t\r\n\t\t\t\t\tUi.Add(cards[2] = new PhotoCard {\r\n\t\t\t\t\t\tRegion = new TextureRegion(Textures.FastLoad(\"Content/mate.png\")),\r\n\t\t\t\t\t\tName = \"Mate Cziner\",\r\n\t\t\t\t\t\tTasks = \"Art & Design\",\r\n\t\t\t\t\t\tUrl = \"https://twitter.com/MateCziner\",\r\n\t\t\t\t\t\tPosition = new Vector2(Display.UiWidth + 350, 135),\r\n\t\t\t\t\t\tTarget = new Vector2(400, 135),\r\n\t\t\t\t\t\tAngle = -1f\r\n\t\t\t\t\t});\r\n\t\t\t\t}, 0.3f);*/\r\n\t\t\t}\r\n\r\n\t\t\tif (ready && added && logoCard.Done && !removed) {\r\n\t\t\t\tremoved = true;\r\n\t\t\t\tEngine.Instance.StateRenderer.UiEffect = Shaders.Ui;\r\n\t\t\t\tEngine.Instance.SetState(new InGameState(gameArea, true));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void RenderUi() {\r\n\t\t\tbase.RenderUi();\r\n\t\t\t\r\n\t\t\tvar v = Math.Min(1, progress / 23f);\r\n\t\t\tlastV += (v - lastV) * Engine.Delta;\r\n\r\n\t\t\tvar w = Display.UiWidth * 0.5f;\r\n\t\t\tvar h = 16;\r\n\t\t\tvar vl = 0.9f;\r\n\t\t\tvar pos = new Vector2((Display.UiWidth - w) / 2, Display.UiHeight * 0.5f + 96);\r\n\t\t\tvar loadingAlpha = Math.Max(0, 1f - (logoCard.Target.Y + 20 - logoCard.Y) / (logoCard.Target.Y + 20));\r\n\t\t\t\r\n\t\t\tGraphics.Color = new Color(1, 1, 1, loadingAlpha);\r\n\t\t\tGraphics.Render(pixel, pos, 0, Vector2.Zero, new Vector2(w, h));\r\n\t\t\tGraphics.Color = ColorUtils.BlackColor;\r\n\t\t\tGraphics.Render(pixel, pos + new Vector2(1), 0, Vector2.Zero, new Vector2(w - 2, h - 2));\r\n\t\t\tGraphics.Color = new Color(vl, vl, vl, loadingAlpha);\r\n\t\t\tGraphics.Render(pixel, pos + new Vector2(2), 0, Vector2.Zero, new Vector2(lastV * (w - 4), h - 4));\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\r\n\t\t\ttipLabel.Tint.A = (byte)(Math.Max(0, 1f - (logoCard.Target.Y - logoCard.Y) / logoCard.Target.Y) * 255);\r\n\r\n\t\t\tGraphics.Color.A = (byte)(loadingAlpha * 255);\r\n\t\t\t\r\n\t\t\tvar percentage = (int) Math.Round(lastV * 100);\r\n\r\n\t\t\tif (percentage > 5) {\r\n\t\t\t\tGraphics.Print($\"{percentage}%\", Font.Small, (int)(pos.X + lastV * (w - 4)) - 15, (int)pos.Y + 3);\r\n\t\t\t}\r\n\r\n\t\t\tvar loadingLabel = $\"Loading: {currentlyLoadingLabel}...\";\r\n\t\t\tGraphics.Print(loadingLabel, Font.Small, Display.UiWidth / 2 - (int)Font.Small.MeasureString(loadingLabel).Width / 2, Display.UiHeight - 20);\r\n\r\n\t\t\tGraphics.Color.A = 255;\r\n\t\t}\r\n\r\n\t\tprivate void GenerateNewTip() {\r\n\t\t\texitTweenDone = false;\r\n\r\n\t\t\t// TODO: Increase tip chance when more tips are added.\r\n\t\t\tvar tip = new Random().NextDouble() > 0.2 ? LoadScreenJokes.Generate() : LoadScreenTips.Generate();\r\n\r\n\t\t\tTween.To(Display.UiWidth + 150, tipLabel.CenterX, x => tipLabel.CenterX = x, 1.5f, Ease.QuadIn).OnEnd += () => {\r\n\t\t\t\ttipLabel.Label = tip;\r\n\t\t\t\ttipLabel.FinishTyping();\r\n\t\t\t\ttipLabel.Center = new Vector2(-150, Display.UiHeight - 55);\r\n\r\n\t\t\t\tvar t = Tween.To(Display.UiWidth / 2f, tipLabel.CenterX, x => tipLabel.CenterX = x, 1.5f, Ease.QuadOut);\r\n\t\t\t\tt.OnEnd = () => exitTweenDone = true;\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tprivate void LoadSection(Action section, string name) {\r\n\t\t\tcurrentlyLoadingLabel = name;\r\n\r\n\t\t\tvar sw = Stopwatch.StartNew();\r\n\t\t\t\r\n\t\t\tsection();\r\n\r\n\t\t\tprogress++;\r\n\r\n\t\t\tif (SectionalLoadTimeLogging) {\r\n\t\t\t\tLog.Info($\"Loaded section '{name}' in {sw.ElapsedMilliseconds} ms.\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/Credits.cs",
    "content": "using System.Collections.Generic;\n\nnamespace BurningKnight.state {\n\tpublic class Credits {\n\t\tpublic static List<string[]> Text = new List<string[]>();\n\n\t\tprivate static void Add(string[] text) {\n\t\t\tText.Add(text);\n\t\t}\n\t\t\n\t\tstatic Credits() {\n\t\t\tAdd(new[] {\n\t\t\t\t\"A game by\",\n\t\t\t\t\"Egor Dorichev\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Developed between May 2018\",\n\t\t\t\t\"And June 2020\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Big thanks to\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Egor Dorichev (egordorichev)\",\n\t\t\t\t\"Programming, Game Design\",\n\t\t\t\t\"Art & Russian Translation\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Viktor Kraus (ViktorRKraus)\",\n\t\t\t\t\"Sound Design\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Jose Ramon (Bibiki)\",\n\t\t\t\t\"Early Sound Design & Composing\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"FailPositive\",\n\t\t\t\t\"Secret Tracks\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Ian Crail (RetrosaurDev)\",\n\t\t\t\t\"Early Art\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Mate Cziner\",\n\t\t\t\t\"Early Art\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Roman Gonzo\",\n\t\t\t\t\"Early Art\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"somepx\",\n\t\t\t\t\"Awesome Fonts\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Pavel Hartunov\",\n\t\t\t\t\"Russian Translation Tweaks\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Kirill Erokhin\",\n\t\t\t\t\"Russian Translation Tweaks\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Cubey\",\n\t\t\t\t\"Polish Translation\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"ArKeid0s & Memeber\",\n\t\t\t\t\"French Translation\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Nikithn\",\n\t\t\t\t\"Belarusian Translation\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Rick Nya\",\n\t\t\t\t\"Portugese Translation\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"nade_\",\n\t\t\t\t\"Italian Translation\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Andreas May (Maanex)\",\n\t\t\t\t\"German Translation & Extensive Playtesting & Wiki Development\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Brastin\",\n\t\t\t\t\"Extensive Playtesting & Inspiration\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Dean aka DSF100\",\n\t\t\t\t\"Extensive Playtesting & Inspiration\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Nufflee\",\n\t\t\t\t\"Early Development & Playtesting\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Nikita Grichan (anivire)\",\n\t\t\t\t\"Trailers & Extensive Playtesting\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"Special thanks to everyone\",\n\t\t\t\t\"from notsosolo, especially to:\"\n\t\t\t});\n\n\t\t\tAdd(new[] {\n\t\t\t\t\"wombatstuff\",\n\t\t\t\t\"Bilge Kaan\",\n\t\t\t\t\"Alex Clay\",\n\t\t\t\t\"Gaziter\",\n\t\t\t\t\"BenStarDEV\",\n\t\t\t\t\"Felipe\",\n\t\t\t\t\"torcado\",\n\t\t\t\t\"Salman_Shh\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"And you!\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Thank you for playing my game\"\n\t\t\t});\n\t\t\t\n\t\t\tAdd(new[] {\n\t\t\t\t\"Egor.\"\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/CutsceneState.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.cutscene.controller;\nusing BurningKnight.physics;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.entity;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.util.camera;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.state {\n\tpublic class CutsceneState : GameState {\n\t\tpublic Camera Camera;\n\t\tprivate float blackBarsSize = 50;\n\t\tprivate TextureRegion black;\n\t\tpublic Area TopUi;\n\n\t\tprivate string text;\n\t\tprivate float textW;\n\t\tprivate bool saying;\n\t\tprivate float a;\n\n\t\tpublic CutsceneState(Area area) {\n\t\t\tArea = area;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tLights.Destroy();\n\t\t\tArea.Destroy();\n\t\t\tArea = null;\n\n\t\t\tPhysics.Destroy();\n\t\t\tbase.Destroy();\n\t\t\tTopUi.Destroy();\n\n\t\t\tInput.Blocked = 0;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tTopUi = new Area();\n\n\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(0f);\n\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\n\t\t\tTween.To(1, 0, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f, Ease.QuadIn);\n\n\t\t\tArea.Add(new GobboCutsceneController {\n\t\t\t\tState = this\n\t\t\t});\n\t\t\t\n\t\t\tUi.Add(Camera = new Camera(new FollowingDriver()));\n\t\t\tCamera.Position = new Vector2(Display.Width / 2f, Display.Height / 2f) + new Vector2(32);\n\t\t\t\n\t\t\tblack = CommonAse.Ui.GetSlice(\"black\");\n\t\t}\n\t\t\n\t\tprivate void PrerenderShadows() {\n\t\t\tvar renderer = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\n\t\t\trenderer.EnableClip = false;\n\t\t\trenderer.End();\n\t\t\trenderer.BeginShadows();\n\n\t\t\tforeach (var e in Area.Tagged[Tags.HasShadow]) {\n\t\t\t\tif (e.AlwaysVisible || e.OnScreen) {\n\t\t\t\t\te.GetComponent<ShadowComponent>().Callback();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\trenderer.EndShadows();\n\t\t\trenderer.Begin();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (saying) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tPrerenderShadows();\n\t\t\tbase.Render();\n\t\t}\n\n\t\tpublic override void RenderUi() {\n\t\t\tbase.RenderUi();\n\t\t\t\n\t\t\tif (blackBarsSize > 0.01f) {\n\t\t\t\tGraphics.Render(black, Vector2.Zero, 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, blackBarsSize));\n\t\t\t\tGraphics.Render(black, new Vector2(0, Display.UiHeight + 1 - blackBarsSize), 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, blackBarsSize + 1));\n\t\t\t}\n\t\t\t\n\t\t\tTopUi.Render();\n\n\t\t\tif (saying) {\n\t\t\t\tGraphics.Color.A = (byte) (a * 255f);\n\t\t\t\tGraphics.Print(text, Font.Medium, new Vector2((Display.UiWidth - textW) * 0.5f, Display.UiHeight * 0.5f - 4));\n\t\t\t\tGraphics.Color.A = 255;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tfloat speed = dt * 120f;\n\t\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad4)) {\n\t\t\t\tCamera.Instance.PositionX -= speed;\n\t\t\t}\n\t\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad6)) {\n\t\t\t\tCamera.Instance.PositionX += speed;\n\t\t\t}\n\t\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad8)) {\n\t\t\t\tCamera.Instance.PositionY -= speed;\n\t\t\t}\n\t\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad2)) {\n\t\t\t\tCamera.Instance.PositionY += speed;\n\t\t\t}\n\t\t\t\n\t\t\tPhysics.Update(dt);\n\t\t\tTopUi.Update(dt);\n\t\t\tRun.Update();\n\t\t}\n\n\t\tpublic void Say(string what, Action callback = null) {\n\t\t\ttext = what;\n\t\t\ttextW = Font.Medium.MeasureString(what).Width;\n\t\t\t\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\n\t\t\tTween.To(0, 1, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f).OnEnd = () => {\n\t\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\n\t\t\t\ta = 0;\n\t\t\t\tTween.To(1, 0, x => a = x, 0.5f);\n\n\t\t\t\tsaying = true;\n\t\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(1f);\n\n\t\t\t\tTween.To(0, 1, x => a = x, 0.5f).OnEnd = () => {\n\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\tsaying = false;\n\t\t\t\t\t\tcallback?.Invoke();\n\t\t\t\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(0f);\n\t\t\t\t\t\tTween.To(1, 0, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f, Ease.QuadIn);\n\t\t\t\t\t}, 2f);\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\tpublic void Transition(Action callback) {\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\n\t\t\tTween.To(0, 1, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f).OnEnd = () => {\n\t\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\t\t\t\tcallback();\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/DevAssetLoadState.cs",
    "content": "using System;\r\nusing System.Threading;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.loot;\r\nusing BurningKnight.assets.mod;\r\nusing BurningKnight.assets.prefabs;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.physics;\r\nusing BurningKnight.save;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.game;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic class DevAssetLoadState : GameState {\r\n\t\tprivate const bool LoadEditor = false;\r\n\t\tpublic const bool LoadCutscene = !LoadEditor && false;\r\n\t\t\r\n\t\tprivate int progress;\r\n\t\tprivate bool ready;\r\n\t\tprivate bool checkFullscreen;\r\n\t\tprivate Area gameArea;\r\n\t\tprivate float t;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\t\r\n\t\t\tprogress = 0;\r\n\r\n\t\t\tvar thread = new Thread(Load);\r\n\r\n\t\t\tthread.Priority = ThreadPriority.Highest;\r\n\t\t\tthread.Start();\r\n\t\t}\r\n\t\t\r\n\t\tprivate void Load() {\r\n\t\t\tLog.Info(\"Starting asset loading thread\");\r\n\r\n\t\t\tSaveManager.Load(gameArea, SaveType.Global);\r\n\t\t\tcheckFullscreen = true;\r\n\t\t\tprogress++;\r\n\t\t\t\r\n\t\t\tvar t = DateTime.Now.Millisecond;\r\n\t\t\tvar c = DateTime.Now.Millisecond;\r\n\r\n\t\t\tAssets.Load(ref progress);\r\n\t\t\tLog.Info($\"Assets took {(DateTime.Now.Millisecond - c) / 1000f} seconds\");\r\n\t\t\tc = DateTime.Now.Millisecond;\r\n\r\n\t\t\tDialogs.Load();\r\n\t\t\tprogress++;\r\n\t\t\tCommonAse.Load();\r\n\t\t\tprogress++;\r\n\t\t\tImGuiHelper.BindTextures();\r\n\t\t\tprogress++;\r\n\t\t\tShaders.Load();\r\n\t\t\tprogress++;\r\n\t\t\tPrefabs.Load();\r\n\t\t\tprogress++;\r\n\t\t\tItems.Load();\r\n\t\t\tprogress++;\r\n\t\t\tLootTables.Load();\r\n\t\t\tprogress++;\r\n\t\t\tMods.Load();\r\n\t\t\tprogress++; // Should be 13 here\r\n\t\t\tLog.Info($\"Custom assets took {(DateTime.Now.Millisecond - c) / 1000f} seconds\");\r\n\t\t\t\t\r\n\t\t\tLog.Info(\"Done loading assets! Loading level now.\");\r\n\t\t\t\r\n\t\t\tLights.Init();\r\n\t\t\tPhysics.Init();\r\n\t\t\tgameArea = new Area();\r\n\r\n\t\t\tRun.Level = null;\r\n\t\t\tTilesets.Load();\r\n\t\t\tprogress++;\r\n\t\t\t\t\r\n\t\t\tAchievements.Load();\r\n\t\t\tc = DateTime.Now.Millisecond;\r\n\r\n\t\t\tif (!LoadEditor) {\r\n\t\t\t\tSaveManager.Load(gameArea, SaveType.Game);\r\n\t\t\t\tprogress++;\r\n\t\t\t\tLog.Info($\"Game took {(DateTime.Now.Millisecond - c) / 1000f} seconds\");\r\n\t\t\t\tc = DateTime.Now.Millisecond;\r\n\r\n\t\t\t\tRnd.Seed = $\"{Run.Seed}_{Run.Depth}\";\r\n\r\n\t\t\t\tSaveManager.Load(gameArea, SaveType.Level);\r\n\t\t\t\tprogress++;\r\n\t\t\t\tLog.Info($\"Level took {(DateTime.Now.Millisecond - c) / 1000f} seconds\");\r\n\t\t\t\tc = DateTime.Now.Millisecond;\r\n\r\n\t\t\t\tif (Run.Depth > 0) {\r\n\t\t\t\t\tSaveManager.Load(gameArea, SaveType.Player);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tSaveManager.Generate(gameArea, SaveType.Player);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tLog.Info($\"Player took {(DateTime.Now.Millisecond - c) / 1000f}\");\r\n\t\t\t}\r\n\r\n\t\t\tprogress++; // Should be 18 here\r\n\t\t\tLog.Info($\"Done loading level! ({(DateTime.Now.Millisecond - t) / 1000f} seconds) Going to menu.\");\r\n\r\n\t\t\tEngine.AssetsLoaded?.Invoke();\r\n\t\t\tready = true;\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (checkFullscreen) {\r\n\t\t\t\tcheckFullscreen = false;\r\n\t\t\t\t\r\n\t\t\t\tif (Settings.Fullscreen) {\r\n\t\t\t\t\tEngine.Instance.SetFullscreen();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tEngine.Instance.SetWindowed(Display.Width * 3, Display.Height * 3);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tt += dt;\r\n\t\t\t\r\n\t\t\tif (ready) {\r\n\t\t\t\tif (Settings.Fullscreen) {\r\n\t\t\t\t\tEngine.Instance.SetFullscreen();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tEngine.Instance.SetWindowed(Display.Width * 3, Display.Height * 3);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tEngine.Instance.StateRenderer.UiEffect = Shaders.Ui;\r\n\t\t\t\tEngine.Instance.SetState(LoadEditor ? (GameState) new EditorState() : (LoadCutscene ? (GameState) new LoadState {\r\n\t\t\t\t\tIntoCutscene = true\r\n\t\t\t\t} : new InGameState(gameArea, false)));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void RenderUi() {\r\n\t\t\tbase.RenderUi();\r\n\t\t\tGraphics.Print($\"Loading assets {progress / 18f * 100}%\", Font.Small, new Vector2(10, 10));\r\n\t\t\t\r\n\t\t\tvar n = t % 2f;\r\n\t\t\tvar s = $\"{(n > 0.5f ? \".\" : \"\")}{(n > 1f ? \".\" : \"\")}{(n > 1.5f ? \".\" : \"\")}\";\r\n\t\t\t\r\n\t\t\tvar x = Font.Small.MeasureString(s).Width * -0.5f;\r\n\t\t\tGraphics.Print(s, Font.Small, new Vector2(Display.UiWidth / 2f + x, Display.UiHeight / 2f + 32));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/DialogEditorState.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.ui.imgui;\nusing Lens;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.state {\n\tpublic class DialogEditorState : GameState {\n\t\tpublic Camera Camera;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tEngine.Instance.StateRenderer = new NativeGameRenderer();\n\t\t\tEngine.Instance.State.Ui.Add(Camera = new Camera(new CameraDriver()));\n\t\t\t\n\t\t\tDialogEditor.Init();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tCamera.Width = Engine.Instance.GetScreenWidth();\n\t\t\tCamera.Height = Engine.Instance.GetScreenHeight();\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tDialogEditor.Destroy();\n\t\t\tbase.Destroy();\n\t\t\tEngine.Instance.StateRenderer = new PixelPerfectGameRenderer();\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tGraphics.Clear(ColorUtils.BlackColor);\n\t\t}\n\n\t\tpublic override void RenderUi() {\n\t\t\tDialogEditor.RenderUi();\n\t\t}\n\n\t\tpublic override void RenderNative() {\n\t\t\tImGuiHelper.Begin();\n\t\t\tDialogEditor.Render();\n\t\t\tDebugWindow.Render();\n\t\t\tImGuiHelper.End();\n\t\t\t\n\t\t\tGraphics.Batch.Begin();\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(Mouse.GetState().Position, 3f), 8, Color.White);\n\t\t\tGraphics.Batch.End();\n\t\t}\n\n\t\tpublic override bool NativeRender() {\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/Editor.cs",
    "content": "using BurningKnight.level;\nusing Lens.entity;\nusing Lens.util.camera;\n\nnamespace BurningKnight.state {\n\tpublic class Editor {\n\t\tpublic Camera Camera;\n\t\tpublic Level Level;\n\t\tpublic Area Area;\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/EditorState.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.prefabs;\nusing BurningKnight.entity.component;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.ui.editor;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\nusing VelcroPhysics.Utilities;\nusing Console = BurningKnight.debug.Console;\n\nnamespace BurningKnight.state {\n\tpublic class EditorState : GameState {\n\t\tpublic Level Level;\n\t\tpublic EditorWindow Editor;\n\t\tpublic Camera Camera;\n\t\tpublic Console Console;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tEngine.Instance.StateRenderer.GameEffect = null;\n\t\t\tEngine.Instance.StateRenderer.UiEffect = null;\n\t\t\t\n\t\t\tWindowManager.LevelEditor = true;\n\n\t\t\tEngine.EditingLevel = true;\n\n\t\t\tPhysics.Init();\n\t\t\tLights.Init();\n\t\t\tTilesets.Load();\n\n\t\t\tUi.Add(Camera = new Camera(new FollowingDriver()));\n\t\t\tConsole = new Console(Area);\n\n\t\t\tEditor = new EditorWindow(new Editor {\n\t\t\t\tArea = Area,\n\t\t\t\tLevel = Level,\n\t\t\t\tCamera = Camera\n\t\t\t});\n\t\t\t\n\n\t\t\tLevel = Editor.Editor.Level;\n\t\t\tfor (var i = 0; i < Level.Explored.Length; i++) {\n\t\t\t\tLevel.Explored[i] = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tPhysics.Destroy();\n\t\t\tLights.Destroy();\n\t\t\t\n\t\t\tEngine.EditingLevel = false;\n\t\t\tPrefabs.Reload();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tConsole.Update(dt);\n\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.Space)) {\n\t\t\t\tCamera.Position -= Input.Mouse.PositionDelta;\n\t\t\t\t\n\t\t\t\tCamera.X = MathUtils.Clamp(Camera.X, -Display.Width / 2f, Level.Width * 16f - Display.Width / 2f);\n\t\t\t\tCamera.Y = MathUtils.Clamp(Camera.Y, -Display.Height / 2f, Level.Height * 16f - Display.Height / 2f);\n\t\t\t}\n\t\t}\n\n\t\tprivate void PrerenderShadows() {\n\t\t\tvar renderer = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\n\t\t\trenderer.EnableClip = false;\n\t\t\trenderer.End();\n\t\t\trenderer.BeginShadows();\n\n\t\t\tforeach (var e in Area.Tagged[Tags.HasShadow]) {\n\t\t\t\tif (e.AlwaysVisible || e.OnScreen) {\n\t\t\t\t\te.GetComponent<ShadowComponent>().Callback();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\trenderer.EndShadows();\n\t\t\trenderer.Begin();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tPrerenderShadows();\n\t\t\tbase.Render();\n\t\t\tPhysics.Render();\n\t\t\tEditor.RenderInGame();\n\t\t}\n\n\t\tpublic override void RenderNative() {\n\t\t\tImGuiHelper.Begin();\n\t\t\tEditor.Render();\n\t\t\tConsole.Render();\n\t\t\tWindowManager.Render(Area);\n\t\t\tImGuiHelper.End();\t\t\t\n\t\t\t\n\t\t\tGraphics.Batch.Begin();\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(Mouse.GetState().Position, 3f), 8, Color.White);\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/InGameAudio.cs",
    "content": "using System.Linq;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature;\r\nusing BurningKnight.entity.creature.bk;\r\nusing BurningKnight.entity.creature.mob.boss;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.door;\r\nusing BurningKnight.entity.events;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.level.entities;\r\nusing BurningKnight.level.rooms;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.camera;\r\nusing Lens.util.math;\r\nusing Lens.util.timer;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Audio;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic class InGameAudio : Entity {\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tAlwaysActive = true;\r\n\r\n\t\t\tAudioEmitterComponent.Listener = new AudioListener();\r\n\t\t\t\r\n\t\t\tSubscribe<GramophoneBrokenEvent>();\r\n\t\t\tSubscribe<Gramophone.DiskChangedEvent>();\r\n\t\t\t\r\n\t\t\tSubscribe<RoomChangedEvent>();\r\n\t\t\tSubscribe<SecretRoomFoundEvent>();\r\n\t\t\tSubscribe<DiedEvent>();\r\n\t\t\tSubscribe<HealthModifiedEvent>();\r\n\t\t\t\r\n\t\t\tSubscribe<DoorClosedEvent>();\r\n\t\t\tSubscribe<DoorOpenedEvent>();\r\n\t\t\tSubscribe<LockOpenedEvent>();\r\n\t\t\tSubscribe<LockClosedEvent>();\r\n\t\t\t\r\n\t\t\tSubscribe<BombPlacedEvent>();\r\n\t\t\tSubscribe<ItemAddedEvent>();\r\n\t\t\t\r\n\t\t\tSubscribe<PlayerRolledEvent>();\r\n\t\t\tSubscribe<Boss.DefeatedEvent>();\r\n\r\n\t\t\tSubscribe<SpawnTrigger.TriggeredEvent>();\r\n\r\n\t\t\tif (!InGameState.InMenu && Run.Level != null) {\r\n\t\t\t\tAudio.PlayMusic(Run.Level.GetMusic()/*, Run.Depth < 1 || Run.Depth % 2 == 1*/);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\t// Audio.PlayMusic(\"Disk 6\", Camera.Instance.Listener, LocalPlayer.Locate(Area).GetComponent<AudioEmitterComponent>().Emitter);\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\tAudioEmitterComponent.Listener = null;\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tvar c = Camera.Instance;\r\n\t\t\t\r\n\t\t\tAudioEmitterComponent.ListenerPosition = new Vector2(c.PositionX, c.PositionY);\r\n\t\t\tAudioEmitterComponent.Listener.Position = new Vector3(c.PositionX * AudioEmitterComponent.PositionScale, 0, c.PositionY * AudioEmitterComponent.PositionScale);\r\n\t\t}\r\n\r\n\t\tpublic override bool HandleEvent(Event e) {\r\n\t\t\tif (InGameState.InMenu) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (e is GramophoneBrokenEvent ge) {\r\n\t\t\t\tvar local = LocalPlayer.Locate(ge.Gramophone.Area);\r\n\r\n\t\t\t\tif (local != null && ge.Gramophone.GetComponent<RoomComponent>().Room ==\r\n\t\t\t\t    local.GetComponent<RoomComponent>().Room) {\r\n\t\r\n\t\t\t\t\tAudio.Stop();\r\n\t\t\t\t}\r\n\t\t\t} else if (e is Gramophone.DiskChangedEvent gdce) {\r\n\t\t\t\tvar t = gdce.Gramophone.GetTune();\r\n\t\t\t\t\t\r\n\t\t\t\tif (t != null) {\r\n\t\t\t\t\tAudio.PlayMusic(t);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tAudio.FadeOut();\r\n\t\t\t\t}\r\n\t\t\t} else if (e is RoomChangedEvent re && re.Who is LocalPlayer) {\r\n\t\t\t\tswitch (re.New.Type) {\r\n\t\t\t\t\tcase RoomType.Boss: {\r\n\t\t\t\t\t\tif (Run.Level.Biome is TechBiome) {\r\n\t\t\t\t\t\t\tAudio.PlayMusic(Run.Level.Biome.GetMusic());\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tif (Area.Tagged[Tags.Boss].Count > 0 && ((Boss) Area.Tagged[Tags.Boss][0]).Awoken) {\r\n\t\t\t\t\t\t\t\tAudio.PlayMusic((Run.Level.Biome is LibraryBiome || Run.Level.Biome is LibraryBiome)\r\n\t\t\t\t\t\t\t\t\t? \"Last chance\"\r\n\t\t\t\t\t\t\t\t\t: \"Fatiga\");\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tAudio.PlayMusic(\"Gobbeon\");\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase RoomType.DarkMarket: {\r\n\t\t\t\t\t\tif (Run.AlternateMusic) {\r\n\t\t\t\t\t\t\tAudio.PlayMusic(\"piano\");\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Serendipity\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase RoomType.Treasure: {\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Ma Precious\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase RoomType.Secret: {\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Serendipity\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcase RoomType.Shop: {\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Shopkeeper\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase RoomType.OldMan: {\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Gobbeon\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase RoomType.Granny: {\r\n\t\t\t\t\t\tAudio.PlayMusic(\"Disk 1\");\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdefault: {\r\n\t\t\t\t\t\tAudio.PlayMusic(Run.Level.GetMusic());\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (e is SecretRoomFoundEvent) {\r\n\t\t\t\tAudio.Stop();\r\n\t\t\t\tAudio.PlaySfx(\"secret\");\r\n\t\t\t} else if (e is DiedEvent de) {\r\n\t\t\t\tif (de.Who is Player pl && InGameState.EveryoneDied(pl)) {\r\n\t\t\t\t\tAudio.Stop();\r\n\t\t\t\t\tAudio.PlayMusic(\"Nostalgia\");\r\n\t\t\t\t}\r\n\t\t\t} else if (e is Boss.DefeatedEvent) {\r\n\t\t\t\tAudio.Stop();\r\n\t\t\t\tAudio.PlayMusic(\"Reckless\");\r\n\t\t\t\tAudio.Repeat = false;\r\n\t\t\t}\r\n\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/InGameState.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.input;\nusing BurningKnight.assets.items;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.fx;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.stand;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.entity.room;\nusing BurningKnight.entity.twitch;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.paintings;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.save;\nusing BurningKnight.save.statistics;\nusing BurningKnight.ui;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.ui.editor;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.ui.inventory;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Audio;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\nusing Newtonsoft.Json;\nusing Steamworks;\nusing Console = BurningKnight.debug.Console;\nusing Timer = Lens.util.timer.Timer;\n\nnamespace BurningKnight.state {\n\tpublic class InGameState : GameState, Subscriber {\n\t\tpublic static bool ShouldHide => Engine.Instance.State is InGameState st && st.Paused && !st.InStats && st.currentBack != st.graphicsBack;\n\t\t\n\t\tpublic static bool SkipPause;\n\t\tpublic static Action<UiTable, string, string, int, Action> SetupLeaderboard;\n\t\tpublic static bool IgnoreSave;\n\t\tpublic static Action SyncAchievements;\n\t\tpublic static bool Multiplayer;\n\t\t\n\t\tprivate const float AutoSaveInterval = 60f;\n\t\tprivate const float PaneTransitionTime = 0.2f;\n\t\tprivate const float BarsSize = 50;\n\t\tprivate static float TitleY = BarsSize / 2f;\n\t\tprivate static float BackY = Display.UiHeight - BarsSize / 2f;\n\n\t\tprivate float blur;\n\t\tprivate static TextureRegion fog;\n\t\t\n\t\tprivate UiPane pauseMenu;\n\t\tprivate UiPane leaderMenu;\n\t\tprivate UiPane statsMenu;\n\t\tprivate UiPane gameOverMenu;\n\t\tprivate UiPane credits;\n\n\t\tprivate UiPane audioSettings;\n\t\tprivate UiPane graphicsSettings;\n\t\tprivate UiPane gameSettings;\n\t\tprivate UiPane confirmationPane;\n\t\tprivate UiPane inputSettings;\n\t\tprivate UiPane gamepadSettings;\n\t\tprivate UiPane keyboardSettings;\n\t\tprivate UiPane languageSettings;\n\t\tprivate UiPane inventory;\n\t\tprivate UiLabel killedLabel;\n\t\tprivate UiLabel placeLabel;\n\n\t\tpublic bool Died;\n\t\tprivate float saveTimer;\n\t\tprivate SaveIndicator indicator;\n\t\tprivate SaveLock saveLock = new SaveLock();\n\n\t\tprivate Painting painting;\n\t\tprivate EditorWindow editor;\n\n\t\tpublic bool Menu;\n\t\tpublic Area TopUi;\n\t\t\n\t\tprivate float offset;\n\t\tprivate bool menuExited;\n\t\tprivate float blackBarsSize;\n\t\tprivate bool doneAnimatingPause = true;\n\t\t\n\t\tprivate TextureRegion gardient;\n\t\tprivate TextureRegion black;\n\t\tprivate TextureRegion emerald;\n\n\t\tpublic UiAnimation Killer;\n\t\tpublic Console Console;\n\t\tprivate UiLabel seedLabel;\n\t\tprivate UiButton currentBack;\n\t\tprivate UiButton inputBack;\n\t\tprivate UiButton gamepadBack;\n\t\tprivate UiButton keyboardBack;\n\t\tprivate UiButton languageBack;\n\n\t\tprivate float timeWas;\n\t\tprivate double startTime;\n\n\t\tpublic static bool Ready;\n\t\tpublic static bool InMenu;\n\t\t\n\t\tpublic void TransitionToBlack(Vector2 position, Action callback = null) {\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tvar v = Camera.Instance.CameraToScreen(position);\n\n\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(v.X / Display.UiWidth);\n\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(v.Y / Display.UiHeight);\n\n\t\t\tTween.To(0, 1, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f).OnEnd = callback;\n\n\t\t\tAudio.FadeOut();\n\t\t\tReady = false;\n\t\t}\n\n\t\tpublic void TransitionToOpen(Action callback = null) {\n\t\t\tShaders.Ui.Parameters[\"bx\"].SetValue(0.333f);\n\t\t\tShaders.Ui.Parameters[\"by\"].SetValue(0.333f);\n\n\t\t\tTween.To(1, 0, x => Shaders.Ui.Parameters[\"black\"].SetValue(x), 0.7f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\tReady = true;\n\t\t\t\tcallback?.Invoke();\n\t\t\t};\n\t\t}\n\n\t\tpublic Painting CurrentPainting {\n\t\t\tset {\n\t\t\t\tpainting = value;\n\t\t\t\tPaused = painting != null;\n\t\t\t}\n\n\t\t\tget => painting;\n\t\t}\n\n\t\tpublic InGameState(Area area, bool menu) {\n\t\t\tMultiplayer = area.Tagged[Tags.Player].Count > 1;\n\t\t\t\n\t\t\tMenu = menu;\n\t\t\tInMenu = menu;\n\t\t\tReady = false;\n\t\t\tInput.EnableImGuiFocus = false;\n\n\t\t\tArea = area;\n\t\t\tArea.EventListener.Subscribe<ItemCheckEvent>(this);\n\t\t\tArea.EventListener.Subscribe<DiedEvent>(this);\n\t\t\tArea.EventListener.Subscribe<GiveEmeraldsUse.GaveEvent>(this);\n\n\t\t\tblack = CommonAse.Ui.GetSlice(\"black\");\n\t\t\temerald = CommonAse.Items.GetSlice(\"bk:emerald\");\n\n\t\t\tif (Menu) {\n\t\t\t\tAchievements.PostLoadCallback?.Invoke();\n\t\t\t\tAchievements.PostLoadCallback = null;\n\t\t\t\n\t\t\t\tInput.Blocked = 1;\n\n\t\t\t\tblackBarsSize = BarsSize;\n\t\t\t\tgardient = CommonAse.Ui.GetSlice(\"gardient\");\n\t\t\t\tblur = 1;\n\n\t\t\t\toffset = Display.UiHeight;\n\t\t\t\tMouse.SetPosition((int) BK.Instance.GetScreenWidth() / 2, (int) BK.Instance.GetScreenHeight() / 2);\n\n\t\t\t\tTimer.Add(() => {\n\t\t\t\t\tTween.To(0, offset, x => offset = x, 2f, Ease.BackOut);\n\t\t\t\t\tAudio.PlayMusic(\"Menu\", true);\n\t\t\t\t}, 1f);\n\t\t\t} else {\n\t\t\t\toffset = Display.UiHeight;\n\t\t\t}\n\t\t\t\n\t\t\tShaders.Screen.Parameters[\"vignette\"].SetValue(Settings.Vignette);\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tif (Run.Depth < 1) {\n\t\t\t\tRun.Time = 0;\n\t\t\t}\n\n\t\t\tunlockedHat = GlobalSave.IsTrue(\"bk:fez\");\n\n\t\t\tTopUi = new Area();\n\t\t\tInput.Blocked = 0;\n\n\t\t\tAudio.Speed = 1f;\n\n\t\t\tEngine.Graphics.SynchronizeWithVerticalRetrace = Settings.Vsync;\n\t\t\tEngine.Graphics.ApplyChanges();\n\n\t\t\tEngine.Instance.StateRenderer.UiEffect = Shaders.Ui;\n\t\t\t\n\t\t\tif (Settings.Fullscreen && !Engine.Graphics.IsFullScreen) {\n\t\t\t\tEngine.Instance.SetFullscreen();\n\t\t\t}\n\n\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(Menu ? 1f : 0f);\n\t\t\t\n\t\t\tSetupUi();\n\n\t\t\tif (Run.Level?.Biome is CastleBiome) {\n\t\t\t\tfor (var i = 0; i < 30; i++) {\n\t\t\t\t\tArea.Add(new WindFx());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfog = Textures.Get(\"noise\");\n\t\t\tArea.Add(new InGameAudio());\n\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tif (p is LocalPlayer) {\n\t\t\t\t\tbool imp = p.GetComponent<InputComponent>().Index == 0;\n\t\t\t\t\tCamera.Instance.Follow(p, imp ? 1f : 0.5f, imp);\n\t\t\t\t\t\n\t\t\t\t\tif (imp && Assets.ImGuiEnabled) {\n\t\t\t\t\t\tAreaDebug.ToFocus = p;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t((Player) p).FindSpawnPoint();\n\t\t\t}\n\n\t\t\tif (!Menu) {\n\t\t\t\tforeach (var e in TopUi.Tagged[Tags.Cursor]) {\n\t\t\t\t\tCamera.Instance.Follow(e, CursorPriority);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCamera.Instance.Jump();\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tif (Events.Halloween) {\n\t\t\t\t\tWeather.IsNight = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Weather.IsNight) {\n\t\t\t\t\twasNight = true;\n\t\t\t\t\tvar x = 0.25f;\n\t\t\t\t\tLights.ClearColor = new Color(x, x, x, 1f);\n\t\t\t\t}\n\n\t\t\t\tif (Weather.Rains || Weather.Snows) {\n\t\t\t\t\tSetupParticles();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!Menu) {\n\t\t\t\tTransitionToOpen();\n\t\t\t}\n\n\t\t\tFireParticle.Hook(Area);\n\t\t\tRun.StartedNew = false;\n\t\t\t\n\t\t\tif (Run.Depth > 0 && GameSave.IsFalse($\"reached_{Run.Depth}\")) {\n\t\t\t\tGameSave.Put($\"reached_{Run.Depth}\", true);\n\t\t\t\tArea.EventListener.Handle(new NewFloorEvent {\n\t\t\t\t\tWasInEL = true\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tRun.Level.Prepare();\n\n\t\t\tif (Run.Depth < 1) {\n\t\t\t\tScourge.Clear();\n\t\t\t}\n\n\t\t\tif (Run.Depth == 1 && Area.Tagged[Tags.BurningKnight].Count == 0) {\n\t\t\t\tArea.Add(new entity.creature.bk.BurningKnight());\n\t\t\t}\n\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tTwitchBridge.OnHubEnter?.Invoke();\n\t\t\t\tSyncAchievements?.Invoke();\n\t\t\t}\n\n\t\t\tCaptureTime();\n\t\t}\n\n\t\tprivate void CaptureTime() {\n\t\t\ttimeWas = Run.Time;\n\t\t\tstartTime = Engine.GameTime.TotalGameTime.TotalSeconds;\n\t\t}\n\n\t\tprivate const float CursorPriority = 0.5f;\n\n\t\tpublic void ResetFollowing() {\n\t\t\tCamera.Instance.Targets.Clear();\n\t\t\tCamera.Instance.MainTarget = null;\n\n\t\t\tvar min = 16;\n\t\t\t\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tif (p is LocalPlayer lp && !lp.Dead) {\n\t\t\t\t\tvar index = p.GetComponent<InputComponent>().Index;\n\n\t\t\t\t\tif (index < min) {\n\t\t\t\t\t\tmin = index;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tif (p is LocalPlayer) {\n\t\t\t\t\tvar imp = !Multiplayer || p.GetComponent<InputComponent>().Index == min;\n\t\t\t\t\tCamera.Instance.Follow(p, imp ? 1f : 0.5f, imp);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!Menu) {\n\t\t\t\tforeach (var e in TopUi.Tagged[Tags.Cursor]) {\n\t\t\t\t\tCamera.Instance.Follow(e, CursorPriority);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tif (Engine.Quiting) {\n\t\t\t\tRun.SavingDepth = Run.Depth;\n\t\t\t}\n\t\t\tItem.Attact = false;\n\n\t\t\tif (rainSound != null) {\n\t\t\t\tif (Engine.Quiting) {\n\t\t\t\t\trainSound.Dispose();\n\t\t\t\t\trainSound = null;\n\t\t\t\t} else {\n\t\t\t\t\tvar ss = rainSound;\n\t\t\t\t\trainSound = null;\n\t\t\t\t\tTween.To(0, ss.Volume, x => ss.Volume = x, 0.5f).OnEnd = () => { ss.Dispose(); };\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tTopUi.Destroy();\n\t\t\t\n\t\t\tTimer.Clear();\n\t\t\tLights.Destroy();\n\n\t\t\tTween.To(1f, Audio.Speed, x => Audio.Speed = x, 1f);\n\t\t\t\n\t\t\tSaveManager.Backup();\n\n\t\t\tvar old = !Engine.Quiting;\n\n\t\t\tSaveManager.Save(Area, SaveType.Global, old);\n\t\t\t// SaveManager.Save(Area, SaveType.Secret);\n\n\t\t\tif (!Run.StartedNew && !Died && !Run.Won) {\n\t\t\t\tvar d = (old ? Run.LastDepth : Run.Depth);\n\t\t\t\t\n\t\t\t\tif (d > 0) {\n\t\t\t\t\tif (IgnoreSave) {\n\t\t\t\t\t\t\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSaveManager.Save(Area, SaveType.Level, old);\n\t\t\t\t\t}\n\n\t\t\t\t\tIgnoreSave = false;\n\n\t\t\t\t\tSaveManager.Save(Area, SaveType.Player, old);\n\t\t\t\t\tSaveManager.Save(Area, SaveType.Game, old);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tShaders.Screen.Parameters[\"split\"].SetValue(0f);\n\t\t\tShaders.Screen.Parameters[\"blur\"].SetValue(0f);\n\n\t\t\tArea.Destroy();\n\t\t\tArea = null;\n\n\t\t\tPhysics.Destroy();\n\t\t\tbase.Destroy();\n\t\t}\n\n\t\tprivate float speedBeforePause;\n\t\tpublic bool InStats;\n\n\t\tprotected override void OnPause() {\n\t\t\tbase.OnPause();\n\t\t\t\n\t\t\tif (Died || InMenu || Run.Won) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tt = 0;\n\t\t\tTween.To(this, new {blur = 1}, 0.25f);\n\n\t\t\tif (!InStats) {\n\t\t\t\tcurrentBack = pauseBack;\n\t\t\t\t\n\t\t\t\tif (seedLabel != null) {\n\t\t\t\t\tseedLabel.Label = $\"{Locale.Get(\"seed\")}: {Run.Seed}\";\n\t\t\t\t}\n\n\t\t\t\tif (scoreLabel != null) {\n\t\t\t\t\tscoreLabel.Label = GetScore();\n\t\t\t\t}\n\n\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\tAudio.PlaySfx(\"ui_goback\", 0.5f);\n\t\t\t\t}\n\n\t\t\t\tif (painting == null) {\n\t\t\t\t\tdoneAnimatingPause = false;\n\n\t\t\t\t\tpauseMenu.X = 0;\n\t\t\t\t\tpauseMenu.Enabled = true;\n\t\t\t\t\tcurrentBack = pauseBack;\n\n\t\t\t\t\tTween.To(0, pauseMenu.Y, x => pauseMenu.Y = x, 0.5f, Ease.BackOut).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tOnPauseCallback?.Invoke();\n\t\t\t\t\t\tOnPauseCallback = null;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcurrentBack = leaderBack;\n\t\t\t}\n\n\t\t\tspeedBeforePause = Audio.Speed;\n\n\t\t\tTween.To(0.5f, Audio.Speed, x => Audio.Speed = x, 1f).OnEnd = () => {\n\t\t\t\tdoneAnimatingPause = true;\n\t\t\t};\n\t\t\tOpenBlackBars();\n\t\t}\n\n\t\tpublic void OpenBlackBars() {\n\t\t\tTween.To(BarsSize, blackBarsSize, x => blackBarsSize = x, 0.3f);\n\t\t}\n\t\t\n\t\tpublic void CloseBlackBars() {\n\t\t\tTween.To(0, blackBarsSize, x => blackBarsSize = x, 0.2f);\n\t\t}\n\n\t\tprotected override void OnResume() {\n\t\t\tif (painting != null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.OnResume();\n\n\t\t\tif (Died || InMenu || Run.Won) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tdoneAnimatingPause = false;\n\n\t\t\tTween.To(this, new {blur = 0}, 0.25f);\n\n\t\t\tif (!InStats) {\n\t\t\t\tTween.To(-Display.UiHeight, pauseMenu.Y, x => pauseMenu.Y = x, 0.25f).OnEnd = () => {\n\t\t\t\t\tpauseMenu.Enabled = false;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tCloseBlackBars();\n\t\t\tTween.To(speedBeforePause, Audio.Speed, x => Audio.Speed = x, 0.4f);\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tdoneAnimatingPause = true;\n\t\t\t}, 0.25f);\n\t\t}\n\n\t\tpublic override void OnDeactivated() {\n\t\t\tbase.OnDeactivated();\n\n\t\t\tif (Menu || Paused || DialogComponent.Talking != null || !Settings.Autopause || !menuExited) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tPaused = true;\n\t\t}\n\n\t\tprivate float t;\n\t\t\n\t\tprivate void SelectFirst() {\n\t\t\tSelectFirst(false);\n\t\t}\n\n\t\tprivate void SelectFirst(bool force) {\n\t\t\tif (!force && GamepadComponent.Current == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\tvar min = UiButton.LastId;\n\t\t\tUiButton btn = null;\n\n\t\t\tforeach (var b in TopUi.Tagged[Tags.Button]) {\n\t\t\t\tvar bt = ((UiButton) b);\n\n\t\t\t\tif (bt.Active && bt.IsOnScreen() && bt.Id < min) {\n\t\t\t\t\tbtn = bt;\n\t\t\t\t\tmin = bt.Id;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (btn != null) {\n\t\t\t\tUiButton.SelectedInstance = btn;\n\t\t\t\tUiButton.Selected = btn.Id;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool wasNight;\n\t\tprivate bool wasRaining;\n\t\tprivate SoundEffectInstance rainSound;\n\t\tprivate List<Entity> particles = new List<Entity>();\n\n\t\tprivate void SetupParticles() {\n\t\t\tif (Settings.LowQuality) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\tif (Weather.Rains && Assets.LoadSfx) {\n\t\t\t\tvar s = Audio.GetSfx(\"level_rain_jungle\");\n\n\t\t\t\tif (s != null) {\n\t\t\t\t\trainSound = s.CreateInstance();\n\n\t\t\t\t\tif (rainSound != null) {\n\t\t\t\t\t\trainSound.Volume = 0;\n\t\t\t\t\t\trainSound.IsLooped = true;\n\t\t\t\t\t\trainSound.Play();\n\n\t\t\t\t\t\tTween.To(0.5f * Settings.MusicVolume * Settings.MasterVolume, 0, x => rainSound.Volume = x, 5f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < 40; i++) {\n\t\t\t\t\tparticles.Add(Run.Level.Area.Add(new RainParticle {\n\t\t\t\t\t\tCustom = true\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t} else if (Weather.Snows) {\n\t\t\t\tfor (var i = 0; i < 100; i++) {\n\t\t\t\t\tparticles.Add(Run.Level.Area.Add(new SnowParticle {\n\t\t\t\t\t\tCustom = true\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool stopped;\n\n\t\tprivate bool unlockedHat;\n\t\tprivate int comboScore;\n\t\tprivate string[] combo = {\n\t\t\tControls.UiLeft, Controls.UiDown, Controls.UiRight, Controls.UiUp, \n\t\t\tControls.UiDown, Controls.UiRight, Controls.UiDown, Controls.UiLeft\n\t\t};\n\n\t\tprivate string[] possibleButtons = {\n\t\t\tControls.UiDown, Controls.UiRight, Controls.UiLeft, Controls.UiUp\n\t\t};\n\n\t\tprivate void CheckCombo() {\n\t\t\tvar reset = false;\n\t\t\tvar data = GamepadComponent.Current;\n\t\t\t\n\t\t\tif (Input.Keyboard.State.GetPressedKeys().Length > 0) {\n\t\t\t\treset = true;\n\t\t\t} else if (data != null && data.AnythingIsDown()) {\n\t\t\t\treset = true;\n\t\t\t}\n\n\t\t\tif (!reset) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar found = false;\n\t\t\t\t\n\t\t\tforeach (var b in possibleButtons) {\n\t\t\t\tif (Input.WasPressed(b, data)) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!found) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cr = combo[comboScore];\n\n\t\t\tif (Input.IsDown(cr, data)) {\n\t\t\t\tforeach (var b in possibleButtons) {\n\t\t\t\t\tif (cr != b && Input.IsDown(b, data)) {\n\t\t\t\t\t\tcomboScore = 0;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcomboScore++;\n\n\t\t\t\tif (comboScore >= 8) {\n\t\t\t\t\tItems.Unlock(\"bk:fez\");\n\t\t\t\t\tAudio.PlaySfx(\"level_cleared\");\n\t\t\t\t\tunlockedHat = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcomboScore = 0;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool doCheck;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tif (!unlockedHat) {\n\t\t\t\tCheckCombo();\n\t\t\t}\n\t\t\t\n\t\t\tif (UiAchievement.Current == null) {\n\t\t\t\tif (Achievements.AchievementBuffer.Count > 0) {\n\t\t\t\t\tvar id = Achievements.AchievementBuffer[0];\n\t\t\t\t\n\t\t\t\t\tvar a = new UiAchievement(id);\n\t\t\t\t\ta.Y = Display.UiHeight + 60;\n\t\t\t\t\tTopUi.Add(a);\n\t\t\t\t\ta.Right = Display.UiWidth - 8;\n\t\t\t\t} else if (Achievements.ItemBuffer.Count > 0) {\n\t\t\t\t\tvar id = Achievements.ItemBuffer[0];\n\t\t\t\t\n\t\t\t\t\tvar a = new UiAchievement(id, true);\n\t\t\t\t\ta.Y = Display.UiHeight + 60;\n\t\t\t\t\tTopUi.Add(a);\n\t\t\t\t\ta.Right = Display.UiWidth - 8;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!Paused && (Settings.Autosave && Run.Depth > 0)) {\n\t\t\t\tif (!saving) {\n\t\t\t\t\tsaveTimer += dt;\n\n\t\t\t\t\tif (saveTimer >= AutoSaveInterval) {\n\t\t\t\t\t\tsaveTimer = 0;\n\t\t\t\t\t\tsaving = true;\n\t\t\t\t\t\tsaveLock.Reset();\n\n\t\t\t\t\t\tindicator.HandleEvent(new SaveStartedEvent());\n\n\t\t\t\t\t\tnew Thread(() => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tSaveManager.Backup();\n\n\t\t\t\t\t\t\t\tSaveManager.ThreadSave(saveLock.UnlockGlobal, Area, SaveType.Global);\n\t\t\t\t\t\t\t\tSaveManager.ThreadSave(saveLock.UnlockGame, Area, SaveType.Game);\n\n\t\t\t\t\t\t\t\tSaveManager.ThreadSave(saveLock.UnlockLevel, Area, SaveType.Level);\n\t\t\t\t\t\t\t\tSaveManager.ThreadSave(saveLock.UnlockPlayer, Area, SaveType.Player);\n\t\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\tPriority = ThreadPriority.Lowest\n\t\t\t\t\t\t}.Start();\n\t\t\t\t\t}\n\t\t\t\t} else if (saveLock.Done) {\n\t\t\t\t\tsaving = false;\n\t\t\t\t\tindicator.HandleEvent(new SaveEndedEvent());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (credits != null && credits.Enabled) {\n\t\t\t\tif (lastCreditsLabel.Y <= Display.UiHeight * 0.75f) {\n\t\t\t\t\tif (!stopped) {\n\t\t\t\t\t\tstopped = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tgameSettings.Enabled = true;\n\n\t\t\t\t\t\t\tTween.To(Display.UiWidth * -2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\t\tcredits.Enabled = false;\n\t\t\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}, Input.IsDown(Controls.UiSelect, GamepadComponent.Current) ? 0.1f : 1f);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tstopped = false;\n\t\t\t\t\tcredits.RelativeY -= dt * 30 * (Input.IsDown(Controls.UiSelect, GamepadComponent.Current) ? 6 : 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar gamepad = GamepadComponent.Current;\n\n\t\t\tif (Died && Input.WasPressed(Controls.QuickRestart)) {\n\t\t\t\toverQuickBack?.OnClick();\n\t\t\t}\n\t\t\t\n\t\t\tif ((Paused || Died || Run.Won) && UiControl.Focused == null) {\n\t\t\t\tif (UiButton.SelectedInstance != null && (!UiButton.SelectedInstance.Active || !UiButton.SelectedInstance.IsOnScreen())) {\n\t\t\t\t\tUiButton.SelectedInstance = null;\n\t\t\t\t\tUiButton.Selected = -1;\n\t\t\t\t}\n\n\t\t\t\tvar inControl = (currentBack == gamepadBack && UiButton.SelectedInstance is UiControl) || currentBack == keyboardBack;\n\t\t\t\t\n\t\t\t\tif (UiButton.SelectedInstance == null && (Input.WasPressed(Controls.UiDown, gamepad, true) || Input.WasPressed(Controls.UiUp, gamepad, true) || (inControl && (Input.WasPressed(Controls.UiLeft, gamepad, true) || Input.WasPressed(Controls.UiRight, gamepad, true))))) {\n\t\t\t\t\tSelectFirst(true);\n\n\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t\t\t}\n\t\t\t\t} else if (UiButton.Selected > -1) {\n\t\t\t\t\tif (Input.WasPressed(Controls.UiDown, gamepad, true) || (inControl && Input.WasPressed(Controls.UiRight, gamepad, true))) {\n\t\t\t\t\t\tUiButton sm = null;\n\t\t\t\t\t\tvar mn = UiButton.LastId;\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var b in TopUi.Tagged[Tags.Button]) {\n\t\t\t\t\t\t\tvar bt = ((UiButton) b);\n\n\t\t\t\t\t\t\tif (bt.Active && bt.IsOnScreen() && bt.Id > UiButton.Selected && bt.Id < mn) {\n\t\t\t\t\t\t\t\tmn = bt.Id;\n\t\t\t\t\t\t\t\tsm = bt;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sm != null) {\n\t\t\t\t\t\t\tUiButton.SelectedInstance = sm;\n\t\t\t\t\t\t\tUiButton.Selected = sm.Id;\n\n\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar min = UiButton.Selected;\n\t\t\t\t\t\t\tUiButton btn = null;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tforeach (var b in TopUi.Tagged[Tags.Button]) {\n\t\t\t\t\t\t\t\tvar bt = ((UiButton) b);\n\n\t\t\t\t\t\t\t\tif (bt.Active && bt.IsOnScreen() && bt.Id < min) {\n\t\t\t\t\t\t\t\t\tbtn = bt;\n\t\t\t\t\t\t\t\t\tmin = bt.Id;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (btn != null) {\n\t\t\t\t\t\t\t\tUiButton.SelectedInstance = btn;\n\t\t\t\t\t\t\t\tUiButton.Selected = btn.Id;\n\n\t\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (Input.WasPressed(Controls.UiUp, gamepad, true) || (inControl && Input.WasPressed(Controls.UiLeft, gamepad, true))) {\n\t\t\t\t\t\tUiButton sm = null;\n\t\t\t\t\t\tvar mn = -1;\n\t\t\t\t\t\t\n\t\t\t\t\t\tforeach (var b in TopUi.Tagged[Tags.Button]) {\n\t\t\t\t\t\t\tvar bt = ((UiButton) b);\n\n\t\t\t\t\t\t\tif (bt.Active && bt.IsOnScreen() && bt.Id < UiButton.Selected && bt.Id > mn) {\n\t\t\t\t\t\t\t\tmn = bt.Id;\n\t\t\t\t\t\t\t\tsm = bt;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (sm != null) {\n\t\t\t\t\t\t\tUiButton.SelectedInstance = sm;\n\t\t\t\t\t\t\tUiButton.Selected = sm.Id;\n\n\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar max = -1;\n\t\t\t\t\t\t\tUiButton btn = null;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tforeach (var b in TopUi.Tagged[Tags.Button]) {\n\t\t\t\t\t\t\t\tvar bt = ((UiButton) b);\n\n\t\t\t\t\t\t\t\tif (bt.Active && bt.IsOnScreen() && bt.Id > max) {\n\t\t\t\t\t\t\t\t\tbtn = bt;\n\t\t\t\t\t\t\t\t\tmax = bt.Id;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (btn != null) {\n\t\t\t\t\t\t\t\tUiButton.SelectedInstance = btn;\n\t\t\t\t\t\t\t\tUiButton.Selected = btn.Id;\n\n\t\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!Paused) {\n\t\t\t\tt += dt;\n\t\t\t\tWeather.Update(dt);\n\n\t\t\t\tif (Run.Depth == 0) {\n\t\t\t\t\tvar night = Weather.IsNight;\n\n\t\t\t\t\tif (Events.Halloween) {\n\t\t\t\t\t\tnight = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (night != wasNight) {\n\t\t\t\t\t\twasNight = night;\n\t\t\t\t\t\tvar v = night ? 0.25f : 0.9f;\n\n\t\t\t\t\t\tTween.To(v, Lights.ClearColor.R / 255f, x => { Lights.ClearColor = new Color(x, x, x, 1f); }, 10f);\n\t\t\t\t\t}\n\n\t\t\t\t\tvar raining = Weather.Rains || Weather.Snows;\n\n\t\t\t\t\tif (wasRaining != raining) {\n\t\t\t\t\t\twasRaining = raining;\n\n\t\t\t\t\t\tif (raining) {\n\t\t\t\t\t\t\tSetupParticles();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tforeach (var p in particles) {\n\t\t\t\t\t\t\t\tif (p is RainParticle r) {\n\t\t\t\t\t\t\t\t\tr.End = true;\n\t\t\t\t\t\t\t\t} else if (p is SnowParticle s) {\n\t\t\t\t\t\t\t\t\ts.End = true;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tp.Done = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tparticles.Clear();\n\n\t\t\t\t\t\t\tif (rainSound != null) {\n\t\t\t\t\t\t\t\tvar ss = rainSound;\n\t\t\t\t\t\t\t\tTween.To(0, ss.Volume, x => ss.Volume = x, 3f);\n\t\t\t\t\t\t\t\trainSound = null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar inside = Engine.GraphicsDevice.Viewport.Bounds.Contains(Input.Mouse.CurrentState.Position);\n\t\t\t\n\t\t\tShaders.Screen.Parameters[\"split\"].SetValue(Engine.Instance.Split);\n\t\t\tShaders.Screen.Parameters[\"blur\"].SetValue(blur);\n\n\t\t\tif (DialogComponent.Talking == null) {\n\t\t\t\tif (!Paused && t >= 1f && !inside && Settings.Autopause && !Menu) {\n\t\t\t\t\tPaused = true;\n\t\t\t\t}/* else if (Paused && pausedByMouseOut && inside) {\n\t\t\t\t\tPaused = false;\n\t\t\t\t}*/\n\t\t\t}\n\n\t\t\tif (Menu && !menuExited) {\n\t\t\t\tif (Input.WasPressed(Controls.GameStart, GamepadComponent.Current, true)) {\n\t\t\t\t\tmenuExited = true;\n\t\t\t\t\tInMenu = false;\n\t\t\t\t\tInput.Blocked = 0;\n\n\t\t\t\t\tAudio.PlaySfx(\"ui_start\");\n\t\t\t\t\tAudio.PlayMusic(\"Hub\", true);\n\n\t\t\t\t\tCloseBlackBars();\n\n\t\t\t\t\tTween.To(this, new {blur = 0}, 0.5f).OnEnd = () => {\n\t\t\t\t\t\tforeach (var e in TopUi.Tagged[Tags.Cursor]) {\n\t\t\t\t\t\t\tCamera.Instance.Follow(e, CursorPriority);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tCamera.Instance.Detached = false;\n\t\t\t\t\tTween.To(-Display.UiHeight, offset, x => offset = x, 0.5f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\t\tMenu = false;\n\n\t\t\t\t\t\tTimer.Add(() => {\n\t\t\t\t\t\t\tforeach (var n in Area.Tagged[Tags.Npc]) {\n\t\t\t\t\t\t\t\tif (n is OldMan m) {\n\t\t\t\t\t\t\t\t\tm.GetComponent<DialogComponent>().StartAndClose(\"shopkeeper_6\", 3);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 0.5f);\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!Paused) {\n\t\t\t\tif (!Died && !Run.Won && Run.Depth > 0) {\n\t\t\t\t\tRun.Time = (float) (timeWas + (Engine.GameTime.TotalGameTime.TotalSeconds - startTime));\n\t\t\t\t} else {\n\t\t\t\t\tCaptureTime();\n\t\t\t\t}\n\n\t\t\t\tvar d = PlayerInputComponent.EnableUpdates ? dt : 0;\n\n\t\t\t\tPhysics.Update(d);\n\t\t\t\tbase.Update(d);\n\t\t\t} else {\n\t\t\t\tUi.Update(dt);\n\t\t\t}\n\t\t\t\n\t\t\tConsole?.Update(dt);\n\n\t\t\tvar controller = GamepadComponent.Current;\n\t\t\t\n\t\t\tif (painting != null) {\n\t\t\t\tif (Input.WasPressed(Controls.Pause, controller) || Input.WasPressed(Controls.Interact, controller) ||\n\t\t\t\t    Input.WasPressed(Controls.Use, controller)) {\n\t\t\t\t\tpainting.Remove();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (doCheck) {\n\t\t\t\t\tif (UiControl.Focused != null) {\n\t\t\t\t\t\tUiControl.Focused.DoCheck();\n\n\t\t\t\t\t\tif (UiControl.Focused != null) {\n\t\t\t\t\t\t\tUiControl.Focused.Cancel();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tdoCheck = false;\n\t\t\t\t}\n\n\t\t\t\tif (doneAnimatingPause) {\n\t\t\t\t\tvar did = false;\n\n\t\t\t\t\tif (DialogComponent.Talking == null) {\n\t\t\t\t\t\tif (!(animating) && Input.WasPressed(Controls.Pause, controller)) {\n\t\t\t\t\t\t\tif (SkipPause) {\n\t\t\t\t\t\t\t\tSkipPause = false;\n\t\t\t\t\t\t\t} else if (Paused) {\n\t\t\t\t\t\t\t\tif (UiControl.Focused == null && currentBack == null) {\n\t\t\t\t\t\t\t\t\tPaused = false;\n\t\t\t\t\t\t\t\t\tdid = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (!Menu) {\n\t\t\t\t\t\t\t\tPaused = true;\n\t\t\t\t\t\t\t\tdid = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!did && (Paused || Died || Run.Won) && Input.WasPressed(Controls.UiBack, controller)) {\n\t\t\t\t\t\t\tif (Settings.UiSfx) {\n\t\t\t\t\t\t\t\tAudio.PlaySfx(\"ui_exit\", 0.5f);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (UiControl.Focused != null) {\n\t\t\t\t\t\t\t\tdoCheck = true;\n\t\t\t\t\t\t\t} else if (currentBack != null) {\n\t\t\t\t\t\t\t\tcurrentBack.Click(currentBack);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tPaused = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t#if DEBUG\n\t\t\t\tUpdateDebug(dt);\n\t\t\t\tTilesets.Update();\n\t\t\t#endif\n\n\t\t\tRun.Update();\n\t\t\t\n\t\t\tif (Input.WasPressed(Controls.Fullscreen) || (Input.Keyboard.WasPressed(Keys.Enter) && (Input.Keyboard.IsDown(Keys.LeftAlt) || Input.Keyboard.IsDown(Keys.RightAlt)))) {\n\t\t\t\tif (Engine.Graphics.IsFullScreen) {\n\t\t\t\t\tEngine.Instance.SetWindowed(Display.Width * 3, Display.Height * 3);\n\t\t\t\t} else {\n\t\t\t\t\tEngine.Instance.SetFullscreen();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSettings.Fullscreen = Engine.Graphics.IsFullScreen;\n\t\t\t}\n\n\t\t\tTopUi.Update(dt);\n\t\t}\n\n\t\tprivate bool saving;\n\t\t\n\t\tprivate void TeleportTo(RoomType type) {\n\t\t\tvar player = LocalPlayer.Locate(Area);\n\t\t\tvar room = player.GetComponent<RoomComponent>().Room;\n\n\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\n\t\t\t\tif (r != room && ((Room) r).Type == type) {\n\t\t\t\t\tplayer.Center = r.Center;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static bool ToolsEnabled = BK.Version.Dev;\n\t\t\n\t\tprivate void UpdateDebug(float dt) {\n\t\t\tif (BK.Version.Dev && Assets.ImGuiEnabled && ((Input.Keyboard.WasPressed(Keys.Tab) && Input.Keyboard.IsDown(Keys.LeftControl)))) {\n\t\t\t\tToolsEnabled = !ToolsEnabled;\n\t\t\t\tvar player = LocalPlayer.Locate(Area);\n\n\t\t\t\tif (player != null) {\n\t\t\t\t\tTextParticle.Add(player, \"Dev Tools\", 1, true, !ToolsEnabled);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!ToolsEnabled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Input.Blocked > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.Insert)) {\n\t\t\t\tSaveManager.Delete(SaveType.Game, SaveType.Level, SaveType.Player);\n\t\t\t\tRun.StartNew(1, Run.Type);\n\t\t\t\tDied = true;\n\n\t\t\t\tRun.NextDepth = Run.Depth;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftControl)) {\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D0)) {\n\t\t\t\t\tRun.Depth = 0;\n\t\t\t\t\t\n\t\t\t\t\tif (Run.Statistics != null) {\n\t\t\t\t\t\tRun.Statistics.Done = true;\n\t\t\t\t\t\tRun.Statistics = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D1)) {\n\t\t\t\t\tRun.Depth = 1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D2)) {\n\t\t\t\t\tRun.Depth = 3;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D3)) {\n\t\t\t\t\tRun.Depth = 5;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D4)) {\n\t\t\t\t\tRun.Depth = 7;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D5)) {\n\t\t\t\t\tRun.Depth = 9;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D6)) {\n\t\t\t\t\tRun.Depth = 11;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftAlt)) {\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D1)) {\n\t\t\t\t\tRun.Depth = 2;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D2)) {\n\t\t\t\t\tRun.Depth = 4;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D3)) {\n\t\t\t\t\tRun.Depth = 6;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D4)) {\n\t\t\t\t\tRun.Depth = 8;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D5)) {\n\t\t\t\t\tRun.Depth = 10;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D6)) {\n\t\t\t\t\tRun.Depth = 11;\n\t\t\t\t\tPlayer.ToBoss = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Input.WasPressed(Controls.Fps)) {\n\t\t\t\tSettings.ShowFps = !Settings.ShowFps;\n\t\t\t}\n\t\t\t\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F3)) {\n\t\t\t\tSettings.HideUi = !Settings.HideUi;\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F4)) {\n\t\t\t\tSettings.HideCursor = !Settings.HideCursor;\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F5)) {\n\t\t\t\tTeleportTo(RoomType.Treasure);\n\t\t\t}\n\t\t\t\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F6)) {\n\t\t\t\tTeleportTo(RoomType.Shop);\n\t\t\t}\n\t\t\t\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F7)) {\n\t\t\t\tTeleportTo(RoomType.Special);\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F8)) {\n\t\t\t\tTeleportTo(RoomType.Secret);\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F9)) {\n\t\t\t\tTeleportTo(RoomType.Boss);\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.NumPad7) || Input.Keyboard.WasPressed(Keys.Home)) {\n\t\t\t\tvar p = LocalPlayer.Locate(Area);\n\t\t\t\tp.Center = p.GetComponent<CursorComponent>().Cursor.GamePosition;\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.PageUp)) {\n\t\t\t\tvar level = Run.Level;\n\n\t\t\t\tfor (var i = 0; i < level.Explored.Length; i++) {\n\t\t\t\t\tlevel.Explored[i] = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.NumPad1)) {\n\t\t\t\tGlobalSave.ResetControlKnowldge();\n\t\t\t}\n\n\t\t\tif (Input.Keyboard.WasPressed(Keys.PageDown)) {\n\t\t\t\tCamera.Instance.Detached = !Camera.Instance.Detached;\n\n\t\t\t\tif (!Camera.Instance.Detached) {\n\t\t\t\t\tResetFollowing();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Camera.Instance.Detached) {\n\t\t\t\tfloat speed = dt * 120f;\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad4)) {\n\t\t\t\t\tCamera.Instance.PositionX -= speed;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad6)) {\n\t\t\t\t\tCamera.Instance.PositionX += speed;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad8)) {\n\t\t\t\t\tCamera.Instance.PositionY -= speed;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Input.Keyboard.IsDown(Keys.NumPad2)) {\n\t\t\t\t\tCamera.Instance.PositionY += speed;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void PrerenderShadows() {\n\t\t\tvar renderer = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\t\t\t\n\t\t\trenderer.End();\n\t\t\t\n\t\t\tvar c = Camera.Instance;\n\t\t\tvar z = c.Zoom;\n\t\t\tvar n = Math.Abs(z - 1) > 0.01f;\n\t\t\t\t\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = 1;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\t\t\t\n\t\t\trenderer.BeginShadows();\n\n\t\t\tforeach (var e in Area.Tagged[Tags.HasShadow]) {\n\t\t\t\tif (!e.Done && (e.AlwaysVisible || e.OnScreen)) {\n\t\t\t\t\te.GetComponent<ShadowComponent>().Callback();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\trenderer.EndShadows();\n\n\t\t\tif (n) {\n\t\t\t\tc.Zoom = z;\n\t\t\t\tc.UpdateMatrices();\n\t\t\t}\n\t\t\t\n\t\t\trenderer.Begin();\n\t\t}\n\t\t\n\t\tpublic static void RenderFog() {\n\t\t\tvar shader = Shaders.Fog;\n\t\t\tShaders.Begin(shader);\n\n\t\t\tvar wind = WindFx.CalculateWind();\n\t\t\t\n\t\t\tshader.Parameters[\"time\"].SetValue(Engine.Time * 0.01f);\n\t\t\tshader.Parameters[\"tx\"].SetValue(wind.X * -0.1f);\n\t\t\tshader.Parameters[\"ty\"].SetValue(wind.Y * -0.1f);\n\t\t\tshader.Parameters[\"cx\"].SetValue(Camera.Instance.Position.X / 512f);\n\t\t\tshader.Parameters[\"cy\"].SetValue(Camera.Instance.Position.Y / 512f);\n\t\t\n\t\t\tGraphics.Render(fog, Camera.Instance.TopLeft);\n\t\t\t\n\t\t\tShaders.End();\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tPrerenderShadows();\n\t\t\tbase.Render();\n\t\t\tPhysics.Render();\n\t\t\teditor?.RenderInGame();\n\t\t\t\n\t\t\tif (RenderDebug) {\n\t\t\t\tUi?.RenderDebug();\n\t\t\t\tTopUi?.RenderDebug();\n\t\t\t}\n\t\t}\n\n\t\tprivate float emeraldY = -20;\n\t\t\n\t\tpublic override void RenderUi() {\n\t\t\tbase.RenderUi();\n\t\t\t\n\t\t\tif (!Settings.HideUi) {\n\t\t\t\tif (Run.Depth == 0 || emeraldY > -20) {\n\t\t\t\t\tvar y = Run.Depth == 0 ? 0 : emeraldY;\n\t\t\t\t\tvar str = $\"{GlobalSave.Emeralds}\";\n\t\t\t\t\tvar xx = Display.UiWidth - emerald.Width - 8;\n\n\t\t\t\t\tGraphics.Render(emerald, new Vector2(xx, 8 + y));\n\t\t\t\t\tGraphics.Print(str, Font.Small, new Vector2(xx - 8 - Font.Small.MeasureString(str).Width, 9 + y));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (blackBarsSize > 0.01f) {\n\t\t\t\tGraphics.Render(black, Vector2.Zero, 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, blackBarsSize));\n\t\t\t\tGraphics.Render(black, new Vector2(0, Display.UiHeight + 1 - blackBarsSize), 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, blackBarsSize + 1));\n\t\t\t}\n\n\t\t\tpainting?.RenderUi();\n\n\t\t\tTopUi.Render();\n\n\t\t\tif (Settings.HideUi) {\n\t\t\t\tforeach (var e in TopUi.Tagged[Tags.Cursor]) {\n\t\t\t\t\te.Render();\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Menu && offset <= Display.UiHeight) {\n\t\t\t\tGraphics.Render(black, new Vector2(0, offset - Display.UiHeight), 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, Display.UiHeight + 1));\n\t\t\t\tGraphics.Render(gardient, new Vector2(0, offset), 0, Vector2.Zero, new Vector2(Display.UiWidth + 1, (Display.UiHeight + 1) / 90f));\n\t\t\t\t\n\t\t\t\tGraphics.Print(\"Press X\", Font.Small, Display.Height + 48 + (int) offset);\n\t\t\t\t\n\t\t\t\tLogoRenderer.Render(offset);\n\t\t\t}\n\n\t\t\tvar x = 1;\n\t\t\t\n\t\t\tif (Settings.ShowFps) {\n\t\t\t\tvar c = Engine.Instance.Counter.AverageFramesPerSecond;\n\t\t\t\tColor color;\n\n\t\t\t\tif (c >= 55) {\n\t\t\t\t\tcolor = new Color(0f, 1f, 0f, 1f);\n\t\t\t\t} else if (c >= 45) {\n\t\t\t\t\tcolor = new Color(1f, 1f, 0f, 1f);\n\t\t\t\t} else {\n\t\t\t\t\tcolor = new Color(1f, 0f, 0f, 1f);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Color = color;\n\t\t\t\tvar s = $\"{c}\";\n\t\t\t\tGraphics.Print(s, Font.Small, x, 1);\n\t\t\t\tx += (int) Font.Small.MeasureString(s).Width + 1;\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t}\n\n\t\t\tif (Settings.SpeedrunTimer) {\n\t\t\t\tGraphics.Print(GetRunTime(), Font.Small, x, 1);\n\t\t\t}\n\n\t\t\t// Graphics.Batch.DrawString(Font.Test, \"Test 你 Test\", Vector2.One, Color.White);\n\t\t\t\n\t\t\tif (RenderDebug) {\n\t\t\t\tUi?.RenderDebug();\n\t\t\t\tTopUi?.RenderDebug();\n\t\t\t}\n\t\t}\n\n\t\tprivate string GetRunTime() {\n\t\t\tvar t = Run.Time;\n\t\t\treturn $\"{(Math.Floor(t / 3600f) + \"\").PadLeft(2, '0')}:{(Math.Floor(t / 60f % 60f) + \"\").PadLeft(2, '0')}:{(Math.Floor(t % 60f) + \"\").PadLeft(2, '0')}\";\n\t\t}\n\n\t\tprivate UiLabel loading;\n\t\tprivate UiChoice choice;\n\t\tprivate UiTable leaderStats;\n\t\tprivate UiTable statsStats;\n\t\tprivate Action<string> d;\n\t\tprivate List<UiItem> inventoryItems = new List<UiItem>();\n\n\t\tpublic void GoToInventory() {\n\t\t\tcurrentBack = inventoryBack;\n\t\t\tinventory.Enabled = true;\n\t\t\tSetupInventory();\n\n\t\t\tTween.To(-Display.UiHeight, pauseMenu.Y, x => pauseMenu.Y = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\tpauseMenu.Enabled = false;\n\t\t\t\tSelectFirst();\n\t\t\t};\n\t\t}\n\n\t\tprivate string GetScore() {\n\t\t\tRun.CalculateScore();\n\t\t\treturn $\"{Run.Score}\".PadLeft(7, '0');\n\t\t}\n\n\t\tpublic Action OnPauseCallback;\n\t\tprivate UiMap map;\n\t\tprivate UiLabel scoreLabel;\n\t\tprivate UiLabel boardType;\n\n\t\tprivate void SetupUi() {\n\t\t\tTopUi.Add(new UiChat());\n\t\t\t\n\t\t\tUiButton.LastId = 0;\n\t\t\t\n\t\t\tvar cam = new Camera(new FollowingDriver());\n\t\t\tTopUi.Add(cam);\n\t\t\t// Ui.Add(new AchievementBanner());\n\n\t\t\tif (Assets.ImGuiEnabled) {\n\t\t\t\teditor = new EditorWindow(new Editor {\n\t\t\t\t\tArea = Area,\n\t\t\t\t\tLevel = Run.Level,\n\t\t\t\t\tCamera = cam\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar id = Run.Level.Biome.Id;\n\n\t\t\tif (id != Biome.Castle && id != Biome.Hub) {\n\t\t\t\tAchievements.Unlock($\"bk:{id}\");\n\t\t\t\tvar i = Run.Level.Biome.GetItemUnlock();\n\n\t\t\t\tif (i != null) {\n\t\t\t\t\tItems.Unlock(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tvar cursor = new Cursor {\n\t\t\t\t\tPlayer = (Player) p\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tTopUi.Add(cursor);\n\t\t\t\tp.GetComponent<CursorComponent>().Cursor = cursor;\n\t\t\t}\n\t\t\t\n\t\t\tUi.Add(indicator = new SaveIndicator());\n\n\t\t\tvar player = LocalPlayer.Locate(Area);\n\n\t\t\tif (!Multiplayer && Run.Depth > 0) {\n\t\t\t\tUi.Add(map = new UiMap(player));\n\t\t\t}\t\n\t\t\t\n\t\t\tif (Assets.ImGuiEnabled) {\n\t\t\t\tConsole = new Console(Area);\n\t\t\t}\n\n\t\t\tforeach (var p in Area.Tagged[Tags.Player]) {\n\t\t\t\tUi.Add(new UiInventory((Player) p, Multiplayer));\n\t\t\t}\n\n\t\t\tTopUi.Add(pauseMenu = new UiPane {\n\t\t\t\tY = -Display.UiHeight\t\n\t\t\t});\n\t\t\t\n\t\t\tTopUi.Add(leaderMenu = new UiPane());\n\n\t\t\tvar space = 24f;\n\t\t\tvar start = Display.UiHeight * 0.5f + (Run.Depth > 0 ? -space * 0.5f : space);\n\n\t\t\tpauseMenu.Add(new UiLabel {\n\t\t\t\tLabel = Level.GetDepthString(),\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false,\n\t\t\t\tAngleMod = 0\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiLabel {\n\t\t\t\tFont = Font.Small,\n\t\t\t\tLabel = BK.Version.ToString(),\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = TitleY + 12,\n\t\t\t\tClickable = false,\n\t\t\t\tAngleMod = 0\n\t\t\t});\n\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tscoreLabel = (UiLabel) pauseMenu.Add(new UiLabel {\n\t\t\t\t\tFont = Font.Small,\n\t\t\t\t\tLabel = GetScore(),\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = TitleY + 24,\n\t\t\t\t\tClickable = false,\n\t\t\t\t\tAngleMod = 0\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\tpauseMenu.Add(seedLabel = new UiButton {\n\t\t\t\t\tFont = Font.Small,\n\t\t\t\t\tSelectable = false,\n\t\t\t\t\tLabel = $\"Seed: {Run.Seed}\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\t\tAngleMod = 0,\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tb.LocaleLabel = \"copied_to_clipboard\";\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Needs xclip on linux\n\t\t\t\t\t\t\tTextCopy.Clipboard.SetText(Run.Seed);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tTimer.Add(() => { b.Label = $\"{Locale.Get(\"seed\")}: {Run.Seed}\"; }, 0.5f);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tpauseBack = currentBack = (UiButton) pauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"resume\",\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = start - space,\n\t\t\t\tClick = b => Paused = false\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"settings\",\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = start,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tif (Run.Depth > 0) {\n\t\t\t\n\t\t\t\n\t\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\t\tLocaleLabel = \"inventory\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = start + space,\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tGoToInventory();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\n\t\t\t\tpauseMenu.Add(inventory = new UiPane {\n\t\t\t\t\tRelativeY = Display.UiHeight\n\t\t\t\t});\n\n\t\t\t\tvar sx = Display.UiWidth * 0.5f;\n\n\t\t\t\tinventory.Add(new UiLabel {\n\t\t\t\t\tLocaleLabel = \"inventory\",\n\t\t\t\t\tRelativeCenterX = sx,\n\t\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\t\tClickable = false\n\t\t\t\t});\n\t\t\t\n\t\t\t\tinventoryBack = (UiButton) inventory.Add(new UiButton {\n\t\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\t\tType = ButtonType.Exit,\n\t\t\t\t\tRelativeCenterX = sx,\n\t\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tcurrentBack = pauseBack;\n\t\t\t\t\t\tpauseMenu.Enabled = true;\n\t\t\t\t\t\n\t\t\t\t\t\tTween.To(0, pauseMenu.Y, x => pauseMenu.Y = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\t\tinventory.Enabled = false;\n\n\t\t\t\t\t\t\tforeach (var i in inventoryItems) {\n\t\t\t\t\t\t\t\ti.Done = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tinventoryItems.Clear();\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\n\t\t\t\tinventory.Enabled = false;\n\t\t\t\n\t\t\t\tif (Run.Type != RunType.Daily) {\n\t\t\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\t\t\tLocaleLabel = \"new_run\",\n\t\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\t\tRelativeCenterY = start + space * 2,\n\t\t\t\t\t\tType = ButtonType.Exit,\n\t\t\t\t\t\tClick = b => GoConfirm(\"start_new_run\", () => { Run.StartNew(); }, () => {\n\t\t\t\t\t\t\tcurrentBack = pauseBack;\n\t\t\t\t\t\t\tpauseMenu.Enabled = true;\n\n\t\t\t\t\t\t\tTween.To(0, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\t\tpauseMenu.Remove(confirmationPane);\n\t\t\t\t\t\t\t\tconfirmationPane = null;\n\t\t\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t})\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (Run.Depth == 0) {\n\t\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\t\tLocaleLabel = \"exit\",\n\t\t\t\t\tType = ButtonType.Exit,\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tEngine.Instance.Quit();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (Run.Depth != 0) {\n\t\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\t\tLocaleLabel = \"back_to_town\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = start + space * 3,\n\t\t\t\t\tType = ButtonType.Exit,\n\t\t\t\t\tClick = b => Run.Depth = 0\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tAddSettings();\n\t\t\t\n\t\t\tpauseMenu.Setup();\n\t\t\t\n\t\t\tTopUi.Add(gameOverMenu = new UiPane {\n\t\t\t\tY = -Display.UiHeight\n\t\t\t});\n\t\t\t\n\t\t\tspace = 20f;\n\t\t\tstart = (Display.UiHeight) / 2f - space;\n\n\t\t\tkilledLabel = (UiLabel) gameOverMenu.Add(new UiLabel {\n\t\t\t\tFont = Font.Small,\n\t\t\t\tLocaleLabel = \"killed_by\",\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.75f,\n\t\t\t\tRelativeCenterY = start - space,\n\t\t\t\tTints = false,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tKiller = (UiAnimation) gameOverMenu.Add(new UiAnimation {\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.75f,\n\t\t\t\tRelativeY = start,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tvar qr = Run.Depth > 0 && (Run.Type == RunType.Regular || Run.Type == RunType.Twitch || Run.Type == RunType.Challenge || Run.Type == RunType.BossRush);\n\t\t\t\n\t\t\tif (qr) {\n\t\t\t\tgameOverMenu.Add(overQuickBack = new UiButton {\n\t\t\t\t\tFont = Font.Small,\n\t\t\t\t\tLocaleLabel = \"quick_restart\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\t\tRelativeCenterY = BackY - 6,\n\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tif (Run.Type == RunType.BossRush) {\n\t\t\t\t\t\t\tif (GlobalSave.Emeralds < 3) {\n\t\t\t\t\t\t\t\tAnimationUtil.ActionFailed();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tGlobalSave.Emeralds -= 3;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgameOverMenu.Enabled = false;\n\t\t\t\t\t\tRun.StartNew(1, Run.Type);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tgameOverMenu.Add(overBack = new UiButton {\n\t\t\t\tLocaleLabel = \"back_to_town\",\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = BackY + (qr ? 12 : 0),\n\n\t\t\t\tClick = b => {\n\t\t\t\t\tgameOverMenu.Enabled = false;\n\t\t\t\t\tRun.StartNew(Run.Depth == -2 ? -2 : 0);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgameOverMenu.Setup();\n\t\t\tgameOverMenu.Enabled = false;\n\n\t\t\tif (Run.Depth > 0 && Run.Level != null && !Menu) {\n\t\t\t\tUi.Add(new UiBanner(Level.GetDepthString()));\n\t\t\t}\n\t\t\t\n\t\t\tleaderMenu.Add(boardType = new UiLabel {\n\t\t\t\tLabel = $\"{Locale.Get($\"run_{Run.Type.ToString().ToLower()}\")} {Locale.Get(\"leaderboard\")}\",\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tleaderStats = new UiTable();\n\t\t\tleaderMenu.Add(leaderStats);\n\n\t\t\tif (SetupLeaderboard == null) {\n\t\t\t\tleaderStats.Add(\"No steam no leaderboards\", \":(\");\n\t\t\t\tleaderStats.Prepare();\n\n\t\t\t\tleaderStats.RelativeCenterX = Display.UiWidth * 0.5f;\n\t\t\t\tleaderStats.RelativeCenterY = Display.UiHeight * 0.5f;\n\t\t\t} else {\n\t\t\t\tloading = (UiLabel) leaderMenu.Add(new UiLabel {\n\t\t\t\t\tLocaleLabel = \"loading\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\t\tRelativeCenterY = Display.UiHeight * 0.5f,\n\t\t\t\t\tClickable = false,\n\t\t\t\t\tHide = true\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tvar offset = 0;\n\t\t\t\tstring lastS = null;\n\t\t\t\t\n\t\t\t\td = (s) =>{\n\t\t\t\t\tif (s == null) {\n\t\t\t\t\t\ts = lastS ?? Run.GetLeaderboardId();\n\t\t\t\t\t}\n\n\t\t\t\t\tlastS = s;\n\t\t\t\t\t\n\t\t\t\t\tloading.Hide = false;\n\t\t\t\t\tchoice.Disabled = true;\n\t\t\t\t\t\n\t\t\t\t\tleaderStats.Clear();\n\t\t\t\t\toffset = Math.Max(0, offset);\n\n\t\t\t\t\tSetupLeaderboard(leaderStats, s, choice.Options[choice.Option], offset, () => {\n\t\t\t\t\t\tleaderStats.Prepare();\n\n\t\t\t\t\t\tleaderStats.RelativeCenterX = Display.UiWidth * 0.5f;\n\t\t\t\t\t\tleaderStats.RelativeCenterY = Display.UiHeight * 0.5f;\n\t\t\t\t\t\t\n\t\t\t\t\t\tloading.Hide = true;\n\t\t\t\t\t\tchoice.Disabled = false;\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tleaderMenu.Add(new UiButton {\n\t\t\t\t\tLabel = \"-\",\n\t\t\t\t\tXPadding = 4,\n\t\t\t\t\tSelectable = false,\n\t\t\t\t\tRelativeX = Display.UiWidth * 0.5f - 10,\n\t\t\t\t\tRelativeCenterY = BackY - 25,\n\t\t\t\t\tType = ButtonType.Slider,\n\t\t\t\t\tClick = bt => {\n\t\t\t\t\t\toffset = Math.Max(0, offset - 10);\n\t\t\t\t\t\td(null);\n\t\t\t\t\t},\n\t\t\t\t\tScaleMod = 3\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tleaderMenu.Add(new UiButton {\n\t\t\t\t\tLabel = \"+\",\n\t\t\t\t\tXPadding = 4,\n\t\t\t\t\tSelectable = false,\n\t\t\t\t\tRelativeX = Display.UiWidth * 0.5f + 10,\n\t\t\t\t\tRelativeCenterY = BackY - 25,\n\t\t\t\t\tType = ButtonType.Slider,\n\t\t\t\t\tClick = bt => {\n\t\t\t\t\t\toffset += 10;\n\t\t\t\t\t\td(null);\n\t\t\t\t\t},\n\t\t\t\t\tScaleMod = 3\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tleaderMenu.Add(choice = new UiChoice {\n\t\t\t\t\tFont = Font.Small,\n\t\t\t\t\tName = \"display\",\n\t\t\t\t\tOptions = new [] {\n\t\t\t\t\t\t\"global\", \"around_you\", \"friends\"\n\t\t\t\t\t},\n\t\t\t\t\n\t\t\t\t\tOption = 0,\n\t\t\t\t\tClick = c => {\n\t\t\t\t\t\toffset = 0;\n\t\t\t\t\t\td(null);\n\t\t\t\t\t},\n\t\t\t\t\tRelativeX = Display.UiWidth * 0.5f,\n\t\t\t\t\tRelativeCenterY = TitleY + 12\n\t\t\t\t});\n\t\t\t}\n\t\t\t\t\n\t\t\tleaderMenu.Add(leaderBack = new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = bt => {\n\t\t\t\t\tHideLeaderboard();\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tleaderMenu.Enabled = false;\n\t\t\tleaderMenu.Y = Display.UiHeight * 2;\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tTopUi.Add(statsMenu = new UiPane());\n\t\t\t\t\n\t\t\t\tplaceLabel = (UiLabel) statsMenu.Add(new UiLabel {\n\t\t\t\t\tLabel = \"404\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\t\tClickable = false\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\tstatsMenu.Add(statsBack = new UiButton {\n\t\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\t\tClick = bt => {\n\t\t\t\t\t\tHideStats();\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tstatsStats = new UiTable();\n\t\t\t\tstatsMenu.Add(statsStats);\n\n\t\t\t\tstatsStats.Prepare();\n\n\t\t\t\tstatsStats.RelativeCenterX = Display.UiWidth * 0.5f;\n\t\t\t\tstatsStats.RelativeCenterY = Display.UiHeight * 0.5f;\n\t\t\t\t\n\t\t\t\tstatsMenu.Enabled = false;\n\t\t\t\tstatsMenu.Y = Display.UiHeight * 2;\n\t\t\t}\n\t\t}\n\n\t\tprivate UiLabel lastCreditsLabel;\n\n\t\tprivate void SetupCredits() {\n\t\t\tif (credits != null) {\n\t\t\t\tcredits.RelativeY = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tpauseMenu.Add(credits = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 3\n\t\t\t});\n\t\t\t\n\t\t\tvar y = TitleY + 128;\n\t\t\tvar count = Credits.Text.Count;\n\t\t\tlastCreditsLabel = null;\n\t\t\t\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar text = Credits.Text[i];\n\t\t\t\t\n\t\t\t\tforeach (var s in text) {\n\t\t\t\t\tlastCreditsLabel = (UiLabel) credits.Add(new UiLabel {\n\t\t\t\t\t\tFont = Font.Medium,\n\t\t\t\t\t\tLabel = s,\n\t\t\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\t\t\tRelativeCenterY = y,\n\t\t\t\t\t\tTints = false,\n\t\t\t\t\t\tClickable = false\n\t\t\t\t\t});\n\n\t\t\t\t\ty += 12f;\n\t\t\t\t}\n\n\t\t\t\ty += 24f;\n\t\t\t}\n\n\t\t\tcredits.Setup();\n\t\t\tcredits.Enabled = false;\n\t\t}\n\n\t\tprivate void SetupInventory() {\n\t\t\tvar player = LocalPlayer.Locate(Area);\n\n\t\t\tif (player == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar iv = player.GetComponent<InventoryComponent>();\n\t\t\tvar offset = Math.Min(iv.Items.Count, 10) * 24 * 0.5f; \n\n\t\t\tfor (var i = 0; i < iv.Items.Count; i++) {\n\t\t\t\tvar item = new UiItem();\n\t\t\t\tvar it = iv.Items[i];\n\t\t\t\t\n\t\t\t\titem.Id = it.Id;\n\t\t\t\titem.Scourged = it.Scourged;\n\n\t\t\t\titem.RelativeCenterX = Display.UiWidth * 0.5f - offset + i % 10 * 24;\n\t\t\t\titem.RelativeY = 72 + (float) Math.Floor(i / 10f) * 24;\n\n\t\t\t\tinventory.Add(item);\n\t\t\t\tinventoryItems.Add(item);\n\t\t\t}\n\t\t}\n\n\t\tprivate void AddSettings() {\n\t\t\tvar sx = Display.UiWidth * 1.5f;\n\t\t\tvar space = 24f;\n\t\t\tvar sy = Display.UiHeight * 0.5f - space;\n\t\t\t\n\t\t\tpauseMenu.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"settings\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"game\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = gameBack;\n\t\t\t\t\tgameSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"graphics\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = graphicsBack;\n\t\t\t\t\tgraphicsSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"audio\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = audioBack;\n\t\t\t\t\taudioSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"input\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 2,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = inputBack;\n\t\t\t\t\tinputSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"language\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 3,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = languageBack;\n\t\t\t\t\tlanguageSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = SelectFirst;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tsettingsBack = (UiButton) pauseMenu.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tnew Thread(() => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tSaveManager.Save(Area, SaveType.Global);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}) {\n\t\t\t\t\t\tPriority = ThreadPriority.Lowest\n\t\t\t\t\t}.Start();\n\t\t\t\t\t\n\t\t\t\t\tcurrentBack = pauseBack;\n\t\t\t\t\tpauseMenu.Enabled = true;\n\t\t\t\t\t\n\t\t\t\t\tTween.To(0, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tpauseMenu.Enabled = false;\n\t\t\t\n\t\t\tAddGameSettings();\n\t\t\tAddGraphicsSettings();\n\t\t\tAddAudioSettings();\n\t\t\tAddInputSettings();\n\t\t\tAddLanguageSettings();\n\t\t}\n\n\t\tprivate UiButton pauseBack;\n\t\tprivate UiButton settingsBack;\n\t\tprivate UiButton audioBack;\n\t\tprivate UiButton graphicsBack;\n\t\tprivate UiButton gameBack;\n\t\tprivate UiButton overBack;\n\t\tprivate UiButton overQuickBack;\n\t\tprivate UiButton leaderBack;\n\t\tprivate UiButton inventoryBack;\n\t\tprivate UiButton statsBack;\n\n\t\tprivate void AddGameSettings() {\n\t\t\tpauseMenu.Add(gameSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 2\t\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 18f;\n\t\t\tvar sy = Display.UiHeight * 0.5f - space * 1.5f - 10;\n\t\t\t\n\t\t\tgameSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"game\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"autosave\",\n\t\t\t\tOn = Settings.Autosave,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy - space * 2,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Autosave = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"autopause\",\n\t\t\t\tOn = Settings.Autopause,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Autopause = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"speedrun_timer\",\n\t\t\t\tOn = Settings.SpeedrunTimer,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.SpeedrunTimer = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar presses = 0;\n\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"vegan_mode\",\n\t\t\t\tOn = Settings.Vegan,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tpresses++;\n\t\t\t\t\tSettings.Vegan = ((UiCheckbox) b).On;\n\n\t\t\t\t\tLog.Info($\"Click #{presses}\");\n\t\t\t\t\t\n\t\t\t\t\tif (presses == 20) {\n\t\t\t\t\t\tLog.Debug(\"Unlock npcs!\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tGlobalSave.Put(ShopNpc.AccessoryTrader, true);\n\t\t\t\t\t\tGlobalSave.Put(ShopNpc.ActiveTrader, true);\n\t\t\t\t\t\tGlobalSave.Put(ShopNpc.HatTrader, true);\n\t\t\t\t\t\tGlobalSave.Put(ShopNpc.WeaponTrader, true);\n\t\t\t\t\t\tGlobalSave.Put(ShopNpc.Mike, true);\n\t\t\t\t\t\t\n\t\t\t\t\t\tGlobalSave.Put(\"control_use\", true);\n\t\t\t\t\t\tGlobalSave.Put(\"control_swap\", true);\n\t\t\t\t\t\tGlobalSave.Put(\"control_roll\", true);\n\t\t\t\t\t\tGlobalSave.Put(\"control_interact\", true);\n\t\t\t\t\t\tGlobalSave.Put(\"control_duck\", true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"blood_n_gore\",\n\t\t\t\tOn = Settings.Blood,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 2,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Blood = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgameSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"minimap\",\n\t\t\t\tOn = Settings.Minimap,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 3,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Minimap = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgameSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"reset_settings\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 4.5f,\n\t\t\t\tClick = b => {\n\t\t\t\t\tGoConfirm(\"reset_settings_dis\", () => {\n\t\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\t\tgameSettings.Enabled = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tnew Thread(() => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tvar d = Run.Depth;\n\t\t\t\t\t\t\t\tRun.RealDepth = -1;\n\t\t\t\t\t\t\t\tRun.Depth = d;\n\t\t\t\t\t\t\t\tControls.BindDefault();\n\t\t\t\t\t\t\t\tControls.Save();\n\t\t\t\t\t\t\t\tSettings.Generate();\n\t\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\tPriority = ThreadPriority.Lowest\n\t\t\t\t\t\t}.Start();\n\t\t\t\t\t}, () => {\n\t\t\t\t\t\tcurrentBack = gameBack;\n\t\t\t\t\t\tgameSettings.Enabled = true;\n\n\t\t\t\t\t\tTween.To(Display.UiWidth * -2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\tpauseMenu.Remove(confirmationPane);\n\t\t\t\t\t\t\tconfirmationPane = null;\t\n\t\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgameSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"reset_progress\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 5.5f,\n\t\t\t\tClick = b => {\n\t\t\t\t\tGoConfirm(\"reset_progress_dis\", () => {\n\t\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\t\tgameSettings.Enabled = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tAchievements.ItemBuffer.Clear();\n\t\t\t\t\t\tAchievements.AchievementBuffer.Clear();\n\t\t\t\t\t\t\n\t\t\t\t\t\tnew Thread(() => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tSaveManager.Delete(SaveType.Player, SaveType.Level, SaveType.Game, SaveType.Global);\n\t\t\t\t\t\t\t\tSaveManager.DeleteCloudSaves();\n\n\t\t\t\t\t\t\t\ttry {\n \t\t\t\t\t\t\t\t\tSteamUserStats.ResetAll(true);\n\t\t\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tAchievements.LoadState();\n\t\t\t\t\t\t\t\tGlobalSave.Emeralds = 0;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tRun.StartingNew = true;\n\t\t\t\t\t\t\t\tRun.NextDepth = 0;\n\t\t\t\t\t\t\t\tRun.IntoMenu = true;\n\t\t\t\t\t\t\t\tSettings.Setup();\n\t\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\tPriority = ThreadPriority.Lowest\n\t\t\t\t\t\t}.Start();\n\t\t\t\t\t}, () => {\n\t\t\t\t\t\tcurrentBack = gameBack;\n\t\t\t\t\t\tgameSettings.Enabled = true;\n\n\t\t\t\t\t\tTween.To(Display.UiWidth * -2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\tconfirmationPane.Active = false;\n\t\t\t\t\t\t\tpauseMenu.Remove(confirmationPane);\n\t\t\t\t\t\t\tconfirmationPane = null;\t\n\t\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\n\t\t\tgameSettings.Add(new UiButton {\n\t\t\t\t\tLocaleLabel = \"credits\",\n\t\t\t\t\tRelativeCenterX = sx,\n\t\t\t\t\tRelativeCenterY = sy + space * 6.5f,\n\t\t\t\t\tClick = b => {\n\t\t\t\t\t\tSetupCredits();\n\t\t\t\t\t\tcredits.Enabled = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tTween.To(Display.UiWidth * -3, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\t\tgameSettings.Enabled = false;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tgameSettings.Add(new UiButton {\n\t\t\t\t\t\tLocaleLabel = \"tutorial\",\n\t\t\t\t\t\tRelativeCenterX = sx,\n\t\t\t\t\t\tRelativeCenterY = sy + space * 7.5f,\n\t\t\t\t\t\tClick = b => { Run.Depth = -2; }\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tgameBack = (UiButton) gameSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tgameSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgameSettings.Enabled = false;\n\t\t}\n\n\t\tprivate void GoConfirm(string text, Action callback, Action nope) {\n\t\t\tpauseMenu.Add(confirmationPane = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 3\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar sy = Display.UiHeight * 0.5f;\n\t\t\tvar space = 32;\n\t\t\t\n\t\t\tconfirmationPane.Add(new UiLabel {\n\t\t\t\tFont = Font.Small,\n\t\t\t\tAngleMod = 0,\n\t\t\t\tLocaleLabel = \"are_you_sure\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy - space * 1.5f,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tconfirmationPane.Add(new UiLabel {\n\t\t\t\tFont = Font.Small,\n\t\t\t\tAngleMod = 0,\n\t\t\t\tLocaleLabel = text,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tvar spx = 32;\n\t\t\t\n\t\t\tconfirmationPane.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"yes\",\n\t\t\t\tRelativeCenterX = sx + spx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tcurrentBack = (UiButton) confirmationPane.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"no\",\n\t\t\t\tRelativeCenterX = sx - spx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tnope();\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tTween.To(Display.UiWidth * -3, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\tSelectFirst();\n\t\t\t\tgameSettings.Enabled = false;\n\t\t\t};\n\t\t}\n\n\t\tpublic void UpdateRainVolume() {\n\t\t\tif (rainSound != null) {\n\t\t\t\trainSound.Volume = (Player.InBuilding ? 0.1f : 0.5f) * Settings.MusicVolume * Settings.MasterVolume;\n\t\t\t}\n\n\t\t\tRun.Level.UpdateRainVolume();\n\t\t}\n\n\t\tprivate void AddGraphicsSettings() {\n\t\t\tpauseMenu.Add(graphicsSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 2\t\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 15f;\n\t\t\tvar sy = Display.UiHeight * 0.5f - space * 4.5f;\n\t\t\t\n\t\t\tgraphicsSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"graphics\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"fullscreen\",\n\t\t\t\tOn = Engine.Graphics.IsFullScreen,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Fullscreen = ((UiCheckbox) b).On;\n\n\t\t\t\t\tif (Settings.Fullscreen) {\n\t\t\t\t\t\tEngine.Instance.SetFullscreen();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tEngine.Instance.SetWindowed(Display.Width * 3, Display.Height * 3);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOnUpdate = c => {\n\t\t\t\t\t((UiCheckbox) c).On = Engine.Graphics.IsFullScreen;\n\t\t\t\t\tSettings.Fullscreen = ((UiCheckbox) c).On;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t/*graphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"vsync\",\n\t\t\t\tOn = Settings.Vsync,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Vsync = ((UiCheckbox) b).On;\n\t\t\t\t\tEngine.Graphics.SynchronizeWithVerticalRetrace = Settings.Vsync;\n\t\t\t\t\tEngine.Graphics.ApplyChanges();\n\t\t\t\t}\n\t\t\t});*/\n\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"fps\",\n\t\t\t\tOn = Settings.ShowFps,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.ShowFps = ((UiCheckbox) b).On;\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOnUpdate = c => {\n\t\t\t\t\t((UiCheckbox) c).On = Settings.ShowFps;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgraphicsSettings.Add(new UiChoice {\n\t\t\t\tName = \"cursor\",\n\t\t\t\tOptions = new [] {\n\t\t\t\t\t\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"J\", \"K\"\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOption = Settings.Cursor,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\t\n\t\t\t\tClick = c => {\n\t\t\t\t\tSettings.Cursor = ((UiChoice) c).Option;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgraphicsSettings.Add(new UiChoice {\n\t\t\t\tName = \"quality\",\n\t\t\t\tOptions = new [] {\n\t\t\t\t\t\"normal\", \"potato\"\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOption = Settings.LowQuality ? 1 : 0,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 2,\n\t\t\t\t\n\t\t\t\tClick = c => {\n\t\t\t\t\tSettings.LowQuality = ((UiChoice) c).Option == 1;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tUiSlider.Make(graphicsSettings, sx, sy + space * 3, \"screenshake\", (int) (Settings.Screenshake * 100), 1000).OnValueChange = s => {\n\t\t\t\tSettings.Screenshake = s.Value / 100f;\n\t\t\t\tShakeComponent.Modifier = Settings.Screenshake;\n\n\t\t\t\tif (s.Value == 1000) {\n\t\t\t\t\tAchievements.Unlock(\"bk:overshake\");\n\t\t\t\t}\n\t\t\t};\n\t\t\t\t\n\t\t\tUiSlider.Make(graphicsSettings, sx, sy + space * 4, \"scale\", (int) (Settings.GameScale * 100), 200, 100).OnValueChange = s => {\n\t\t\t\tTween.To(s.Value / 100f, Settings.GameScale, x => Settings.GameScale = x, 0.3f);\n\t\t\t};\n\t\t\t\n\t\t\tUiSlider.Make(graphicsSettings, sx, sy + space * 5, \"floor_brightness\", (int) (Settings.FloorDarkness * 100), 100).OnValueChange = s => {\n\t\t\t\tTween.To(s.Value / 100f, Settings.FloorDarkness, x => Settings.FloorDarkness = x, 0.3f);\n\t\t\t};\n\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"pixel_perfect\",\n\t\t\t\tOn = Settings.PixelPerfect,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 6,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.PixelPerfect = ((UiCheckbox) b).On;\n\t\t\t\t\tEngine.Instance.UpdateView();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"vsync\",\n\t\t\t\tOn = Settings.Vsync,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 7,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Vsync = ((UiCheckbox) b).On;\n\t\t\t\t\tEngine.Graphics.SynchronizeWithVerticalRetrace = Settings.Vsync;\n\t\t\t\t\tEngine.Graphics.ApplyChanges();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"flashes\",\n\t\t\t\tOn = Settings.Flashes,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 8,\n\t\t\t\tClick = b => {\n\t\t\t\t\tEngine.Flashes = Settings.Flashes = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgraphicsSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"Vignette\",\n\t\t\t\tOn = Settings.Vignette,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 9,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Vignette = ((UiCheckbox) b).On;\n\t\t\t\t\tShaders.Screen.Parameters[\"vignette\"].SetValue(Settings.Vignette);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t\n\t\t\tgraphicsBack = (UiButton) graphicsSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tgraphicsSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgraphicsSettings.Enabled = false;\n\t\t}\n\n\t\tprivate void AddAudioSettings() {\n\t\t\tpauseMenu.Add(audioSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 2\t\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 20f;\n\t\t\tvar sy = Display.UiHeight * 0.5f - space;\n\t\t\t\n\t\t\taudioSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"audio\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\t\t\t\n\t\t\tUiSlider.Make(audioSettings, sx, sy - space, \"master_volume\", (int) (Settings.MasterVolume * 100)).OnValueChange = s => {\n\t\t\t\tSettings.MasterVolume = s.Value / 100f;\n\t\t\t\tUpdateRainVolume();\n\t\t\t};\n\t\t\t\n\t\t\tUiSlider.Make(audioSettings, sx, sy, \"music\", (int) (Settings.MusicVolume * 100)).OnValueChange = s => {\n\t\t\t\tSettings.MusicVolume = s.Value / 100f;\n\t\t\t\tUpdateRainVolume();\n\t\t\t};\n\t\t\t\n\t\t\tUiSlider.Make(audioSettings, sx, sy + space, \"sfx\", (int) (Settings.SfxVolume * 100)).OnValueChange = s => {\n\t\t\t\tSettings.SfxVolume = s.Value / 100f;\n\t\t\t};\n\n\t\t\taudioSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"ui_sfx\",\n\t\t\t\tOn = Settings.UiSfx,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 2.5f,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.UiSfx = ((UiCheckbox) b).On;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\taudioBack = (UiButton) audioSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\taudioSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\taudioSettings.Enabled = false;\n\t\t}\n\n\t\tpublic void AddInputSettings() {\n\t\t\tpauseMenu.Add(inputSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 2\t\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 20f;\n\t\t\tvar sy = Display.UiHeight * 0.5f - space * 0.5f;\n\t\t\t\n\t\t\tinputSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"input\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tvar first = true;\n\t\t\tUiButton gamepad = null;\n\t\t\t\n\t\t\tinputSettings.Add(new UiChoice {\n\t\t\t\tName = \"gamepad\",\n\t\t\t\t\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t\t\n\t\t\t\tOptions = new [] {\"none\"},\n\t\t\t\t\n\t\t\t\tClick = c => {\n\t\t\t\t\t// var i = ((UiChoice) c).Option;\n\t\t\t\t\tvar p = LocalPlayer.Locate(Area);\n\t\t\t\t\t// var e = i == GamepadData.Identifiers.Length;\n\t\t\t\t\t\n\t\t\t\t\t// Settings.Gamepad = e ? null : GamepadData.Identifiers[i];\n\t\t\t\t\tif (p != null) {\n\t\t\t\t\t\tvar d = p.GetComponent<GamepadComponent>();\n\t\t\t\t\t\td.Controller?.StopRumble();\n\t\t\t\t\t\td.Controller = null;\n\t\t\t\t\t\td.GamepadId = null;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOnUpdate = uc => {\n\t\t\t\t\t\n\t\t\t\t\tif (!first && !GamepadData.WasChanged) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar con = new List<string>();\n\t\t\t\t\tvar id = new List<string>();\n\t\t\t\t\tvar cur = 0;\n\t\t\t\n\t\t\t\t\tfor (var i = 0; i < 4; i++) {\n\t\t\t\t\t\tif (Input.Gamepads[i].Attached) {\n\t\t\t\t\t\t\tvar d = GamePad.GetCapabilities(i);\n\t\t\t\t\t\n\t\t\t\t\t\t\tif (d.GamePadType == GamePadType.GamePad) {\n\t\t\t\t\t\t\t\tid.Add(d.Identifier);\n\t\t\t\t\t\t\t\tcon.Add(d.DisplayName);\n\t\n\t\t\t\t\t\t\t\tif (Settings.Gamepad == d.Identifier) {\n\t\t\t\t\t\t\t\t\tcur = i;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tGamepadData.Identifiers = id.ToArray();\n\t\t\t\t\tcon.Add(\"none\");\n\n\t\t\t\t\tuc.Options = con.ToArray();\n\t\t\t\t\tuc.Option = cur;\n\n\t\t\t\t\tif (first && cur == con.Count - 1) {\n\t\t\t\t\t\t// gamepad.Visible = gamepad.Active = false;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfirst = false;\n\t\t\t\t\tGamepadData.Identifiers = id.ToArray();\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tsy += space * 0.5f;\n\t\t\t\n\t\t\tinputSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"keyboard_controls\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = keyboardBack;\n\t\t\t\t\tkeyboardSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 3, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tinputSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgamepad = (UiButton) inputSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"gamepad_controls\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = gamepadBack;\n\t\t\t\t\tgamepadSettings.Enabled = true;\n\t\t\t\t\tTween.To(-Display.UiWidth * 3, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tinputSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\t// gamepad.Visible = GamepadComponent.Current != null || Settings.Gamepad != null;\n\t\t\t\n\t\t\tinputBack = (UiButton) inputSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tinputSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tinputSettings.Enabled = false;\n\n\t\t\tAddKeyboardSettings();\n\t\t\tAddGamepadSettings();\n\t\t}\n\n\t\tprivate void AddKeyboardSettings() {\n\t\t\tpauseMenu.Add(keyboardSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 3\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 20f;\n\t\t\tvar spX = 96f;\n\t\t\tvar sy = Display.UiHeight * 0.5f + space * 1.5f;\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"keyboard\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\t\tKey = Controls.Left,\n\t\t\t\t\tRelativeX = sx - spX,\n\t\t\t\t\tRelativeCenterY = sy - space * 4,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\t\tKey = Controls.Right,\n\t\t\t\t\tRelativeX = sx + spX,\n\t\t\t\t\tRelativeCenterY = sy - space * 4,\n\t\t\t});\n\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\t\tKey = Controls.Up,\n\t\t\t\t\tRelativeX = sx - spX,\n\t\t\t\t\tRelativeCenterY = sy - space * 3,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\t\tKey = Controls.Down,\n\t\t\t\t\tRelativeX = sx + spX,\n\t\t\t\t\tRelativeCenterY = sy - space * 3,\n\t\t\t});\n\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Use,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy - space * 2,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Active,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy - space * 2,\n\t\t\t});\n\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Bomb,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Interact,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Swap,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Roll,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Duck,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space,\n\t\t\t});\n\t\t\t\n\t\t\tkeyboardBack = (UiButton) keyboardSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tinputSettings.Enabled = true;\n\t\t\t\t\tcurrentBack = inputBack;\n\t\t\t\t\tTween.To(Display.UiWidth * -2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tkeyboardSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tkeyboardSettings.Enabled = false;\n\t\t}\n\t\t\n\t\tprivate static string[] languages = {\n\t\t\t\"en\", \"ru\", \"de\", \"fr\", \"pl\", \"by\", \"it\", \"pt\"\n\t\t};\n\t\t\n\t\tprivate void AddLanguageSettings() {\n\t\t\tpauseMenu.Add(languageSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 2\n\t\t\t});\n\n\t\t\tlanguageSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"language\",\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tvar l = new List<string>();\n\t\t\t\n\t\t\tl.AddRange(languages);\n\n\t\t\tif (Achievements.IsComplete(\"bk:quackers\")) {\n\t\t\t\tl.Add(\"qu\");\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < l.Count; i++) {\n\t\t\t\tvar lng = l[i];\n\t\t\t\t\n\t\t\t\tlanguageSettings.Add(new UiImageButton {\n\t\t\t\t\tId = lng,\n\t\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f + 30 * (i % 2 == 0 ? -1 : 1),\n\t\t\t\t\tRelativeCenterY = (Display.UiHeight - languages.Length * 20) * 0.5f + (int) Math.Floor(i / 2f) * 40,\n\t\t\t\t\tClick = (b) => {\n\t\t\t\t\t\tSettings.Language = lng;\n\t\t\t\t\t\tLocale.Load(lng);\n\t\t\t\t\t\tSettings.Save();\n\t\t\t\t\t\t// languageBack.Click(languageBack);\n\n\t\t\t\t\t\tvar d = Run.Depth;\n\t\t\t\t\t\tRun.RealDepth = -1;\n\t\t\t\t\t\tRun.Depth = d;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tlanguageBack = (UiButton) languageSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = Display.UiWidth * 0.5f,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tpauseMenu.Enabled = true;\n\t\t\t\t\tcurrentBack = settingsBack;\n\t\t\t\t\t\n\t\t\t\t\tTween.To(-Display.UiWidth, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tlanguageSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlanguageSettings.Enabled = false;\n\t\t}\n\n\t\tprivate void AddGamepadSettings() {\n\t\t\tpauseMenu.Add(gamepadSettings = new UiPane {\n\t\t\t\tRelativeX = Display.UiWidth * 3\n\t\t\t});\n\t\t\t\n\t\t\tvar sx = Display.UiWidth * 0.5f;\n\t\t\tvar space = 20f;\n\t\t\tvar spX = 96f;\n\t\t\tvar sy = Display.UiHeight * 0.5f;// + space * 0.5f;\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiLabel {\n\t\t\t\tLocaleLabel = \"gamepad\",\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tvar g = LocalPlayer.Locate(Area)?.GetComponent<GamepadComponent>();\n\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Use,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy - space * 3,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Active,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy - space * 3,\n\t\t\t});\n\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Bomb,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy - space * 2,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Interact,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy - space * 2,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Swap,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx - spX,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Roll,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx + spX,\n\t\t\t\tRelativeCenterY = sy - space,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiControl {\n\t\t\t\tKey = Controls.Duck,\n\t\t\t\tGamepad = true,\n\t\t\t\tGamepadComponent = g,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy,\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Add(new UiCheckbox {\n\t\t\t\tName = \"vibration\",\n\t\t\t\tOn = Settings.Vibrate,\n\t\t\t\tRelativeX = sx,\n\t\t\t\tRelativeCenterY = sy + space * 1.5f,\n\t\t\t\tClick = b => {\n\t\t\t\t\tSettings.Vibrate = ((UiCheckbox) b).On;\n\n\t\t\t\t\tif (!Settings.Vibrate) {\n\t\t\t\t\t\tGamepadComponent.Current?.StopRumble();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\n\t\t\t\tOnUpdate = c => {\n\t\t\t\t\t((UiCheckbox) c).On = Settings.Vibrate;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tUiSlider.Make(gamepadSettings, sx, sy + space * 2.5f, \"sensivity\", (int) (Settings.Sensivity * 100), 200, 10).OnValueChange = s => {\n\t\t\t\tSettings.Sensivity = s.Value / 100f;\n\t\t\t};\n\t\t\t\n\t\t\tUiSlider.Make(gamepadSettings, sx, sy + space * 3.5f, \"cursor_radius\", (int) (Settings.CursorRadius * 100), 300, 10).OnValueChange = s => {\n\t\t\t\tSettings.CursorRadius = s.Value / 100f;\n\t\t\t};\n\n\t\t\tgamepadBack = (UiButton) gamepadSettings.Add(new UiButton {\n\t\t\t\tLocaleLabel = \"back\",\n\t\t\t\tType = ButtonType.Exit,\n\t\t\t\tRelativeCenterX = sx,\n\t\t\t\tRelativeCenterY = BackY,\n\t\t\t\tClick = b => {\n\t\t\t\t\tcurrentBack = inputBack;\n\t\t\t\t\tinputSettings.Enabled = true;\n\t\t\t\t\tTween.To(Display.UiWidth * -2, pauseMenu.X, x => pauseMenu.X = x, PaneTransitionTime).OnEnd = () => {\n\t\t\t\t\t\tSelectFirst();\n\t\t\t\t\t\tgamepadSettings.Enabled = false;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tgamepadSettings.Enabled = false;\n\t\t}\n\n\t\tpublic Action ReturnFromLeaderboard;\n\t\tprivate bool busy;\n\n\t\tpublic void ShowLeaderboard(string board, string name) {\n\t\t\tif (busy) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbusy = true;\n\t\t\tanimating = true;\n\n\t\t\tif (loading != null) {\n\t\t\t\tloading.Hide = false;\n\t\t\t\tleaderStats.Clear();\n\t\t\t}\n\n\t\t\tif (choice != null) {\n\t\t\t\tchoice.Option = 0;\n\t\t\t}\n\n\t\t\tif (name == \"high_score\") {\n\t\t\t\tname = \"regular\";\n\t\t\t} else if (name.StartsWith(\"daily\")) {\n\t\t\t\tname = \"daily\";\n\t\t\t}\n\t\t\t\n\t\t\tboardType.Label = $\"{Locale.Get($\"run_{name}\")} {Locale.Get(\"leaderboard\")}\";\n\n\t\t\tleaderMenu.Enabled = true;\n\t\t\tcurrentBack = leaderBack;\n\t\t\tleaderMenu.Y = Display.UiHeight;\n\t\t\t\n\t\t\tTween.To(0, leaderMenu.Y, x => leaderMenu.Y = x, 1f, Ease.BackOut).OnEnd = () => {\n\t\t\t\tSelectFirst();\n\t\t\t\td?.Invoke(board);\n\t\t\t\tanimating = false;\n\t\t\t};\n\t\t}\n\n\t\tprivate void HideLeaderboard() {\n\t\t\tif (!busy || animating) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbusy = false;\n\t\t\tanimating = true;\n\t\t\t\n\t\t\tTween.To(Display.UiHeight * 2, leaderMenu.Y, x => leaderMenu.Y = x, 0.6f).OnEnd = () => {\n\t\t\t\tSelectFirst();\t\t\t\n\t\t\t\tleaderMenu.Enabled = false;\n\t\t\t\tReturnFromLeaderboard?.Invoke();\n\t\t\t\tanimating = false;\n\t\t\t};\n\t\t\t\n\t\t\tPaused = false;\n\t\t}\n\n\t\tpublic override void OnActivated() {\n\t\t\tbase.OnActivated();\n\t\t\tt = 0;\n\t\t}\n\n\t\tpublic Action ReturnFromStats;\n\t\tprivate bool sbusy;\n\n\t\tpublic void ShowStats(int place, string id) {\n\t\t\tif (sbusy) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsbusy = true;\n\n\t\t\tstatsStats.Clear();\n\n\t\t\tplaceLabel.Label = $\"{Locale.Get(\"top\")} #{place + 1} {Locale.Get(\"run\")}\";\n\t\t\tplaceLabel.RelativeCenterX = Display.UiWidth * 0.5f;\n\n\t\t\ttry {\n\t\t\t\tvar score = GlobalSave.GetInt(id);\n\t\t\t\tvar data = GlobalSave.GetJson($\"{id}_data\");\n\n\t\t\t\tstatsStats.Add(Locale.Get(\"seed\"), data[\"seed\"].AsString, false, bt => {\n\t\t\t\t\tvar b = (UiTableEntry) bt;\n\t\t\t\t\tb.RealLocaleLabel = \"copied_to_clipboard\";\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Needs xclip on linux\n\t\t\t\t\t\tTextCopy.Clipboard.SetText(Run.Seed);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tTimer.Add(() => b.RealLocaleLabel = \"seed\", 0.5f);\n\t\t\t\t});\n\n\t\t\t\tstatsStats.Add(Locale.Get(\"won\"), Locale.Get(data[\"won\"].AsBoolean ? \"yes\" : \"no\"));\n\t\t\t\tstatsStats.Add(Locale.Get(\"time\"), data[\"time\"].AsString);\n\t\t\t\tstatsStats.Add(Locale.Get(\"lamp\"), Locale.Get(data[\"lamp\"].String(\"none\")));\n\t\t\t\tstatsStats.Add(Locale.Get(\"depth\"), data[\"depth\"].String(\"old data\"));\n\t\t\t\tstatsStats.Add(Locale.Get(\"coins_collected\"), data[\"coins\"].AsNumber.ToString());\n\t\t\t\tstatsStats.Add(Locale.Get(\"items_collected\"), data[\"items\"].AsNumber.ToString());\n\t\t\t\tstatsStats.Add(Locale.Get(\"damage_taken\"), data[\"damage\"].AsNumber.ToString());\n\t\t\t\tstatsStats.Add(Locale.Get(\"kills\"), data[\"kills\"].AsNumber.ToString());\n\t\t\t\tstatsStats.Add(Locale.Get(\"scourge_stats\"), data[\"scourge\"].AsNumber.ToString());\n\t\t\t\tstatsStats.Add(Locale.Get(\"rooms_explored\"), data[\"rooms\"].AsString);\n\t\t\t\tstatsStats.Add(Locale.Get(\"distance_traveled\"), data[\"distance\"].AsString);\n\t\t\t\tstatsStats.Add(Locale.Get(\"score\"), score.ToString());\n\t\t\t\t\n\t\t\t} catch (Exception e) {\n\t\t\t\tstatsStats.Add(\"Error\", e.Message);\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tstatsStats.Prepare();\n\n\t\t\tstatsStats.RelativeCenterX = Display.UiWidth * 0.5f;\n\t\t\tstatsStats.RelativeCenterY = Display.UiHeight * 0.5f;\n\n\t\t\tstatsMenu.Enabled = true;\n\t\t\tcurrentBack = statsBack;\n\t\t\tstatsMenu.Y = Display.UiHeight;\n\t\t\tanimating = true;\n\t\t\t\n\t\t\tTween.To(0, statsMenu.Y, x => statsMenu.Y = x, 1f, Ease.BackOut).OnEnd = () => {\n\t\t\t\tSelectFirst();\n\t\t\t\tanimating = false;\n\t\t\t};\n\t\t}\n\t\t\n\t\tprivate bool animating;\n\n\t\tprivate void HideStats() {\n\t\t\tif (!sbusy || animating) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsbusy = false;\n\t\t\tanimating = true;\n\t\t\t\n\t\t\tTween.To(Display.UiHeight * 2, statsMenu.Y, x => statsMenu.Y = x, 0.6f).OnEnd = () => {\n\t\t\t\tSelectFirst();\t\t\t\n\t\t\t\tstatsMenu.Enabled = false;\n\t\t\t\tReturnFromStats?.Invoke();\n\t\t\t\tanimating = false;\n\t\t\t};\n\n\t\t\tPaused = false;\n\t\t}\n\n\t\tpublic static bool EveryoneDied(Player pl = null) {\n\t\t\tforeach (var p in Engine.Instance.State.Area.Tagged[Tags.Player]) {\n\t\t\t\tif (!((Player) p).Dead && p != pl) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tpublic void AnimateDoneScreen(Player player) {\n\t\t\tif (Run.Type == RunType.Daily) {\n\t\t\t\tfor (var i = 0; i < Player.MaxPlayers; i++) {\n\t\t\t\t\tPlayer.StartingItems[i] = null;\n\t\t\t\t\tPlayer.StartingWeapons[i] = null;\n\t\t\t\t\tPlayer.StartingLamps[i] = null;\n\t\t\t\t}\n\n\t\t\t\tPlayer.DailyItems = null;\n\t\t\t}\n\n\t\t\tif (map != null) {\n\t\t\t\tmap.Done = true;\n\t\t\t}\n\n\t\t\tTween.To(0, emeraldY, x => emeraldY = x, 0.4f, Ease.BackOut);\n\t\t\t\n\t\t\tGlobalSave.Put(\"run_count\", GlobalSave.GetInt(\"run_count\") + 1);\n\n\n\t\t\tvar lamp = \"none\";\n\n\t\t\ttry {\n\t\t\t\tvar l = player.GetComponent<LampComponent>().Item;\n\n\t\t\t\tif (l != null) {\n\t\t\t\t\tlamp = l.Id;\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tif (Run.Won) {\n\t\t\t\tif (Run.Type == RunType.BossRush) {\n\t\t\t\t\tAchievements.Unlock(\"bk:boss_rush\");\n\t\t\t\t} else if (Run.Type == RunType.Challenge) {\n\t\t\t\t\tGlobalSave.Put($\"challenge_{Run.ChallengeId}\", true);\n\t\t\t\t\tvar count = 0;\n\n\t\t\t\t\tfor (var i = 1; i <= 30; i++) {\n\t\t\t\t\t\tif (GlobalSave.IsTrue($\"challenge_{i}\")) {\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tAchievements.SetProgress(\"bk:10_challenges\", Math.Min(10, count), 10);\n\t\t\t\t\tAchievements.SetProgress(\"bk:20_challenges\", Math.Min(20, count), 20);\n\t\t\t\t\tAchievements.SetProgress(\"bk:30_challenges\", Math.Min(30, count), 30);\n\t\t\t\t} else if (Run.Type == RunType.Daily) {\n\t\t\t\t\tAchievements.Unlock(\"bk:daily\");\n\t\t\t\t} else if (Run.Type == RunType.Regular) {\n\t\t\t\t\tif (player.GetComponent<LampComponent>().Item?.Id != \"bk:no_lamp\") {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:unstoppable\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!(GameSave.IsTrue(\"sk_enraged\") || GameSave.IsTrue(\"item_stolen\"))) {\n\t\t\t\t\t\tAchievements.Unlock(\"bk:not_a_thief\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgameOverMenu.Enabled = true;\t\n\t\t\tGlobalSave.Put(\"played_once\", true);\n\n\t\t\tgameOverMenu.Add(new UiLabel {\n\t\t\t\tLocaleLabel = Run.Won ? (BK.Demo ? \"you_won_demo\" : \"won_message\") : \"death_message\",\n\t\t\t\tRelativeCenterX = Display.UiWidth / 2f,\n\t\t\t\tRelativeCenterY = TitleY,\n\t\t\t\tClickable = false\n\t\t\t});\n\n\t\t\tCamera.Instance.Targets.Clear();\n\n\t\t\tvar stats = new UiTable();\n\n\t\t\tgameOverMenu.Add(stats);\n\n\t\t\tstats.Add(Locale.Get(\"run_type\"), Locale.Get($\"run_{Run.Type.ToString().ToLower()}\") + (Run.CustomSeed ? \" \" + Locale.Get(\"seeded\") : \"\"));\n\t\t\tstats.Add(Locale.Get(\"seed\"), Run.Seed, false, bt => {\n\t\t\t\tvar b = (UiTableEntry) bt;\n\t\t\t\tb.RealLocaleLabel = \"copied_to_clipboard\";\n\n\t\t\t\ttry {\n\t\t\t\t\t// Needs xclip on linux\n\t\t\t\t\tTextCopy.Clipboard.SetText(Run.Seed);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\n\t\t\t\tTimer.Add(() => b.RealLocaleLabel = \"seed\", 0.5f);\n\t\t\t});\n\t\t\t\n\t\t\tstats.Add(Locale.Get(\"lamp\"), Locale.Get(lamp));\n\t\t\tstats.Add(Locale.Get(\"time\"), GetRunTime());\n\t\t\tstats.Add(Locale.Get(\"depth\"), Level.GetDepthString(true));\n\t\t\tstats.Add(Locale.Get(\"coins_collected\"), Run.Statistics.CoinsObtained.ToString());\n\t\t\tstats.Add(Locale.Get(\"items_collected\"), Run.Statistics.Items.Count.ToString());\n\t\t\tstats.Add(Locale.Get(\"damage_taken\"), Run.Statistics.DamageTaken.ToString());\n\t\t\tstats.Add(Locale.Get(\"kills\"), Run.Statistics.MobsKilled.ToString());\n\t\t\tstats.Add(Locale.Get(\"scourge_stats\"), Run.Scourge.ToString());\n\t\t\tstats.Add(Locale.Get(\"rooms_explored\"), $\"{Run.Statistics.RoomsExplored} / {Run.Statistics.RoomsTotal}\");\n\t\t\tstats.Add(Locale.Get(\"distance_traveled\"), $\"{(Run.Statistics.TilesWalked / 1024f):0.0} {Locale.Get(\"km\")}\");\n\n\t\t\tRun.CalculateScore();\n\t\t\tLog.Info($\"Run score is {Run.Score}\");\n\n\t\t\tcurrentBack = overBack;\n\t\t\tvar newHigh = false;\n\n\t\t\tif (Run.Type == RunType.Regular) {\n\t\t\t\tnewHigh = GlobalSave.GetInt(\"high_score\") < Run.Score;\n\t\t\t\t\n\t\t\t\tif (newHigh) {\n\t\t\t\t\tLog.Info(\"New highscore!\");\n\t\t\t\t\tGlobalSave.Put(\"high_score\", Run.Score);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar board = Run.GetLeaderboardId();\n\t\t\t\n\t\t\tstats.Add(Locale.Get(\"score\"), newHigh ? $\"{Locale.Get(\"new_high_score\")} {Run.Score}\" : Run.Score.ToString(), newHigh, b => {\n\t\t\t\tShowLeaderboard(board, board);\n\n\t\t\t\tTween.To(-Display.UiHeight, gameOverMenu.Y, x => gameOverMenu.Y = x, 0.6f).OnEnd = () => {\n\t\t\t\t\tgameOverMenu.Enabled = false;\n\t\t\t\t};\n\n\t\t\t\tReturnFromLeaderboard = () => {\n\t\t\t\t\tgameOverMenu.Enabled = true;\n\t\t\t\t\tcurrentBack = overBack;\n\t\t\t\t\tTween.To(0, gameOverMenu.Y, x => gameOverMenu.Y = x, 1f, Ease.BackOut);\n\t\t\t\t};\n\t\t\t});\n\t\t\t\n\t\t\tstats.Prepare();\n\t\t\t\n\t\t\tstats.RelativeCenterX = Display.UiWidth * 0.5f;\n\t\t\tstats.RelativeCenterY = Display.UiHeight * 0.5f;\n\t\t\t\n\t\t\tif (Run.Type == RunType.Regular) {\n\t\t\t\tvar place = -1;\n\n\t\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\t\tvar id = $\"top_{i}\";\n\t\t\t\t\t\t\n\t\t\t\t\tif (!GlobalSave.Exists(id) || GlobalSave.GetInt(id) < Run.Score) {\n\t\t\t\t\t\tplace = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (place != -1) {\n\t\t\t\t\tif (place < 2) {\n\t\t\t\t\t\tfor (var i = 1; i >= place; i--) {\n\t\t\t\t\t\t\tvar id1 = $\"top_{i}\";\n\t\t\t\t\t\t\tvar id2 = $\"top_{i + 1}\";\n\n\t\t\t\t\t\t\tGlobalSave.Put(id2, GlobalSave.GetInt(id1));\n\t\t\t\t\t\t\tGlobalSave.Put($\"{id2}_data\", GlobalSave.GetString($\"{id1}_data\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tLog.Info($\"New #{place} run!\");\n\n\t\t\t\t\tvar root = new JsonObject();\n\n\t\t\t\t\troot[\"seed\"] = Run.Seed;\n\t\t\t\t\troot[\"time\"] = GetRunTime();\n\t\t\t\t\troot[\"depth\"] = Level.GetDepthString(true);\n\t\t\t\t\troot[\"won\"] = Run.Won;\n\n\t\t\t\t\troot[\"lamp\"] = lamp;\n\t\t\t\t\troot[\"coins\"] = Run.Statistics.CoinsObtained;\n\t\t\t\t\troot[\"items\"] = Run.Statistics.Items.Count;\n\t\t\t\t\troot[\"damage\"] = Run.Statistics.DamageTaken;\n\t\t\t\t\troot[\"kills\"] = Run.Statistics.MobsKilled;\n\t\t\t\t\troot[\"rooms\"] = $\"{Run.Statistics.RoomsExplored} / {Run.Statistics.RoomsTotal}\";\n\t\t\t\t\troot[\"scourge\"] = Run.Scourge;\n\t\t\t\t\troot[\"distance\"] = $\"{(Run.Statistics.TilesWalked / 1024f):0.0} {Locale.Get(\"km\")}\";\n\n\t\t\t\t\tvar id = $\"top_{place}\";\n\n\t\t\t\t\tGlobalSave.Put(id, Run.Score);\n\t\t\t\t\tGlobalSave.Put($\"{id}_data\", root.ToString());\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (Run.Won) {\n\t\t\t\tkilledLabel.Done = true;\n\t\t\t\tKiller.Done = true;\n\n\t\t\t\tnew Thread(() => {\n\t\t\t\t\t// SaveManager.Save(Area, SaveType.Statistics);\n\t\t\t\t\tSaveManager.Delete(SaveType.Player, SaveType.Level, SaveType.Game);\n\t\t\t\t\tSaveManager.Backup();\n\t\t\t\t}).Start();\n\t\t\t}\n\t\t\t\n\t\t\tAudio.PlayMusic(\"Nostalgia\", true);\n\t\t\t\n\t\t\tTween.To(this, new {blur = 1}, 0.5f);\n\t\t\tTween.To(0, gameOverMenu.Y, x => gameOverMenu.Y = x, 1f, Ease.BackOut).OnEnd = () => {\n\t\t\t\tSelectFirst();\n\t\t\t};\n\t\t\t\n\t\t\tOpenBlackBars();\n\n\t\t\tRun.SubmitScore?.Invoke(Run.Score, board);\n\t\t}\n\t\t\n\t\tpublic void HandleDeath() {\n\t\t\tDied = true;\n\t\t\t\t\n\t\t\tnew Thread(() => {\n\t\t\t\t// SaveManager.Save(Area, SaveType.Statistics);\n\t\t\t\tSaveManager.Delete(SaveType.Player, SaveType.Level, SaveType.Game);\n\t\t\t\tSaveManager.Backup();\n\t\t\t}).Start();\n\t\t}\n\n\t\tprivate TweenTask last;\n\n\t\tpublic bool HandleEvent(Event e) {\n\t\t\tif (e is GiveEmeraldsUse.GaveEvent ge) {\n\t\t\t\tTween.To(0, emeraldY, x => emeraldY = x, 0.4f, Ease.BackOut).OnEnd = () => {\n\t\t\t\t\tTween.Remove(last);\n\t\t\t\t\t\n\t\t\t\t\tlast = Tween.To(-20, emeraldY, x => emeraldY = x, 0.3f, Ease.QuadIn);\n\t\t\t\t\tlast.OnEnd = () => { last = null; };\n\t\t\t\t\tlast.Delay = 3;\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (Died || Run.Won) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (e is DiedEvent de && de.Who is Mob) {\n\t\t\t\tRun.KillCount++;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic override void RenderNative() {\n\t\t\tif (!Console.Open) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGuiHelper.Begin();\n\t\t\t\n\t\t\tConsole?.Render();\n\t\t\teditor?.Render();\n\t\t\t\n\t\t\tWindowManager.Render(Area);\n\t\t\tImGuiHelper.End();\n\t\t\t\n\t\t\tGraphics.Batch.Begin();\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(Mouse.GetState().Position, 3f), 8, Color.White);\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/state/ItemEditor.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.items;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.item;\r\nusing BurningKnight.entity.item.renderer;\r\nusing BurningKnight.entity.item.stand;\r\nusing BurningKnight.entity.item.use;\r\nusing BurningKnight.save;\r\nusing BurningKnight.ui.imgui;\r\nusing BurningKnight.util;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.graphics;\r\nusing Lens.input;\r\nusing Lens.lightJson;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing Num = System.Numerics;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic static class ItemEditor {\r\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\r\n\t\tprivate static unsafe ImGuiTextFilterPtr popupFilter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\r\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\r\n\t\tprivate static System.Numerics.Vector2 popupSize = new System.Numerics.Vector2(400, 400);\r\n\r\n\t\tprivate static int id;\r\n\t\tprivate static int ud;\r\n\t\tprivate static string selectedUse;\r\n\t\tprivate static string selectedRenderer;\r\n\t\tpublic static ItemData Selected;\r\n\t\tprivate static JsonValue toAdd;\r\n\t\t\r\n\t\t// Keep in sync with ItemType enum!!!\r\n\t\t// (in the same order)\r\n\t\tpublic static string[] Types = {\r\n\t\t\t\"artifact\",\r\n\t\t\t\"active\",\r\n\t\t\t\"coin\",\r\n\t\t\t\"bomb\",\r\n\t\t\t\"key\",\r\n\t\t\t\"heart\",\r\n\t\t\t\"consumable_artifact\",\r\n\t\t\t\"weapon\",\r\n\t\t\t\"battery\",\r\n\t\t\t\"hat\",\r\n\t\t\t\"pouch\",\r\n\t\t\t\"scourge\",\r\n\t\t\t\"mana\",\r\n\t\t\t\"lamp\"\r\n\t\t};\r\n\r\n\t\t// Keep in sync with the WeaponType enum!!!\r\n\t\tpublic static string[] WeaponTypes = {\r\n\t\t\t\"melee\",\r\n\t\t\t\"ranged\",\r\n\t\t\t\"magic\",\r\n\t\t\t\"none\"\r\n\t\t};\r\n\t\t\r\n\t\t// Keep in sync with the ItemQuality enum!!!\r\n\t\tpublic static string[] Quality = {\r\n\t\t\t\"wooden\",\r\n\t\t\t\"iron\",\r\n\t\t\t\"golden\",\r\n\t\t\t\"trash\"\r\n\t\t};\r\n\r\n\t\tprivate static int toRemove = -1;\r\n\r\n\t\tpublic static void DisplayUse(JsonValue parent, JsonValue root, string useId = null) {\r\n\t\t\tif (root == JsonValue.Null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tImGui.PushID(ud);\r\n\t\t\tud++;\r\n\t\t\t\r\n\t\t\tif (!root.IsJsonArray && parent != JsonValue.Null) {\r\n\t\t\t\tif (ImGui.Button(\"-\")) {\r\n\t\t\t\t\tif (parent.IsJsonArray) {\r\n\t\t\t\t\t\ttoRemove = parent.AsJsonArray.IndexOf(root);\r\n\t\t\t\t\t}\telse if (root.IsJsonObject) {\r\n\t\t\t\t\t\troot.AsJsonObject.Clear();\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t}\r\n\r\n\t\t\tif (root.IsString) {\r\n\t\t\t\tif (ImGui.TreeNode(root.AsString)) {\r\n\t\t\t\t\tImGui.TreePop();\r\n\t\t\t\t}\r\n\t\t\t} else if (root.IsJsonObject && root[\"id\"] != JsonValue.Null) {\r\n\t\t\t\tvar id = root[\"id\"].AsString;\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.TreeNode(id)) {\r\n\t\t\t\t\troot.Checkbox(\"Single Use\", \"single\", false);\r\n\t\t\t\t\tImGui.Separator();\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (UseRegistry.Renderers.TryGetValue(id, out var renderer)) {\r\n\t\t\t\t\t\trenderer(root);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tImGui.Text($\"No renderer found for use '{id}'\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tImGui.TreePop();\r\n\t\t\t\t}\r\n\t\t\t} else if (root.IsJsonArray) {\r\n\t\t\t\tforeach (var u in root.AsJsonArray) {\r\n\t\t\t\t\tDisplayUse(root, u);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (toRemove > -1) {\r\n\t\t\t\t\troot.AsJsonArray.Remove(toRemove);\r\n\t\t\t\t\ttoRemove = -1;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (useId != null) {\r\n\t\t\t\t\tif (ImGui.Button(\"Add\")) {\r\n\t\t\t\t\t\troot.AsJsonArray.Add(new JsonObject {\r\n\t\t\t\t\t\t\t[\"id\"] = useId\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (ImGui.Button(\"Add use\")) {\r\n\t\t\t\t\t\ttoAdd = root;\r\n\t\t\t\t\t\tImGui.OpenPopup(\"Add item use\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (ImGui.BeginPopupModal(\"Add item use\")) {\r\n\t\t\t\t\tid = 0;\r\n\t\t\t\t\t\r\n\t\t\t\t\tImGui.SetWindowSize(popupSize);\r\n\t\t\t\t\tpopupFilter.Draw(\"\");\r\n\t\t\t\t\tImGui.BeginChild(\"ScrollingRegionUses\", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), \r\n\t\t\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\r\n\r\n\t\t\t\t\tforeach (var i in UseRegistry.Uses) {\r\n\t\t\t\t\t\tImGui.PushID(id);\r\n\t\t\t\t\r\n\t\t\t\t\t\tif (popupFilter.PassFilter(i.Key) && ImGui.Selectable(i.Key, selectedUse == i.Key)) {\r\n\t\t\t\t\t\t\tselectedUse = i.Key;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tImGui.PopID();\r\n\t\t\t\t\t\tid++;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tImGui.EndChild();\r\n\t\t\t\t\tImGui.Separator();\r\n\r\n\t\t\t\t\tif (ImGui.Button(\"Add\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\r\n\t\t\t\t\t\ttoAdd.AsJsonArray.Add(new JsonObject {\r\n\t\t\t\t\t\t\t[\"id\"] = selectedUse\r\n\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tImGui.SameLine();\r\n\t\t\t\t\r\n\t\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\r\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t\tImGui.EndPopup();\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (ImGui.TreeNode(root.ToString())) {\r\n\t\t\t\t\tImGui.TreePop();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.PopID();\r\n\t\t}\r\n\r\n\t\tprivate static bool toSort = true;\r\n\r\n\t\tprivate static void DisplayRenderer(JsonValue parent, JsonValue root) {\r\n\t\t\tvar nil = root == JsonValue.Null || root[\"id\"] == JsonValue.Null;\r\n\t\t\t\r\n\t\t\tif (nil) {\r\n\t\t\t\tImGui.Text(\"None\");\r\n\t\t\t} else {\r\n\t\t\t\tvar id = root[\"id\"].AsString;\r\n\r\n\t\t\t\tif (RendererRegistry.DebugRenderers.TryGetValue(id, out var renderer)) {\r\n\t\t\t\t\tImGui.PushID(ud);\r\n\t\t\t\t\tud++;\r\n\t\t\t\t\trenderer(Selected.Id, parent, root);\r\n\t\t\t\t\tImGui.PopID();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tImGui.Text($\"No renderer found for '{id}'\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Button(nil ? \"Add renderer\" : \"Replace\")) {\r\n\t\t\t\ttoAdd = parent;\r\n\t\t\t\tImGui.OpenPopup(\"Select renderer\");\r\n\t\t\t}\r\n\r\n\t\t\tif (!nil) {\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Remove\")) {\r\n\t\t\t\t\tparent[\"renderer\"] = JsonValue.Null;\r\n\t\t\t\t\tSelected.Renderer = JsonValue.Null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"Select renderer\")) {\r\n\t\t\t\tImGui.SetWindowSize(popupSize);\r\n\t\t\t\t\r\n\t\t\t\tpopupFilter.Draw(\"\");\r\n\t\t\t\tImGui.BeginChild(\"ScrollingRegionRenderers\", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), \r\n\t\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\r\n\r\n\t\t\t\tforeach (var i in RendererRegistry.Renderers) {\r\n\t\t\t\t\tImGui.PushID(id);\r\n\t\t\t\t\r\n\t\t\t\t\tif (popupFilter.PassFilter(i.Key) && ImGui.Selectable(i.Key, selectedRenderer == i.Key)) {\r\n\t\t\t\t\t\tselectedRenderer = i.Key;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tImGui.PopID();\r\n\t\t\t\t\tid++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.EndChild();\r\n\t\t\t\tImGui.Separator();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Select\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\r\n\t\t\t\t\ttoAdd[\"renderer\"] = new JsonObject {\r\n\t\t\t\t\t\t[\"id\"] = selectedRenderer\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tSelected.Renderer = toAdd[\"renderer\"];\r\n\t\t\t\t\t\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void DrawItem(TextureRegion region) {\r\n\t\t\tImGui.Image(ImGuiHelper.ItemsTexture, new Num.Vector2(region.Width * 3, region.Height * 3),\r\n\t\t\t\tnew Num.Vector2(region.X / region.Texture.Width, region.Y / region.Texture.Height),\r\n\t\t\t\tnew Num.Vector2((region.X + region.Width) / region.Texture.Width, \r\n\t\t\t\t\t(region.Y + region.Height) / region.Texture.Height));\r\n\t\t}\r\n\r\n\t\tpublic static bool ForceFocus;\r\n\r\n\t\tprivate static string[] types = {\r\n\t\t\t\"Room charged\", \"Auto charged\", \"Single use\", \"Infinite\"\r\n\t\t};\r\n\t\t\r\n\t\tprivate static void RenderWindow() {\r\n\t\t\tif (Selected == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar show = true;\r\n\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\r\n\r\n\t\t\tif (!ImGui.Begin(\"Item editor\", ref show, ImGuiWindowFlags.AlwaysAutoResize)) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (!show) {\r\n\t\t\t\tSelected = null;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar name = Locale.Get(Selected.Id);\r\n\t\t\tvar animated = Selected.Animation != null;\r\n\t\t\tvar region = animated ? null : CommonAse.Items.GetSlice(Selected.Id);\r\n\r\n\t\t\tif (!animated && region != null) {\r\n\t\t\t\tDrawItem(region);\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Text(Selected.Id);\r\n\r\n\t\t\tif (ImGui.Button(\"Give\")) {\r\n\t\t\t\tLocalPlayer.Locate(Engine.Instance.State.Area)\r\n\t\t\t\t\t?.GetComponent<InventoryComponent>()\r\n\t\t\t\t\t.Pickup(Items.CreateAndAdd(\r\n\t\t\t\t\t\tSelected.Id, Engine.Instance.State.Area\r\n\t\t\t\t\t));\r\n\t\t\t}\r\n\r\n\t\t\tif (player != null) {\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Spawn\")) {\r\n\t\t\t\t\tvar item = Items.CreateAndAdd(\r\n\t\t\t\t\t\tSelected.Id, Engine.Instance.State.Area, false\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\titem.Center = player.Center;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Spawn on stand\")) {\r\n\t\t\t\t\tvar stand = new ItemStand();\r\n\t\t\t\t\tEngine.Instance.State.Area.Add(stand);\r\n\t\t\t\t\tvar item = Items.CreateAndAdd(\r\n\t\t\t\t\t\tSelected.Id, Engine.Instance.State.Area, false\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tstand.Center = player.Center;\r\n\t\t\t\t\tstand.SetItem(item, null);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\t\t\t\r\n\t\t\tif (ImGui.Button(\"Rename\")) {\r\n\t\t\t\tImGui.OpenPopup(\"Rename\");\r\n\t\t\t\titemName = Selected.Id;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.BeginPopupModal(\"Rename\")) {\r\n\t\t\t\tImGui.PushItemWidth(300);\r\n\t\t\t\tImGui.InputText(\"Id\", ref itemName, 64);\r\n\t\t\t\tImGui.PopItemWidth();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Rename\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\r\n\t\t\t\t\tvar iname = Locale.Get(Selected.Id);\r\n\t\t\t\t\tvar idesc = $\"{Selected.Id}_desc\";\r\n\t\t\t\t\tvar description = Locale.Get(idesc);\r\n\t\t\t\t\t\r\n\t\t\t\t\tLocale.Map.Remove(Selected.Id);\r\n\t\t\t\t\tLocale.Map.Remove(idesc);\r\n\r\n\t\t\t\t\tItems.Datas.Remove(Selected.Id);\r\n\r\n\t\t\t\t\tSelected.Id = itemName;\r\n\t\t\t\t\titemName = \"\";\r\n\r\n\t\t\t\t\tLocale.Map[Selected.Id] = iname;\r\n\t\t\t\t\tLocale.Map[$\"{Selected.Id}_desc\"] = description;\r\n\t\t\t\t\tItems.Datas[Selected.Id] = Selected;\r\n\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\t\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\r\n\t\t\t\t\titemName = \"\";\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Name\", ref name, 64)) {\r\n\t\t\t\tLocale.Map[Selected.Id] = name;\r\n\t\t\t}\r\n\r\n\t\t\tvar key = $\"{Selected.Id}_desc\";\r\n\t\t\tvar desc = Locale.Get(key);\r\n\t\t\t\t\r\n\t\t\tif (ImGui.InputText(\"Description\", ref desc, 128)) {\r\n\t\t\t\tLocale.Map[key] = desc;\r\n\t\t\t}\r\n\r\n\t\t\tvar type = (int) Selected.Type;\r\n\r\n\t\t\tif (ImGui.Combo(\"Type\", ref type, Types, Types.Length)) {\r\n\t\t\t\tSelected.Type = (ItemType) type;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\ttype = (int) Selected.Quality;\r\n\r\n\t\t\tif (ImGui.Combo(\"Quality\", ref type, Quality, Quality.Length)) {\r\n\t\t\t\tSelected.Quality = (ItemQuality) type;\r\n\t\t\t}\r\n\r\n\t\t\tif (Selected.Type == ItemType.Weapon) {\r\n\t\t\t\ttype = (int) Selected.WeaponType;\r\n\r\n\t\t\t\tif (ImGui.Combo(\"Weapon Type\", ref type, WeaponTypes, WeaponTypes.Length)) {\r\n\t\t\t\t\tSelected.WeaponType = (WeaponType) type;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar t = Selected.Type;\r\n\r\n\t\t\tif (t != ItemType.Coin && t != ItemType.Heart && t != ItemType.Bomb && t != ItemType.Key) {\r\n\t\t\t\tif (t == ItemType.Active) {\r\n\t\t\t\t\tvar o = 0; // Room charged\r\n\r\n\t\t\t\t\tif (Selected.SingleUse) {\r\n\t\t\t\t\t\to = 2;\r\n\t\t\t\t\t} else if (Selected.UseTime < -0.01f) {\r\n\t\t\t\t\t\to = 1; // Auto charged\r\n\t\t\t\t\t} else if (Selected.UseTime < 0.01f) {\r\n\t\t\t\t\t\to = 3; // Infinite\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ImGui.Combo(\"RC\", ref o, types, types.Length)) {\r\n\t\t\t\t\t\tSelected.SingleUse = false;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tif (o == 0) {\r\n\t\t\t\t\t\t\tSelected.UseTime = Math.Max(0.01f, Math.Abs(Selected.UseTime));\r\n\t\t\t\t\t\t} else if (o == 1) {\r\n\t\t\t\t\t\t\tSelected.UseTime = Math.Min(-0.1f, -Math.Abs(Selected.UseTime));\r\n\t\t\t\t\t\t} else if (o == 3) {\r\n\t\t\t\t\t\t\tSelected.UseTime = 0;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tSelected.SingleUse = true;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (o == 0) {\r\n\t\t\t\t\t\tvar v = (int) Selected.UseTime;\r\n\r\n\t\t\t\t\t\tif (ImGui.InputInt(\"Charges\", ref v)) {\r\n\t\t\t\t\t\t\tSelected.UseTime = v;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (o == 1) {\r\n\t\t\t\t\t\tvar v = -Selected.UseTime;\r\n\r\n\t\t\t\t\t\tif (ImGui.InputFloat(\"Charge time\", ref v)) {\r\n\t\t\t\t\t\t\tSelected.UseTime = -v;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (t == ItemType.Weapon) {\r\n\t\t\t\t\tImGui.InputFloat(\"Use time\", ref Selected.UseTime);\r\n\t\t\t\t\tImGui.Checkbox(\"Automatic\", ref Selected.Automatic);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.Checkbox(\"Auto pickup\", ref Selected.AutoPickup);\r\n\t\t\t\tImGui.Checkbox(\"Scourge\", ref Selected.Scourged);\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t} else {\r\n\t\t\t\tSelected.AutoPickup = true;\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Checkbox(\"Animated\", ref animated)) {\r\n\t\t\t\tSelected.Animation = animated ? \"\" : null;\r\n\t\t\t}\r\n\r\n\t\t\tif (animated) {\r\n\t\t\t\tImGui.InputText(\"Animation\", ref Selected.Animation, 128);\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\tImGui.Checkbox(\"Lockable\", ref Selected.Lockable);\r\n\r\n\t\t\tif (Selected.Lockable) {\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\tvar unlocked = GlobalSave.IsTrue(Selected.Id);\r\n\r\n\t\t\t\tif (ImGui.Checkbox(\"Unlocked\", ref unlocked)) {\r\n\t\t\t\t\tif (unlocked) {\r\n\t\t\t\t\t\tItems.Unlock(Selected.Id);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tGlobalSave.Put(Selected.Id, false);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar sells = Selected.UnlockPrice > 0;\r\n\r\n\t\t\t\tif (ImGui.Checkbox(\"Sells\", ref sells)) {\r\n\t\t\t\t\tSelected.UnlockPrice = sells ? 1 : 0;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (sells) {\r\n\t\t\t\t\tImGui.SameLine();\r\n\t\t\t\t\tImGui.InputInt(\"Price\", ref Selected.UnlockPrice);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Separator();\r\n\r\n\t\t\tif (ImGui.CollapsingHeader(\"Uses\")) {\r\n\t\t\t\tDisplayUse(Selected.Root, Selected.Uses);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.CollapsingHeader(\"Renderer\")) {\r\n\t\t\t\tDisplayRenderer(Selected.Root, Selected.Renderer);\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.CollapsingHeader(\"Pools\")) {\r\n\t\t\t\tImGui.Checkbox(\"Single spawn\", ref Selected.Single);\r\n\t\t\t\t\r\n\t\t\t\tvar i = 0;\r\n\t\t\t\tImGui.Text($\"{Selected.Pools}\");\r\n\t\t\t\t\r\n\t\t\t\tforeach (var p in ItemPool.ById) {\r\n\t\t\t\t\tvar val = p.Contains(Selected.Pools);\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (ImGui.Checkbox(p.Name, ref val)) {\r\n\t\t\t\t\t\tSelected.Pools = p.Apply(Selected.Pools, val);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\ti++;\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (i == ItemPool.Count) {\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (ImGui.CollapsingHeader(\"Spawn chance\")) {\r\n\t\t\t\tSelected.Chance.RenderDebug();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tif (ImGui.Button(\"Delete\")) {\r\n\t\t\t\tItems.Datas.Remove(Selected.Id);\r\n\t\t\t\tSelected = null;\r\n\t\t\t}\r\n\r\n\t\t\tif (Selected != null && player != null) {\r\n\t\t\t\tvar id = Selected.Id;\r\n\t\t\t\t\r\n\t\t\t\tif (player.GetComponent<InventoryComponent>().Has(id)) {\r\n\t\t\t\t\tImGui.BulletText(\"Present in inventory\");\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (player.GetComponent<ActiveWeaponComponent>().Has(id)) {\r\n\t\t\t\t\tImGui.BulletText(\"Present in active weapon slot\");\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (player.GetComponent<WeaponComponent>().Has(id)) {\r\n\t\t\t\t\tImGui.BulletText(\"Present in weapon slot\");\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (player.GetComponent<ActiveItemComponent>().Has(id)) {\r\n\t\t\t\t\tImGui.BulletText(\"Present in active item slot\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\r\n\t\tprivate static bool fromCurrent;\r\n\t\tprivate static int sortType;\r\n\t\tprivate static string itemName = \"\";\r\n\t\tprivate static int count;\r\n\t\tprivate static bool locked = true;\r\n\t\tprivate static int pools;\r\n\t\tprivate static int quality;\r\n\t\tprivate static int sortBy;\r\n\t\tprivate static bool single;\r\n\t\tprivate static bool invertSpawn;\r\n\t\tprivate static WeaponType weaponTypeSort;\r\n\r\n\t\tprivate static string[] sortTypes = {\r\n\t\t\t\"None\",\r\n\t\t\t\"Type\",\r\n\t\t\t\"Lockable\",\r\n\t\t\t\"Pool\",\r\n\t\t\t\"Single spawn\",\r\n\t\t\t\"Quality\",\r\n\t\t\t\"Weapon Type\"\r\n\t\t};\r\n\t\t\r\n\t\tprivate static void Sort() {\r\n\t\t\t// fixme\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Render() {\r\n\t\t\tif (!WindowManager.ItemEditor) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (toSort) {\r\n\t\t\t\ttoSort = false;\r\n\t\t\t\tSort();\r\n\t\t\t}\r\n\r\n\t\t\tRenderWindow();\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Item explorer\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tid = 0;\r\n\t\t\tud = 0;\r\n\r\n\t\t\tif (ImGui.Button(\"New\")) {\r\n\t\t\t\tImGui.OpenPopup(\"New item\");\r\n\t\t\t\tfromCurrent = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (Selected != null) {\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"New from current\")) {\r\n\t\t\t\t\tImGui.OpenPopup(\"New item\");\r\n\t\t\t\t\tfromCurrent = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Save\") || (Input.Keyboard.IsDown(Keys.LeftControl, true) && Input.Keyboard.WasPressed(Keys.S))) {\r\n\t\t\t\tLog.Info(\"Saving items\");\r\n\t\t\t\tItems.Save();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Spawn All (super laggy!)\")) {\r\n\t\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\r\n\r\n\t\t\t\tforeach (var id in Items.Datas.Keys) {\r\n\t\t\t\t\tItems.CreateAndAdd(id, Engine.Instance.State.Area, false).Center = player.Center;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Unlock All\")) {\r\n\t\t\t\tforeach (var data in Items.Datas.Values) {\r\n\t\t\t\t\tif (!data.Unlocked) {\r\n\t\t\t\t\t\tItems.Unlock(data.Id);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"New item\")) {\r\n\t\t\t\tImGui.PushItemWidth(300);\r\n\t\t\t\tImGui.InputText(\"Id\", ref itemName, 64);\r\n\t\t\t\tImGui.PopItemWidth();\r\n\t\t\t\t\r\n\t\t\t\tif (ImGui.Button(\"Create\") || Input.Keyboard.WasPressed(Keys.Enter, true)) {\r\n\t\t\t\t\tvar data = new ItemData();\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (fromCurrent && Selected != null) {\r\n\t\t\t\t\t\tdata.Type = Selected.Type;\r\n\t\t\t\t\t\tdata.Quality = Selected.Quality;\r\n\t\t\t\t\t\tdata.Animation = Selected.Animation;\r\n\t\t\t\t\t\tdata.Pools = Selected.Pools;\r\n\t\t\t\t\t\tdata.Root = JsonValue.Parse(Selected.Root.ToString());\r\n\t\t\t\t\t\tdata.Renderer = data.Root[\"renderer\"];\r\n\t\t\t\t\t\tdata.Uses = data.Root[\"uses\"];\r\n\t\t\t\t\t\tdata.SingleUse = Selected.SingleUse;\r\n\t\t\t\t\t\tdata.UseTime = Selected.UseTime;\r\n\t\t\t\t\t\tdata.Lockable = Selected.Lockable;\r\n\t\t\t\t\t\tdata.UnlockPrice = Selected.UnlockPrice;\r\n\t\t\t\t\t\tdata.Single = Selected.Single;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tvar c = Selected.Chance;\r\n\t\t\t\t\t\tdata.Chance = new Chance(c.Any, c.Melee, c.Magic, c.Range);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tdata.Chance = Chance.All();\r\n\t\t\t\t\t\tdata.Uses = new JsonArray();\r\n\t\t\t\t\t\tdata.Renderer = new JsonObject();\r\n\r\n\t\t\t\t\t\tdata.Root = new JsonObject {\r\n\t\t\t\t\t\t\t[\"uses\"] = data.Uses, \r\n\t\t\t\t\t\t\t[\"renderer\"] = data.Renderer\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdata.Id = itemName;\r\n\t\t\t\t\tItems.Datas[data.Id] = data;\r\n\t\t\t\t\tSelected = data;\r\n\t\t\t\t\titemName = \"\";\r\n\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\t\r\n\t\t\t\t\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Cancel\") || Input.Keyboard.WasPressed(Keys.Escape, true)) {\r\n\t\t\t\t\titemName = \"\";\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tfilter.Draw(\"Search\");\r\n\r\n\t\t\tImGui.SameLine();\r\n\t\t\tImGui.Text($\"{count}\");\r\n\r\n\t\t\tcount = 0;\r\n\t\t\tImGui.Combo(\"Filter by\", ref sortBy, sortTypes, sortTypes.Length);\r\n\r\n\t\t\tif (sortBy > 0) {\r\n\t\t\t\tif (sortBy == 1) {\r\n\t\t\t\t\tImGui.Combo(\"Type\", ref sortType, Types, Types.Length);\r\n\t\t\t\t} else if (sortBy == 2) {\r\n\t\t\t\t\tImGui.Checkbox(\"Lockable\", ref locked);\r\n\t\t\t\t} else if (sortBy == 3) {\r\n\t\t\t\t\tif (ImGui.TreeNode(\"Spawns in\")) {\r\n\t\t\t\t\t\tImGui.Checkbox(\"Does not spawn\", ref invertSpawn);\r\n\t\t\t\t\t\tImGui.Separator();\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tvar i = 0;\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tforeach (var p in ItemPool.ById) {\r\n\t\t\t\t\t\t\tvar val = p.Contains(pools);\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (ImGui.Checkbox(p.Name, ref val)) {\r\n\t\t\t\t\t\t\t\tpools = p.Apply(pools, val);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\ti++;\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\tif (i == ItemPool.Count) {\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tImGui.TreePop();\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (sortBy == 4) {\r\n\t\t\t\t\tImGui.Checkbox(\"Single?\", ref single);\r\n\t\t\t\t} else if (sortBy == 5) {\r\n\t\t\t\t\tImGui.Combo(\"Quality\", ref quality, Quality, Quality.Length);\r\n\t\t\t\t} else if (sortBy == 6) {\r\n\t\t\t\t\tvar v = (int) weaponTypeSort;\r\n\r\n\t\t\t\t\tif (ImGui.Combo(\"Weapon Type\", ref v, WeaponTypes, WeaponTypes.Length)) {\r\n\t\t\t\t\t\tweaponTypeSort = (WeaponType) v;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y;\r\n\t\t\tImGui.BeginChild(\"ScrollingRegionItems\", new System.Numerics.Vector2(0, -height), \r\n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\r\n\r\n\t\t\tforeach (var i in Items.Datas.Values) {\r\n\t\t\t\tImGui.PushID(id);\r\n\r\n\t\t\t\tif (ForceFocus && i == Selected) {\r\n\t\t\t\t\tImGui.SetScrollHereY();\r\n\t\t\t\t\tForceFocus = false;\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (filter.PassFilter(i.Id)) {\r\n\t\t\t\t\tif (sortBy > 0) {\r\n\t\t\t\t\t\tif (sortBy == 1) {\r\n\t\t\t\t\t\t\tif (i.Type != (ItemType) sortType) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (sortBy == 2) {\r\n\t\t\t\t\t\t\tif (i.Lockable != locked) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (sortBy == 3) {\r\n\t\t\t\t\t\t\tvar found = false;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tfor (var j = 0; j < 32; j++) {\r\n\t\t\t\t\t\t\t\tif (BitHelper.IsBitSet(pools, j) && BitHelper.IsBitSet(i.Pools, j)) {\r\n\t\t\t\t\t\t\t\t\tfound = true;\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (invertSpawn == found) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (sortBy == 4) {\r\n\t\t\t\t\t\t\tif (i.Single != single) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (sortBy == 5) {\r\n\t\t\t\t\t\t\tif (i.Quality != (ItemQuality) quality) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else if (sortBy == 6) {\r\n\t\t\t\t\t\t\tif (i.Type != ItemType.Weapon || i.WeaponType != weaponTypeSort) {\r\n\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcount++;\r\n\r\n\t\t\t\t\tif (ImGui.Selectable(i.Id, i == Selected)) {\r\n\t\t\t\t\t\tSelected = i;\r\n\r\n\t\t\t\t\t\tif (ImGui.IsMouseDown(1)) {\r\n\t\t\t\t\t\t\tif (ImGui.Button(\"Give\")) {\r\n\t\t\t\t\t\t\t\tLocalPlayer.Locate(Engine.Instance.State.Area)\r\n\t\t\t\t\t\t\t\t\t?.GetComponent<InventoryComponent>()\r\n\t\t\t\t\t\t\t\t\t.Pickup(Items.CreateAndAdd(\r\n\t\t\t\t\t\t\t\t\t\tSelected.Id, Engine.Instance.State.Area\r\n\t\t\t\t\t\t\t\t\t));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.PopID();\r\n\t\t\t\tid++;\r\n\t\t\t}\r\n\r\n\t\t\tImGui.EndChild();\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/LoadState.cs",
    "content": "using System;\nusing System.Threading;\nusing BurningKnight.assets;\nusing BurningKnight.assets.lighting;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.physics;\nusing BurningKnight.save;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing Console = BurningKnight.debug.Console;\n\nnamespace BurningKnight.state {\n\tpublic class LoadState : GameState {\n\t\tpublic string Path;\n\t\tprivate Area gameArea;\n\t\tprivate bool ready;\n\t\tprivate bool down;\n\t\tprivate float alpha;\n\t\tprivate string title;\n\t\tprivate string prefix;\n\t\tprivate float titleX;\n\t\tprivate float prefixX;\n\t\tprivate float t;\n\t\tprivate int progress;\n\t\tprivate float timer;\n\t\tprivate bool loading;\n\t\tprivate bool nice;\n\t\tpublic bool IntoCutscene;\n\t\t\n\t\tpublic bool Menu;\n\n\t\tprivate Animation animation;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(1f);\n\t\t\t\t\n\t\t\tanimation = Animations.Create(\"loading\");\n\t\t\tanimation.Paused = false;\n\n\t\t\tnice = Rnd.Chance(4.2f);\n\t\t\t\n\t\t\tif (SaveManager.ExistsAndValid(SaveType.Game)\n\t\t\t    && SaveManager.ExistsAndValid(SaveType.Level)\n\t\t\t    && SaveManager.ExistsAndValid(SaveType.Player)) {\n\n\t\t\t\tloading = true;\n\t\t\t}\n\n\t\t\tprefix = Locale.Get(loading || Run.Depth < 1 ? Locale.Get(\"loading\") : Locale.Get(\"generating\"));\n\t\t\ttitle = new Random().NextDouble() > 0.3 ? LoadScreenJokes.Generate() : BiomeTitles.Generate(BiomeRegistry.GenerateForDepth(Run.Depth).Id);\n\t\t\t\n\t\t\tLights.Init();\n\t\t\tPhysics.Init();\n\t\t\tgameArea = new Area();\n\n\t\t\tRun.Level = null;\n\t\t\tprogress = 0;\n\n\t\t\tvar thread = new Thread(() => {\n\t\t\t\tTilesets.Load();\n\t\t\t\t\n\t\t\t\tSaveManager.Load(gameArea, SaveType.Game, Path);\n\t\t\t\tprogress++;\n\n\t\t\t\tSaveManager.Load(gameArea, SaveType.Level, Path);\n\t\t\t\tprogress++;\n\n\t\t\t\tRun.Luck = 0;\n\t\t\t\tRun.ResetScourge();\n\t\t\t\t\n\t\t\t\tif (Run.Depth > 0) {\n\t\t\t\t\tSaveManager.Load(gameArea, SaveType.Player, Path);\n\t\t\t\t} else {\n\t\t\t\t\tSaveManager.Generate(gameArea, SaveType.Player);\n\t\t\t\t}\n\n\t\t\t\tGC.Collect();\n\t\t\t\tprogress++;\n\t\t\t\tEngine.AssetsLoaded?.Invoke();\n\t\t\t\tready = true;\n\t\t\t});\n\n\t\t\tthread.Priority = ThreadPriority.Lowest;\n\t\t\tthread.IsBackground = true;\n\t\t\tthread.Start();\n\n\t\t\ttitleX = Font.Small.MeasureString(title).Width * -0.5f;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tShaders.Ui.Parameters[\"black\"].SetValue(0f);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tanimation.Update(dt);\n\n\t\t\tt += dt;\n\t\t\t\n\t\t\ttimer += dt / 3;\n\t\t\ttimer = Math.Min(timer, (progress + 1) * 0.345f);\n\t\t\t\n\t\t\tif (down) {\n\t\t\t\tif (ready && ((Engine.Version.Dev || loading || Run.Depth == 0) || timer >= 1f)) {\n\t\t\t\t\ttimer = 1;\n\t\t\t\t\talpha -= dt * 5;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\talpha = Math.Min(1, alpha + dt * 5);\n\n\t\t\t\tif (alpha >= 0.95f) {\n\t\t\t\t\talpha = 1;\n\t\t\t\t\tdown = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ready && ((down && alpha < 0.05f) || (Engine.Version.Dev) || Run.Depth == 0)) {\n\t\t\t\tif (IntoCutscene) {\n\t\t\t\t\tEngine.Instance.SetState(new CutsceneState(gameArea));\n\t\t\t\t} else {\n\t\t\t\t\tEngine.Instance.SetState(new InGameState(gameArea, Menu));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tMenu = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderUi() {\n\t\t\tbase.RenderUi();\n\n\t\t\tvar value = (int) Math.Min(102, Math.Floor(timer * 100f));\n\t\t\tvar s = $\"{prefix} {(nice && value == 69 ? \"Nice.\" : $\"{value}\")}%\";\n\t\t\t\n\t\t\tprefixX = Font.Medium.MeasureString(s).Width * -0.5f;\n\t\t\t\n\t\t\tGraphics.Color = new Color(1f, 1f, 1f, alpha);\n\t\t\tGraphics.Print(s, Font.Medium, new Vector2(Display.UiWidth / 2f + prefixX, Display.UiHeight / 2f - 8));\n\t\t\tGraphics.Print(title, Font.Small, new Vector2(Display.UiWidth / 2f + titleX, Display.UiHeight / 2f + 8));\n\n\t\t\tanimation.Render(new Vector2(Display.UiWidth / 2f - 5.5f, Display.UiHeight / 2f + 24));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\n\t\tpublic override void RenderNative() {\n\t\t\tif (!Assets.ImGuiEnabled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGuiHelper.Begin();\n\t\t\n\t\t\tif (Console.Open) {\n\t\t\t\tDebugWindow.Render();\n\t\t\t}\n\n\t\t\tImGuiHelper.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/LogoRenderer.cs",
    "content": "using System;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.state {\n\tpublic static class LogoRenderer {\n\t\tprivate static TextureRegion letterB;\n\t\tprivate static TextureRegion letterU;\n\t\tprivate static TextureRegion letterR;\n\t\tprivate static TextureRegion letterN1;\n\t\tprivate static TextureRegion letterI1;\n\t\tprivate static TextureRegion letterN2;\n\t\tprivate static TextureRegion letterG1;\n\t\tprivate static TextureRegion letterK;\n\t\tprivate static TextureRegion letterN3;\n\t\tprivate static TextureRegion letterI2;\n\t\tprivate static TextureRegion letterG2;\n\t\tprivate static TextureRegion letterH;\n\t\tprivate static TextureRegion letterT;\n\t\tprivate static TextureRegion dot;\n\t\t\n\t\tprivate static TextureRegion letterBB;\n\t\tprivate static TextureRegion letterBU;\n\t\tprivate static TextureRegion letterBR;\n\t\tprivate static TextureRegion letterBN1;\n\t\tprivate static TextureRegion letterBI1;\n\t\tprivate static TextureRegion letterBN2;\n\t\tprivate static TextureRegion letterBG1;\n\t\tprivate static TextureRegion letterBK;\n\t\tprivate static TextureRegion letterBN3;\n\t\tprivate static TextureRegion letterBI2;\n\t\tprivate static TextureRegion letterBG2;\n\t\tprivate static TextureRegion letterBH;\n\t\tprivate static TextureRegion letterBT;\n\t\tprivate static TextureRegion bdot;\n\n\t\tprivate static TextureRegion letterWB;\n\t\tprivate static TextureRegion letterWU;\n\t\tprivate static TextureRegion letterWR;\n\t\tprivate static TextureRegion letterWN1;\n\t\tprivate static TextureRegion letterWI1;\n\t\tprivate static TextureRegion letterWN2;\n\t\tprivate static TextureRegion letterWG1;\n\t\tprivate static TextureRegion letterWK;\n\t\tprivate static TextureRegion letterWN3;\n\t\tprivate static TextureRegion letterWI2;\n\t\tprivate static TextureRegion letterWG2;\n\t\tprivate static TextureRegion letterWH;\n\t\tprivate static TextureRegion letterWT;\n\t\tprivate static TextureRegion wdot;\n\n\t\tprivate static Vector2[] positions = {\n\t\t\tnew Vector2(0, 0),\n\t\t\tnew Vector2(37, 19),\n\t\t\tnew Vector2(62, 30),\n\t\t\tnew Vector2(83, 17),\n\t\t\tnew Vector2(109, 22),\n\t\t\tnew Vector2(125, 19),\n\t\t\tnew Vector2(148, 19),\n\t\t\tnew Vector2(20, 60),\n\t\t\tnew Vector2(57, 90),\n\t\t\tnew Vector2(84, 89),\n\t\t\tnew Vector2(93, 90),\n\t\t\tnew Vector2(121, 78),\n\t\t\tnew Vector2(143, 78),\n\t\t\tnew Vector2(83, 59)\n\t\t};\n\n\t\tprivate static bool showK;\n\t\tprivate static bool flipR;\n\t\tprivate static bool flipAll;\n\t\tprivate static bool extremeWave;\n\t\tprivate static bool knig;\n\n\t\tpublic static void Init() {\n\t\t\tif (letterB != null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar d = DateTime.Now;\n\n\t\t\tflipAll = d.Month == 4 && d.Day == 1;\n\t\t\tshowK = Rnd.Float() < 0.999f;\n\t\t\tflipR = Rnd.Float() > 0.999f;\n\t\t\textremeWave = Rnd.Float() > 0.999f;\n\t\t\tknig = true;\n\t\t\t\n\t\t\tvar anim = Animations.Get(\"logo\");\n\n\t\t\tletterB = anim.GetSlice(\"b\");\n\t\t\tletterU = anim.GetSlice(\"u\");\n\t\t\tletterR = anim.GetSlice(\"r\");\n\t\t\tletterN1 = anim.GetSlice(\"n1\");\n\t\t\tletterI1 = anim.GetSlice(\"i1\");\n\t\t\tletterN2 = anim.GetSlice(\"n2\");\n\t\t\tletterG1 = anim.GetSlice(\"g1\");\n\t\t\tletterK = anim.GetSlice(\"k\");\n\t\t\tletterN3 = anim.GetSlice(\"n3\");\n\t\t\tletterI2 = anim.GetSlice(\"i2\");\n\t\t\tletterG2 = anim.GetSlice(\"g2\");\n\t\t\tletterH = anim.GetSlice(\"h\");\n\t\t\tletterT = anim.GetSlice(\"t\");\n\t\t\tdot = anim.GetSlice(\"dot\");\n\t\t\t\n\t\t\tanim = Animations.Get(\"logobg\");\n\n\t\t\tletterWB = anim.GetSlice(\"b\");\n\t\t\tletterWU = anim.GetSlice(\"u\");\n\t\t\tletterWR = anim.GetSlice(\"r\");\n\t\t\tletterWN1 = anim.GetSlice(\"n1\");\n\t\t\tletterWI1 = anim.GetSlice(\"i1\");\n\t\t\tletterWN2 = anim.GetSlice(\"n2\");\n\t\t\tletterWG1 = anim.GetSlice(\"g1\");\n\t\t\tletterWK = anim.GetSlice(\"k\");\n\t\t\tletterWN3 = anim.GetSlice(\"n3\");\n\t\t\tletterWI2 = anim.GetSlice(\"i2\");\n\t\t\tletterWG2 = anim.GetSlice(\"g2\");\n\t\t\tletterWH = anim.GetSlice(\"h\");\n\t\t\tletterWT = anim.GetSlice(\"t\");\n\t\t\twdot = anim.GetSlice(\"dot\");\n\n\t\t\tletterBB = anim.GetSlice(\"bb\");\n\t\t\tletterBU = anim.GetSlice(\"bu\");\n\t\t\tletterBR = anim.GetSlice(\"br\");\n\t\t\tletterBN1 = anim.GetSlice(\"bn1\");\n\t\t\tletterBI1 = anim.GetSlice(\"bi1\");\n\t\t\tletterBN2 = anim.GetSlice(\"bn2\");\n\t\t\tletterBG1 = anim.GetSlice(\"bg1\");\n\t\t\tletterBK = anim.GetSlice(\"bk\");\n\t\t\tletterBN3 = anim.GetSlice(\"bn3\");\n\t\t\tletterBI2 = anim.GetSlice(\"bi2\");\n\t\t\tletterBG2 = anim.GetSlice(\"bg2\");\n\t\t\tletterBH = anim.GetSlice(\"bh\");\n\t\t\tletterBT = anim.GetSlice(\"bt\");\n\t\t\tbdot = anim.GetSlice(\"bdot\");\n\t\t}\n \n\t\tprivate static void Render(TextureRegion letter, TextureRegion origin, Vector2 pos, bool flip = false) {\n\t\t\tvar m = extremeWave ? 6 : 1;\n\t\t\t\n\t\t\tvar x = pos.X + origin.Center.X + (Display.UiWidth - 172) / 2f;\n\t\t\tvar y = pos.Y + origin.Center.Y + (Display.UiHeight - 134) / 2f + (float) Math.Cos(Engine.Time * 2.5f + (pos.X) * 0.03f) * 1.5f * m;\n\t\t\tvar angle = (float) Math.Sin(Engine.Time * 2.5f + (pos.X) * 0.03f - Math.PI) * 0.05f * m;\n\n\t\t\tGraphics.Render(letter, new Vector2(x, y), angle, letter.Center, Vector2.One, flipAll ^ flip ? SpriteEffects.FlipVertically : SpriteEffects.None);\n\t\t}\n\t\t\n\t\tpublic static void Render(float offset) {\n\t\t\tInit();\n\t\t\t\n\t\t\tvar o = new Vector2(0, offset);\n\t\t\t\n\t\t\tRender(letterBB, letterB, positions[0] + o);\n\t\t\tRender(letterBU, letterU, positions[1] + o);\n\t\t\tRender(letterBR, letterR, positions[2] + o, flipR);\n\t\t\tRender(letterBN1, letterN1, positions[3] + o);\n\t\t\tRender(letterBI1, letterI1, positions[4] + o);\n\t\t\tRender(letterBN2, letterN2, positions[5] + o);\n\t\t\tRender(letterBG1, letterG1, positions[6] + o);\n\n\t\t\tif (showK) {\n\t\t\t\tRender(letterBK, letterK, positions[7] + o);\n\t\t\t}\n\n\t\t\tRender(letterBN3, letterN3, positions[8] + o);\n\t\t\tRender(letterBI2, letterI2, positions[9] + o);\n\t\t\tRender(letterBG2, letterG2, positions[10] + o);\n\n\t\t\tif (knig) {\n\t\t\t\tRender(letterBH, letterH, positions[11] + o);\n\t\t\t\tRender(letterBT, letterT, positions[12] + o);\n\t\t\t}\n\n\t\t\tRender(bdot, dot, positions[13] + o);\n\n\t\t\tRender(letterWB, letterB, positions[0] + o);\n\t\t\tRender(letterWU, letterU, positions[1] + o);\n\t\t\tRender(letterWR, letterR, positions[2] + o, flipR);\n\t\t\tRender(letterWN1, letterN1, positions[3] + o);\n\t\t\tRender(letterWI1, letterI1, positions[4] + o);\n\t\t\tRender(letterWN2, letterN2, positions[5] + o);\n\t\t\tRender(letterWG1, letterG1, positions[6] + o);\n\n\t\t\tif (showK) {\n\t\t\t\tRender(letterWK, letterK, positions[7] + o);\n\t\t\t}\n\n\t\t\tRender(letterWN3, letterN3, positions[8] + o);\n\t\t\tRender(letterWI2, letterI2, positions[9] + o);\n\t\t\tRender(letterWG2, letterG2, positions[10] + o);\n\n\t\t\tif (knig) {\n\t\t\t\tRender(letterWH, letterH, positions[11] + o);\n\t\t\t\tRender(letterWT, letterT, positions[12] + o);\n\t\t\t}\n\n\t\t\tRender(wdot, dot, positions[13] + o);\n\t\t\t\n\t\t\tRender(letterB, letterB, positions[0] + o);\n\t\t\tRender(letterU, letterU, positions[1] + o);\n\t\t\tRender(letterR, letterR, positions[2] + o, flipR);\n\t\t\tRender(letterN1, letterN1, positions[3] + o);\n\t\t\tRender(letterI1, letterI1, positions[4] + o);\n\t\t\tRender(letterN2, letterN2, positions[5] + o);\n\t\t\tRender(letterG1, letterG1, positions[6] + o);\n\n\t\t\tif (showK) {\n\t\t\t\tRender(letterK, letterK, positions[7] + o);\n\t\t\t}\n\n\t\t\tRender(letterN3, letterN3, positions[8] + o);\n\t\t\tRender(letterI2, letterI2, positions[9] + o);\n\t\t\tRender(letterG2, letterG2, positions[10] + o);\n\n\t\t\tif (knig) {\n\t\t\t\tRender(letterH, letterH, positions[11] + o);\n\t\t\t\tRender(letterT, letterT, positions[12] + o);\n\t\t\t}\n\t\t\t\n\n\t\t\tRender(dot, dot, positions[13] + o);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/PhotoCard.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\r\n\r\nnamespace BurningKnight.state {\r\n\tpublic class PhotoCard : Entity {\r\n\t\tprivate static Color tint = new Color(0.6f, 0.6f, 0.6f, 1f);\r\n\t\t\r\n\t\tpublic TextureRegion Region;\r\n\t\tpublic string Name;\r\n\t\tpublic string Tasks;\r\n\t\tpublic string Url;\r\n\t\tpublic Vector2 Target;\r\n\t\tpublic float Angle;\r\n\t\tpublic bool GoAway;\r\n\r\n\t\tpublic bool DoneLerping { get; private set; }\r\n\r\n\t\tpublic Vector2 Start;\r\n\t\tprivate bool hovered;\r\n\t\tprivate float sc = 1;\r\n\t\tpublic float Scale = 0.6f;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tStart = Position;\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tAlwaysVisible = true;\r\n\t\t\tWidth = Region.Width;\r\n\t\t\tHeight = Region.Height;\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\t\t\t\r\n\t\t\tif (Math.Abs(Angle) > 0.1f) {\r\n\t\t\t\tAngle -= Angle * (dt * 2.5f);\r\n\t\t\t}\r\n\r\n\t\t\tif (GoAway) {\r\n\t\t\t\tGoAway = false;\r\n\r\n\t\t\t\tTween.To(Start.X, Position.X, x => X = x, 0.8f, Ease.QuadIn).OnEnd = () => Done = true;\r\n\t\t\t\tTween.To(Start.Y, Position.Y, x => Y = x, 0.8f, Ease.QuadIn);\r\n\t\t\t} else if (!DoneLerping) {\r\n\t\t\t\tvar dx = Target.X - Position.X;\r\n\t\t\t\tvar dy = Target.Y - Position.Y;\r\n\t\t\t\tvar d = MathUtils.Distance(dx, dy);\r\n\r\n\t\t\t\tvar s = dt * 4f;\r\n\t\t\t\t\r\n\t\t\t\tX += dx * s;\r\n\t\t\t\tY += dy * s;\r\n\r\n\t\t\t\tif (d < 0.3f) {\r\n\t\t\t\t\tPosition = Target;\r\n\t\t\t\t\tDoneLerping = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t/*var w = Width * Scale;\r\n\t\t\tvar h = Height * Scale;\r\n\r\n\t\t\thovered = new Rectangle((int) (X - w / 2f), (int) (Y - h / 2f), (int) w, (int) h).Contains(Input.Mouse.UiPosition);\r\n\r\n\t\t\tsc += ((hovered ? 1.3f : 1) - sc) * dt * 5;\r\n\r\n\t\t\tif (hovered) {\r\n\t\t\t\tif (Input.Mouse.WasPressedLeftButton) {\r\n\t\t\t\t\tWeb.Open(Url);\r\n\t\t\t\t}\r\n\t\t\t}*/\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tvar scl = Scale * sc;\r\n\t\t\tvar a = Math.Max(0, Math.Abs(Angle) - 0.1f) * Math.Sign(Angle);\r\n\r\n\t\t\tGraphics.Render(Region, Position, Angle, Region.Center, new Vector2(scl));\r\n\r\n\t\t\tif (Name != null) {\r\n\t\t\t\tPrint(Name, (int) Position.X, (int) (Position.Y + Height / 2f * scl + 15), a);\r\n\t\t\t}\r\n\r\n\t\t\tif (Tasks != null) {\r\n\t\t\t\tGraphics.Color = tint;\r\n\t\t\t\tPrint(Tasks, (int) Position.X, (int) (Position.Y + Height / 2f * scl + 25), a);\r\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate static void Print(string s, int x, int y, float angle) {\r\n\t\t\tvar m = Font.Small.MeasureString(s);\r\n\t\t\tGraphics.Print(s, Font.Small, new Vector2(x, y), angle, new Vector2(m.Width / 2f, m.Height / 2f), Vector2.One);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/PicoState.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.ui.imgui;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.state {\n\tpublic class PicoState : GameState {\n\t\tprivate TextureRegion frame;\n\t\tprivate TextureRegion fill;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tvar anim = Animations.Get(\"monitor\");\n\n\t\t\tframe = anim.GetSlice(\"frame\");\n\t\t\tfill = anim.GetSlice(\"fill\");\n\n\t\t\tvar c = new Camera(new FollowingDriver());\n\t\t\t\n\t\t\tUi.Add(c);\n\t\t\tUi.Add(new Cursor());\n\t\t\t\n\t\t\tc.Position = new Vector2(Display.Width / 2f, Display.Height / 2f);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\t\t\t\n\t\t\tGraphics.Render(frame, new Vector2(32, 10));\n\t\t\tGraphics.Render(fill, new Vector2(37, 26));\n\t\t}\n\n\t\tpublic override void RenderNative() {\n\t\t\tImGuiHelper.Begin();\n\t\t\tDebugWindow.Render();\n\t\t\tImGuiHelper.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/RoomEditorState.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.level;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.floors;\nusing BurningKnight.level.rooms.regular;\nusing BurningKnight.level.tile;\nusing BurningKnight.level.walls;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.state {\n\t/*\n\t * TODO: some actual doors?\n\t */\n\tpublic class RoomEditorState : GameState {\n\t\tprivate Level level;\n\n\t\tprivate bool fixedSize;\n\t\tprivate int roomWidth = 10;\n\t\tprivate int roomHeight = 10;\n\n\t\tprivate string[] floors;\n\t\tprivate string[] walls;\n\t\t\n\t\tprivate int currentFloor;\n\t\tprivate int currentWall;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tfloors = new string[FloorRegistry.Instance.Size + 2];\n\t\t\tfloors[0] = \"Random\";\n\t\t\tfloors[1] = \"None\";\n\n\t\t\tfor (var i = 0; i < FloorRegistry.Instance.Size; i++) {\n\t\t\t\tfloors[i + 2] = FloorRegistry.Instance.Get(i).GetType().Name.Replace(\"Floor\", \"\");\n\t\t\t}\n\n\t\t\twalls = new string[WallRegistry.Instance.Size + 2];\n\t\t\twalls[0] = \"Random\";\n\t\t\twalls[1] = \"None\";\n\t\t\t\n\t\t\tfor (var i = 0; i < WallRegistry.Instance.Size; i++) {\n\t\t\t\twalls[i + 2] = WallRegistry.Instance.Get(i).GetType().Name.Replace(\"Walls\", \"\").Replace(\"Wall\", \"\");\n\t\t\t}\n\t\t\t\n\t\t\tTilesets.Load();\n\n\t\t\tUi.Add(new Camera(new FollowingDriver()) {\n\t\t\t\tPosition = new Vector2(Display.Width / 2f, Display.Height / 2f)\n\t\t\t});\n\t\t\t\n\t\t\tlevel = new RegularLevel {\n\t\t\t\tWidth = Display.Width / 16, \n\t\t\t\tHeight = Display.Height / 16 + 1, \n\t\t\t\tNoLightNoRender = false, \n\t\t\t\tDrawLight = false\n\t\t\t};\n\n\t\t\tArea.Add(level);\n\n\t\t\tlevel.SetBiome(BiomeRegistry.Get(Biome.Castle));\n\t\t\tlevel.Setup();\n\n\t\t\tPaint();\n\t\t}\n\n\t\tprivate void Paint() {\n\t\t\tlevel.MarkForClearing();\n\t\t\tlevel.Fill(Tile.WallA);\n\n\t\t\tvar room = new RegularRoom();\n\n\t\t\tif (fixedSize) {\n\t\t\t\troom.Resize(Math.Min(level.Width, roomWidth) + 1, Math.Min(level.Height, roomHeight) + 1);\n\t\t\t} else {\n\t\t\t\troom.SetSizeWithLimit(level.Width, level.Height);\n\t\t\t}\n\n\t\t\troom.SetPos((int) Math.Floor((level.Width - room.GetWidth()) / 2f), (int) Math.Floor((level.Height - room.GetHeight()) / 2f));\n\n\t\t\tif (currentFloor == 0) {\n\t\t\t\troom.PaintFloor(level);\n\t\t\t} else if (currentFloor > 1) {\n\t\t\t\tFloorRegistry.Paint(level, room, currentFloor - 2);\n\t\t\t}\n\n\t\t\tif (currentWall == 0) {\n\t\t\t\troom.Paint(level);\n\t\t\t} else if (currentWall > 1) {\n\t\t\t\tWallRegistry.Paint(level, room, null, currentWall - 2);\n\t\t\t}\n\n\t\t\tlevel.TileUp();\n\t\t}\n\n\t\tprivate void RenderWindow() {\n\t\t\tif (!ImGui.Begin(\"Room editor\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Fixed size\", ref fixedSize);\n\n\t\t\tif (fixedSize) {\n\t\t\t\tImGui.DragInt2(\"Size\", ref roomWidth, 1, 5, 20);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tImGui.Combo(\"Floor\", ref currentFloor, floors, floors.Length);\n\t\t\tImGui.Combo(\"Walls\", ref currentWall, walls, walls.Length);\n\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tif (ImGui.Button(\"Generate\")) {\n\t\t\t\tPaint();\n\t\t\t}\n\t\t\t\n\t\t\tImGui.End();\n\t\t}\n\t\t\n\t\tpublic override void RenderNative() {\n\t\t\tImGuiHelper.Begin();\n\t\t\tRenderWindow();\t\t\t\n\t\t\tImGuiHelper.End();\n\t\t\t\n\t\t\tGraphics.Batch.Begin();\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(Mouse.GetState().Position, 3f), 8, Color.White);\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/Run.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.particle;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level;\nusing BurningKnight.save;\nusing BurningKnight.save.statistics;\nusing Lens;\nusing Lens.assets;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.state {\n\tpublic static class Run {\n\t\tpublic static Action<int, string> SubmitScore;\n\t\tpublic static int ContentEndDepth = BK.Demo ? 5 : 11;\n\n\t\tprivate static int depth = BK.Version.Dev ? 1 : 0;\n\t\tpublic static int NextDepth = depth;\n\t\tpublic static int LastDepth = depth;\n\n\t\tprivate static int loop;\n\n\t\tpublic static int Loop {\n\t\t\tget => loop;\n\n\t\t\tset {\n\t\t\t\tLastLoop = Loop;\n\t\t\t\tloop = value;\n\t\t\t}\n\t\t}\n\n\t\tpublic static int LastLoop = Loop;\n\t\tpublic static bool CustomSeed; // -934034507\n\t\tpublic static int Id;\n\t\tpublic static bool Redo;\n\t\tpublic static int NumPlayers;\n\n\t\tpublic static int ActualDepth {\n\t\t\tset => depth = value;\n\t\t}\n\t\t\n\t\tpublic static int SavingDepth;\n\t\tpublic static bool StartingNew;\n\t\tpublic static int KillCount;\n\t\tpublic static float Time;\n\t\tpublic static Level Level;\n\t\tpublic static bool StartedNew;\n\t\tpublic static bool HasRun;\n\t\t\n\t\tpublic static string Seed;\n\n\t\tpublic static bool IgnoreSeed;\n\t\tpublic static int Luck;\n\t\tpublic static int Scourge { get; private set; }\n\t\tpublic static int PermanentScourge { get; internal set; }\n\t\tpublic static bool IntoMenu;\n\t\tpublic static RunStatistics Statistics;\n\t\tpublic static string NextSeed;\n\t\tpublic static int LastSavedDepth;\n\t\tpublic static bool AlternateMusic;\n\t\tpublic static RunType Type;\n\t\tpublic static int Score;\n\t\tpublic static int DailyId;\n\t\tpublic static byte ChallengeId;\n\t\tpublic static bool Won;\n\t\t\n\t\tpublic static int Depth {\n\t\t\tget => depth;\n\t\t\tset => NextDepth = value;\n\t\t}\n\n\t\tpublic static int RealDepth {\n\t\t\tset { depth = value; }\n\t\t}\n\n\t\tpublic static void Update() {\n\t\t\tif (Redo || StartingNew || depth != NextDepth) {\n\t\t\t\tLastDepth = depth;\n\t\t\t\tLastLoop = Loop;\n\t\t\t\tSavingDepth = depth;\n\t\t\t\tdepth = NextDepth;\n\t\t\t\tStartedNew = StartingNew;\n\n\t\t\t\tif (StartingNew) {\n\t\t\t\t\tSaveManager.Delete(SaveType.Player, SaveType.Game, SaveType.Level);\n\t\t\t\t}\n\n\t\t\t\tRedo = false;\n\t\t\t\tStartingNew = false;\n\n\t\t\t\tEngine.Instance.SetState(new LoadState {\n\t\t\t\t\tMenu = IntoMenu,\n\t\t\t\t\tIntoCutscene = depth < -2\n\t\t\t\t});\n\n\t\t\t\tIntoMenu = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void StartNew(int depth = 1, RunType type = RunType.Regular) {\n\t\t\tif (Statistics != null) {\n\t\t\t\tStatistics.Done = true;\n\t\t\t\tStatistics = null;\n\t\t\t}\n\t\t\t\n\t\t\tStartingNew = true;\n\t\t\tHasRun = false;\n\t\t\tNextDepth = depth;\n\t\t\tType = type;\n\t\t\tLoop = 0;\n\t\t\tCustomSeed = false;\n\t\t\t\n\t\t\tif (NextSeed != null) {\n\t\t\t\tSeed = NextSeed;\n\t\t\t\tNextSeed = null;\n\t\t\t\tIgnoreSeed = false;\n\t\t\t\tCustomSeed = true;\n\t\t\t\tLog.Debug(\"Using preset seed\");\n\t\t\t} else if (IgnoreSeed) {\n\t\t\t\tIgnoreSeed = false;\n\t\t\t\tLog.Debug(\"Ignoring seed\");\n\t\t\t} else {\n\t\t\t\tLog.Debug(\"Generating seed\");\n\t\t\t\t// fixme\n\t\t\t\tSeed = Rnd.GenerateSeed();\n\t\t\t}\n\n\t\t\tif (Type != RunType.Challenge) {\n\t\t\t\tChallengeId = 0;\n\t\t\t} else {\n\t\t\t\tLog.Info($\"Starting challenge {ChallengeId}\");\n\t\t\t}\n\n\t\t\tif (Type == RunType.Daily) {\n\t\t\t\tvar date = DateTime.UtcNow;\n\t\t\t\tDailyId = CalculateDailyId();\n\t\t\t\tLog.Debug($\"Today is {date.DayOfYear} day of the year {date.Year}, so the daily id is {DailyId}\");\n\n\t\t\t\tSeed = Rnd.GenerateSeed(8, DailyId);\n\t\t\t} else {\n\t\t\t\tDailyId = 0;\n\t\t\t}\n\n\t\t\tif (depth == 1) {\n\t\t\t\tGlobalSave.RunId++;\n\t\t\t}\n\n\t\t\tRnd.Seed = Seed;\n\t\t\tAlternateMusic = Rnd.Chance(0.5f);\n\t\t\t\n\t\t\tLog.Debug($\"This run's seed is {Seed}\");\n\t\t}\n\n\t\tpublic static int CalculateDailyId() {\n\t\t\tvar date = DateTime.UtcNow;\n\t\t\treturn (date.Year - 2020) * 365 + (date.DayOfYear) - 81;\n\t\t}\n\n\t\tpublic static void ResetStats() {\n\t\t\tKillCount = 0;\n\t\t\tTime = 0;\n\t\t\tHasRun = false;\n\t\t\tLuck = 0;\n\t\t\tScourge = 0;\n\t\t\tWon = false;\n\t\t\tPermanentScourge = 0;\n\t\t\tLastSavedDepth = 0;\n\t\t\t\n\t\t\tentity.item.Scourge.Clear();\n\t\t}\n\n\t\tpublic static string FormatTime() {\n\t\t\treturn $\"{Math.Floor(Time / 3600f)}h {Math.Floor(Time / 60f % 60f)}m {Math.Floor(Time % 60f)}s\";\n\t\t}\n\n\t\tpublic static void RemoveScourge() {\n\t\t\tif (Scourge == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tPermanentScourge = Math.Max(0, PermanentScourge - 1);\n\t\t\tScourge--;\n\t\t\t\n\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\n\n\t\t\tif (player == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTextParticle.Add(player, Locale.Get(\"scourge\"), 1, true, true);\n\t\t}\n\n\t\tpublic static void AddScourge(bool permanent = false) {\n\t\t\tScourge++;\n\t\t\tAudio.PlaySfx(\"player_cursed\");\n\n\t\t\tif (Scourge >= 10) {\n\t\t\t\tAchievements.Unlock(\"bk:scourge_king\");\n\t\t\t}\n\n\t\t\tif (Scourge > 10) {\n\t\t\t\tScourge = 10;\n\t\t\t}\n\t\t\t\n\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\n\n\t\t\tif (player == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTextParticle.Add(player, Locale.Get(\"scourge\"), 1, true);\n\t\t\tvar center = player.Center;\n\t\t\t\n\t\t\tfor (var i = 0; i < 10; i++) {\n\t\t\t\tvar part = new ParticleEntity(Particles.Scourge());\n\t\t\t\t\t\t\n\t\t\t\tpart.Position = center + Rnd.Vector(-4, 4);\n\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\n\t\t\t\tLevel.Area.Add(part);\n\t\t\t\tpart.Depth = 1;\n\t\t\t}\n\t\t\t\n\t\t\tif (permanent) {\n\t\t\t\tPermanentScourge++;\n\n\t\t\t\tif (PermanentScourge > 10) {\n\t\t\t\t\tPermanentScourge = 10;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void ResetScourge() {\n\t\t\tScourge = PermanentScourge;\n\t\t}\n\n\t\tpublic static void CalculateScore() {\n\t\t\tif (Assets.DataModified || Statistics == null) {\n\t\t\t\tScore = -696969;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tScore = 1000;\n\n\t\t\tScore += (Depth - 1) * 5000;\n\t\t\tScore += Statistics.CoinsObtained * 10;\n\t\t\tScore += Statistics.Items.Count * 100;\n\t\t\tScore += (int) Statistics.MobsKilled * 10;\n\t\t\tScore += (int) Statistics.RoomsExplored * 2;\n\t\t\tScore += Statistics.BossesDefeated * 1000;\n\t\t\tScore += Loop * 100000;\n\n\t\t\tif (Won) {\n\t\t\t\tScore += 5000;\n\t\t\t}\n\t\t\t\n\t\t\tScore -= (int) Statistics.DamageTaken * 100;\n\t\t\tScore -= (int) Time * 2;\n\t\t\tScore -= Statistics.PitsFallen * 1000;\n\n\t\t\tvar multiplier = 1 + Scourge * 0.1f;\n\t\t\tScore = (int) (Score * multiplier);\n\t\t}\n\n\t\tpublic static void Win() {\n\t\t\tif (Won) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tWon = true;\n\t\t\tStatistics.Won = true;\n\t\t\tPlayer pl = null;\n\n\t\t\tforeach (var p in Engine.Instance.State.Area.Tagged[Tags.Player]) {\n\t\t\t\tp.RemoveComponent<PlayerInputComponent>();\n\t\t\t\tp.GetComponent<HealthComponent>().Unhittable = true;\n\n\t\t\t\tpl = (Player) p;\n\t\t\t}\n\t\t\t\n\t\t\t((InGameState) Engine.Instance.State).AnimateDoneScreen(pl);\n\t\t}\n\n\t\tpublic static string GetLeaderboardId() {\n\t\t\tswitch (Type) {\n\t\t\t\tcase RunType.Daily: {\n\t\t\t\t\treturn $\"daily_{Run.DailyId}\";\n\t\t\t\t}\n\n\t\t\t\tcase RunType.BossRush: {\n\t\t\t\t\treturn \"boss_rush\";\n\t\t\t\t}\n\n\t\t\t\tcase RunType.Challenge: {\n\t\t\t\t\treturn $\"challenge_{Run.ChallengeId}\";\n\t\t\t\t}\n\n\t\t\t\tcase RunType.Twitch: {\n\t\t\t\t\treturn \"twitch\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdefault: case RunType.Regular: {\n\t\t\t\t\treturn \"high_score\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void GoToTutorial() {\n\t\t\tDepth = -3;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/state/RunType.cs",
    "content": "namespace BurningKnight.state {\n\tpublic enum RunType {\n\t\tRegular,\n\t\tDaily,\n\t\tChallenge,\n\t\tBossRush,\n\t\tTwitch\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/EntityData.cs",
    "content": "namespace BurningKnight.state.save {\n\tpublic class EntityData {\n\t\tpublic int Count;\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/EntityInspector.cs",
    "content": "using System.Collections.Generic;\nusing ImGuiNET;\nusing Lens.util.file;\n\nnamespace BurningKnight.state.save {\n\tpublic unsafe class EntityInspector : SaveInspector {\n\t\tpublic Dictionary<string, EntityData> Datas = new Dictionary<string, EntityData>();\n\t\tpublic int total;\n\t\t\n\t\tpublic override void Inspect(FileReader reader) {\n\t\t\tvar count = reader.ReadInt32();\n\t\t\tvar lastType = \"\";\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar type = reader.ReadString();\n\n\t\t\t\tif (type == null) {\n\t\t\t\t\ttype = lastType;\n\t\t\t\t}\n\n\t\t\t\tif (!Datas.TryGetValue(type, out var data)) {\n\t\t\t\t\tdata = new EntityData();\n\t\t\t\t\tDatas[type] = data;\n\t\t\t\t}\n\n\t\t\t\tdata.Count++;\n\t\t\t\ttotal++;\n\n\t\t\t\t// It's important to split this into two expression statements\n\t\t\t\t// Because readInt affects position\n\t\t\t\tvar size = reader.ReadInt16();\n\t\t\t\treader.Position += size;\n\t\t\t\tlastType = type;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\t\n\t\tpublic override void Render() {\n\t\t\tImGui.Text($\"Entity Save ({total} entities)\");\n\t\t\tfilter.Draw();\n\n\t\t\tforeach (var pair in Datas) {\n\t\t\t\tif (filter.PassFilter(pair.Key)) {\n\t\t\t\t\tImGui.BulletText($\"{pair.Key} x{pair.Value.Count}\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/GameInspector.cs",
    "content": "using System;\nusing ImGuiNET;\nusing Lens.util.file;\n\nnamespace BurningKnight.state.save {\n\tpublic class GameInspector : SaveInspector {\n\t\tprivate sbyte depth;\n\t\tprivate int killCount;\n\t\tprivate float time;\n\t\tprivate int id;\n\t\tprivate string seed;\n\n\t\tpublic override void Inspect(FileReader reader) {\n\t\t\tdepth = reader.ReadSbyte();\n\t\t\tkillCount = reader.ReadInt32();\n\t\t\ttime = reader.ReadFloat();\n\t\t\tid = reader.ReadInt32();\n\t\t\tseed = reader.ReadString();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tImGui.Text(\"Game Save\");\n\n\t\t\tImGui.Text($\"Depth: {depth}\");\n\t\t\tImGui.Text($\"Kill count: {killCount}\");\n\t\t\tImGui.Text($\"Time: {Math.Floor(time / 3600)}:{Math.Floor(time / 60)}:{(int) Math.Floor(time % 1) * 60}\");\n\t\t\tImGui.Text($\"Id: {id}\");\n\t\t\tImGui.Text($\"Seed: {seed}\");\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/GlobalInspector.cs",
    "content": "using System.Collections.Generic;\nusing ImGuiNET;\nusing Lens.util.file;\n\nnamespace BurningKnight.state.save {\n\tpublic unsafe class GlobalInspector : SaveInspector {\n\t\tpublic Dictionary<string, string> Values = new Dictionary<string, string>();\n\n\t\tpublic override void Inspect(FileReader reader) {\n\t\t\tvar count = reader.ReadInt32();\n\n\t\t\tfor (var i = 0; i < count; i++) {\n\t\t\t\tvar key = reader.ReadString();\n\t\t\t\tvar val = reader.ReadString();\n\n\t\t\t\tValues[key] = val;\n\t\t\t}\n\t\t}\n\n\t\tprivate ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\n\t\tpublic override void Render() {\n\t\t\tImGui.Text($\"Global Save ({Values.Count} entries)\");\n\t\t\tfilter.Draw();\n\n\t\t\tforeach (var pair in Values) {\n\t\t\t\tif (filter.PassFilter(pair.Key)) {\n\t\t\t\t\tImGui.BulletText(pair.Key);\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\tImGui.Text(pair.Value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/SaveData.cs",
    "content": "using BurningKnight.save;\nusing Lens.util.file;\n\nnamespace BurningKnight.state.save {\n\tpublic class SaveData : SaveNode {\n\t\tpublic SaveType SaveType;\n\t\tpublic SaveInspector Inspector;\n\t\t\n\t\tpublic void Load() {\n\t\t\tvar stream = new FileReader(FullPath);\n\t\t\tSaveType = (SaveType) stream.ReadByte();\n\n\t\t\tswitch (SaveType) {\n\t\t\t\tcase SaveType.Game: \n\t\t\t\t\tInspector = new GameInspector();\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tcase SaveType.Global: \n\t\t\t\t\tInspector = new GlobalInspector();\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tdefault:\n\t\t\t\t\tInspector = new EntityInspector();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tInspector.Inspect(stream);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tInspector.Render();\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/SaveExplorerState.cs",
    "content": "using BurningKnight.assets;\r\nusing BurningKnight.save;\r\nusing ImGuiNET;\r\nusing Lens.game;\r\nusing Lens.graphics;\r\nusing Lens.util.file;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing MonoGame.Extended;\r\n\r\nnamespace BurningKnight.state.save {\r\n\tpublic class SaveExplorerState : GameState {\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tRefreshSaveDir();\r\n\t\t}\r\n\r\n\t\tpublic override void RenderNative() {\r\n\t\t\tImGuiHelper.Begin();\r\n\t\t\tRenderGui();\r\n\t\t\tImGuiHelper.End();\r\n\r\n\t\t\tGraphics.Batch.Begin();\r\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(Mouse.GetState().Position, 3f), 8, Color.White);\r\n\t\t\tGraphics.Batch.End();\r\n\t\t}\r\n\r\n\t\tprivate FileHandle saveDir;\r\n\t\tprivate SaveGroup nodes;\r\n\r\n\t\tprivate void RefreshSaveDir() {\r\n\t\t\tsaveDir = new FileHandle(SaveManager.SaveDir);\r\n\t\t\tnodes = new SaveGroup();\r\n\r\n\t\t\tAddNodes(saveDir, nodes);\r\n\t\t}\r\n\r\n\t\tprivate void AddNodes(FileHandle dir, SaveGroup group) {\r\n\t\t\tforeach (var d in dir.ListDirectoryHandles()) {\r\n\t\t\t\tvar node = new SaveGroup {\r\n\t\t\t\t\tFullPath = d.FullPath,\r\n\t\t\t\t\tName = d.Name\r\n\t\t\t\t};\r\n\t\t\t\t\r\n\t\t\t\tgroup.Dirs.Add(node);\r\n\t\t\t\tAddNodes(d, node);\r\n\t\t\t}\r\n\r\n\t\t\tforeach (var f in dir.ListFileHandles()) {\r\n\t\t\t\tvar node = new SaveData {\r\n\t\t\t\t\tFullPath = f.FullPath,\r\n\t\t\t\t\tName = f.Name\r\n\t\t\t\t};\r\n\t\t\t\t\r\n\t\t\t\tgroup.Files.Add(node);\r\n\t\t\t\tnode.Load();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void RenderGui() {\r\n\t\t\tif (!ImGui.Begin(\"Save files\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Save directory: \\\"{SaveManager.SaveDir}\\\"\");\r\n\t\t\t\r\n\t\t\tImGui.Text($\"Exists: {saveDir.Exists()}\");\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Refresh\")) {\r\n\t\t\t\tRefreshSaveDir();\r\n\t\t\t}\r\n\r\n\t\t\tnodes.Render();\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/state/save/SaveGroup.cs",
    "content": "using System.Collections.Generic;\nusing ImGuiNET;\n\nnamespace BurningKnight.state.save {\n\tpublic class SaveGroup : SaveNode {\n\t\tpublic List<SaveGroup> Dirs = new List<SaveGroup>();\n\t\tpublic List<SaveNode> Files = new List<SaveNode>();\n\n\t\tpublic override void Render() {\n\t\t\tforeach (var f in Dirs) {\n\t\t\t\tif (ImGui.TreeNode(f.Name)) {\n\t\t\t\t\tImGui.TreePush();\n\t\t\t\t\tf.Render();\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var f in Files) {\n\t\t\t\tif (ImGui.TreeNode(f.Name)) {\n\t\t\t\t\tf.Render();\n\t\t\t\t\tImGui.TreePop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/SaveInspector.cs",
    "content": "using Lens.util.file;\n\nnamespace BurningKnight.state.save {\n\tpublic class SaveInspector {\n\t\tpublic virtual void Inspect(FileReader reader) {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic virtual void Render() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/state/save/SaveNode.cs",
    "content": "namespace BurningKnight.state.save {\n\tpublic class SaveNode {\n\t\tpublic string FullPath;\n\t\tpublic string Name;\n\t\t\n\t\tpublic virtual void Render() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/AchievementBanner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing BurningKnight.state;\nusing BurningKnight.ui.str;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.util.timer;\nusing Lens.util.tween;\n\nnamespace BurningKnight.ui {\n\tpublic class AchievementBanner : UiString {\n\t\tpublic AchievementBanner() : base(Font.Small) {\n\t\t\t\n\t\t}\n\n\t\tprivate float timer;\n\t\tprivate Queue<string> toSay = new Queue<string>();\n\t\tprivate bool ready = true;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tSubscribe<Achievement.UnlockedEvent>();\n\t\t\tSubscribe<Achievement.LockedEvent>();\n\t\t\tSubscribe<Item.UnlockedEvent>();\n\n\t\t\tFinishedTyping += e => { timer = 3f; };\n\t\t\tAlwaysActive = true;\n\n\t\t\tY = Display.UiHeight;\n\n\t\t\tDepth = 10;\n\t\t\t\n\t\t\tif (Run.Depth == 0) {\n\t\t\t\tif (Events.XMas) {\n\t\t\t\t\tItems.Unlock(\"bk:xmas_hat\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (Events.Halloween) {\n\t\t\t\t\tItems.Unlock(\"bk:pumpkin_hat\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (ready && toSay.Count > 0) {\n\t\t\t\tActuallySay(toSay.Dequeue());\n\t\t\t}\n\t\t\t\n\t\t\tif (timer > 0) {\n\t\t\t\ttimer -= dt;\n\n\t\t\t\tif (timer <= 0) {\n\t\t\t\t\ttimer = -1;\n\n\t\t\t\t\tif (Finished) {\n\t\t\t\t\t\tTween.To(Display.UiHeight, Y, x => Y = x, 0.2f, Ease.QuadIn).OnEnd = () => {\n\t\t\t\t\t\t\tTint.A = 0;\n\t\t\t\t\t\t\tTimer.Add(() => { ready = true; }, 0.25f);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is Achievement.UnlockedEvent au) {\n\t\t\t\t// Say($\"Achievement [cl red]{Locale.Get(\"ach_\" + au.Achievement.Id)}[cl] ^^%%complete%%^^!\");\n\t\t\t} else if (e is Achievement.LockedEvent al) {\n\t\t\t\tSay($\"Achievement [cl red]{Locale.Get(\"ach_\" + al.Achievement.Id)} [cl gray]locked[cl] :(\");\n\t\t\t} else if (e is Item.UnlockedEvent iu) {\n\t\t\t\tif (iu.Data.Type != ItemType.Hat) {\n\t\t\t\t\tSay($\"[cl red]{Locale.Get(iu.Data.Id)}[cl] was ^^%%unlocked%%^^!\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tprivate void Say(string str) {\n\t\t\tif (!toSay.Contains(str)) {\n\t\t\t\ttoSay.Enqueue(str);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void ActuallySay(string str) {\n\t\t\tLabel = str;\n\t\t\tready = false;\n\n\t\t\tWidth = FinalWidth;\n\t\t\tCenterX = Display.UiWidth / 2f;\n\t\t\tTint.A = 255;\n\n\t\t\tTween.To(Display.UiHeight - 32, Y, x => Y = x, 0.4f, Ease.BackOut);\n\n\t\t\tStartTyping();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/ButtonType.cs",
    "content": "namespace BurningKnight.ui {\r\n\tpublic enum ButtonType {\r\n\t\tNormal,\r\n\t\tExit,\r\n\t\tSlider\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/FrameRenderer.cs",
    "content": "using Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class FrameRenderer : Entity {\n\t\tprotected TextureRegion Top;\n\t\tprotected TextureRegion TopLeft;\n\t\tprotected TextureRegion TopRight;\n\t\t\n\t\tprotected TextureRegion RCenter;\n\t\tprotected TextureRegion CenterLeft;\n\t\tprotected TextureRegion CenterRight;\n\t\t\n\t\tprotected TextureRegion RBottom;\n\t\tprotected TextureRegion BottomLeft;\n\t\tprotected TextureRegion BottomRight;\n\n\t\tpublic Color Tint = Color.White;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic void Setup(string ase, string prefix) {\n\t\t\tvar anim = Animations.Get(ase);\n\n\t\t\tTop = anim.GetSlice($\"{prefix}top\");\n\t\t\tTopLeft = anim.GetSlice($\"{prefix}top_left\");\n\t\t\tTopRight = anim.GetSlice($\"{prefix}top_right\");\n\t\t\t\n\t\t\tRCenter = anim.GetSlice($\"{prefix}center\");\n\t\t\tCenterLeft = anim.GetSlice($\"{prefix}left\");\n\t\t\tCenterRight = anim.GetSlice($\"{prefix}right\");\n\t\t\t\n\t\t\tRBottom = anim.GetSlice($\"{prefix}bottom\");\n\t\t\tBottomLeft = anim.GetSlice($\"{prefix}bottom_left\");\n\t\t\tBottomRight = anim.GetSlice($\"{prefix}bottom_right\");\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\t\t\tRenderFrame();\n\t\t}\n\n\t\tpublic virtual void RenderFrame() {\n\t\t\tif (Tint.A == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color = Tint;\n\t\t\t\n\t\t\tGraphics.Render(TopLeft, Position);\n\t\t\tGraphics.Render(Top, new Vector2(X + TopLeft.Width, Y), 0, Vector2.Zero, \n\t\t\t\tnew Vector2((Width - TopLeft.Width - TopRight.Width) / (Top.Width), 1));\n\t\t\tGraphics.Render(TopRight, new Vector2(Right - TopRight.Width, Y));\n\t\t\t\n\t\t\tGraphics.Render(CenterLeft, new Vector2(X, Y + TopLeft.Height), 0, Vector2.Zero, \n\t\t\t\tnew Vector2(1, (Height - TopLeft.Height - BottomLeft.Height) / (CenterLeft.Height)));\n\t\t\tGraphics.Render(RCenter, new Vector2(X + CenterLeft.Width, Y + Top.Height), 0, Vector2.Zero, \n\t\t\t\tnew Vector2(\n\t\t\t\t\t(Width - CenterLeft.Width - CenterRight.Width) / (RCenter.Width), \n\t\t\t\t\t(Height - Top.Height - RBottom.Height) / (RCenter.Height)\n\t\t\t\t\t));\n\t\t\tGraphics.Render(CenterRight, new Vector2(Right - CenterRight.Width, Y + TopRight.Height), 0, Vector2.Zero,\n\t\t\t\tnew Vector2(1, (Height - TopRight.Height - BottomRight.Height) / (CenterRight.Height)));\n\t\t\t\n\t\t\tGraphics.Render(BottomLeft, new Vector2(X, Bottom - BottomLeft.Height));\n\t\t\tGraphics.Render(RBottom, new Vector2(X + BottomLeft.Width, Bottom - RBottom.Height), 0, Vector2.Zero, \n\t\t\t\tnew Vector2((Width - BottomLeft.Width - BottomRight.Width) / (RBottom.Width), 1));\n\t\t\tGraphics.Render(BottomRight, new Vector2(Right - BottomRight.Width, Bottom - BottomRight.Height));\n\t\t\t\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/HealthBar.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.assets.particle;\r\nusing BurningKnight.assets.particle.controller;\r\nusing BurningKnight.assets.particle.renderer;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.mob.boss;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.ui {\r\n\tpublic class HealthBar : Entity {\r\n\t\tprivate const float ChangeDelay = 1f;\r\n\t\tprivate static Vector2 barOffset = new Vector2(1, 6);\r\n\t\t\r\n\t\tprivate TextureRegion frame;\r\n\t\tprivate TextureRegion fill;\r\n\t\tprivate TextureRegion damage;\r\n\t\tprivate TextureRegion phase;\r\n\t\tprivate TextureRegion phaseB;\r\n\t\t\r\n\t\tprivate float lastHp;\r\n\t\tprivate float sinceLastDamage;\r\n\t\tprivate float lastChange;\r\n\t\tprivate float lastDamage;\r\n\t\tprivate bool charge;\r\n\t\t\r\n\t\tprivate Boss entity;\r\n\t\tprivate List<float> phases = new List<float>();\r\n\r\n\t\tprivate string name;\r\n\t\tprivate float nameW;\r\n\t\t\r\n\t\tpublic HealthBar(Boss owner) {\r\n\t\t\tentity = owner;\r\n\t\t\tname = Locale.Get(owner.GetId());\r\n\t\t\tnameW = Font.Small.MeasureString(name).Width;\r\n\t\t}\r\n\r\n\t\tpublic void AddPhase(float percent) {\r\n\t\t\tphases.Add(percent);\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void AddComponents() {\r\n\t\t\tbase.AddComponents();\r\n\r\n\t\t\tAlwaysActive = true;\r\n\t\t\tAlwaysVisible = true;\r\n\r\n\t\t\tframe = CommonAse.Ui.GetSlice(\"hb_frame\");\r\n\t\t\tfill = CommonAse.Ui.GetSlice(\"hb\");\r\n\t\t\tdamage = CommonAse.Ui.GetSlice(\"hb_damage\");\r\n\t\t\tphase = CommonAse.Ui.GetSlice(\"hb_phase\");\r\n\t\t\tphaseB = CommonAse.Ui.GetSlice(\"hb_b\");\r\n\t\t\t\r\n\t\t\tWidth = frame.Width;\r\n\t\t\tHeight = frame.Height;\r\n\r\n\t\t\tCenterX = Display.UiWidth / 2f;\r\n\t\t\tY = -Height;\r\n\r\n\t\t\tDepth = 32;\r\n\t\t}\r\n\r\n\t\tprivate bool showedUp;\r\n\t\tprivate bool tweened;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (charge) {\r\n\t\t\t\tsinceLastDamage += dt;\r\n\r\n\t\t\t\tif (sinceLastDamage >= ChangeDelay) {\r\n\t\t\t\t\tvar health = entity.GetComponent<HealthComponent>();\r\n\t\t\t\t\tvar h = health.Health;\r\n\t\t\t\t\tvar s = (lastChange - h) / health.MaxHealth * fill.Width;\r\n\r\n\t\t\t\t\tvar p = new ParticleEntity(new Particle(new HealthParticleController(), new HealthParticleRenderer(damage, s)));\r\n\t\t\t\t\tp.Particle.Position = Position + barOffset + new Vector2((float) h / health.MaxHealth * fill.Width, 0);\r\n\t\t\t\t\tp.Position = p.Particle.Position;\r\n\t\t\t\t\tp.AlwaysActive = true;\r\n\t\t\t\t\tp.AlwaysVisible = true;\r\n\t\t\t\t\tArea.Add(p);\r\n\t\t\t\t\tp.Depth = Depth + 1;\r\n\t\t\t\t\t\r\n\t\t\t\t\tTween.To(h, lastChange, x => lastChange = x, 0.3f);\r\n\t\t\t\t\tcharge = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (entity.Awoken && !showedUp) {\r\n\t\t\t\tshowedUp = true;\r\n\t\t\t\tTween.To(0, Y, x => Y = x, 0.3f);\r\n\t\t\t}\r\n\r\n\t\t\tif (showedUp && (!entity.Awoken || (entity.Done && !tweened))) {\r\n\t\t\t\tRemove();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void Remove() {\r\n\t\t\ttweened = true;\r\n\r\n\t\t\tif (showedUp) {\r\n\t\t\t\tTween.To(-Height - 14, Y, x => Y = x, 0.3f).OnEnd = () => {\r\n\t\t\t\t\ttweened = false;\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tif (!entity.Awoken) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tGraphics.Render(frame, Position);\r\n\r\n\t\t\tvar health = entity.GetComponent<HealthComponent>();\r\n\t\t\tvar region = new TextureRegion(fill.Texture, fill.Source);\r\n\t\t\tvar h = health.Health;\r\n\t\t\t\r\n\t\t\tif (h < lastDamage) {\r\n\t\t\t\tsinceLastDamage = 0;\r\n\t\t\t\tlastDamage = h;\r\n\t\t\t\tcharge = true;\r\n\t\t\t} else if (h > lastDamage) {\r\n\t\t\t\tlastDamage = h;\r\n\t\t\t}\r\n\r\n\t\t\tif (h > lastChange) {\r\n\t\t\t\tlastChange = h;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tGraphics.Render(damage, Position + barOffset, 0, Vector2.Zero, new Vector2(lastChange / health.MaxHealth * region.Width, 1));\r\n\r\n\t\t\tif (lastHp > h) {\r\n\t\t\t\tlastHp += Engine.Delta * 10f * (h - lastHp);\r\n\r\n\t\t\t\tif (Math.Abs(h) < 0.01f && lastHp <= 2f) {\r\n\t\t\t\t\tlastHp = 0;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tlastHp = h;\r\n\t\t\t}\r\n\r\n\t\t\tvar w = region.Width;\r\n\t\t\tregion.Source.Width = (int) Math.Ceiling(lastHp / health.MaxHealth * w);\r\n\t\t\tGraphics.Render(region, Position + barOffset);\r\n\t\t\t\r\n\t\t\tforeach (var p in phases) {\r\n\t\t\t\tGraphics.Render(health.Health / health.MaxHealth >= p ? phase : phaseB, Position + barOffset + new Vector2(p * (w - 1), 0));\r\n\t\t\t}\r\n\r\n\t\t\tGraphics.Print(name, Font.Small, new Vector2(CenterX - nameW * 0.5f, Bottom - 3));\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/SaveIndicator.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.events;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class SaveIndicator : Entity {\n\t\tprivate TextureRegion region;\n\t\tprivate bool saving;\n\t\tprivate float timer;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tAlwaysVisible = true;\n\t\t\tAlwaysActive = true;\n\t\t\tregion = CommonAse.Ui.GetSlice(\"save\");\n\n\t\t\tX = Display.UiWidth - region.Width * 2;\n\t\t\tY = Display.UiHeight - region.Height * 2;\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tif (saving) {\n\t\t\t\tGraphics.Render(region, Position, (float) Math.Cos(Engine.Time * 2f) * 0.25f, region.Center, \n\t\t\t\t\tnew Vector2((float) Math.Cos(Engine.Time * 3f) * 0.25f + 1f));\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\ttimer += dt;\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is SaveStartedEvent) {\n\t\t\t\tsaving = true;\n\t\t\t\ttimer = 0;\n\t\t\t\t\n\t\t\t\tY = Display.UiHeight + region.Height;\n\t\t\t\tTween.To(Display.UiHeight - region.Height * 2, Y, y => Y = y, 0.4f, Ease.BackOut);\n\t\t\t} else if (e is SaveEndedEvent) {\n\t\t\t\tvar task = Tween.To(Display.UiHeight + region.Height, Display.UiHeight - region.Height * 2, y => Y = y, 0.4f, Ease.BackIn);\n\n\t\t\t\ttask.Delay = Math.Max(0, 5f - timer);\n\t\t\t\ttask.OnEnd = () => saving = false;\n\t\t\t}\n\t\t\t\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiAchievement.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiAchievement : FrameRenderer {\n\t\tpublic static UiAchievement Current;\n\t\t\n\t\tprivate const int Padding = 6;\n\t\t\n\t\tprivate string title;\n\t\tprivate string description;\n\t\tprivate TextureRegion icon;\n\t\tprivate TextureRegion iconBg;\n\n\t\tprivate Vector2 bgOffset;\n\t\tprivate Vector2 iconOffset;\n\t\tprivate Vector2 titleOffset;\n\t\tprivate Vector2 descriptionOffset;\n\n\t\tprivate bool isItem;\n\t\t\n\t\tpublic UiAchievement(string id, bool item = false) {\n\t\t\tCurrent = this;\n\t\t\tisItem = item;\n\t\t\t\n\t\t\ttitle = Locale.Get(item ? id : $\"ach_{id}\");\n\t\t\tdescription = Locale.Get(item ? \"was_unlocked\" : $\"ach_{id}_desc\");\n\t\t\ticon = Animations.Get(item ? \"items\" : \"achievements\").GetSlice(id);\n\t\t\ticonBg = CommonAse.Ui.GetSlice(\"item_bg\");\n\n\t\t\tvar titleSize = Font.Small.MeasureString(title);\n\t\t\tvar descriptionSize = Font.Small.MeasureString(description);\n\n\t\t\tbgOffset = new Vector2(Padding);\n\t\t\ticonOffset = new Vector2(Padding + (20 - icon.Width) / 2f, Padding + (20 - icon.Height) / 2f);\n\t\t\ttitleOffset = new Vector2(Padding * 2 + 20, Padding - 1);\n\t\t\tdescriptionOffset = new Vector2(Padding * 2 + 20, Padding + 10);\n\n\t\t\tWidth = Math.Max(128, (Math.Max(titleSize.Width, descriptionSize.Width) + 22 + Padding * 3));\n\t\t\tHeight = 20 + Padding * 2;\n\t\t\tDepth = 32;\n\n\t\t\tif (!item) {\n\t\t\t\tAudio.PlaySfx(\"ui_achievement\", 0.3f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tSetup(\"ui\", \"bg_\");\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Current == this) {\n\t\t\t\tCurrent = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tTween.To(Display.UiHeight - 8 - Height, Y, x => Y = x, 0.7f, Ease.BackOut).OnEnd = () => {\n\t\t\t\tvar t = Tween.To(Display.UiHeight + 2, Y, x => Y = x, 0.5f, Ease.BackIn);\n\n\t\t\t\tt.Delay = 5f;\n\t\t\t\tt.OnStart = () => {\n\t\t\t\t\tCurrent = null;\n\t\t\t\t\tDepth--;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (isItem) {\n\t\t\t\t\t\t\tAchievements.ItemBuffer.RemoveAt(0);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tAchievements.AchievementBuffer.RemoveAt(0);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tt.OnEnd = () => {\n\t\t\t\t\tDone = true;\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tGraphics.Render(iconBg, Position + bgOffset);\n\t\t\tGraphics.Render(icon, Position + iconOffset);\n\t\t\tGraphics.Print(title, Font.Small, Position + titleOffset);\n\t\t\tGraphics.Print(description, Font.Small, Position + descriptionOffset);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiAnimation.cs",
    "content": "using Lens.graphics;\nusing Lens.graphics.animation;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.ui {\n\tpublic class UiAnimation : UiEntity {\n\t\tpublic Animation Animation;\n\t\tpublic TextureRegion Slice;\n\t\tpublic bool UseSlice;\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tWidth = 48;\n\t\t\tHeight = 48;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (!UseSlice) {\n\t\t\t\tAnimation?.Update(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Animation == null && Slice == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar region = UseSlice ? Slice : Animation.GetCurrentTexture();\n\t\t\tGraphics.Render(region, Center, 0, region.Center, new Vector2(2));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiBanner.cs",
    "content": "using BurningKnight.assets;\r\nusing Lens;\r\nusing Lens.graphics;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.ui {\r\n\tpublic class UiBanner : FrameRenderer {\r\n\t\tprivate string label;\r\n\t\tprivate float labelX;\r\n\t\tprivate float targetW;\r\n\t\tprivate Color color = Color.White;\r\n\t\t\r\n\t\tpublic UiBanner(string str) {\r\n\t\t\tvar w = Font.Small.MeasureString(str).Width;\r\n\t\t\t\r\n\t\t\tlabel = str;\r\n\t\t\tlabelX = w * -0.5f;\r\n\r\n\t\t\ttargetW = w + 28;\r\n\r\n\t\t\tWidth = 20;\r\n\t\t\tHeight = 23;\r\n\r\n\t\t\tcolor.A = 0;\r\n\t\t}\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\t\r\n\t\t\tSetup(\"ui\", \"scroll_\");\r\n\r\n\t\t\tCenterX = (Display.UiWidth) / 2f;\r\n\t\t\tCenterY = Display.UiHeight + 64;\r\n\r\n\t\t\t// fix centring\r\n\t\t\tTween.To(Display.UiHeight - 64f, CenterY, x => CenterY = x, 1f, Ease.BackOut).OnEnd = () => {\r\n\t\t\t\tTween.To(targetW, Width, x => {\r\n\t\t\t\t\tWidth = x;\r\n\t\t\t\t\tCenterX = (Display.UiWidth) / 2f;\r\n\t\t\t\t}, 0.7f, Ease.BackOut).OnEnd = () => {\r\n\t\t\t\t\tTween.To(255, 0, x => color.A = (byte) x, 0.3f);\r\n\r\n\t\t\t\t\tvar t = Tween.To(0, 255, x => color.A = (byte) x, 0.3f);\r\n\t\t\t\t\tt.Delay = 3;\r\n\r\n\t\t\t\t\tt.OnEnd = () => {\r\n\t\t\t\t\t\tTween.To(20, Width, x => {\r\n\t\t\t\t\t\t\t\tWidth = x;\r\n\t\t\t\t\t\t\t\tCenterX = (Display.UiWidth) / 2f;\r\n\t\t\t\t\t\t\t}, 0.7f, Ease.BackIn).OnEnd = \r\n\t\t\t\t\t\t\t() => Tween.To(Display.UiHeight + 64, CenterY, x => CenterY = x, 1f, Ease.BackIn).OnEnd = \r\n\t\t\t\t\t\t\t\t() => { Done = true; };\r\n\t\t\t\t\t};\r\n\t\t\t\t};\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tbase.Render();\r\n\r\n\t\t\tGraphics.Color = color;\r\n\t\t\tGraphics.Print(label, Font.Small, new Vector2(labelX + Width / 2, 8) + Position);\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/UiButton.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.input;\nusing BurningKnight.entity.component;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.ui {\n\tpublic class UiButton : UiLabel {\n\t\tpublic static int Selected = -1;\n\t\tpublic static UiButton SelectedInstance;\n\n\t\tpublic static int LastId;\n\t\t\n\t\tpublic Action<UiButton> Click;\n\t\tpublic ButtonType Type = ButtonType.Normal;\n\t\tpublic float XPadding;\n\t\tpublic float YPadding;\n\t\tpublic int Id;\n\t\tpublic bool Selectable = true;\n\n\t\tprivate bool wasSelected;\n\n\t\tpublic UiButton() {\n\t\t\tId = LastId++;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tAddTag(Tags.Button);\n\t\t}\n\n\t\tpublic override bool CheckCollision(Vector2 v) {\n\t\t\treturn new Rectangle((int) (X - XPadding), (int) (Y - YPadding), (int) (Width + XPadding * 2), (int) (Height + YPadding * 2)).Contains(v);\n\t\t}\n\n\t\tprotected override void OnHover() {\n\t\t\tif (Selected != Id) {\n\t\t\t\tif (SelectedInstance == null && Type != ButtonType.Slider) {\n\t\t\t\t\tSelectedInstance = this;\n\t\t\t\t\tSelected = Id;\n\t\t\t\t} else {\n\t\t\t\t\tbase.OnHover();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPlaySfx(\"ui_moving\");\n\t\t}\n\n\t\tpublic override void PlaySfx(string sfx) {\n\t\t\tif (Clickable) {\n\t\t\t\tbase.PlaySfx(sfx);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnUnhover() {\n\t\t\tif (GamepadComponent.Current == null && Selected == Id) {\n\t\t\t\tSelected = -1;\n\t\t\t\tSelectedInstance = null;\n\t\t\t}\n\t\t\n\t\t\tif (Selected != Id) {\n\t\t\t\tbase.OnUnhover();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void OnClick() {\n\t\t\tbase.OnClick();\n\t\t\tClick?.Invoke(this);\n\n\t\t\tswitch (Type) {\n\t\t\t\tcase ButtonType.Normal: {\n\t\t\t\t\tPlaySfx(\"ui_select\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase ButtonType.Exit: {\n\t\t\t\t\tPlaySfx(\"ui_exit\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase ButtonType.Slider: {\n\t\t\t\t\tPlaySfx(\"ui_change_parameter\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar selected = Selected == Id;\n\n\t\t\tif (selected) {\n\t\t\t\tSelectedInstance = this;\n\t\t\t}\n\t\t\t\n\t\t\tif (wasSelected && !selected) {\n\t\t\t\tTween.To(UiLabel.DefaultTint, Tint, x => Tint = x, 0.1f);\n\t\t\t\tTween.To(1f, scale, x => scale = x, 0.1f);\n\t\t\t} else if (selected && !wasSelected) {\n\t\t\t\tTween.To(1, Tint, x => Tint = x, 0.1f);\n\t\t\t\tTween.To(1 + ScaleMod * 0.2f, scale, x => scale = x, 0.1f);\n\t\t\t}\n\n\t\t\tif (selected && Input.WasPressed(Controls.UiSelect, GamepadComponent.Current, true)) {\n\t\t\t\tOnClick();\n\t\t\t}\n\n\t\t\twasSelected = selected;\n\t\t}\n\t\t\n\t\tpublic bool IsOnScreen() {\n\t\t\treturn Selectable && X >= 0 && Right <= Display.UiWidth && Y >= 0 && Bottom <= Display.UiHeight;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiChat.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.ui {\n\tpublic class UiChat : Entity {\n\t\tprivate bool open;\n\t\tprivate string input = \"\";\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t\tDepth = 32;\n\n\t\t\tEngine.Instance.Window.TextInput += HandleInput;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tEngine.Instance.Window.TextInput -= HandleInput;\n\t\t}\n\t\t\n\t\tpublic void HandleInput(object e, TextInputEventArgs args) {\n\t\t\tif (Engine.Instance.State.Paused) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (args.Key == Keys.Back) {\n\t\t\t\tif (open && input.Length > 0) {\n\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t\tinput = input.Substring(0, input.Length - 1);\n\t\t\t\t}\n\t\t\t} else if (args.Key == Keys.Enter) {\n\t\t\t\tif (open) {\n\t\t\t\t\topen = false;\n\t\t\t\t\tInput.Blocked = 0;\n\t\t\t\t\tAudio.PlaySfx(\"ui_exit\");\n\n\t\t\t\t\tif (input != \"\") {\n\t\t\t\t\t\tif (input == \"muffin\") {\n\t\t\t\t\t\t\tinput = \"##[cl red]NANI??!?!?\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar player = LocalPlayer.Locate(Engine.Instance.State.Area);\n\n\t\t\t\t\t\tif (player != null) {\n\t\t\t\t\t\t\tplayer.GetComponent<DialogComponent>().StartAndClose(input, 5);\n\t\t\t\t\t\t\tinput = \"\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar c = args.Character;\n\n\t\t\t\tif (c == '/') {\n\t\t\t\t\topen = !open;\n\n\t\t\t\t\tif (open) {\n\t\t\t\t\t\tInput.Blocked = 1;\n\t\t\t\t\t\tAudio.PlaySfx(\"ui_select\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tInput.Blocked = 0;\n\t\t\t\t\t\tAudio.PlaySfx(\"ui_exit\");\n\t\t\t\t\t}\n\t\t\t\t} else if (open && c != '\\0' && c != '\\t' && c != '\\n') {\n\t\t\t\t\tinput += c;\n\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\tt += dt;\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tGraphics.Print($\"> {input}{(t % 1f > 0.5f ? \"\" : \"|\")}\", Font.Small, new Vector2(4, Display.UiHeight - 16));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiCheckbox.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui {\n\tpublic class UiCheckbox : UiChoice {\n\t\tpublic bool On {\n\t\t\tget => Option == 0;\n\t\t\tset {\n\t\t\t\tif (On != value) {\n\t\t\t\t\tOption = value ? 0 : 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic UiCheckbox() {\n\t\t\tOptions = new[] {\n\t\t\t\t\"on\", \"off\"\n\t\t\t};\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiChoice.cs",
    "content": "using System;\nusing Lens.assets;\nusing Lens.input;\nusing Lens.util;\n\nnamespace BurningKnight.ui {\n\tpublic class UiChoice : UiButton {\n\t\tprivate float cx;\n\t\tprivate int option;\n\n\t\tpublic bool Disabled;\n\t\t\n\t\tpublic int Option {\n\t\t\tget => option;\n\n\t\t\tset {\n\t\t\t\toption = value;\n\n\t\t\t\tif (Options != null && Options.Length > 0) {\n\t\t\t\t\tLabel = $\"{Locale.Get(Name)}: {Locale.Get(Options[Option])}\";\n\t\t\t\t\tRelativeCenterX = cx;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic string Name = \"\";\n\t\tpublic string[] Options;\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tcx = RelativeX;\n\t\t\tOption = option;\n\t\t}\n\n\t\tpublic override void OnClick() {\n\t\t\tif (!Disabled) {\n\t\t\t\tvar o = Option + (Input.Mouse.CheckRightButton ? -1 : 1);\n\n\t\t\t\tif (o < 0) {\n\t\t\t\t\tOption = Options.Length - 1;\n\t\t\t\t} else if (o >= Options.Length) {\n\t\t\t\t\tOption = 0;\n\t\t\t\t} else {\n\t\t\t\t\tOption = o;\n\t\t\t\t}\n\n\t\t\t\tbase.OnClick();\n\t\t\t}\n\t\t}\n\n\t\tpublic Action<UiChoice> OnUpdate;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tOnUpdate?.Invoke(this);\n\t\t\tbase.Update(dt);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiControl.cs",
    "content": "using BurningKnight.assets.input;\r\nusing BurningKnight.entity.component;\r\nusing Lens.assets;\r\nusing Lens.input;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace BurningKnight.ui {\r\n\tpublic class UiControl : UiButton {\r\n\t\tpublic static UiControl Focused;\r\n\t\tpublic string Key;\r\n\t\tpublic bool Gamepad;\r\n\t\tpublic GamepadComponent GamepadComponent;\r\n\r\n\t\tprivate float cx;\r\n\t\tprivate bool firstClickFrame;\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\tcx = RelativeX;\r\n\t\t\tSetLabel();\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (Focused == this) {\r\n\t\t\t\tFocused = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void OnClick() {\r\n\t\t\tbase.OnClick();\r\n\r\n\t\t\tif (Focused == this) {\r\n\t\t\t\t// Focused = null;\r\n\t\t\t\t// SetLabel();\r\n\t\t\t} else {\r\n\t\t\t\tfirstFrame = true;\r\n\t\t\t\tfirstClickFrame = true;\r\n\t\t\t\tFocused = this;\r\n\t\t\t\tLabel = $\"{Locale.Get(Key)}: {Locale.Get(\"select\")}\";\r\n\t\t\t\tRelativeCenterX = cx;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate void SetLabel() {\r\n\t\t\tvar k = Controls.Find(Key, Gamepad);\r\n\t\t\t\r\n\t\t\tLabel = $\"{Locale.Get(Key)}: {k}\";\r\n\t\t\tRelativeCenterX = cx;\r\n\t\t}\r\n\r\n\t\tprivate static Keys[] keysToCheck = {\r\n\t\t\tKeys.Q, Keys.W, Keys.E, Keys.R, Keys.T, Keys.Y, Keys.U, Keys.I, Keys.O, Keys.P,\r\n\t\t\tKeys.A, Keys.S, Keys.D, Keys.F, Keys.G, Keys.H, Keys.J, Keys.K, Keys.L,\r\n\t\t\tKeys.Z, Keys.X, Keys.C, Keys.V, Keys.B, Keys.N, Keys.M, \r\n\t\t\tKeys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, Keys.D9,\r\n\t\t\r\n\t\t\tKeys.Space, Keys.LeftShift, Keys.LeftControl, Keys.LeftWindows, Keys.LeftAlt, Keys.Tab, Keys.CapsLock\r\n\t\t};\r\n\r\n\t\tprivate static MouseButtons[] mouseToCheck = {\r\n\t\t\tMouseButtons.Left, MouseButtons.Middle, MouseButtons.Right\r\n\t\t};\r\n\r\n\t\tprivate static Buttons[] buttonsToCheck = {\r\n\t\t\tButtons.A, Buttons.B, Buttons.X, Buttons.Y, Buttons.LeftShoulder, Buttons.RightShoulder,\r\n\t\t\tButtons.LeftStick, Buttons.RightStick, Buttons.LeftTrigger, Buttons.RightTrigger,\r\n\t\t\tButtons.DPadDown, Buttons.DPadUp, Buttons.DPadLeft, Buttons.DPadRight\r\n\t\t};\r\n\r\n\t\tpublic void Cancel() {\r\n\t\t\tFocused = null;\r\n\t\t\tSetLabel();\r\n\t\t}\r\n\r\n\t\tprivate bool firstFrame;\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (firstFrame) {\r\n\t\t\t\tfirstFrame = false;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tDoCheck();\r\n\t\t}\r\n\r\n\t\tpublic void DoCheck() {\r\n\t\t\tif (firstFrame) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (Focused == this) {\r\n\t\t\t\tif (Gamepad) {\r\n\t\t\t\t\tif (GamepadComponent.Controller == null) {\r\n\t\t\t\t\t\tLog.Error(\"Null controller\");\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\r\n\t\t\t\t\tforeach (var b in buttonsToCheck) {\r\n\t\t\t\t\t\tif (GamepadComponent.Controller.WasPressed(b)) {\r\n\t\t\t\t\t\t\tControls.Replace(Key, b);\r\n\t\t\t\t\t\t\tControls.Bind();\r\n\t\t\t\t\t\t\tControls.Save();\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tFocused = null;\r\n\t\t\t\t\t\t\tSetLabel();\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tforeach (var k in keysToCheck) {\r\n\t\t\t\t\t\tif (Input.Keyboard.WasPressed(k)) {\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tControls.Replace(Key, k);\r\n\t\t\t\t\t\t\tControls.Bind();\r\n\t\t\t\t\t\t\tControls.Save();\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tFocused = null;\r\n\t\t\t\t\t\t\tSetLabel();\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (firstClickFrame) {\r\n\t\t\t\t\t\tfirstClickFrame = false;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tforeach (var b in mouseToCheck) {\r\n\t\t\t\t\t\t\tif (Input.Mouse.Check(b, Input.CheckType.PRESSED)) {\r\n\r\n\t\t\t\t\t\t\t\tControls.Replace(Key, b);\r\n\t\t\t\t\t\t\t\tControls.Bind();\r\n\t\t\t\t\t\t\t\tControls.Save();\r\n\r\n\t\t\t\t\t\t\t\tFocused = null;\r\n\t\t\t\t\t\t\t\tSetLabel();\r\n\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/UiDescriptionBanner.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.item;\nusing BurningKnight.ui.str;\nusing Lens;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Timer = Lens.util.timer.Timer;\n\nnamespace BurningKnight.ui {\n\tpublic class UiDescriptionBanner : UiString {\n\t\tprivate static UiDescriptionBanner last;\n\t\t\n\t\tprivate string title;\n\t\tprivate int titleWidth;\n\t\t\n\t\tpublic UiDescriptionBanner() : base(Font.Small) {\n\t\t\tif (last != null) {\n\t\t\t\tlast.Done = true;\n\t\t\t}\n\t\t\t\n\t\t\tlast = this;\n\t\t}\n\n\t\tpublic void Show(Item item) {\n\t\t\tTint = Color.White;\n\t\t\tTint.A = 0;\n\n\t\t\tTween.To(255, 0, x => Tint.A = (byte) x, 0.4f);\n\n\t\t\t\n\t\t\ttitle = item.Name;\n\t\t\tLabel = item.Description;\n\t\t\tDepth = 3;\n\n\t\t\tvar size = Font.Small.MeasureString(Label);\n\n\t\t\tWidth = size.Width;\n\t\t\tHeight = size.Height;\n\t\t\tFinishTyping();\n\n\t\t\tCenterX = Display.UiWidth / 2f;\n\t\t\tY = 64f;\n\n\t\t\ttitleWidth = (int) Font.Medium.MeasureString(title).Width;\n\n\t\t\tTimer.Add(() => {\n\t\t\t\tTween.To(0, 255, x => Tint.A = (byte) x, 0.3f).OnEnd = () => {\n\t\t\t\t\ttitle = null;\n\t\t\t\t\tDone = true;\n\t\t\t\t};\n\t\t\t}, 3f);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (last == this) {\n\t\t\t\tlast = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (title == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tGraphics.Color = Tint;\n\t\t\tGraphics.Print(title, Font.Medium, new Vector2((Display.UiWidth - titleWidth) / 2f, Y - 16));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\tbase.Render();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiEntity.cs",
    "content": "﻿using System;\nusing BurningKnight.assets.input;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.input;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiEntity : Entity {\n\t\tpublic UiEntity Super;\n\t\tpublic bool Clickable = true;\n\n\t\tpublic bool Enabled {\n\t\t\tset {\n\t\t\t\tVisible = value;\n\t\t\t\tActive = value;\n\t\t\t}\n\t\t}\n\n\t\t#region Relative Position\n\t\tpublic Vector2 RelativePosition;\n\n\t\tpublic float RelativeX {\n\t\t\tget => Centered ? RelativePosition.X - Width / 2 : RelativePosition.X;\n\t\t\tset => RelativePosition.X = Centered ? value + Width / 2 : value;\n\t\t}\n\n\t\tpublic float RelativeY {\n\t\t\tget => Centered ? RelativePosition.Y - Height / 2 : RelativePosition.Y;\n\t\t\tset => RelativePosition.Y = Centered ? value + Height / 2 : value;\n\t\t}\n\n\t\tpublic Vector2 RelativeCenter {\n\t\t\tget => new Vector2(RelativeCenterX, RelativeCenterY);\n\t\t\tset {\n\t\t\t\tRelativeX = value.X - Width / 2;\n\t\t\t\tRelativeY = value.Y - Height / 2;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic float RelativeCenterX {\n\t\t\tget => RelativeX + Width / 2;\n\t\t\tset => RelativeX = value - Width / 2;\n\t\t}\n\n\t\tpublic float RelativeCenterY {\n\t\t\tget => RelativeY + Height / 2;\n\t\t\tset => RelativeY = value - Height / 2;\n\t\t}\n\n\t\tpublic float RelativeRight => RelativeX + Width;\n\t\tpublic float RelativeBottom => RelativeY + Height;\n\t\t#endregion\n\t\t\n\t\tprotected bool hovered;\n\t\tprotected float angle;\n\t\tprotected internal float scale = 1f;\n\t\tprotected Vector2 origin = new Vector2(0);\n\n\t\tpublic float AngleMod = 1f;\n\t\tpublic float ScaleMod = 1f;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic virtual bool CheckCollision(Vector2 v) {\n\t\t\treturn Contains(v);\n\t\t}\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tbool was = hovered;\n\t\t\thovered = CheckCollision(Input.Mouse.UiPosition);\n\n\t\t\tif (hovered) {\n\t\t\t\tif (!was) {\n\t\t\t\t\tOnHover();\n\t\t\t\t}\n\n\t\t\t\tif (Input.WasPressed(Controls.UiAccept)) {\n\t\t\t\t\tOnClick();\n\t\t\t\t}\n\t\t\t} else if (!hovered && was) {\n\t\t\t\tOnUnhover();\n\t\t\t}\n\n\t\t\tangle = (float) Math.Cos(Engine.Time * 3f + Y / (Display.UiHeight * 0.5f) * Math.PI) * (scale - 0.9f) * AngleMod / Math.Max(1, Width * 0.04f);\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PlaySfx(string sfx) {\n\t\t\tif (Settings.UiSfx) {\n\t\t\t\tAudio.PlaySfx(sfx, 0.5f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected virtual void OnHover() {\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1 + ScaleMod * 0.2f, scale, x => scale = x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void OnUnhover() {\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1f, scale, x => scale = x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void OnClick() {\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1 - ScaleMod * 0.5f, scale, x => scale = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, scale, x => scale = x, 0.2f);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiError.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.assets.achievements;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiError : FrameRenderer {\n\t\tprivate const int Padding = 6;\n\t\t\n\t\tprivate string title;\n\t\tprivate string description;\n\t\tprivate TextureRegion icon;\n\t\tprivate TextureRegion iconBg;\n\n\t\tprivate Vector2 bgOffset;\n\t\tprivate Vector2 iconOffset;\n\t\tprivate Vector2 titleOffset;\n\t\tprivate Vector2 descriptionOffset;\n\n\t\tpublic UiError(string t, string desc) {\n\t\t\ttitle = t;\n\t\t\tdescription = desc;\n\t\t\ticon = Animations.Get(\"items\").GetSlice(\"bk:no_hat\");\n\t\t\ticonBg = CommonAse.Ui.GetSlice(\"er_bg\");\n\n\t\t\tvar titleSize = Font.Small.MeasureString(title);\n\t\t\tvar descriptionSize = Font.Small.MeasureString(description);\n\n\t\t\tbgOffset = new Vector2(Padding);\n\t\t\ticonOffset = new Vector2(Padding + (20 - icon.Width) / 2f, Padding + (20 - icon.Height) / 2f);\n\t\t\ttitleOffset = new Vector2(Padding * 2 + 20, Padding - 1);\n\t\t\tdescriptionOffset = new Vector2(Padding * 2 + 20, Padding + 10);\n\n\t\t\tWidth = Math.Max(128, (Math.Max(titleSize.Width, descriptionSize.Width) + 22 + Padding * 3));\n\t\t\tHeight = 20 + Padding * 2;\n\t\t\tDepth = 32;\n\n\t\t\tX = Display.UiWidth - Width - 8;\n\t\t}\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\tSetup(\"ui\", \"er_\");\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\n\t\t\tTween.To(Display.UiHeight - 8 - Height, Y, x => Y = x, 0.7f, Ease.BackOut).OnEnd = () => {\n\t\t\t\tvar t = Tween.To(Display.UiHeight + 2, Y, x => Y = x, 0.5f, Ease.BackIn);\n\n\t\t\t\tt.Delay = 5f;\n\t\t\t\tt.OnStart = () => {\n\t\t\t\t\tDepth--;\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tt.OnEnd = () => {\n\t\t\t\t\tDone = true;\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tbase.Render();\n\n\t\t\tGraphics.Render(iconBg, Position + bgOffset);\n\t\t\tGraphics.Render(icon, Position + iconOffset);\n\t\t\tGraphics.Print(title, Font.Small, Position + titleOffset);\n\t\t\tGraphics.Print(description, Font.Small, Position + descriptionOffset);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiImageButton.cs",
    "content": "using BurningKnight.assets;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiImageButton : UiButton {\n\t\tprivate string id;\n\t\tpublic float Size = 2;\n\n\t\tpublic string Id {\n\t\t\tget => id;\n\n\t\t\tset {\n\t\t\t\tid = value;\n\n\t\t\t\tif (id == null) {\n\t\t\t\t\tRegion = null;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tRegion = CommonAse.Ui.GetSlice(id);\n\t\t\t\tWidth = Region.Width * Size;\n\t\t\t\tHeight = Region.Height * Size;\n\t\t\t}\n\t\t}\n\n\t\tpublic TextureRegion Region;\n\n\t\tpublic override void Render() {\n\t\t\tGraphics.Render(Region, Center, 0, Region.Center, new Vector2(scale * Size));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiLabel.cs",
    "content": "﻿using System;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended.BitmapFonts;\n\nnamespace BurningKnight.ui {\n\tpublic class UiLabel : UiEntity {\n\t\tpublic const float DefaultTint = 0.7f;\n\t\t\n\t\tprotected string label;\n\t\tpublic BitmapFont Font = assets.Font.Medium;\n\t\tpublic float Tint = DefaultTint;\n\t\tpublic bool Tints = true;\n\t\tpublic bool Hide;\n\n\t\tprotected override void OnHover() {\n\t\t\tif (Hide) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.OnHover();\n\t\t\t\n\t\t\tPlaySfx(\"ui_moving\");\n\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1, Tint, x => Tint = x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnUnhover() {\n\t\t\tif (Hide) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.OnUnhover();\n\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(DefaultTint, Tint, x => Tint = x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void OnClick() {\n\t\t\tif (Hide) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbase.OnClick();\n\n\t\t\tif (Clickable) {\n\t\t\t\tTint = 0.5f;\n\t\t\t\tTween.To(1, Tint, x => Tint = x, 0.2f);\n\t\t\t}\n\t\t}\n\n\t\tpublic string Label {\n\t\t\tget => label;\n\n\t\t\tset {\n\t\t\t\tif (label != value) {\n\t\t\t\t\tlabel = value;\n\t\t\t\t\t\n\t\t\t\t\tvar size = Font.MeasureString(label);\n\n\t\t\t\t\tWidth = size.Width;\n\t\t\t\t\tHeight = size.Height;\n\t\t\t\t\t\n\t\t\t\t\torigin = new Vector2(Width / 2, Height / 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic string LocaleLabel {\n\t\t\tset => Label = Locale.Get(value);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Hide) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (Tints) {\n\t\t\t\tvar t = Tint + ((Tint - DefaultTint) * ((float) Math.Cos(Engine.Time * 17) * 0.5f - 0.5f) * 0.5f);\n\t\t\t\tGraphics.Color = new Color(t, t, t, 1f);\n\t\t\t}\n\n\t\t\tGraphics.Print(label, Font, Position + origin, angle, origin, new Vector2(scale));\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiMap.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.projectile;\nusing BurningKnight.entity.room;\nusing BurningKnight.level.rooms;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util.geometry;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.ui {\n\tpublic class UiMap : Entity {\n\t\tprivate const int W = 64;\n\t\tprivate const int H = 64;\n\n\t\tprivate static Vector2 scale = new Vector2(1f);\n\t\tprivate static Vector2 bigScale = new Vector2(3f);\n\t\tprivate static Color doorColor = new Color(93, 44, 40);\n\n\t\tprivate Player player;\n\t\tprivate TextureRegion slice;\n\n\t\tprivate TextureRegion playerIcon;\n\t\tprivate TextureRegion frame;\n\n\t\tprivate RenderTarget2D target;\n\n\t\tpublic UiMap(Player pl) {\n\t\t\tplayer = pl;\n\t\t\ttarget = new RenderTarget2D(Engine.GraphicsDevice, W, H, false, Engine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24);\n\n\t\t\tWidth = W;\n\t\t\tHeight = H;\n\n\t\t\tX = Display.UiWidth - W - 11;\n\t\t\tY = 11;\n\n\t\t\tslice = CommonAse.Particles.GetSlice(\"fire\");\n\n\t\t\tplayerIcon = CommonAse.Ui.GetSlice(\"gps\");\n\t\t\tframe = CommonAse.Ui.GetSlice(\"map_frame\");\n\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\ttarget.Dispose();\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (!Settings.Minimap || Engine.Instance.State.Paused || Run.Type == RunType.Twitch) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (player.TryGetComponent<PlayerInputComponent>(out var inp) && inp.InDialog) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar fx = player.CenterX / 16;\n\t\t\tvar fy = player.CenterY / 16;\n\t\t\tvar x = (int) Math.Floor(fx);\n\t\t\tvar y = (int) Math.Floor(fy);\n\t\t\tvar level = Run.Level;\n\n\t\t\tvar sx = MathUtils.Clamp(0, level.Width - 1, x - W / 2);\n\t\t\tvar sy = MathUtils.Clamp(0, level.Height - 1, y - H / 2);\n\t\t\tvar tx = MathUtils.Clamp(0, level.Width - 1, x + W / 2);\n\t\t\tvar ty = MathUtils.Clamp(0, level.Height - 1, y + H / 2);\n\t\t\tvar rect = new Rect(sx, sy, tx, ty);\n\n\t\t\tvar r = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer;\n\n\t\t\tr.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(target);\n\t\t\tGraphics.Clear(Color.Transparent);\n\t\t\tr.BeginUi(true);\n\n\t\t\tGraphics.Color = ColorUtils.BlackColor;\n\t\t\tGraphics.Color.A = 150;\n\t\t\tGraphics.Render(slice, Vector2.Zero, 0, Vector2.Zero, new Vector2(W, H));\n\t\t\tGraphics.Color.A = 255;\n\n\t\t\tforeach (var rm in level.Area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) rm;\n\n\t\t\t\tif (room.Explored && rect.Intersects(room.Rect)) {\n\t\t\t\t\tfor (var yy = room.MapY - 1; yy < room.MapY + room.MapH; yy++) {\n\t\t\t\t\t\tfor (var xx = room.MapX; xx < room.MapX + room.MapW; xx++) {\n\t\t\t\t\t\t\tvar i = level.ToIndex(xx, yy);\n\n\t\t\t\t\t\t\tif (level.Explored[i] && !level.Get(i).IsWall() && xx >= sx && xx <= tx && yy >= sy && yy <= ty) {\n\t\t\t\t\t\t\t\tGraphics.Render(slice, new Vector2((int) Math.Floor(W / 2 + (xx - fx)) - 1, (int) Math.Floor(H / 2 + (yy - fy)) - 1), 0, Vector2.Zero, bigScale);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar cl = Run.Level.Biome.GetMapColor();\n\t\t\tGraphics.Color = cl;\n\n\t\t\tforeach (var rm in level.Area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) rm;\n\n\t\t\t\tif (room.Explored && rect.Intersects(room.Rect)) {\n\t\t\t\t\tfor (var yy = room.MapY; yy < room.MapY + room.MapH; yy++) {\n\t\t\t\t\t\tfor (var xx = room.MapX; xx < room.MapX + room.MapW; xx++) {\n\t\t\t\t\t\t\tvar i = level.ToIndex(xx, yy);\n\n\t\t\t\t\t\t\tif (level.Explored[i] && !level.Get(i).IsWall() && xx >= sx && xx <= tx && yy >= sy && yy <= ty) {\n\t\t\t\t\t\t\t\tGraphics.Render(slice, new Vector2((int) Math.Floor(W / 2 + (xx - fx)), (int) Math.Floor(H / 2 + (yy - fy))), 0, Vector2.Zero, scale);\n\t\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\t\tif (room.Explored && !(room.Type == RoomType.Granny || room.Type == RoomType.OldMan || room.Type == RoomType.Boss)) {\n\t\t\t\t\t\t\t\tGraphics.Color = doorColor;\n\n\t\t\t\t\t\t\t\tforeach (var d in room.Doors) {\n\t\t\t\t\t\t\t\t\tGraphics.Render(slice, new Vector2((int) Math.Floor(W / 2 - fx + (int) Math.Floor(d.CenterX / 16)), (int) Math.Floor(H / 2 - fy + (int) Math.Floor(d.Bottom / 16))));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tGraphics.Color = cl;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\n\t\t\tforeach (var rm in level.Area.Tagged[Tags.Room]) {\n\t\t\t\tvar room = (Room) rm;\n\n\t\t\t\tif (!room.Explored) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar tp = room.Type;\n\n\t\t\t\tif (tp == RoomType.Exit ? Run.Depth % 2 == 1 : RoomTypeHelper.ShouldBeDisplayOnMap(tp)) {\n\t\t\t\t\tif (rect.Intersects(room.Rect)) {\n\t\t\t\t\t\tvar icon = RoomTypeHelper.Icons[(int) tp];\n\t\t\t\t\t\tGraphics.Render(icon, new Vector2((int) Math.Floor(W * 0.5f + (int) Math.Floor(room.MapX + room.MapW * 0.5f) - fx), (int) Math.Floor(H * 0.5f + (int) Math.Floor(room.MapY + room.MapH * 0.5f) - fy)), 0, icon.Center);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGraphics.Render(playerIcon, new Vector2(W / 2f, H / 2f), 0, playerIcon.Center);\n\n\t\t\tr.End();\n\t\t\tr.Begin();\n\n\t\t\tGraphics.Render(target, Position);\n\t\t\tGraphics.Render(frame, Position - new Vector2(3));\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiPane.cs",
    "content": "using System.Collections.Generic;\nusing Lens;\n\nnamespace BurningKnight.ui {\n\tpublic class UiPane : UiEntity {\n\t\tprivate bool enabled = true;\n\n\t\tpublic bool Enabled {\n\t\t\tget => enabled;\n\n\t\t\tset {\n\t\t\t\tif (value == enabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tenabled = value;\n\n\t\t\t\tforeach (var e in Entities) {\n\t\t\t\t\te.Active = enabled;\n\t\t\t\t\te.Visible = enabled;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic List<UiEntity> Entities = new List<UiEntity>();\n\n\t\tpublic void Setup() {\n\t\t\tforeach (var e in Entities) {\n\t\t\t\te.Position = Position + e.RelativePosition;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tWidth = Display.UiWidth;\n\t\t\tHeight = Display.UiHeight;\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (Enabled) {\n\t\t\t\tSetup();\n\t\t\t}\n\t\t}\n\n\t\tpublic UiEntity Add(UiEntity entity) {\n\t\t\tEntities.Add(entity);\n\t\t\tentity.Super = this;\n\n\t\t\tArea.Add(entity);\n\n\t\t\treturn entity;\n\t\t}\n\n\t\tpublic void Remove(UiEntity entity) {\n\t\t\tEntities.Remove(entity);\n\t\t\tentity.Super = null;\n\t\t\tentity.Done = true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiSlider.cs",
    "content": "using System;\r\nusing BurningKnight.assets.input;\r\nusing BurningKnight.entity.component;\r\nusing Lens.input;\r\nusing Lens.util.tween;\r\n\r\nnamespace BurningKnight.ui {\r\n\tpublic static class UiSlider {\r\n\t\tpublic static UiSliderLabel Make(UiPane pane, float x, float y, string label, int value, int max = 100, int min = 0) {\r\n\t\t\tvar a = (UiSliderButton) pane.Add(new UiSliderButton {\r\n\t\t\t\tLocaleLabel = label,\r\n\t\t\t\tRelativeX = x,\r\n\t\t\t\tRelativeCenterY = y\r\n\t\t\t});\r\n\r\n\t\t\tUiSliderLabel c = null;\r\n\r\n\t\t\tvar b = pane.Add(new UiButton {\r\n\t\t\t\tLabel = \"-\",\r\n\t\t\t\tXPadding = 4,\r\n\t\t\t\tSelectable = false,\r\n\t\t\t\tRelativeX = x + a.Width + 10,\r\n\t\t\t\tType = ButtonType.Slider,\r\n\t\t\t\tRelativeCenterY = y,\r\n\t\t\t\tClick = bt => {\r\n\t\t\t\t\tc.Value = Math.Max(min, c.Value - 10);\r\n\t\t\t\t},\r\n\t\t\t\tScaleMod = 3\r\n\t\t\t});\r\n\r\n\t\t\tc = (UiSliderLabel) pane.Add(new UiSliderLabel {\r\n\t\t\t\tLabel = $\"{value}%\",\r\n\t\t\t\tRelativeX = x + a.Width + b.Width + 20,\r\n\t\t\t\tRelativeCenterY = y,\r\n\t\t\t\tClick = bt => {\r\n\t\t\t\t\tvar n = (UiSliderLabel) bt;\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (Input.Mouse.CheckRightButton) {\r\n\t\t\t\t\t\tn.Value = Math.Max(min, n.Value - 10);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tn.Value = Math.Min(max, n.Value + 10);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tc.Value = value;\r\n\t\t\t\r\n\t\t\tvar d = pane.Add(new UiButton {\r\n\t\t\t\tLabel = \"+\",\r\n\t\t\t\tXPadding = 4,\r\n\t\t\t\tSelectable = false,\r\n\t\t\t\tType = ButtonType.Slider,\r\n\t\t\t\tRelativeX = x + a.Width + b.Width + c.Width + 30,\r\n\t\t\t\tRelativeCenterY = y,\r\n\t\t\t\tClick = bt => {\r\n\t\t\t\t\tc.Value = Math.Min(max, c.Value + 10);\r\n\t\t\t\t},\r\n\t\t\t\tScaleMod = 3\r\n\t\t\t});\r\n\r\n\t\t\tvar m = (d.RelativeX + d.Width - a.RelativeX) / 2f;\r\n\t\t\t\r\n\t\t\ta.RelativeX -= m;\r\n\t\t\tb.RelativeX -= m;\r\n\t\t\tc.RelativeX -= m;\r\n\t\t\td.RelativeX -= m;\r\n\r\n\t\t\ta.Minus = (UiButton) b;\r\n\t\t\ta.Plus = (UiButton) d;\r\n\r\n\t\t\treturn c;\r\n\t\t}\r\n\r\n\t\tpublic class UiSliderLabel : UiButton {\r\n\t\t\tprivate int value;\r\n\t\t\tpublic Action<UiSliderLabel> OnValueChange;\r\n\r\n\t\t\tpublic override void Init() {\r\n\t\t\t\tbase.Init();\r\n\t\t\t\tSelectable = false;\r\n\t\t\t}\r\n\r\n\t\t\tpublic int Value {\r\n\t\t\t\tget => value;\r\n\r\n\t\t\t\tset {\r\n\t\t\t\t\tif (this.value == value) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tthis.value = value;\r\n\t\t\t\t\tLabel = $\"{value}%\";\r\n\r\n\t\t\t\t\tscale = 1.5f;\r\n\t\t\t\t\tTween.To(1f, scale, x => scale = x, 0.3f);\r\n\t\t\t\t\t\r\n\t\t\t\t\tOnValueChange?.Invoke(this);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic class UiSliderButton : UiButton {\r\n\t\t\tpublic UiButton Minus;\r\n\t\t\tpublic UiButton Plus;\r\n\t\t\t\r\n\t\t\tpublic override void Update(float dt) {\r\n\t\t\t\tbase.Update(dt);\r\n\t\t\t\t\r\n\t\t\t\tif (Selected == Id) {\r\n\t\t\t\t\tif (Input.WasPressed(Controls.UiLeft, GamepadComponent.Current, true)) {\r\n\t\t\t\t\t\tMinus.OnClick();\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tif (Input.WasPressed(Controls.UiRight, GamepadComponent.Current, true)) {\r\n\t\t\t\t\t\tPlus.OnClick();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/UiTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.entity.projectile;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiTable : UiEntity {\n\t\tprivate const float EntryHeight = 15;\n\t\t\n\t\tprivate List<UiTableEntry> entries = new List<UiTableEntry>();\n\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tWidth = 128 + 16;\n\t\t}\n\n\t\tpublic void Clear() {\n\t\t\tforeach (var e in entries) {\n\t\t\t\t((UiPane) Super).Remove(e);\n\t\t\t}\n\t\t\t\n\t\t\tentries.Clear();\n\t\t}\n\n\t\tpublic void Add(string key, string value, bool h = false, Action<UiButton> a = null) {\n\t\t\tvalue = value ?? \"\";\n\n\t\t\tvar entry = new UiTableEntry() {\n\t\t\t\tLabel = key ?? \"\",\n\t\t\t\tValue = value,\n\t\t\t\tClick = a\n\t\t\t};\n\n\t\t\tif (h) {\n\t\t\t\tentry.Color = ProjectileColor.Cyan;\n\t\t\t}\n\n\t\t\t((UiPane) Super).Add(entry);\n\t\t\tentries.Add(entry);\n\t\t}\n\n\t\tpublic void Prepare() {\n\t\t\tClickable = false;\n\t\t\tHeight = entries.Count * EntryHeight;\n\t\t\t\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tvar p = ((UiPane) Super).Position;\n\t\t\t\n\t\t\tfor (var i = 0; i < entries.Count; i++) {\n\t\t\t\tvar e = entries[i];\n\t\t\t\t\n\t\t\t\te.RelativeX = RelativeX;\n\t\t\t\te.RelativeY = RelativeY + i * EntryHeight;\n\t\t\t\te.Position = p + e.RelativePosition;\n\n\t\t\t\tif (e.Hidden) {\n\t\t\t\t\te.Hidden = false;\n\t\t\t\t\te.scale = 0;\n\n\t\t\t\t\tTween.To(1, 0, x => e.scale = x, Rnd.Float(0.3f, 0.5f));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/UiTableEntry.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui {\n\tpublic class UiTableEntry : UiButton {\n\t\tprivate const float XPadding = 3;\n\t\tpublic const float YPadding = 1;\n\t\t\n\t\tprivate TextureRegion texture;\n\t\tprivate string value;\n\t\tprivate float vw;\n\t\tprivate Vector2 textOrigin;\n\t\tprivate Vector2 valueOrigin;\n\n\t\tpublic Color Color = ColorUtils.WhiteColor;\n\t\tpublic bool Hidden = true;\n\n\t\tpublic UiTableEntry() {\n\t\t\tFont = assets.Font.Small;\n\t\t}\n\n\t\tpublic string Value {\n\t\t\tset {\n\t\t\t\tthis.value = value;\n\t\t\t\tvw = Font.MeasureString(this.value).Width;\n\t\t\t}\n\t\t}\n\n\t\tpublic string RealLocaleLabel {\n\t\t\tset {\n\t\t\t\tlabel = Locale.Get(value);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\n\t\t\ttexture = CommonAse.Ui.GetSlice(\"table_item\");\n\t\t\tWidth = texture.Width;\n\t\t\tHeight = texture.Height;\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\t\n\t\t\tif (Click == null) {\n\t\t\t\tRemoveTag(Tags.Button);\n\t\t\t\tClickable = false;\n\t\t\t\tScaleMod = 0;\n\t\t\t}\n\n\t\t\ttextOrigin = new Vector2(Width / 2f, Height / 2f);\n\t\t\tvalueOrigin = new Vector2(-Width / 2f + vw, Height / 2f);\n\t\t}\n\n\t\tprotected override void OnHover() {\n\t\t\tbase.OnHover();\n\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1 + ScaleMod * 0.2f, Depth, x => Depth = (int) x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnUnhover() {\n\t\t\tbase.OnUnhover();\n\n\t\t\tif (Clickable) {\n\t\t\t\tTween.To(1f, Depth, x => Depth = (int) x, 0.1f);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (Hidden) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar or = texture.Center;\n\t\t\tvar s = new Vector2(scale);\n\t\t\t\n\t\t\tGraphics.Color.A = 220;\n\t\t\tGraphics.Render(texture, Position + or, angle, or, s);\n\t\t\tGraphics.Color.A = 255;\n\n\t\t\tif (Clickable) {\n\t\t\t\tvar t = Tint + ((Tint - DefaultTint) * ((float) Math.Cos(Engine.Time * 17) * 0.5f - 0.5f) * 0.5f);\n\t\t\t\tGraphics.Color = new Color(Color.R / 255f * t, Color.G / 255f * t, Color.B / 255f * t, Color.A / 255f);\n\t\t\t} else {\n\t\t\t\tGraphics.Color = Color;\n\t\t\t}\n\n\t\t\tGraphics.Print(label, Font, new Vector2(X + XPadding, Y + YPadding) + textOrigin, angle, textOrigin, s);\n\t\t\tGraphics.Print(value, Font, new Vector2(Right - vw - XPadding, Y + YPadding) + valueOrigin, angle, valueOrigin, s);\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/AnswerDialog.cs",
    "content": "using Lens.assets;\r\nusing Lens.input;\r\nusing Lens.util.math;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace BurningKnight.ui.dialog {\r\n\tpublic class AnswerDialog : Dialog {\r\n\t\t// Keep in sync with AnswerType!\r\n\t\tpublic static string[] Types = {\r\n\t\t\t\"Text\", \"Seed\"\r\n\t\t};\r\n\t\t\r\n\t\tpublic string Answer = \"\";\r\n\t\tpublic bool Focused = true;\r\n\t\tpublic AnswerType Type;\r\n\t\t\r\n\t\tpublic AnswerDialog(string id, AnswerType type, string[] next = null) : base(id, next) {\r\n\t\t\tType = type;\r\n\t\t}\r\n\r\n\t\tpublic override void Reset() {\r\n\t\t\tbase.Reset();\r\n\r\n\t\t\tFocused = true;\r\n\t\t\tAnswer = \"\";\r\n\t\t}\r\n\r\n\t\tpublic override string Modify(string dialog) {\r\n\t\t\treturn $\"{dialog}\\n[rn 0] \";\r\n\t\t}\r\n\r\n\t\tpublic void HandleInput(TextInputEventArgs args) {\r\n\t\t\tif (args.Key == Keys.Back) {\r\n\t\t\t\tif (Answer.Length > 0) {\r\n\t\t\t\t\tAnswer = Answer.Substring(0, Answer.Length - 1);\r\n\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\r\n\t\t\t\t}\r\n\t\t\t} else if (args.Key == Keys.Enter) {\r\n\t\t\t\tFocused = false;\r\n\t\t\t} else {\r\n\t\t\t\tvar c = CheckChar(args.Character);\r\n\t\t\t\t\r\n\t\t\t\tif (c != '\\0') {\r\n\t\t\t\t\tAnswer += c;\t\r\n\t\t\t\t\tAudio.PlaySfx(\"ui_moving\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate char CheckChar(char c) {\r\n\t\t\tswitch (Type) {\r\n\t\t\t\tcase AnswerType.Text: return c;\r\n\r\n\t\t\t\tcase AnswerType.Seed: {\r\n\t\t\t\t\tif (char.IsLower(c)) {\r\n\t\t\t\t\t\tc = char.ToUpper(c);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\treturn Answer.Length < 8 && Rnd.SeedChars.IndexOf(c) != -1 && c != '_' ? c : '\\0';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn '\\0';\r\n\t\t}\r\n\r\n\t\tprivate void AttachLetter(char c) {\r\n\t\t\tif (!Focused) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tAnswer += c;\r\n\r\n\t\t\tif (Answer.Length == 8) {\r\n\t\t\t\tFocused = false;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic void CheckGamepadInput(GamepadData data) {\r\n\t\t\tif (data.WasPressed(Buttons.X)) {\r\n\t\t\t\tAttachLetter('X');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.Y)) {\r\n\t\t\t\tAttachLetter('Y');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.A)) {\r\n\t\t\t\tAttachLetter('A');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.B)) {\r\n\t\t\t\tAttachLetter('B');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.DPadUp)) {\r\n\t\t\t\tAttachLetter('U');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.DPadDown)) {\r\n\t\t\t\tAttachLetter('D');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.DPadLeft)) {\r\n\t\t\t\tAttachLetter('L');\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (data.WasPressed(Buttons.DPadRight)) {\r\n\t\t\t\tAttachLetter('R');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/AnswerType.cs",
    "content": "namespace BurningKnight.ui.dialog {\r\n\tpublic enum AnswerType {\r\n\t\tText,\r\n\t\tSeed\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/ChoiceDialog.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Lens.assets;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.ui.dialog {\n\tpublic class ChoiceDialog : Dialog {\n\t\tpublic readonly string[] Options;\n\t\tpublic readonly List<string[]> Branches;\n\t\tpublic Action<string, int> Callback;\n\n\t\tpublic int Choice;\n\t\tpublic int Last;\n\t\t\n\t\tpublic ChoiceDialog(string id, string[] options, List<string[]> branches, Action<string, int> callback = null) : base(id) {\n\t\t\tOptions = options;\n\t\t\tBranches  = branches;\n\t\t\tCallback = callback;\n\t\t}\n\n\t\tpublic override string Modify(string dialog) {\n\t\t\tvar builder = new StringBuilder();\n\t\t\tvar i = 0;\n\n\t\t\tbuilder.Append(dialog).Append(\"\\n[skp]\");\n\n\t\t\tforeach (var option in Options) {\n\t\t\t\tbuilder.Append($\"[rn {i}]  \").Append(Locale.Get(option));\n\t\t\t\ti++;\n\n\t\t\t\tif (i < Options.Length) {\n\t\t\t\t\tbuilder.Append('\\n');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn builder.ToString();\n\t\t}\n\n\t\tpublic override string DecideNext() {\n\t\t\tif (Branches.Count == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar array = Branches[Choice];\n\t\t\tvar option = array.Length == 0 ? null : array[Rnd.Int(array.Length)]; \n\t\t\t\n\t\t\tCallback?.Invoke(option, Choice);\n\t\t\t\n\t\t\tLast = Choice;\n\t\t\tChoice = 0;\n\t\t\t\n\t\t\treturn option;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/CombineDialog.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Lens.assets;\n\nnamespace BurningKnight.ui.dialog {\n\tpublic class CombineDialog : ChoiceDialog {\n\t\tpublic string Ar;\n\t\tpublic string Br;\n\t\t\n\t\tpublic CombineDialog(string id, string ar = null, string br = null, Action<string, int> callback = null) : base(id, new[] {\n\t\t\t$\"{id}_a\", $\"{id}_b\"\n\t\t}, new List<string[]> {\n\t\t\tnew[] { $\"{id}_ar\" }, \n\t\t\tnew[] { $\"{id}_br\" }\n\t\t}, callback) {\n\t\t\tAr = ar;\n\t\t\tBr = br;\n\t\t}\n\n\t\tpublic override Dialog GetNext() {\n\t\t\tvar str = DecideNext();\n\t\t\treturn new Dialog($\"[sp 2]{Locale.Get(Id)}\\n{Locale.Get(Options[Last])}\\n{Locale.Get(str)}\", new [] {\n\t\t\t\tLast == 0 ? Ar : Br\n\t\t\t});\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/Dialog.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing Lens.entity;\nusing Lens.util.math;\n\nnamespace BurningKnight.ui.dialog {\n\tpublic class Dialog {\n\t\tpublic readonly string Id;\n\t\tpublic string[] Next;\n\n\t\tpublic List<Func<Dialog, DialogComponent, Dialog>> Callbacks = new List<Func<Dialog, DialogComponent, Dialog>>();\n\t\t\n\t\tpublic Dialog(string id, string[] next = null) {\n\t\t\tId = id;\n\t\t\tNext = next;\n\t\t}\n\n\t\tpublic virtual string DecideNext() {\n\t\t\tif (Next == null || Next.Length == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\treturn Next?[Rnd.Int(Next.Length)];\n\t\t}\n\n\t\tpublic virtual Dialog GetNext() {\n\t\t\tvar next = DecideNext();\n\t\t\treturn next != null ? Dialogs.Get(next) : null;\n\t\t}\n\n\t\tpublic virtual string Modify(string dialog) {\n\t\t\treturn dialog;\n\t\t}\n\n\t\tpublic virtual void Reset() {\n\t\t\t\n\t\t}\n\n\t\tpublic class StartedEvent : Event {\n\t\t\tpublic Dialog Dialog;\n\t\t\tpublic Entity Owner;\n\t\t}\n\n\t\tpublic class EndedEvent : Event {\n\t\t\tpublic Dialog Dialog;\n\t\t\tpublic Entity Owner;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/DialogComponent.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.entity.component;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.ui.dialog {\n\tpublic delegate void DialogCallback(DialogComponent d);\n\t\n\tpublic class DialogComponent : Component {\n\t\tpublic static DialogComponent Talking;\n\t\t\n\t\tpublic UiDialog Dialog;\n\t\tpublic Dialog Last;\n\t\tpublic Dialog Current;\n\t\tpublic bool AnimateTyping = true;\n\n\t\tpublic DialogCallback OnNext;\n\t\tpublic Entity To;\n\t\tpublic Action InitCallback;\n\t\tpublic Action FinishCallback;\n\n\t\tprivate bool added;\n\t\tprivate float tillClose = -1;\n\t\t\n\t\tprivate void HandleInput(object sender, TextInputEventArgs args) {\n\t\t\tif (Current is AnswerDialog a) {\n\t\t\t\tif (a.Focused) {\n\t\t\t\t\ta.HandleInput(args);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\t\t\t\n\t\t\tEngine.Instance.Window.TextInput += HandleInput;\n\n\t\t\tDialog = new UiDialog();\n\t\t\tDialog.Owner = Entity;\n\t\t\t\n\t\t\tDialog.OnEnd += () => {\n\t\t\t\tDialog next = null;\n\t\t\t\t\n\t\t\t\tforeach (var c in Current.Callbacks) {\n\t\t\t\t\tvar d = c(Current, this);\n\n\t\t\t\t\tif (d != null) {\n\t\t\t\t\t\tnext = d;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (next == null) {\n\t\t\t\t\tnext = Current.GetNext();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tCurrent.Reset();\n\n\t\t\t\tif (next == null) {\n\t\t\t\t\tLast = Current;\n\t\t\t\t\tCurrent = null;\n\t\t\t\t\tOnNext?.Invoke(this);\n\n\t\t\t\t\tif (To != null) {\n\t\t\t\t\t\tOnEnd();\n\t\t\t\t\t\tTo = null;\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tSetup(next);\n\t\t\t\tOnNext?.Invoke(this);\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tDialog.Close(() => { Dialog.Done = true; });\n\t\t\tEngine.Instance.Window.TextInput -= HandleInput;\n\n\t\t\tif (Talking == this) {\n\t\t\t\tTalking = null;\n\t\t\t}\n\t\t}\n\n\t\tprivate bool tweening;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (tillClose > -1 && Dialog.DoneSaying) {\n\t\t\t\ttillClose -= dt;\n\n\t\t\t\tif (tillClose <= 0) {\n\t\t\t\t\tClose();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (added) {\n\t\t\t\tif (GamepadComponent.Current != null && Current is AnswerDialog aa && aa.Focused) {\n\t\t\t\t\taa.CheckGamepadInput(GamepadComponent.Current);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Engine.Instance.State is InGameState ss) {\n\t\t\t\tss.TopUi.Add(Dialog);\n\t\t\t} if (Engine.Instance.State is CutsceneState cs) {\n\t\t\t\tcs.TopUi.Add(Dialog);\n\t\t\t} else {\n\t\t\t\tEngine.Instance.State.Ui.Add(Dialog);\n\t\t\t}\n\n\t\t\tDialog.Str.FinishedTyping += s => {\n\t\t\t\tEntity.HandleEvent(new Dialog.EndedEvent {\n\t\t\t\t\tDialog = Last ?? Current,\n\t\t\t\t\tOwner = Entity\n\t\t\t\t});\n\n\t\t\t\tif (!(Engine.Instance.State is CutsceneState)) {\n\t\t\t\t\tFinishCallback?.Invoke();\n\t\t\t\t\tFinishCallback = null;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif (AnimateTyping) {\n\t\t\t\tDialog.Str.CharTyped += (s, i, c) => {\n\t\t\t\t\tif (!tweening && c != ' ' && Entity.TryGetComponent<AnimationComponent>(out var a)) {\n\t\t\t\t\t\ttweening = true;\n\n\t\t\t\t\t\tTween.To(1.3f, a.Scale.X, x => a.Scale.X = x, 0.15f);\n\n\t\t\t\t\t\tTween.To(0.75f, a.Scale.Y, x => a.Scale.Y = x, 0.15f).OnEnd = () => {\n\t\t\t\t\t\t\tTween.To(1, a.Scale.X, x => a.Scale.X = x, 0.1f);\n\t\t\t\t\t\t\tTween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.1f);\n\n\t\t\t\t\t\t\ttweening = false;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tadded = true;\t\t\t\n\t\t\tInitCallback?.Invoke();\n\t\t}\n\n\t\tpublic void Start(string id, Entity to = null, Action end = null) {\n\t\t\tvar dialog = Dialogs.Get(id);\n\t\t\ttillClose = -1;\n\n\t\t\tFinishCallback = end;\n\n\t\t\tif (dialog == null) {\n\t\t\t\tSetup(new Dialog(id), to);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tSetup(dialog, to);\n\t\t}\n\n\t\tpublic void StartAndClose(string id, float time, Entity to = null) {\n\t\t\tStart(id, to);\n\t\t\ttillClose = time;\n\t\t}\n\n\t\tpublic void Close() {\n\t\t\tLast = Current;\n\t\t\ttillClose = -1;\n\n\t\t\tif (Dialog == null || Current == null) {\n\t\t\t\tCurrent = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCurrent = null;\n\t\t\tDialog.Close();\n\t\t}\n\n\t\tprivate static string toSay = \"\";\n\n\t\tpublic override void RenderDebug() {\n\t\t\tbase.RenderDebug();\n\n\t\t\tif (ImGui.InputText(\"Say\", ref toSay, 256, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tStart(toSay);\n\t\t\t\ttoSay = \"\";\n\t\t\t}\n\n\t\t\tImGui.InputInt(\"Voice\", ref Dialog.Voice);\n\n\t\t\tif (ImGui.Button(\"Test\")) {\n\t\t\t\tStart(\"Quick brown fox jumped over lazy dog\");\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\n\t\t\tif (ImGui.Button(\"Close\")) {\n\t\t\t\tClose();\n\t\t\t}\n\t\t}\n\n\t\tprivate void Setup(Dialog dialog, Entity to = null) {\n\t\t\tLast = Current;\n\t\t\tCurrent = dialog;\n\n\t\t\tvar c = Locale.Get(dialog.Id);\n\t\t\tvar s = dialog.Modify(c);\n\t\t\t\n\t\t\tDialog.Say(s);\n\t\t\t\n\t\t\tif (Dialog.Str != null) {\n\t\t\t\tDialog.Str.Renderer = RenderChoice;\n\t\t\t}\n\n\t\t\tif (to is Player) {\n\t\t\t\tTo = to;\n\t\t\t\tOnStart();\n\t\t\t}\n\n\t\t\tEntity.HandleEvent(new Dialog.StartedEvent {\n\t\t\t\tDialog = dialog,\n\t\t\t\tOwner = Entity\n\t\t\t});\n\t\t}\n\n\t\tprivate void RenderChoice(Vector2 pos, int i) {\n\t\t\tif (Current is ChoiceDialog c) {\n\t\t\t\tif (i == c.Choice) {\n\t\t\t\t\tGraphics.Print(\">\", Font.Small, pos);\n\t\t\t\t}\n\t\t\t} else if (Current is AnswerDialog a) {\n\t\t\t\tGraphics.Print($\"{a.Answer}{(a.Focused && Engine.Time % 0.8f > 0.4f ? \"|\" : \"\")}\", Font.Small, pos);\n\t\t\t}\n\t\t}\n\n\t\tprivate bool wasUnhittable;\n\n\t\tprivate void OnStart() {\n\t\t\tvar p = (Player) To;\n\n\t\t\tif (p.TryGetComponent<PlayerInputComponent>(out var input)) {\n\t\t\t\tinput.InDialog = true;\n\t\t\t\tinput.Dialog = this;\n\t\t\t\tDialog.ShowArrow = true;\n\t\t\t}\n\n\t\t\tvar health = To.GetComponent<HealthComponent>();\n\t\t\twasUnhittable = health.Unhittable;\n\t\t\thealth.Unhittable = true;\n\t\t\t\n\t\t\tTween.To(2, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.3f, Ease.QuadInOut);\n\t\t\t\t\t\t\n\t\t\tp.GetComponent<StateComponent>().Become<Player.IdleState>();\n\t\t\t((InGameState) Engine.Instance.State).OpenBlackBars();\n\n\t\t\tTalking = this;\n\t\t}\n\t\t\n\t\tpublic void OnEnd() {\n\t\t\tif (To != null) {\n\t\t\t\tif (To.TryGetComponent<PlayerInputComponent>(out var input)) {\n\t\t\t\t\tinput.InDialog = false;\n\t\t\t\t\tinput.Dialog = null;\n\t\t\t\t\tDialog.ShowArrow = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTo.GetComponent<HealthComponent>().Unhittable = wasUnhittable;\n\t\t\t\twasUnhittable = false;\n\t\t\t}\n\n\t\t\tTween.To(1, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.3f, Ease.QuadInOut);\n\t\t\t((InGameState) Engine.Instance.State).CloseBlackBars();\n\n\t\t\tTalking = null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/DialogNode.cs",
    "content": "namespace BurningKnight.ui.dialog {\n\tpublic interface DialogNode {\n\t\tDialog Convert();\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/EventDialog.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui.dialog {\n\tpublic class EventDialog : Dialog {\n\t\tpublic readonly Func<string> Callback;\n\t\t\n\t\tpublic EventDialog(string id, Func<string> callback) : base(id) {\n\t\t\tCallback = callback;\n\t\t}\n\n\t\tpublic override string DecideNext() {\n\t\t\treturn Callback();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/dialog/UiDialog.cs",
    "content": "using System;\r\nusing BurningKnight.assets;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.ui.str;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.graphics;\r\nusing Lens.input;\r\nusing Lens.util;\r\nusing Lens.util.camera;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.ui.dialog {\r\n\tpublic class UiDialog : FrameRenderer {\r\n\t\tpublic Entity Owner;\r\n\r\n\t\tprivate TextureRegion triangle;\r\n\t\tpublic UiString Str;\r\n\t\tpublic bool ShowArrow;\r\n\t\tpublic bool AlwaysShowArrow;\r\n\r\n\t\tpublic bool Saying { get; private set; }\r\n\t\tpublic bool DoneSaying { get; private set; }\r\n\r\n\t\tpublic Func<bool> OnEnd;\r\n\t\tpublic bool JustStarted;\r\n\t\tpublic int Voice = 5;\r\n\t\t\r\n\t\tprivate string toSay;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\t\r\n\t\t\tWidth = 4;\r\n\t\t\tHeight = 4;\r\n\t\t\t\t\r\n\t\t\tSetup(\"ui\", \"dialog_\");\r\n\t\t\ttriangle = CommonAse.Ui.GetSlice(\"dialog_tri\");\r\n\t\t\t\r\n\t\t\tStr = new UiString(Font.Small);\r\n\t\t\tArea.Add(Str);\r\n\r\n\t\t\tDepth = 2;\r\n\t\t\tStr.Paused = true;\r\n\t\t\tStr.Depth = Depth + 1;\r\n\t\t\tStr.WidthLimit = 172;\r\n\t\t\tStr.Visible = false;\r\n\t\t\tStr.AlwaysVisible = false;\r\n\r\n\t\t\tif (!Owner.HasComponent<AudioEmitterComponent>()) {\r\n\t\t\t\tOwner.AddComponent(new AudioEmitterComponent());\r\n\t\t\t}\r\n\r\n\t\t\tvar id = 0;\r\n\r\n\t\t\tStr.FinishedTyping += s => {\r\n\t\t\t\tDoneSaying = true;\r\n\t\t\t\tid = 0;\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tStr.CharTyped += (s, i, c) => {\r\n\t\t\t\tif (!char.IsLetter(c)) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (id++ % 2 == 1) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar sf = (int) char.ToLower(c);\r\n\t\t\t\tvar v = (sf % 26) / 26f;\r\n\r\n\t\t\t\tif (Owner is entity.creature.bk.BurningKnight) {\r\n\t\t\t\t\tAudio.PlaySfx($\"mob_bk_syllable_{sf % 5 + 1}\", 1f, v - 0.5f);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tOwner.GetComponent<AudioEmitterComponent>().Emit($\"npc_voice_{Voice}\", 1f - Audio.Db3, v + 0.5f);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tTint.A = 0;\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\tStr.Done = true;\r\n\t\t}\r\n\r\n\t\tpublic void Say(string s) {\r\n\t\t\tif (Str == null) {\r\n\t\t\t\ttoSay = s;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (!Saying) {\r\n\t\t\t\tTween.To(255, 0, x => Tint.A = (byte) x, 0.3f);\r\n\t\t\t}\r\n\r\n\t\t\tJustStarted = true;\r\n\t\t\tSaying = true;\r\n\t\t\tStr.Width = 4;\r\n\t\t\tStr.Height = 4;\r\n\t\t\tStr.Label = s;\r\n\t\t}\r\n\r\n\t\tpublic override void Render() {\r\n\t\t\tif (!Engine.Instance.State.Paused) {\r\n\t\t\t\tbase.Render();\r\n\r\n\t\t\t\tif (Str != null) {\r\n\t\t\t\t\tStr.Render();\r\n\r\n\t\t\t\t\tif ((AlwaysShowArrow || ShowArrow) && Str.Finished && !Str.ShouldntRender) {\r\n\t\t\t\t\t\tGraphics.Color = Tint;\r\n\t\t\t\t\t\tGraphics.Print(\"<\", Font.Small, Position + new Vector2(Width - 8, Height - 8 + (float) Math.Sin(Engine.Time * 4f) * 1.5f * Display.UiScale));\r\n\t\t\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void RenderFrame() {\r\n\t\t\tif (Tint.A == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tbase.RenderFrame();\r\n\t\t\t\r\n\t\t\tGraphics.Color = Tint;\r\n\t\t\tGraphics.Render(triangle, Position + new Vector2((Width - triangle.Width) / 2f, Height - 1f));\r\n\t\t\tGraphics.Color = ColorUtils.WhiteColor;\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (Camera.Instance == null) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tPosition = Camera.Instance.CameraToUi(new Vector2(Owner.CenterX, Owner.Y - 4 - (!(Owner is Player) && Owner.TryGetComponent<ZComponent>(out var z) ? z.Z : 0)));\r\n\t\t\tvar s = dt * 10;\r\n\r\n\t\t\tif (DoneSaying || JustStarted) {\r\n\t\t\t\ts = 1;\r\n\t\t\t}\r\n\r\n\t\t\tHeight += (Str.Height + 12 - Height) * s;\r\n\t\t\tWidth += (Str.Width + 16 - Width) * s;\r\n\t\t\tX -= Width / 2;\r\n\t\t\tY -= Height;\r\n\r\n\t\t\tStr.Tint = Tint;\r\n\t\t\tStr.Position = Position + new Vector2(8, 4);\r\n\r\n\t\t\tif (toSay != null) {\r\n\t\t\t\tSay(toSay);\r\n\t\t\t\ttoSay = null;\r\n\t\t\t} else if (Saying) {\r\n\t\t\t\tJustStarted = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic void Finish() {\r\n\t\t\tDoneSaying = false;\r\n\r\n\t\t\tif (OnEnd == null || OnEnd.Invoke()) {\r\n\t\t\t\tClose();\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic void Close(Action callback = null) {\r\n\t\t\tSaying = false;\r\n\t\t\tDoneSaying = false;\r\n\t\t\t\r\n\t\t\tStr?.Stop();\r\n\t\t\t\r\n\t\t\tTween.To(0, 255, x => Tint.A = (byte) x, 0.3f).OnEnd = () => {\r\n\t\t\t\tif (Str != null) {\r\n\t\t\t\t\tStr.Width = 4;\r\n\t\t\t\t\tStr.Height = 4;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tWidth = 4;\r\n\t\t\t\tHeight = 4;\r\n\t\t\t\tShowArrow = false;\r\n\t\t\t\tcallback?.Invoke();\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/editor/CursorMode.cs",
    "content": "namespace BurningKnight.ui.editor {\r\n\tpublic static class CursorMode {\r\n\t\tpublic const int Paint = 0;\r\n\t\tpublic const int Fill = 1;\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/editor/EditorWindow.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing BurningKnight.level;\r\nusing BurningKnight.level.biome;\r\nusing BurningKnight.level.tile;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui.editor.command;\r\nusing BurningKnight.ui.imgui;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.entity;\r\nusing Lens.input;\r\nusing Lens.util;\r\nusing Lens.util.file;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Input;\r\n\r\nnamespace BurningKnight.ui.editor {\r\n\tpublic class EditorWindow {\r\n\t\tprivate static string levelName = \"new_level\";\r\n\t\tprivate static string[] levels;\r\n\t\tprivate static int currentLevel;\r\n\t\tprivate static int levelWidth = 32;\r\n\t\tprivate static int levelHeight = 32;\r\n\t\t\r\n\t\tpublic CommandQueue Commands;\r\n\t\tpublic Editor Editor;\r\n\t\t\r\n\t\tpublic EditorWindow(Editor e) {\r\n\t\t\tEditor = e;\r\n\r\n\t\t\tEntityEditor.Editor = e;\r\n\t\t\tTileEditor.Window = this;\r\n\t\t\tTileEditor.Editor = e;\r\n\t\t\t\r\n\t\t\tCommands = new CommandQueue {\r\n\t\t\t\tEditor = e\r\n\t\t\t};\r\n\r\n\t\t\tif (!Engine.EditingLevel) {\r\n\t\t\t\tTileEditor.ReloadBiome();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar locales = FileHandle.FromRoot(\"Prefabs/\");\r\n\r\n\t\t\tif (!locales.Exists()) {\r\n\t\t\t\tlevels = new[] {\r\n\t\t\t\t\t\"test\"\r\n\t\t\t\t};\r\n\t\t\t\t\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar names = new List<string>();\r\n\r\n\t\t\tforeach (var f in locales.ListFileHandles()) {\r\n\t\t\t\tif (f.Extension == \".lvl\") {\r\n\t\t\t\t\tnames.Add(f.NameWithoutExtension);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlevels = names.ToArray();\r\n\t\t\tLoad();\r\n\t\t}\r\n\r\n\t\tprivate void Save() {\r\n\t\t\tif (levels.Length == 0) {\r\n\t\t\t\tLog.Error(\"Nothing to save\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tSaveManager.Save(Editor.Area, SaveType.Level, true, FileHandle.FromRoot($\"Prefabs/{levels[currentLevel]}.lvl\").FullPath);\r\n\t\t}\r\n\t\t\r\n\t\tprivate void Load() {\r\n\t\t\tEditor.Area.Destroy();\r\n\t\t\tEditor.Area = new Area();\r\n\t\t\tEngine.Instance.State.Area = Editor.Area;\r\n\t\t\t\r\n\t\t\tRun.Level = null;\r\n\r\n\t\t\tif (levels.Length == 0) {\r\n\t\t\t\tvar level = new RegularLevel {\r\n\t\t\t\t\tWidth = levelWidth,\r\n\t\t\t\t\tHeight = levelHeight,\r\n\t\t\t\t\tNoLightNoRender = false,\r\n\t\t\t\t\tDrawLight = false\r\n\t\t\t\t};\r\n\r\n\t\t\t\tEditor.Level = level;\r\n\t\t\t\tEditor.Area.Add(level);\r\n\r\n\t\t\t\tlevel.SetBiome(BiomeRegistry.Get(Biome.Castle));\r\n\t\t\t\tlevel.Setup();\r\n\t\t\t\tlevel.Fill(Tile.FloorA);\r\n\t\t\t\tlevel.TileUp();\r\n\r\n\t\t\t\tEditor.Camera.Position = Vector2.Zero;\r\n\t\t\t} else {\r\n\t\t\t\tSaveManager.Load(Editor.Area, SaveType.Level, $\"Content/Prefabs/{levels[currentLevel]}.lvl\");\r\n\t\t\t\tEditor.Level = Run.Level;\r\n\t\t\t}\r\n\r\n\t\t\tfor (var i = 0; i < Editor.Level.Size; i++) {\r\n\t\t\t\tEditor.Level.Explored[i] = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tTileEditor.ReloadBiome();\r\n\t\t}\r\n\r\n\t\tprivate void Delete() {\r\n\t\t\tvar file = FileHandle.FromRoot($\"Prefabs/{levels[currentLevel]}.lvl\");\r\n\r\n\t\t\ttry {\r\n\t\t\t\tfile.Delete();\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Error(e);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic void Render() {\r\n\t\t\tif (!WindowManager.LevelEditor) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftControl, true)) {\r\n\t\t\t\tif (Engine.EditingLevel && Input.Keyboard.WasPressed(Keys.S, true)) {\r\n\t\t\t\t\tSave();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.Z, true)) {\r\n\t\t\t\t\tCommands.Undo();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tif (Input.Keyboard.WasPressed(Keys.Y, true)) {\r\n\t\t\t\t\tCommands.Redo();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (Engine.Instance.State is InGameState) {\r\n\t\t\t\tEntityEditor.Render();\r\n\t\t\t\tTileEditor.Render();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowPos(System.Numerics.Vector2.Zero, ImGuiCond.Once);\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Level Editor\", ImGuiWindowFlags.AlwaysAutoResize)) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tvar o = currentLevel;\r\n\r\n\t\t\tif (ImGui.Combo(\"Level\", ref currentLevel, levels, levels.Length)) {\r\n\t\t\t\tvar oo = currentLevel;\r\n\t\t\t\tcurrentLevel = o;\r\n\t\t\t\tSave();\r\n\t\t\t\tcurrentLevel = oo;\r\n\t\t\t\t\r\n\t\t\t\tLoad();\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.Button(\"Save\")) {\r\n\t\t\t\tSave();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Delete\")) {\r\n\t\t\t\tImGui.OpenPopup(\"Delete?##s\");\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"Delete?##s\")) {\r\n\t\t\t\tImGui.Text(\"This operation can't be undone!\");\r\n\t\t\t\tImGui.Text(\"Are you sure?\");\r\n\r\n\t\t\t\tif (ImGui.Button(\"Yes\")) {\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t\tDelete();\r\n\r\n\t\t\t\t\tvar list = levels.ToList();\r\n\t\t\t\t\tlist.Remove(levels[currentLevel]);\r\n\t\t\t\t\tlevels = list.ToArray();\r\n\t\t\t\t\tcurrentLevel = 0;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.SameLine();\r\n\t\t\t\tImGui.SetItemDefaultFocus();\r\n\r\n\t\t\t\tif (ImGui.Button(\"No\")) {\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"New\")) {\r\n\t\t\t\tImGui.OpenPopup(\"New level\");\r\n\t\t\t\tlevelName = \"new\";\r\n\t\t\t\tlevelWidth = 32;\r\n\t\t\t\tlevelHeight = 32;\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"New level\")) {\r\n\t\t\t\tvar ol = currentLevel;\r\n\r\n\t\t\t\tImGui.SetItemDefaultFocus();\r\n\t\t\t\tvar input = ImGui.InputText(\"Name\", ref levelName, 64, ImGuiInputTextFlags.EnterReturnsTrue);\r\n\t\t\t\tImGui.InputInt2(\"Size\", ref levelWidth);\r\n\r\n\t\t\t\tvar button = ImGui.Button(\"Create\");\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Cancel\")) {\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (input || button) {\r\n\t\t\t\t\t\tvar oo = currentLevel;\r\n\t\t\t\t\t\tcurrentLevel = ol;\r\n\t\t\t\t\t\tSave();\r\n\t\t\t\t\t\tcurrentLevel = oo;\r\n\r\n\t\t\t\t\t\tlevelWidth = Math.Min(1024, Math.Max(1, levelWidth));\r\n\t\t\t\t\t\tlevelHeight = Math.Min(1024, Math.Max(1, levelHeight));\r\n\r\n\t\t\t\t\t\tvar list = levels.ToList();\r\n\t\t\t\t\t\tlist.Add(levelName);\r\n\r\n\t\t\t\t\t\tlevels = list.ToArray();\r\n\t\t\t\t\t\tcurrentLevel = list.Count - 1;\r\n\r\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\r\n\t\t\t\t\t\tforeach (var e in Editor.Area.Tagged[Tags.LevelSave]) {\r\n\t\t\t\t\t\t\te.Done = true;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tEditor.Area.AutoRemove();\r\n\t\t\t\t\t\tRun.Level = null;\r\n\r\n\t\t\t\t\t\tvar level = new RegularLevel {\r\n\t\t\t\t\t\t\tWidth = levelWidth,\r\n\t\t\t\t\t\t\tHeight = levelHeight,\r\n\t\t\t\t\t\t\tNoLightNoRender = false,\r\n\t\t\t\t\t\t\tDrawLight = false\r\n\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\tEditor.Level = level;\r\n\t\t\t\t\t\tEditor.Area.Add(level);\r\n\r\n\t\t\t\t\t\tlevel.SetBiome(BiomeRegistry.Get(Biome.Castle));\r\n\t\t\t\t\t\tlevel.Setup();\r\n\t\t\t\t\t\tlevel.Fill(Tile.FloorB);\r\n\t\t\t\t\t\tlevel.TileUp();\r\n\r\n\t\t\t\t\t\tEditor.Camera.Position = Vector2.Zero;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.Text($\"{Editor.Level.Width}x{Editor.Level.Height}\");\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Resize\")) {\r\n\t\t\t\tImGui.OpenPopup(\"Resize level\");\r\n\r\n\t\t\t\tlevelWidth = Editor.Level.Width;\r\n\t\t\t\tlevelHeight = Editor.Level.Height;\r\n\t\t\t}\r\n\r\n\t\t\tif (ImGui.BeginPopupModal(\"Resize level\")) {\r\n\t\t\t\tImGui.Text($\"Current size is {Editor.Level.Width}x{Editor.Level.Height}\");\r\n\t\t\t\tImGui.InputInt2(\"New size\", ref levelWidth);\r\n\r\n\t\t\t\tif (ImGui.Button(\"Resize\")) {\r\n\t\t\t\t\tlevelWidth = Math.Min(1024, Math.Max(1, levelWidth));\r\n\t\t\t\t\tlevelHeight = Math.Min(1024, Math.Max(1, levelHeight));\r\n\r\n\t\t\t\t\tEditor.Level.Resize(levelWidth, levelHeight);\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.SameLine();\r\n\r\n\t\t\t\tif (ImGui.Button(\"Cancel\")) {\r\n\t\t\t\t\tImGui.CloseCurrentPopup();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.EndPopup();\r\n\t\t\t}\r\n\r\n\t\t\tImGui.End();\r\n\t\t\t\r\n\t\t\tEntityEditor.Render();\r\n\t\t\tTileEditor.Render();\r\n\t\t}\r\n\r\n\t\tpublic void RenderInGame() {\r\n\t\t\tif (!WindowManager.LevelEditor) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tTileEditor.RenderInGame();\r\n\t\t\tEntityEditor.RenderInGame();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/editor/EntityEditor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.prefabs;\nusing BurningKnight.entity.creature.npc;\nusing BurningKnight.entity.door;\nusing BurningKnight.entity.fx;\nusing BurningKnight.level.entities;\nusing BurningKnight.state;\nusing ImGuiNET;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\nusing Num = System.Numerics;\n\nnamespace BurningKnight.ui.editor {\n\tpublic static class EntityEditor {\n\t\tprivate static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static Num.Vector2 size = new Num.Vector2(200, 400);\n\n\t\tprivate static bool move;\n\t\tprivate static Type currentType;\n\t\tprivate static Vector2 offset;\n\t\tprivate static Type copy;\n\t\tprivate static Entity entity;\t\n\t\tprivate static int selected;\n\n\t\tpublic static List<TypeInfo> Types = new List<TypeInfo>();\n\t\tpublic static bool SnapToGrid = true;\n\t\tpublic static bool Center;\n\t\tpublic static Editor Editor;\n\t\tpublic static Entity CurrentEntity => entity;\n\t\tpublic static Entity HoveredEntity;\n\t\t\n\t\tstatic EntityEditor() {\n\t\t\tvar blocked = new List<Type> {\n\t\t\t\ttypeof(Slime),\n\t\t\t\ttypeof(Prop),\n\t\t\t\ttypeof(SlicedProp),\n\t\t\t\ttypeof(SolidProp),\n\t\t\t\ttypeof(BreakableProp),\n\t\t\t\ttypeof(PlaceableEntity),\n\t\t\t\ttypeof(Mob),\n\t\t\t\ttypeof(Npc)\n\t\t\t};\n\t\t\t\n\t\t\tvar pe = typeof(PlaceableEntity);\n\t\t\t\n\t\t\tforeach (var t in Assembly.GetExecutingAssembly()\n\t\t\t\t.GetTypes()\n\t\t\t\t.Where(type => pe.IsAssignableFrom(type) && type != pe && !blocked.Contains(type))) {\n\n\t\t\t\tTypes.Add(new TypeInfo {\n\t\t\t\t\tType = t,\n\t\t\t\t\tName = t.Name\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tTypes.Sort((a, b) => a.GetType().FullName.CompareTo(b.GetType().FullName));\n\t\t}\n\n\t\tprivate static bool open;\n\t\t\n\t\tpublic static void Render() {\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\t\t\t\n\t\t\tif (!ImGui.Begin(\"Entity placer\")) {\n\t\t\t\tImGui.End();\n\t\t\t\topen = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\topen = true;\n\t\t\t\n\t\t\tvar down = !ImGui.GetIO().WantCaptureMouse && Input.Mouse.CheckLeftButton;\n\t\t\tvar clicked = !ImGui.GetIO().WantCaptureMouse && MouseData.HadClick;\n\t\t\t\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftControl, true)) {\n\t\t\t\tif (entity != null) {\n\t\t\t\t\tif (Input.Keyboard.WasPressed(Keys.C, true)) {\n\t\t\t\t\t\tcopy = entity.GetType();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (copy != null && Input.Keyboard.WasPressed(Keys.V, true)) {\n\t\t\t\t\t\tvar od = currentType;\n\t\t\t\t\t\tcurrentType = copy;\n\t\t\t\t\t\tCreateEntity(false);\n\t\t\t\t\t\tcurrentType = od;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (Input.Keyboard.WasPressed(Keys.D, true)) {\n\t\t\t\t\t\tentity.Done = true;\n\t\t\t\t\t\tentity = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Move\", ref move);/*) {\n\t\t\t\tif (entityMode != 0) {\n\t\t\t\t\tRemoveEntity();\n\t\t\t\t}\n\t\t\t}*/\n\n\t\t\tif (!move && entity != null) {\n\t\t\t\tvar mouse = Input.Mouse.GamePosition;\n\n\t\t\t\tif (SnapToGrid) {\n\t\t\t\t\tmouse.X = (float) Math.Floor(mouse.X / 16) * 16;\n\t\t\t\t\tmouse.Y = (float) Math.Floor(mouse.Y / 16) * 16;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmouse += new Vector2(8 - entity.Width / 2f, 8 - entity.Height / 2f);\n\t\t\t\t\n\t\t\t\tif (Center) {\n\t\t\t\t\tentity.Center = mouse;\n\t\t\t\t} else {\n\t\t\t\t\tentity.Position = mouse;\n\t\t\t\t}\n\n\t\t\t\tif (clicked) {\n\t\t\t\t\tCreateEntity(false);\n\t\t\t\t}\n\t\t\t} else if (move) {\n\t\t\t\tvar mouse = Input.Mouse.GamePosition;\n\t\t\t\tEntity selected = null;\n\t\t\t\t\t\n\t\t\t\tforeach (var e in Editor.Area.Entities.Entities) {\n\t\t\t\t\tif (e.OnScreen && AreaDebug.PassFilter(e) && !(e is Firefly || e is WindFx || e is Lock)) {\n\t\t\t\t\t\tif (e.Contains(mouse)) {\n\t\t\t\t\t\t\tselected = e;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tHoveredEntity = selected;\n\t\t\t\t\n\t\t\t\tif (clicked) {\n\t\t\t\t\tentity = selected;\n\n\t\t\t\t\tif (selected != null) {\n\t\t\t\t\t\tAreaDebug.ToFocus = entity;\n\t\t\t\t\t\toffset = entity.Position - mouse;\n\t\t\t\t\t}\n\t\t\t\t} else if (entity != null && (down && entity.Contains(mouse) || Input.Keyboard.IsDown(Keys.LeftAlt, true))) {\n\t\t\t\t\tmouse += offset;\n\t\t\t\t\t\n\t\t\t\t\tif (SnapToGrid) {\n\t\t\t\t\t\tmouse.X = (float) Math.Round(mouse.X / 16) * 16;\n\t\t\t\t\t\tmouse.Y = (float) Math.Round(mouse.Y / 16) * 16;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmouse += new Vector2(8 - entity.Width / 2f, 8 - entity.Height / 2f);\n\t\t\t\t\n\t\t\t\t\tif (Center) {\n\t\t\t\t\t\tentity.Center = mouse;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tentity.Position = mouse;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Snap to grid\", ref SnapToGrid);\n\t\t\tImGui.SameLine();\n\t\t\tImGui.Checkbox(\"Center\", ref Center);\n\t\t\t\n\t\t\tif (entity != null) {\n\t\t\t\tImGui.Separator();\n\t\t\t\tImGui.Text(entity.GetType().Name);\n\n\t\t\t\tif (ImGui.Button(\"Open debug\")) {\n\t\t\t\t\tAreaDebug.ToFocus = entity;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.Separator();\n\t\t\t}\n\n\t\t\tfilter.Draw(\"\");\n\t\t\tvar i = 0;\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\tvar h = ImGui.GetStyle().ItemSpacing.Y;\n\t\t\tImGui.BeginChild(\"ScrollingRegionConsole\", new System.Numerics.Vector2(0, -h), \n\t\t\t\tfalse, ImGuiWindowFlags.HorizontalScrollbar);\n\t\t\n\t\t\tforeach (var t in Types) {\n\t\t\t\tif (filter.PassFilter(t.Name)) {\n\t\t\t\t\tif (ImGui.Selectable(t.Name, selected == i)) {\n\t\t\t\t\t\tselected = i;\n\n\t\t\t\t\t\tcurrentType = t.Type;\n\t\t\t\t\t\tCreateEntity();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tImGui.EndChild();\n\t\t\tImGui.End();\n\t\t}\n\n\t\tprivate static void CreateEntity(bool remove = true) {\n\t\t\tif (remove) {\n\t\t\t\tRemoveEntity();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tentity = (Entity) Activator.CreateInstance(currentType);\n\t\t\t\tEditor.Area.Add(entity);\n\t\t\t\tentity.Position = Input.Mouse.GamePosition;\n\t\t\t\t// somethig wrong here\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RemoveEntity() {\n\t\t\tif (entity != null) {\n\t\t\t\tentity.Done = true;\n\t\t\t\tentity = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void RenderInGame() {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (HoveredEntity != null) {\n\t\t\t\tGraphics.Batch.DrawRectangle(HoveredEntity.Position - new Vector2(1), new Vector2(HoveredEntity.Width + 2, HoveredEntity.Height + 2), new Color(0.7f, 0.7f, 1f, 1f));\n\t\t\t}\n\t\t\t\t\n\t\t\tif (CurrentEntity != null) {\n\t\t\t\tvar e = CurrentEntity;\n\t\t\t\tGraphics.Batch.DrawRectangle(e.Position - new Vector2(1), new Vector2(e.Width + 2, e.Height + 2), new Color(0.7f, 1f, 0.7f, 1f));\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/PlaceableEntity.cs",
    "content": "namespace BurningKnight.ui.editor {\n\tpublic interface PlaceableEntity {\n\t\t\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/TileEditor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.level.biome;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing BurningKnight.ui.editor.command;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\nusing Num = System.Numerics;\n\nnamespace BurningKnight.ui.editor {\n\tpublic static class TileEditor {\n\t\tprivate static Num.Vector2 tileSize = new Num.Vector2(32f);\n\t\tprivate static Num.Vector4 tintColorActive = new Num.Vector4(0.6f);\n\t\tprivate static Num.Vector4 tintColor = new Num.Vector4(1f);\n\t\tprivate static Num.Vector4 bg = new Num.Vector4(0.1f);\n\n\t\tpublic static Editor Editor;\n\t\tpublic static EditorWindow Window;\n\t\t\n\t\tprivate static string[] biomes;\n\t\tprivate static int currentBiome;\n\t\tprivate static List<TileInfo> infos = new List<TileInfo>();\n\t\tprivate static Texture2D biomeTexture;\n\t\tprivate static IntPtr biomePointer;\n\t\tprivate static Texture2D tilesetTexture;\n\t\tprivate static IntPtr tilesetPointer;\n\t\tprivate static bool fill;\n\t\tprivate static bool open;\n\n\t\tpublic static TileInfo CurrentInfo;\n\t\tpublic static bool Grid;\n\t\t\n\t\tpublic static void ReloadBiome() {\n\t\t\tif (Editor?.Level?.Biome == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\n\t\t\tbiomes = new string[BiomeRegistry.Defined.Count];\n\t\t\tvar i = 0;\n\t\t\t\n\t\t\tforeach (var r in BiomeRegistry.Defined.Values) {\n\t\t\t\tif (r.Id == Editor?.Level?.Biome?.Id) {\n\t\t\t\t\tcurrentBiome = i;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbiomes[i] = r.Id;\n\t\t\t\ti++;\n\t\t\t}\n\t\t\t\n\t\t\ttilesetTexture = Animations.Get($\"{Editor.Level.Biome.Id}_biome\").Texture;\n\t\t\ttilesetPointer = ImGuiHelper.Renderer.BindTexture(tilesetTexture);\n\t\t\t\n\t\t\tbiomeTexture = Animations.Get(\"biome_assets\").Texture;\n\t\t\tbiomePointer = ImGuiHelper.Renderer.BindTexture(biomeTexture);\n\t\t\t\n\t\t\tinfos.Clear();\n\t\t\t\n\t\t\tDefineTile(Tile.WallA, 128, 0);\n\t\t\tDefineTile(Tile.WallB, 144, 0);\n\t\t\tDefineTile(Tile.Planks, 352, 144, true);\n\t\t\tDefineTile(Tile.Collider, 305, 96, true);\n\t\t\tDefineTile(Tile.GrannyWall, 192, 336, true);\n\t\t\tDefineTile(Tile.EvilWall, 0, 336, true);\n\t\t\tDefineTile(Tile.Crack, 128, 48);\n\t\t\tDefineTile(Tile.GrannyFloor, 192, 368, true);\n\t\t\tDefineTile(Tile.EvilFloor, 48, 384, true);\n\t\t\tDefineTile(Tile.FloorA, 0, 80);\n\t\t\tDefineTile(Tile.FloorB, 64, 80);\n\t\t\tDefineTile(Tile.FloorC, 0, 160);\n\t\t\tDefineTile(Tile.FloorD, 64, 160);\n\t\t\tDefineTile(Tile.Path, 400, 368, true);\n\t\t\tDefineTile(Tile.GrannyFloor, 192, 368);\n\t\t\tDefineTile(Tile.EvilFloor, 48, 384);\n\t\t\tDefineTile(Tile.Water, 64, 240, true);\n\t\t\tDefineTile(Tile.Ice, 192, 112, true);\n\t\t\tDefineTile(Tile.Lava, 64, 112, true);\n\t\t\tDefineTile(Tile.Venom, 64, 304, true);\n\t\t\tDefineTile(Tile.Obsidian, 64, 176, true);\n\t\t\tDefineTile(Tile.Dirt, 64, 48, true);\n\t\t\tDefineTile(Tile.Sand, 464, 352, true);\n\t\t\tDefineTile(Tile.Snow, 464, 288, true);\n\t\t\tDefineTile(Tile.Grass, 192, 48, true);\n\t\t\tDefineTile(Tile.HighGrass, 336, 0, true);\n\t\t\tDefineTile(Tile.Cobweb, 192, 240, true);\n\t\t\tDefineTile(Tile.Ember, 144, 160, true);\n\t\t\tDefineTile(Tile.Chasm, 288, 32, true);\n\t\t\tDefineTile(Tile.Piston, 128, 0);\n\t\t\tDefineTile(Tile.PistonDown, 128, 0);\n\t\t\tDefineTile(Tile.Rock, 160, 192);\n\t\t\tDefineTile(Tile.TintedRock, 160, 224);\n\t\t\tDefineTile(Tile.MetalBlock, 128, 192);\n\t\t\t\n\t\t\tCurrentInfo = infos[0];\n\t\t}\n\t\t\n\t\tpublic static void Render() {\n\t\t\tif (!ImGui.Begin(\"Tile editor\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\topen = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\topen = true;\n\n\t\t\tif (ImGui.Combo(\"Biome\", ref currentBiome, biomes, biomes.Length)) {\n\t\t\t\tEditor.Level.SetBiome(BiomeRegistry.Get(biomes[currentBiome]));\n\t\t\t\tReloadBiome();\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Checkbox(\"Show grid\", ref Grid);\n\t\t\t\n\t\t\tEntityEditor.RemoveEntity();\n\t\t\t\n\t\t\tvar down = !ImGui.GetIO().WantCaptureMouse && Input.Mouse.CheckLeftButton;\n\t\t\tvar clicked = !ImGui.GetIO().WantCaptureMouse && MouseData.HadClick;\n\t\t\t\t\n\t\t\tImGui.Checkbox(\"Fill\", ref fill);\n\t\t\tImGui.Separator();\n\n\t\t\tif (CurrentInfo == null) {\n\t\t\t\tCurrentInfo = infos[1];\n\t\t\t}\n\n\t\t\tvar cur = CurrentInfo;\n\n\t\t\tImGui.ImageButton(cur.Texture, tileSize, cur.Uv0, cur.Uv1, 4, bg, tintColor);\n\t\t\tImGui.SameLine();\n\t\t\tImGui.Text(CurrentInfo.Tile.ToString());\n\n\t\t\tif (CurrentInfo.Tile.Matches(TileFlags.LiquidLayer)) {\n\t\t\t\tImGui.SameLine();\n\t\t\t\tImGui.Text(\"Liquid\");\n\t\t\t} else if (CurrentInfo.Tile.Matches(TileFlags.WallLayer)) {\n\t\t\t\tImGui.SameLine();\n\t\t\t\tImGui.Text(\"Wall\");\n\t\t\t}\n\t\t\t\t\t\n\t\t\tif (Input.Keyboard.WasPressed(Keys.F)) {\n\t\t\t\tfill = true;\n\t\t\t} else if (Input.Keyboard.WasPressed(Keys.P)) {\n\t\t\t\tfill = false;\n\t\t\t}\n\n\t\t\tif (CurrentInfo.Tile.Matches(TileFlags.Burns)) {\n\t\t\t\tImGui.SameLine();\n\t\t\t\tImGui.Text(\"Burns\");\n\t\t\t}\n\t\t\t\t\n\t\t\tImGui.Separator();\n\n\t\t\tfor (var i = 0; i < infos.Count; i++) {\n\t\t\t\tvar info = infos[i];\n\t\t\t\tImGui.PushID((int) info.Tile);\n\n\t\t\t\tif (ImGui.ImageButton(info.Texture, tileSize, info.Uv0, info.Uv1, 0, bg, info == CurrentInfo ? tintColorActive : tintColor)) {\n\t\t\t\t\tCurrentInfo = info;\n\t\t\t\t}\n\n\t\t\t\tImGui.PopID();\n\t\t\t\t\t\n\t\t\t\tif (i % 4 < 3 && i < infos.Count - 1) {\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\n\n\t\t\tif (down) {\n\t\t\t\tvar mouse = Input.Mouse.GamePosition;\n\n\t\t\t\tvar x = (int) (mouse.X / 16);\n\t\t\t\tvar y = (int) (mouse.Y / 16);\n\t\t\t\t\t\n\t\t\t\tif (Editor.Level.IsInside(x, y)) {\n\t\t\t\t\tif (Editor.Level.Get(x, y, CurrentInfo.Tile.Matches(TileFlags.LiquidLayer)) != CurrentInfo.Tile) {\n\t\t\t\t\t\tif (!fill) {\n\t\t\t\t\t\t\tWindow.Commands.Do(new SetCommand {\n\t\t\t\t\t\t\t\tX = x,\n\t\t\t\t\t\t\t\tY = y,\n\t\t\t\t\t\t\t\tTile = CurrentInfo.Tile\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tWindow.Commands.Do(new FillCommand {\n\t\t\t\t\t\t\t\tX = x,\n\t\t\t\t\t\t\t\tY = y,\n\t\t\t\t\t\t\t\tTile = CurrentInfo.Tile\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tImGui.End();\n\t\t}\n\t\t\n\t\tprivate static void DefineTile(Tile tile, int x, int y, bool biome = false) {\n\t\t\tinfos.Add(new TileInfo(tile, biome ? biomeTexture : tilesetTexture, biome ? biomePointer : tilesetPointer, x, y));\n\t\t}\n\n\t\tpublic static void RenderInGame() {\n\t\t\tif (!open) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tColor color;\n\n\t\t\tif (Grid) {\n\t\t\t\tvar gridSize = 16;\n\t\t\t\tvar off = (Camera.Instance.TopLeft - new Vector2(0, 8));\n\t\t\t\tcolor = new Color(1f, 1f, 1f, 0.5f);\n\n\t\t\t\tfor (float x = Math.Max(0, off.X - off.X % gridSize); x <= off.X + Display.Width && x <= Editor.Level.Width * 16; x += gridSize) {\n\t\t\t\t\tGraphics.Batch.DrawLine(x, off.Y, x, off.Y + Display.Height + gridSize, color);\n\t\t\t\t}\n\n\t\t\t\tfor (float y = Math.Max(0, off.Y - off.Y % gridSize); y <= off.Y + Display.Height && y <= Editor.Level.Height * 16; y += gridSize) {\n\t\t\t\t\tGraphics.Batch.DrawLine(off.X, y, off.X + Display.Width + gridSize, y, color);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar mouse = Input.Mouse.GamePosition;\n\t\t\tcolor = new Color(1f, 0.5f, 0.5f, 1f);\n\t\t\tvar fill = new Color(1f, 0.5f, 0.5f, 0.5f);\n\n\t\t\tmouse.X = (float) (Math.Floor(mouse.X / 16) * 16);\n\t\t\tmouse.Y = (float) (Math.Floor(mouse.Y / 16) * 16);\n\n\t\t\tif (CurrentInfo.Tile.Matches(TileFlags.WallLayer)) {\n\t\t\t\tmouse.Y -= 8;\n\t\t\t\tGraphics.Batch.FillRectangle(mouse, new Vector2(16, 24), fill);\n\t\t\t\tmouse.Y += 16;\n\t\t\t\tGraphics.Batch.DrawRectangle(mouse, new Vector2(16, 8), new Color(1f, 0.7f, 0.7f, 1f));\n\t\t\t\tmouse.Y -= 16;\n\t\t\t\tGraphics.Batch.DrawRectangle(mouse, new Vector2(16), color);\n\t\t\t} else {\n\t\t\t\tGraphics.Batch.FillRectangle(mouse, new Vector2(16, 16), fill);\n\t\t\t\tGraphics.Batch.DrawRectangle(mouse, new Vector2(16), color);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/TileInfo.cs",
    "content": "using System;\nusing System.Numerics;\nusing BurningKnight.level.tile;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace BurningKnight.ui.editor {\n\tpublic class TileInfo {\n\t\tpublic Tile Tile;\n\t\tpublic Vector2 Uv0;\n\t\tpublic Vector2 Uv1;\n\t\tpublic IntPtr Texture;\n\n\t\tpublic TileInfo(Tile tile, Texture2D texture, IntPtr ptr, int x, int y) {\n\t\t\tTile = tile;\n\t\t\tTexture = ptr;\n\n\t\t\tUv0.X = (float) x / texture.Width;\n\t\t\tUv0.Y = (float) y / texture.Height;\n\t\t\tUv1.X = Uv0.X + 16f / texture.Width;\n\t\t\tUv1.Y= Uv0.Y + 16f / texture.Height;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/TypeInfo.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui.editor {\n\tpublic class TypeInfo {\n\t\tpublic Type Type;\n\t\tpublic string Name;\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/command/Command.cs",
    "content": "using BurningKnight.level;\n\nnamespace BurningKnight.ui.editor.command {\n\tpublic interface Command {\n\t\tvoid Do(Level level);\n\t\tvoid Undo(Level level);\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/command/CommandQueue.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.state;\n\nnamespace BurningKnight.ui.editor.command {\n\tpublic class CommandQueue {\n\t\tprivate Stack<Command> commands = new Stack<Command>();\n\t\tprivate Stack<Command> redo = new Stack<Command>();\n\n\t\tpublic Editor Editor;\n\t\t\n\t\tpublic void Do(Command command) {\n\t\t\tredo.Clear();\n\t\t\t\n\t\t\tcommands.Push(command);\n\t\t\tcommand.Do(Editor.Level);\n\t\t}\n\n\t\tpublic void Undo() {\n\t\t\tif (commands.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar command = commands.Pop();\n\t\t\t\n\t\t\tcommand.Undo(Editor.Level);\n\t\t\tredo.Push(command);\n\t\t}\n\n\t\tpublic void Redo() {\n\t\t\tif (redo.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar command = redo.Pop();\n\t\t\t\n\t\t\tcommand.Do(Editor.Level);\n\t\t\tcommands.Push(command);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/command/FillCommand.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level;\nusing BurningKnight.level.tile;\nusing Lens.input;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.ui.editor.command {\n\tpublic class FillCommand : Command {\n\t\tpublic Tile Tile;\n\t\tpublic Tile Start;\n\t\tpublic int X;\n\t\tpublic int Y;\n\t\tpublic bool Dir8;\n\n\t\tprivate Tile before;\n\t\tprivate Tile beforeLiquid;\n\t\tprivate List<Point> where = new List<Point>();\n\n\t\tprivate void Set(Level level, int x, int y, bool liquid) {\n\t\t\tif (!level.IsInside(x, y)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar tile = level.Get(x, y, liquid);\n\n\t\t\tif (tile != Start) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\twhere.Add(new Point(x, y));\n\t\t\tlevel.Set(x, y, Tile);\n\t\t\tlevel.UpdateTile(x, y);\n\t\t\t\n\t\t\tSet(level, x - 1, y, liquid);\n\t\t\tSet(level, x + 1, y, liquid);\n\t\t\tSet(level, x, y - 1, liquid);\n\t\t\tSet(level, x, y + 1, liquid);\n\n\t\t\tif (Dir8) {\n\t\t\t\tSet(level, x - 1, y - 1, liquid);\n\t\t\t\tSet(level, x + 1, y - 1, liquid);\n\t\t\t\tSet(level, x + 1, y + 1, liquid);\n\t\t\t\tSet(level, x - 1, y + 1, liquid);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Do(Level level) {\n\t\t\ttry {\n\t\t\t\tvar i = level.ToIndex(X, Y);\n\t\t\t\tvar l = level.Liquid[i] != 0;\n\t\t\t\t\n\t\t\t\tDir8 = Input.Keyboard.IsDown(Keys.LeftShift);\n\t\t\t\tStart = l ? level.Get(i, true) : level.Get(i);\n\t\t\t\t\n\t\t\t\tSet(level, X, Y, l);\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t\tLog.Error(\"Failed to fill\");\n\t\t\t}\n\t\t}\n\n\t\tpublic void Undo(Level level) {\n\t\t\tforeach (var p in where) {\n\t\t\t\tlevel.Set(p.X, p.Y, Start);\n\t\t\t\tlevel.UpdateTile(p.X, p.Y);\n\t\t\t}\n\t\t\t\n\t\t\twhere.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/editor/command/SetCommand.cs",
    "content": "using BurningKnight.level;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens;\n\nnamespace BurningKnight.ui.editor.command {\n\tpublic class SetCommand : Command {\n\t\tpublic Tile Tile;\n\t\tpublic int X;\n\t\tpublic int Y;\n\n\t\tprivate Tile before;\n\t\tprivate Tile beforeLiquid;\n\t\t\n\t\tpublic void Do(Level level) {\n\t\t\tvar index = level.ToIndex(X, Y);\n\n\t\t\tbefore = level.Get(index);\n\t\t\tbeforeLiquid = level.Get(index, true);\n\t\t\t\n\t\t\tlevel.Liquid[index] = 0;\n\n\t\t\tif (Tile.Matches(TileFlags.LiquidLayer) && (before.Matches(TileFlags.Solid) || before.Matches(TileFlags.Hole))) {\n\t\t\t\tlevel.Tiles[index] = (byte) Tiles.RandomFloor();\n\t\t\t}\n\t\t\t\n\t\t\tlevel.Set(index, Tile);\n\t\t\tlevel.UpdateTile(X, Y);\n\n\t\t\tif (Engine.Instance.State is InGameState) {\n\t\t\t\tlevel.ReCreateBodyChunk(X, Y);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Undo(Level level) {\n\t\t\tlevel.Set(X, Y, before);\n\t\t\tlevel.Set(X, Y, beforeLiquid);\n\t\t\tlevel.UpdateTile(X, Y);\n\n\t\t\tif (Engine.Instance.State is InGameState) {\n\t\t\t\tlevel.ReCreateBodyChunk(X, Y);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/DebugWindow.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.state.save;\nusing BurningKnight.util;\nusing ImGuiNET;\nusing Lens;\nusing Lens.game;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.imgui {\n\tpublic static class DebugWindow {\n\t\tprivate static string[] states = {\n\t\t\t\"ingame\", \"dialog_editor\", \"level_editor\", \"pico\", \"load\", \"save_explorer\", \"room_editor\", \"cutscene\"\n\t\t};\n\t\t\n\t\tprivate static PerformanceCounter cpuCounter = new PerformanceCounter(\"Processor\", \"% Processor Time\", \"_Total\");\n\n\t\tprivate static Type[] types = {\n\t\t\ttypeof(InGameState), typeof(DialogEditorState),\n\t\t\ttypeof(EditorState), typeof(PicoState), typeof(LoadState),\n\t\t\ttypeof(SaveExplorerState), typeof(RoomEditorState), typeof(CutsceneState)\n\t\t};\n\t\t\n\t\tprivate static float[] fps = new float[60];\n\t\tprivate static float[] cpuUsage = new float[60];\n\t\tprivate static float[] memUsage = new float[60];\n\t\tprivate static int pos;\n\t\tprivate static int lastCall;\n\t\tprivate static float lastFps;\n\t\tprivate static float lastMem;\n\n\t\tpublic static bool ItemShader = true;\n\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.Debug) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (!ImGui.Begin(\"Debug\", ImGuiWindowFlags.AlwaysAutoResize)) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Engine.Instance.StateRenderer is PixelPerfectGameRenderer pr) {\n\t\t\t\tImGui.Checkbox(\"Enable Clip\", ref pr.EnableClip);\n\t\t\t}\n\n\t\t\tif (Input.Blocked > 0) {\n\t\t\t\tImGui.Text(\"Input blocked\");\n\t\t\t} else {\n\t\t\t\tImGui.Text(\"Input free\");\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Text($\"Multiplayer: {InGameState.Multiplayer}\");\n\t\t\tImGui.Text($\"Camera targets: {Camera.Instance?.Targets?.Count ?? 0}\");\n\n\t\t\tvar current = 0;\n\t\t\tvar t = Engine.Instance.State.GetType();\n\n\t\t\tfor (var i = 0; i < types.Length; i++) {\n\t\t\t\tif (t == types[i]) {\n\t\t\t\t\tcurrent = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar old = current;\n\n\t\t\tif (ImGui.Combo(\"State\", ref current, states, states.Length) && old != current) {\n\t\t\t\tif (current == 0) {\n\t\t\t\t\tEngine.Instance.SetState(new LoadState());\n\t\t\t\t} else {\n\t\t\t\t\tEngine.Instance.SetState((GameState) Activator.CreateInstance(types[current]));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.CollapsingHeader(\"Performance\")) {\n\t\t\t\tlastMem += Engine.Delta;\n\n\t\t\t\tImGui.Text($\"Update time: {Engine.UpdateTime} ms\");\n\t\t\t\tImGui.Text($\"Render time: {Engine.RenderTime} ms\");\n\n\t\t\t\tif (Engine.Instance?.State?.Area?.Tagged?[Tags.Projectile] != null) {\n\t\t\t\t\tImGui.Text($\"Projectiles: {Engine.Instance.State.Area.Tagged[Tags.Projectile].Count}\");\n\t\t\t\t}\n\n\t\t\t\tfloat mem;\n\n\t\t\t\tusing (var data = Process.GetCurrentProcess()) {\n\t\t\t\t\tmem = data.PrivateMemorySize64 / (1024f * 1024f);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.Text($\"Memory: {mem} mb\");\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"GC\")) {\n\t\t\t\t\tGC.Collect();\n\t\t\t\t}\n\n\t\t\t\tif (lastMem > 0.5f) {\n\t\t\t\t\tlastMem = 0;\n\n\t\t\t\t\tfor (var i = 1; i < memUsage.Length; i++) {\n\t\t\t\t\t\tmemUsage[i - 1] = memUsage[i];\n\t\t\t\t\t}\n\n\t\t\t\t\tmemUsage[memUsage.Length - 1] = mem;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.PlotHistogram(\"Memory\", ref memUsage[0], memUsage.Length, 0, null, 0, 2048, new System.Numerics.Vector2(300, 100));\n\t\t\t\t\n\t\t\t\tImGui.Text($\"FPS: {Engine.Instance.Counter.CurrentFramesPerSecond}\");\n\t\t\t\tlastFps += Engine.Delta;\n\n\t\t\t\tif (lastFps > 0.5f) {\n\t\t\t\t\tlastFps = 0;\n\n\t\t\t\t\tfor (var i = 1; i < fps.Length; i++) {\n\t\t\t\t\t\tfps[i - 1] = fps[i];\n\t\t\t\t\t}\n\n\t\t\t\t\tfps[fps.Length - 1] = Engine.Instance.Counter.AverageFramesPerSecond;\n\t\t\t\t}\n\n\t\t\t\tImGui.PlotHistogram(\"FPS\", ref fps[0], fps.Length, 0, null, 0, 60);\n\n\t\t\t\tif (lastCall < (int) Engine.Time) {\n\t\t\t\t\tlastCall = (int) Engine.Time;\n\n\t\t\t\t\tfor (var i = 1; i < cpuUsage.Length; i++) {\n\t\t\t\t\t\tcpuUsage[i - 1] = cpuUsage[i];\n\t\t\t\t\t}\n\n\t\t\t\t\tcpuUsage[cpuUsage.Length - 1] = (float) Math.Round(cpuCounter.NextValue());\n\t\t\t\t}\n\n\t\t\t\tImGui.PlotHistogram(\"CPU\", ref cpuUsage[0], cpuUsage.Length, 0, null, 0, 100);\n\n\n\t\t\t\tImGui.DragFloat(\"Speed\", ref Engine.Instance.Speed, 0.01f, 0.1f, 2f);\n\n\t\t\t\tImGui.Text($\"Draw calls: {Engine.Graphics.GraphicsDevice.Metrics.DrawCount}\");\n\t\t\t\tImGui.Text($\"Clear calls: {Engine.Graphics.GraphicsDevice.Metrics.ClearCount}\");\n\t\t\t\tImGui.Text($\"FBO binds: {Engine.Graphics.GraphicsDevice.Metrics.TargetCount}\");\n\t\t\t\tImGui.Text($\"Shader binds: {Engine.Graphics.GraphicsDevice.Metrics.PixelShaderCount}\");\n\t\t\t\tImGui.Text($\"Texture count: {Engine.Graphics.GraphicsDevice.Metrics.TextureCount}\");\n\n\t\t\t\tImGui.Spacing();\n\t\t\t\tImGui.Checkbox(\"Enable batcher\", ref GameRenderer.EnableBatcher);\n\t\t\t\tImGui.Checkbox(\"Enable item shader\", ref ItemShader);\n\t\t\t}\n\n\t\t\tif (ImGui.CollapsingHeader(\"Run info\")) {\n\t\t\t\tImGui.Text($\"Run ID: {GlobalSave.RunId}\");\n\t\t\t\tImGui.Text($\"Type: {Run.Type}\");\n\t\t\t\tImGui.Text($\"Seed: {Run.Seed}\");\n\t\t\t\tImGui.Text($\"Kills: {Run.KillCount}\");\n\t\t\t\tImGui.Text($\"Time: {Run.FormatTime()}\");\n\t\t\t\tImGui.Text($\"Has run: {Run.HasRun}\");\n\t\t\t\tImGui.Text($\"Luck: {Run.Luck}\");\n\t\t\t\tImGui.Text($\"Scourge: {Run.Scourge}\");\n\t\t\t}\n\n\t\t\tif (ImGui.CollapsingHeader(\"Camera\")) {\n\t\t\t\tvar c = Camera.Instance;\n\t\t\t\tvar v = c.X;\n\n\t\t\t\tif (ImGui.DragFloat(\"X\", ref v)) {\n\t\t\t\t\tc.X = v;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tv = c.Y;\n\n\t\t\t\tif (ImGui.DragFloat(\"Y\", ref v)) {\n\t\t\t\t\tc.Y = v;\n\t\t\t\t}\n\n\t\t\t\tImGui.Checkbox(\"Detatched\", ref c.Detached);\n\n\t\t\t\tv = c.Zoom;\n\n\t\t\t\tif (ImGui.InputFloat(\"Zoom\", ref v)) {\n\t\t\t\t\tc.Zoom = v;\n\t\t\t\t}\n\n\t\t\t\tImGui.InputFloat(\"Texture zoom\", ref c.TextureZoom);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.BulletText($\"{GlobalSave.Emeralds} emeralds\");\n\n\t\t\tif (ImGui.Button(\"Go to hall (0)\")) {\n\t\t\t\tRun.Depth = 0;\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\n\t\t\tif (ImGui.Button(\"Go to hub (-1)\")) {\n\t\t\t\tRun.Depth = -1;\n\t\t\t}\n\n\t\t\tif (ImGui.Button(\"New run\")) {\n\t\t\t\tRun.StartNew();\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\n\t\t\tif (ImGui.Button(\"Kill\")) {\n\t\t\t\tLocalPlayer.Locate(Run.Level.Area)?.GetComponent<HealthComponent>().Kill(null);\n\t\t\t}\n\n\t\t\tImGui.Separator();\n\n\t\t\tif (Run.Level != null) {\n\t\t\t\tvar player = LocalPlayer.Locate(Run.Level.Area);\n\n\t\t\t\tif (player != null) {\n\t\t\t\t\tImGui.Checkbox(\"Unhittable\", ref player.GetComponent<HealthComponent>().Unhittable);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/DialogEditor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing BurningKnight.assets;\nusing BurningKnight.ui.imgui.node;\nusing BurningKnight.ui.str;\nusing ImGuiNET;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.lightJson;\nusing Lens.lightJson.Serialization;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.imgui {\n\tpublic static class DialogEditor {\n\t\tprivate static string[] files;\n\t\tprivate static int current;\n\n\t\tpublic static string Current => files[current];\n\t\t\n\t\tpublic static void Init() {\n\t\t\tLoad();\n\t\t\tLoadCurrent();\n\n\t\t\tstr = new UiString(Font.Small);\n\t\t\tEngine.Instance.State.Ui.Add(str);\n\t\t\tstr.Position = new Vector2(5);\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tSaveDialogs();\n\t\t\tImGuiHelper.ClearNodes();\n\t\t}\n\t\n\t\tprivate static void SaveDialogs() {\n\t\t\tif (files.Length == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tLocale.Save();\n\t\t\tLog.Info($\"Saving {files[current]}\");\n\t\t\t\n\t\t\tvar nodes = ImNodes.Nodes;\n\t\t\tvar root = new JsonArray();\n\n\t\t\tforeach (var p in nodes) {\n\t\t\t\tvar node = p.Value;\n\t\t\t\t\n\t\t\t\tvar obj = new JsonObject();\n\n\t\t\t\tnode.Save(obj);\n\t\t\t\troot.Add(obj);\n\t\t\t}\n\n\t\t\tvar file = File.CreateText(FileHandle.FromRoot($\"Dialogs/{files[current]}.json\").FullPath);\n\t\t\tvar writer = new JsonWriter(file);\n\t\t\twriter.Write(root);\n\t\t\tfile.Close();\n\t\t}\n\n\t\tpublic static void Load() {\n\t\t\tvar folder = FileHandle.FromRoot(\"Dialogs\");\n\n\t\t\tif (!folder.Exists()) {\n\t\t\t\tLog.Error(\"Dialog folder is not found!\");\n\t\t\t\tfiles = new string[0];\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar fs = new List<string>();\n\t\t\t\n\t\t\tforeach (var f in folder.ListFileHandles()) {\n\t\t\t\tif (f.Extension == \".json\") {\n\t\t\t\t\tfs.Add(f.NameWithoutExtension);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfiles = fs.ToArray();\n\t\t}\n\t\t\n\t\tpublic static void LoadCurrent() {\n\t\t\tif (files.Length == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\ttry {\n\t\t\t\tImGuiHelper.ClearNodes();\n\t\t\t\tvar name = files[current];\n\t\t\t\tLoadFromRoot(name, JsonValue.Parse(FileHandle.FromRoot($\"Dialogs/{name}.json\").ReadAll()));\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tprivate static void LoadFromRoot(string name, JsonArray root) {\n\t\t\tforeach (var vl in root) {\n\t\t\t\tImNode.Create(name, vl);\n\t\t\t}\n\t\t}\n\n\t\tprivate static ImNode last;\n\t\tprivate static UiString str;\n\n\t\tpublic static void RenderUi() {\n\t\t\tif (ImNode.Focused != null) {\n\t\t\t\tif (last != ImNode.Focused) {\n\t\t\t\t\tlast = ImNode.Focused;\n\t\t\t\t\tstr.Label = Locale.Get(ImNode.Focused.LocaleId);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstr.Render();\n\t\t}\n\t\t\n\t\tprivate static string newName = \"\";\n\n\t\tpublic static void Render() {\n\t\t\tif (ImGuiHelper.BeforeRender()) {\n\t\t\t\tImGui.PushItemWidth(-1);\n\n\t\t\t\tvar old = current;\n\t\t\t\t\n\t\t\t\tif (ImGui.Combo(\"##file\", ref current, files, files.Length)) {\n\t\t\t\t\tvar o = current;\n\t\t\t\t\tcurrent = old;\n\t\t\t\t\tSaveDialogs();\n\t\t\t\t\tcurrent = o;\n\t\t\t\t\tLoadCurrent();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.PopItemWidth();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Save\")) {\n\t\t\t\t\tSaveDialogs();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Delete\")) {\n\t\t\t\t\tImGui.OpenPopup(\"Delete?\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.BeginPopupModal(\"Delete?\")) {\n\t\t\t\t\tImGui.Text(\"This operation can't be undone!\");\n\t\t\t\t\tImGui.Text(\"Are you sure?\");\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button(\"Yes\")) {\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t\tvar list = files.ToList();\n\t\t\t\t\t\tvar s = files[current];\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tvar file = FileHandle.FromRoot($\"Dialogs/{s}.json\");\n\t\t\t\t\t\t\tfile.Delete();\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tlist.RemoveAt(current);\n\t\t\t\t\t\tfiles = list.ToArray();\n\t\t\t\t\t\tcurrent = 0;\n\t\t\t\t\t\tLoadCurrent();\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\tImGui.SetItemDefaultFocus();\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button(\"No\")) { \n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.EndPopup();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"New\")) {\n\t\t\t\t\tImGui.OpenPopup(\"New tree\");\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif (ImGui.BeginPopupModal(\"New tree\")) {\n\t\t\t\t\tImGui.SetItemDefaultFocus();\n\t\t\t\t\tvar input = ImGui.InputText(\"Name\", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue);\n\t\t\t\t\tvar button = ImGui.Button(\"Create\");\n\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\t\tif (ImGui.Button(\"Cancel\")) {\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t\tnewName = \"\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (input || button) {\n\t\t\t\t\t\t\tvar list = files.ToList();\n\t\t\t\t\t\t\tlist.Add(newName);\n\t\t\t\t\t\t\tfiles = list.ToArray();\n\t\t\t\t\t\t\tcurrent = list.Count - 1;\n\n\t\t\t\t\t\t\tnewName = \"\";\n\t\t\t\t\t\t\tSaveDialogs();\n\t\t\t\t\t\t\tLoadCurrent();\n\t\t\t\t\t\t\tImGuiHelper.ClearNodes();\n\t\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t\t}\t\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.EndPopup();\n\t\t\t\t}\n\n\t\t\t\tImGui.Separator();\n\t\t\t\tImGuiHelper.RenderNodes();\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/DrawVertDeclaration.cs",
    "content": "using ImGuiNET;\r\nusing Microsoft.Xna.Framework.Graphics;\r\n\r\nnamespace BurningKnight.ui.imgui {\r\n\tpublic static class DrawVertDeclaration {\r\n\t\tpublic static readonly VertexDeclaration Declaration;\r\n\r\n\t\tpublic static readonly int Size;\r\n\r\n\t\tstatic DrawVertDeclaration() {\r\n\t\t\tunsafe {\r\n\t\t\t\tSize = sizeof(ImDrawVert);\r\n\t\t\t}\r\n\r\n\t\t\tDeclaration = new VertexDeclaration(\r\n\t\t\t\tSize,\r\n\r\n\t\t\t\t// Position\r\n\t\t\t\tnew VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),\r\n\r\n\t\t\t\t// UV\r\n\t\t\t\tnew VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),\r\n\r\n\t\t\t\t// Color\r\n\t\t\t\tnew VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color, 0)\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/ImConnection.cs",
    "content": "using System.Collections.Generic;\nusing System.Numerics;\nusing BurningKnight.ui.imgui.node;\n\nnamespace BurningKnight.ui.imgui {\n\tpublic class ImConnection {\n\t\tpublic Vector2 Offset;\n\t\tpublic List<ImConnection> ConnectedTo = new List<ImConnection>();\n\t\tpublic ImNode Parent;\n\t\tpublic bool Input;\n\t\tpublic int Id;\n\t\tpublic bool Active;\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/ImGuiRenderer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Net.Mime;\nusing System.Runtime.InteropServices;\nusing ImGuiNET;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing Microsoft.Xna.Framework.Input;\nusing Vector2 = System.Numerics.Vector2;\n\nnamespace BurningKnight.ui.imgui {\n    public class ImGuiRenderer\n    {\n        private Game _game;\n\n        // Graphics\n        private GraphicsDevice _graphicsDevice;\n\n        private BasicEffect _effect;\n        private RasterizerState _rasterizerState;\n\n        private byte[] _vertexData;\n        private VertexBuffer _vertexBuffer;\n        private int _vertexBufferSize;\n\n        private byte[] _indexData;\n        private IndexBuffer _indexBuffer;\n        private int _indexBufferSize;\n\n        // Textures\n        private Dictionary<IntPtr, Texture2D> _loadedTextures;\n\n        private int _textureId;\n        private IntPtr? _fontTextureId;\n\n        // Input\n        private int _scrollWheelValue;\n\n        private List<int> _keys = new List<int>();\n\n        public ImGuiRenderer(Game game)\n        {\n            var context = ImGui.CreateContext();\n            ImGui.SetCurrentContext(context);\n\n            _game = game ?? throw new ArgumentNullException(nameof(game));\n            _graphicsDevice = game.GraphicsDevice;\n\n            _loadedTextures = new Dictionary<IntPtr, Texture2D>();\n\n            _rasterizerState = new RasterizerState()\n            {\n                CullMode = CullMode.None,\n                DepthBias = 0,\n                FillMode = FillMode.Solid,\n                MultiSampleAntiAlias = false,\n                ScissorTestEnable = true,\n                SlopeScaleDepthBias = 0\n            };\n\n            SetupInput();\n        }\n\n        #region ImGuiRenderer\n\n        /// <summary>\n        /// Creates a texture and loads the font data from ImGui. Should be called when the <see cref=\"GraphicsDevice\" /> is initialized but before any rendering is done\n        /// </summary>\n        public virtual unsafe void RebuildFontAtlas()\n        {\n            // Get font texture from ImGui\n            var io = ImGui.GetIO();\n            io.Fonts.GetTexDataAsRGBA32(out byte* pixelData, out int width, out int height, out int bytesPerPixel);\n\n            // Copy the data to a managed array\n            var pixels = new byte[width * height * bytesPerPixel];\n            unsafe { Marshal.Copy(new IntPtr(pixelData), pixels, 0, pixels.Length); }\n\n            // Create and register the texture as an XNA texture\n            var tex2d = new Texture2D(_graphicsDevice, width, height, false, SurfaceFormat.Color);\n            tex2d.SetData(pixels);\n\n            // Should a texture already have been build previously, unbind it first so it can be deallocated\n            if (_fontTextureId.HasValue) UnbindTexture(_fontTextureId.Value);\n\n            // Bind the new texture to an ImGui-friendly id\n            _fontTextureId = BindTexture(tex2d);\n\n            // Let ImGui know where to find the texture\n            io.Fonts.SetTexID(_fontTextureId.Value);\n            io.Fonts.ClearTexData(); // Clears CPU side texture data\n        }\n\n        /// <summary>\n        /// Creates a pointer to a texture, which can be passed through ImGui calls such as <see cref=\"ImGui.Image\" />. That pointer is then used by ImGui to let us know what texture to draw\n        /// </summary>\n        public virtual IntPtr BindTexture(Texture2D texture)\n        {\n            var id = new IntPtr(_textureId++);\n\n            _loadedTextures.Add(id, texture);\n\n            return id;\n        }\n\n        /// <summary>\n        /// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated\n        /// </summary>\n        public virtual void UnbindTexture(IntPtr textureId)\n        {\n            _loadedTextures.Remove(textureId);\n        }\n\n        /// <summary>\n        /// Sets up ImGui for a new frame, should be called at frame start\n        /// </summary>\n        public virtual void BeforeLayout(GameTime gameTime)\n        {\n            ImGui.GetIO().DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;\n\n            UpdateInput();\n\n            ImGui.NewFrame();\n        }\n\n        /// <summary>\n        /// Asks ImGui for the generated geometry data and sends it to the graphics pipeline, should be called after the UI is drawn using ImGui.** calls\n        /// </summary>\n        public virtual void AfterLayout()\n        {\n            ImGui.Render();\n\n            unsafe { RenderDrawData(ImGui.GetDrawData()); }\n        }\n\n        #endregion ImGuiRenderer\n\n        #region Setup & Update\n\n        /// <summary>\n        /// Maps ImGui keys to XNA keys. We use this later on to tell ImGui what keys were pressed\n        /// </summary>\n        protected virtual void SetupInput()\n        {\n            var io = ImGui.GetIO();\n\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Tab] = (int)Keys.Tab);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Keys.Left);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Keys.Right);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Keys.Up);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Keys.Down);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.PageUp] = (int)Keys.PageUp);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.PageDown] = (int)Keys.PageDown);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Home] = (int)Keys.Home);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.End] = (int)Keys.End);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Delete] = (int)Keys.Delete);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keys.Back);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Enter] = (int)Keys.Enter);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Escape] = (int)Keys.Escape);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.A] = (int)Keys.A);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.C] = (int)Keys.C);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.V] = (int)Keys.V);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.X] = (int)Keys.X);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Y] = (int)Keys.Y);\n            _keys.Add(io.KeyMap[(int)ImGuiKey.Z] = (int)Keys.Z);\n\n            // MonoGame-specific //////////////////////\n            _game.Window.TextInput += (s, a) =>\n            {\n                if (a.Character == '\\t') return;\n\n                io.AddInputCharacter(a.Character);\n            };\n            ///////////////////////////////////////////\n\n            // FNA-specific ///////////////////////////\n            //TextInputEXT.TextInput += c =>\n            //{\n            //    if (c == '\\t') return;\n\n            //    ImGui.GetIO().AddInputCharacter(c);\n            //};\n            ///////////////////////////////////////////\n\n            // ImGui.GetIO().Fonts.AddFontDefault();\n            ImGui.GetIO().Fonts.AddFontFromFileTTF(\"Content/Fonts/font.ttf\", 16.0f, null, ImGui.GetIO().Fonts.GetGlyphRangesCyrillic());\n        }\n\n        /// <summary>\n        /// Updates the <see cref=\"Effect\" /> to the current matrices and texture\n        /// </summary>\n        protected virtual Effect UpdateEffect(Texture2D texture)\n        {\n            _effect = _effect ?? new BasicEffect(_graphicsDevice);\n\n            var io = ImGui.GetIO();\n\n            // MonoGame-specific //////////////////////\n            var offset = .5f;\n            ///////////////////////////////////////////\n\n            // FNA-specific ///////////////////////////\n            //var offset = 0f;\n            ///////////////////////////////////////////\n\n            _effect.World = Matrix.Identity;\n            _effect.View = Matrix.Identity;\n            _effect.Projection = Matrix.CreateOrthographicOffCenter(offset, io.DisplaySize.X + offset, io.DisplaySize.Y + offset, offset, -1f, 1f);\n            _effect.TextureEnabled = true;\n            _effect.Texture = texture;\n            _effect.VertexColorEnabled = true;\n\n            return _effect;\n        }\n\n        /// <summary>\n        /// Sends XNA input state to ImGui\n        /// </summary>\n        protected virtual void UpdateInput()\n        {\n            var io = ImGui.GetIO();\n\n            var mouse = Mouse.GetState();\n            var keyboard = Keyboard.GetState();\n\n            for (int i = 0; i < _keys.Count; i++)\n            {\n                io.KeysDown[_keys[i]] = keyboard.IsKeyDown((Keys)_keys[i]);\n            }\n\n            io.KeyShift = keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift);\n            io.KeyCtrl = keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl);\n            io.KeyAlt = keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt);\n            io.KeySuper = keyboard.IsKeyDown(Keys.LeftWindows) || keyboard.IsKeyDown(Keys.RightWindows);\n\n            io.DisplaySize = new System.Numerics.Vector2(_graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight);\n            io.DisplayFramebufferScale = new System.Numerics.Vector2(1f, 1f);\n\n            io.MousePos = new System.Numerics.Vector2(mouse.X, mouse.Y);\n\n            io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;\n            io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;\n            io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;\n\n            var scrollDelta = mouse.ScrollWheelValue - _scrollWheelValue;\n            io.MouseWheel = scrollDelta > 0 ? 1 : scrollDelta < 0 ? -1 : 0;\n            _scrollWheelValue = mouse.ScrollWheelValue;\n        }\n\n        #endregion Setup & Update\n\n        #region Internals\n\n        /// <summary>\n        /// Gets the geometry as set up by ImGui and sends it to the graphics device\n        /// </summary>\n        private void RenderDrawData(ImDrawDataPtr drawData)\n        {\n            // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers\n            var lastViewport = _graphicsDevice.Viewport;\n            var lastScissorBox = _graphicsDevice.ScissorRectangle;\n\n            _graphicsDevice.BlendFactor = Color.White;\n            _graphicsDevice.BlendState = BlendState.NonPremultiplied;\n            _graphicsDevice.RasterizerState = _rasterizerState;\n            _graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;\n\n            // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)\n            drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale);\n\n            // Setup projection\n            _graphicsDevice.Viewport = new Viewport(0, 0, _graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight);\n\n            UpdateBuffers(drawData);\n\n            RenderCommandLists(drawData);\n\n            // Restore modified state\n            _graphicsDevice.Viewport = lastViewport;\n            _graphicsDevice.ScissorRectangle = lastScissorBox;\n        }\n\n        private unsafe void UpdateBuffers(ImDrawDataPtr drawData)\n        {\n            if (drawData.TotalVtxCount == 0)\n            {\n                return;\n            }\n\n            // Expand buffers if we need more room\n            if (drawData.TotalVtxCount > _vertexBufferSize)\n            {\n                _vertexBuffer?.Dispose();\n\n                _vertexBufferSize = (int)(drawData.TotalVtxCount * 1.5f);\n                _vertexBuffer = new VertexBuffer(_graphicsDevice, DrawVertDeclaration.Declaration, _vertexBufferSize, BufferUsage.None);\n                _vertexData = new byte[_vertexBufferSize * DrawVertDeclaration.Size];\n            }\n\n            if (drawData.TotalIdxCount > _indexBufferSize)\n            {\n                _indexBuffer?.Dispose();\n\n                _indexBufferSize = (int)(drawData.TotalIdxCount * 1.5f);\n                _indexBuffer = new IndexBuffer(_graphicsDevice, IndexElementSize.SixteenBits, _indexBufferSize, BufferUsage.None);\n                _indexData = new byte[_indexBufferSize * sizeof(ushort)];\n            }\n\n            // Copy ImGui's vertices and indices to a set of managed byte arrays\n            int vtxOffset = 0;\n            int idxOffset = 0;\n\n            for (int n = 0; n < drawData.CmdListsCount; n++)\n            {\n                ImDrawListPtr cmdList = drawData.CmdListsRange[n];\n\n                fixed (void* vtxDstPtr = &_vertexData[vtxOffset * DrawVertDeclaration.Size])\n                fixed (void* idxDstPtr = &_indexData[idxOffset * sizeof(ushort)])\n                {\n                    Buffer.MemoryCopy((void*)cmdList.VtxBuffer.Data, vtxDstPtr, _vertexData.Length, cmdList.VtxBuffer.Size * DrawVertDeclaration.Size);\n                    Buffer.MemoryCopy((void*)cmdList.IdxBuffer.Data, idxDstPtr, _indexData.Length, cmdList.IdxBuffer.Size * sizeof(ushort));\n                }\n\n                vtxOffset += cmdList.VtxBuffer.Size;\n                idxOffset += cmdList.IdxBuffer.Size;\n            }\n\n            // Copy the managed byte arrays to the gpu vertex- and index buffers\n            _vertexBuffer.SetData(_vertexData, 0, drawData.TotalVtxCount * DrawVertDeclaration.Size);\n            _indexBuffer.SetData(_indexData, 0, drawData.TotalIdxCount * sizeof(ushort));\n        }\n\n        private unsafe void RenderCommandLists(ImDrawDataPtr drawData)\n        {\n            _graphicsDevice.SetVertexBuffer(_vertexBuffer);\n            _graphicsDevice.Indices = _indexBuffer;\n\n            int vtxOffset = 0;\n            int idxOffset = 0;\n\n            for (int n = 0; n < drawData.CmdListsCount; n++)\n            {\n                ImDrawListPtr cmdList = drawData.CmdListsRange[n];\n\n                for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++)\n                {\n                    ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi];\n\n                    if (!_loadedTextures.ContainsKey(drawCmd.TextureId))\n                    {\n                        throw new InvalidOperationException($\"Could not find a texture with id '{drawCmd.TextureId}', please check your bindings\");\n                    }\n\n                    _graphicsDevice.ScissorRectangle = new Rectangle(\n                        (int)drawCmd.ClipRect.X,\n                        (int)drawCmd.ClipRect.Y,\n                        (int)(drawCmd.ClipRect.Z - drawCmd.ClipRect.X),\n                        (int)(drawCmd.ClipRect.W - drawCmd.ClipRect.Y)\n                    );\n\n                    var effect = UpdateEffect(_loadedTextures[drawCmd.TextureId]);\n\n                    foreach (var pass in effect.CurrentTechnique.Passes)\n                    {\n                        pass.Apply();\n\n#pragma warning disable CS0618 // // FNA does not expose an alternative method.\n                        _graphicsDevice.DrawIndexedPrimitives(\n                            primitiveType: PrimitiveType.TriangleList,\n                            baseVertex: vtxOffset,\n                            minVertexIndex: 0,\n                            numVertices: cmdList.VtxBuffer.Size,\n                            startIndex: idxOffset,\n                            primitiveCount: (int)drawCmd.ElemCount / 3\n                        );\n#pragma warning restore CS0618\n                    }\n\n                    idxOffset += (int)drawCmd.ElemCount;\n                }\n\n                vtxOffset += cmdList.VtxBuffer.Size;\n            }\n        }\n\n        #endregion Internals\n    }\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/ImNodes.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.ui.imgui.node;\nusing ImGuiNET;\n\nnamespace BurningKnight.ui.imgui {\n\tpublic static class ImNodes {\n\t\tpublic static Dictionary<int, ImNode> Nodes = new Dictionary<int, ImNode>();\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/LocaleEditor.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.input;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace BurningKnight.ui.imgui {\n\tpublic static unsafe class LocaleEditor {\n\t\tprivate static ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null));\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\n\t\tprivate static bool filterByKey = true;\n\t\tprivate static System.Numerics.Vector2 spacer = new System.Numerics.Vector2(4, 1);\n\t\tprivate static List<ModifiedInfo> modified = new List<ModifiedInfo>();\n\t\tprivate static string[] aviableLocales;\n\t\tprivate static int locale;\n\t\tprivate static string newKey = \"\";\n\t\tprivate static string created;\n\t\tprivate static bool showEnglish = true;\n\t\tprivate static string newLocaleName = \"\";\n\t\t\n\t\tprivate class ModifiedInfo {\n\t\t\tpublic string OldKey;\n\t\t\tpublic string OldValue;\n\t\t\tpublic string Key;\n\t\t\tpublic string Value;\n\t\t\tpublic bool KeyChanged;\n\t\t}\n\n\t\tstatic LocaleEditor() {\n\t\t\tvar locales = FileHandle.FromRoot(\"Locales/\");\n\n\t\t\tif (!locales.Exists()) {\n\t\t\t\taviableLocales = new[] { \"en\" };\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar names = new List<string>();\n\n\t\t\tforeach (var f in locales.ListFileHandles()) {\n\t\t\t\tif (f.Extension == \".json\") {\n\t\t\t\t\tnames.Add(f.NameWithoutExtension);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\taviableLocales = names.ToArray();\n\t\t\tlocale = names.IndexOf(Locale.Current);\n\t\t}\n\t\t\n\t\tpublic static void Render() {\n\t\t\tif (!WindowManager.LocaleEditor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SetNextWindowSize(size, ImGuiCond.Once);\n\t\t\t\n\t\t\tif (!ImGui.Begin(\"Locale editor\")) {\n\t\t\t\tImGui.End();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (ImGui.Combo(\"##locale\", ref locale, aviableLocales, aviableLocales.Length)) {\n\t\t\t\tLocale.Load(aviableLocales[locale]);\t\n\t\t\t}\n\t\t\t\n\t\t\tImGui.SameLine();\n\n\t\t\tif (ImGui.Button(\"Save\")) {\n\t\t\t\tLocale.Save();\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif (ImGui.Button(\"New\")) {\n\t\t\t\tImGui.OpenPopup(\"New locale\");\n\t\t\t}\n\t\t\t\n\t\t\tif (ImGui.BeginPopupModal(\"New locale\")) {\n\t\t\t\tImGui.SetItemDefaultFocus();\n\t\t\t\tvar input = ImGui.InputText(\"Name\", ref newLocaleName, 3, ImGuiInputTextFlags.EnterReturnsTrue);\n\t\t\t\tvar button = ImGui.Button(\"Create\");\n\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Cancel\")) {\n\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\tnewLocaleName = \"\";\n\t\t\t\t} else {\n\t\t\t\t\tif (input || button) {\n\t\t\t\t\t\tLocale.Current = newLocaleName;\n\t\t\t\t\t\tLocale.Map = new Dictionary<string, string>();\n\t\t\t\t\t\tLocale.Loaded[newLocaleName] = Locale.Map;\n\t\t\t\t\t\n\t\t\t\t\t\tvar list = aviableLocales.ToList();\n\t\t\t\t\t\tlist.Add(newLocaleName);\n\t\t\t\t\t\taviableLocales = list.ToArray();\n\t\t\t\t\t\tlocale = list.Count - 1;\n\n\t\t\t\t\t\tnewLocaleName = \"\";\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t}\t\n\t\t\t\t}\n\n\t\t\t\tImGui.EndPopup();\n\t\t\t}\n\n\t\t\tvar notEng = aviableLocales[locale] != \"en\";\n\n\t\t\tif (notEng) {\n\t\t\t\tif (ImGui.Button(\"Clear\")) {\n\t\t\t\t\tLocale.Map.Clear();\n\t\t\t\t}\n\n\t\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\t\tif (ImGui.Button(\"Delete\")) {\n\t\t\t\t\tImGui.OpenPopup(\"Delete?\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (ImGui.BeginPopupModal(\"Delete?\")) {\n\t\t\t\t\tImGui.Text(\"This operation can't be undone!\");\n\t\t\t\t\tImGui.Text(\"Are you sure?\");\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button(\"Yes\")) {\n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t\tvar list = aviableLocales.ToList();\n\t\t\t\t\t\tlist.Remove(Locale.Current);\n\t\t\t\t\t\taviableLocales = list.ToArray();\n\t\t\t\t\t\tlocale = 0;\n\t\t\t\t\t\tLocale.Delete();\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\tImGui.SetItemDefaultFocus();\n\t\t\t\t\t\n\t\t\t\t\tif (ImGui.Button(\"No\")) { \n\t\t\t\t\t\tImGui.CloseCurrentPopup();\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.EndPopup();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (notEng) {\n\t\t\t\tImGui.SameLine();\n\n\t\t\t\tif (ImGui.Button(\"Add en\")) {\n\t\t\t\t\tforeach (var t in Locale.Fallback) {\n\t\t\t\t\t\tif (!Locale.Map.ContainsKey(t.Key)) {\n\t\t\t\t\t\t\tLocale.Map[t.Key] = t.Value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui.Text(notEng ? $\"{Locale.Map.Count} entries (en has {Locale.Fallback.Count})\" : $\"{Locale.Map.Count} entries\");\n\n\t\t\tif (notEng) {\n\t\t\t\tImGui.Checkbox(\"Show english\", ref showEnglish);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tfilter.Draw(\"\");\n\t\t\tImGui.SameLine();\n\t\t\tImGui.Checkbox(\"By key\", ref filterByKey);\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\tvar height = ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeightWithSpacing() + 4;\n\t\t\tImGui.BeginChild(\"ScrollingRegionLocale\", new System.Numerics.Vector2(0, -height), \n\t\t\t\tfalse);\n\t\t\tImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, spacer);\n\n\t\t\tvar i = 0;\n\t\t\tstring remove = null;\n\t\t\t\n\t\t\tforeach (var t in Locale.Map) {\n\t\t\t\tif (filter.PassFilter(filterByKey ? t.Key : t.Value)) {\n\t\t\t\t\tvar key = t.Key;\n\t\t\t\t\tvar value = t.Value;\n\n\t\t\t\t\tImGui.PushItemWidth(100);\n\t\t\t\t\tImGui.PushID($\"{i}__key\");\n\t\t\t\t\t\n\t\t\t\t\tif (notEng && showEnglish && Locale.Fallback.TryGetValue(t.Key, out var en)) {\n\t\t\t\t\t\tImGui.InputText(\"\", ref en, 64);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tImGui.InputText(\"\", ref key, 64);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tImGui.PopID();\n\t\t\t\t\tImGui.PopItemWidth();\n\t\t\t\t\tImGui.SameLine();\n\t\t\t\t\tImGui.PushID($\"{i}__value\");\n\t\t\t\t\tImGui.InputText(\"\", ref value, 256);\n\n\t\t\t\t\tif (created == t.Key) {\n\t\t\t\t\t\tImGui.SetKeyboardFocusHere(-1);\n\t\t\t\t\t\tImGui.SetScrollHereY(-1);\n\t\t\t\t\t\tcreated = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (key != t.Key || value != t.Value) {\n\t\t\t\t\t\tmodified.Add(new ModifiedInfo {\n\t\t\t\t\t\t\tOldKey = t.Key,\n\t\t\t\t\t\t\tOldValue = t.Value,\n\t\t\t\t\t\t\tKey = key,\n\t\t\t\t\t\t\tValue = value,\n\t\t\t\t\t\t\tKeyChanged = key != t.Key\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui.SameLine();\n\n\t\t\t\t\tif (ImGui.SmallButton(\"-\")) {\n\t\t\t\t\t\tremove = t.Key;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tif (remove != null) {\n\t\t\t\tLocale.Map.Remove(remove);\n\t\t\t}\n\t\t\t\n\t\t\tImGui.PopStyleVar();\n\t\t\tImGui.EndChild();\n\t\t\tImGui.Separator();\n\n\t\t\tvar enter = ImGui.InputText(\"##newkey\", ref newKey, 128, ImGuiInputTextFlags.EnterReturnsTrue);\n\t\t\tImGui.SameLine();\n\t\t\t\n\t\t\tif ((enter || ImGui.Button(\"Add\")) && newKey.Length > 0) {\n\t\t\t\tmodified.Add(new ModifiedInfo {\n\t\t\t\t\tKey = newKey,\n\t\t\t\t\tValue = newKey\n\t\t\t\t});\n\n\t\t\t\tcreated = newKey;\n\t\t\t\tnewKey = \"\";\n\t\t\t}\n\n\t\t\tif (modified.Count > 0) {\n\t\t\t\tforeach (var t in modified) {\n\t\t\t\t\tif (t.OldKey != null) {\n\t\t\t\t\t\tLocale.Map.Remove(t.KeyChanged ? t.OldKey : Locale.Map.FirstOrDefault(m => m.Value == t.OldValue).Key);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (t.Key.Length > 0) {\n\t\t\t\t\t\tLocale.Map[t.Key] = t.Value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmodified.Clear();\n\t\t\t}\n\n\t\t\tImGui.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/WindowManager.cs",
    "content": "using System.Collections.Generic;\r\nusing System.Numerics;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.debug;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.entity.room;\r\nusing BurningKnight.level.rooms.regular;\r\nusing BurningKnight.save;\r\nusing BurningKnight.save.statistics;\r\nusing BurningKnight.state;\r\nusing ImGuiNET;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\n\r\nnamespace BurningKnight.ui.imgui {\r\n\tpublic static class WindowManager {\r\n\t\tprivate static Vector2 size;\r\n\r\n\t\tpublic static bool Cheats;\r\n\t\tpublic static bool Debug;\r\n\t\tpublic static bool Entities;\r\n\t\tpublic static bool RunInfo;\r\n\t\tpublic static bool Console = true;\r\n\t\tpublic static bool ItemEditor;\r\n\t\tpublic static bool LevelEditor;\r\n\t\tpublic static bool LayerDebug;\r\n\t\tpublic static bool LocaleEditor;\r\n\t\tpublic static bool Rooms;\r\n\t\tpublic static bool Settings;\r\n\t\tpublic static bool Lighting;\r\n\t\tpublic static bool Achievements;\r\n\t\tpublic static bool Save;\r\n\t\tpublic static bool PoolEditor;\r\n\t\tpublic static bool LootTable;\r\n\t\t\r\n\t\tprivate static void RenderSettings() {\r\n\t\t\tif (!Settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tif (!ImGui.Begin(\"Settings\")) {\r\n\t\t\t\tImGui.End();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar v = AudioEmitterComponent.PositionScale * 100;\r\n\t\t\tImGui.InputFloat(\"Position scale\", ref v);\r\n\t\t\tAudioEmitterComponent.PositionScale = v / 100;\r\n\t\t\tImGui.InputFloat(\"Distance\", ref AudioEmitterComponent.Distance);\r\n\t\t\tImGui.InputFloat(\"Speed\", ref Audio.Speed);\r\n\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Render(Area Area) {\r\n\t\t\tCheatWindow.Render();\r\n\t\t\tAreaDebug.Render(Area);\r\n\t\t\tDebugWindow.Render();\r\n\t\t\t\r\n\t\t\timgui.LocaleEditor.Render();\t\t\t\r\n\t\t\tdebug.PoolEditor.Render();\r\n\t\t\tstate.ItemEditor.Render();\r\n\t\t\tRenderSettings();\r\n\t\t\tLights.RenderDebug();\r\n\t\t\tSaveDebug.RenderDebug();\r\n\t\t\tLevelLayerDebug.Render();\r\n\t\t\tLootTableEditor.Render();\r\n\t\t\tassets.achievements.Achievements.RenderDebug();\r\n\r\n\t\t\tRunStatistics.RenderDebug();\r\n\r\n\t\t\tif (Rooms && ImGui.Begin(\"Rooms\", ImGuiWindowFlags.AlwaysAutoResize)) {\r\n\t\t\t\tvar p = LocalPlayer.Locate(Area);\r\n\r\n\t\t\t\tif (p != null) {\r\n\t\t\t\t\tvar rm = p.GetComponent<RoomComponent>().Room;\r\n\t\t\t\t\tvar rn = new List<Room>();\r\n\r\n\t\t\t\t\tforeach (var r in Area.Tagged[Tags.Room]) {\r\n\t\t\t\t\t\trn.Add((Room) r);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\trn.Sort((a, b) => a.Type.CompareTo(b.Type));\r\n\t\t\t\t\t\r\n\t\t\t\t\tforeach (var r in rn) {\r\n\t\t\t\t\t\tvar v = rm == r;\r\n\r\n\t\t\t\t\t\tif (ImGui.Selectable($\"{r.Type}#{r.Y}\", ref v) && v) {\r\n\t\t\t\t\t\t\tp.Center = r.Center;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tImGui.End();\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SetNextWindowPos(new Vector2(Engine.Instance.GetScreenWidth() - size.X - 10, Engine.Instance.GetScreenHeight() - size.Y - 10));\r\n\t\t\tImGui.Begin(\"Windows\", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoTitleBar);\r\n\r\n\t\t\tif (ImGui.Button(\"Hide\")) {\r\n\t\t\t\tDebug = Entities = RunInfo = Console = ItemEditor = LevelEditor = LocaleEditor = Rooms = Settings = PoolEditor = LootTable = false;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.SameLine();\r\n\r\n\t\t\tif (ImGui.Button(\"Show\")) {\r\n\t\t\t\tDebug = Entities = RunInfo = Console = ItemEditor = LevelEditor = LocaleEditor = Rooms = Settings = PoolEditor = LootTable = true;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tImGui.Separator();\r\n\t\t\t\r\n\t\t\tImGui.Checkbox(\"Cheats\", ref Cheats);\r\n\t\t\tImGui.Checkbox(\"Entities\", ref Entities);\r\n\t\t\tImGui.Checkbox(\"Run Info\", ref RunInfo);\r\n\t\t\tImGui.Checkbox(\"Console\", ref Console);\r\n\t\t\tImGui.Checkbox(\"Item Editor\", ref ItemEditor);\r\n\t\t\tImGui.Checkbox(\"Level Editor\", ref LevelEditor);\r\n\t\t\tImGui.Checkbox(\"Layer Debug\", ref LayerDebug);\r\n\t\t\tImGui.Checkbox(\"Locale Editor\", ref LocaleEditor);\r\n\t\t\tImGui.Checkbox(\"Debug\", ref Debug);\r\n\t\t\tImGui.Checkbox(\"Rooms\", ref Rooms);\r\n\t\t\tImGui.Checkbox(\"Settings\", ref Settings);\r\n\t\t\tImGui.Checkbox(\"Lighting\", ref Lighting);\r\n\t\t\tImGui.Checkbox(\"Achievements\", ref Achievements);\r\n\t\t\tImGui.Checkbox(\"Save\", ref Save);\r\n\t\t\tImGui.Checkbox(\"Pool Editor\", ref PoolEditor);\r\n\t\t\tImGui.Checkbox(\"Loot Table Editor\", ref LootTable);\r\n\t\t\t\r\n\t\t\tsize = ImGui.GetWindowSize();\r\n\t\t\tImGui.End();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImAnswerNode.cs",
    "content": "using BurningKnight.ui.dialog;\r\nusing ImGuiNET;\r\nusing Lens.lightJson;\r\n\r\nnamespace BurningKnight.ui.imgui.node {\r\n\tpublic class ImAnswerNode : ImDialogNode {\r\n\t\tprivate int type;\r\n\t\t\r\n\t\tpublic override void RenderElements() {\r\n\t\t\tbase.RenderElements();\r\n\t\t\tImGui.Combo(\"Type\", ref type, AnswerDialog.Types, AnswerDialog.Types.Length);\r\n\t\t}\r\n\r\n\t\tprotected override Dialog CreateDialog(string id, string[] variants) {\r\n\t\t\treturn new AnswerDialog(id, (AnswerType) type, variants);\r\n\t\t}\r\n\r\n\t\tpublic override void Save(JsonObject root) {\r\n\t\t\tbase.Save(root);\r\n\t\t\troot[\"atype\"] = type;\r\n\t\t}\r\n\r\n\t\tpublic override void Load(JsonObject root) {\r\n\t\t\tbase.Load(root);\r\n\t\t\ttype = root[\"atype\"].Int(0);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImChoiceNode.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.ui.dialog;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.lightJson;\n\nnamespace BurningKnight.ui.imgui.node {\n\tpublic class ImChoiceNode : ImNode, DialogNode {\n\t\tprivate List<string> choices = new List<string>();\n\t\tprivate string label = \"\";\n\t\tprivate string name = \"\";\n\n\t\tpublic ImChoiceNode() {\n\t\t\tAddInput();\n\t\t}\n\n\t\tpublic override string GetName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic override void RenderElements() {\n\t\t\tif (choices.Count == 0) {\n\t\t\t\tchoices.Add(\"\");\n\t\t\t\tAddOutput();\n\t\t\t}\n\t\t\t\n\t\t\tInputs[0].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\n\t\t\tImGui.PushItemWidth(200);\n\t\t\t\n\t\t\tif (ImGui.InputText($\"##{name}\", ref label, 256, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tname = label;\n\t\t\t}\n\n\t\t\tImGui.SameLine();\n\t\t\t\t\n\t\t\tvar add = ImGui.Button(\"+##choice\");\n\t\t\tImGui.PopItemWidth();\n\t\t\tImGui.Separator();\n\t\t\t\n\t\t\tvar i = 0;\n\t\t\tvar toRemove = -1;\n\t\t\t\n\t\t\tforeach (var output in Outputs) {\n\t\t\t\tvar s = choices[i];\n\t\t\t\toutput.Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\n\t\t\t\tImGui.Bullet();\n\t\t\t\tImGui.SameLine();\n\t\t\t\tImGui.PushItemWidth(200);\n\n\t\t\t\tImGui.InputText($\"##s_{i}\", ref s, 512);\n\t\t\t\tchoices[i] = s;\n\n\t\t\t\tImGui.PopItemWidth();\n\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tImGui.SameLine();\n\n\t\t\t\t\tif (ImGui.Button($\"-##{i}\")) {\n\t\t\t\t\t\ttoRemove = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tif (toRemove > -1) {\n\t\t\t\tchoices.RemoveAt(toRemove);\n\t\t\t\tRemoveConnection(Outputs[toRemove], true);\n\t\t\t}\n\n\t\t\tif (add) {\n\t\t\t\tchoices.Add(\"\");\n\t\t\t\tAddOutput();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Save(JsonObject root) {\n\t\t\tbase.Save(root);\n\n\t\t\tvar i = 0;\n\t\t\t\n\t\t\tforeach (var c in choices) {\n\t\t\t\tLocale.Map[$\"{LocaleId}_{i}\"] = c;\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\troot[\"cc\"] = choices.Count;\n\t\t\tLocale.Map[LocaleId] = name;\n\t\t}\n\n\t\tpublic override void Load(JsonObject root) {\n\t\t\tbase.Load(root);\n\n\t\t\tfor (var i = 0; i < root[\"cc\"]; i++) {\n\t\t\t\tchoices.Add($\"{LocaleId}_{i}\");\n\t\t\t\tAddOutput();\n\t\t\t}\n\n\t\t\tname = Locale.Map[LocaleId];\n\t\t\tlabel = name;\n\t\t}\n\n\t\tpublic Dialog Convert() {\n\t\t\tList<string[]> variants = null;\n\t\t\t\n\t\t\tif (Outputs.Count > 0) {\n\t\t\t\tvariants = new List<string[]>();\n\t\t\t\t\n\t\t\t\tforeach (var o in Outputs) {\n\t\t\t\t\tif (o.ConnectedTo.Count > 0) {\n\t\t\t\t\t\tvar list = new string[o.ConnectedTo.Count];\n\n\t\t\t\t\t\tfor (var j = 0; j < o.ConnectedTo.Count; j++) {\n\t\t\t\t\t\t\tlist[j] = o.ConnectedTo[j].Parent.LocaleId;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvariants.Add(list);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn new ChoiceDialog(LocaleId, choices.ToArray(), variants);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImDialogNode.cs",
    "content": "namespace BurningKnight.ui.imgui.node {\n\tpublic class ImDialogNode : ImTextNode {\n\t\tpublic ImDialogNode() {\n\t\t\tAddInput();\n\t\t\tAddOutput();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImNode.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing ImGuiNET;\nusing Lens.input;\nusing Lens.lightJson;\nusing Lens.util;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing Vector2 = System.Numerics.Vector2;\n\nnamespace BurningKnight.ui.imgui.node {\n\tpublic class ImNode {\n\t\tpublic const int InputHalfHeight = 8;\n\t\tprivate const int connectorRadius = 7;\n\t\tprivate const int connectorRadiusSquare = connectorRadius * connectorRadius;\n\n\t\tprivate static Color connectorColor = new Color(0.6f, 0.6f, 0.6f, 1f); \n\t\tprivate static Color hoveredConnectorColor = new Color(1f, 1f, 1f, 1f);\n\t\tprivate static Color connectionColor = new Color(0.6f, 1f, 0.6f, 0.6f);\n\t\tprivate static Color hoveredConnectionColor = new Color(0.3f, 1f, 0.3f, 1f);\n\t\tprivate static Color nodeBg = new Color(0f, 0f, 0f, 0.8f);\n\t\tprivate static Color hoveredNodeBg = new Color(0.1f, 0.1f, 0.1f, 0.8f);\n\t\tprivate static Color activeNodeBg = new Color(0.2f, 0.2f, 0.2f, 0.8f);\n\t\tprivate static Vector2 connectorVector = new Vector2(connectorRadius);\n\t\tpublic static int LastId;\n\t\t\n\t\tpublic static ImNode Focused;\n\t\tpublic static Vector2 Offset;\n\n\t\tpublic int Id;\n\t\tpublic Vector2 Position;\n\t\tpublic Vector2 RealPosition;\n\t\tpublic Vector2 Size;\n\t\tpublic List<ImConnection> Inputs = new List<ImConnection>();\n\t\tpublic List<ImConnection> Outputs = new List<ImConnection>();\n\t\tpublic ImConnection CurrentActive;\n\t\tpublic bool Done;\n\t\tpublic string Tip;\n\t\tpublic string File;\n\t\t\n\t\tpublic string LocaleId => $\"{File}_{Id}\";\n\t\t\n\t\tpublic ImNode() {\n\t\t\tId = LastId++;\n\t\t}\n\n\t\tprivate static bool IsConnectorHovered(Vector2 connector) {\n\t\t\tvar mouse = ImGui.GetIO().MousePos;\n\n\t\t\tvar dx = mouse.X - connector.X;\n\t\t\tvar dy = mouse.Y - connector.Y;\n\n\t\t\treturn (dx * dx + dy * dy) < connectorRadiusSquare;\n\t\t}\n\n\t\tpublic void AddInput() {\n\t\t\tInputs.Add(new ImConnection {\n\t\t\t\tInput = true,\n\t\t\t\tParent = this,\n\t\t\t\tId = Inputs.Count\n\t\t\t});\n\t\t}\n\n\t\tpublic void AddOutput() {\n\t\t\tOutputs.Add(new ImConnection {\n\t\t\t\tParent = this,\n\t\t\t\tId = Outputs.Count\n\t\t\t});\n\t\t}\n\t\t\n\t\tprivate unsafe void RenderConnector(ImDrawListPtr list, ImConnection connection, Vector2 connector) {\n\t\t\tvar hovered = IsConnectorHovered(connector);\n\t\t\tlist.AddCircleFilled(connector, connectorRadius, (hovered ? hoveredConnectorColor : connectorColor).PackedValue);\n\n\t\t\tif ((connection.ConnectedTo.Count == 0 || connection.Input) && !OnScreen) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!OnScreen) {\n\t\t\t\tvar found = false;\n\n\t\t\t\tforeach (var c in connection.ConnectedTo) {\n\t\t\t\t\tif (c.Parent.OnScreen) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (hovered) {\n\t\t\t\tif (ImGui.IsMouseClicked(0)) {\n\t\t\t\t\tjustStarted = true;\n\n\t\t\t\t\tif (CurrentActive != null && CurrentActive == connection) {\n\t\t\t\t\t\tCurrentActive.Active = false;\n\t\t\t\t\t\tCurrentActive = null;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (CurrentActive != null) {\n\t\t\t\t\t\t\tCurrentActive.Active = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tCurrentActive = connection;\n\t\t\t\t\t\tCurrentActive.Active = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (ImGuiHelper.CurrentActive == null) {\n\t\t\t\t\t\t\tImGuiHelper.CurrentActive = this;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar active = ImGuiHelper.CurrentActive;\n\t\t\t\t\t\t\tImGuiHelper.CurrentActive = null;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (active.CurrentActive != CurrentActive && active.CurrentActive.Input != CurrentActive.Input) {\n\t\t\t\t\t\t\t\tactive.CurrentActive.ConnectedTo.Add(CurrentActive);\n\t\t\t\t\t\t\t\tCurrentActive.ConnectedTo.Add(active.CurrentActive);\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tactive.justStarted = true;\n\t\t\t\t\t\t\tactive.CurrentActive.Active = false;\n\t\t\t\t\t\t\tactive.CurrentActive = null;\n\n\t\t\t\t\t\t\tif (CurrentActive != null) {\n\t\t\t\t\t\t\t\tCurrentActive.Active = false;\n\t\t\t\t\t\t\t\tCurrentActive = null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (ImGui.IsMouseClicked(1) && connection.ConnectedTo.Count > 0) {\n\t\t\t\t\tRemoveConnection(connection);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!connection.Input && connection.ConnectedTo.Count > 0) {\n\t\t\t\tforeach (var to in connection.ConnectedTo) {\n\t\t\t\t\tvar p = to.Parent.Position + to.Offset;\n\t\t\t\t\tDrawHermite(ImGui.GetBackgroundDrawList(), connector, p, 12, hovered || IsConnectorHovered(p) ? hoveredConnectionColor : connectionColor);\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (CurrentActive == connection) {\n\t\t\t\tDrawHermite(ImGui.GetBackgroundDrawList(), connector, ImGui.GetIO().MousePos, 12, hovered ? hoveredConnectionColor : connectionColor);\t\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void RemoveConnection(ImConnection connection, bool remove = false) {\n\t\t\tif (ImGuiHelper.CurrentActive == this) {\n\t\t\t\tImGuiHelper.CurrentActive = null;\n\t\t\t} else {\n\t\t\t\tforeach (var to in connection.ConnectedTo) {\n\t\t\t\t\tif (ImGuiHelper.CurrentActive == to.Parent) {\n\t\t\t\t\t\tImGuiHelper.CurrentActive = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var to in connection.ConnectedTo) {\n\t\t\t\tto.Active = false;\n\t\t\t\tto.ConnectedTo.Remove(connection);\n\t\t\t\tto.Parent.CurrentActive = null;\n\t\t\t}\n\t\t\t\t\t\n\t\t\tconnection.ConnectedTo.Clear();\n\t\t\tconnection.Active = false;\n\n\t\t\tCurrentActive = null;\n\n\t\t\tif (remove) {\n\t\t\t\tif (connection.Input) {\n\t\t\t\t\tInputs.Remove(connection);\n\t\t\t\t} else {\n\t\t\t\t\tOutputs.Remove(connection);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate bool hovered;\n\t\tprivate bool focused;\n\t\tprivate bool justStarted;\n\t\tpublic bool ForceFocus;\n\t\tpublic bool New;\n\n\t\tprivate bool readPosition;\n\t\tprivate JsonArray outputs;\n\n\t\tpublic void RemoveEmptyConnection() {\n\t\t\tif (ImGuiHelper.CurrentActive == this) {\n\t\t\t\tif (justStarted) {\n\t\t\t\t\tjustStarted = false;\n\t\t\t\t} else if (ImGui.IsMouseClicked(0) && CurrentActive != null) {\n\t\t\t\t\tCurrentActive.Active = false;\n\t\t\t\t\tCurrentActive = null;\n\t\t\t\t\tImGuiHelper.CurrentActive = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool OnScreen;\n\n\t\tpublic void RenderConnections() {\n\t\t\tvar rightSide = Position + new Vector2(Size.X, 0);\n\t\t\tvar list = OnScreen ? ImGui.GetWindowDrawList() : ImGui.GetForegroundDrawList();\n\n\t\t\tlist.PushClipRect(Position - connectorVector, Position + Size + connectorVector);\n\n\t\t\tforeach (var input in Inputs) {\n\t\t\t\tRenderConnector(list, input, Position + input.Offset);\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var output in Outputs) {\n\t\t\t\tRenderConnector(list, output, rightSide + output.Offset);\n\t\t\t}\n\t\t\t\n\t\t\tlist.PopClipRect();\n\t\t}\n\t\t\n\t\tpublic void ReadOutputs() {\n\t\t\tvar j = -1;\n\n\t\t\tif (outputs != JsonValue.Null) {\n\t\t\t\tforeach (var i in outputs) {\n\t\t\t\t\tj++;\n\n\t\t\t\t\tif (!i.IsJsonArray) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\tforeach (var o in i.AsJsonArray) {\n\t\t\t\t\t\tif (!o.IsJsonArray || o.AsJsonArray.Count == 0) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tvar to = ImNodes.Nodes[o[0]];\n\t\t\t\t\t\tvar from = Outputs[j];\n\t\t\t\t\t\tvar where = to.Inputs[o[1]];\n\n\t\t\t\t\t\tfrom.ConnectedTo.Add(where);\n\t\t\t\t\t\twhere.ConnectedTo.Add(from);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toutputs = null;\n\t\t}\n\t\t\n\t\tpublic virtual void Render() {\n\t\t\tif (!New) {\n\t\t\t\tPosition = RealPosition + Offset;\n\t\t\t}\n\n\t\t\tif (readPosition && Camera.Instance != null && (Position.X + Size.X < 0 || Position.X > Camera.Instance.Width || Position.Y + Size.Y < 0 || Position.Y > Camera.Instance.Height)) {\n\t\t\t\tOnScreen = false;\n\t\t\t\tRenderConnections();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tOnScreen = true;\n\t\t\t\n\t\t\tif (outputs != null) {\n\t\t\t\tReadOutputs();\n\t\t\t}\n\t\t\t\n\t\t\tif (Focused != this) {\n\t\t\t\tfocused = false;\n\t\t\t\tForceFocus = false;\n\t\t\t}\n\t\t\t\n\t\t\tif (focused || ForceFocus) {\n\t\t\t\tImGui.PushStyleColor(ImGuiCol.WindowBg, activeNodeBg.PackedValue);\n\t\t\t} else if (hovered) {\n\t\t\t\tImGui.PushStyleColor(ImGuiCol.WindowBg, hoveredNodeBg.PackedValue);\n\t\t\t} else {\n\t\t\t\tImGui.PushStyleColor(ImGuiCol.WindowBg, nodeBg.PackedValue);\n\t\t\t}\n\n\t\t\tif (New) {\n\t\t\t\tImGui.SetNextWindowPos(Position, ImGuiCond.Always);\n\t\t\t\tRealPosition = Position - Offset; // fixme\n\t\t\t} else if (readPosition) {\n\t\t\t\tImGui.SetNextWindowPos(RealPosition + Offset, ImGuiCond.Always);\n\t\t\t}\n\n\t\t\tImGui.Begin($\"node_{Tip}_{Id}\", ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.AlwaysAutoResize);\n\t\t\tvar old = ImGuiHelper.CurrentMenu;\n\t\t\tImGuiHelper.CurrentMenu = this;\n\t\t\tImGuiHelper.RenderMenu(true);\n\n\t\t\tRenderElements();\n\t\t\tRenderConnections();\n\t\t\t\n\t\t\thovered = ImGui.IsWindowHovered();\n\t\t\tfocused = ImGui.IsWindowFocused();\n\n\t\t\tif (focused) {\n\t\t\t\tFocused = this;\n\t\t\t}\n\n\t\t\tif (New) {\n\t\t\t\tNew = false;\n\t\t\t} else {\n\t\t\t\treadPosition = true;\n\t\t\t\tSize = ImGui.GetWindowSize();\n\t\t\t}\n\n\t\t\tMoved = false;\n\t\t\t\n\t\t\tif (hovered) {\n\t\t\t\tif (ImGui.IsMouseDragging(0) || Input.Keyboard.IsDown(Keys.LeftControl, true)) {\n\t\t\t\t\tvar d = ImGui.GetIO().MouseDelta;\n\t\t\t\t\tRealPosition += d;\t\n\t\t\t\t} else if (Input.Keyboard.IsDown(Keys.LeftShift, true)) {\n\t\t\t\t\tMove(ImGui.GetIO().MouseDelta);\n\t\t\t\t} else if (Input.Keyboard.IsDown(Keys.LeftWindows, true)) {\n\t\t\t\t\tMoveBoth(ImGui.GetIO().MouseDelta);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tImGui.End();\n\t\t\tImGui.PopStyleColor();\n\t\t\tImGuiHelper.CurrentMenu = old;\n\n\t\t\tif (Done) {\n\t\t\t\tRemove();\n\t\t\t}\n\t\t}\n\n\t\tpublic bool Moved;\n\t\t\n\t\tpublic void Move(Vector2 d) {\n\t\t\tif (Moved) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tMoved = true;\n\t\t\tRealPosition += d;\n\n\t\t\tforeach (var c in Outputs) {\n\t\t\t\tforeach (var cc in c.ConnectedTo) {\n\t\t\t\t\tcc.Parent.Move(d);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void MoveBoth(Vector2 d) {\n\t\t\tif (Moved) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tMoved = true;\n\t\t\tRealPosition += d;\n\n\t\t\tforeach (var c in Outputs) {\n\t\t\t\tforeach (var cc in c.ConnectedTo) {\n\t\t\t\t\tcc.Parent.Move(d);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in Inputs) {\n\t\t\t\tforeach (var cc in c.ConnectedTo) {\n\t\t\t\t\tcc.Parent.Move(d);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Remove() {\n\t\t\tDone = true;\n\t\t\t\n\t\t\tif (ImGuiHelper.CurrentActive == this) {\n\t\t\t\tImGuiHelper.CurrentActive = null;\n\t\t\t}\n\n\t\t\tforeach (var i in Inputs) {\n\t\t\t\tforeach (var t in i.ConnectedTo) {\n\t\t\t\t\tt.ConnectedTo.Remove(i);\n\t\t\t\t}\n\n\t\t\t\ti.ConnectedTo.Clear();\n\t\t\t}\n\n\t\t\tforeach (var i in Outputs) {\n\t\t\t\tforeach (var t in i.ConnectedTo) {\n\t\t\t\t\tt.ConnectedTo.Remove(i);\n\t\t\t\t}\n\n\t\t\t\ti.ConnectedTo.Clear();\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void RenderElements() {\n\t\t\t\n\t\t}\n\t\t\n\t\tprivate JsonArray SaveConnections(List<ImConnection> connections) {\n\t\t\tvar root = new JsonArray();\n\n\t\t\tforeach (var c in connections) {\n\t\t\t\tvar array = new JsonArray();\n\t\t\t\troot.Add(array);\n\n\t\t\t\tif (c.ConnectedTo.Count == 0) {\n\t\t\t\t\tarray.Add(new JsonArray());\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tforeach (var cc in c.ConnectedTo) {\n\t\t\t\t\tarray.Add(new JsonArray {\n\t\t\t\t\t\tcc.Parent.Id, \n\t\t\t\t\t\tcc.Id\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn root;\n\t\t}\n\t\t\n\t\tpublic virtual void Save(JsonObject root) {\n\t\t\troot[\"id\"] = Id;\n\t\t\troot[\"outputs\"] = SaveConnections(Outputs);\n\t\t\troot[\"type\"] = ImNodeRegistry.GetName(this);\n\t\t\troot[\"x\"] = RealPosition.X;\n\t\t\troot[\"y\"] = RealPosition.Y;\n\t\t}\n\n\t\tpublic virtual void Load(JsonObject root) {\n\t\t\tId = root[\"id\"].AsInteger;\n\t\t\toutputs = root[\"outputs\"].AsJsonArray;\n\n\t\t\tRealPosition.X = root[\"x\"];\n\t\t\tRealPosition.Y = root[\"y\"];\n\n\t\t\tLastId = Math.Max(LastId, Id);\n\t\t}\n\n\t\tpublic static unsafe void DrawHermite(ImDrawList* drawList, Vector2 p1, Vector2 p2, int steps, Color color) {\n\t\t\tvar t1 = new Vector2(80.0f, 0.0f);\n\t\t\tvar t2 = new Vector2(80.0f, 0.0f);\n\n\t\t\tfor (var step = 0; step <= steps; step++) {\n\t\t\t\tvar t = (float) step / steps;\n\t\t\t\tvar h1 = +2 * t * t * t - 3 * t * t + 1.0f;\n\t\t\t\tvar h2 = -2 * t * t * t + 3 * t * t;\n\t\t\t\tvar h3 = t * t * t - 2 * t * t + t;\n\t\t\t\tvar h4 = t * t * t - t * t;\n\n\t\t\t\tImGuiNative.ImDrawList_PathLineTo(drawList, new Vector2(h1 * p1.X + h2 * p2.X + h3 * t1.X + h4 * t2.X, h1 * p1.Y + h2 * p2.Y + h3 * t1.Y + h4 * t2.Y));\n\t\t\t}\n\n\t\t\tImGuiNative.ImDrawList_PathStroke(drawList, color.PackedValue, 0, 3.0f);\n\t\t}\n\n\t\tpublic virtual string GetName() {\n\t\t\treturn \"Node\";\n\t\t}\n\n\t\tpublic static ImNode Create(string file, JsonValue vl, bool ignoreId = false) {\n\t\t\tif (!vl.IsJsonObject) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar type = vl[\"type\"];\n\n\t\t\tif (!type.IsString) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar node = ImNodeRegistry.Create(type.AsString);\n\n\t\t\tif (node == null) {\n\t\t\t\tLog.Error($\"Unknown node type {type.AsString}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tnode.Tip = type.AsString;\n\t\t\tnode.File = file;\n\t\t\tnode.Load(vl);\n\n\t\t\tif (ignoreId) {\n\t\t\t\tnode.Id = LastId;\n\t\t\t}\n\t\t\t\n\t\t\tImNodes.Nodes[node.Id] = node;\n\t\t\treturn node;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImNodeRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace BurningKnight.ui.imgui.node {\n\tpublic static class ImNodeRegistry {\n\t\tpublic static Dictionary<string, Type> Defined = new Dictionary<string, Type>();\n\n\t\tstatic ImNodeRegistry() {\n\t\t\tDefine<ImOrdNode>(\"Ord\");\n\t\t\tDefine<ImTextNode>(\"Text\");\n\t\t\tDefine<ImTextOutputNode>(\"Text output\");\n\t\t\tDefine<ImTextInputNode>(\"Text input\");\n\t\t\tDefine<ImDialogNode>(\"Dialog\");\n\t\t\tDefine<ImChoiceNode>(\"Choice\");\n\t\t\tDefine<ImAnswerNode>(\"Answer\");\n\t\t}\n\t\t\n\t\tpublic static void Define<T>(string name) where T : ImNode {\n\t\t\tDefined[name] = typeof(T);\n\t\t}\n\n\t\tpublic static ImNode Create(string name) {\n\t\t\tif (!Defined.TryGetValue(name, out var type)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar node = (ImNode) Activator.CreateInstance(type);\n\t\t\tnode.Tip = name;\n\t\t\t\n\t\t\treturn node;\n\t\t}\n\n\t\tpublic static string GetName(ImNode node) {\n\t\t\treturn node.Tip;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImOrdNode.cs",
    "content": "using ImGuiNET;\nusing Lens.assets;\nusing Lens.lightJson;\n\nnamespace BurningKnight.ui.imgui.node {\n\tpublic class ImOrdNode : ImNode {\n\t\tprivate string header = \"Title\";\n\t\tprivate string optionA = \"Option A\";\n\t\tprivate string optionB = \"Option B\";\n\t\tprivate string answerA = \"Answer A\";\n\t\tprivate string answerB = \"Answer B\";\n\n\t\tpublic ImOrdNode() {\n\t\t\tAddInput();\n\t\t\t\n\t\t\tAddOutput();\n\t\t\tAddOutput();\n\t\t}\n\n\t\tpublic override void RenderElements() {\n\t\t\tImGui.PushItemWidth(200);\n\t\t\tInputs[0].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\t\t\tImGui.InputText($\"Header##{Id}\", ref header, 128);\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\tImGui.InputText($\"Option A##{Id}\", ref optionA, 128);\n\t\t\tOutputs[0].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\t\t\tImGui.InputText($\"Answer A##{Id}\", ref answerA, 128);\n\t\t\t\n\t\t\tImGui.Separator();\n\t\t\tImGui.InputText($\"Option B##{Id}\", ref optionB, 128);\n\t\t\tOutputs[1].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\t\t\tImGui.InputText($\"Answer B##{Id}\", ref answerB, 128);\n\t\t\tImGui.PopItemWidth();\n\t\t}\n\n\t\tpublic override void Save(JsonObject root) {\n\t\t\tbase.Save(root);\n\t\t\t\n\t\t\tLocale.Map[LocaleId] = header;\n\t\t\tLocale.Map[$\"{LocaleId}_a\"] = optionA;\n\t\t\tLocale.Map[$\"{LocaleId}_aa\"] = answerA;\n\t\t\tLocale.Map[$\"{LocaleId}_b\"] = optionB;\n\t\t\tLocale.Map[$\"{LocaleId}_ab\"] = answerB;\n\t\t}\n\n\t\tpublic override void Load(JsonObject root) {\n\t\t\tbase.Load(root);\n\t\t\t\n\t\t\theader = Locale.Map[LocaleId];\n\t\t\toptionA = Locale.Map[$\"{LocaleId}_a\"];\n\t\t\tanswerA = Locale.Map[$\"{LocaleId}_aa\"];\n\t\t\toptionB = Locale.Map[$\"{LocaleId}_b\"];\n\t\t\tanswerB = Locale.Map[$\"{LocaleId}_ab\"];\n\t\t}\n\n\t\tpublic override string GetName() {\n\t\t\treturn header;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImTextInputNode.cs",
    "content": "namespace BurningKnight.ui.imgui.node {\n\tpublic class ImTextInputNode : ImTextNode {\n\t\tpublic ImTextInputNode() {\n\t\t\tAddInput();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImTextNode.cs",
    "content": "using BurningKnight.ui.dialog;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.lightJson;\n\nnamespace BurningKnight.ui.imgui.node {\n\tpublic class ImTextNode : ImNode, DialogNode {\n\t\tprivate string name = \"\";\n\t\tprivate string label = \"\";\n\t\t\n\t\tpublic override void RenderElements() {\n\t\t\tif (Inputs.Count > 0) {\n\t\t\t\tInputs[0].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\t\t\t}\n\n\t\t\tif (Outputs.Count > 0) {\n\t\t\t\tOutputs[0].Offset.Y = ImGui.GetCursorPos().Y + InputHalfHeight;\n\t\t\t}\n\n\t\t\tImGui.PushItemWidth(200);\n\t\t\t\n\t\t\tif (ImGui.InputText($\"##{name}\", ref label, 256, ImGuiInputTextFlags.EnterReturnsTrue)) {\n\t\t\t\tname = label;\n\t\t\t}\n\t\t\t\n\t\t\tImGui.PopItemWidth();\n\t\t}\n\n\t\tpublic override void Load(JsonObject root) {\n\t\t\tbase.Load(root);\n\t\t\tname = Locale.Map[LocaleId];\n\t\t\tlabel = name;\n\t\t}\n\n\t\tpublic override void Save(JsonObject root) {\n\t\t\tbase.Save(root);\n\t\t\tname = label;\n\t\t\tLocale.Map[LocaleId] = name;\n\t\t}\n\n\t\tpublic override string GetName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic virtual Dialog Convert() {\n\t\t\tstring[] variants = null;\n\n\t\t\tif (Outputs.Count == 1) {\n\t\t\t\tvar t = Outputs[0].ConnectedTo;\n\t\t\t\tvariants = new string[t.Count];\n\t\t\t\tvar i = 0;\n\t\t\t\t\n\t\t\t\tforeach (var o in t) {\n\t\t\t\t\tvariants[i] = o.Parent.LocaleId;\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn CreateDialog(LocaleId, variants);\n\t\t}\n\n\t\tprotected virtual Dialog CreateDialog(string id, string[] variants) {\n\t\t\treturn new Dialog(id, variants);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/imgui/node/ImTextOutputNode.cs",
    "content": "namespace BurningKnight.ui.imgui.node {\n\tpublic class ImTextOutputNode : ImTextNode {\n\t\tpublic ImTextOutputNode() {\n\t\t\tAddOutput();\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/inventory/UiActiveItemSlot.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.inventory {\n\tpublic class UiActiveItemSlot : UiEntity {\n\t\tprivate UiInventory inventory;\n\n\t\tprivate TextureRegion activeSide;\n\t\tprivate TextureRegion activeBorder;\n\t\tprivate TextureRegion activeEmpty;\n\t\tprivate TextureRegion activeFull;\n\n\t\tprivate Vector2 activeScale = new Vector2(1);\n\n\t\tpublic float ActivePosition = -1f;\n\t\tprivate bool tweened;\n\n\t\tprivate UiItem uiItem;\n\t\t\n\t\tpublic UiActiveItemSlot(UiInventory inv) {\n\t\t\tinventory = inv;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tuiItem = new UiItem {\n\t\t\t\tOnTop = true\n\t\t\t};\n\t\t\t\n\t\t\tArea.Add(uiItem);\n\t\t\t\n\t\t\tvar area = inventory.Player.Area;\n\t\t\t\n\t\t\tSubscribe<ItemUsedEvent>(area);\n\t\t\tSubscribe<ItemAddedEvent>(area);\n\t\t\t\n\t\t\tvar anim = Animations.Get(\"ui\");\n\n\t\t\tactiveSide = anim.GetSlice(\"active_side\");\n\t\t\tactiveBorder = anim.GetSlice(\"active_border\");\n\t\t\tactiveEmpty = anim.GetSlice(\"active_empty\");\n\t\t\tactiveFull = anim.GetSlice(\"active_full\");\n\t\t\t\n\t\t\tif (inventory.Player?.GetComponent<ActiveItemComponent>().Item != null) {\n\t\t\t\tActivePosition = 0;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (ActivePosition <= -0.99f) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar component = inventory.Player.GetComponent<ActiveItemComponent>();\n\t\t\tvar item = component.Item;\n\t\t\t\n\t\t\tif (item != null && item.Id != uiItem.Id) {\n\t\t\t\tuiItem.Id = item.Id;\n\t\t\t\tuiItem.Scourged = item.Scourged;\n\t\t\t}\n\n\t\t\tvar v = ActivePosition * (inventory.ItemSlot.Width + 10);\n\t\t\tvar a = inventory.UseSlot.Center.X + 8 + v;\n\n\t\t\tif (inventory.Second && item != null && Math.Abs(item.UseTime) > 0.01f) {\n\t\t\t\ta += 4; // For the charge bar\n\t\t\t}\n\t\t\t\n\t\t\tvar pos = new Vector2(inventory.Second ? Display.UiWidth - a : a, inventory.UseSlot.Center.Y + 8);\n\t\t\t\n\t\t\tGraphics.Render(inventory.ItemSlot, pos, 0, inventory.ItemSlot.Center, activeScale);\n\n\t\t\tuiItem.Center = pos;\n\t\t\t\n\t\t\tif (item == null || (item.Done && !tweened)) {\n\t\t\t\ttweened = true;\n\t\t\t\t\t\n\t\t\t\tTween.To(-1, 0, x => ActivePosition = x, 0.3f).OnEnd = () => {\n\t\t\t\t\tinventory.Player.GetComponent<ActiveItemComponent>().Clear();\n\t\t\t\t\ttweened = false;\n\t\t\t\t};\n\t\t\t}\n\t\t\t\n\t\t\tif (item != null) {\n\t\t\t\t// var region = item.Region;\n\t\t\t\tvar timed = item.UseTime < 0;\n\t\t\t\tvar chargeMax = Math.Abs(item.UseTime);\n\t\t\t\tvar charge = timed ? chargeMax - item.Delay : (float) Math.Floor(chargeMax - item.Delay);\n\n\t\t\t\tuiItem.DrawBorder = Math.Abs(charge - chargeMax) < 0.01f;\n\n\t\t\t\t// Render the use time\n\t\t\t\tif (Math.Abs(item.UseTime) <= 0.01f) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tpos.X += inventory.ItemSlot.Width / 2f;\n\t\t\t\tpos.Y -= inventory.ItemSlot.Height / 2f;\n\n\t\t\t\tvar h = inventory.ItemSlot.Height;\n\t\t\t\tvar cellH = timed ? (h - 2) : (float) Math.Floor((h - 2) / chargeMax);\n\t\t\t\tvar barH = (timed ? h : (float) Math.Floor((double) ((h - 2) / (int) chargeMax)) * chargeMax);\n\t\t\t\tvar n = timed ? 0 : (h - barH - 1);\n\t\t\t\n\t\t\t\tGraphics.Render(activeSide, pos + new Vector2(0, n));\n\t\t\t\tGraphics.Render(activeSide, pos + new Vector2(0, inventory.ItemSlot.Height - 1));\n\t\t\t\n\t\t\t\tGraphics.Render(activeBorder, pos + new Vector2(3, 1 + n), 0, Vector2.Zero, new Vector2(1, barH - 1));\n\n\t\t\t\tif (charge < chargeMax) {\n\t\t\t\t\tGraphics.Render(activeEmpty, pos + new Vector2(0, 1 + n), 0, Vector2.Zero, new Vector2(1, barH - (timed ? 2 : 1)));\n\t\t\t\t}\n\n\t\t\t\tif (charge > 0) {\n\t\t\t\t\tif (timed) {\n\t\t\t\t\t\tvar hh = charge / chargeMax * (cellH);\n\t\t\t\t\t\tGraphics.Render(activeFull, pos + new Vector2(0, barH - hh - 1), 0, Vector2.Zero,\n\t\t\t\t\t\t\tnew Vector2(1, hh));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (var i = 0; i < charge; i++) {\n\t\t\t\t\t\t\tGraphics.Render(activeFull, pos + new Vector2(0, h - (i + 1) * cellH), 0, Vector2.Zero,\n\t\t\t\t\t\t\t\tnew Vector2(1, cellH - 1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!timed) {\n\t\t\t\t\tfor (var i = 0; i < chargeMax - 1; i++) {\n\t\t\t\t\t\tGraphics.Render(activeSide, pos + new Vector2(0, barH - (i + 1) * cellH + n));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Animate() {\n\t\t\tTween.To(0.6f, activeScale.X, x => activeScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1.5f, activeScale.X, x => activeScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\t\t\tTween.To(1f, activeScale.X, x => activeScale.X = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\tTween.To(1.5f, activeScale.Y, x => activeScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(0.6f, activeScale.Y, x => activeScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\t\t\tTween.To(1f, activeScale.Y, x => activeScale.Y = x, 0.2f);\n\n\t\t\t\n\t\t\tTween.To(0.3f, uiItem.IconScale.X, x => uiItem.IconScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, uiItem.IconScale.X, x => uiItem.IconScale.X = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\tTween.To(2f, uiItem.IconScale.Y, x => uiItem.IconScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, uiItem.IconScale.Y, x => uiItem.IconScale.Y = x, 0.2f);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is ItemUsedEvent item) {\n\t\t\t\tif (inventory.Player.GetComponent<ActiveItemComponent>().Item == item.Item) {\n\t\t\t\t\tAnimate();\n\t\t\t\t}\n\t\t\t} else if (e is ItemAddedEvent iae) {\n\t\t\t\tif (iae.Who == inventory.Player) {\n\t\t\t\t\tif (iae.Item.Type == ItemType.Active) {\n\t\t\t\t\t\tif (ActivePosition <= 0f || tweened) {\n\t\t\t\t\t\t\tTween.To(0, -1, x => ActivePosition = x, 0.6f, Ease.BackOut);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tAnimate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/inventory/UiInventory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.entity;\nusing BurningKnight.entity.buff;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature;\nusing BurningKnight.entity.creature.mob;\nusing BurningKnight.entity.creature.mob.boss;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing BurningKnight.entity.item.use;\nusing BurningKnight.level.entities;\nusing BurningKnight.level.rooms;\nusing BurningKnight.state;\nusing BurningKnight.ui.str;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.inventory {\n\tpublic class UiInventory : UiEntity {\n\t\tpublic TextureRegion ItemSlot;\n\t\tpublic TextureRegion UseSlot;\n\t\t\n\t\tprivate TextureRegion question;\t\t\n\t\tprivate TextureRegion bomb;\n\t\tprivate TextureRegion key;\n\t\tprivate TextureRegion coin;\n\t\tprivate TextureRegion pointer;\n\t\tprivate TextureRegion exitPointer;\n\t\t\n\t\tprivate UiString description;\n\t\tprivate UiItem lastItem;\n\n\t\tpublic static TextureRegion Heart;\n\t\tpublic static TextureRegion HalfHeart;\n\t\tpublic static TextureRegion HeartBackground;\n\t\tprivate TextureRegion changedHeartBackground;\n\t\tprivate static TextureRegion halfHeartBackground;\n\t\tprivate TextureRegion changedHalfHeartBackground;\n\n\t\tpublic static TextureRegion veganHeart;\n\t\tpublic static TextureRegion veganHalfHeart;\n\t\tpublic static TextureRegion veganHeartBackground;\n\t\tprivate TextureRegion veganchangedHeartBackground;\n\t\tprivate static TextureRegion veganhalfHeartBackground;\n\t\tprivate TextureRegion veganchangedHalfHeartBackground;\n\t\t\n\t\tpublic static TextureRegion Mana;\n\t\tpublic static TextureRegion HalfMana;\n\t\tpublic static TextureRegion ManaBackground;\n\t\tpublic static TextureRegion ChangedManaBackground;\n\t\t\n\t\tpublic static TextureRegion Bomb;\n\t\tpublic static TextureRegion BombBg;\n\t\tpublic static TextureRegion ChangedBombBg;\n\t\t\n\t\tpublic static TextureRegion ShieldBackground;\n\t\tprivate TextureRegion changedShieldBackground;\n\t\tprivate static TextureRegion halfShieldBackground;\n\t\tprivate TextureRegion changedHalfShieldBackground;\n\t\tprivate UiButton more;\n\t\t\n\t\tpublic Player Player;\n\n\t\tprivate int coins;\n\t\tprivate int keys;\n\t\tprivate int bombs;\n\t\t\n\t\tprivate Vector2 coinScale = new Vector2(1);\n\t\tprivate Vector2 keyScale = new Vector2(1);\n\t\tprivate Vector2 bombScale = new Vector2(1);\n\n\t\tprivate List<UiItem> items = new List<UiItem>();\n\t\tprivate UiActiveItemSlot activeSlot;\n\t\tprivate UiWeaponSlot weaponSlot;\n\t\tprivate UiWeaponSlot activeWeaponSlot;\n\n\t\tprivate bool multiplayer;\n\t\tpublic bool Second;\n\t\tpublic bool ForceUpdate;\n\n\t\tpublic UiInventory(Player player, bool multiplayer) {\n\t\t\tPlayer = player;\t\n\t\t\tactiveSlot = new UiActiveItemSlot(this);\n\n\t\t\tif (player.HasComponent<WeaponComponent>()) {\n\t\t\t\tweaponSlot = new UiWeaponSlot(this);\n\t\t\t}\n\n\t\t\tactiveWeaponSlot = new UiWeaponSlot(this) {\n\t\t\t\tActive = true\n\t\t\t};\n\n\t\t\tthis.multiplayer = multiplayer;\n\t\t\tSecond = multiplayer && player.GetComponent<InputComponent>().Index > 0;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tdescription = new UiString(Font.Small);\n\t\t\t((InGameState) Engine.Instance.State).TopUi.Add(description);\n\t\t\t((InGameState) Engine.Instance.State).TopUi.Add(new RenderTrigger(RenderTop, 10));\n\t\t\tdescription.DisableRender = true;\n\t\t\t\n\t\t\tArea.Add(activeSlot);\n\n\t\t\tif (weaponSlot != null) {\n\t\t\t\tArea.Add(weaponSlot);\n\t\t\t}\n\n\t\t\tArea.Add(activeWeaponSlot);\n\n\t\t\tvar anim = Animations.Get(\"ui\");\n\n\t\t\tItemSlot = anim.GetSlice(\"item_slot\");\n\t\t\tUseSlot = new TextureRegion();\n\t\t\tUseSlot.Set(ItemSlot);\n\t\t\t\n\t\t\tquestion = anim.GetSlice(\"question\");\n\t\t\tbomb = anim.GetSlice(\"bomb\");\n\t\t\tkey = anim.GetSlice(\"key\");\n\t\t\tcoin = anim.GetSlice(\"coin\");\n\t\t\tpointer = anim.GetSlice(\"pointer\");\n\t\t\texitPointer = anim.GetSlice(\"exit_pointer\");\n\n\t\t\tHeart = anim.GetSlice(\"heart\");\n\t\t\tHalfHeart = anim.GetSlice(\"half_heart\");\n\t\t\tHeartBackground = anim.GetSlice(\"heart_bg\");\n\t\t\tchangedHeartBackground = anim.GetSlice(\"heart_hurt_bg\");\n\t\t\thalfHeartBackground = anim.GetSlice(\"half_heart_bg\");\n\t\t\tchangedHalfHeartBackground = anim.GetSlice(\"half_heart_hurt\");\n\t\t\t\n\t\t\tveganHeart = anim.GetSlice(\"vegan\");\n\t\t\tveganHalfHeart = anim.GetSlice(\"half_vegan\");\n\t\t\tveganHeartBackground = anim.GetSlice(\"vegan_bg\");\n\t\t\tveganchangedHeartBackground = anim.GetSlice(\"vegan_hurt_bg\");\n\t\t\tveganhalfHeartBackground = anim.GetSlice(\"half_vegan_bg\");\n\t\t\tveganchangedHalfHeartBackground = anim.GetSlice(\"half_vegan_hurt_bg\");\n\t\t\t\n\t\t\tBomb = anim.GetSlice(\"bmb\");\n\t\t\tBombBg = anim.GetSlice(\"bmb_bg\");\n\t\t\tChangedBombBg = anim.GetSlice(\"bmb_hurt\");\n\t\t\t\n\t\t\tMana = anim.GetSlice(\"mana\");\n\t\t\tHalfMana = anim.GetSlice(\"half_mana\");\n\t\t\tManaBackground = anim.GetSlice(\"mana_bg\");\n\t\t\tChangedManaBackground = anim.GetSlice(\"mana_hurt_bg\");\n\t\t\t\n\t\t\tShieldBackground = anim.GetSlice(\"shield_bg\");\n\t\t\tchangedShieldBackground = anim.GetSlice(\"shield_hurt\");\n\t\t\thalfShieldBackground = anim.GetSlice(\"half_shield_bg\");\n\t\t\tchangedHalfShieldBackground = anim.GetSlice(\"half_shield_hurt\");\n\t\t\t\n\t\t\tif (Player != null) {\n\t\t\t\tvar component = Player.GetComponent<ConsumablesComponent>();\n\n\t\t\t\tcoins = component.Coins;\n\t\t\t\tkeys = component.Keys;\n\t\t\t\tbombs = component.Bombs;\n\n\t\t\t\tvar area = Player.Area;\n\n\t\t\t\tSubscribe<ConsumableAddedEvent>(area);\n\t\t\t\tSubscribe<ConsumableRemovedEvent>(area);\n\t\t\t\tSubscribe<ItemUsedEvent>(area);\n\t\t\t\tSubscribe<ItemAddedEvent>(area);\n\t\t\t\tSubscribe<ItemRemovedEvent>(area);\n\t\t\t\tSubscribe<RerollItemsOnPlayerUse.RerolledEvent>(area);\n\n\t\t\t\tmore = new UiButton();\n\t\t\t\tmore.Font = Font.Small;\n\n\t\t\t\tmore.Click = (b) => {\n\t\t\t\t\tvar state = (InGameState) Engine.Instance.State;\n\t\t\t\t\tstate.OnPauseCallback = state.GoToInventory;\n\t\t\t\t\tstate.Paused = true;\n\t\t\t\t};\n\n\t\t\t\tmore.Enabled = false;\n\t\t\t\tArea.Add(more);\n\t\t\t\tmore.Right = Display.UiWidth - 8;\n\t\t\t\tmore.Bottom = Display.UiHeight - 5;\n\t\t\t\t\n\t\t\t\tvar inventory = Player.GetComponent<InventoryComponent>();\n\n\t\t\t\tforeach (var item in inventory.Items) {\n\t\t\t\t\tAddArtifact(item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (ForceUpdate) {\n\t\t\t\tForceUpdate = false;\n\t\t\t\tUpdateConsumables();\n\t\t\t}\n\t\t}\n\n\t\tpublic void UpdateConsumables() {\n\t\t\tvar c = Player.GetComponent<ConsumablesComponent>();\n\n\t\t\tbombs = c.Bombs;\n\t\t\tkeys = c.Keys;\n\t\t\tcoins = c.Coins;\n\t\t}\n\n\t\tprivate void AnimateConsumableChange(int amount, int now, ItemType type) {\n\t\t\tif (type == ItemType.Bomb) {\n\t\t\t\tif (Math.Abs(amount) == 1) {\n\t\t\t\t\tbombs = now;\n\t\t\t\t} else {\n\t\t\t\t\tTween.To(this, new {bombs = now}, 0.05f * Math.Abs(amount));\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTween.To(0.3f, bombScale.X, x => bombScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, bombScale.X, x => bombScale.X = x, 0.2f);\n\n\t\t\t\tTween.To(2f, bombScale.Y, x => bombScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, bombScale.Y, x => bombScale.Y = x, 0.2f);\n\t\t\t} else if (type == ItemType.Key) {\n\t\t\t\tif (Math.Abs(amount) == 1) {\n\t\t\t\t\tkeys = now;\n\t\t\t\t} else {\n\t\t\t\t\tTween.To(this, new {keys = now}, 0.05f * Math.Abs(amount));\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTween.To(0.3f, keyScale.X, x => keyScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, keyScale.X, x => keyScale.X = x, 0.2f);\n\n\t\t\t\tTween.To(2f, keyScale.Y, x => keyScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, keyScale.Y, x => keyScale.Y = x, 0.2f);\n\t\t\t} else if (type == ItemType.Coin) {\n\t\t\t\tif (Math.Abs(amount) == 1) {\n\t\t\t\t\tcoins = now;\n\t\t\t\t} else {\n\t\t\t\t\tTween.To(this, new {coins = now}, 0.05f * Math.Abs(amount));\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTween.To(2f, coinScale.Y, x => coinScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, coinScale.Y, x => coinScale.Y = x, 0.2f);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tswitch (e) {\n\t\t\t\tcase ConsumableAddedEvent add: {\n\t\t\t\t\tAnimateConsumableChange(add.Amount, add.TotalNow, add.Type);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase ConsumableRemovedEvent rem: {\n\t\t\t\t\tAnimateConsumableChange(rem.Amount, rem.TotalNow, rem.Type);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase RerollItemsOnPlayerUse.RerolledEvent re: {\n\t\t\t\t\tif (re.Entity == Player) {\n\t\t\t\t\t\tforeach (var i in items) {\n\t\t\t\t\t\t\ti.Done = true;\n\t\t\t\t\t\t}\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\titems.Clear();\n\t\t\t\t\t\tvar inventory = Player.GetComponent<InventoryComponent>();\n\n\t\t\t\t\t\tforeach (var item in inventory.Items) {\n\t\t\t\t\t\t\tAddArtifact(item);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcase ItemAddedEvent iae: {\n\t\t\t\t\tif (iae.Who == Player) {\n\t\t\t\t\t\tvar item = iae.Item;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tif (item.Type == ItemType.Artifact || item.Type == ItemType.Scourge) {\n\t\t\t\t\t\t\tAddArtifact(item);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase ItemRemovedEvent ire: {\n\t\t\t\t\tif (ire.Owner == Player) {\n\t\t\t\t\t\tRemoveArtifact(ire.Item);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t\t\n\t\tprivate void AddArtifact(Item item) {\n\t\t\tif (item.Hide || multiplayer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tUiItem old = null;\n\n\t\t\tforeach (var i in items) {\n\t\t\t\tif (i.Id == item.Id) {\n\t\t\t\t\told = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (old == null) {\n\t\t\t\tvar x = Display.UiWidth - 8f;\n\n\t\t\t\tif (items.Count > 0) {\n\t\t\t\t\tx = items[items.Count - 1].X - 8;\n\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\told = new UiItem();\n\t\t\t\told.Id = item.Id;\n\t\t\t\told.Scourged = item.Scourged;\n\t\t\t\tArea.Add(old);\n\t\t\t\titems.Add(old);\n\n\t\t\t\told.Right = x;\n\t\t\t\told.Bottom = Display.UiHeight - 8f;\n\n\t\t\t\tif (items.Count > 6) {\n\t\t\t\t\tmore.Label = $\"+{items.Count - 6}\";\n\t\t\t\t\tmore.Enabled = true;\n\t\t\t\t\tmore.Right = Display.UiWidth - 8;\n\t\t\t\t\tmore.Bottom = Display.UiHeight - 5f;\n\n\t\t\t\t\tfor (var i = 0; i < items.Count - 6; i++) {\n\t\t\t\t\t\tvar it = items[i];\n\t\t\t\t\t\tit.X = Display.UiWidth + 32;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar ps = Display.UiWidth - 8f;\n\n\t\t\t\t\tps -= more.Width + 8;\n\t\t\t\t\t\n\t\t\t\t\tfor (var i = items.Count - 6; i < items.Count; i++) {\n\t\t\t\t\t\tvar it = items[i];\n\t\t\t\t\t\tit.Right = ps;\n\n\t\t\t\t\t\tps -= 8 + it.Width;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\told.Count++;\n\t\t\t}\n\t\t}\n\n\t\tprivate void RemoveArtifact(Item item) {\n\t\t\tif (multiplayer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tUiItem old = null;\n\t\t\tvar j = 0;\n\n\t\t\tforeach (var i in items) {\n\t\t\t\tif (i.Id == item.Id) {\n\t\t\t\t\told = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\t\t\n\n\t\t\t\tj++;\n\t\t\t}\n\n\t\t\tif (old == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (old.Count > 1) {\n\t\t\t\told.Count--;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\titems.Remove(old);\n\t\t\told.Done = true;\n\n\t\t\tfor (var i = j; i < items.Count; i++) {\n\t\t\t\titems[i].Right = items[i - 1].X - 8;\n\t\t\t}\n\t\t}\n\n\t\tpublic void RenderArrow(Vector2 target, bool arg = false) {\n\t\t\tvar d = Player.DistanceTo(target);\n\t\t\tvar spr = arg ? exitPointer : pointer;\n\n\t\t\tif (d > 64) {\n\t\t\t\tvar dd = d * 0.7f;\n\t\t\t\tvar a = Player.AngleTo(target);\n\t\t\t\tvar m = (float) Math.Cos(Engine.Time * 4f) * 6f + 6f;\n\t\t\t\tvar v = (float) Math.Cos(Engine.Time * 5f) * 0.3f + 0.7f;\n\n\t\t\t\tvar point = Player.Center + new Vector2((float) Math.Cos(a) * dd, (float) Math.Sin(a) * dd);\n\t\t\t\tvar center = new Vector2(Display.UiWidth, Display.UiHeight) * 0.5f;\n\t\t\t\t\t\n\t\t\t\tpoint = Camera.Instance.CameraToUi(point);\n\t\t\t\tpoint.X = MathUtils.Clamp((float) -Math.Cos(a) * (center.X - 16) + center.X, (float) Math.Cos(a) * (center.X - 16) + center.X, point.X);\n\t\t\t\tpoint.Y = MathUtils.Clamp((float) -Math.Sin(a) * (center.Y - 16) + center.Y,  (float) Math.Sin(a) * (center.Y - 16) + center.Y, point.Y);\n\t\t\t\tpoint -= MathUtils.CreateVector(a, m);\n\t\t\t\t\t\n\t\t\t\tGraphics.Color = new Color(v, v, v, 1f - MathUtils.Clamp(0, 1, (80 - d) / 16f));\n\t\t\t\tGraphics.Render(spr, point, a, spr.Center);\n\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tif (Player == null || Player.Done) {\n\t\t\t\tDone = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tEntity target;\n\t\t\tvar r = Player.GetComponent<RoomComponent>().Room;\n\t\t\t\n\t\t\tif (!Second && !Engine.Instance.State.Paused && r != null) {\n\t\t\t\tif (r.Tagged[Tags.MustBeKilled].Count == 1 && r.Type != RoomType.Connection && !(r.Tagged[Tags.MustBeKilled][0] is Boss)) {\n\t\t\t\t\ttarget = r.Tagged[Tags.MustBeKilled][0];\n\n\t\t\t\t\tif (target != null && (!(target is Mob mb) || mb.Target != null) && target is Creature c && c.GetComponent<HealthComponent>().Health >= 1f && r.Contains(c.Center)) {\n\t\t\t\t\t\tRenderArrow(target.Center);\n\t\t\t\t\t}\n\t\t\t\t} else if (Run.Depth > 0 && r.Tagged[Tags.MustBeKilled].Count == 0 && Exit.Instance != null && Player.CheckClear(Engine.Instance.State.Area)) {\n\t\t\t\t\tRenderArrow(Exit.Instance.Center, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar show = Run.Depth > 0;\n\t\t\tvar hasMana = Player.GetComponent<WeaponComponent>().Item?.Data?.WeaponType == WeaponType.Magic || Player.GetComponent<ActiveWeaponComponent>().Item?.Data?.WeaponType == WeaponType.Magic;\n\n\t\t\tRenderHealthBar(true);\n\n\t\t\tif (show && hasMana) {\n\t\t\t\tRenderMana();\n\t\t\t}\n\n\t\t\tif ((show || Run.Depth == -2) && Player != null && Player.GetComponent<ConsumablesComponent>() == Player.ForceGetComponent<ConsumablesComponent>()) {\n\t\t\t\tRenderConsumables(hasMana);\n\t\t\t}\n\t\t}\n\n\t\tprivate void RenderTop() {\n\t\t\tvar show = Run.Depth > 0;\n\n\t\t\tif (show && Player != null) {\n\t\t\t\tif (UiItem.Hovered != null) {\n\t\t\t\t\tvar item = UiItem.Hovered;\n\n\t\t\t\t\tif (lastItem != UiItem.Hovered) {\n\t\t\t\t\t\tlastItem = UiItem.Hovered;\n\t\t\t\t\t\tdescription.Label = item.Description;\n\t\t\t\t\t\tdescription.FinishTyping();\n\t\t\t\t\t}\n\n\t\t\t\t\tvar x = MathUtils.Clamp(item.OnTop ? 40 : 4,\n\t\t\t\t\t\tDisplay.UiWidth - 6 - Math.Max(item.DescriptionSize.X, item.NameSize.X), item.Position.X);\n\n\t\t\t\t\tvar y = item.OnTop\n\t\t\t\t\t\t? MathUtils.Clamp(8 + item.NameSize.Y, Display.UiHeight - 6 - item.DescriptionSize.Y, item.Y)\n\t\t\t\t\t\t: MathUtils.Clamp(4, Display.UiHeight - 6 - item.DescriptionSize.Y - item.NameSize.Y - 4, item.Y - 7);\n\n\t\t\t\t\tGraphics.Color = new Color(1f, 1f, 1f, item.TextA);\n\t\t\t\t\tGraphics.Print(item.Name, Font.Small, new Vector2(x, y - item.DescriptionSize.Y + 2));\n\n\t\t\t\t\t// Graphics.Print(item.Description, Font.Small, new Vector2(x, y));\n\n\t\t\t\t\tdescription.X = x;\n\t\t\t\t\tdescription.Y = y - 2;\n\t\t\t\t\tGraphics.Color = ColorUtils.WhiteColor;\n\n\t\t\t\t\tdescription.Tint.A = (byte) (item.TextA * 255f);\n\t\t\t\t\tdescription.RenderString();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate int Bump(int value) {\n\t\t\treturn value % 2 == 0 ? value : value + 1;\n\t\t}\n\n\t\tprivate Vector2 GetHeartPosition(bool pad, int i, bool bg = false) {\n\t\t\tvar d = 0;\n\t\t\tvar it = Player.GetComponent<ActiveItemComponent>().Item;\n\n\t\t\tif (pad && it != null && Math.Abs(it.UseTime) > 0.01f) {\n\t\t\t\td = 4;\n\t\t\t}\n\n\t\t\tvar a = (pad ? (4 + (4 + ItemSlot.Source.Width + d) * (activeSlot.ActivePosition + 1)) : 6) + 4;\n\t\t\tvar c = Second ? Math.Min(HeartsComponent.PerRow, Bump(Player.GetComponent<HealthComponent>().MaxHealth + Player.GetComponent<HeartsComponent>().TotalMax)) : 0;\n\t\t\t\n\t\t\treturn new Vector2(\n\t\t\t\t(bg ? 0 : 1) + (Second ? Display.UiWidth - a - c * 5.5f : a) + (int) (i % HeartsComponent.PerRow * 5.5f),\n\t\t\t\t(bg ? 0 : 1) + (i / HeartsComponent.PerRow) * 10 + 11\n\t\t\t\t+ (float) Math.Cos(i / 8f * Math.PI + Engine.Time * 12) * 0.5f * Math.Max(0, (float) (Math.Cos(Engine.Time * 0.25f) - 0.9f) * 10f)\n\t\t\t);\n\t\t}\n\n\t\tprivate float lastRed;\n\t\t\n\t\tprivate void RenderHealthBar(bool pad) {\n\t\t\tvar red = Player.GetComponent<HealthComponent>();\n\t\t\tvar phases = red.Phases;\n\n\t\t\tif (Scourge.IsEnabled(Scourge.OfRisk)) {\n\t\t\t\tGraphics.Render(question, new Vector2(8 + (int) ((4 + ItemSlot.Source.Width) * (activeSlot.ActivePosition + 1)), 11));\n\n\t\t\t\tif (phases > 0) {\n\t\t\t\t\tGraphics.Print($\"x{phases}\", Font.Small, new Vector2(8 + question.Width + 4 + (int) ((4 + ItemSlot.Source.Width) * (activeSlot.ActivePosition + 1)), 12));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar hearts = Player.GetComponent<HeartsComponent>();\n\t\t\tvar totalRed = red.Health;\n\n\t\t\tif (lastRed > totalRed) {\n\t\t\t\tlastRed = totalRed;\n\t\t\t} else if (lastRed < totalRed) { \n\t\t\t\tlastRed = Math.Min(totalRed, lastRed + Engine.Delta * 30);\n\t\t\t}\n\n\t\t\tvar r = (int) lastRed;\n\t\t\tvar maxRed = red.MaxHealth;\n\t\t\tvar hurt = red.InvincibilityTimer > 0;\n\t\t\tvar shields = hearts.ShieldHalfs;\n\t\t\tvar bombs = (int) hearts.Bombs;\n\t\t\tvar dbombs = bombs * 2;\n\t\t\tvar mbombs = (int) hearts.BombsMax;\n\t\t\tvar mdbombs = mbombs * 2;\n\n\t\t\tvar n = r;\n\t\t\tvar jn = maxRed;\n\t\t\t\n\t\t\tif (jn % 2 == 1) {\n\t\t\t\tjn++;\n\t\t\t}\n\n\t\t\tvar vegan = Settings.Vegan;\n\t\t\t\n\t\t\tfor (var i = 0; i < maxRed; i += 2) {\n\t\t\t\tvar region = hurt ? (vegan ? veganchangedHeartBackground : changedHeartBackground) : (vegan ? veganHeartBackground : HeartBackground);\n\n\t\t\t\tif (i == maxRed - 1) {\n\t\t\t\t\tregion = hurt ? (vegan ? veganchangedHalfHeartBackground : changedHalfHeartBackground) : (vegan ? veganhalfHeartBackground : halfHeartBackground);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Render(region, GetHeartPosition(pad, i, true));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = jn; i < maxRed + mdbombs; i += 2) {\n\t\t\t\tvar region = hurt ? ChangedBombBg : BombBg;\n\t\t\t\t\n\t\t\t\tGraphics.Render(region, GetHeartPosition(pad, i, true) + new Vector2(0, -1));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = jn + mdbombs; i < maxRed + shields + mdbombs; i += 2) {\n\t\t\t\tvar region = hurt ? changedShieldBackground : ShieldBackground;\n\n\t\t\t\tif (i == maxRed + shields - 1) {\n\t\t\t\t\tregion = hurt ? changedHalfShieldBackground : halfShieldBackground;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Render(region, GetHeartPosition(pad, i, true));\n\t\t\t}\n\n\t\t\tfor (var j = 0; j < n; j++) {\n\t\t\t\tvar h = j % 2 == 0;\n\t\t\t\tGraphics.Render(h ? (vegan ? veganHalfHeart : HalfHeart) : (vegan ? veganHeart : Heart), GetHeartPosition(pad, j) + (h ? Vector2.Zero : new Vector2(-1, 0)));\n\t\t\t}\n\t\t\t\n\t\t\tfor (var j = jn; j < maxRed + dbombs; j += 2) {\n\t\t\t\tGraphics.Render(Bomb, GetHeartPosition(pad, j) + new Vector2(0, -1));\n\t\t\t}\n\t\t\t\n\t\t\tif (phases > 0) {\n\t\t\t\tGraphics.Print($\"x{phases}\", Font.Small, GetHeartPosition(pad, Math.Min(15, maxRed + shields + bombs)) + new Vector2(4, -2));\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate float lastMana;\n\t\tprivate float changedTime;\n\n\t\tprivate Vector2 GetStarPosition(bool pad, int i, bool bg = false) {\n\t\t\tvar d = 0;\n\t\t\tvar it = Player.GetComponent<ActiveItemComponent>().Item;\n\n\t\t\tif (pad && it != null && Math.Abs(it.UseTime) > 0.01f) {\n\t\t\t\td = 4;\n\t\t\t}\n\n\t\t\tvar a = (pad ? 4 : 6) + (8 + ItemSlot.Source.Width + d) * (activeSlot.ActivePosition + 1) + 4 +\n\t\t\t        (int) (i % HeartsComponent.PerRow * 11f);\n\t\t\t\n\t\t\treturn new Vector2(\n\t\t\t\t(bg ? 0 : 1) + (Second ? Display.UiWidth - a - 8 : a) - 2,\n\t\t\t\t(bg ? 0 : 1) + (i / HeartsComponent.PerRow) * 10 + 11 + (Player.GetComponent<HealthComponent>().MaxHealth + Player.GetComponent<HeartsComponent>().Total > HeartsComponent.PerRow ? 10 : 0) + 10\n\t\t\t\t+ (float) Math.Cos(i / 8f * Math.PI + Engine.Time * 12 - 1) * 0.5f * Math.Max(0, (float) (Math.Cos(Engine.Time * 0.25f - 1) - 0.9f) * 10f)\n\t\t\t);\n\t\t}\n\t\t\n\t\tprivate void RenderMana() {\n\t\t\tvar manaComponent = Player.GetComponent<ManaComponent>();\n\t\t\t\n\t\t\tvar totalMana = manaComponent.Mana;\n\t\t\t\n\t\t\tif (changedTime > 0) {\n\t\t\t\tchangedTime -= Engine.Delta;\n\t\t\t}\n\n\t\t\tif (lastMana > totalMana) {\n\t\t\t\tlastMana = totalMana;\n\t\t\t\tchangedTime = 0.5f;\n\t\t\t} else if (lastMana < totalMana) { \n\t\t\t\tlastMana = Math.Min(totalMana, lastMana + Engine.Delta * 30);\n\t\t\t\tchangedTime = 0.5f;\n\t\t\t}\n\n\n\t\t\tvar r = (int) lastMana;\n\t\t\tvar maxMana = manaComponent.ManaMax;\n\t\t\tvar hurt = changedTime > 0;\n\n\t\t\tvar n = r;\n\t\t\tvar jn = maxMana;\n\t\t\t\n\t\t\tfor (var i = 0; i < maxMana / 2; i++) {\n\t\t\t\tGraphics.Render(hurt ? ChangedManaBackground : ManaBackground, GetStarPosition(false, i, true) + (hurt ? new Vector2(-1) : Vector2.Zero));\n\t\t\t}\n\n\t\t\tfor (var j = 0; j < n; j += 2) {\n\t\t\t\tGraphics.Render(j == r - 1 ? HalfMana : Mana, GetStarPosition(false, j / 2));\n\t\t\t}\n\t\t}\n\n\t\tprivate float Wrap(float v) {\n\t\t\treturn Second ? Display.UiWidth - v : v;\n\t\t}\n\n\t\tprivate void PrintString(string s, float x, float y) {\n\t\t\tGraphics.Print(s, Font.Small, new Vector2(Second ? Display.UiWidth - x - Font.Small.MeasureString(s).Width - 1 : 18, y));\n\t\t}\n\n\t\tprivate void RenderConsumables(bool hasMana) {\n\t\t\tvar bottomY = 8 + 9 + 8 + (hasMana ? 10 : 0) + (Player.GetComponent<HealthComponent>().MaxHealth + Player.GetComponent<HeartsComponent>().Total > HeartsComponent.PerRow ? 10 : 0) + (int) (12 * (activeSlot.ActivePosition + 1));\n\n\t\t\tif (Scourge.IsEnabled(Scourge.OfKeys)) {\n\t\t\t\tGraphics.Render(question, new Vector2(8, bottomY + 1));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(coin, new Vector2(Wrap(8 + coin.Center.X), bottomY + 1 + coin.Center.Y), 0, coin.Center, coinScale);\n\t\t\tPrintString($\"{coins}\", 18, bottomY - 1);\n\t\t\tbottomY += 12;\n\n\t\t\tGraphics.Render(key, new Vector2(Wrap(7 + key.Center.X), bottomY + key.Center.Y + 2), 0, key.Center, keyScale);\n\t\t\tPrintString($\"{keys}\", 18, bottomY - 1);\n\t\t\tbottomY += bomb.Source.Height + 2;\n\n\t\t\tGraphics.Render(bomb, new Vector2(Wrap(8 + bomb.Center.X), bottomY + bomb.Center.Y), 0,\n\t\t\t\tbomb.Center, bombScale);\n\t\t\tPrintString($\"{bombs}\", 18, bottomY - 1);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/inventory/UiItem.cs",
    "content": "using System.Linq;\nusing BurningKnight.assets;\nusing BurningKnight.assets.items;\nusing BurningKnight.entity.item;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\nusing MonoGame.Extended;\n\nnamespace BurningKnight.ui.inventory {\n\tpublic class UiItem : UiEntity {\n\t\tpublic static UiItem Hovered;\n\n\t\tprivate string id;\n\t\tpublic float TextA;\n\n\t\tpublic string Id {\n\t\t\tget => id;\n\n\t\t\tset {\n\t\t\t\tid = value;\n\n\t\t\t\tif (id == null) {\n\t\t\t\t\tRegion = null;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar idd = Scourge.IsEnabled(Scourge.OfEgg)\n\t\t\t\t\t? Items.Datas.Values.ElementAt(Rnd.Int(Items.Datas.Count)).Id\n\t\t\t\t\t: Id;\n\t\t\t\t\n\t\t\t\tName = Locale.Get(idd);\n\t\t\t\tDescription = Locale.Get($\"{idd}_desc\");\n\t\t\t\tRegion = CommonAse.Items.GetSlice(id);\n\n\t\t\t\tNameSize = Font.Small.MeasureString(Name);\n\t\t\t\tDescriptionSize = Font.Small.MeasureString(Description);\n\n\t\t\t\tWidth = Region.Width;\n\t\t\t}\n\t\t}\n\n\t\tpublic string Name;\n\t\tpublic string Description;\n\t\tpublic Vector2 NameSize;\n\t\tpublic Vector2 DescriptionSize;\n\t\tpublic bool OnTop;\n\n\t\tpublic TextureRegion Region;\n\t\tprivate string countStr;\n\t\tprivate int count;\n\t\tprivate int countW;\n\t\tprivate int countH;\n\n\t\tprivate float border;\n\t\tpublic bool DrawBorder;\n\t\tpublic bool Scourged;\n\n\t\tpublic Vector2 IconScale = Vector2.One;\n\n\t\tpublic int Count {\n\t\t\tget => count;\n\n\t\t\tset {\n\t\t\t\tcount = value;\n\t\t\t\tcountStr = $\"{count}\";\n\t\t\t\t\n\t\t\t\tvar s = Font.Small.MeasureString(countStr);\n\t\t\t\tcountW = (int) s.Width;\n\t\t\t\tcountH = (int) s.Height;\n\n\t\t\t\tIconScale.X = 0;\n\t\t\t\tIconScale.Y = 2;\n\n\t\t\t\tTween.To(1, IconScale.X, x => IconScale.X = x, 0.3f);\n\t\t\t\tTween.To(1, IconScale.Y, x => IconScale.Y = x, 0.3f);\n\t\t\t}\n\t\t}\n\n\t\tpublic UiItem() {\n\t\t\tCount = 1;\n\t\t\tScaleMod = 2;\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (Hovered == this) {\n\t\t\t\tHovered = null;\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnHover() {\n\t\t\tif (id == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.OnHover();\n\t\t\t\n\t\t\tTween.To(1, border, x => border = x, 0.3f);\n\t\t\tTween.To(1, TextA, x => TextA = x, 0.3f);\n\n\t\t\tif (Settings.UiSfx) {\n\t\t\t\tAudio.PlaySfx(\"ui_moving\", 0.5f);\n\t\t\t}\n\n\t\t\tHovered = this;\n\t\t}\n\n\t\tprotected override void OnUnhover() {\n\t\t\tif (id == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbase.OnUnhover();\n\t\t\t\n\t\t\tTween.To(0, border, x => border = x, 0.3f);\n\t\t\tTween.To(0, TextA, x => TextA = x, 0.3f);\n\n\t\t\tif (Hovered == this) {\n\t\t\t\tHovered = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tif (id == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar b = DrawBorder ? 1 : border;\n\t\t\t\n\t\t\tif (Scourged || b > 0.01f) {\n\t\t\t\tvar shader = Shaders.Entity;\n\t\t\t\tShaders.Begin(shader);\n\n\t\t\t\tshader.Parameters[\"flash\"].SetValue(Scourged ? 1 : b);\n\t\t\t\tshader.Parameters[\"flashReplace\"].SetValue(1f);\n\t\t\t\tshader.Parameters[\"flashColor\"].SetValue(Scourged ? ItemGraphicsComponent.ScourgedColor : ColorUtils.White);\n\n\t\t\t\tforeach (var d in MathUtils.Directions) {\n\t\t\t\t\tGraphics.Render(Region, Center + d, 0, Region.Center, IconScale * scale);\n\t\t\t\t}\n\n\t\t\t\tShaders.End();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Render(Region, Center, 0, Region.Center, IconScale * scale);\n\t\t\t\n\t\t\tif (count < 2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tGraphics.Print(countStr, Font.Small, (int) (X + Width - countW), (int) (Y + Height + 6 - countH));\n\t\t}\n\n\t\tpublic override void OnClick() {\n\t\t\tbase.OnClick();\n\n\t\t\tif (Input.Keyboard.IsDown(Keys.LeftControl) || Input.Keyboard.IsDown(Keys.LeftShift) ||\n\t\t\t    Input.Keyboard.IsDown(Keys.RightControl)) {\n\n\t\t\t\tSystem.Diagnostics.Process.Start($\"https://wiki.burningknight.net/?item={Id}\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/inventory/UiWeaponSlot.cs",
    "content": "using System;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.events;\nusing BurningKnight.entity.item;\nusing Lens;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.inventory {\n\tpublic class UiWeaponSlot : UiEntity {\n\t\tprivate UiInventory inventory;\n\t\tprivate Vector2 activeScale = new Vector2(1);\n\t\tprivate UiItem uiItem;\n\n\t\tpublic bool Active;\n\t\t\n\t\tpublic UiWeaponSlot(UiInventory inv) {\n\t\t\tinventory = inv;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tuiItem = new UiItem {\n\t\t\t\tOnTop = true\n\t\t\t};\n\t\t\t\n\t\t\tArea.Add(uiItem);\n\t\t\t\n\t\t\tvar area = inventory.Player.Area;\n\t\t\t\n\t\t\tSubscribe<WeaponSwappedEvent>(area);\n\t\t\tSubscribe<ItemAddedEvent>(area);\n\t\t}\n\n\t\tpublic override void Render() {\n\t\t\tvar component = Active ? inventory.Player.GetComponent<ActiveWeaponComponent>() : inventory.Player.GetComponent<WeaponComponent>();\n\n\t\t\tif (component.Disabled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar item = component.Item;\n\n\t\t\tif (item == null) {\n\t\t\t\tuiItem.Id = null;\n\t\t\t} else if (item.Id != uiItem.Id) {\n\t\t\t\tuiItem.Id = item.Id;\n\t\t\t\tuiItem.Scourged = item.Scourged;\n\t\t\t}\n\n\t\t\t// Graphics.Render(inventory.ItemSlot, pos, 0, inventory.ItemSlot.Center, activeScale);\n\n\t\t\tif (uiItem.Region != null) {\n\t\t\t\tvar a = uiItem.Region.Width / 2f + (Active ? 8 : 24);\n\t\t\t\t\n\t\t\t\tuiItem.Center = new Vector2(inventory.Second ? Display.UiWidth - a : a, Display.UiHeight - uiItem.Region.Height / 2f - 8);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Animate() {\n\t\t\tvar v = Active ? 2 : 1;\n\t\t\t\n\t\t\tTween.To(0.6f, activeScale.X, x => activeScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1.5f, activeScale.X, x => activeScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\t\t\tTween.To(1f, activeScale.X, x => activeScale.X = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\tTween.To(1.5f, activeScale.Y, x => activeScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(0.6f, activeScale.Y, x => activeScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\t\t\tTween.To(1f, activeScale.Y, x => activeScale.Y = x, 0.2f);\n\n\t\t\t\n\t\t\tTween.To(0.3f, uiItem.IconScale.X, x => uiItem.IconScale.X = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, uiItem.IconScale.X, x => uiItem.IconScale.X = x, 0.2f);\n\t\t\t\t\t\t\n\t\t\tTween.To(2f, uiItem.IconScale.Y, x => uiItem.IconScale.Y = x, 0.1f).OnEnd = () =>\n\t\t\t\t\tTween.To(1f, uiItem.IconScale.Y, x => uiItem.IconScale.Y = x, 0.2f);\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tif (e is WeaponSwappedEvent ws && ws.Who == inventory.Player) {\n\t\t\t\tAnimate();\n\t\t\t} else if (e is ItemAddedEvent iae) {\n\t\t\t\tif (iae.Who == inventory.Player) {\n\t\t\t\t\tif (iae.Item.Type == ItemType.Weapon) {\n\t\t\t\t\t\tAnimate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/Glyph.cs",
    "content": "using System.Collections.Generic;\nusing BurningKnight.ui.str.@event;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended.BitmapFonts;\n\nnamespace BurningKnight.ui.str {\n\tpublic class Glyph {\n\t\tpublic BitmapFontGlyph G;\n\t\tpublic Color Color;\n\t\tpublic Vector2 Offset;\n\t\tpublic Vector2 Origin;\n\t\tpublic float Angle;\n\t\tpublic Vector2 Scale = Vector2.One;\n\t\tpublic SpriteEffects Effects;\n\t\tpublic List<GlyphEvent> Events = new List<GlyphEvent>();\n\t\tpublic bool State;\n\t\t\n\t\tpublic void Reset() {\n\t\t\tColor = ColorUtils.WhiteColor;\n\t\t\tOffset.X = 0;\n\t\t\tOffset.Y = 0;\n\n\t\t\tif (G.FontRegion != null) {\n\t\t\t\tOrigin.X = G.FontRegion.Width / 2f;\n\t\t\t\tOrigin.Y = G.FontRegion.Height / 2f;\n\t\t\t}\n\t\t\t\n\t\t\tAngle = 0;\n\t\t\tScale.X = 1;\n\t\t\tScale.Y = 1;\n\t\t\tEffects = SpriteEffects.None;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/IconRenderer.cs",
    "content": "using Lens.graphics;\nusing Lens.util;\n\nnamespace BurningKnight.ui.str {\n\tpublic class IconRenderer : StrRenderer {\n\t\tpublic TextureRegion Region;\n\t\t\n\t\tpublic override int GetWidth(UiString str) {\n\t\t\tif (Region == null && str.Icons.Count > Id) {\n\t\t\t\tRegion = str.Icons[Id];\n\n\t\t\t\tif (Region == null) {\n\t\t\t\t\tLog.Error($\"Unknown icon {Id}\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Region != null) {\n\t\t\t\treturn (int) Region.Width;\n\t\t\t}\n\t\t\t\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/StrRenderer.cs",
    "content": "namespace BurningKnight.ui.str {\r\n\tpublic class StrRenderer {\r\n\t\tpublic int Id;\r\n\t\tpublic int Where;\r\n\r\n\t\tpublic virtual int GetWidth(UiString str) {\r\n\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/str/UiString.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing BurningKnight.ui.str.effect;\nusing BurningKnight.ui.str.@event;\nusing Lens;\nusing Lens.entity;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing MonoGame.Extended.BitmapFonts;\n\nnamespace BurningKnight.ui.str {\n\tpublic delegate void StartedTyping(UiString str);\n\tpublic delegate void FinishedTyping(UiString str);\n\tpublic delegate void CharTyped(UiString str, int i, char c);\n\tpublic delegate void EventFired(UiString str, string id);\n\t\n\t/*\n\t * syntax:\n\t *\n\t * _ starts italic\n\t * ** starts bold\n\t * ## starts shake\n\t * @@ starts blink\n\t * && starts flip\n\t * %% starts rainbow\n\t * ^^ starts wave\n\t * ~~ starts randomizer ~~\n\t *\n\t * [event_name var1 var2] starts an event\n\t *  + [dl time] delays\n\t *  + [skp] finishes printing out the string\n\t *  + [sp speed] sets speed\n\t *  + [ev event] fires user event\n\t *  + [vr variable_name] replaced with user variable\n\t *  + [cl color] sets color, can be hex or predefined string in Palette class\n\t *  + [ic id] draws an icon with id=id\n\t */\n\t\n\t/*\n\t * todo:\n\t * [tg a]test[dl a]\n\t */\n\tpublic class UiString : Entity {\n\t\tprivate string label;\n\t\tprivate BitmapFont font;\n\t\tprivate List<Glyph> glyphs = new List<Glyph>();\n\t\tprivate List<GlyphEffect> effects = new List<GlyphEffect>();\n\t\tprivate List<StrRenderer> renderers = new List<StrRenderer>();\n\t\tprivate float progress;\n\t\tprivate int lastChar;\n\t\tpublic float FinalWidth;\n\t\tprivate float finalHeight;\n\n\t\tpublic float Delay;\n\t\tpublic bool Paused;\n\t\tpublic float Speed = 1f;\n\t\tpublic int WidthLimit;\n\t\tpublic bool Finished => progress >= glyphs.Count;\n\n\t\tpublic StartedTyping StartedTyping;\n\t\tpublic FinishedTyping FinishedTyping;\n\t\tpublic EventFired EventFired;\n\t\tpublic CharTyped CharTyped;\n\t\tpublic Action<Vector2, int> Renderer;\n\t\tpublic Dictionary<string, object> Variables = new Dictionary<string, object>();\n\t\tpublic List<TextureRegion> Icons = new List<TextureRegion>();\n\n\t\tpublic void SetVariable(string id, object o) {\n\t\t\tVariables[id] = o;\n\t\t}\n\n\t\tpublic void ClearIcons() {\n\t\t\tIcons.Clear();\n\t\t}\n\t\t\n\t\tpublic void AddIcon(TextureRegion o) {\n\t\t\tif (o == null) {\n\t\t\t\tLog.Error(\"Unknown icon\");\n\t\t\t}\n\t\t\t\n\t\t\tIcons.Add(o);\n\t\t}\n\n\t\tpublic Color Tint = Color.White;\n\t\t\n\t\tpublic string Label {\n\t\t\tget => label;\n\t\t\tset {\n\t\t\t\tlabel = value;\n\t\t\t\tRecalculate();\n\t\t\t}\n\t\t}\n\n\t\tpublic UiString(BitmapFont font) {\n\t\t\tthis.font = font;\n\n\t\t\tWidth = 4;\n\t\t\tHeight = 4;\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\t\t}\n\n\t\tprivate GlyphEffect FindEffect<T>(bool open = true) where T: GlyphEffect {\n\t\t\tvar t = typeof(T);\n\n\t\t\tforeach (var e in effects) {\n\t\t\t\tif (e.GetType() == t && (!open || !e.Closed)) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate void AddEffect<T>(StringBuilder builder) where T: GlyphEffect {\n\t\t\tvar e = FindEffect<T>();\n\n\t\t\tif (e != null) {\n\t\t\t\te.End = builder.Length;\n\t\t\t\te.Closed = true;\n\t\t\t} else {\n\t\t\t\tvar ef = (GlyphEffect) Activator.CreateInstance(typeof(T));\n\n\t\t\t\tef.Start = builder.Length;\n\t\t\t\teffects.Add(ef);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Recalculate() {\n\t\t\tglyphs.Clear();\n\t\t\teffects.Clear();\n\t\t\trenderers.Clear();\n\t\t\t\n\t\t\tStartTyping();\n\n\t\t\tvar builder = new StringBuilder();\n\t\t\tvar token = new StringBuilder();\n\t\t\tvar lc = '\\0';\n\t\t\tvar parsingToken = false;\n\t\t\tvar events = new List<GlyphEvent>();\n\n\t\t\tfor (var i = 0; i < label.Length; i++) {\n\t\t\t\tvar c = label[i];\n\n\t\t\t\tif (parsingToken) {\n\t\t\t\t\tif (c == ']') {\n\t\t\t\t\t\tparsingToken = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar t = token.ToString().TrimStart().TrimEnd();\n\t\t\t\t\t\tvar parts = t.Split(null);\n\n\t\t\t\t\t\tif (parts.Length == 0) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tGlyphEvent e = null;\n\n\t\t\t\t\t\tswitch (parts[0]) {\n\t\t\t\t\t\t\tcase \"skp\": {\n\t\t\t\t\t\t\t\te = new SkipEvent();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"sp\": {\n\t\t\t\t\t\t\t\te = new SpeedEvent();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"dl\": {\n\t\t\t\t\t\t\t\te = new DelayEvent();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"ev\": {\n\t\t\t\t\t\t\t\te = new UserEvent();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"vr\": {\n\t\t\t\t\t\t\t\tif (parts.Length > 1) {\n\t\t\t\t\t\t\t\t\tif (Variables.TryGetValue(parts[1], out var vr)) {\n\t\t\t\t\t\t\t\t\t\tbuilder.Append(vr == null ? \"null\" : vr.ToString());\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tLog.Error($\"Undefined variable {parts[1]}!\");\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"rn\": {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\trenderers.Add(new StrRenderer {\n\t\t\t\t\t\t\t\t\t\tId = parts.Length > 1 ? int.Parse(parts[1]) : 0,\n\t\t\t\t\t\t\t\t\t\tWhere = builder.Length\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\t\t\t\tLog.Error(ex);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"ic\": {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\trenderers.Add(new IconRenderer {\n\t\t\t\t\t\t\t\t\t\tId = parts.Length > 1 ? int.Parse(parts[1]) : 0,\n\t\t\t\t\t\t\t\t\t\tWhere = builder.Length\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tbuilder.Append(' ');\n\t\t\t\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\t\t\t\tLog.Error(ex);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"cl\": {\n\t\t\t\t\t\t\t\tif (parts.Length >= 2) {\n\t\t\t\t\t\t\t\t\tvar ef = new ColorEffect();\n\n\t\t\t\t\t\t\t\t\tef.ParseColor(parts[1]);\n\t\t\t\t\t\t\t\t\tef.Start = builder.Length;\n\t\t\t\t\t\t\t\t\teffects.Add(ef);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tvar en = FindEffect<ColorEffect>();\n\n\t\t\t\t\t\t\t\t\tif (en != null) {\n\t\t\t\t\t\t\t\t\t\ten.End = builder.Length;\n\t\t\t\t\t\t\t\t\t\ten.Closed = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcase \"/cl\": {\n\t\t\t\t\t\t\t\tAddEffect<WaveEffect>(builder);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (e != null) {\n\t\t\t\t\t\t\te.I = builder.Length;\n\t\t\t\t\t\t\te.Parse(parts);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tevents.Add(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\ttoken.Append(c);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '[': {\n\t\t\t\t\t\tif (lc == '\\\\') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tbuilder.Append('[');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparsingToken = true;\n\t\t\t\t\t\ttoken.Clear();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '^': {\n\t\t\t\t\t\tif (lc == '^') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<WaveEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '*': {\n\t\t\t\t\t\tif (lc == '*') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<BoldEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '_': {\n\t\t\t\t\t\tif (lc == '\\\\') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tAddEffect<ItalicEffect>(builder);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '%': {\n\t\t\t\t\t\tif (lc == '%') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<RainbowEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcase '&': {\n\t\t\t\t\t\tif (lc == '&') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<FlipEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '@': {\n\t\t\t\t\t\tif (lc == '@') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<BlinkEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '#': {\n\t\t\t\t\t\tif (lc == '#') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<ShakeEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase '~': {\n\t\t\t\t\t\tif (lc == '~') {\n\t\t\t\t\t\t\tbuilder.Remove(builder.Length - 1, 1);\n\t\t\t\t\t\t\tAddEffect<RandomEffect>(builder);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlc = c;\n\t\t\t}\n\n\t\t\tforeach (var e in effects) {\n\t\t\t\tif (!e.Closed) {\n\t\t\t\t\te.End = builder.Length;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tlabel = builder.ToString();\n\t\t\tbuilder.Clear();\n\t\t\tvar glp = font.GetGlyphs(label);\n\t\t\tvar spaceWidth = (int) (font.MeasureString(\"a a\").Width - font.MeasureString(\"aa\").Width);\n\n\t\t\tif (WidthLimit > 0) {\n\t\t\t\tvar k = 0;\n\t\t\t\tvar lastSpace = 0;\n\t\t\t\tvar sinceLastSpace = 0;\n\t\t\t\tvar sinceLast = 0;\n\t\t\t\tvar width = 0;\n\t\t\t\tvar first = true;\n\t\t\t\tvar i = 0;\n\t\t\t\t\n\t\t\t\tforeach (var g in glp) {\n\t\t\t\t\tvar c = label[k];\n\t\t\t\t\tvar w = 0;\n\n\t\t\t\t\tif (c == ' ') {\n\t\t\t\t\t\tlastSpace = k;\n\t\t\t\t\t\tsinceLastSpace = 0;\n\t\t\t\t\t\tw = spaceWidth;\n\t\t\t\t\t} else if (c == '\\n') {\n\t\t\t\t\t\tsinceLast = 0;\n\t\t\t\t\t\tsinceLastSpace = 0;\n\t\t\t\t\t\twidth = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tw = g.FontRegion.Width;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar hadIcon = false;\n\t\t\t\t\t\n\t\t\t\t\tif (renderers.Count > 0) {\n\t\t\t\t\t\tforeach (var r in renderers) {\n\t\t\t\t\t\t\tif (r.Where == i) {\n\t\t\t\t\t\t\t\tif (r is IconRenderer ir) {\n\t\t\t\t\t\t\t\t\tw += ir.GetWidth(this) - spaceWidth;\n\t\t\t\t\t\t\t\t\thadIcon = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ti++;\n\n\t\t\t\t\tif (c != '\\n' || hadIcon) {\n\t\t\t\t\t\tsinceLast += w;\n\t\t\t\t\t\twidth += w;\n\n\t\t\t\t\t\tif (c != ' ') {\n\t\t\t\t\t\t\tsinceLastSpace += w;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\n\t\t\t\t\tif (width >= WidthLimit) {\n\t\t\t\t\t\tif (first) {\n\t\t\t\t\t\t\tWidthLimit = width - sinceLastSpace - spaceWidth;\n\t\t\t\t\t\t\tfirst = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\twidth -= sinceLast;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsinceLast = width;\n\t\t\t\t\t\tbuilder[lastSpace] = '\\n';\n\t\t\t\t\t}\n\n\t\t\t\t\tk++;\n\t\t\t\t}\n\n\t\t\t\tlabel = builder.ToString();\n\t\t\t}\n\t\t\t\n\t\t\tglp = font.GetGlyphs(label);\n\t\t\tvar size = font.MeasureString(label);\n\n\t\t\tFinalWidth = size.Width;\n\t\t\tfinalHeight = size.Height - 4;\n\n\t\t\tvar j = 0;\n\t\t\tvar ww = 0;\n\n\t\t\tforeach (var g in glp) {\n\t\t\t\tvar gl = new Glyph {\n\t\t\t\t\tG = g\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tif (label[j] == '\\n') {\n\t\t\t\t\tww = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgl.G.Position.X += ww;\n\t\t\t\t\n\t\t\t\tif (renderers.Count > 0) {\n\t\t\t\t\tforeach (var r in renderers) {\n\t\t\t\t\t\tif (r.Where == j) {\n\t\t\t\t\t\t\tif (r is IconRenderer ir) {\n\t\t\t\t\t\t\t\tvar v = ir.GetWidth(this) - spaceWidth;\n\t\t\t\t\t\t\t\tww += v;\n\t\t\t\t\t\t\t\tFinalWidth += v;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tgl.Reset();\n\t\t\t\tglyphs.Add(gl);\n\n\t\t\t\tfor (var i = events.Count - 1; i >= 0; i--) {\n\t\t\t\t\tvar e = events[i];\n\n\t\t\t\t\tif (e.I == j) {\n\t\t\t\t\t\tgl.Events.Add(e);\n\t\t\t\t\t\tevents.RemoveAt(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tj++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Stop() {\n\t\t\tPaused = true;\n\t\t}\n\t\t\n\t\tpublic bool ShouldntRender => Engine.Instance.State.Paused || label == null || Tint.A == 0 || glyphs.Count == 0;\n\t\tpublic bool DisableRender;\n\n\t\tpublic override void Render() {\n\t\t\tif (ShouldntRender || DisableRender) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tRenderString();\n\t\t}\n\n\t\tpublic void RenderString() {\n\t\t\tvar m = 1;\n\t\t\tvar n = m - 1;\n\t\t\tvar l = (int) Math.Min(progress + n, glyphs.Count);\n\n\t\t\tfor (var i = 0; i < l; i++) {\n\t\t\t\tvar g = glyphs[i];\n\t\t\t\t\n\t\t\t\tif (g.G.FontRegion != null) {\n\t\t\t\t\tvar pos = new Vector2(\n\t\t\t\t\t\tPosition.X + g.G.Position.X + g.Offset.X + g.Origin.X,\n\t\t\t\t\t\tPosition.Y + g.G.Position.Y + g.Offset.Y + g.Origin.Y\n\t\t\t\t\t);\n\n\t\t\t\t\tvar c = g.Color;\n\n\t\t\t\t\tif (progress > i && progress < i + 1) {\n\t\t\t\t\t\tfloat v = (progress + n - i) / m;\n\t\t\t\t\t\t\n\t\t\t\t\t\tpos.Y -= (1 - v) * 8f;\n\t\t\t\t\t\tc.A = (byte) (v * 255);\n\t\t\t\t\t}\n\n\t\t\t\t\tc.A = (byte) MathUtils.Clamp(0, 255, (float) c.A * Tint.A / 255f);\n\n\t\t\t\t\tGraphics.Batch.Draw(g.G.FontRegion.TextureRegion.Texture, pos,\n\t\t\t\t\t\tg.G.FontRegion.TextureRegion.Bounds, c, g.Angle, g.Origin, g.Scale, g.Effects, 0);\n\t\t\t\t}\n\n\t\t\t\tif (renderers.Count > 0) {\n\t\t\t\t\tGraphics.Color.A = (byte) MathUtils.Clamp(0, 255, (float) g.Color.A * Tint.A / 255f);\n\n\t\t\t\t\tforeach (var r in renderers) {\n\t\t\t\t\t\tif (r.Where == i) {\n\t\t\t\t\t\t\tif (r is IconRenderer ir) {\n\t\t\t\t\t\t\t\tif (ir.Region != null) {\n\t\t\t\t\t\t\t\t\tGraphics.Render(ir.Region, new Vector2(Position.X + g.G.Position.X + g.Offset.X + g.Origin.X,\n\t\t\t\t\t\t\t\t\t\tPosition.Y + g.G.Position.Y + (ir.Region.Height - 7) / 2f - ir.Region.Height + 1 + g.Offset.Y + g.Origin.Y));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tRenderer(Position + g.G.Position + g.Offset - new Vector2(0, 9), r.Id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Color.A = 255;\n\t\t\t}\n\t\t}\n\n\t\tpublic void FinishTyping() {\n\t\t\tprogress = glyphs.Count;\n\t\t\tWidth = FinalWidth;\n\t\t\tHeight = finalHeight;\n\t\t\tFinishedTyping?.Invoke(this);\n\t\t}\n\n\t\tpublic void StartTyping() {\n\t\t\tprogress = 0f;\n\t\t\tlastChar = 0;\n\t\t\tDelay = 0;\n\t\t\tPaused = false;\n\t\t\tSpeed = 1;\n\n\t\t\tif (WidthLimit > 0) {\n\t\t\t\tWidthLimit = 200;\n\t\t\t}\n\t\t\t\n\t\t\tStartedTyping?.Invoke(this);\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Delay > 0 || Paused) {\n\t\t\t\tDelay -= dt;\n\t\t\t} else {\n\t\t\t\tprogress = Math.Min(progress + Speed * dt * 25f, glyphs.Count);\n\t\t\t\tvar v = (int) Math.Floor(progress);\n\n\t\t\t\twhile (true) {\n\t\t\t\t\tif (v > lastChar) {\n\t\t\t\t\t\tlastChar++;\n\n\t\t\t\t\t\tif (v < glyphs.Count) {\n\t\t\t\t\t\t\tvar g = glyphs[v];\n\n\t\t\t\t\t\t\tforeach (var e in g.Events) {\n\t\t\t\t\t\t\t\te.Fire(this, g);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tCharTyped?.Invoke(this, v, label[v]);\n\n\t\t\t\t\t\t\tif (g.G.FontRegion != null) {\n\t\t\t\t\t\t\t\tWidth = Math.Max(Width, g.G.Position.X + g.G.FontRegion.Width);\n\t\t\t\t\t\t\t\tHeight = Math.Max(Height, g.G.Position.Y + g.G.FontRegion.Height);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ((int) Math.Ceiling(progress) == glyphs.Count) {\n\t\t\t\t\t\t\tFinishTyping();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var g in glyphs) {\n\t\t\t\tg.Reset();\n\t\t\t}\n\n\t\t\tfor (var i = effects.Count - 1; i >= 0; i--) {\n\t\t\t\tvar e = effects[i];\n\t\t\t\te.Update(dt);\n\t\t\t\t\n\t\t\t\tfor (var j = e.Start; j < Math.Min(glyphs.Count, e.End); j++) {\n\t\t\t\t\te.Apply(glyphs[j], j);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (e.Ended()) {\n\t\t\t\t\teffects.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/BlinkEffect.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class BlinkEffect : GlyphEffect {\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Color.A = (byte) Math.Round((Math.Cos(Time * 2f) * 0.5f + 0.5f) * 255);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/BoldEffect.cs",
    "content": "namespace BurningKnight.ui.str.effect {\n\tpublic class BoldEffect : GlyphEffect {\n\t\tpublic float Scale = 0.2f;\n\t\t\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Scale.X += Scale;\n\t\t\tglyph.Scale.Y += Scale;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/ColorEffect.cs",
    "content": "using BurningKnight.assets;\nusing Lens.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class ColorEffect : GlyphEffect {\n\t\tpublic Color Color = ColorUtils.WhiteColor;\n\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Color = Color;\n\t\t}\n\n\t\tpublic void ParseColor(string color) {\n\t\t\tif (color.StartsWith(\"#\")) {\n\t\t\t\tColor = ColorUtils.FromHex(color);\n\t\t\t} else if (Palette.Colors.TryGetValue(color, out var c)) {\n\t\t\t\tColor = c;\n\t\t\t} else {\n\t\t\t\tLog.Error($\"Unknown color {color}\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/FlipEffect.cs",
    "content": "namespace BurningKnight.ui.str.effect {\n\tpublic class FlipEffect : GlyphEffect {\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Scale.Y *= -1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/GlyphEffect.cs",
    "content": "namespace BurningKnight.ui.str.effect {\n\tpublic class GlyphEffect {\n\t\tpublic int Start;\n\t\tpublic int End;\n\t\tpublic float Time;\n\t\tpublic bool Closed;\n\t\t\n\t\tpublic virtual void Apply(Glyph glyph, int i) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\tTime += dt;\n\t\t}\n\n\t\tpublic virtual bool Ended() {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/ItalicEffect.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class ItalicEffect : GlyphEffect {\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Angle = (float) (Math.PI * 0.06f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/RainbowEffect.cs",
    "content": "using Lens.graphics;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class RainbowEffect : GlyphEffect {\n\t\tpublic float Speed = 1f;\n\t\tpublic float Width = 0.05f;\n\t\t\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Color = ColorUtils.FromHSV(((Time * Speed + i * Width) * 360f) % 360f, 100f, 100f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/RandomEffect.cs",
    "content": "using System;\nusing BurningKnight.assets;\nusing Lens;\nusing Lens.util.math;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class RandomEffect : GlyphEffect {\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tvar t = Engine.Time * 0.1f;\n\t\t\tvar a = Math.Cos(i * 0.1f + t * 4 * Math.Sin(t * 0.5f) * Math.Cos(t * i)) > 0.6f;\n\t\t\t\n\t\t\tif (glyph.State != a) {\n\t\t\t\tglyph.State = a;\n\t\t\t\tglyph.G.FontRegion = Font.Small.GetCharacterRegion(a ? Rnd.Int(255) : glyph.G.Character);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/ShakeEffect.cs",
    "content": "using Lens.util;\r\n\r\nnamespace BurningKnight.ui.str.effect {\r\n\tpublic class ShakeEffect : GlyphEffect {\r\n\t\tpublic float Amplitude = 0.01f;\r\n\t\t\r\n\t\tpublic override void Apply(Glyph glyph, int i) {\r\n\t\t\tvar t = Time * 6f + i * 10;\r\n\t\t\tglyph.Offset.X = Noise.Generate(-t) * Amplitude;\r\n\t\t\tglyph.Offset.Y = Noise.Generate(-t * 0.95f + 32f) * Amplitude;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/str/effect/WaveEffect.cs",
    "content": "using System;\n\nnamespace BurningKnight.ui.str.effect {\n\tpublic class WaveEffect : GlyphEffect {\n\t\tpublic float Amplitude = 1f;\n\t\tpublic float Width = 1f;\n\t\tpublic float Speed = 1f;\n\t\t\n\t\tpublic override void Apply(Glyph glyph, int i) {\n\t\t\tglyph.Offset.Y += (float) Math.Cos(Time * Speed * 4f + i * Math.PI / 8f * Width) * Amplitude * 2.5f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/event/DelayEvent.cs",
    "content": "namespace BurningKnight.ui.str.@event {\r\n\tpublic class DelayEvent : GlyphEvent {\r\n\t\tpublic float Delay = 0.5f;\r\n\t\t\r\n\t\tpublic override void Fire(UiString str, Glyph g) {\r\n\t\t\tstr.Delay += Delay;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/str/event/GlyphEvent.cs",
    "content": "namespace BurningKnight.ui.str.@event {\r\n\tpublic class GlyphEvent {\r\n\t\tpublic int I;\r\n\t\t\r\n\t\tpublic virtual void Fire(UiString str, Glyph g) {\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tpublic virtual void Parse(string[] args) {\r\n\t\t\t\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/ui/str/event/SkipEvent.cs",
    "content": "namespace BurningKnight.ui.str.@event {\n\tpublic class SkipEvent : GlyphEvent {\n\t\tpublic override void Fire(UiString str, Glyph g) {\n\t\t\tstr.FinishTyping();\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/event/SpeedEvent.cs",
    "content": "using System;\nusing Lens.util;\n\nnamespace BurningKnight.ui.str.@event {\n\tpublic class SpeedEvent : GlyphEvent {\n\t\tpublic float Speed = 1f;\n\t\t\n\t\tpublic override void Fire(UiString str, Glyph g) {\n\t\t\tstr.Speed = Speed;\n\t\t}\n\n\t\tpublic override void Parse(string[] args) {\n\t\t\tif (args.Length >= 2) {\n\t\t\t\ttry {\n\t\t\t\t\tfloat.TryParse(args[1], out Speed);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/ui/str/event/UserEvent.cs",
    "content": "namespace BurningKnight.ui.str.@event {\n\tpublic class UserEvent : GlyphEvent {\n\t\tpublic string Id = \"unknown\";\n\t\t\n\t\tpublic override void Fire(UiString str, Glyph g) {\n\t\t\tstr.EventFired?.Invoke(str, Id);\n\t\t}\n\n\t\tpublic override void Parse(string[] args) {\n\t\t\tif (args.Length >= 2) {\n\t\t\t\tId = args[1];\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/AnimationUtil.cs",
    "content": "using System;\r\nusing BurningKnight.assets.lighting;\r\nusing BurningKnight.assets.particle;\r\nusing BurningKnight.assets.particle.custom;\r\nusing BurningKnight.entity.component;\r\nusing BurningKnight.entity.creature.player;\r\nusing BurningKnight.state;\r\nusing Lens.assets;\r\nusing Lens.entity;\r\nusing Lens.util;\r\nusing Lens.util.camera;\r\nusing Lens.util.math;\r\nusing Lens.util.tween;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.util {\r\n\tpublic static class AnimationUtil {\r\n\t\tpublic static void ActionFailed() {\r\n\t\t\tCamera.Instance.Shake(10);\r\n\t\t\tAudio.PlaySfx(\"item_nocash\");\r\n\t\t}\r\n\r\n\t\tpublic static void Poof(Vector2 where, int depth = 0) {\r\n\t\t\tif (Settings.LowQuality) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < 4; i++) {\r\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\r\n\t\t\t\t\t\t\r\n\t\t\t\tpart.Position = where;\r\n\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\r\n\t\t\t\tRun.Level.Area.Add(part);\r\n\t\t\t\tpart.Depth = depth;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Confetti(Vector2 where) {\r\n\t\t\tif (Settings.LowQuality) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < 15; i++) {\r\n\t\t\t\tvar p = Run.Level.Area.Add(new ConfettiParticle());\r\n\t\t\t\tp.Center = where;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void Ash(Vector2 where, int depth = 0) {\r\n\t\t\tif (Settings.LowQuality) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tfor (var i = 0; i < 4; i++) {\r\n\t\t\t\tvar part = new ParticleEntity(Particles.Ash());\r\n\t\t\t\t\t\t\r\n\t\t\t\tpart.Position = where;\r\n\t\t\t\tpart.Particle.Scale = Rnd.Float(1f, 2f);\r\n\t\t\t\tpart.Particle.Velocity = new Vector2(Rnd.Float(20, 30) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(40, 66));\r\n\t\t\t\tRun.Level.Area.Add(part);\r\n\t\t\t\tpart.Depth = depth;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tpublic static void PoofFrom(Vector2 where, Vector2 from, int depth = 0) {\r\n\t\t\tfor (var i = 0; i < 4; i++) {\r\n\t\t\t\tvar part = new ParticleEntity(Particles.Dust());\r\n\t\t\t\t\t\t\r\n\t\t\t\tpart.Position = where;\r\n\t\t\t\tpart.Particle.Scale = Rnd.Float(0.4f, 0.8f);\r\n\t\t\t\tRun.Level.Area.Add(part);\r\n\t\t\t\tpart.Depth = depth;\r\n\t\t\t\tpart.Particle.Velocity = MathUtils.CreateVector((where - from).ToAngle(), 80);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void Explosion(Vector2 where, float scale = 1) {\r\n\t\t\tvar explosion = new ParticleEntity(Particles.Animated(\"explosion\", \"explosion\"));\r\n\t\t\texplosion.Position = where;\r\n\t\t\tRun.Level.Area.Add(explosion);\r\n\t\t\texplosion.Depth = 32;\r\n\t\t\texplosion.Particle.Velocity = Vector2.Zero;\r\n\t\t\texplosion.Particle.Scale = scale;\r\n\t\t\texplosion.AddShadow();\r\n\r\n\t\t\tLights.Flash = 1f;\r\n\t\t}\r\n\r\n\t\tpublic static void TeleportAway(Entity entity, Action callback) {\r\n\t\t\tvar scale = entity is Player\r\n\t\t\t\t? entity.GetComponent<PlayerGraphicsComponent>().Scale\r\n\t\t\t\t: entity.GetAnyComponent<MobAnimationComponent>().Scale;\r\n\r\n\t\t\tif (!entity.HasComponent<ZComponent>()) {\r\n\t\t\t\tentity.AddComponent(new ZComponent());\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar z = entity.GetComponent<ZComponent>();\r\n\t\t\t\r\n\t\t\tentity.GetComponent<HealthComponent>().Unhittable = true;\r\n\r\n\t\t\tTween.To(0, (entity is Player\r\n\t\t\t\t? entity.GetComponent<PlayerGraphicsComponent>().Scale\r\n\t\t\t\t: entity.GetAnyComponent<MobAnimationComponent>().Scale).X, x => {\r\n\r\n\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.X = x;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.X = x;\r\n\t\t\t\t}\r\n\t\t\t}, 0.3f, Ease.QuadIn);\r\n\t\t\tTween.To(4, (entity is Player\r\n\t\t\t\t? entity.GetComponent<PlayerGraphicsComponent>().Scale\r\n\t\t\t\t: entity.GetAnyComponent<MobAnimationComponent>().Scale).Y, x => {\r\n\t\t\t\t\r\n\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.Y = x;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.Y = x;\r\n\t\t\t\t}\r\n\t\t\t}, 0.3f, Ease.QuadIn);\r\n\t\t\t\r\n\t\t\tTween.To(128, z.Z, x => z.Z = x, 0.3f, Ease.QuadIn).OnEnd = callback;\r\n\t\t}\r\n\r\n\t\tpublic static void TeleportIn(Entity entity) {\r\n\t\t\tvar scale = new Func<Vector2>(() => entity is Player\r\n\t\t\t\t? entity.GetComponent<PlayerGraphicsComponent>().Scale\r\n\t\t\t\t: entity.GetAnyComponent<MobAnimationComponent>().Scale);\r\n\r\n\t\t\tvar z = entity.GetComponent<ZComponent>();\r\n\t\t\t\r\n\t\t\tentity.GetComponent<HealthComponent>().Unhittable = true;\r\n\r\n\t\t\tTween.To(1.5f, scale().X, x => {\r\n\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.X = x;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.X = x;\r\n\t\t\t\t}\r\n\t\t\t}, 0.3f);\r\n\t\t\tTween.To(0.1f, scale().Y, x => {\r\n\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.Y = x;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.Y = x;\r\n\t\t\t\t}\r\n\t\t\t}, 0.3f).OnEnd = () => {\r\n\t\t\t\tTween.To(1, scale().X, x => {\r\n\t\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.X = x;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.X = x;\r\n\t\t\t\t\t}\r\n\t\t\t\t}, 0.3f);\r\n\t\t\t\tTween.To(1f, scale().Y, x => {\r\n\t\t\t\t\tif (entity is Player) {\r\n\t\t\t\t\t\tentity.GetComponent<PlayerGraphicsComponent>().Scale.Y = x;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tentity.GetAnyComponent<MobAnimationComponent>().Scale.Y = x;\r\n\t\t\t\t\t}\r\n\t\t\t\t}, 0.3f);\r\n\t\t\t};\r\n\t\t\t\r\n\t\t\tTween.To(0, z.Z, x => z.Z = x, 0.2f).OnEnd = () => {\r\n\t\t\t\tentity.GetComponent<HealthComponent>().Unhittable = false;\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/util/ArrayUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace BurningKnight.util {\n\tpublic static class ArrayUtils {\n\t\tpublic static float[] Clone(float[] array) {\n\t\t\tvar clone = new float[array.Length];\n\n\t\t\tfor (var i = 0; i < array.Length; i++) {\n\t\t\t\tclone[i] = array[i];\n\t\t\t}\n\t\t\t\n\t\t\treturn clone;\n\t\t}\n\t\t\n\t\tpublic static bool[] Clone(bool[] array) {\n\t\t\tvar clone = new bool[array.Length];\n\n\t\t\tfor (var i = 0; i < array.Length; i++) {\n\t\t\t\tclone[i] = array[i];\n\t\t\t}\n\t\t\t\n\t\t\treturn clone;\n\t\t}\n\t\t\n\t\tpublic static T[] Clone<T>(List<T> array) {\n\t\t\tvar clone = new T[array.Count];\n\n\t\t\tfor (var i = 0; i < array.Count; i++) {\n\t\t\t\tclone[i] = array[i];\n\t\t\t}\n\t\t\t\n\t\t\treturn clone;\n\t\t}\n\n\t\tpublic static void Remove<T>(List<T> array, Func<T, bool> filter) {\n\t\t\tfor (var i = array.Count - 1; i >= 0; i--) {\n\t\t\t\tif (filter(array[i])) {\n\t\t\t\t\tarray.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/BArray.cs",
    "content": "namespace BurningKnight.util {\n\tpublic class BArray {\n\t\tpublic static bool[] Not(bool[] A, bool[] Result) {\n\t\t\tint Length = A.Length;\n\n\t\t\tif (Result == null) {\n\t\t\t\tResult = new bool[Length];\n\t\t\t}\n\n\t\t\tfor (var I = 0; I < Length; I++) {\n\t\t\t\tResult[I] = !A[I];\n\t\t\t}\n\n\t\t\treturn Result;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/BiomeTitles.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.level.biome;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.util {\n\tpublic static class BiomeTitles {\n\t\tprivate static Dictionary<string, List<string>> defined = new Dictionary<string, List<string>>();\n\n\t\tpublic static void Add(string biome, params string[] joke) {\n\t\t\tif (!defined.ContainsKey(biome)) {\n\t\t\t\tdefined[biome] = new List<string>();\n\t\t\t}\n\t\t\t\n\t\t\tdefined[biome].AddRange(joke);\n\t\t}\n\n\t\tpublic static string Generate(string biome) {\n\t\t\tif (!defined.TryGetValue(biome, out var list)) {\n\t\t\t\tLog.Error($\"Didn't find title for {biome}\");\n\t\t\t\treturn \"Idk man, kinda 404?\";\n\t\t\t}\n\n\t\t\treturn list[new Random().Next(list.Count)];\n\t\t}\n\n\t\tstatic BiomeTitles() {\n\t\t\tAdd(Biome.Hub,\n\t\t\t\t\"Dodge this\",\n\t\t\t\t\"Shopkeeper knows something\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Castle,\n\t\t\t\t\"This place is old\",\n\t\t\t\t\"The knights are gone\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Desert,\n\t\t\t\t\"Drink water, stay hydrated\",\n\t\t\t\t\"Anakin hates sand\",\n\t\t\t\t\"It's getting hot\",\n\t\t\t\t\"Not to be confused with the desert\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Jungle,\n\t\t\t\t\"This is wild\",\n\t\t\t\t\"Jungle be like\",\n\t\t\t\t\"This place is growing on me\",\n\t\t\t\t\"Like snakes and ladders without ladders\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Ice,\n\t\t\t\t\"This place is cool\",\n\t\t\t\t\"Let it snow\",\n\t\t\t\t\"The winter is coming\",\n\t\t\t\t\"Ice Age\",\n\t\t\t\t\"Snow Inc.\",\n\t\t\t\t\"I saw mammoth\",\n\t\t\t\t\"Stop the global warming!\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Library,\n\t\t\t\t\"Try to pillage quieter, please!\",\n\t\t\t\t\"Read a book\",\n\t\t\t\t\"Books are expensive\",\n\t\t\t\t\"Book a flight, read a book\",\n\t\t\t\t\"404. Page not found\",\n\t\t\t\t\"Peace was never an option\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Tech,\n\t\t\t\t\"Inside of the simulation\",\n\t\t\t\t\"Chips & Chops\",\n\t\t\t\t\"Null Pointer Exception\",\n\t\t\t\t\"Processor Inside\",\n\t\t\t\t\"Modern problems require modern solutions\",\n\t\t\t\t\"Hakerman\",\n\t\t\t\t\"Just like in the simulations\"\n\t\t\t);\n\t\t\t\n\t\t\tAdd(Biome.Cave,\n\t\t\t\t\"Deep stuff\",\n\t\t\t\t\"Rave cave\",\n\t\t\t\t\"Hello?\",\n\t\t\t\t\"Shiny stuff\",\n\t\t\t\t\"Grab your pickaxes\"\n\t\t\t);\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Birthday.cs",
    "content": "namespace BurningKnight.util {\n\tpublic class Birthday {\n\t\tpublic int Day;\n\t\tpublic int Month;\n\n\t\tpublic Birthday(int day, int month) {\n\t\t\tDay = day;\n\t\t\tMonth = month;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/BitHelper.cs",
    "content": "namespace BurningKnight.util {\n\tpublic class BitHelper {\n\t\tpublic static bool IsBitSet(int val, int pos) {\n\t\t\treturn (val & (1 << pos)) != 0;\n\t\t}\n\n\t\tpublic static int SetBit(int Val, int Pos, bool Set) {\n\t\t\tif (Set) {\n\t\t\t\treturn Val | (1 << Pos);\n\t\t\t}\n\n\t\t\treturn Val & ~(1 << Pos);\n\t\t}\n\n\t\tpublic static int GetBit(int Data, int Bit) {\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/CollisionHelper.cs",
    "content": "namespace BurningKnight.util {\n\tpublic class CollisionHelper {\n\t\tpublic static bool Check(int Px, int Py, int X, int Y, int W, int H) {\n\t\t\treturn Px >= X && Py >= Y && Px <= X + W && Py <= Y + H;\n\t\t}\n\n\t\tpublic static bool Check(float X, float Y, float W, float H, float X1, float Y1, float W1, float H1) {\n\t\t\treturn X < X1 + W1 && X + W > X1 && Y < Y1 + H1 && Y + H > Y1;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Direction.cs",
    "content": "namespace BurningKnight.util {\n\tpublic enum Direction {\n\t\tUp, Down,\n\t\tLeft, Right,\n\t\tCenter\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Directions.cs",
    "content": "using System;\n\nnamespace BurningKnight.util {\n\tpublic static class Directions {\n\t\tpublic static Direction[] Values = {\n\t\t\tDirection.Up, Direction.Down,\n\t\t\tDirection.Left, Direction.Right,\n\t\t\tDirection.Center\n\t\t};\n\n\t\tpublic static int Convert(this Direction value) {\n\t\t\tfor (var i = 0; i < Values.Length; i++) {\n\t\t\t\tif (Values[i] == value) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic static Direction Convert(int i) {\n\t\t\treturn Values[i];\n\t\t}\n\n\t\tpublic static string ToString(this Direction value) {\n\t\t\treturn value.ToString().ToLower();\n\t\t}\n\n\t\tpublic static float ToAngle(this Direction direction) {\n\t\t\tswitch (direction) {\n\t\t\t\tcase Direction.Left: return (float) Math.PI;\n\t\t\t\tcase Direction.Up: return (float) Math.PI * 1.5f;\n\t\t\t\tcase Direction.Down: return (float) Math.PI * 0.5f;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic static int GetMx(this Direction direction) {\n\t\t\tswitch (direction) {\n\t\t\t\tcase Direction.Left: return 1;\n\t\t\t\tcase Direction.Right: return -1;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic static int GetMy(this Direction direction) {\n\t\t\tswitch (direction) {\n\t\t\t\tcase Direction.Up: return 1;\n\t\t\t\tcase Direction.Down: return -1;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/FollowingDriver.cs",
    "content": "﻿using BurningKnight.entity;\nusing Lens;\nusing Lens.util.camera;\n\nnamespace BurningKnight.util {\n\tpublic class FollowingDriver : CameraDriver {\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tforeach (var target in Camera.Targets) {\n\t\t\t\tif (target.Entity.Area == Camera.Area) {\n\t\t\t\t\tCamera.PositionX += (target.Entity.CenterX - Display.UiWidth * 0.5f) * dt * target.Priority;\n\t\t\t\t\tCamera.PositionY += (target.Entity.CenterY - Display.UiHeight * 0.5f) * dt * target.Priority * Display.Viewport * 1.6f;\t\n\t\t\t\t} else {\n\t\t\t\t\tCamera.Approach(target.Entity.Center, dt * 5 * target.Priority);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/ImJson.cs",
    "content": "using ImGuiNET;\nusing Lens.lightJson;\n\nnamespace BurningKnight.util {\n\tpublic static class ImJson {\n\t\tpublic static bool Checkbox(this JsonValue value, string name, string id, bool d = true) {\n\t\t\tvar val = value[id].Bool(d);\n\t\t\tImGui.Checkbox(name, ref val);\n\t\t\tvalue[id] = val;\n\n\t\t\treturn val;\n\t\t}\n\t\t\n\t\tpublic static int InputInt(this JsonValue value, string name, string id, int d = 1) {\n\t\t\tvar val = value[id].Int(d);\n\t\t\tImGui.InputInt(name, ref val);\n\t\t\tvalue[id] = val;\n\n\t\t\treturn val;\n\t\t}\n\t\t\n\t\tpublic static float InputFloat(this JsonValue value, string name, string id, float d = 1) {\n\t\t\tvar val = value[id].Number(d);\n\t\t\tImGui.InputFloat(name, ref val);\n\t\t\tvalue[id] = val;\n\n\t\t\treturn val;\n\t\t}\n\t\t\n\t\tpublic static string InputText(this JsonValue value, string name, string id, string d = \"\", uint length = 64) {\n\t\t\tvar val = value[id].String(d) ?? \"\";\n\n\t\t\tImGui.InputText(name, ref val, length); \n\t\t\tvalue[id] = val;\n\n\t\t\treturn val;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/JsonCounter.cs",
    "content": "namespace BurningKnight.util {\n\tpublic static class JsonCounter {\n\t\tpublic static int Calculate(string data) {\n\t\t\tvar number = 0;\n\n\t\t\tforeach (var c in data) {\n\t\t\t\tnumber += c;\n\t\t\t}\n\n\t\t\treturn number;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Line.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.util {\n\tpublic class Line {\n\t\tpublic List<Vector2> Points;\n\n\t\tpublic Line(int X0, int Y0, int X1, int Y1) {\n\t\t\tPoints = new List<Vector2>();\n\t\t\tint Dx = Math.Abs(X0 - X1);\n\t\t\tint Dy = Math.Abs(Y0 - Y1);\n\t\t\tvar Sx = X0 < X1 ? 1 : -1;\n\t\t\tvar Sy = Y0 < Y1 ? 1 : -1;\n\t\t\tvar Err = Dx - Dy;\n\n\t\t\twhile (true) {\n\t\t\t\tPoints.Add(new Vector2(X0, Y0));\n\n\t\t\t\tif (X0 == X1 && Y0 == Y1) break;\n\n\t\t\t\tvar E2 = Err * 2;\n\n\t\t\t\tif (E2 > -Dx) {\n\t\t\t\t\tErr -= Dy;\n\t\t\t\t\tX0 += Sx;\n\t\t\t\t}\n\n\t\t\t\tif (E2 < Dx) {\n\t\t\t\t\tErr += Dx;\n\t\t\t\t\tY0 += Sy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/LoadScreenJokes.cs",
    "content": "using System;\n\nnamespace BurningKnight.util {\n\tpublic static class LoadScreenJokes {\n\t\tpublic static string Generate() {\n\t\t\treturn jokes[new Random().Next(jokes.Length)];\n\t\t}\n\t\t\n\t\tprivate static readonly string[] jokes = {\n\t\t\t\"Please stand by\",\n\t\t\t\"Press X\",\n\t\t\t\"Generating trouble\",\n\t\t\t\"If you want to buy something, you need to have money\",\n\t\t\t\"Press / to open chat\",\n\t\t\t\"Generating generators\",\n\t\t\t\"Submitting an issue\",\n\t\t\t\"Terraforming Mars\",\n\t\t\t\"Occupying Mars\",\n\t\t\t\"To defeat a boss, shoot at it until it dies\",\n\t\t\t\"I think that knight wanted to say something\",\n\t\t\t\"Are we there yet?\",\n\t\t\t\"Generating secrets\",\n\t\t\t\"Hiding secrets\",\n\t\t\t\"I'm hungry\",\n\t\t\t\"/!\\\\ /!\\\\ /!\\\\\",\n\t\t\t\"Saving is important\",\n\t\t\t\"Cooling down\",\n\t\t\t\"Heating up\",\n\t\t\t\"Adding some drama\",\n\t\t\t\"You better get digging\",\n\t\t\t\"Generating generators\",\n\t\t\t\"Waking up\",\n\t\t\t\"Deleting the saves\",\n\t\t\t\"Preparing to start\",\n\t\t\t\"Looking for an excuse\",\n\t\t\t\"Automatically synchronizing cardinal grammeters\",\n\t\t\t\"Reducing sinusoidal repleneration\",\n\t\t\t\"Fromaging the bituminous spandrels\",\n\t\t\t\"Reticulating splines\",\n\t\t\t\"Calculating Math.PI\",\n\t\t\t\"Inventing the wheel\",\n\t\t\t\"Recruiting robot hamsters\",\n\t\t\t\"Generating buttons\",\n\t\t\t\"~~Installing deinstallers~~\",\n\t\t\t\"Thinking\",\n\t\t\t\"I like pizza\",\n\t\t\t\"That fight tho\",\n\t\t\t\"Be careful\",\n\t\t\t\"Almost alive\",\n\t\t\t\"Dog food\",\n\t\t\t\"Always wear dry socks\",\n\t\t\t\"Its your lucky day\",\n\t\t\t\"Press F to pay respect\",\n\t\t\t\"Let's do this\",\n\t\t\t\"Let's ##go##\",\n\t\t\t\"##YOOOOOO##\",\n\t\t\t\"This is a joke mimic\",\n\t\t\t\"Go go go\",\n\t\t\t\"Делаем вид что это что-то значит\",\n\t\t\t\"Loading terrain\",\n\t\t\t\"Building terrain\",\n\t\t\t\"Generating more enemies\",\n\t\t\t\"Sending help\",\n\t\t\t\"SOS\",\n\t\t\t\"Are we lost?\",\n\t\t\t\"Spooooky\",\n\t\t\t\"On fire\",\n\t\t\t\"It's magic time\",\n\t\t\t\"Settings things on fire\",\n\t\t\t\"Preparing to explode\",\n\t\t\t\"Installing Linux\",\n\t\t\t\"Deleting System32\",\n\t\t\t\"Erasing data\",\n\t\t\t\"Generating a joke\",\n\t\t\t\"Attacking enemies does more damage, than not attacking\",\n\t\t\t\"Getting hit hurts\",\n\t\t\t\"^^Yeeeeet^^\",\n\t\t\t\"You get a higher chance to hit the enemy, if you aim\",\n\t\t\t\"Money is useful\",\n\t\t\t\"Dying is bad\",\n\t\t\t\"You can change the cursor in settings\",\n\t\t\t\"Fullscreen is dope\",\n\t\t\t\"Hold on...\",\n\t\t\t\"You still here?\",\n\t\t\t\"Does anyone ever read these?\",\n\t\t\t\"Don't get hit by a car\",\n\t\t\t\"##Always cook second##\"\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "BurningKnight/util/LoadScreenTips.cs",
    "content": "﻿using System;\n\nnamespace BurningKnight.util {\n  public static class LoadScreenTips {\n    public static string Generate() {\n      return jokes[new Random().Next(jokes.Length)];\n    }\n\n    private static readonly string[] jokes = {\n      \"[cl yellow]Maanex[cl] holds the secret to looping\",\n      \"[cl red]Redkey[cl] is the key\",\n      \"Crosses on the walls mean something...\",\n      \"Press R for a surprise!\",\n      \"Not all paintings are useless\",\n      \"Aiming at enemies helps to hit them\"\n    };\n  }\n}"
  },
  {
    "path": "BurningKnight/util/Maze.cs",
    "content": "using System;\nusing BurningKnight.level.rooms;\nusing BurningKnight.util.geometry;\nusing Lens.util;\nusing Lens.util.math;\n\nnamespace BurningKnight.util {\n\tpublic class Maze {\n\t\tpublic const bool Empty = false;\n\t\tpublic const bool Filled = true;\n\n\t\tpublic static bool[][] Generate(RoomDef R) {\n\t\t\tvar Maze = new bool[R.GetWidth()][];\n\n\t\t\tfor (var X = 0; X < Maze.Length; X++) {\n\t\t\t\tMaze[X] = new bool[R.GetHeight()];\n\n\t\t\t\tfor (var Y = 0; Y < Maze[0].Length; Y++) {\n\t\t\t\t\tif (X == 0 || X == Maze.Length - 1 || Y == 0 || Y == Maze[0].Length - 1) {\n\t\t\t\t\t\tMaze[X][Y] = Filled;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tforeach (var D in R.Connected.Values) {\n\t\t\t\ttry {\n\t\t\t\t\tMaze[D.X - R.Left][D.Y - R.Top] = Empty;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Generate(Maze);\n\t\t}\n\n\t\tpublic static bool[][] Generate(Rect R) {\n\t\t\treturn Generate(R.GetWidth() + 1, R.GetHeight() + 1);\n\t\t}\n\n\t\tpublic static bool[][] Generate(int Width, int Height) {\n\t\t\tvar array = new bool[Width][];\n\n\t\t\tfor (var X = 0; X < Width; X++) {\n\t\t\t\tarray[X] = new bool[Height];\n\n\t\t\t\tfor (var Y = 0; Y < Height; Y++) {\n\t\t\t\t\tif (X == 0 || X == Width - 1 || Y == 0 || Y == Height - 1) {\n\t\t\t\t\t\tarray[X][Y] = Filled;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Generate(array);\n\t\t}\n\n\t\tpublic static bool[][] Generate(bool[][] Maze) {\n\t\t\tvar Fails = 0;\n\t\t\tint X;\n\t\t\tint Y;\n\t\t\tint Moves;\n\t\t\tint[] Mov;\n\n\t\t\tLog.Debug($\"Generating maze {Maze.Length}x{Maze[0].Length}\");\n\n\t\t\twhile (Fails < 2500) {\n\t\t\t\tdo {\n\t\t\t\t\tX = Rnd.Int(Maze.Length);\n\t\t\t\t\tY = Rnd.Int(Maze[0].Length);\n\t\t\t\t} while (!Maze[X][Y]);\n\n\t\t\t\tMov = DecideDirection(Maze, X, Y);\n\n\t\t\t\tif (Mov == null) {\n\t\t\t\t\tFails++;\n\t\t\t\t} else {\n\t\t\t\t\tFails = 0;\n\t\t\t\t\tMoves = 0;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\tX += Mov[0];\n\t\t\t\t\t\tY += Mov[1];\n\t\t\t\t\t\tMaze[X][Y] = Filled;\n\t\t\t\t\t\tMoves++;\n\t\t\t\t\t} while (Rnd.Int(Moves) == 0 && CheckValidMove(Maze, X, Y, Mov));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Maze;\n\t\t}\n\n\t\tprivate static int[] DecideDirection(bool[][] Maze, int X, int Y) {\n\t\t\tif (Rnd.Int(4) == 0 && CheckValidMove(Maze, X, Y, new[] {0, -1})) {\n\t\t\t\treturn new[] {0, -1};\n\t\t\t}\n\n\t\t\tif (Rnd.Int(3) == 0 && CheckValidMove(Maze, X, Y, new[] {1, 0})) {\n\t\t\t\treturn new[] {1, 0};\n\t\t\t}\n\n\t\t\tif (Rnd.Int(2) == 0 && CheckValidMove(Maze, X, Y, new[] {\n\t\t\t\t0, 1\n\t\t\t})) {\n\t\t\t\treturn new[] {\n\t\t\t\t\t0, 1\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (CheckValidMove(Maze, X, Y, new[] {\n\t\t\t\t-1, 0\n\t\t\t})) {\n\t\t\t\treturn new[] {\n\t\t\t\t\t-1, 0\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate static bool CheckValidMove(bool[][] Maze, int X, int Y, int[] Mov) {\n\t\t\tvar SideX = 1 - Math.Abs(Mov[0]);\n\t\t\tvar SideY = 1 - Math.Abs(Mov[1]);\n\n\t\t\tfor (var I = 0; I < 2; I++) {\n\t\t\t\tX += Mov[0];\n\t\t\t\tY += Mov[1];\n\n\t\t\t\tif (!(X > 0 && X < Maze.Length - 1 && Y > 0 && Y < Maze[0].Length - 1\n\t\t\t\t      && !Maze[X][Y] && !Maze[X + SideX][Y + SideY] && !Maze[X - SideX][Y - SideY])) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/PathFinder.cs",
    "content": "using System;\nusing BurningKnight.level.tile;\nusing BurningKnight.state;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.util {\n\tpublic class PathFinder {\n\t\tpublic static int[] Distance;\n\t\tpublic static int[] Neighbours4;\n\t\tpublic static int[] Neighbours8;\n\t\tpublic static int[] Neighbours9;\n\t\tpublic static int[] Circle4;\n\t\tpublic static int[] Corner;\n\t\tpublic static Vector2[] VCircle4 = new[] {new Vector2(0, -1), new Vector2(1, 0), new Vector2(0, 1), new Vector2(-1, 0)};\n\t\tpublic static Vector2[] VCorner = new[] {new Vector2(1, -1), new Vector2(1, 1), new Vector2(-1, 1), new Vector2(-1, -1)};\n\t\tpublic static int[] Circle8; \n\t\tprivate static bool[] Goals;\n\t\tprivate static int[] Queue;\n\t\tprivate static int Size;\n\t\tprivate static int Width;\n\t\tprivate static int[] Dir;\n\t\tprivate static int[] DirLR;\n\n\t\tpublic static void SetMapSize(int Width, int Height) {\n\t\t\tPathFinder.Width = Width;\n\t\t\tSize = Width * Height;\n\t\t\tDistance = new int[Size];\n\t\t\tGoals = new bool[Size];\n\t\t\tQueue = new int[(int) (Size * 2)];\n\t\t\n\n\t\t\tDir = new[] {-1, +1, -Width, +Width};\n\t\t\tDirLR = new[] {-1, -Width, +Width, +1};\n\t\t\tNeighbours4 = new[] {-Width, -1, +1, +Width};\n\t\t\tNeighbours8 = new[] {-Width - 1, -Width, -Width + 1, -1, +1, +Width - 1, +Width, +Width + 1};\n\t\t\tNeighbours9 = new[] {-Width - 1, -Width, -Width + 1, -1, 0, +1, +Width - 1, +Width, +Width + 1};\n\t\t\tCircle4 = new[] {-Width, +1, +Width, -1};\n\t\t\tCorner = new[] {-Width + 1, +Width + 1, +Width - 1, -1 - Width};\n\t\t\tCircle8 = new[] {-Width - 1, -Width, -Width + 1, +1, +Width + 1, +Width, +Width - 1, -1};\n\t\t}\n\n\t\tpublic static int StepCost(int I) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tpublic static int GetStep(int From, int To, bool[] Passable) {\n\t\t\tif (!BuildDistanceMap(From, To, Passable)) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tvar MinD = Distance[From];\n\t\t\tvar Best = From;\n\t\t\tint Step;\n\t\t\tint StepD;\n\n\t\t\tfor (var I = 0; I < Dir.Length; I++) {\n\t\t\t\tif ((StepD = Distance[Step = From + Dir[I]]) < MinD) {\n\t\t\t\t\tMinD = StepD;\n\t\t\t\t\tBest = Step;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Best;\n\t\t}\n\n\t\tpublic static int GetStepBack(int Cur, int From, bool[] Passable, int Last) {\n\t\t\tvar D = BuildEscapeDistanceMap(Cur, From, 2f, Passable);\n\n\t\t\tif (Last > -1) {\n\t\t\t\tDistance[Last] = Int32.MaxValue;\n\t\t\t}\n\n\t\t\tfor (var I = 0; I < Size; I++) {\n\t\t\t\tGoals[I] = Distance[I] == D;\n\t\t\t}\n\n\t\t\tif (!BuildDistanceMap(Cur, Goals, Passable)) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tvar MinD = Distance[Cur];\n\t\t\tvar Mins = Cur;\n\n\t\t\tfor (var I = 0; I < Dir.Length; I++) {\n\t\t\t\tvar N = Cur + Dir[I];\n\t\t\t\tvar ThisD = Distance[N];\n\n\t\t\t\tif (N != Last && Passable[N] && ThisD < MinD) {\n\t\t\t\t\tMinD = ThisD;\n\t\t\t\t\tMins = N;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Mins;\n\t\t}\n\n\t\tprivate static bool BuildDistanceMap(int From, int To, bool[] Passable) {\n\t\t\tif (From == To) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < Distance.Length; i++) {\n\t\t\t\tDistance[i] = int.MaxValue;\n\t\t\t}\n\n\t\t\tvar PathFound = false;\n\t\t\tvar Head = 0;\n\t\t\tvar Tail = 0;\n\n\t\t\tif (To < 0) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tQueue[Tail++] = To;\n\t\t\tDistance[To] = 0;\n\n\t\t\twhile (Head < Tail) {\n\t\t\t\tvar Step = Queue[Head++];\n\n\t\t\t\tif (Step == From) {\n\t\t\t\t\tPathFound = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar NextDistance = Distance[Step] + 1;\n\t\t\t\tvar Start = Step % Width == 0 ? 3 : 0;\n\t\t\t\tvar End = (Step + 1) % Width == 0 ? 3 : 0;\n\n\t\t\t\tfor (var I = Start; I < DirLR.Length - End; I++) {\n\t\t\t\t\tvar N = Step + DirLR[I];\n\n\t\t\t\t\tif (N == From || N >= 0 && N < Size && Passable[N] &&\n\t\t\t\t\t    Distance[N] > NextDistance) {\n\t\t\t\t\t\tQueue[Tail++] = N;\n\t\t\t\t\t\tDistance[N] = NextDistance + StepCost(N);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn PathFound;\n\t\t}\n\n\t\tprivate static bool BuildDistanceMap(int From, bool[] To, bool[] Passable) {\n\t\t\tif (To[From]) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < Distance.Length; i++) {\n\t\t\t\tDistance[i] = int.MaxValue;\n\t\t\t}\n\n\t\t\tvar PathFound = false;\n\t\t\tvar Head = 0;\n\t\t\tvar Tail = 0;\n\n\t\t\tfor (var I = 0; I < Size; I++) {\n\t\t\t\tif (To[I]) {\n\t\t\t\t\tQueue[Tail++] = I;\n\t\t\t\t\tDistance[I] = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twhile (Head < Tail) {\n\t\t\t\tvar Step = Queue[Head++];\n\n\t\t\t\tif (Step == From) {\n\t\t\t\t\tPathFound = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar NextDistance = Distance[Step] + 1;\n\t\t\t\tvar Start = Step % Width == 0 ? 3 : 0;\n\t\t\t\tvar End = (Step + 1) % Width == 0 ? 3 : 0;\n\n\t\t\t\tfor (var I = Start; I < DirLR.Length - End; I++) {\n\t\t\t\t\tvar N = Step + DirLR[I];\n\n\t\t\t\t\tif (N == From || N >= 0 && N < Size && Passable[N] &&\n\t\t\t\t\t    Distance[N] > NextDistance) {\n\t\t\t\t\t\tQueue[Tail++] = N;\n\t\t\t\t\t\tDistance[N] = NextDistance + StepCost(N);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn PathFound;\n\t\t}\n\n\t\tprivate static int BuildEscapeDistanceMap(int Cur, int From, float Factor, bool[] Passable) {\n\t\t\tfor (var i = 0; i < Distance.Length; i++) {\n\t\t\t\tDistance[i] = int.MaxValue;\n\t\t\t}\n\n\t\t\tvar DestDist = int.MaxValue;\n\n\t\t\tvar Head = 0;\n\t\t\tvar Tail = 0;\n\t\t\tQueue[Tail++] = From;\n\t\t\tDistance[From] = 0;\n\t\t\tvar Dist = 0;\n\n\t\t\twhile (Head < Tail) {\n\t\t\t\tvar Step = Queue[Head++];\n\t\t\t\tDist = Distance[Step];\n\n\t\t\t\tif (Dist > DestDist) {\n\t\t\t\t\treturn DestDist;\n\t\t\t\t}\n\n\t\t\t\tif (Step == Cur) {\n\t\t\t\t\tDestDist = (int) (Dist * Factor) + 1;\n\t\t\t\t}\n\n\t\t\t\tvar NextDistance = Dist + 1;\n\t\t\t\tvar Start = Step % Width == 0 ? 3 : 0;\n\t\t\t\tvar End = (Step + 1) % Width == 0 ? 3 : 0;\n\n\t\t\t\tfor (var I = Start; I < DirLR.Length - End; I++) {\n\t\t\t\t\tvar N = Step + DirLR[I];\n\n\t\t\t\t\tif (N >= 0 && N < Size && Passable[N] && Distance[N] > NextDistance) {\n\t\t\t\t\t\tQueue[Tail++] = N;\n\t\t\t\t\t\tDistance[N] = NextDistance + StepCost(N);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn Dist;\n\t\t}\n\n\t\tpublic static void BuildDistanceMap(int To, bool[] Passable) {\n\t\t\tfor (var i = 0; i < Distance.Length; i++) {\n\t\t\t\tDistance[i] = int.MaxValue;\n\t\t\t}\n\n\t\t\tif (Passable.Length != Distance.Length) {\n\t\t\t\tLog.Error($\"Invalid passable length. Expected {Distance.Length} got {Passable.Length}\");\n\t\t\t}\n\n\t\t\tvar Head = 0;\n\t\t\tvar Tail = 0;\n\t\t\tQueue[Tail++] = To;\n\t\t\tDistance[To] = 0;\n\n\t\t\ttry {\n\t\t\t\twhile (Head < Tail) {\n\t\t\t\t\tvar Step = Queue[Head++];\n\t\t\t\t\tvar NextDistance = Distance[Step] + 1;\n\t\t\t\t\tvar Start = Step % Width == 0 ? 3 : 0;\n\t\t\t\t\tvar End = (Step + 1) % Width == 0 ? 3 : 0;\n\n\t\t\t\t\tfor (var I = Start; I < DirLR.Length - End; I++) {\n\t\t\t\t\t\tvar N = Step + DirLR[I];\n\n\t\t\t\t\t\tif (N >= 0 && N < Size && Passable[N] && Distance[N] > NextDistance) {\n\t\t\t\t\t\t\tQueue[Tail++] = N;\n\t\t\t\t\t\t\tDistance[N] = NextDistance + StepCost(N);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Titles.cs",
    "content": "using System;\nusing Lens.util.math;\n\nnamespace BurningKnight.util {\n\tpublic static class Titles {\n\t\tprivate static Birthday[] birthdays = {\n\t\t\tnew Birthday(29, 6), // Egor\n\t\t\tnew Birthday(25, 9), // Mate\n\t\t\tnew Birthday(21, 2), // Bibiki\n\t\t\tnew Birthday(14, 6), // Viktor\n\t\t\tnew Birthday(10, 6), // Nufflee\n    };\n\t\t\n\t\tpublic static string Generate() {\n\t\t\tvar now = DateTime.Now;\n\t\t\t\n\t\t\tforeach (var b in birthdays) {\n\t\t\t\tif (b.Day == now.Day && b.Month == now.Month) {\n\t\t\t\t\treturn birthdayTitles[Rnd.Int(birthdayTitles.Length)];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Rnd.Chance(0.01f)) {\n\t\t\t\treturn \"You feel lucky\";\n\t\t\t}\n\n\t\t\treturn titles[Rnd.Int(titles.Length)];\n\t\t}\n\n\t\tprivate static string[] titles = {\n\t\t\t\"oh no my game... EXPLODED!!!\",\n\t\t\t\"Fireproof\",\n\t\t\t\"Might burn\",\n\t\t\t\"'Friendly' fire\",\n\t\t\t\"Get ready to burn\",\n\t\t\t\"Do you need some heat?\",\n\t\t\t\"sqrt(-1) love you!\",\n\t\t\t\"Han shot first\",\n\t\t\t\"Sneak 100\",\n\t\t\t\"BBQ is ready!\",\n\t\t\t\"Hot sales!\",\n\t\t\t\"AAAAAA\",\n\t\t\t\"June 5th 2020\",\n\t\t\t\"It burns burns burns\",\n\t\t\t\"Not for children under -1\",\n\t\t\t\"Unhandled fire\",\n\t\t\t\"Chili music\",\n\t\t\t\"Fire trap\",\n\t\t\t\"On-fire\",\n\t\t\t\"Hot potatoo\",\n\t\t\t\"Also try Nuclear Throne\",\n\t\t\t\"undefined\",\n\t\t\t\"If only you could talk to the enemies...\",\n\t\t\t\"It slit. Thank you, good knight\",\n\t\t\t\"Why aren't you in fullscreen?\",\n\t\t\t\"so fire, so good\",\n\t\t\t\"Please don't feed the goblins\",\n\t\t\t\"Burn, baby, burn\",\n\t\t\t\"Only you can prevent the absence of forest fire\",\n\t\t\t\"If at first you don't success, just burn everything\",\n\t\t\t\"Attention: may cause sick burns\",\n\t\t\t\"What doesn't make you stronger kills you\",\n\t\t\t\"Is that a plane? Is that a bird? It is a flying fire!\",\n\t\t\t\"Of course we still love you\",\n\t\t\t\"Just read the instructions\",\n\t\t\t\"Your CPU is close to overheating\",\n\t\t\t\"This is fine\",\n\t\t\t\"Ice cool\",\n\t\t\t\"Overheat alarm was triggered\",\n\t\t\t\"Burn\",\n\t\t\t\"Being a Knight does not guarantee burning\",\n\t\t\t\"Burning does not guarantee becoming a knight\",\n\t\t\t\"The thing of fire\",\n\t\t\t\"Sick burn, knight\",\n\t\t\t\"Wombats are dangerous\",\n\t\t\t\"Stuff happens\",\n\t\t\t\"1000% screen shake\",\n\t\t\t\"Water, fire, air, and... chocolate!\",\n\t\t\t\"What can be cooler than fire?\",\n\t\t\t\"???\",\n\t\t\t\"!!!\",\n\t\t\t\"Ya feel lucky\",\n\t\t\t\"Today is the day\",\n\t\t\t\"Run, gobbo, run!\",\n\t\t\t\"Oszor is watching you\",\n\t\t\t\"Always wear dry socks\",\n\t\t\t\"But can you procedurally generate titles?\",\n\t\t\t\"Now with more Math.random() than ever!\",\n\t\t\t\"Never gets the cold feet\",\n\t\t\t\"If you play with fire...\",\n\t\t\t\"Now with more pathos than ever!\",\n\t\t\t\"Now with less bugs than ever!\",\n\t\t\t\"Now with more code than ever!\",\n\t\t\t\"There is a throne, however it's made of metal and not uranium...\",\n\t\t\t\"Не ожидали?\",\n\t\t\t\"Flameberrry\",\n\t\t\t\"This is a title mimic\",\n\t\t\t\"Lets play\",\n\t\t\t\"Remains functional up to 4000 degrees Kelvin\",\n\t\t\t\"Caution: might contain knights\",\n\t\t\t\"/!\\\\ Do not throw oil at the knight!\",\n\t\t\t\"/!\\\\ /!\\\\ /!\\\\\",\n\t\t\t\"xD\",\n\t\t\t\"All your knights are belong to us\",\n\t\t\t\"It's dangerous to go alone, take this!\",\n\t\t\t\"Note: This game contains flammables\",\n\t\t\t\"We didn't start the fire\",\n\t\t\t\"I'm on fire!\",\n\t\t\t\"The Knight is lava\",\n\t\t\t\"Hello fire, my old friend\",\n\t\t\t\"I'm here to talk with you again\",\n\t\t\t\"Hot n' spicy!\",\n\t\t\t\"This it lit\",\n\t\t\t\"Вообще огонь\",\n\t\t\t\"Roses are red, violets are blue, burning is knight and gobbo is you\",\n\t\t\t\"Roses are red, violets are blue, water boils at 100°C and freezes at 0°C - @DSF100\",\n\t\t\t\"Burn CPU, BURN\",\n\t\t\t\"Please, read the instructions\",\n\t\t\t\"¯\\\\_(ツ)_/¯\",\n\t\t\t\"☉_☉\",\n\t\t\t\"⌐■-■\",\n\t\t\t\"Open fire\",\n\t\t\t\"In case of fire break the monitor\",\n\t\t\t\"In case of fire backup the saves\",\n\t\t\t\"You'd better get burning\",\n\t\t\t\"Why are you reading this?\",\n\t\t\t\"Yes\",\n\t\t\t\"No\",\n\t\t\t\"No U\",\n\t\t\t\"Uno\",\n\t\t\t\"The ducks in the park are free\",\n\t\t\t\"The Trickster\",\n\t\t\t\"Sneak 100\",\n\t\t\t\"Title 100\",\n\t\t\t\"Stonks\",\n\t\t\t\"Confused Stonks\",\n\t\t\t\"Not Stonks\",\n\t\t\t\"Never gonna give you up\",\n\t\t\t\"Oh no\",\n\t\t\t\"Nobody:\",\n\t\t\t\"Do or do not there is no try\",\n\t\t\t\"NaN\",\n\t\t\t\"[object Object]\",\n\t\t\t\"An interesting title\",\n\t\t\t\"I'm once again asking for your emotional support\",\n\t\t\t\"Outstanding move\",\n\t\t\t\"Never gonna let you down\",\n\t\t\t\"You know the rules and so do I\",\n\t\t\t\"F\",\n\t\t\t\"Nobody expects the Spanish Inquisition!\",\n\t\t\tDateTime.Now.ToString()\n\t\t};\n\n\t\tprivate static string[] birthdayTitles = {\n\t\t\t\"Happy burning!\",\n\t\t\t\"It's a good day to die hard\",\n\t\t\t\"Someone is not burning today\",\n\t\t\t\"Burning party\",\n\t\t\t\"Fire hard!\",\n\t\t\t\"Today is a special day\",\n\t\t\t\"I need a cake\",\n\t\t\t\"I hope the presents won't explode\"\n\t\t};\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/Vec2.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace BurningKnight.util {\n\tpublic class Vec2 {\n\t\tpublic Vec2(Vector2 v) {\n\t\t\tX = v.X;\n\t\t\tY = v.Y;\n\t\t}\n\t\t\n\t\tpublic Vec2() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic float X;\n\t\tpublic float Y;\n\t}\n}"
  },
  {
    "path": "BurningKnight/util/geometry/Dot.cs",
    "content": "using Microsoft.Xna.Framework;\r\n\r\nnamespace BurningKnight.util.geometry {\r\n\tpublic class Dot {\r\n\t\tpublic int X;\r\n\t\tpublic int Y;\r\n\t\t\r\n\t\tpublic Dot() {\r\n\t\t\t\r\n\t\t}\r\n\t\t\r\n\t\tpublic Dot(int x, int y) {\r\n\t\t\tX = x;\r\n\t\t\tY = y;\r\n\t\t}\r\n\r\n\t\tpublic Dot(int x) {\r\n\t\t\tX = x;\r\n\t\t\tY = x;\r\n\t\t}\r\n\r\n\t\tpublic Vector2 ToVector() {\r\n\t\t\treturn new Vector2(X, Y);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static implicit operator Vector2(Dot dot) {\r\n\t\t\treturn new Vector2(dot.X, dot.Y);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static Dot operator *(Dot a, int v) {\r\n\t\t\treturn new Dot(a.X * v, a.Y * v);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static Vector2 operator +(Dot a, Vector2 b) {\r\n\t\t\treturn new Vector2(a.X + b.X, a.Y + b.Y);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static Dot operator +(Dot a, Dot b) {\r\n\t\t\treturn new Dot(a.X + b.X, a.Y + b.Y);\r\n\t\t}\r\n\t\t\r\n\t\tpublic static Dot operator -(Dot a, Dot b) {\r\n\t\t\treturn new Dot(a.X - b.X, a.Y - b.Y);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "BurningKnight/util/geometry/Rect.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\n\nnamespace BurningKnight.util.geometry {\n\tpublic class Rect {\n\t\tpublic int Bottom;\n\t\tpublic int Left;\n\t\tpublic int Right;\n\t\tpublic int Top;\n\n\t\tpublic Rect() {\n\t\t\t\n\t\t}\n\n\t\tpublic Rect(Dot vec) {\n\t\t\tSet((int) vec.X, (int) vec.Y, (int) vec.X, (int) vec.Y);\n\t\t}\n\t\t\n\t\tpublic Rect(int x, int y) {\n\t\t\tSet(x, y, x, y);\n\t\t}\n\t\t\n\t\tpublic Rect(int Left, int Top, int Right, int Bottom) {\n\t\t\tSet(Left, Top, Right, Bottom);\n\t\t}\n\n\t\tpublic virtual int GetWidth() {\n\t\t\treturn Right - Left;\n\t\t}\n\t\t\n\t\tpublic virtual int GetHeight() {\n\t\t\treturn Bottom - Top;\n\t\t}\n\n\t\tpublic Rect Set(int Left, int Top, int Right, int Bottom) {\n\t\t\tif (Left > Right) {\n\t\t\t\tvar tmp = Left;\n\t\t\t\tLeft = Right;\n\t\t\t\tRight = tmp;\n\t\t\t}\n\n\t\t\tif (Top > Bottom) {\n\t\t\t\tvar tmp = Top;\n\t\t\t\tTop = Bottom;\n\t\t\t\tBottom = tmp;\n\t\t\t}\n\n\t\t\tthis.Left = Left;\n\t\t\tthis.Top = Top;\n\t\t\tthis.Right = Right;\n\t\t\tthis.Bottom = Bottom;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Rect Setup(int x, int y, int w, int h) {\n\t\t\treturn Set(x, y, x + w, y + h);\n\t\t}\n\t\t\n\t\tpublic Rect Set(Rect Rect) {\n\t\t\treturn Set(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);\n\t\t}\n\n\t\tpublic Rect SetPos(int X, int Y) {\n\t\t\treturn Set(X, Y, X + (Right - Left), Y + (Bottom - Top));\n\t\t}\n\n\t\tpublic Rect Shift(int X, int Y) {\n\t\t\treturn Set(Left + X, Top + Y, Right + X, Bottom + Y);\n\t\t}\n\n\t\tpublic Rect Resize(int W, int H) {\n\t\t\treturn Set(Left, Top, Left + W, Top + H);\n\t\t}\n\n\t\tpublic bool IsEmpty() {\n\t\t\treturn Right <= Left || Bottom <= Top;\n\t\t}\n\n\t\tpublic Rect SetEmpty() {\n\t\t\tLeft = Right = Top = Bottom = 0;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic bool Contains(int x, int y) {\n\t\t\treturn x >= Left && x <= Right && y >= Top && y <= Bottom;\n\t\t}\n\n\t\tpublic bool Intersects(Rect other) {\n\t\t\treturn !(Right < other.Left || Left > other.Right || Bottom < other.Top || Top > other.Bottom);\n\t\t}\n\n\t\tpublic Rect Intersect(Rect Other) {\n\t\t\tvar Result = new Rect();\n\t\t\tResult.Left = Math.Max(Left, Other.Left);\n\t\t\tResult.Right = Math.Min(Right, Other.Right);\n\t\t\tResult.Top = Math.Max(Top, Other.Top);\n\t\t\tResult.Bottom = Math.Min(Bottom, Other.Bottom);\n\n\t\t\treturn Result;\n\t\t}\n\t\t\n\t\tpublic Rect Union(Rect Other) {\n\t\t\tvar Result = new Rect();\n\t\t\tResult.Left = Math.Min(Left, Other.Left);\n\t\t\tResult.Right = Math.Max(Right, Other.Right);\n\t\t\tResult.Top = Math.Min(Top, Other.Top);\n\t\t\tResult.Bottom = Math.Max(Bottom, Other.Bottom);\n\n\t\t\treturn Result;\n\t\t}\n\n\t\tpublic Rect Union(int X, int Y) {\n\t\t\tif (IsEmpty()) {\n\t\t\t\treturn Set(X, Y, X + 1, Y + 1);\n\t\t\t}\n\n\t\t\tif (X < Left)\n\t\t\t\tLeft = X;\n\t\t\telse if (X >= Right) Right = X + 1;\n\n\t\t\tif (Y < Top)\n\t\t\t\tTop = Y;\n\t\t\telse if (Y >= Bottom) Bottom = Y + 1;\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Rect Union(Dot P) {\n\t\t\treturn Union((int) P.X, (int) P.Y);\n\t\t}\n\n\t\tpublic bool Inside(Dot P) {\n\t\t\treturn P.X >= Left && P.X < Right && P.Y >= Top && P.Y < Bottom;\n\t\t}\n\n\t\tpublic Rect Shrink(int D = 1) {\n\t\t\treturn new Rect(Left + D, Top + D, Right - D, Bottom - D);\n\t\t}\n\t\t\n\t\tpublic Rect Shrink(int x, int y) {\n\t\t\treturn new Rect(Left, Top, Right - x, Bottom - y);\n\t\t}\n\n\t\tpublic List<Dot> GetPoints() {\n\t\t\tvar Points = new List<Dot>();\n\n\t\t\tfor (int I = Math.Min(Right, Left); I <= Math.Max(Right, Left); I++) {\n                for (int J = Math.Min(Top, Bottom); J <= Math.Max(Top, Bottom); J++) {\n                    Points.Add(new Dot(I, J));\n                }\n\t\t\t}\n\n\t\t\treturn Points;\n\t\t}\n\t}\n}"
  },
  {
    "path": "CompileNetFrameworkOnLinux.md",
    "content": "# How to compile Net Framework code on Linux\n\nMy setup: Ubuntu 20.4 LTS, mono 6.12.0.122, .NET Core SDK (3.1.408), msbuild 16.6.0, JetBrains Rider as IDE\n\n## Mono\n\nMono can be used instead of NET Framework 4.x, since there's no NET Framework for Linux\n\nInstall mono-devel (you may need to add mono repositories, to do this follow [these instructions](https://www.mono-project.com/download/stable/#download-lin))\n\n```sh\nsudo apt-get install mono-devel\n```\n\nIf your IDE shows tons of errors and/or can't compile the code (but you can compile it in the terminal), you will need:\n\n```sh\nsudo apt-get install mono-dbg\n```\n\nThis is a debugger for mono\n\n## .NET Core SDK 3.1\n\nFollow these [instructions](https://docs.microsoft.com/en-us/dotnet/core/install/linux) to download the .NET Core\n\n## msbuild\n\nTo download msbuild, run:\n\n```sh\nsudo apt-get install msbuild\n```\n\n## nuget\n\nYou don't need nuget to compile the code, it's a package manager for .NET. It can be pretty useful though.\n\n```sh\nsudo apt-get install nuget\n```\n\n## Compiling [Burning Knight](https://github.com/egordorichev/BurningKnight)\n\n```sh\n# clone the repo\ngit clone https://github.com/egordorichev/BurningKnight\ncd BurningKnight\n# install the packages\nnuget restore\n# build the project\nmsbuild\n# run the game\ncd Desktop/bin/Debug/\nmono Desktop.exe\n```\n\n"
  },
  {
    "path": "Desktop/Desktop.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x64</Platform>\n    <ProjectGuid>{68B0E433-3961-4232-9EB1-393AB85FAF7C}</ProjectGuid>\n    <OutputType>WinExe</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Desktop</RootNamespace>\n    <AssemblyName>Desktop</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32bit>false</Prefer32bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32bit>false</Prefer32bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Facepunch.Steamworks.Win64, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\Facepunch.Steamworks.2.3.3\\lib\\net46\\Facepunch.Steamworks.Win64.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"ImGui.NET, Version=1.70.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\ImGui.NET.1.70.0\\lib\\netstandard2.0\\ImGui.NET.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Extensions.DependencyInjection, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">\n      <HintPath>..\\packages\\Microsoft.Extensions.DependencyInjection.1.1.1\\lib\\netstandard1.1\\Microsoft.Extensions.DependencyInjection.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">\n      <HintPath>..\\packages\\Microsoft.Extensions.DependencyInjection.Abstractions.1.1.1\\lib\\netstandard1.0\\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60\">\n      <HintPath>..\\packages\\Microsoft.Extensions.Logging.Abstractions.2.1.1\\lib\\netstandard2.0\\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\Microsoft.Win32.Primitives.4.3.0\\lib\\net46\\Microsoft.Win32.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework, Version=3.8.0.1641, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.DesktopGL.3.8.0.1641\\lib\\net452\\MonoGame.Framework.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"mscorlib\" />\n    <Reference Include=\"netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\" />\n    <Reference Include=\"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed\">\n      <HintPath>..\\packages\\Newtonsoft.Json.12.0.3\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.AppContext.4.3.0\\lib\\net463\\System.AppContext.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Buffers.4.4.0\\lib\\netstandard2.0\\System.Buffers.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Collections, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\System.Collections.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Collections.Immutable.1.3.1\\lib\\portable-net45+win8+wp8+wpa81\\System.Collections.Immutable.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.ComponentModel.Composition\" />\n    <Reference Include=\"System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Console.4.3.0\\lib\\net46\\System.Console.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Diagnostics.DiagnosticSource.4.3.0\\lib\\net46\\System.Diagnostics.DiagnosticSource.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Diagnostics.Tracing.4.3.0\\lib\\net462\\System.Diagnostics.Tracing.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Globalization.Calendars.4.3.0\\lib\\net46\\System.Globalization.Calendars.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Interactive.Async, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263\">\n      <HintPath>..\\packages\\System.Interactive.Async.3.1.1\\lib\\net46\\System.Interactive.Async.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.4.3.0\\lib\\net462\\System.IO.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.4.3.0\\lib\\net46\\System.IO.Compression.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.ZipFile.4.3.0\\lib\\net46\\System.IO.Compression.ZipFile.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.4.3.0\\lib\\net46\\System.IO.FileSystem.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.Primitives.4.3.0\\lib\\net46\\System.IO.FileSystem.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.4.3.0\\lib\\net463\\System.Linq.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.Expressions.4.3.0\\lib\\net463\\System.Linq.Expressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Http.4.3.0\\lib\\net46\\System.Net.Http.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Sockets.4.3.0\\lib\\net46\\System.Net.Sockets.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Numerics\" />\n    <Reference Include=\"System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\System.Numerics.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Numerics.Vectors\" />\n    <Reference Include=\"System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Numerics.Vectors.4.4.0\\lib\\net46\\System.Numerics.Vectors.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Reflection.4.3.0\\lib\\net462\\System.Reflection.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.4.3.0\\lib\\net462\\System.Runtime.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.CompilerServices.Unsafe.4.5.0-preview2-26406-04\\lib\\netstandard2.0\\System.Runtime.CompilerServices.Unsafe.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.Extensions.4.3.0\\lib\\net462\\System.Runtime.Extensions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.InteropServices.4.3.0\\lib\\net463\\System.Runtime.InteropServices.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.InteropServices.RuntimeInformation.4.3.0\\lib\\net45\\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Algorithms.4.3.0\\lib\\net463\\System.Security.Cryptography.Algorithms.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Encoding.4.3.0\\lib\\net46\\System.Security.Cryptography.Encoding.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Primitives.4.3.0\\lib\\net46\\System.Security.Cryptography.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.X509Certificates.4.3.0\\lib\\net461\\System.Security.Cryptography.X509Certificates.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Text.RegularExpressions.4.3.0\\lib\\net463\\System.Text.RegularExpressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Threading, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\System.Threading.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Xml.ReaderWriter.4.3.0\\lib\\net46\\System.Xml.ReaderWriter.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"TwitchLib.Client, Version=3.1.5.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\TwitchLib.Client.3.1.5\\lib\\netstandard2.0\\TwitchLib.Client.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"TwitchLib.Client.Enums, Version=3.1.4.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\TwitchLib.Client.Enums.3.1.4\\lib\\netstandard2.0\\TwitchLib.Client.Enums.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"TwitchLib.Client.Models, Version=3.1.5.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\TwitchLib.Client.Models.3.1.5\\lib\\netstandard2.0\\TwitchLib.Client.Models.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"TwitchLib.Communication, Version=1.0.3.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\TwitchLib.Communication.1.0.3\\lib\\netstandard2.0\\TwitchLib.Communication.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"DesktopApp.cs\" />\n    <Compile Include=\"integration\\crash\\CrashReporter.cs\" />\n    <Compile Include=\"integration\\discord\\DiscordIntegration.cs\" />\n    <Compile Include=\"integration\\discord\\DiscordRpc.cs\" />\n    <Compile Include=\"integration\\Integration.cs\" />\n    <Compile Include=\"integration\\rgb\\RgbIntegration.cs\" />\n    <Compile Include=\"integration\\steam\\SteamIntegration.cs\" />\n    <Compile Include=\"integration\\twitch\\HappeningOption.cs\" />\n    <Compile Include=\"integration\\twitch\\TwitchContoller.cs\" />\n    <Compile Include=\"integration\\twitch\\TwitchIntegration.cs\" />\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Aseprite\\Aseprite.csproj\">\n      <Project>{13c6f252-0b3c-4a22-a9db-270c76657fab}</Project>\n      <Name>Aseprite</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\BurningKnight\\BurningKnight.csproj\">\n      <Project>{d31d0d40-105e-47d5-a5d0-f6e30328bf86}</Project>\n      <Name>BurningKnight</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\Lens\\Lens.csproj\">\n      <Project>{3b26aa2e-0ba2-42dc-ad62-e6c8617f9e4d}</Project>\n      <Name>Lens</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"libs/**\" Link=\"%(Filename)%(Extension)\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\MonoGame.Framework.DesktopGL.3.8.0.1641\\build\\MonoGame.Framework.DesktopGL.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MonoGame.Framework.DesktopGL.3.8.0.1641\\build\\MonoGame.Framework.DesktopGL.targets'))\" />\n  </Target>\n  <Import Project=\"..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets\" Condition=\"Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" />\n  <Import Project=\"..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets\" Condition=\"Exists('..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets')\" />\n  <PropertyGroup>\n    <ApplicationIcon>icon.ico</ApplicationIcon>\n  </PropertyGroup>\n  <ItemGroup>\n    <EmbeddedResource Include=\"icon.bmp\">\n      <LogicalName>Icon.bmp</LogicalName>\n    </EmbeddedResource>\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"CppNet.dll\" />\n    <Content Include=\"integration\\twitch_todo.md\" />\n    <Content Include=\"libmojoshader_64.dll\" />\n    <Content Include=\"mgfxc.deps.json\" />\n    <Content Include=\"mgfxc.dll\" />\n    <Content Include=\"mgfxc.exe\" />\n    <Content Include=\"mgfxc.pdb\" />\n    <Content Include=\"mgfxc.runtimeconfig.dev.json\" />\n    <Content Include=\"mgfxc.runtimeconfig.json\" />\n    <Content Include=\"README.md\" />\n    <Content Include=\"SharpDX.D3DCompiler.dll\" />\n    <Content Include=\"SharpDX.D3DCompiler.xml\" />\n    <Content Include=\"SharpDX.dll\" />\n    <Content Include=\"SharpDX.xml\" />\n    <Content Include=\"steam_api64.dll\" />\n  </ItemGroup>\n  <Import Project=\"..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets\" Condition=\"Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" />\n  <Import Project=\"..\\packages\\MonoGame.Framework.DesktopGL.3.8.0.1641\\build\\MonoGame.Framework.DesktopGL.targets\" Condition=\"Exists('..\\packages\\MonoGame.Framework.DesktopGL.3.8.0.1641\\build\\MonoGame.Framework.DesktopGL.targets')\" />\n  <!--<Target Name=\"Rename\" AfterTargets=\"AfterBuild\">\n    <Move SourceFiles=\"$(OUTDIR)\\Desktop.exe\" DestinationFiles=\"$(OUTDIR)\\BurningKnight.exe\" />\n    <Message Text=\"Renamed executable file.\" Importance=\"high\" />\n  </Target>-->\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n         Other similar extension points exist, see Microsoft.Common.targets.\n    <Target Name=\"BeforeBuild\">\n    </Target>\n    <Target Name=\"AfterBuild\">\n    </Target>\n    -->\n</Project>"
  },
  {
    "path": "Desktop/DesktopApp.cs",
    "content": "﻿using System.Collections.Generic;\nusing BurningKnight;\nusing Desktop.integration;\nusing Desktop.integration.crash;\nusing Desktop.integration.discord;\nusing Desktop.integration.rgb;\nusing Desktop.integration.steam;\nusing Desktop.integration.twitch;\nusing Lens;\nusing Microsoft.Xna.Framework;\n\nnamespace Desktop {\n\tpublic class DesktopApp : BK {\n\t\tprivate const int Scale = 3;\n\t\tpublic static string In = \"20sw479alxyc1\";\n\t\t\n\t\tprivate List<Integration> integrations = new List<Integration>();\n\t\tprivate TwitchIntegration twitchIntegration;\n\t\t\n\t\tpublic DesktopApp() : base(Display.Width * Scale, Display.Height * Scale, !BK.Version.Dev) {\n\t\t\t\n\t\t}\n\n\t\tprotected override void Initialize() {\n\t\t\tbase.Initialize();\n\n\t\t\tintegrations.Add(new DiscordIntegration());\n\t\t\tintegrations.Add(new SteamIntegration());\n\t\t\tintegrations.Add(twitchIntegration = new TwitchIntegration());\n\n\t\t\tforeach (var i in integrations) {\n\t\t\t\ti.Init();\n\t\t\t}\n\t\t\t\n\t\t\tAssetsLoaded += () => {\n\t\t\t\tforeach (var i in integrations) {\n\t\t\t\t\ti.PostInit();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprotected override void Destroy() {\n\t\t\tforeach (var i in integrations) {\n\t\t\t\ti.Destroy();\n\t\t\t}\n\t\t\t\n\t\t\tintegrations.Clear();\n\t\t\t\n\t\t\tbase.Destroy();\n\t\t}\n\n\t\tprotected override void Update(GameTime gameTime) {\n\t\t\tbase.Update(gameTime);\n\t\t\t\n\t\t\tforeach (var i in integrations) {\n\t\t\t\ti.Update(Delta);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void RenderUi() {\n\t\t\tbase.RenderUi();\n\t\t\ttwitchIntegration?.Render();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Desktop/Program.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.IO;\nusing Desktop.integration.crash;\nusing Lens.assets;\nusing Microsoft.Xna.Framework.Audio;\n\nnamespace Desktop {\n\tpublic class Program {\n\t\tprivate static void TryToRemove(string file) {\n\t\t\tif (File.Exists(file)) {\n\t\t\t\ttry {\n\t\t\t\t\tFile.Delete(file);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tConsole.WriteLine(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t[STAThread]\n\t\tpublic static void Main() {\n\t\t\tCrashReporter.Bind();\n\n\t\t\tif (!Environment.Is64BitOperatingSystem) {\n\t\t\t\tConsole.ForegroundColor = ConsoleColor.Red;\n\t\t\t\tConsole.WriteLine(\"Burning Knight can't run on 32 bit OS, sorry :(\");\n\t\t\t\tConsole.ForegroundColor = ConsoleColor.White;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar current = Process.GetCurrentProcess();\n\t\t\tvar processes = Process.GetProcessesByName(current.ProcessName);\n\n\t\t\tConsole.WriteLine($\"Found a total of {processes.Length} processes with name {current.ProcessName}\");\n\n\t\t\tforeach (var process in processes) {\n\t\t\t\tif (process.Id != current.Id) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.CloseMainWindow();\n\t\t\t\t\t\tprocess.Kill();\n\t\t\t\t\t\tConsole.WriteLine(\"Killing older process\");\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tConsole.WriteLine($\"Failed: {e}\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tTryToRemove(\"burning_log.txt\");\n\t\t\tTryToRemove(\"crashes.txt\");\n\n\t\t\ttry {\n\t\t\t\tSoundEffect.Initialize();\n\t\t\t\tConsole.WriteLine(\"SoundEffect.Initialize() went ok\");\n\t\t\t} catch (Exception e) {\n\t\t\t\tAssets.FailedToLoadAudio = true;\n\t\t\t\tAssets.LoadSfx = false;\n\t\t\t\tAssets.LoadMusic = false;\n\t\t\t\t\n\t\t\t\tConsole.WriteLine($\"Failed: {e}\");\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tusing (var game = new DesktopApp()) {\n\t\t\t\t\tgame.Run();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tCrashReporter.Report(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Desktop/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Desktop\")]\n[assembly: AssemblyDescription(\"Happy Burning!\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"BurningKnight\")]\n[assembly: AssemblyCopyright(\"Copyright Rexcellent Games © 2019\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"68B0E433-3961-4232-9EB1-393AB85FAF7C\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]"
  },
  {
    "path": "Desktop/README.md",
    "content": "# Desktop launcher\n\nThis is a tiny wrapper for desktop only features (you see, I planned this out with more platforms in mind).\nNothing too interesting to look at here, perhaps only at the Twitch integration?"
  },
  {
    "path": "Desktop/integration/Integration.cs",
    "content": "﻿namespace Desktop.integration {\n\tpublic class Integration {\n\t\tpublic static string Pus = \"7q57bnzns\";\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PostInit() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\t}\n} \t"
  },
  {
    "path": "Desktop/integration/crash/CrashReporter.cs",
    "content": "using System;\r\nusing System.IO;\r\nusing System.Reflection;\r\nusing System.Text;\r\nusing System.Windows.Forms;\r\nusing Lens;\r\nusing Lens.util;\r\nusing Microsoft.Xna.Framework.Audio;\r\n\r\nnamespace Desktop.integration.crash {\r\n\tpublic class CrashReporter {\r\n\t\tpublic static void Bind() {\r\n\t\t\tAppDomain.CurrentDomain.UnhandledException += ExceptionHandler;\r\n\t\t}\r\n\r\n\t\tprivate static void ExceptionHandler(object sender, UnhandledExceptionEventArgs args) {\r\n\t\t\tvar e = (Exception) args.ExceptionObject;\r\n\t\t\tReport(e);\r\n\t\t}\r\n\r\n\t\tpublic static void Report(Exception e) {\r\n\t\t\tif (e is NoAudioHardwareException) {\r\n\t\t\t\tLog.Error(\"Stupid monogame no audio hardware exception\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tvar builder = new StringBuilder();\r\n\t\t\t\r\n\t\t\tbuilder.AppendLine(\"--- Burning Knight has crashed :( ---\");\r\n\t\t\tbuilder.AppendLine(\"PLEASE REPORT THIS TO REXCELLENT GAMES\");\r\n\t\t\tbuilder.AppendLine(\"via contact@rexcellentgames.com or @egordorichev on twitter\");\r\n\t\t\r\n\t\t\tbuilder.AppendLine(\"--- Info --- \");\r\n\r\n\t\t\tbuilder.AppendLine($\"Date: {DateTime.Now:dd.MM.yyyy h:mm tt}\");\r\n\t\t\tbuilder.AppendLine($\"OS: {Environment.OSVersion} {(Environment.Is64BitOperatingSystem ? 64 : 32 )} bit\");\r\n\r\n\t\t\tbuilder.AppendLine($\"Mono version: {GetMonoVersion()}\");\r\n\t\t\tbuilder.AppendLine($\"Burning Knight version: {Engine.Version}\");\r\n\t\t\t\r\n\t\t\tbuilder.AppendLine(\"--- Error --- \");\r\n\t\t\t\r\n\t\t\tbuilder.AppendLine(e.Message);\r\n\t\t\tbuilder.AppendLine();\r\n\t\t\tbuilder.AppendLine(e.StackTrace);\r\n\r\n\t\t\tbuilder.AppendLine(\"--- Please report a screenshot of this dialog to help us fix the issue! <3 ---\");\r\n\r\n\t\t\tvar message = builder.ToString();\r\n\t\t\tFile.AppendAllText(\"crashes.txt\", message);\r\n\r\n\t\t\tLog.Error(message);\r\n\t\t\tLog.Close();\r\n\t\t\t\r\n\t\t\tMessageBox.Show(message, \"Error\");\r\n\t\t}\r\n\r\n\t\tprivate static string GetMonoVersion() {\r\n\t\t\tvar type = Type.GetType(\"Mono.Runtime\");\r\n\r\n\t\t\tif (type != null) {\r\n\t\t\t\tvar method = type.GetMethod(\"GetDisplayName\", BindingFlags.NonPublic | BindingFlags.Static);\r\n\r\n\t\t\t\tif (method != null) {\r\n\t\t\t\t\treturn (string) method.Invoke(null, null);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn \"Unknown\";\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "Desktop/integration/discord/DiscordIntegration.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.level;\nusing BurningKnight.state;\nusing Lens;\nusing Lens.assets;\nusing Lens.util;\n\nnamespace Desktop.integration.discord {\n\tpublic class DiscordIntegration : Integration {\n\t\tpublic static string CurrentPlayer;\n\t\t\n\t\tprivate float lastUpdate;\n\t\tprivate long startTime;\n\n\t\tpublic bool Broken;\n\n\t\tprivate static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);\n\n\t\tpublic static long CurrentTimeMillis() {\n\t\t\treturn (long) (DateTime.UtcNow - Jan1st1970).TotalMilliseconds;\n\t\t}\n\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tstartTime = CurrentTimeMillis() / 1000;\n\n\t\t\ttry {\n\t\t\t\tDiscordRpc.Initialize(\"459603244256198657\", new DiscordRpc.EventHandlers());\n\t\t\t} catch (Exception e) {\n\t\t\t\tBroken = true;\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tUpdateStatus();\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (Broken) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tlastUpdate += dt;\n\n\t\t\tif (lastUpdate >= 3f) {\n\t\t\t\tlastUpdate = 0;\n\n\t\t\t\ttry {\n\t\t\t\t\tUpdateStatus();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\n\t\t\t\tDiscordRpc.RunCallbacks();\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void UpdateStatus() {\n\t\t\tif (Run.Level?.Biome == null || Broken) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar status = new DiscordRpc.RichPresence();\n\n\t\t\tif (Run.Level != null) {\n\t\t\t\tstatus.details = $\"{Level.GetDepthString(true)}\";\n\t\t\t\tvar p = LocalPlayer.Locate(Engine.Instance.State.Area);\n\n\t\t\t\tif (p != null) {\n\t\t\t\t\tvar h = p.GetComponent<HatComponent>().Item;\n\n\t\t\t\t\tif (h != null && h.Id != \"bk:no_hat\") {\n\t\t\t\t\t\tstatus.state = $\"{Locale.GetEnglish(h.Id)}\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstatus.state = \"No hat :(\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatus.largeImageKey = \"bk\";\n\t\t\tstatus.largeImageText = \"burningknight.net/s\";\n\t\t\tstatus.startTimestamp = startTime;\n\t\t\t\n\t\t\tDiscordRpc.UpdatePresence(status);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\n\t\t\tif (!Broken) {\n\t\t\t\tDiscordRpc.Shutdown();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Desktop/integration/discord/DiscordRpc.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace Desktop.integration.discord {\n\tpublic class DiscordRpc {\n\t\tpublic struct EventHandlers {\n\t\t\tpublic IntPtr ready;\n\t\t\tpublic IntPtr disconnected;\n\t\t\tpublic IntPtr errored;\n\t\t\tpublic IntPtr joinGame;\n\t\t\tpublic IntPtr spectateGame;\n\t\t\tpublic IntPtr joinRequest;\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\tpublic struct RichPresence {\n\t\t\tpublic string state;\n\t\t\tpublic string details;\n\t\t\tpublic Int64 startTimestamp;\n\t\t\tpublic Int64 endTimestamp;\n\t\t\tpublic string largeImageKey;\n\t\t\tpublic string largeImageText;\n\t\t\tpublic string smallImageKey;\n\t\t\tpublic string smallImageText;\n\t\t\tpublic string partyId;\n\t\t\tpublic int partySize;\n\t\t\tpublic int partyMax;\n\t\t\tpublic string matchSecret;\n\t\t\tpublic string joinSecret;\n\t\t\tpublic string spectateSecret;\n\t\t\tpublic sbyte instance;\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\t\t\n\t\tpublic struct DiscordUser {\n\t\t\tpublic string userId;\n\t\t\tpublic string username;\n\t\t\tpublic string discriminator;\n\t\t\tpublic string avatar;\n\t\t}\n\t\t\n\t\tpublic struct JoinRequest {\n\t\t\tpublic string userId;\n\t\t\tpublic string username;\n\t\t\tpublic string avatar;\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\tpublic enum Reply : int {\n\t\t\tNo = 0,\n\t\t\tYes = 1,\n\t\t\tIgnore = 2\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_Initialize([MarshalAs(UnmanagedType.LPStr)] string applicationID,\n\t\t\tref EventHandlers handlers,\n\t\t\tint autoRegister,\n\t\t\t[MarshalAs(UnmanagedType.LPStr)] string optionalSteamId);\n\n\t\tpublic static void Initialize(string appID, EventHandlers handlers) {\n\t\t\tDiscord_Initialize(appID, ref handlers, 1, String.Empty);\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_UpdatePresence(IntPtr presence);\n\n\t\tpublic static void UpdatePresence(RichPresence presence) {\n\t\t\tIntPtr ptrPresence = Marshal.AllocHGlobal(Marshal.SizeOf(presence));\n\t\t\tMarshal.StructureToPtr(presence, ptrPresence, false);\n\t\t\tDiscord_UpdatePresence(ptrPresence);\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_Shutdown();\n\n\t\tpublic static void Shutdown() {\n\t\t\tDiscord_Shutdown();\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_UpdateConnection();\n\n\t\tpublic static void UpdateConnection() {\n\t\t\tDiscord_UpdateConnection();\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_RunCallbacks();\n\n\t\tpublic static void RunCallbacks() {\n\t\t\tDiscord_RunCallbacks();\n\t\t}\n\n\t\t//--------------------------------------------------------------------------------\n\n\t\t[DllImport(\"discord-rpc.dll\")]\n\t\tprivate static extern void Discord_Respond(string userId, int reply);\n\n\t\tpublic static void Respond(string userID, Reply reply) {\n\t\t\tDiscord_Respond(userID, (int) reply);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Desktop/integration/rgb/RgbIntegration.cs",
    "content": "using System;\r\nusing System.IO.Ports;\r\nusing Lens;\r\nusing Lens.graphics;\r\nusing Lens.util;\r\n\r\nnamespace Desktop.integration.rgb {\r\n\tpublic class RgbIntegration : Integration {\r\n\t\tprivate SerialPort port;\r\n\t\t\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\t\t\tport = new SerialPort(\"/dev/ttyUSB0\", 9600);\r\n\t\t\tport.Open();\r\n\t\t\tport.WriteLine(\"ffffff\");\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tvar t = Engine.Time;\r\n\t\t\tvar color = ColorUtils.FromHSV(t * 50 % 360, 100, 100);\r\n\t\t\tvar s = $\"{BitConverter.ToString(new[] {color.R})}{BitConverter.ToString(new[] {color.G})}{BitConverter.ToString(new[] {color.B})}\";\r\n\r\n\t\t\tport.WriteLine(s);\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\t\t\tport.Close();\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "Desktop/integration/steam/SteamIntegration.cs",
    "content": "using System;\r\nusing System.Threading;\r\nusing BurningKnight.assets.achievements;\r\nusing BurningKnight.save;\r\nusing BurningKnight.state;\r\nusing BurningKnight.ui;\r\nusing Lens;\r\nusing Lens.assets;\r\nusing Lens.util;\r\nusing Steamworks;\r\nusing Steamworks.Data;\r\nusing Achievement = Steamworks.Data.Achievement;\r\n\r\nnamespace Desktop.integration.steam {\r\n\tpublic class SteamIntegration : Integration {\r\n\t\tpublic static bool LaunchedFromSteam { get; private set; }\r\n\r\n\t\tpublic override void Init() {\r\n\t\t\tbase.Init();\r\n\r\n\t\t\ttry {\r\n\t\t\t\tSteamClient.Init(851150);\r\n\r\n\t\t\t\tLaunchedFromSteam = true;\r\n\t\t\t\tSaveManager.EnableCloudSave = true;\r\n\t\t\t\t\r\n\t\t\t\tvar lang = SteamApps.GameLanguage.ToLower();\r\n\t\t\t\tvar ui = SteamUtils.SteamUILanguage;\r\n\r\n\t\t\t\tLog.Info($\"Starting from steam! <3 ({lang}, ui: {ui})\");\r\n\r\n\t\t\t\tif (lang == \"english\" && ui != lang) {\r\n\t\t\t\t\tlang = ui;\r\n\t\t\t\t\tLog.Info(\"Preffering ui language over default\");\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\tswitch (lang) {\r\n\t\t\t\t\tcase \"english\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"en\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\t\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase \"russian\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"ru\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase \"german\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"de\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase \"italian\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"it\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase \"polish\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"pl\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\tcase \"french\": {\r\n\t\t\t\t\t\tLocale.PrefferedClientLanguage = \"fr\";\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tRun.SubmitScore += (score, board) => {\r\n\t\t\t\t\tif (Assets.DataModified) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnew Thread(() => {\r\n\t\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t\tLog.Info($\"Submitting score {score} to board {board}\");\r\n\r\n\t\t\t\t\t\t\t\tvar br = SteamUserStats\r\n\t\t\t\t\t\t\t\t\t.FindOrCreateLeaderboardAsync(board, LeaderboardSort.Descending, LeaderboardDisplay.Numeric)\r\n\t\t\t\t\t\t\t\t\t.GetAwaiter().GetResult();\r\n\r\n\t\t\t\t\t\t\t\tbr?.SubmitScoreAsync(score).GetAwaiter().GetResult();\r\n\r\n\t\t\t\t\t\t\t\tLog.Info($\"Done submitting the score {score}\");\r\n\t\t\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}).Start();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tInGameState.SetupLeaderboard += (stats, boardId, type, offset, end) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnew Thread(() => {\r\n\t\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t\tvar i = 0;\r\n\t\t\t\t\t\t\t\tvar count = 0;\r\n\t\t\t\t\t\t\t\tvar name = SteamClient.Name;\r\n\r\n\t\t\t\t\t\t\t\tvar board = SteamUserStats\r\n\t\t\t\t\t\t\t\t\t.FindOrCreateLeaderboardAsync(boardId, LeaderboardSort.Descending, LeaderboardDisplay.Numeric)\r\n\t\t\t\t\t\t\t\t\t.GetAwaiter().GetResult().Value;\r\n\r\n\t\t\t\t\t\t\t\tLeaderboardEntry[] scores;\r\n\r\n\t\t\t\t\t\t\t\tif (type == \"global\") {\r\n\t\t\t\t\t\t\t\t\tscores = board.GetScoresAsync(10, Math.Max(1, offset)).GetAwaiter().GetResult();\r\n\t\t\t\t\t\t\t\t} else if (type == \"friends\") {\r\n\t\t\t\t\t\t\t\t\tscores = board.GetScoresFromFriendsAsync().GetAwaiter().GetResult();\r\n\t\t\t\t\t\t\t\t\ti = Math.Max(0, offset);\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tscores = board.GetScoresAroundUserAsync(-5 + offset, 5 + offset).GetAwaiter().GetResult();\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tif (scores != null) {\r\n\t\t\t\t\t\t\t\t\tfor (; i < scores.Length && count < 10; i++) {\r\n\t\t\t\t\t\t\t\t\t\tvar score = scores[i];\r\n\r\n\t\t\t\t\t\t\t\t\t\tvar n = score.User.Name;\r\n\t\t\t\t\t\t\t\t\t\tn = n.Substring(0, Math.Min(n.Length, 18));\r\n\r\n\t\t\t\t\t\t\t\t\t\tstats.Add($\"#{score.GlobalRank} {n}\", score.Score.ToString(), score.User.Name == name);\r\n\r\n\t\t\t\t\t\t\t\t\t\tcount++;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tstats.Add(Locale.Get(\"no_scores_yet\"), \":(\");\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tend();\r\n\t\t\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}).Start();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tAchievements.PostLoadCallback += () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tforeach (var achievement in Achievements.Defined) {\r\n\t\t\t\t\t\t\tif (achievement.Value.Unlocked) {\r\n\t\t\t\t\t\t\t\tnew Achievement(achievement.Key).Trigger();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\tforeach (var achievement in SteamUserStats.Achievements) {\r\n\t\t\t\t\t\t\tif (achievement.State) {\r\n\t\t\t\t\t\t\t\tAchievements.Unlock(achievement.Identifier);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tAchievements.UnlockedCallback += (id) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnew Achievement(id).Trigger();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tAchievements.LockedCallback += (id) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnew Achievement(id).Clear();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tAchievements.ProgressSetCallback += (id, progress, max) => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tSteamUserStats.IndicateAchievementProgress(id, progress, max);\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\tInGameState.SyncAchievements += () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tforeach (var achievement in Achievements.Defined) {\r\n\t\t\t\t\t\t\tif (achievement.Value.Unlocked) {\r\n\t\t\t\t\t\t\t\tnew Achievement(achievement.Key).Trigger();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tforeach (var achievement in SteamUserStats.Achievements) {\r\n\t\t\t\t\t\t\tif (achievement.State) {\r\n\t\t\t\t\t\t\t\tAchievements.Unlock(achievement.Identifier);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\ttry {\r\n\t\t\t\t\tSaveManager.LoadCloudSaves();\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tSteamFriends.OnGameOverlayActivated += (a) => {\r\n\t\t\t\t\tEngine.Instance.State.Paused = true;\r\n\t\t\t\t};\r\n\t\t\t\t\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tLog.Info(\"No steam no fire :/\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Update(float dt) {\r\n\t\t\tbase.Update(dt);\r\n\r\n\t\t\tif (LaunchedFromSteam) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tSteamClient.RunCallbacks();\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic override void Destroy() {\r\n\t\t\tbase.Destroy();\r\n\r\n\t\t\tif (LaunchedFromSteam) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tSaveManager.SaveCloudSaves();\r\n\t\t\t\t\tSteamClient.Shutdown();\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tLog.Error(e);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tLaunchedFromSteam = false;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "Desktop/integration/twitch/HappeningOption.cs",
    "content": "using BurningKnight.assets;\nusing BurningKnight.entity.twitch.happening;\nusing Lens.assets;\nusing Lens.entity;\nusing Lens.graphics;\nusing Microsoft.Xna.Framework;\n\nnamespace Desktop.integration.twitch {\n\tpublic class HappeningOption {\n\t\tpublic Vector2 Position;\n\n\t\tpublic int Num;\n\t\tpublic string Id;\n\t\tpublic string Label;\n\t\tpublic string Name;\n\t\tpublic float LabelWidth;\n\t\tpublic int Votes;\n\t\tpublic int Percent;\n\t\tpublic Happening Happening;\n\n\t\tpublic HappeningOption(string id, int i) {\n\t\t\tHappening = HappeningRegistry.Get(id);\n\t\t\tId = id;\n\n\t\t\tvar name = Locale.Get($\"happening_{id}\");\n\n\t\t\tNum = i;\n\t\t\tName = name.ToLower();\n\t\t\tLabel = $\"#{i} {name}\";\n\t\t\tLabelWidth = Font.Small.MeasureString($\"{Label} (100%)\").Width;\n\t\t}\n\n\t\tpublic void Render() {\n\t\t\tGraphics.Print($\"{Label} ({Percent}%)\", Font.Small, Position);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Desktop/integration/twitch/TwitchContoller.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight.assets;\nusing BurningKnight.assets.particle.custom;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.twitch.happening;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing Lens;\nusing Lens.assets;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.math;\nusing Lens.util.timer;\nusing Microsoft.Xna.Framework;\nusing TwitchLib.Client.Models;\n\nnamespace Desktop.integration.twitch {\n\tpublic class TwitchContoller {\n\t\tprivate const int TotalTime = 45;\n\t\t\n\t\tprivate List<HappeningOption> options = new List<HappeningOption>();\n\t\tprivate List<string> votersCache = new List<string>();\n\t\tprivate float timeLeft = 1f;\n\t\tprivate Player player;\n\t\tprivate string question;\n\t\tprivate string totalVotes;\n\t\tprivate HappeningOption happeningRn;\n\t\tprivate float voteDelay;\n\t\tprivate float toHappen;\n\t\t\n\t\tpublic void Init() {\n\t\t\tGenerateOptions();\n\t\t}\n\n\t\tprivate void GenerateOptions() {\n\t\t\tquestion = Locale.Get(\"twitch_next\");\n\t\t\ttotalVotes = Locale.Get(\"total_votes\");\n\t\t\t\n\t\t\tvotersCache.Clear();\n\t\t\toptions.Clear();\n\t\t\ttimeLeft = 1f;\n\n\t\t\tvar pool = new List<string>();\n\n\t\t\tforeach (var h in HappeningRegistry.Defined) {\n\t\t\t\tpool.Add(h.Key);\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < 3; i++) {\n\t\t\t\tvar j = Rnd.Int(pool.Count);\n\t\t\t\tvar happening = pool[j];\n\t\t\t\tpool.RemoveAt(j);\n\t\t\t\t\n\t\t\t\tAddOption(happening, 3 - i);\n\t\t\t}\n\t\t}\n\n\t\tprivate void AddOption(string id, int i) {\n\t\t\tvar happening = HappeningRegistry.Get(id);\n\n\t\t\tif (happening == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar option = new HappeningOption(id, i);\n\t\t\toptions.Add(option);\n\n\t\t\tfloat x = Display.UiWidth;\n\n\t\t\tforeach (var o in options) {\n\t\t\t\tx -= o.LabelWidth + 8;\n\t\t\t}\n\n\t\t\toption.Position = new Vector2(x, 18);\n\t\t}\n\n\t\tpublic void Update(float dt) {\n\t\t\tvar state = Engine.Instance.State;\n\n\t\t\tif (!(state is InGameState ig) || state.Paused) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (ig.Died) {\n\t\t\t\thappeningRn = null;\n\n\t\t\t\tif (timeLeft < 1f) {\n\t\t\t\t\ttimeLeft = 1f;\n\t\t\t\t\tGenerateOptions();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (busy) {\n\t\t\t\ttoHappen -= dt;\n\n\t\t\t\tif (toHappen <= 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tLog.Debug($\"Happening {happeningRn.Id} {happeningRn.Happening.GetType().Name}\");\n\t\t\t\t\t\thappeningRn.Happening.Happen(player);\n\t\t\t\t\t\tLog.Debug(\"Done\");\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tbusy = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else if (happeningRn != null) {\n\t\t\t\tvoteDelay -= dt;\n\t\t\t\thappeningRn.Happening.Update(dt);\n\t\t\t\t\n\t\t\t\tif (voteDelay <= 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\thappeningRn.Happening.End(last);\n\t\t\t\t\t\tlast = null;\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvoteDelay = 0;\n\t\t\t\t\thappeningRn = null;\n\t\t\t\t\tGenerateOptions();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttimeLeft -= dt / TotalTime;\n\n\t\t\t\tif (timeLeft <= 0) {\n\t\t\t\t\tExecuteOrder66();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Render() {\n\t\t\tif (!(Engine.Instance.State is InGameState ig) || ig.Died) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (happeningRn != null || busy) {\n\t\t\t\tif (happeningRn != null) {\n\t\t\t\t\tvar tt = $\"{lastName} ({(int) Math.Ceiling(voteDelay)}s)\";\n\t\t\t\t\tGraphics.Print(tt, Font.Small, new Vector2(Display.UiWidth - Font.Small.MeasureString(tt).Width - 8, 8));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar text = $\"{question}{(busy ? \"\" : $\" ({(int) Math.Ceiling(timeLeft * TotalTime)}s)\")}\";\n\n\t\t\tGraphics.Color.A = 200;\n\t\t\tGraphics.Print(text, Font.Small, new Vector2(Display.UiWidth - Font.Small.MeasureString(text).Width - 8, 8));\n\t\t\tGraphics.Color.A = 255;\n\t\t\t\n\t\t\tforeach (var option in options) {\n\t\t\t\toption.Render();\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Color.A = 170;\n\t\t\tvar t = $\"{votersCache.Count} {totalVotes}\";\n\t\t\tGraphics.Print(t, Font.Small, new Vector2(Display.UiWidth - Font.Small.MeasureString(t).Width - 8, 28));\n\t\t\tGraphics.Color.A = 255;\n\t\t}\n\t\t\n\t\tprivate void BalanceVotes() {\n\t\t\tfloat total = votersCache.Count;\n\n\t\t\tforeach (var o in options) {\n\t\t\t\to.Percent = (int) Math.Floor(o.Votes / total * 100);\n\t\t\t}\n\t\t}\n\n\t\tpublic bool HandleMessage(ChatMessage chatMessage) {\n\t\t\tif (happeningRn != null || busy) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tvar message = chatMessage.Message;\n\n\t\t\tif (!votersCache.Contains(chatMessage.Username)) {\n\t\t\t\tvar m = message.ToLower();\n\n\t\t\t\tforeach (var o in options) {\n\t\t\t\t\tif (o.Name == m) {\n\t\t\t\t\t\tvotersCache.Add(chatMessage.Username);\n\t\t\t\t\t\to.Votes++;\n\n\t\t\t\t\t\tBalanceVotes();\n\t\t\t\t\t\tLog.Info($\"Voted for {m}\");\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (message.StartsWith(\"#\")) {\n\t\t\t\tmessage = message.Substring(1, message.Length - 1);\n\t\t\t}\n\t\t\t\n\t\t\tif (int.TryParse(message, out var number)) {\n\t\t\t\tif (number < 1 || number > options.Count || (chatMessage.Username != TwitchIntegration.DevAccount && votersCache.Contains(chatMessage.Username))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvotersCache.Add(chatMessage.Username);\n\t\t\t\toptions[(options.Count - number)].Votes++;\n\n\t\t\t\tBalanceVotes();\n\t\t\t\t\n\t\t\t\tLog.Info($\"Voted for #{number}\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate Player last;\n\t\tprivate bool busy;\n\t\tprivate string lastName;\n\t\t\n\t\tprivate void ExecuteOrder66() {\n\t\t\tplayer = LocalPlayer.Locate(Engine.Instance.State.Area);\n\t\t\t\t\n\t\t\tif (player == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tbusy = true;\n\t\t\tvar options = new List<HappeningOption>();\n\t\t\t\n\t\t\tHappeningOption opt = null;\n\t\t\tvar mostVotes = 0;\n\n\t\t\tforeach (var h in this.options) {\n\t\t\t\tif (opt == null || h.Votes > mostVotes) {\n\t\t\t\t\topt = h;\n\t\t\t\t\tmostVotes = h.Votes;\n\t\t\t\t\toptions.Clear();\n\t\t\t\t\toptions.Add(h);\n\t\t\t\t} else if (h.Votes == mostVotes) {\n\t\t\t\t\toptions.Add(h);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.Count > 1) {\n\t\t\t\tLog.Info($\"Picking from the same vote candidates of size {options.Count}\");\n\t\t\t\topt = options[Rnd.Int(options.Count)];\n\t\t\t}\n\n\t\t\tif (opt == null) {\n\t\t\t\tLog.Error(\"The jedi have escaped\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar name = Locale.Get($\"happening_{opt.Id}\");\n\t\t\tlastName = name;\n\t\t\tLog.Debug($\"Option #{opt.Num} ({name}) has won!\");\n\t\t\t\n\t\t\t\n\t\t\tplayer.GetComponent<DialogComponent>().StartAndClose($\"[cl purple]{name}[cl]\", 3);\n\t\t\t\n\t\t\tlast = player;\n\t\t\thappeningRn = opt;\n\t\t\tvoteDelay = opt.Happening.GetVoteDelay();\n\n\t\t\ttoHappen = 4f;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Desktop/integration/twitch/TwitchIntegration.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing BurningKnight;\nusing BurningKnight.assets;\nusing BurningKnight.entity.component;\nusing BurningKnight.entity.creature.player;\nusing BurningKnight.entity.twitch;\nusing BurningKnight.save;\nusing BurningKnight.state;\nusing BurningKnight.ui.dialog;\nusing BurningKnight.util;\nusing Lens;\nusing Lens.assets;\nusing Lens.util;\nusing Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing TwitchLib.Client;\nusing TwitchLib.Client.Events;\nusing TwitchLib.Client.Models;\nusing TwitchLib.Communication.Clients;\nusing TwitchLib.Communication.Models;\n\nnamespace Desktop.integration.twitch {\n\tpublic class TwitchIntegration : Integration {\n\t\tpublic const string DevAccount = \"egordorichev\";\n\t\tprivate static string Boots = \"rwzxul2y\";\n\t\t\n\t\tprivate TwitchClient client;\n\t\tprivate TwitchContoller controller;\n\t\tprivate bool enableDevMessages = true;\n\t\tprivate bool spawnAllPets;\n\t\t\n\t\tpublic override void Init() {\n\t\t\tbase.Init();\n\n\t\t\tTwitchBridge.TurnOn = (channel, callback) => {\n\t\t\t\tif (TwitchBridge.On) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tTwitchBridge.On = true;\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tvar credentials = new ConnectionCredentials(\"BurningKnightBot\", $\"{Pus}{DesktopApp.In}{Boots}\");\n\t\t\t\t\tvar customClient = new WebSocketClient(new ClientOptions {\n\t\t\t\t\t\tMessagesAllowedInPeriod = 750,\n\t\t\t\t\t\tThrottlingPeriod = TimeSpan.FromSeconds(30)\n\t\t\t\t\t});\n\t\t\t\t\n\t\t\t\t\tclient = new TwitchClient(customClient);\n\t\t\t\t\tclient.Initialize(credentials, channel);\n\n\t\t\t\t\tclient.OnConnected += (o, e) => {\n\t\t\t\t\t\tTwitchBridge.LastUsername = channel;\n\n\t\t\t\t\t\tLog.Info($\"Connected to {e.AutoJoinChannel}\");\n\t\t\t\t\t\tcallback(true);\n\t\t\t\t\t\tclient.SendMessage(channel, \"The Knight is here, bois\");\n\t\t\t\t\n\t\t\t\t\t\tcontroller = new TwitchContoller();\n\t\t\t\t\t\tcontroller.Init();\n\n\t\t\t\t\t\tTwitchBridge.On = true;\n\t\t\t\t\t};\n\n\t\t\t\t\tclient.OnError += (sender, args) => {\n\t\t\t\t\t\tLog.Error(args.Exception.Message);\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tclient.OnConnectionError += (o, e) => {\n\t\t\t\t\t\tcallback(false);\n\t\t\t\t\t};\n\n\t\t\t\t\tclient.OnNewSubscriber += (o, e) => {\n\t\t\t\t\t\tOnSub(e.Subscriber.DisplayName, e.Subscriber.ColorHex);\n\t\t\t\t\t};\n\n\t\t\t\t\tclient.OnReSubscriber += (o, e) => {\n\t\t\t\t\t\tOnSub(e.ReSubscriber.DisplayName, e.ReSubscriber.ColorHex);\n\t\t\t\t\t};\n\n\t\t\t\t\tclient.OnGiftedSubscription += (o, e) => {\n\t\t\t\t\t\tOnSub(e.GiftedSubscription.DisplayName, \"#ff00ff\");\n\t\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\t\tclient.OnMessageReceived += OnMessageReceived;\n\t\t\t\t\tclient.Connect();\n\n\t\t\t\t\tTwitchBridge.On = true;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tTwitchBridge.On = false;\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tTwitchBridge.TurnOff = (callback) => {\n\t\t\t\tLog.Info(\"Turning twitch integration off\");\n\t\t\t\t\n\t\t\t\tcontroller = null;\n\t\t\t\tclient.Disconnect();\n\t\t\t\tclient = null;\n\n\t\t\t\tTwitchBridge.On = false;\n\t\t\t\tcallback();\n\t\t\t};\n\n\t\t\tTwitchBridge.OnHubEnter += () => {\n\t\t\t\tspawnAllPets = true;\n\t\t\t};\n\n\t\t\tTwitchBridge.OnNewRun += () => {\n\t\t\t\tif (Run.Type == RunType.Twitch) {\n\t\t\t\t\tspawnAllPets = true;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tpublic override void PostInit() {\n\t\t\tbase.PostInit();\n\t\t\tvar id = GlobalSave.GetString(\"twitch_username\");\n\n\t\t\tif (id == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTwitchBridge.TurnOn(id, (ok) => {\n\t\t\t\t\t\n\t\t\t});\n\t\t}\n\n\t\tprivate class Data {\n\t\t\tpublic string Nick;\n\t\t\tpublic string Color;\n\t\t}\n\t\t\n\t\tprivate List<Data> buffer = new List<Data>();\n\t\tprivate List<Data> totalBuffer = new List<Data>();\n\t\tprivate List<string> messageIds = new List<string>();\n\n\t\tprivate void OnSub(string who, string color) {\n\t\t\ttry {\n\t\t\t\t// Just to be safe from threading tbh\n\t\t\t\tfor (var i = 0; i < buffer.Count; i++) {\n\t\t\t\t\tif (buffer[i].Nick == who) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < totalBuffer.Count; i++) {\n\t\t\t\t\tif (totalBuffer[i].Nick == who) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tLog.Info($\"{who} subscribed!\");\n\t\t\t\tAudio.PlaySfx(\"level_cleared\");\n\n\t\t\t\tbuffer.Add(new Data {\n\t\t\t\t\tNick = who,\n\t\t\t\t\tColor = color\n\t\t\t\t});\n\n\t\t\t\ttotalBuffer.Add(new Data {\n\t\t\t\t\tNick = who,\n\t\t\t\t\tColor = color\n\t\t\t\t});\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tprivate void OnMessageReceived(object sender, OnMessageReceivedArgs e) {\n\t\t\tvar dev = e.ChatMessage.Username == DevAccount;\n\n\t\t\tif (!dev && (Run.Depth < 1 || Run.Type != RunType.Twitch)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (messageIds.Contains(e.ChatMessage.Id)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmessageIds.Add(e.ChatMessage.Id);\n\t\t\t\n\t\t\ttry {\n\t\t\t\tvar state = Engine.Instance.State;\n\n\t\t\t\tif (!(state is InGameState gamestate)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar message = e.ChatMessage.Message;\n\t\t\t\tLog.Debug(message);\n\n\t\t\t\tif (dev) {\n\t\t\t\t\tif (message.StartsWith(\"sudo \")) {\n\t\t\t\t\t\tvar command = message.Substring(5, message.Length - 5);\n\n\t\t\t\t\t\tswitch (command) {\n\t\t\t\t\t\t\tcase \"msg\": {\n\t\t\t\t\t\t\t\tenableDevMessages = !enableDevMessages;\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcase \"sub\": {\n\t\t\t\t\t\t\t\tOnSub(\"egordorichev\", e.ChatMessage.ColorHex);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tLog.Debug(command);\n\t\t\t\t\t\tgamestate.Console.RunCommand(command);\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (message.StartsWith(\"!\")) {\n\t\t\t\t\tvar m = message.Substring(1, message.Length - 1);\n\t\t\t\t\tvar n = e.ChatMessage.DisplayName;\n\n\t\t\t\t\tif (m.StartsWith(\"color \")) {\n\t\t\t\t\t\tvar pet = state.Area.Find<TwitchPet>(f => f is TwitchPet p && p.Nick == n);\n\n\t\t\t\t\t\tif (pet != null) {\n\t\t\t\t\t\t\tvar cl = m.Substring(6, m.Length - 6);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tpet.Color = cl;\n\t\t\t\t\t\t\tpet.UpdateColor();\n\t\t\t\t\t\t\tpet.GetComponent<AnimationComponent>().Animate();\n\n\t\t\t\t\t\t\tforeach (var p in totalBuffer) {\n\t\t\t\t\t\t\t\tif (p.Nick == pet.Nick) {\n\t\t\t\t\t\t\t\t\tp.Color = cl;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else if (m == \"wink\") {\n\t\t\t\t\t\tvar pet = state.Area.Find<TwitchPet>(f => f is TwitchPet p && p.Nick == n);\n\t\t\t\t\t\tpet.GetComponent<AnimationComponent>().Animate();\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (controller != null && !controller.HandleMessage(e.ChatMessage) && dev) {\n\t\t\t\t\tif (enableDevMessages) {\n\t\t\t\t\t\tvar a = state.Area.Tagged[Tags.BurningKnight];\n\n\t\t\t\t\t\tif (a.Count > 0) {\n\t\t\t\t\t\t\tvar bk = a[0];\n\t\t\t\t\t\t\tbk.GetComponent<DialogComponent>().StartAndClose(message, 5);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception ex) {\n\t\t\t\tLog.Error(ex);\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\ttry {\n\t\t\t\tclient?.Disconnect();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t\t\n\t\t\tbase.Destroy();\n\t\t}\n\n\t\tprivate float t;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tt += dt;\n\n\t\t\tif (t >= 10f) {\n\t\t\t\tt = 0;\n\t\t\t\tmessageIds.Clear();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tif (controller != null && Run.Type == RunType.Twitch && Run.Depth > 0) {\n\t\t\t\t\tcontroller.Update(dt);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!(Engine.Instance.State is InGameState ingame)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (spawnAllPets && (Run.Type == RunType.Twitch || Run.Depth == 0)) {\n\t\t\t\t\tSpawnPets(totalBuffer);\n\t\t\t\t\tspawnAllPets = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (buffer.Count > 0) {\n\t\t\t\t\tSpawnPets(buffer);\n\t\t\t\t\tbuffer.Clear();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate void SpawnPets(List<Data> pets) {\n\t\t\tvar ingame = (InGameState) Engine.Instance.State;\n\t\t\tvar player = LocalPlayer.Locate(ingame.Area);\n\t\t\t\t\n\t\t\tfor (var i = 0; i < pets.Count; i++) {\n\t\t\t\tvar d = pets[i];\n\t\t\t\t\n\t\t\t\tvar p = new TwitchPet {\n\t\t\t\t\tNick = d.Nick,\n\t\t\t\t\tColor = d.Color\n\t\t\t\t};\n\t\t\t\t\t\n\t\t\t\tingame.Area.Add(p);\n\t\t\t\t\t\n\t\t\t\tp.Center = player.Center + Rnd.Offset(24);\n\t\t\t\tAnimationUtil.Poof(p.Center, player.Depth + 1);\n\t\t\t\t\n\t\t\t\tAnimationUtil.Confetti(p.Center);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Render() {\n\t\t\tif (Run.Depth < 1 || Run.Type != RunType.Twitch) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcontroller?.Render();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Desktop/integration/twitch_todo.md",
    "content": "* show what you ended up voting for, delay before next vote\n\n* voting: {\n * what item appear in the shop\n * what item appears in treasure room\n * what item drops from the boss\n}\n\n* Random dude selected as a companion per run\n* Chat reactions on death\n* New subs/followers celebration"
  },
  {
    "path": "Desktop/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Facepunch.Steamworks\" version=\"2.3.3\" targetFramework=\"net472\" />\n  <package id=\"ImGui.NET\" version=\"1.70.0\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.Extensions.DependencyInjection\" version=\"1.1.1\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.Extensions.DependencyInjection.Abstractions\" version=\"1.1.1\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.Extensions.Logging.Abstractions\" version=\"2.1.1\" targetFramework=\"net472\" />\n  <package id=\"Microsoft.NETCore.Platforms\" version=\"1.1.0\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.Win32.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Extended\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.DesktopGL\" version=\"3.8.0.1641\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.DesktopGL.Core\" version=\"3.8.0.13\" targetFramework=\"net472\" />\n  <package id=\"NETStandard.Library\" version=\"2.0.0\" targetFramework=\"net471\" />\n  <package id=\"Newtonsoft.Json\" version=\"12.0.3\" targetFramework=\"net472\" />\n  <package id=\"System.AppContext\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Buffers\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections.Concurrent\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections.Immutable\" version=\"1.3.1\" targetFramework=\"net471\" />\n  <package id=\"System.ComponentModel\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Console\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Debug\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.DiagnosticSource\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Tools\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Tracing\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Globalization\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Globalization.Calendars\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Interactive.Async\" version=\"3.1.1\" targetFramework=\"net471\" />\n  <package id=\"System.IO\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.Compression\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.Compression.ZipFile\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.FileSystem\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.FileSystem.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Linq\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Linq.Expressions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Net.Http\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Net.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Net.Sockets\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Numerics.Vectors\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.ObjectModel\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Resources.ResourceManager\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.CompilerServices.Unsafe\" version=\"4.5.0-preview2-26406-04\" targetFramework=\"net472\" />\n  <package id=\"System.Runtime.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.Handles\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.InteropServices\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.InteropServices.RuntimeInformation\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.Numerics\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Algorithms\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Encoding\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.X509Certificates\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.Encoding\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.Encoding.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.RegularExpressions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading.Tasks\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading.Timer\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Xml.ReaderWriter\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Xml.XDocument\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"TwitchLib.Client\" version=\"3.1.5\" targetFramework=\"net472\" />\n  <package id=\"TwitchLib.Client.Enums\" version=\"3.1.4\" targetFramework=\"net472\" />\n  <package id=\"TwitchLib.Client.Models\" version=\"3.1.5\" targetFramework=\"net472\" />\n  <package id=\"TwitchLib.Communication\" version=\"1.0.3\" targetFramework=\"net472\" />\n</packages>"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Georgiy Dorichev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Lens/Cloner.cs",
    "content": "using System.IO;\r\nusing System.Runtime.Serialization.Formatters.Binary;\r\n\r\nnamespace Lens {\r\n\tpublic class Cloner {\r\n\t\tpublic static T DeepClone<T>(T obj)\r\n\t\t{\r\n\t\t\tusing (var ms = new MemoryStream())\r\n\t\t\t{\r\n\t\t\t\tvar formatter = new BinaryFormatter();\r\n\t\t\t\tformatter.Serialize(ms, obj);\r\n\t\t\t\tms.Position = 0;\r\n\r\n\t\t\t\treturn (T) formatter.Deserialize(ms);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "Lens/Display.cs",
    "content": "﻿namespace Lens {\n\tpublic class Display {\n\t\tpublic static int Width = 320;\n\t\tpublic static int Height = 180;\n\t\tpublic static float Viewport = (float) Width / Height;\n\t\tpublic static float InvertedViewport = (float) Height / Width;\n\t\tpublic const float UiScale = 1.5f;\n\t\tpublic static int UiWidth = (int) (Width * UiScale);\n\t\tpublic static int UiHeight = (int) (Height * UiScale);\n\t}\n}"
  },
  {
    "path": "Lens/Engine.cs",
    "content": "﻿using System;\nusing Lens.assets;\nusing Lens.game;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Lens.input;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.timer;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing Microsoft.Xna.Framework.Input;\nusing System.Runtime.InteropServices;\n\nnamespace Lens {\n\tpublic class Engine : Game {\n#if DEBUG\n\t\tpublic const bool Debug = true;\n#else\n\t\tpublic const bool Debug = false;\n#endif\n\n\t\tpublic static Action AssetsLoaded;\n\t\t\n\t\tpublic static bool PixelPerfect;\n\t\tpublic static bool EditingLevel;\n\t\tpublic static Version Version;\n\t\tpublic static Engine Instance;\n\t\tpublic static GraphicsDeviceManager Graphics;\n\t\tpublic new static GraphicsDevice GraphicsDevice;\n\t\tpublic static Matrix ScreenMatrix;\n\t\tpublic static Matrix UiMatrix;\n\t\tpublic static float Time;\n\t\tpublic static float Delta;\n\t\tpublic static GameTime GameTime;\n\t\tpublic static bool Quiting;\n\t\tpublic static int UpdateTime;\n\t\tpublic static int RenderTime;\n\t\tpublic static bool Flashes = true;\n\t\t\n\t\tpublic FrameCounter Counter;\n\t\tpublic GameRenderer StateRenderer;\n\t\tpublic GameState State { get; private set; }\n\t\tpublic static Vector2 Viewport;\n\t\tpublic float Upscale;\n\t\tpublic float UiUpscale;\n\n\t\tprivate static Core.Core core;\n\t\tprivate const float FixedUpdateTime = 0.015f;\n\t\tprivate float time;\n\t\tpublic float Speed = 1;\n\t\tpublic float Flash;\n\t\tpublic float Freeze;\n\t\tpublic static float FlashModifier = 1;\n\t\tpublic static float FreezeModifier = 1;\n\t\t\n\t\tpublic bool Focused;\n\t\tpublic Color FlashColor = ColorUtils.WhiteColor;\n\t\tpublic float Split;\n\t\t// Window.Title works only in Init, sadly\n\t\tprivate string tmpTitle;\n\t\tprivate GameState newState;\n\t\t\n\t\tpublic string Title {\n\t\t\tget => Window.Title;\n\t\t\tset {\n\t\t\t\tif (value != null && !RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tWindow.Title = value;\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic Engine(Version version, GameState state, string title, int width, int height, bool fullscreen) {\n\t\t\tInstance = this;\n\t\t\ttmpTitle = title;\n\t\t\tVersion = version;\n\t\t\tIsFixedTimeStep = false;\n\t\t\t\n\t\t\tGraphics = new GraphicsDeviceManager(this);\n\t\t\t// Graphics.GraphicsProfile = GraphicsProfile.HiDef;\n\t\t\t\n\t\t\tGraphics.PreferMultiSampling = false;\n\t\t\tGraphics.GraphicsProfile = GraphicsProfile.Reach;\n\t\t\t\n\t\t\tGraphics.HardwareModeSwitch = false;\n\n\t\t\tcore = Core.Core.SelectCore(Window, Graphics);\n\t\t\tcore.Init(width, height, fullscreen);\n\n\t\t\tContent.RootDirectory = \"Content/\";\n\t\t\tAssets.Content = Content;\n\t\t\tnewState = state;\n\t\t\tCounter = new FrameCounter();\n\t\t}\n\n\t\tprotected override void OnActivated(object sender, EventArgs args) {\n\t\t\tbase.OnActivated(sender, args);\n\t\t\tFocused = true;\n\t\t\tState?.OnActivated();\n\t\t}\n\n\t\tprotected override void OnDeactivated(object sender, EventArgs args) {\n\t\t\tbase.OnDeactivated(sender, args);\n\t\t\tFocused = false;\n\t\t\tState?.OnDeactivated();\n\t\t}\n\n\t\tprotected override void LoadContent() {\n\t\t\tGraphicsDevice = base.GraphicsDevice;\n\t\t\tGraphicsDevice.BlendState = BlendState.NonPremultiplied;\n\t\t\tLens.graphics.Graphics.Init();\n\t\t}\n\t\t\n\t\tprotected override void UnloadContent() {\n\t\t\tQuiting = true;\n\t\t\tState?.Destroy();\n\t\t\tStateRenderer?.Destroy();\n\n\t\t\tDestroy();\n\t\t\t\n\t\t\tAssets.Destroy();\n\t\t\tInput.Destroy();\n\n\t\t\tInstance = null;\n\t\t\tLog.Info(\"Bye\");\n\t\t\tLog.Close();\n\t\t}\n\n\t\tprotected virtual void Destroy() {\n\t\t\t\n\t\t}\n\t\t\n\t\tprotected override void Initialize() {\n\t\t\tbase.Initialize();\n\n\t\t\tif (StateRenderer == null) {\n\t\t\t\tStateRenderer = new PixelPerfectGameRenderer();\n\t\t\t}\n\t\t\t\n\t\t\tUpdateView();\n\n\t\t\tLog.Open();\n\t\t\tLog.Info($\"{tmpTitle} v{Version}\");\n\t\t\tLog.Info($\"Starting from {AppDomain.CurrentDomain.BaseDirectory}\");\n\t\t\tLog.Info(tmpTitle);\n\t\t\tLog.Info(DateTime.Now.ToString(\"dd.MM.yyyy h:mm tt\"));\n\n\t\t\tTitle = tmpTitle;\n\n\t\t\tInput.Init();\n\t\t}\n\n\t\tprotected override void Update(GameTime gameTime) {\n\t\t\tvar t = DateTime.Now.Millisecond;\n\t\t\t\n\t\t\tbase.Update(gameTime);\n\n\t\t\tGameTime = gameTime;\n\t\t\tvar dt = (float) gameTime.ElapsedGameTime.TotalSeconds * Speed;\n\n\t\t\tDelta = dt;\n\t\t\tTime += dt;\n\n\t\t\tAudio.Update(dt);\n\n\t\t\tSplit = Math.Max(0, Split - dt);\n\n\t\t\tif (Flash > 0) {\n\t\t\t\tFlash -= dt * 240f;\n\t\t\t}\n\t\t\t\n\t\t\t// Freeze = Math.Max(0, Math.Min(1, Freeze) - dt * 60f * (1.1f - FreezeModifier));\n\n\t\t\t// if (FreezeModifier <= 0.01f || Freeze < 0.01f) {\n\t\t\t\ttime += dt;\n\t\t\t// }\n\n\t\t\tMouseData.HadClick = false;\n\n\t\t\t// Make sure we don't have to process more than ~15 frames in 1 frame\n\t\t\ttime = Math.Min(time, 0.25f);\n\n\t\t\twhile (time >= FixedUpdateTime) {\n\t\t\t\ttime -= FixedUpdateTime;\n\t\n\t\t\t\tif (newState != null) {\n\t\t\t\t\tLog.Info(\"Setting state to \" + newState.GetType().Name);\n\n\t\t\t\t\tSpeed = 1;\n\t\t\t\t\t\n\t\t\t\t\tState?.Destroy();\n\t\t\t\t\tState = newState;\n\t\t\t\t\tInput.EnableImGuiFocus = true;\n\t\t\t\t\tState?.Init();\n\n\t\t\t\t\tnewState = null;\n\t\t\t\t\tUpdateView();\n\t\t\t\t}\n\n\t\t\t\tAssets.Update(FixedUpdateTime);\n\t\t\t\tInput.Update(FixedUpdateTime);\n\t\t\t\tTimer.Update(FixedUpdateTime);\n\t\t\t\tTween.Update(FixedUpdateTime);\n\n\t\t\t\tState?.Update(FixedUpdateTime);\n\t\t\t}\n\t\t\t\n\t\t\tCounter.Update(dt);\n\t\t\tUpdateTime = DateTime.Now.Millisecond - t;\n\t\t}\n\n\t\tpublic virtual void RenderUi() {\n\t\t\t\n\t\t}\n\n\t\tpublic void SetState(GameState state) {\n\t\t\tif (State == null) {\n\t\t\t\tState = state;\n\t\t\t\tState.Init();\n\t\t\t} else {\n\t\t\t\tnewState = state;\t\t\t\t\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic void Quit() {\n\t\t\tExit();\n\t\t}\n\t\t\n\t\tprotected override void Draw(GameTime gameTime) {\n\t\t\tvar t = DateTime.Now.Millisecond;\n\t\t\tStateRenderer.Render();\n\t\t\tbase.Draw(gameTime);\n\t\t\tRenderTime = DateTime.Now.Millisecond - t;\n\t\t}\n\n\t\tpublic void SetWindowed(int width, int height) {\n\t\t\tcore.SetWindowed(width, height);\n\t\t\tUpdateView();\n\t\t}\n\n\t\tpublic void SetFullscreen() {\n\t\t\tcore.SetFullscreen();\n\t\t\tUpdateView();\n\t\t}\n\n\t\tpublic float GetScreenWidth() {\n\t\t\tif (Graphics.IsFullScreen) {\n\t\t\t\treturn GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;\n\t\t\t}\n\n\t\t\treturn Math.Max(Display.Width, Graphics.PreferredBackBufferWidth);\n\t\t}\n\n\t\tpublic float GetScreenHeight() {\n\t\t\tif (Graphics.IsFullScreen) {\n\t\t\t\treturn GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;\n\t\t\t}\n\n\t\t\treturn Math.Max(Display.Height, Graphics.PreferredBackBufferHeight);\n\t\t}\n\t\t\n\t\tpublic void UpdateView() {\n\t\t\tvar screenWidth = GetScreenWidth();\n\t\t\tvar screenHeight = GetScreenHeight();\n\n\t\t\tGraphics.PreferredBackBufferWidth = (int) screenWidth;\n\t\t\tGraphics.PreferredBackBufferHeight = (int) screenHeight;\n\t\t\tGraphics.ApplyChanges();\n\n\t\t\tif (State?.NativeRender() ?? false) {\n\t\t\t\tUpscale = 1;\n\t\t\t\tUiUpscale = 1;\n\t\t\t\tViewport.X = 0;\n\t\t\t\tViewport.Y = 0;\n\t\t\t\t\n\t\t\t\tScreenMatrix = Matrix.Identity;\n\t\t\t\tUiMatrix = Matrix.Identity;\n\t\t\t} else {\n\t\t\t\tUpscale = Math.Min(screenWidth / Display.Width, screenHeight / Display.Height);\n\n\t\t\t\tif (PixelPerfect) {\n\t\t\t\t\tUpscale = (int) Math.Floor(Upscale);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tViewport.X = (screenWidth - Upscale * Display.Width) / 2;\n\t\t\t\tViewport.Y = (screenHeight - Upscale * Display.Height) / 2;\t\n\t\t\t\t\n\t\t\t\tif (PixelPerfect) {\n\t\t\t\t\tscreenWidth = (int) Math.Floor(screenWidth / Display.Width) * Display.Width;\n\t\t\t\t\tscreenHeight = (int) Math.Floor(screenHeight / Display.Height) * Display.Height;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tUiUpscale = Math.Min(screenWidth / Display.UiWidth, screenHeight / Display.UiHeight);\n\n\t\t\t\tfloat viewWidth;\n\t\t\t\n\t\t\t\tif (screenWidth / Display.Width > screenHeight / Display.Height) {\n\t\t\t\t\tviewWidth = screenHeight / Display.Height * Display.Width;\n\t\t\t\t} else {\n\t\t\t\t\tviewWidth = screenWidth;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tScreenMatrix = Matrix.CreateScale(Upscale) * Matrix.CreateTranslation(Viewport.X, Viewport.Y, 0);\n\t\t\t\tUiMatrix = Matrix.CreateScale(viewWidth / Display.UiWidth) * Matrix.CreateTranslation(Viewport.X, Viewport.Y, 0);\n\t\t\t}\n\t\t\t\n\t\t\tStateRenderer?.Resize((int) screenWidth, (int) screenHeight);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/Lens.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">x64</Platform>\n    <ProjectGuid>{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Lens</RootNamespace>\n    <AssemblyName>Lens</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <LangVersion>7</LangVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|x64' \">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"ImGui.NET, Version=1.70.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\ImGui.NET.1.70.0\\lib\\netstandard2.0\\ImGui.NET.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\Microsoft.Win32.Primitives.4.3.0\\lib\\net46\\Microsoft.Win32.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended.Graphics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.Graphics.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.Graphics.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Extended.Tiled, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Extended.Tiled.3.8.0\\lib\\netstandard2.0\\MonoGame.Extended.Tiled.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework, Version=3.8.0.13, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\lib\\net452\\MonoGame.Framework.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MonoGame.Framework.Content.Pipeline, Version=3.7.1.189, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\MonoGame.Framework.Content.Pipeline.Portable.3.7.1.189\\lib\\portable-net45+win8+wpa81\\MonoGame.Framework.Content.Pipeline.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"mscorlib\" />\n    <Reference Include=\"NAudio, Version=1.10.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\NAudio.1.10.0\\lib\\net35\\NAudio.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\" />\n    <Reference Include=\"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed\">\n      <HintPath>..\\packages\\Newtonsoft.Json.12.0.3\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SharpFNT, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null\">\n      <HintPath>..\\packages\\SharpFNT.1.1.0\\lib\\netstandard1.3\\SharpFNT.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.AppContext.4.3.0\\lib\\net463\\System.AppContext.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Buffers.4.4.0\\lib\\netstandard2.0\\System.Buffers.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Collections, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\System.Collections.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.ComponentModel.Composition\" />\n    <Reference Include=\"System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Console.4.3.0\\lib\\net46\\System.Console.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Diagnostics.DiagnosticSource.4.3.0\\lib\\net46\\System.Diagnostics.DiagnosticSource.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Diagnostics.Tracing.4.3.0\\lib\\net462\\System.Diagnostics.Tracing.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Globalization.Calendars.4.3.0\\lib\\net46\\System.Globalization.Calendars.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.4.3.0\\lib\\net462\\System.IO.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.4.3.0\\lib\\net46\\System.IO.Compression.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n      <HintPath>..\\packages\\System.IO.Compression.ZipFile.4.3.0\\lib\\net46\\System.IO.Compression.ZipFile.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.4.3.0\\lib\\net46\\System.IO.FileSystem.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.IO.FileSystem.Primitives.4.3.0\\lib\\net46\\System.IO.FileSystem.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.4.3.0\\lib\\net463\\System.Linq.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Linq.Expressions.4.3.0\\lib\\net463\\System.Linq.Expressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.Memory.4.5.0-preview2-26406-04\\lib\\netstandard2.0\\System.Memory.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Http.4.3.0\\lib\\net46\\System.Net.Http.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Net.Sockets.4.3.0\\lib\\net46\\System.Net.Sockets.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Numerics\" />\n    <Reference Include=\"System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Numerics.Vectors.4.4.0\\lib\\net46\\System.Numerics.Vectors.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Reflection.4.3.0\\lib\\net462\\System.Reflection.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.4.3.0\\lib\\net462\\System.Runtime.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.CompilerServices.Unsafe.4.5.0-preview2-26406-04\\lib\\netstandard2.0\\System.Runtime.CompilerServices.Unsafe.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Runtime.Extensions.4.3.0\\lib\\net462\\System.Runtime.Extensions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Algorithms.4.3.0\\lib\\net463\\System.Security.Cryptography.Algorithms.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Encoding.4.3.0\\lib\\net46\\System.Security.Cryptography.Encoding.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.Primitives.4.3.0\\lib\\net46\\System.Security.Cryptography.Primitives.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Security.Cryptography.X509Certificates.4.3.0\\lib\\net461\\System.Security.Cryptography.X509Certificates.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Text.RegularExpressions.4.3.0\\lib\\net463\\System.Text.RegularExpressions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\packages\\System.ValueTuple.4.5.0\\lib\\net47\\System.ValueTuple.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n      <HintPath>..\\packages\\System.Xml.ReaderWriter.4.3.0\\lib\\net46\\System.Xml.ReaderWriter.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"assets\\Animations.cs\" />\n    <Compile Include=\"assets\\Assets.cs\" />\n    <Compile Include=\"assets\\Audio.cs\" />\n    <Compile Include=\"assets\\Effects.cs\" />\n    <Compile Include=\"assets\\Locale.cs\" />\n    <Compile Include=\"assets\\Textures.cs\" />\n    <Compile Include=\"Cloner.cs\" />\n    <Compile Include=\"core\\ConsoleCore.cs\" />\n    <Compile Include=\"core\\Core.cs\" />\n    <Compile Include=\"core\\DesktopCore.cs\" />\n    <Compile Include=\"core\\PS4Core.cs\" />\n    <Compile Include=\"core\\SwitchCore.cs\" />\n    <Compile Include=\"core\\XBoxCore.cs\" />\n    <Compile Include=\"Display.cs\" />\n    <Compile Include=\"entity\\Area.cs\" />\n    <Compile Include=\"entity\\BitTag.cs\" />\n    <Compile Include=\"entity\\component\\Component.cs\" />\n    <Compile Include=\"entity\\component\\graphics\\GraphicsComponent.cs\" />\n    <Compile Include=\"entity\\component\\graphics\\ImageComponent.cs\" />\n    <Compile Include=\"entity\\component\\logic\\EntityState.cs\" />\n    <Compile Include=\"entity\\component\\logic\\InterestingComponent.cs\" />\n    <Compile Include=\"entity\\component\\logic\\ShakeComponent.cs\" />\n    <Compile Include=\"entity\\component\\logic\\StateChangedEvent.cs\" />\n    <Compile Include=\"entity\\component\\logic\\StateComponent.cs\" />\n    <Compile Include=\"entity\\component\\SaveableComponent.cs\" />\n    <Compile Include=\"entity\\Entity.cs\" />\n    <Compile Include=\"entity\\EntityList.cs\" />\n    <Compile Include=\"entity\\Event.cs\" />\n    <Compile Include=\"entity\\EventListener.cs\" />\n    <Compile Include=\"entity\\Subscriber.cs\" />\n    <Compile Include=\"entity\\TagLists.cs\" />\n    <Compile Include=\"graphics\\animation\\Animation.cs\" />\n    <Compile Include=\"graphics\\animation\\AnimationData.cs\" />\n    <Compile Include=\"graphics\\animation\\AnimationDirection.cs\" />\n    <Compile Include=\"graphics\\animation\\AnimationFrame.cs\" />\n    <Compile Include=\"graphics\\animation\\AnimationTag.cs\" />\n    <Compile Include=\"graphics\\animation\\ColorSet.cs\" />\n    <Compile Include=\"graphics\\animation\\ColorSets.cs\" />\n    <Compile Include=\"graphics\\ColorUtils.cs\" />\n    <Compile Include=\"graphics\\gamerenderer\\DefaultGameRenderer.cs\" />\n    <Compile Include=\"graphics\\gamerenderer\\GameRenderer.cs\" />\n    <Compile Include=\"graphics\\gamerenderer\\NativeGameRenderer.cs\" />\n    <Compile Include=\"graphics\\gamerenderer\\PixelPerfectGameRenderer.cs\" />\n    <Compile Include=\"graphics\\Graphics.cs\" />\n    <Compile Include=\"graphics\\TextureRegion.cs\" />\n    <Compile Include=\"input\\GamepadData.cs\" />\n    <Compile Include=\"input\\Input.cs\" />\n    <Compile Include=\"input\\InputButton.cs\" />\n    <Compile Include=\"input\\InputComponent.cs\" />\n    <Compile Include=\"input\\KeyboardData.cs\" />\n    <Compile Include=\"input\\MouseButtons.cs\" />\n    <Compile Include=\"input\\MouseData.cs\" />\n    <Compile Include=\"lightJson\\JsonArray.cs\" />\n    <Compile Include=\"lightJson\\JsonObject.cs\" />\n    <Compile Include=\"lightJson\\JsonValue.cs\" />\n    <Compile Include=\"lightJson\\JsonValueType.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\JsonParseException.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\JsonReader.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\JsonSerializationException.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\JsonWriter.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\TextPosition.cs\" />\n    <Compile Include=\"lightJson\\Serialization\\TextScanner.cs\" />\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Engine.cs\" />\n    <Compile Include=\"game\\GameState.cs\" />\n    <Compile Include=\"util\\camera\\Camera.cs\" />\n    <Compile Include=\"util\\camera\\CameraDriver.cs\" />\n    <Compile Include=\"util\\camera\\CustomCameraJumper.cs\" />\n    <Compile Include=\"util\\file\\FileHandle.cs\" />\n    <Compile Include=\"util\\file\\FileReader.cs\" />\n    <Compile Include=\"util\\file\\FileWriter.cs\" />\n    <Compile Include=\"util\\FrameCounter.cs\" />\n    <Compile Include=\"util\\Log.cs\" />\n    <Compile Include=\"util\\MathUtils.cs\" />\n    <Compile Include=\"util\\math\\Calc.cs\" />\n    <Compile Include=\"util\\math\\Rnd.cs\" />\n    <Compile Include=\"util\\Noise.cs\" />\n    <Compile Include=\"util\\NumberExtensions.cs\" />\n    <Compile Include=\"util\\pool\\DisposablePool.cs\" />\n    <Compile Include=\"util\\pool\\Pool.cs\" />\n    <Compile Include=\"util\\timer\\Timer.cs\" />\n    <Compile Include=\"util\\timer\\TimerTask.cs\" />\n    <Compile Include=\"util\\tween\\Ease.cs\" />\n    <Compile Include=\"util\\tween\\Tween.cs\" />\n    <Compile Include=\"util\\tween\\TweenTask.cs\" />\n    <Compile Include=\"util\\tween\\TweenValue.cs\" />\n    <Compile Include=\"util\\VectorExtension.cs\" />\n    <Compile Include=\"util\\Web.cs\" />\n    <Compile Include=\"Version.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"MonoGame.Framework.dll.config\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Aseprite\\Aseprite.csproj\">\n      <Project>{13c6f252-0b3c-4a22-a9db-270c76657fab}</Project>\n      <Name>Aseprite</Name>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\VelcroPhysics\\VelcroPhysics.MonoGame.csproj\">\n      <Project>{4650bd15-4b03-4a7e-98d4-9f8697ed2eb4}</Project>\n      <Name>VelcroPhysics.MonoGame</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"CppNet.dll\" />\n    <Content Include=\"libmojoshader_64.dll\" />\n    <Content Include=\"lightJson\\README.md\" />\n    <Content Include=\"mgfxc.deps.json\" />\n    <Content Include=\"mgfxc.dll\" />\n    <Content Include=\"mgfxc.exe\" />\n    <Content Include=\"mgfxc.pdb\" />\n    <Content Include=\"mgfxc.runtimeconfig.dev.json\" />\n    <Content Include=\"mgfxc.runtimeconfig.json\" />\n    <Content Include=\"README.md\" />\n    <Content Include=\"SharpDX.D3DCompiler.dll\" />\n    <Content Include=\"SharpDX.D3DCompiler.xml\" />\n    <Content Include=\"SharpDX.dll\" />\n    <Content Include=\"SharpDX.xml\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <Import Project=\"..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets\" Condition=\"Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" />\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\ImGui.NET.1.70.0\\build\\net40\\ImGui.NET.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets'))\" />\n  </Target>\n  <Import Project=\"..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets\" Condition=\"Exists('..\\packages\\NETStandard.Library.2.0.0\\build\\netstandard2.0\\NETStandard.Library.targets')\" />\n  <Import Project=\"..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets\" Condition=\"Exists('..\\packages\\MonoGame.Framework.DesktopGL.Core.3.8.0.13\\build\\MonoGame.Framework.DesktopGL.Core.targets')\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n         Other similar extension points exist, see Microsoft.Common.targets.\n    <Target Name=\"BeforeBuild\">\n    </Target>\n    <Target Name=\"AfterBuild\">\n    </Target>\n    -->\n</Project>"
  },
  {
    "path": "Lens/MonoGame.Framework.dll.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\t<dllmap dll=\"SDL2.dll\" os=\"linux\" cpu=\"x64\" target=\"../../lib/x64/libSDL2-2.0.so.0\"/>\n\t<dllmap dll=\"soft_oal.dll\" os=\"linux\" cpu=\"x64\" target=\"../../lib/x64/libopenal.so.1\" />\n\t<dllmap dll=\"SDL2.dll\" os=\"windows\" cpu=\"x64\" target=\"../../lib/x64/SDL2.dll\"/>\n\t<dllmap dll=\"soft_oal.dll\" os=\"windows\" cpu=\"x64\" target=\"../../lib/x64/soft_oal.dll\" />\n</configuration>\n"
  },
  {
    "path": "Lens/Program.cs",
    "content": "﻿using System;\n\nnamespace Lens {\n\tpublic class Program {\n\t\t[STAThread]\n\t\tpublic static void Main() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"Lens\")]\n[assembly: AssemblyDescription(\"Lens engine\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"Lens Games\")]\n[assembly: AssemblyProduct(\"MonogameRiderTemplate\")]\n[assembly: AssemblyCopyright(\"Copyright RexcellentGames © 2018\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "Lens/README.md",
    "content": "# Lens (my little _engine?_ inspired by Monocle)\r\n\r\nThis project contains essential systems, such as Entity-Area management, Events & Event Handlers, loading assets and more."
  },
  {
    "path": "Lens/Version.cs",
    "content": "﻿namespace Lens {\n\tpublic class Version {\n\t\tpublic readonly uint Major;\n\t\tpublic readonly uint Minor;\n\t\tpublic readonly uint Update;\n\t\tpublic readonly uint Patch;\n\t\tpublic readonly bool Dev;\n\t\tpublic readonly uint Id;\n\t\tpublic readonly string Name;\n\t\t\n\t\tpublic Version(string name, uint id, uint major, uint minor, uint update, uint patch, bool dev) {\n\t\t\tName = name;\n\t\t\tId = id;\n\t\t\tMajor = major;\n\t\t\tMinor = minor;\n\t\t\tUpdate = update;\n\t\t\tPatch = patch;\n\t\t\tDev = dev;\n\t\t}\n\n\t\tpublic override string ToString() {\n\t\t\treturn $\"{Major}.{Minor}.{Update}{(Patch == 0 ? \"\" : $\".{Patch}\")}{(Dev ? \" dev\" : \"\")}{(Name == \"\" ? \"\" : $\" {Name}\")}\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Animations.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing Aseprite;\nusing Lens.graphics;\nusing Lens.graphics.animation;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.assets {\n\tpublic struct Animations {\n\t\tpublic static bool Reload;\n\t\tprivate static Dictionary<string, AnimationData> animations = new Dictionary<string, AnimationData>();\n\t\t\n\t\tinternal static void Load() {\n\t\t\tvar animationDir = FileHandle.FromRoot(\"Animations/\");\n\n\t\t\tif (animationDir.Exists()) {\n\t\t\t\tforeach (var animation in animationDir.ListFileHandles()) {\n\t\t\t\t\tif (animation.Extension == \".ase\") {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tLoadAnimation(animation.NameWithoutExtension, animation.FullPath);\n\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate static void LoadAnimation(string name, string fullPath) {\n\t\t\tvar file = new AsepriteFile(fullPath);\n\t\t\tvar animation = new AnimationData();\n\t\t\t\n\t\t\tfor (var i = 0; i < file.Layers.Count; i++) {\n\t\t\t\tvar layer = file.Layers[i];\n\t\t\t\tvar list = new List<AnimationFrame>();\n\t\t\t\t\n\t\t\t\tfor (var j = 0; j < file.Frames.Count; j++) {\n\t\t\t\t\tvar frame = file.Frames[j];\n\t\t\t\t\tvar newFrame = new AnimationFrame();\n\t\t\t\t\t\n\t\t\t\t\tnewFrame.Duration = frame.Duration;\n\t\t\t\t\tnewFrame.Texture = new TextureRegion(file.Texture, new Rectangle(j * file.Width, i * file.Height, file.Width, file.Height));\n\t\t\t\t\tnewFrame.Bounds = newFrame.Texture.Source;\n\t\t\t\t\t\n\t\t\t\t\tlist.Add(newFrame);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tanimation.Layers[layer.Name] = list;\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < file.Slices.Count; i++) {\n\t\t\t\tvar slice = file.Slices[i];\n\t\t\t\tanimation.Slices[slice.Name] = new TextureRegion(file.Texture, new Rectangle(slice.OriginX, slice.OriginY, slice.Width, slice.Height));\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var tag in file.Animations.Values) {\n\t\t\t\tvar newTag = new AnimationTag();\n\t\t\t\n\t\t\t\tnewTag.Direction = (AnimationDirection) tag.Directions;\n\t\t\t\tnewTag.StartFrame = (uint) tag.FirstFrame;\n\t\t\t\tnewTag.EndFrame = (uint) tag.LastFrame;\n\t\t\t\t\n\t\t\t\tanimation.Tags[tag.Name] = newTag;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var tag in file.Tags) {\n\t\t\t\tvar newTag = new AnimationTag();\n\t\t\t\n\t\t\t\tnewTag.Direction = (AnimationDirection) tag.LoopDirection;\n\t\t\t\tnewTag.StartFrame = (uint) tag.From;\n\t\t\t\tnewTag.EndFrame = (uint) tag.To;\n\t\t\t\t\n\t\t\t\tanimation.Tags[tag.Name] = newTag;\n\t\t\t}\n\n\n\t\t\tanimation.Texture = file.Texture;\n\t\t\tanimations[name] = animation;\n\t\t}\n\t\t\n\t\tinternal static void Destroy() {\n\t\t\tforeach (var animation in animations.Values) {\n\t\t\t\tanimation.Texture.Dispose();\n\t\t\t}\n\t\t}\n\n\t\tpublic static AnimationData Get(string id) {\n\t\t\tif (animations.TryGetValue(id, out var animation)) {\n\t\t\t\treturn animation;\n\t\t\t}\n\t\t\t\n\t\t\tLog.Error($\"Animation {id} was not found!\");\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic static Animation Create(string id, string layer = null) {\n\t\t\treturn new Animation(Get(id), layer);\n\t\t}\n\n\t\tpublic static AnimationData GetColored(string id, ColorSet set) {\n\t\t\tif (set == null) {\n\t\t\t\treturn Get(id);\n\t\t\t}\n\t\t\t\n\t\t\tvar fullId = $\"{id}_{set.Id}\";\n\t\t\t\n\t\t\tif (animations.TryGetValue(fullId, out var animation)) {\n\t\t\t\treturn animation;\n\t\t\t}\n\t\t\t\n\t\t\tanimation = Get(id);\n\n\t\t\tif (animation == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar data = new AnimationData();\n\t\t\tvar w = animation.Texture.Width;\n\t\t\tvar h = animation.Texture.Height;\n\t\t\tvar texture = new Texture2D(Engine.GraphicsDevice, w, h);\n\t\t\tvar tdata = new Color[w * h];\n\t\t\t\n\t\t\tanimation.Texture.GetData(tdata);\n\t\t\tvar pixelData = new Color[w * h];\n\t\t\t\n\t\t\tfor (int y = 0; y < h; y++) {\n\t\t\t\tfor (int x = 0; x < w; x++) {\n\t\t\t\t\tvar i = x + y * w;\n\t\t\t\t\tvar color = tdata[i];\n\n\t\t\t\t\tfor (int c = 0; c < set.From.Length; c++) {\n\t\t\t\t\t\tif (ColorUtils.Compare(set.From[c], color, 4)) {\n\t\t\t\t\t\t\tcolor = set.To[c];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tpixelData[i] = color;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\ttexture.SetData(pixelData);\n\n\t\t\tforeach (var l in animation.Layers) {\n\t\t\t\tvar list = new List<AnimationFrame>();\n\t\t\t\t\n\t\t\t\tforeach (var f in l.Value) {\n\t\t\t\t\tlist.Add(new AnimationFrame {\n\t\t\t\t\t\tTexture = new TextureRegion(texture, f.Bounds),\n\t\t\t\t\t\tDuration = f.Duration,\n\t\t\t\t\t\tBounds = f.Bounds\n\t\t\t\t\t});\t\n\t\t\t\t}\n\n\t\t\t\tdata.Layers[l.Key] = list;\n\t\t\t}\n\n\t\t\tforeach (var s in animation.Slices) {\n\t\t\t\tdata.Slices[s.Key] = new TextureRegion(texture, s.Value.Source);\n\t\t\t}\n\n\t\t\tforeach (var t in animation.Tags) {\n\t\t\t\tdata.Tags[t.Key] = t.Value;\n\t\t\t}\n\t\t\t\n\t\t\tdata.Texture = texture;\n\t\t\tanimations[fullId] = data;\n\t\t\t\n\t\t\treturn data;\n\t\t}\n\t\t\n\t\tpublic static Animation CreateColored(string id, ColorSet set, string layer = null) {\n\t\t\treturn new Animation(GetColored(id, set), layer);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Assets.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing Lens.graphics;\nusing Lens.util;\nusing Aseprite;\nusing Microsoft.Xna.Framework.Content;\n\nnamespace Lens.assets {\n\tpublic static class Assets {\n\t\tpublic static bool ImGuiEnabled;\n\t\tprivate static bool modified;\n\n\t\tpublic static bool DataModified {\n\t\t\tget => modified;\n\n\t\t\tset {\n\t\t\t\tif (!modified && value) {\n\t\t\t\t\tmodified = true;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tEngine.Instance.Window.Title = $\"MODIFIED {Engine.Instance.Window.Title}\";\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic const int ItemData = 6617551;\n\t\n#if DEBUG\n\t\tpublic static bool LoadOriginalFiles = true;\n\t\tpublic static bool LoadMusic = true;\n\t\tpublic static bool LoadSfx = true;\n\t\tpublic const bool Reload = false;\n\t\tpublic static bool LoadMods = false;\n#else\n\t\tpublic static bool LoadOriginalFiles = false;\n\t\tpublic static bool LoadMusic = true;\n\t\tpublic static bool LoadSfx = true;\n\t\tpublic static bool Reload = false;\n\t\tpublic static bool LoadMods = true;\n#endif\n\n\t\tpublic static bool FailedToLoadAudio;\n\n\t\tpublic static ContentManager Content;\n\t\tpublic static string Root => LoadOriginalFiles \n\t\t    ? Path.Combine(Directory.GetCurrentDirectory(), \"../../../BurningKnight/Content/\") \n\t\t    : NearRoot;\n\t\t    \n\t\tpublic static string NearRoot => $\"{Directory.GetCurrentDirectory()}/Content/\";\n\t\t\n\t\tprivate static string[] folders;\n\t\tprivate static List<FileSystemEventArgs> changed = new List<FileSystemEventArgs>();\n\t\tprivate static float lastUpdate;\n\t\t\n\t\tpublic static void Load(ref int progress) {\n\t\t\tLoadAssets(ref progress);\n\n\t\t\tif (Reload && LoadOriginalFiles) {\t\t\t\t\n\t\t\t\tfolders = new[] {\n\t\t\t\t\t//\"Textures/\",\n\t\t\t\t\t\"Animations/\"\n\t\t\t\t\t//\"Sfx/\"\n\t\t\t\t};\n\n\t\t\t\tfor (int i = 0; i < folders.Length; i++) {\n\t\t\t\t\tvar watcher = new FileSystemWatcher();\n\t\t\t\t\t\n\t\t\t\t\twatcher.Path = Path.GetFullPath(Root + folders[i]);\n\t\t\t\t\twatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite\n\t\t\t\t\t                                                | NotifyFilters.FileName | NotifyFilters.DirectoryName;\n\n\t\t\t\t\twatcher.Changed += OnChanged;\n\t\t\t\t\twatcher.Created += OnChanged;\n\n\t\t\t\t\twatcher.EnableRaisingEvents = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate static void OnChanged(object source, FileSystemEventArgs e) {\n\t\t\tchanged.Add(e);\n\t\t}\n\n\t\tprivate static void LoadAssets(ref int progress) {\n\t\t\tAsepriteReader.GraphicsDevice = Engine.GraphicsDevice;\n\t\t\t\n\t\t\tAudio.StartThread();\n\n\t\t\tif (Locale.Map == null) {\n\t\t\t\tLocale.Load(Locale.PrefferedClientLanguage);\n\t\t\t}\n\n\t\t\tprogress++;\n\t\t\tEffects.Load();\n\t\t\tprogress++;\n\t\t\tTextures.Load();\n\t\t\tprogress++;\n\t\t\tAnimations.Load();\n\t\t\tprogress++;\n\t\t\t\n\t\t\tif (LoadSfx) {\n\t\t\t\tAudio.Load();\n\t\t\t}\n\n\t\t\tprogress++;\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tGraphics.Destroy();\n\t\t\tDestroyAssets();\n\t\t}\n\n\t\tprivate static void DestroyAssets() {\n\t\t\tEffects.Destroy();\n\t\t\tTextures.Destroy();\n\t\t\tAnimations.Destroy();\n\t\t\tAudio.Destroy();\n\t\t}\n\n\t\tpublic static void Update(float dt) {\n\t\t\tAnimations.Reload = false;\n\n\t\t\tlastUpdate += dt;\n\n\t\t\tif (lastUpdate >= 0.3f) {\n\t\t\t\tlastUpdate = 0;\n\t\t\t\tCheckForUpdates();\n\t\t\t}\n\t\t}\n\n\t\tprivate static void CheckForUpdates() {\n\t\t\tif (changed.Count == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar reloadedTextures = false;\n\t\t\tvar reloadedSfx = false;\n\t\t\tvar reloadedAnimations = false;\n\n\t\t\tvar changedClone = changed.ToArray();\n\t\t\t\n\t\t\tforeach (var e in changedClone) {\n\t\t\t\tswitch (new DirectoryInfo(Path.GetDirectoryName(e.FullPath)).Name) {\n\t\t\t\t\tcase \"Textures\": {\n\t\t\t\t\t\tif (!reloadedTextures) {\n\t\t\t\t\t\t\tLog.Debug(\"Reloading textures...\");\n\t\t\t\t\t\t\treloadedTextures = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"Sfx\": {\n\t\t\t\t\t\tif (!reloadedSfx) {\n\t\t\t\t\t\t\tLog.Debug(\"Reloading sfx...\");\n\n\t\t\t\t\t\t\tAudio.Destroy();\n\t\t\t\t\t\t\tAudio.Load();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treloadedSfx = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"Animations\": {\n\t\t\t\t\t\tif (!reloadedAnimations) {\n\t\t\t\t\t\t\tLog.Debug(\"Reloading animations...\");\n\n\t\t\t\t\t\t\tAnimations.Load();\n\t\t\t\t\t\t\tAnimations.Reload = true;\n\n\t\t\t\t\t\t\treloadedAnimations = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tchanged.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Audio.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Threading;\nusing Aseprite;\nusing Lens.entity;\nusing Lens.util;\nusing Lens.util.camera;\nusing Lens.util.file;\nusing Lens.util.tween;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Audio;\nusing Microsoft.Xna.Framework.Media;\nusing VelcroPhysics;\n\nnamespace Lens.assets {\n\tpublic class Audio {\n\t\tpublic static float MasterVolume = 1;\n\t\tpublic static float SfxVolume = 1;\n\t\tpublic static float SfxVolumeBuffer = 1f;\n\t\tpublic static float SfxVolumeBufferResetTimer = 0;\n\t\tprivate const float CrossFadeTime = 0.25f;\n\n\t\tpublic static float Db3 = 0.1f;\n\n\t\tprivate static Song currentPlaying;\n\t\tprivate static string currentPlayingMusic;\n\t\tprivate static Dictionary<string, Song> musicInstances = new Dictionary<string, Song>();\n\t\tprivate static Dictionary<string, SoundEffect> sounds = new Dictionary<string, SoundEffect>();\n\n\t\tpublic static bool Repeat {\n\t\t\tget => MediaPlayer.IsRepeating;\n\t\t\tset => MediaPlayer.IsRepeating = value;\n\t\t}\n\n\t\tpublic static DynamicSoundEffectInstance SoundEffectInstance;\n\n\t\tpublic static float Speed = 1;\n\n\t\tprivate static void LoadSfx(FileHandle file, string path, bool root = false) {\n\t\t\tif (file.Exists()) {\n\t\t\t\tpath = $\"{path}{file.Name}{(root ? \"\" : \"/\")}\";\n\n\t\t\t\tforeach (var sfx in file.ListFileHandles()) {\n\t\t\t\t\tif (sfx.Extension == \".xnb\") {\n\t\t\t\t\t\tLoadSfx(sfx.NameWithoutExtension, path);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tforeach (var dir in file.ListDirectoryHandles()) {\n\t\t\t\t\tLoadSfx(dir, path);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.Error($\"File {file.Name} is missing\");\n\t\t\t}\n\t\t}\n\n\t\tpublic static void StartThread() {\n\t\t\t\n\t\t}\n\t\t\n\t\tinternal static void Load() {\n\t\t\tLoadSfx(FileHandle.FromNearRoot(\"bin/Sfx/\"), \"\", true);\n\t\t}\n\n\t\tprivate static void LoadSfx(string sfx, string path) {\n\t\t\tvar s = Path.GetFileNameWithoutExtension(sfx);\n\t\t\tsounds[$\"{path}{s}\".Replace('/', '_')] = Assets.Content.Load<SoundEffect>($\"bin/Sfx/{path}{s}\");\t\t\t\t\n\t\t}\n\t\t\n\t\tinternal static void Destroy() {\n\t\t\tforeach (var sound in sounds.Values) {\n\t\t\t\tsound.Dispose();\n\t\t\t\tGC.SuppressFinalize(sound); // Lol what?\n\t\t\t}\n\n\t\t\tif (SoundEffectInstance != null) {\n\t\t\t\tLog.Info(\"Disposing audio mixer\");\n\n\t\t\t\tSoundEffectInstance.Stop();\n\t\t\t\tSoundEffectInstance.Dispose();\n\t\t\t\tGC.SuppressFinalize(SoundEffectInstance);\n\t\t\t\t\n\t\t\t\tSoundEffectInstance = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void PlaySfx(string id, float volume = 1, float pitch = 0, float pan = 0) {\n\t\t\tif (!Engine.Instance.Focused || !Assets.LoadSfx) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tPlaySfx(GetSfx(id), volume * (id.StartsWith(\"level_explosion\") ? MasterVolume : SfxVolumeBuffer), pitch, pan);\n\t\t}\n\n\t\tpublic static SoundEffect GetSfx(string id) {\n\t\t\tSoundEffect effect;\n\n\t\t\tif (sounds.TryGetValue(id, out effect)) {\n\t\t\t\treturn effect;\n\t\t\t}\n\n\t\t\tLog.Error($\"Sound effect {id} was not found!\");\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic static void PlaySfx(SoundEffect sfx, float volume = 1, float pitch = 0, float pan = 0) {\n\t\t\tif (!Assets.LoadSfx) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tsfx?.Play(MathUtils.Clamp(0, 1, volume * SfxVolume * MasterVolume), pitch, pan);\n\t\t}\n\t\t\n\t\tpublic static void PlayMusic(string music, bool fromStart = false) {\n\t\t\tif (!Assets.LoadMusic) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (currentPlayingMusic == music && currentPlaying != null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tRepeat = true;\n\n\t\t\tif (!fromStart) {\n\t\t\t\tFadeOut(() => {\n\t\t\t\t\tLoadAndPlayMusic(music, fromStart);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tLoadAndPlayMusic(music, fromStart);\n\t\t\t}\n\t\t}\n\n\t\tprivate static bool loading;\n\n\t\tprivate static void LoadAndPlayMusic(string music, bool fromStart = false) {\n\t\t\tif (musicInstances.ContainsKey(music)) {\n\t\t\t\tThreadLoad(music, fromStart);\n\t\t\t} else {\n\t\t\t\tnew Thread(() => {\n\t\t\t\t\tThreadLoad(music, fromStart);\n\t\t\t\t}).Start();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void ThreadLoad(string music, bool fromStart = false) {\n\t\t\ttry {\n\t\t\t\tloading = true;\n\n\t\t\t\tLog.Info($\"Playing music {music} repeat = {Repeat}\");\n\t\t\t\tcurrentPlayingMusic = music;\n\n\t\t\t\tif (!musicInstances.TryGetValue(music, out currentPlaying)) {\n\t\t\t\t\tcurrentPlaying = Assets.Content.Load<Song>($\"bin/Music/{music}\");\n\t\t\t\t\tmusicInstances[music] = currentPlaying;\n\t\t\t\t}\n\n\t\t\t\tMediaPlayer.Volume = 0;\n\t\t\t\tMediaPlayer.Play(currentPlaying);\n\n\t\t\t\tTween.To(musicVolume, MediaPlayer.Volume, x => MediaPlayer.Volume = x, fromStart ? 0.05f : CrossFadeTime);\n\n\t\t\t\tloading = false;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error($\"Failed to load {music}\");\n\t\t\t\tLog.Error(e);\n\t\t\t\tloading = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic static void FadeOut(Action callback = null) {\n\t\t\tif (currentPlaying != null) {\n\t\t\t\tTween.To(0, MediaPlayer.Volume, x => MediaPlayer.Volume = x, CrossFadeTime).OnEnd = () => {\n\t\t\t\t\tcurrentPlaying = null;\n\t\t\t\t\tcurrentPlayingMusic = null;\n\n\t\t\t\t\tMediaPlayer.Stop();\n\t\t\t\t\tcallback?.Invoke();\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tcallback?.Invoke();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void Stop() {\n\t\t\tMediaPlayer.Stop();\n\n\t\t\tcurrentPlaying = null;\n\t\t\tcurrentPlayingMusic = null;\n\t\t}\n\n\t\tprivate static float musicVolume = 1;\n\n\t\tpublic static void UpdateMusicVolume(float value) {\n\t\t\tMediaPlayer.Volume = value;\n\t\t\tmusicVolume = value;\n\t\t}\n\n\t\tpublic static void Update(float dt) {\n\t\t\tif (SfxVolumeBufferResetTimer > 0) {\n\t\t\t\tSfxVolumeBufferResetTimer -= dt;\n\n\t\t\t\tif (SfxVolumeBufferResetTimer <= 0) {\n\t\t\t\t\tTween.To(1, SfxVolumeBuffer, x => SfxVolumeBuffer = x, 0.3f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Effects.cs",
    "content": "﻿using System.Collections.Generic;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.assets {\n\tpublic static class Effects {\n\t\tpublic static Dictionary<string, Effect> All = new Dictionary<string, Effect>();\n\t\t\n\t\tpublic static void Load() {\n\t\t\tvar shaderDir = FileHandle.FromRoot(\"bin/Shaders/\");\n\t\t\t\n\t\t\tif (shaderDir.Exists()) {\n\t\t\t\tforeach (var h in shaderDir.ListFileHandles()) {\n\t\t\t\t\tif (h.Extension == \".xnb\") {\n\t\t\t\t\t\tLoadEffect(h);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate static void LoadEffect(FileHandle handle) {\n\t\t\tAll[handle.NameWithoutExtension] = Assets.Content.Load<Effect>($\"bin/Shaders/{handle.NameWithoutExtension}\");\n\t\t}\n\t\t\n\t\tpublic static void Destroy() {\n\t\t\tforeach (var e in All) {\n\t\t\t\te.Value.Dispose();\n\t\t\t}\t\n\t\t\t\n\t\t\tAll.Clear();\n\t\t}\n\n\t\tpublic static Effect Get(string id) {\n\t\t\treturn All.TryGetValue(id, out var o) ? o : null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Locale.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text.RegularExpressions;\nusing Lens.lightJson;\nusing Lens.lightJson.Serialization;\nusing Lens.util;\nusing Lens.util.file;\nusing Lens.util.math;\n\nnamespace Lens.assets {\n\tpublic class Locale {\n\t\tpublic static Dictionary<string, string> Map;\n\t\t\n\t\tpublic static Dictionary<string, string> Fallback = new Dictionary<string, string>();\n\t\tpublic static Dictionary<string, Dictionary<string, string>> Loaded = new Dictionary<string, Dictionary<string, string>>();\n\t\tprivate static bool LoadedFallback;\n\t\t\n\t\tpublic static string Current;\n\t\tpublic static string PrefferedClientLanguage = \"en\";\n\n\t\tprivate static string[] quacks = { \"quack\", \"QUACK\", \"quaaak\", \"qk\" };\n\n\t\tprivate static void LoadRaw(string name, string path, bool backup = false) {\n\t\t\tif (Loaded.TryGetValue(name, out var cached)) {\n\t\t\t\tMap = cached;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (name == \"qu\") {\n\t\t\t\tcached = new Dictionary<string, string>();\n\t\t\t\tLoaded[name] = cached;\n\n\t\t\t\tvar i = 0;\n\n\t\t\t\tforeach (var entry in Fallback) {\n\t\t\t\t\tcached[entry.Key] = Regex.Replace(entry.Value, @\"\\w+(?<!^\\[)\\b\", (m) => {\n\t\t\t\t\t\ti++;\n\t\t\t\t\t\treturn char.IsUpper(m.Value[0]) ? \"Quack\" : quacks[(m.Value[0] + i * 5) % quacks.Length];\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar file = FileHandle.FromRoot(path);\n\n\t\t\tif (!file.Exists()) {\n\t\t\t\tLog.Error($\"Locale {path} was not found!\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tvar root = JsonValue.Parse(file.ReadAll());\n\t\t\t\t\n\t\t\t\tcached = new Dictionary<string, string>();\n\t\t\t\tLoaded[name] = cached;\n\n\t\t\t\tforeach (var entry in root.AsJsonObject) {\n\t\t\t\t\tcached[entry.Key] = entry.Value.AsString;\n\t\t\t\t}\n\n\t\t\t\tif (backup) {\n\t\t\t\t\tFallback = cached;\n\t\t\t\t} else {\n\t\t\t\t\tLoaded[name] = cached;\n\t\t\t\t\tMap = cached;\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void Load(string locale) {\n\t\t\tif (!LoadedFallback) {\n\t\t\t\tLoadRaw(\"en\", \"Locales/en.json\", true);\n\t\t\t\tLoadedFallback = true;\n\t\t\t} \n\t\t\t\n\t\t\tif (Current == locale) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tCurrent = locale;\n\n\t\t\tif (!Loaded.ContainsKey(locale)) {\n\t\t\t\tLoadRaw(locale, $\"Locales/{locale}.json\");\n\t\t\t}\n\n\t\t\tif (Loaded.ContainsKey(locale)) {\n\t\t\t\tMap = Loaded[locale];\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Save() {\n\t\t\tLog.Info($\"Saving locale {Current}\");\n\t\t\t\n\t\t\ttry {\n\t\t\t\tvar file = File.CreateText(FileHandle.FromRoot($\"Locales/{Current}.json\").FullPath);\n\t\t\t\tvar writer = new JsonWriter(file, \n\t\t\t\t\t#if DEBUG\n\t\t\t\t\t\ttrue\n\t\t\t\t\t#else\n\t\t\t\t\t\tfalse\n\t\t\t\t\t#endif\n\t\t\t\t\t);\n\t\t\t\tvar root = new JsonObject();\n\n\t\t\t\tforeach (var t in Map) {\n\t\t\t\t\troot[t.Key] = t.Value;\n\t\t\t\t}\n\n\t\t\t\twriter.Write(root);\n\t\t\t\tfile.Close();\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Delete() {\n\t\t\ttry {\n\t\t\t\tFileHandle.FromRoot($\"Locales/{Current}.json\").Delete();\n\t\t\t\tCurrent = \"en\";\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\n\t\tpublic static string Get(string key, bool eng = false) {\n\t\t\treturn !eng && Map.ContainsKey(key) ? Map[key] : GetEnglish(key);\n\t\t}\n\t\t\n\t\tpublic static string GetEnglish(string key) {\n\t\t\treturn Fallback.ContainsKey(key) ? Fallback[key] : key;\n\t\t}\n\n\t\tpublic static bool Contains(string key) {\n\t\t\treturn Map.ContainsKey(key) || Fallback.ContainsKey(key);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/assets/Textures.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing Aseprite;\nusing Lens.graphics;\nusing Lens.util;\nusing Lens.util.file;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.assets {\n\tpublic class Textures {\n\t\tprivate static Dictionary<string, TextureRegion> textures = new Dictionary<string, TextureRegion>();\n\t\tpublic static TextureRegion Missing;\n\t\t\n\t\tinternal static void Load() {\n\t\t\tvar textureDir = FileHandle.FromRoot(\"Textures/\");\n\t\t\t\n\t\t\tif (textureDir.Exists()) {\n\t\t\t\tLoadTextures(textureDir);\n\t\t\t}\n\t\t}\n\n\t\tpublic static Texture2D FastLoad(string path) {\n\t\t\tvar fileStream = new FileStream(path, FileMode.Open);\n\t\t\tvar texture = Texture2D.FromStream(Engine.GraphicsDevice, fileStream);\n\t\t\tfileStream.Dispose();\n\n\t\t\treturn texture;\n\t\t}\n\t\t\n\t\tprivate static void LoadTextures(FileHandle handle) {\n\t\t\tforeach (var h in handle.ListFileHandles()) {\n\t\t\t\tLoadTexture(h);\n\t\t\t}\n\n\t\t\tforeach (var h in handle.ListDirectoryHandles()) {\n\t\t\t\tLoadTextures(h);\n\t\t\t}\n\t\t}\n\n\t\tprivate static void LoadTexture(FileHandle handle) {\n\t\t\tvar region = new TextureRegion();\n\t\t\tstring id = handle.NameWithoutExtension;\n\n\t\t\tif (Assets.LoadOriginalFiles) {\n\t\t\t\tvar fileStream = new FileStream(handle.FullPath, FileMode.Open);\n\t\t\t\tregion.Texture = Texture2D.FromStream(Engine.GraphicsDevice, fileStream);\n\t\t\t\tfileStream.Dispose();\n\t\t\t} else {\n\t\t\t\tregion.Texture = Assets.Content.Load<Texture2D>($\"bin/Textures/{handle.NameWithoutExtension}\");\n\t\t\t}\n\n\t\t\tregion.Source = region.Texture.Bounds;\n\t\t\tregion.Center = new Vector2(region.Source.Width / 2f, region.Source.Height / 2f);\n\t\t\t\n\t\t\ttextures[id] = region;\n\t\t}\n\n\t\tinternal static void Destroy() {\n\t\t\tforeach (var region in textures.Values) {\n\t\t\t\tregion.Texture.Dispose();\n\t\t\t}\n\t\t\t\n\t\t\ttextures.Clear();\n\t\t}\n\t\t\n\t\tpublic static TextureRegion Get(string id) {\n\t\t\tif (textures.TryGetValue(id, out var region)) {\n\t\t\t\treturn region;\n\t\t\t}\n\t\t\t\n\t\t\tLog.Error($\"Texture {id} was not found!\");\n\t\t\treturn Missing;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/core/ConsoleCore.cs",
    "content": "﻿namespace Lens.Core {\n\tpublic class ConsoleCore : Core {\n\t\t\n\t}\n}"
  },
  {
    "path": "Lens/core/Core.cs",
    "content": "﻿using Microsoft.Xna.Framework;\n\nnamespace Lens.Core {\n\tpublic class Core {\n\t\tpublic GameWindow Window;\n\t\tpublic GraphicsDeviceManager Graphics;\n\t\t\n\t\tpublic virtual void Init(int width, int height, bool fullscreen) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void SetWindowed(int width, int height) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void SetFullscreen() {\n\t\t\t\n\t\t}\n\n\t\tpublic static Core SelectCore(GameWindow Window, GraphicsDeviceManager Graphics) {\n\t\t\tCore core;\n\t\t\t\n#if NSWITCH\n\t\t\tcore = SwitchCore();\n#elif XBOXONE\n\t\t\tcore = new XBoxCore();\n#elif PS4\n\t\t\tcore = new PS4Core();\n#else\n\t\t\tcore = new DesktopCore();\n#endif\n\n\t\t\tcore.Window = Window;\n\t\t\tcore.Graphics = Graphics;\n\n\t\t\treturn core;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/core/DesktopCore.cs",
    "content": "﻿using System;\nusing Lens.util;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.Core {\n\tpublic class DesktopCore : Core {\n\t\tprivate static bool resizing;\n\t\tprivate static bool fullscreen;\n\t\t\n\t\tpublic override void Init(int width, int height, bool fullscreen) {\n\t\t\tbase.Init(width, height, fullscreen);\n\n\t\t\tWindow.AllowUserResizing = true;\n\t\t\tWindow.ClientSizeChanged += OnClientSizeChanged;\n\n\t\t\tif (fullscreen) {\n\t\t\t\tGraphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;\n\t\t\t\tGraphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;\n\t\t\t\tGraphics.IsFullScreen = true;\n\t\t\t} else {\n\t\t\t\tGraphics.PreferredBackBufferWidth = width;\n\t\t\t\tGraphics.PreferredBackBufferHeight = height;\n\t\t\t\tGraphics.IsFullScreen = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetWindowed(int width, int height) {\t\t\t\n\t\t\tif (width > 0 && height > 0) {\n\t\t\t\tresizing = true;\n\t\t\t\tfullscreen = false;\n\t\t\t\tGraphics.PreferredBackBufferWidth = width;\n\t\t\t\tGraphics.PreferredBackBufferHeight = height;\n\t\t\t\tGraphics.IsFullScreen = false;\n\t\t\t\tGraphics.ApplyChanges();\n\t\t\t\t\n\t\t\t\tLog.Info($\"Going windowed {width}:{height}\");\n\t\t\t\tresizing = false;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void SetFullscreen() {\n\t\t\tif (fullscreen) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfullscreen = true;\n\t\t\tresizing = true;\n\t\t\tGraphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;\n\t\t\tGraphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;\n\t\t\tGraphics.IsFullScreen = true;\n\t\t\tGraphics.ApplyChanges();\n\t\t\t\n\t\t\tLog.Info(\"Going to fullscreen\");\n\t\t\tresizing = false;\n\t\t}\n\n\t\tprotected virtual void OnClientSizeChanged(object sender, EventArgs e) {\n\t\t\tif (Window.ClientBounds.Width > 0 && Window.ClientBounds.Height > 0 && !resizing) {\n\t\t\t\tresizing = true;\n\n\t\t\t\tGraphics.PreferredBackBufferWidth = Window.ClientBounds.Width;\n\t\t\t\tGraphics.PreferredBackBufferHeight = Window.ClientBounds.Height;\n\t\t\t\tEngine.Instance.UpdateView();\n\n\t\t\t\tresizing = false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/core/PS4Core.cs",
    "content": "﻿namespace Lens.Core {\n\tpublic class PS4Core : ConsoleCore {\n\t\tpublic override void Init(int width, int height, bool fullscreen) {\n\t\t\tbase.Init(width, height, fullscreen);\n\t\t\t\n\t\t\tGraphics.PreferredBackBufferWidth = 1920;\n\t\t\tGraphics.PreferredBackBufferHeight = 1080;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/core/SwitchCore.cs",
    "content": "﻿namespace Lens.Core {\n\tpublic class SwitchCore : ConsoleCore {\n\t\tpublic override void Init(int width, int height, bool fullscreen) {\n\t\t\tbase.Init(width, height, fullscreen);\n\t\t\t\n\t\t\tGraphics.PreferredBackBufferWidth = 1280;\n\t\t\tGraphics.PreferredBackBufferHeight = 720;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/core/XBoxCore.cs",
    "content": "﻿namespace Lens.Core {\n\tpublic class XBoxCore : ConsoleCore  {\n\t\tpublic override void Init(int width, int height, bool fullscreen) {\n\t\t\tbase.Init(width, height, fullscreen);\n\t\t\t\n\t\t\tGraphics.PreferredBackBufferWidth = 1920;\n\t\t\tGraphics.PreferredBackBufferHeight = 1080;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/Area.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.entity {\n\tpublic class Area {\n\t\tpublic TagLists Tagged;\n\t\tpublic EventListener EventListener;\n\t\tpublic bool NoInit;\n\t\t\n\t\tprivate static bool initedTags;\n\t\tprivate EntityList entities;\n\n\t\tpublic EntityList Entities => entities;\n\t\t\n\t\tpublic Area() {\n\t\t\tif (!initedTags) {\n\t\t\t\tinitedTags = true;\n\t\t\t\tInitTags();\n\t\t\t}\n\t\t\t\n\t\t\tEventListener = new EventListener();\n\t\t\tTagged = new TagLists();\n\t\t\tentities = new EntityList(this);\n\t\t}\n\n\t\tpublic void AutoRemove() {\n\t\t\tforeach (var e in entities.Entities) {\n\t\t\t\tif (e.Done) {\n\t\t\t\t\tentities.ToRemove.Add(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = entities.ToAdd.Count - 1; i >= 0; i--) {\n\t\t\t\tif (entities.ToAdd[i].Done) {\n\t\t\t\t\tentities.ToAdd.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tentities.AutoRemove();\n\t\t}\n\n\t\tpublic void Destroy() {\n\t\t\tforeach (var entity in entities.Entities) {\n\t\t\t\tentity.Destroy();\n\t\t\t}\n\n\t\t\tforeach (var list in Tagged.Lists) {\n\t\t\t\tlist.Clear();\n\t\t\t}\n\n\t\t\tEventListener.Destroy();\n\n\t\t\tAutoRemove();\n\n\t\t\tentities.Entities.Clear();\n\t\t\tentities.ToAdd.Clear();\n\t\t\tentities.ToRemove.Clear();\n\t\t}\n\n\t\tpublic Entity Add(Entity entity, bool postInit = true) {\n\t\t\tif (entity == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tif (entity.Area != null) {\n\t\t\t\tentity.Area = this;\n\t\t\t\tentities.Add(entity);\n\t\t\t\tTagged.Add(entity);\n\t\t\t\t\n\t\t\t\treturn entity;\n\t\t\t}\n\n\t\t\tentity.Area = this;\n\t\t\tentities.Add(entity);\n\t\t\tTagged.Add(entity);\n\n\t\t\tif (!NoInit) {\n\t\t\t\tentity.Init();\n\n\t\t\t\tif (postInit) {\n\t\t\t\t\tentity.PostInit();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn entity;\n\t\t}\n\n\t\tpublic void Remove(Entity entity) {\n\t\t\tentities.Remove(entity);\n\t\t\tTagged.Remove(entity);\n\t\t}\n\n\t\tpublic void Update(float dt) {\n\t\t\tentities.Update(dt);\n\t\t}\n\n\t\tpublic void Render() {\n\t\t\tentities.Render();\n\t\t}\n\n\t\tpublic void RenderDebug() {\n\t\t\tentities.RenderDebug();\n\t\t}\n\n\t\tpublic List<Entity> GetEntites() {\n\t\t\treturn entities.Entities;\n\t\t}\n\n\t\tpublic List<Entity> GetEntitesInRadius(Vector2 from, float radius, Type component = null) {\n\t\t\tvar list = new List<Entity>();\n\t\t\tvar d = radius * radius;\n\n\t\t\tforeach (var entity in entities.Entities) {\n\t\t\t\tif (component != null && !entity.HasComponent(component)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (entity.DistanceToSquared(from) <= d) {\n\t\t\t\t\tlist.Add(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn list;\n\t\t}\n\n\t\tprivate void InitTags() {\n\t\t\t\n\t\t}\n\n\t\tpublic Entity FindClosest(Vector2 to, int tag, Func<Entity, bool> filter) {\n\t\t\tvar min = float.MaxValue;\n\t\t\tEntity en = null;\n\t\t\t\n\t\t\tforeach (var e in Tagged[tag]) {\n\t\t\t\tif (filter(e)) {\n\t\t\t\t\tvar d = e.DistanceTo(to);\n\n\t\t\t\t\tif (d < min) {\n\t\t\t\t\t\tmin = d;\n\t\t\t\t\t\ten = e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn en;\n\t\t}\n\n\t\tpublic T Find<T>(Func<T, bool> filter = null) where T: Entity {\n\t\t\tforeach (var e in Entities.Entities) {\n\t\t\t\tif (e is T t && (filter == null || filter(t))) {\n\t\t\t\t\treturn t;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/BitTag.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Lens.entity {\n\tpublic class BitTag {\n\t\tpublic static BitTag[] Tags = new BitTag[32];\n\t\tpublic static byte Total;\n\t\t\n\t\tprivate static Dictionary<string, BitTag> byName = new Dictionary<string, BitTag>(StringComparer.OrdinalIgnoreCase);\n\t\t\n\t\tpublic int ID;\n\t\tpublic int Value;\n\t\tpublic string Name;\n\n\t\tpublic BitTag(string name) {\n\t\t\tif (Total >= 32) {\n\t\t\t\tthrow new Exception(\"Can't define more than 32 tags\");\n\t\t\t}\n\t\t\t\n\t\t\tif (byName.ContainsKey(name)) {\n\t\t\t\tthrow new Exception(\"Tag \" + name + \" is already defined!\");\n\t\t\t}\n\t\t\t\n\t\t\tName = name;\n\t\t\tID = Total;\n\t\t\tValue = 1 << Total;\n\n\t\t\tTags[ID] = this;\n\t\t\tbyName[name] = this;\n\n\t\t\tTotal++;\n\t\t}\n\t\t\n\t\tpublic static implicit operator int(BitTag tag) {\n\t\t\treturn tag.ID;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/Entity.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Lens.entity.component;\nusing Lens.entity.component.graphics;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.entity {\n\tpublic delegate void PositionChanged();\n\t\n\tpublic class Entity : Subscriber, IComparable {\n\t\tpublic Area Area;\n\t\t\n\t\tpublic bool Active = true;\n\t\tpublic bool Visible = true;\n\t\tpublic bool AlwaysActive;\n\t\tpublic bool AlwaysVisible;\n\t\tpublic bool OnScreen;\n\t\tpublic bool Done;\n\t\t\n\t\tpublic int Depth;\n\t\t\n\t\t#region Bounds and position\n\n\t\tprivate Vector2 position;\n\t\tpublic Vector2 Position {\n\t\t\tget => position;\n\t\t\tset {\n\t\t\t\tif (value != position) {\n\t\t\t\t\tposition = value;\n\t\t\t\t\tPositionChanged?.Invoke();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic Vector2 PositionWithoutTrigger {\n\t\t\tset => position = value;\n\t\t}\n\t\t\n\t\tpublic event PositionChanged PositionChanged;\n\t\tpublic float Width = 16;\n\t\tpublic float Height = 16;\n\t\tpublic bool Centered;\n\t\t\n\t\tpublic float X {\n\t\t\tget => Centered ? Position.X - Width / 2 : Position.X;\n\t\t\tset {\n\t\t\t\tposition.X = Centered ? value + Width / 2 : value;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\n\t\tpublic float Y {\n\t\t\tget => Centered ? Position.Y - Height / 2 : Position.Y;\n\t\t\tset {\n\t\t\t\tposition.Y = Centered ? value + Height / 2 : value;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\n\t\tpublic Vector2 Center {\n\t\t\tget => new Vector2(CenterX, CenterY);\n\t\t\tset {\n\t\t\t\tX = value.X - Width / 2;\n\t\t\t\tY = value.Y - Height / 2;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic Vector2 TopCenter {\n\t\t\tget => new Vector2(CenterX, Y);\n\t\t\tset {\n\t\t\t\tX = value.X - Width / 2;\n\t\t\t\tY = value.Y;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\n\t\tpublic Vector2 BottomCenter {\n\t\t\tget => new Vector2(CenterX, Bottom);\n\t\t\tset {\n\t\t\t\tX = value.X - Width / 2;\n\t\t\t\tY = value.Y - Height;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic float CenterX {\n\t\t\tget => X + Width / 2;\n\t\t\tset {\n\t\t\t\tX = value - Width / 2;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\n\t\tpublic float CenterY {\n\t\t\tget => Y + Height / 2;\n\t\t\tset {\n\t\t\t\tY = value - Height / 2;\n\t\t\t\tPositionChanged?.Invoke();\n\t\t\t}\n\t\t}\n\n\t\tpublic float Right {\n\t\t\tget => X + Width;\n\t\t\tset => X = value - Width;\n\t\t}\n\n\t\tpublic float Bottom {\n\t\t\tget => Y + Height;\n\t\t\tset => Y = value - Height;\n\t\t}\n\n\t\t#endregion\n\t\t\n\t\t#region Entity tags\n\n\t\tprivate int tag;\n\t\t\n\t\tpublic int Tag {\n\t\t\tget => tag;\n\n\t\t\tset {\n\t\t\t\tif (tag != value && Area != null) {\n\t\t\t\t\tfor (int i = 0; i < BitTag.Total; i++) {\n\t\t\t\t\t\tint check = 1 << i;\n\t\t\t\t\t\tbool add = (value & check) != 0;\n\t\t\t\t\t\tbool has = (tag & check) != 0;\n\n\t\t\t\t\t\tif (has != add) {\n\t\t\t\t\t\t\tif (add) {\n\t\t\t\t\t\t\t\tAddToTag(i);\n\t\t\t\t\t\t\t\tArea.Tagged[i].Add(this);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tRemoveFromTag(i);\n\t\t\t\t\t\t\t\tArea.Tagged[i].Remove(this);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\t\n\n\t\t\t\t\ttag = value;\n\t\t\t\t}\t\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual void AddToTag(int i) {\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in Components.Values) {\n\t\t\t\tc.OnTagAdded(i);\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected virtual void RemoveFromTag(int i) {\n\t\t\tif (Components == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var c in Components.Values) {\n\t\t\t\tc.OnTagRemoved(i);\n\t\t\t}\n\t\t}\n\n\t\tpublic bool HasTag(int tag) {\n\t\t\treturn (this.tag & 1 << tag) != 0;\n\t\t}\n\n\t\tpublic void AddTag(int tag) {\n\t\t\tTag |= 1 << tag;\n\t\t}\n\n\t\tpublic void RemoveTag(int tag) {\n\t\t\tTag &= ~(1 << tag);\n\t\t}\n\t\t\n\t\t#endregion\n\t\t\n\t\t#region Entity logic\n\n\t\tpublic GraphicsComponent GraphicsComponent;\n\t\tpublic Dictionary<Type, Component> Components;\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\tif (Components == null) {\n\t\t\t\tComponents = new Dictionary<Type, Component>();\n\t\t\t\tAddComponents();\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void AddComponents() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PostInit() {\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tcomponent.PostInit();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic virtual void Destroy() {\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tcomponent.Destroy();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic virtual void Update(float dt) {\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tcomponent.Update(dt);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic virtual bool HandleEvent(Event e) {\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tif (component.HandleEvent(e)) {\n\t\t\t\t\te.Handled = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (e.WasInEL) {\n\t\t\t\treturn e.Handled;\n\t\t\t}\n\n\t\t\te.WasInEL = true;\n\n\t\t\tif (Area.EventListener.Handle(e)) {\n\t\t\t\te.Handled = true;\n\t\t\t}\n\n\t\t\treturn e.Handled;\n\t\t}\n\n\t\tpublic virtual void Render() {\n\t\t\tif (GraphicsComponent != null && GraphicsComponent.Enabled) {\n\t\t\t\tGraphicsComponent.Render(false);\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void RenderDebug() {\n\t\t\t\n\t\t}\n\n\t\tpublic void RemoveSelf() {\n\t\t\tif (Area != null) {\n\t\t\t\tArea.Remove(this);\n\t\t\t\tArea = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddComponent(Component component) {\n\t\t\tif (component is GraphicsComponent g) {\n\t\t\t\tGraphicsComponent = g;\n\t\t\t}\n\t\t\t\n\t\t\tComponents[component.GetType()] = component;\n\n\t\t\tcomponent.Entity = this;\n\t\t\tcomponent.Init();\n\t\t}\n\t\t\n\t\tpublic void RemoveComponent<T>() {\n\t\t\tvar type = typeof(T);\n\t\t\t\n\t\t\tif (Components.TryGetValue(type, out var component)) {\n\t\t\t\tcomponent.Destroy();\n\t\t\t\tComponents.Remove(type);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Subscribe<T>(Area area = null) where T : Event {\n\t\t\t(area ?? Area).EventListener.Subscribe<T>(this);\n\t\t}\n\n\t\tpublic void Unsubscribe<T>(Area area = null) where T : Event {\n\t\t\t(area ?? Area).EventListener.Unsubscribe<T>(this);\n\t\t}\n\t\t\t\t\n\t\tpublic virtual T GetComponent<T>() where T : Component {\n\t\t\treturn (T) Components[typeof(T)];\n\t\t}\n\t\t\n\t\tpublic T GetAnyComponent<T>() where T : Component {\n\t\t\tvar type = typeof(T);\n\n\t\t\tforeach (var component in Components.Values) {\n\t\t\t\tvar t = component.GetType();\n\t\t\t\t\n\t\t\t\tif (t == type || t.IsSubclassOf(type)) {\n\t\t\t\t\treturn component as T;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic bool HasComponent(Type type) {\n\t\t\treturn Components.ContainsKey(type);\n\t\t}\n\n\t\tpublic bool HasComponent<T>() {\n\t\t\treturn Components.ContainsKey(typeof(T));\n\t\t}\n\n\t\tpublic bool TryGetComponent<T>(out T t) where T : Component {\n\t\t\tif (Components.TryGetValue(typeof(T), out var tmp)) {\n\t\t\t\tt = (T) tmp;\n\t\t\t\treturn true;\n\t\t\t}\n\n\n\t\t\tt = default(T);\n\t\t\treturn false;\n\t\t}\n\n\t\t#endregion\n\t\t\n\t\t#region Distance and angle\n\n\t\tpublic float DxTo(Entity entity) {\n\t\t\treturn entity.CenterX - CenterX;\n\t\t}\n\t\t\n\t\tpublic float DyTo(Entity entity) {\n\t\t\treturn entity.CenterY - CenterY;\n\t\t}\n\n\t\tpublic float DistanceToSquared(Entity entity) {\n\t\t\tfloat dx = DxTo(entity);\n\t\t\tfloat dy = DyTo(entity);\n\t\t\t\n\t\t\treturn dx * dx + dy * dy;\n\t\t}\n\n\t\tpublic float DxTo(Vector2 entity) {\n\t\t\treturn entity.X - CenterX;\n\t\t}\n\t\t\n\t\tpublic float DyTo(Vector2 entity) {\n\t\t\treturn entity.Y - CenterY;\n\t\t}\n\n\t\tpublic float DistanceToSquared(Vector2 entity) {\n\t\t\tfloat dx = DxTo(entity);\n\t\t\tfloat dy = DyTo(entity);\n\t\t\t\n\t\t\treturn dx * dx + dy * dy;\n\t\t}\n\n\t\tpublic float DistanceTo(Vector2 entity) {\n\t\t\treturn (float) Math.Sqrt(DistanceToSquared(entity));\n\t\t}\n\n\t\tpublic float DistanceToFromBottom(Vector2 entity) {\n\t\t\tvar dx = DxTo(entity);\n\t\t\tvar dy = entity.Y - Bottom;\n\t\t\treturn (float) Math.Sqrt(dx * dx + dy * dy);\n\t\t}\n\t\t\n\t\tpublic float DistanceTo(Entity entity) {\n\t\t\treturn (float) Math.Sqrt(DistanceToSquared(entity));\n\t\t}\n\t\t\n\t\tpublic float AngleTo(Entity entity) {\n\t\t\treturn (float) Math.Atan2(DyTo(entity), DxTo(entity));\n\t\t}\n\t\t\n\t\tpublic float AngleTo(Vector2 vec) {\n\t\t\treturn (float) Math.Atan2(DyTo(vec), DxTo(vec));\n\t\t}\n\t\t\n\t\t#endregion\n\t\t\n\t\t#region Simple collision\n\n\t\tpublic virtual bool Overlaps(Entity entity) {\n\t\t\treturn !(entity.X > Right ||\n\t\t\t         entity.Right < X ||\n\t\t\t         entity.Y > Bottom ||\n\t\t\t         entity.Bottom < Y);\n\t\t}\n\t\t\n\t\tpublic virtual bool Overlaps(Rectangle entity) {\n\t\t\treturn !(entity.X > Right ||\n\t\t\t         entity.Right < X ||\n\t\t\t         entity.Y > Bottom ||\n\t\t\t         entity.Bottom < Y);\n\t\t}\n\n\t\tpublic virtual bool Contains(Entity entity) {\n\t\t\treturn entity.X >= X && entity.Right <= Right\n\t\t\t                     && entity.Y >= Y && entity.Bottom <= Bottom;\n\t\t}\n\t\t\n\t\tpublic virtual bool Contains(Entity entity, float border) {\n\t\t\treturn entity.X >= X - border && entity.Right <= Right + border\n\t\t\t                     && entity.Y >= Y - border && entity.Bottom <= Bottom + border;\n\t\t}\n\n\t\tpublic virtual bool Contains(Vector2 point) {\n\t\t\treturn point.X >= X && point.X <= Right\n\t\t\t\t\t\t\t\t\t\t\t\t\t&& point.Y >= Y && point.Y <= Bottom;\n\t\t}\n\t\t\n\t\t#endregion\n\n\t\tpublic int CompareTo(object obj) {\n\t\t\treturn GetType().FullName.CompareTo(obj.GetType().FullName);\n\t\t}\n\n\t\tpublic virtual void RenderImDebug() {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/EntityList.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Lens.util;\nusing Lens.util.camera;\n\nnamespace Lens.entity {\n\tpublic class EntityList {\n\t\tpublic List<Entity> Entities = new List<Entity>();\n\t\tpublic List<Entity> ToAdd = new List<Entity>();\n\t\tpublic List<Entity> ToRemove = new List<Entity>();\n\n\t\tprivate Area Area;\n\n\t\tpublic EntityList(Area area) {\n\t\t\tArea = area;\n\t\t}\n\t\t\n\t\tpublic void Add(Entity entity) {\n\t\t\tToAdd.Add(entity);\n\t\t\tToRemove.Remove(entity);\n\t\t}\n\t\t\n\t\tpublic void Remove(Entity entity) {\n\t\t\tToRemove.Add(entity);\n\t\t\tToAdd.Remove(entity);\n\n\t\t\tif (entity.Area == Area) {\n\t\t\t\tentity.Done = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate bool CheckOnScreen(Entity entity) {\n\t\t\tif (Camera.Instance == null) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn Camera.Instance.Sees(entity);\n\t\t}\n\n\t\tpublic void AutoRemove() {\n\t\t\tif (ToRemove.Count > 0) {\n\t\t\t\ttry {\n\t\t\t\t\tfor (var i = ToRemove.Count - 1; i >= 0; i--) {\n\t\t\t\t\t\tvar entity = ToRemove[i];\n\n\t\t\t\t\t\tif (entity.Area == Area) {\n\t\t\t\t\t\t\tentity.Destroy();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tentity.Area.Tagged.Remove(entity);\n\t\t\t\t\t\tEntities.Remove(entity);\n\t\t\t\t\t}\n\n\t\t\t\t\tToRemove.Clear();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void AddNew() {\n\t\t\tif (ToAdd.Count > 0) {\n\t\t\t\tfor (int i = 0; i < ToAdd.Count; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar entity = ToAdd[i];\n\t\t\t\t\t\tEntities.Add(entity);\n\n\t\t\t\t\t\tif (!Area.NoInit && entity.Components == null) {\n\t\t\t\t\t\t\tentity.Area = Area;\n\t\t\t\t\t\t\tentity.Init();\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tToAdd.Clear();\n\t\t\t}\n\t\t}\n\n\t\tpublic void Update(float dt) {\n\t\t\tAutoRemove();\n\t\t\tAddNew();\n\n\t\t\tforeach (var entity in Entities) {\n\t\t\t\tentity.OnScreen = CheckOnScreen(entity);\n\n\t\t\t\tif ((entity.OnScreen || entity.AlwaysActive) && entity.Active) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tentity.Update(dt);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (entity.Done) {\n\t\t\t\t\tToRemove.Add(entity);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tEntities = Entities.OrderBy(e => e.Depth).ThenBy(e => e.Bottom).ToList();\n\t\t}\n\n\t\tpublic void Render() {\n\t\t\tforeach (var entity in Entities) {\n\t\t\t\tif ((entity.OnScreen || entity.AlwaysVisible) && entity.Visible) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tentity.Render();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void RenderDebug() {\n\t\t\tforeach (var entity in Entities) {\n\t\t\t\tif (entity.OnScreen || entity.AlwaysVisible) {\n\t\t\t\t\tentity.RenderDebug();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic Entity Find(Func<Entity, bool> filter) {\n\t\t\tforeach (var e in Entities) {\n\t\t\t\tif (filter(e)) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic Entity Find<T>() where T : Entity {\n\t\t\tvar t = typeof(T);\n\t\t\treturn Find(e => e.GetType() == t);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/Event.cs",
    "content": "namespace Lens.entity {\n\tpublic class Event {\n\t\tpublic bool Handled;\n\t\tpublic bool WasInEL;\n\t}\n}"
  },
  {
    "path": "Lens/entity/EventListener.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Lens.util;\n\nnamespace Lens.entity {\n\tpublic class EventListener {\n\t\tprivate Dictionary<Type, List<Subscriber>> subscribers = new Dictionary<Type, List<Subscriber>>();\n\n\t\tpublic void Copy(EventListener l) {\n\t\t\tforeach (var pair in l.subscribers) {\n\t\t\t\tif (!subscribers.ContainsKey(pair.Key)) {\n\t\t\t\t\tsubscribers[pair.Key] = new List<Subscriber>();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsubscribers[pair.Key].AddRange(pair.Value);\n\t\t\t}\n\t\t\t\n\t\t\tl.subscribers.Clear();\n\t\t}\n\t\t\n\t\tpublic bool Handle(Event e) {\n\t\t\tif (subscribers.TryGetValue(e.GetType(), out var subs)) {\n\t\t\t\tforeach (var sub in subs) {\n\t\t\t\t\tif (sub.HandleEvent(e)) {\n\t\t\t\t\t\te.Handled = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn e.Handled;\n\t\t}\n\n\t\tpublic void Subscribe<T>(Subscriber s) where T : Event {\n\t\t\tvar type = typeof(T);\n\n\t\t\tif (subscribers.TryGetValue(type, out var subs)) {\n\t\t\t\tsubs.Add(s);\n\t\t\t} else {\n\t\t\t\tsubs = new List<Subscriber>();\n\t\t\t\tsubs.Add(s);\n\t\t\t\t\n\t\t\t\tsubscribers[type] = subs;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Unsubscribe<T>(Subscriber s) where T : Event {\n\t\t\tif (subscribers.TryGetValue(typeof(T), out var subs)) {\n\t\t\t\tsubs.Remove(s);\n\t\t\t}\n\t\t}\n\n\t\tpublic void Destroy() {\n\t\t\tsubscribers.Clear();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/Subscriber.cs",
    "content": "namespace Lens.entity {\n\tpublic interface Subscriber {\n\t\tbool HandleEvent(Event e);\n\t}\n}"
  },
  {
    "path": "Lens/entity/TagLists.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Lens.entity {\n\tpublic class TagLists {\n\t\tpublic List<Entity>[] Lists = new List<Entity>[32];\n\t\tpublic List<Entity> this[int index] => Lists[index];\n\n\t\tpublic TagLists() {\n\t\t\tfor (var i = 0; i < Lists.Length; i++) {\n\t\t\t\tLists[i] = new List<Entity>();\n\t\t\t}\n\t\t}\n\n\t\tpublic void Add(Entity entity) {\n\t\t\t// Most entities don't have any tags, avoid for loop\n\t\t\tif (entity.Tag == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tint tag = entity.Tag;\n\n\t\t\tfor (int i = 0; i < BitTag.Total; i++) {\n\t\t\t\tif ((tag & 1 << i) != 0) {\n\t\t\t\t\tvar l = Lists[i];\n\n\t\t\t\t\tif (!l.Contains(entity)) {\n\t\t\t\t\t\tl.Add(entity);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Remove(Entity entity) {\n\t\t\tvar tag = entity.Tag;\n\n\t\t\tfor (int i = 0; i < BitTag.Total; i++) {\n\t\t\t\tif ((tag & 1 << i) != 0) {\n\t\t\t\t\tLists[i].Remove(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/Component.cs",
    "content": "﻿namespace Lens.entity.component {\n\tpublic class Component {\n\t\tpublic Entity Entity;\n\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void PostInit() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool HandleEvent(Event e) {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool Send(Event e) {\n\t\t\treturn Entity.HandleEvent(e);\n\t\t}\n\n\t\tpublic T GetComponent<T>() where T : Component {\n\t\t\treturn Entity.GetComponent<T>();\n\t\t}\n\n\t\tpublic virtual void RenderDebug() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void OnTagAdded(int i) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void OnTagRemoved(int i) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/SaveableComponent.cs",
    "content": "using Lens.util.file;\n\nnamespace Lens.entity.component {\n\tpublic class SaveableComponent : Component {\n\t\tpublic virtual void Save(FileWriter stream) {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Load(FileReader stream) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/graphics/GraphicsComponent.cs",
    "content": "﻿using ImGuiNET;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.entity.component.graphics {\n\tpublic class GraphicsComponent : Component {\n\t\tpublic bool Flipped;\n\t\tpublic bool FlippedVerticaly;\n\t\tpublic bool CustomFlip;\n\t\tpublic bool Enabled = true;\n\t\tpublic Vector2 Offset;\n\t\t\n\t\tpublic virtual void Render(bool shadow) {\n\t\t\t\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tbase.RenderDebug();\n\t\t\tImGui.Checkbox(\"Visible\", ref Enabled);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/graphics/ImageComponent.cs",
    "content": "﻿using Lens.assets;\nusing Lens.graphics;\n\nnamespace Lens.entity.component.graphics {\n\tpublic class ImageComponent : GraphicsComponent {\n\t\tpublic TextureRegion Sprite;\n\t\t\n\t\tpublic ImageComponent(string image) {\n\t\t\tSprite = Textures.Get(image);\n\t\t}\n\n\t\tpublic override void Render(bool shadow) {\n\t\t\tGraphics.Render(Sprite, Entity.Position);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/logic/EntityState.cs",
    "content": "﻿namespace Lens.entity.component.logic {\n\tpublic class EntityState {\n\t\tpublic Entity Self;\n\t\tpublic float T;\n\n\t\tpublic virtual void Assign(Entity self) {\n\t\t\tSelf = self;\n\t\t}\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\tT += dt;\n\t\t}\n\n\t\tpublic void Become<T>() {\n\t\t\tSelf.GetComponent<StateComponent>().Become<T>();\n\t\t}\n\n\t\tpublic virtual void HandleEvent(Event e) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/logic/InterestingComponent.cs",
    "content": "﻿namespace Lens.entity.component.logic {\n\tpublic class InterestingComponent : Component {\n\t\t\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/logic/ShakeComponent.cs",
    "content": "﻿using System;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.entity.component.logic {\n\tpublic class ShakeComponent : Component {\n\t\tpublic static float Modifier = 1;\n\n\t\tpublic float Amount;\n\t\tpublic float Angle;\n\t\tpublic Vector2 Position;\n\t\tpublic Vector2 PushDirection;\n\t\tpublic float Push;\n\t\tpublic float Time;\n\t\t\n\t\tpublic override void Update(float dt) {\n\t\t\tTime += dt * 10f;\n\n\t\t\tif (Amount <= 0.1f) {\n\t\t\t\tAngle = 0;\n\t\t\t\tPosition.X = 0;\n\t\t\t\tPosition.Y = 0;\n\t\t\t} else {\n\t\t\t\tvar a = Math.Min(4, Amount * Amount * 0.07f) * Modifier;\n\n\t\t\t\tAngle = Noise.Generate(Time) * a * 0.01f;\n\t\t\t\tPosition.X = Noise.Generate(Time * 2f + 32) * a;\n\t\t\t\tPosition.Y = Noise.Generate(Time * 2f + 64) * a;\t\n\t\t\t}\n\n\t\t\tif (Push >= 0.01f) {\n\t\t\t\tvar force = Push * Push * 1.2f * (Modifier * 0.3f);\n\t\t\t\tPosition.X += PushDirection.X * force;\n\t\t\t\tPosition.Y += PushDirection.Y * force;\n\t\t\t}\n\t\t\t\n\t\t\tAmount = Math.Max(0, Amount - dt * 10f);\n\t\t\tPush = Math.Max(0, Push - dt * 20f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/logic/StateChangedEvent.cs",
    "content": "using System;\n\nnamespace Lens.entity.component.logic {\n\tpublic class StateChangedEvent : Event {\n\t\tpublic Type NewState;\n\t\tpublic EntityState State;\n\t}\n}"
  },
  {
    "path": "Lens/entity/component/logic/StateComponent.cs",
    "content": "﻿using System;\nusing ImGuiNET;\nusing Lens.entity.component.graphics;\n\nnamespace Lens.entity.component.logic {\n\tpublic class StateComponent : Component {\n\t\tprivate EntityState state;\n\t\tprivate Type newState;\n\n\t\tpublic bool PauseOnChange;\n\t\t\n\t\tpublic Type State {\n\t\t\tget => state.GetType();\n\t\t\t\n\t\t\tset {\n\t\t\t\tif (state == null || state.GetType() != value) {\n\t\t\t\t\tnewState = value;\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tpublic Type ForceState {\n\t\t\tset => newState = value;\n\t\t}\n\n\t\tpublic EntityState StateInstance => state;\n\t\tpublic int Pause;\n\t\t\n\t\tpublic void Become<T>(bool force = false) {\n\t\t\tif (force) {\n\t\t\t\tForceState = typeof(T);\n\t\t\t} else {\n\t\t\t\tState = typeof(T);\n\t\t\t}\n\t\t}\n\n\t\tpublic void PushState(EntityState st) {\n\t\t\tstate?.Destroy();\n\n\t\t\tstate = st;\n\t\t\tstate.Assign(Entity);\n\t\t\tstate.Init();\n\n\t\t\tSend(new StateChangedEvent {\n\t\t\t\tNewState = state.GetType(),\n\t\t\t\tState = state\n\t\t\t});\n\t\t\t\n\t\t\tif (PauseOnChange) {\n\t\t\t\tPauseOnChange = false;\n\t\t\t\tPause = 1;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (newState != null) {\n\t\t\t\tPushState((EntityState) Activator.CreateInstance(newState));\n\t\t\t\tnewState = null;\n\t\t\t}\n\n\t\t\tif (!Engine.EditingLevel && Pause < 1) {\n\t\t\t\tstate?.Update(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic override bool HandleEvent(Event e) {\n\t\t\tstate?.HandleEvent(e);\n\t\t\treturn base.HandleEvent(e);\n\t\t}\n\n\t\tpublic override void RenderDebug() {\n\t\t\tImGui.Text($\"State: {(state == null ? \"null\" : state.GetType().Name)}\");\n\t\t\tvar paused = Pause > 0;\n\n\t\t\tif (ImGui.Checkbox(\"Paused\", ref paused)) {\n\t\t\t\tPause = paused ? 1 : 0;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/game/GameState.cs",
    "content": "﻿using Lens.entity;\n\nnamespace Lens.game {\n\tpublic class GameState {\n\t\tpublic static bool RenderDebug = false;\n\n\t\tpublic Area Area = new Area();\n\t\tpublic Area Ui = new Area();\n\t\tpublic float Time;\n\n\t\tprivate bool paused;\n\t\t\n\t\tpublic bool Paused {\n\t\t\tget {\n\t\t\t\treturn paused;\n\t\t\t}\n\t\t\t\n\t\t\tset {\n\t\t\t\tif (paused != value) {\n\t\t\t\t\tpaused = value;\n\n\t\t\t\t\tif (paused) {\n\t\t\t\t\t\tOnPause();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tOnResume();\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void OnActivated() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void OnDeactivated() {\n\t\t\t\n\t\t}\n\n\t\tprotected virtual void OnPause() {\n\t\t\t\n\t\t}\n\n\t\tprotected virtual void OnResume() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\tArea?.Destroy();\n\t\t\tUi.Destroy();\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\tUi.Update(dt); // Update ui first for screenshake compression\n\t\t\tArea?.Update(dt);\n\n\t\t\tif (!Paused) {\n\t\t\t\tTime += dt;\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void Render() {\n\t\t\tArea?.Render();\n\n\t\t\tif (RenderDebug) {\n\t\t\t\tArea?.RenderDebug();\n\t\t\t}\n\t\t}\n\n\t\tpublic virtual void RenderUi() {\n\t\t\tUi.Render();\n\n\t\t\tif (RenderDebug) {\n\t\t\t\tUi.RenderDebug();\n\t\t\t}\n\n\t\t\tEngine.Instance.RenderUi();\n\t\t}\n\n\t\tpublic virtual void RenderNative() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual bool NativeRender() {\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/ColorUtils.cs",
    "content": "using System;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.graphics {\n\tpublic static class ColorUtils {\n\t\tpublic static Vector4 White = new Vector4(1, 1, 1, 1);\n\t\tpublic static Vector4 Black = new Vector4(0, 0, 0, 1);\n\t\tpublic static Vector4 HalfBlack = new Vector4(0, 0, 0, 0.5f);\n\t\tpublic static Color WhiteColor = Color.White;\n\t\tpublic static Color HalfWhiteColor = new Color(1f, 1f, 1f, 0.5f);\n\t\tpublic static Color GrayColor = new Color(0.5f, 0.5f, 0.5f, 1f);\n\t\tpublic static Color BlackColor = Color.Black;\n\t\t\n\t\tpublic static Color FromHex(string hex) {\n\t\t\tif (!hex.StartsWith(\"#\")) {\n\t\t\t\thex = $\"#{hex}\";\n\t\t\t}\n\t\t\t\n\t\t\tif (hex.Length != 7) {\n\t\t\t\treturn Color.White;\n\t\t\t}\n\t\t\t\n\t\t\tColor color = new Color();\n\n\t\t\tcolor.R = (byte) int.Parse(hex.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);\n\t\t\tcolor.G = (byte) int.Parse(hex.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);\n\t\t\tcolor.B = (byte) int.Parse(hex.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);\n\t\t\tcolor.A = 255;\n\t\t\t\n\t\t\treturn color;\n\t\t}\n\n\t\tpublic static bool Compare(byte a, byte b, byte ac) {\n\t\t\treturn Math.Abs(a - b) <= ac;\n\t\t}\n\t\t\n\t\tpublic static bool Compare(Color a, Color b, byte ac) {\n\t\t\treturn Compare(a.R, b.R, ac) && Compare(a.G, b.G, ac) && Compare(a.B, b.B, ac);\n\t\t}\n\n\t\tpublic static Color FromHSV(float H, float S, float V) {\n\t\t\tdouble R;\n\t\t\tdouble G;\n\t\t\tdouble B;\n\t\t\tint I;\n\t\t\tfloat F;\n\t\t\tfloat P;\n\t\t\tfloat Q;\n\t\t\tfloat T;\n\t\t\tH = (float) Math.Max(0.0, Math.Min(360.0, H));\n\t\t\tS = (float) Math.Max(0.0, Math.Min(100.0, S));\n\t\t\tV = (float) Math.Max(0.0, Math.Min(100.0, V));\n\t\t\tS /= 100;\n\t\t\tV /= 100;\n\t\t\tH /= 60;\n\t\t\tI = (int) Math.Floor(H);\n\t\t\tF = H - I;\n\t\t\tP = V * (1 - S);\n\t\t\tQ = V * (1 - S * F);\n\t\t\tT = V * (1 - S * (1 - F));\n\n\t\t\tswitch (I) {\n\t\t\t\tcase 0: {\n\t\t\t\t\tR = Math.Round(255 * V);\n\t\t\t\t\tG = Math.Round(255 * T);\n\t\t\t\t\tB = Math.Round(255 * P);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 1: {\n\t\t\t\t\tR = Math.Round(255 * Q);\n\t\t\t\t\tG = Math.Round(255 * V);\n\t\t\t\t\tB = Math.Round(255 * P);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 2: {\n\t\t\t\t\tR = Math.Round(255 * P);\n\t\t\t\t\tG = Math.Round(255 * V);\n\t\t\t\t\tB = Math.Round(255 * T);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 3: {\n\t\t\t\t\tR = Math.Round(255 * P);\n\t\t\t\t\tG = Math.Round(255 * Q);\n\t\t\t\t\tB = Math.Round(255 * V);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase 4: {\n\t\t\t\t\tR = Math.Round(255 * T);\n\t\t\t\t\tG = Math.Round(255 * P);\n\t\t\t\t\tB = Math.Round(255 * V);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tR = Math.Round(255 * V);\n\t\t\t\t\tG = Math.Round(255 * P);\n\t\t\t\t\tB = Math.Round(255 * Q);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new Color((float) R / 255.0f, (float) G / 255.0f, (float) B / 255.0f, 1);\n\t\t}\n\t\t\n\t\tpublic static Color Mod(Color c) {\n\t\t\tvar color = new Color();\n\n\t\t\tvar f = 30;\n\n\t\t\tcolor.R = (byte) MathUtils.Clamp(0, 255, c.R + util.math.Rnd.Int(-f, f));\n\t\t\tcolor.G = (byte) MathUtils.Clamp(0, 255, c.G + util.math.Rnd.Int(-f, f));\n\t\t\tcolor.B = (byte) MathUtils.Clamp(0, 255, c.B + util.math.Rnd.Int(-f, f));\n\t\t\tcolor.A = 255;\n\n\t\t\treturn color;\n\t\t}\n\n\t\tpublic static Vector4 ToVector4(this Color color) {\n\t\t\treturn new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);\n\t\t}\n\n\t\tpublic static Vector4 Mix(Vector4 a, Vector4 b, float proportion) {\n\t\t\tif (proportion <= 0.04f) {\n\t\t\t\treturn a;\n\t\t\t} else if (proportion >= 0.96f) {\n\t\t\t\treturn b;\n\t\t\t}\n\t\t\t\n\t\t\treturn b * proportion + a * (1f - proportion);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/Graphics.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended.BitmapFonts;\n\nnamespace Lens.graphics {\n\tpublic static class Graphics {\n\t\tpublic static SpriteBatch Batch;\n\t\tpublic static Color Color = Color.White;\n\t\t\n\t\tpublic static void Init() {\n\t\t\tBatch = new SpriteBatch(Engine.GraphicsDevice);\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tBatch.Dispose();\n\t\t}\n\n\t\tpublic static void Clear(Color color) {\n\t\t\tEngine.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, color, 1, 0);\n\t\t}\n\n\t\tpublic static void Render(TextureRegion region, Vector2 position) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(region.Texture, position, region.Source, Color);\n\t\t}\n\n\t\tpublic static void Render(TextureRegion region, Vector2 position, float a, Vector2 origin) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(region.Texture, position, region.Source, Color, a, origin, Vector2.One, SpriteEffects.None, 0);\n\t\t}\n\n\t\tpublic static void Render(TextureRegion region, Vector2 position, float a, Vector2 origin, Vector2 scale, SpriteEffects flip = SpriteEffects.None) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(region.Texture, position, region.Source, Color, a, origin, scale, flip, 0);\n\t\t}\n\n\t\tpublic static void Render(Texture2D texture, Vector2 position) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(texture, position, texture.Bounds, Color);\n\t\t}\n\t\t\n\t\tpublic static void Render(Texture2D texture, Vector2 position, float a, Vector2 origin) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(texture, position, texture.Bounds, Color, a, origin, Vector2.One, SpriteEffects.None, 0);\n\t\t}\n\t\t\n\t\tpublic static void Render(Texture2D texture, Vector2 position, float a, Vector2 origin, Vector2 scale, SpriteEffects flip = SpriteEffects.None) {\n\t\t\t// position.Floor();\n\t\t\tBatch.Draw(texture, position, texture.Bounds, Color, a, origin, scale, flip, 0);\n\t\t}\n\t\t\n\t\tpublic static void Print(string str, BitmapFont font, int x, int y) {\n\t\t\tBatch.DrawString(font, str, new Vector2(x + 1, y - 3), Color);\n\t\t}\n\t\t\n\t\tpublic static void Print(string str, BitmapFont font, int y, bool ui = true) {\n\t\t\tBatch.DrawString(font, str, new Vector2(((ui ? Display.UiWidth : Display.Width) - font.MeasureString(str).Width) / 2f + 1, y - 3), Color);\n\t\t}\n\n\t\tpublic static void Print(string str, BitmapFont font, Vector2 position) {\n\t\t\tBatch.DrawString(font, str, new Vector2(position.X + 1, position.Y - 2), Color);\n\t\t}\n\n\t\tpublic static void Print(string str, BitmapFont font, Vector2 position, float angle, Vector2 origin, Vector2 scale, SpriteEffects effects = SpriteEffects.None) {\n\t\t\tBatch.DrawString(font, str, new Vector2(position.X + 1, position.Y - 2), Color, angle, origin, scale, effects, 0f);\n\t\t}\n\n\t\tpublic static SpriteEffects ParseEffect(bool h, bool v) {\n\t\t\tif (h && v) {\n\t\t\t\treturn SpriteEffects.FlipVertically | SpriteEffects.FlipHorizontally;\n\t\t\t}\n\t\t\t\n\t\t\tif (v) {\n\t\t\t\treturn SpriteEffects.FlipVertically;\n\t\t\t}\n\t\t\t\n\t\t\treturn h ? SpriteEffects.FlipHorizontally : SpriteEffects.None;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/TextureRegion.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.graphics {\n\tpublic class TextureRegion {\n\t\tpublic Texture2D Texture;\n\t\tpublic Rectangle Source;\n\t\tpublic Vector2 Center;\n\n\t\tpublic float X => Source.X;\n\t\tpublic float Y => Source.Y;\n\t\tpublic float Width => Source.Width;\n\t\tpublic float Height => Source.Height;\n\t\t\n\t\tpublic TextureRegion() {\n\t\t\t\n\t\t}\n\n\t\tpublic TextureRegion(Texture2D texture) {\n\t\t\tTexture = texture;\n\t\t\tSource = texture.Bounds;\n\t\t\tCenter = new Vector2(Source.Width / 2f, Source.Height / 2f);\n\t\t}\n\t\n\t\tpublic TextureRegion(TextureRegion texture, int w, int h) {\n\t\t\tTexture = texture.Texture;\n\t\t\tSource = new Rectangle {\n\t\t\t\tX = texture.Source.X, Y = texture.Source.Y, Width = w, Height = h\n\t\t\t};\n\t\t\t\n\t\t\tCenter = new Vector2(Source.Width / 2f, Source.Height / 2f);\n\t\t}\n\n\t\tpublic TextureRegion(Texture2D texture, Rectangle source) {\n\t\t\tTexture = texture;\n\t\t\tSource = source;\n\t\t\tCenter = new Vector2(Source.Width / 2f, Source.Height / 2f);\n\t\t}\n\n\t\tpublic void Set(TextureRegion region) {\n\t\t\tif (region == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTexture = region.Texture;\n\t\t\tSource = new Rectangle(region.Source.X, region.Source.Y, region.Source.Width, region.Source.Height);\n\t\t\tCenter = new Vector2(Source.Width / 2f, Source.Height / 2f);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/Animation.cs",
    "content": "﻿using Lens.util.math;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.graphics.animation {\n\tpublic delegate void AnimationCallback();\n\t\n\tpublic class Animation {\n\t\tpublic AnimationData Data;\n\t\tpublic AnimationCallback OnEnd;\n\t\t\n\t\tprivate AnimationFrame frame;\n\t\t\n\t\tprivate uint currentFrame;\n\t\tpublic uint StartFrame { get; private set; }\n\t\tpublic uint EndFrame { get; private set; }\n\t\t\n\t\tpublic float SpeedModifier = 1f;\n\t\tpublic bool Paused;\n\t\tpublic bool AutoStop;\n\t\tpublic bool Reverse;\n\n\t\tpublic uint TagSize => (EndFrame - StartFrame + 1);\n\n\t\tpublic uint Frame {\n\t\t\tget => currentFrame;\n\t\t\tset {\n\t\t\t\tvar v = value % TagSize;\n\n\t\t\t\tif (v != currentFrame) {\n\t\t\t\t\tcurrentFrame = v;\n\t\t\t\t\tReadFrame();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate string layer;\n\t\tprivate string tag;\n\n\t\tpublic string Layer {\n\t\t\tget => layer;\n\n\t\t\tset {\n\t\t\t\tif (layer == value) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlayer = value;\n\t\t\t\tReadFrame();\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic string Tag {\n\t\t\tget => tag;\n\n\t\t\tset {\n\t\t\t\tcurrentFrame = 0;\n\t\t\t\ttag = value;\n\t\t\t\tPaused = false;\n\t\t\t\t\n\t\t\t\tReadFrame();\n\t\t\t}\n\t\t}\n\t\t\n\t\tprivate float timer;\n\n\t\tpublic float Timer {\n\t\t\tget => timer;\n\n\t\t\tset {\n\t\t\t\ttimer = value;\n\n\t\t\t\tif (timer >= frame.Duration) {\n\t\t\t\t\ttimer = 0;\n\n\t\t\t\t\tif (!AutoStop || currentFrame < EndFrame - StartFrame) {\n\t\t\t\t\t\tFrame++;\n\t\t\t\t\t\n\t\t\t\t\t\tif (SkipNextFrame) {\n\t\t\t\t\t\t\tSkipNextFrame = false;\n\t\t\t\t\t\t\tFrame++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tReadFrame();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tPaused = true;\n\t\t\t\t\t\tOnEnd?.Invoke();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool PingGoingForward;\n\t\tpublic bool SkipNextFrame;\n\t\t\n\t\tpublic Animation(AnimationData data, string layer = null) {\n\t\t\tData = data;\n\n\t\t\tif (layer != null) {\n\t\t\t\tLayer = layer;\n\t\t\t} else {\n\t\t\t\tReadFrame(true);\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tpublic void Update(float dt) {\n\t\t\tif (!Paused) {\n\t\t\t\tvar frame = currentFrame;\n\t\t\t\tTimer += dt * SpeedModifier;\n\t\t\t\tvar newFrame = currentFrame;\n\n\t\t\t\tif (frame != newFrame && newFrame == 0) {\n\t\t\t\t\tOnEnd?.Invoke();\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void Render(Vector2 position, bool flipped = false, bool vflip = false) {\n\t\t\tGraphics.Render(frame.Texture, position, 0, Vector2.Zero, Vector2.One, Graphics.ParseEffect(flipped, vflip));\n\t\t}\n\n\t\tpublic TextureRegion GetCurrentTexture() {\n\t\t\treturn frame.Texture;\n\t\t}\n\t\t\n\t\tpublic TextureRegion GetFirstCurrent() {\n\t\t\treturn tag == null ? Data.GetFrame(layer, 0)?.Texture : GetFrame(tag, 0);\n\t\t}\n\t\t\n\t\tpublic void Reset() {\n\t\t\tFrame = 0;\n\t\t}\n\n\t\tpublic bool HasTag(string tag) {\n\t\t\treturn Data.Tags.ContainsKey(tag);\n\t\t}\n\n\t\tprivate void ReadFrame(bool rand = false) {\n\t\t\tvar nullableTag = Data.GetTag(tag);\n\n\t\t\tif (nullableTag == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar currentTag = nullableTag.Value;\n\n\t\t\tStartFrame = currentTag.StartFrame;\n\t\t\tEndFrame = currentTag.EndFrame;\n\t\t\t\n\t\t\tif (rand) {\n\t\t\t\tcurrentFrame = (uint) Rnd.Int(0, (int) (currentTag.EndFrame - currentTag.StartFrame));\n\t\t\t}\n\t\t\t\n\t\t\tvar frame = Data.GetFrame(layer, currentTag.Direction.GetFrameId(this, Reverse));\n\n\t\t\tif (frame != null) {\n\t\t\t\tthis.frame = (AnimationFrame) frame;\n\t\t\t}\n\t\t}\n\n\t\tpublic TextureRegion GetFrame(string tag, int frame) {\n\t\t\tif (tag == null || !Data.Tags.TryGetValue(tag, out var t)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn Data.GetFrame(layer, (uint) (t.StartFrame + frame))?.Texture;\n\t\t}\n\n\t\tpublic void Randomize() {\n\t\t\tFrame = (uint) Rnd.Int((int) TagSize);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/AnimationData.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Lens.assets;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.graphics.animation {\n\tpublic class AnimationData {\n\t\tpublic Dictionary<string, List<AnimationFrame>> Layers = new Dictionary<string, List<AnimationFrame>>();\n\t\tpublic Dictionary<string, AnimationTag> Tags = new Dictionary<string, AnimationTag>();\n\t\tpublic Dictionary<string, TextureRegion> Slices = new Dictionary<string, TextureRegion>();\n\t\tpublic Texture2D Texture;\n\n\t\tpublic AnimationData Recolor(Color[] from, Color[] to) {\n\t\t\tif (from.Length != to.Length) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tAnimationData data = new AnimationData();\n\t\t\t\n\t\t\treturn data;\n\t\t}\n\t\t\n\t\tpublic AnimationTag? GetTag(string tagName) {\n\t\t\tAnimationTag tag;\n\n\t\t\tif (tagName == null) {\n\t\t\t\ttag = Tags.FirstOrDefault().Value;\n\t\t\t} else if (!Tags.TryGetValue(tagName, out tag)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn tag;\n\t\t}\n\n\t\tpublic TextureRegion GetSlice(string name, bool error = true) {\n\t\t\tif (Slices.TryGetValue(name, out var region)) {\n\t\t\t\treturn region;\n\t\t\t}\n\n\t\t\tif (!error) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tLog.Warning($\"Unable to find slice {name}\");\n\t\t\treturn Textures.Missing;\n\t\t}\n\t\t\n\t\tpublic AnimationFrame? GetFrame(string layer, uint id) {\n\t\t\tList<AnimationFrame> frames;\n\n\t\t\tif (layer == null) {\n\t\t\t\tframes = Layers.FirstOrDefault().Value;\n\t\t\t} else if (!Layers.TryGetValue(layer, out frames)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (frames.Count < id) {\n\t\t\t\tLog.Warning($\"Unable to find frame {layer}:{id}\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn frames[(int) id];\n\t\t}\n\n\t\tpublic Animation CreateAnimation(string layer = null) {\n\t\t\treturn new Animation(this, layer);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/AnimationDirection.cs",
    "content": "﻿namespace Lens.graphics.animation {\n\tpublic enum AnimationDirection {\n\t\tForward = 0,\n\t\tBackwards = 1,\n\t\tPingPong = 2\n\t}\n\n\tstatic class AnimationDirectionMethods {\n\t\tpublic static uint GetFrameId(this AnimationDirection direction, Animation animation, bool reverse) {\n\t\t\tswitch (direction) {\n\t\t\t\tcase AnimationDirection.Forward: return reverse ? animation.EndFrame - animation.Frame : animation.StartFrame + animation.Frame;\n\t\t\t\tcase AnimationDirection.Backwards: return reverse ? animation.StartFrame + animation.Frame : animation.EndFrame - animation.Frame;\n\t\t\t\t\n\t\t\t\tdefault: {\n\t\t\t\t\tuint frame;\n\t\t\t\t\t\n\t\t\t\t\tif (animation.PingGoingForward) {\n\t\t\t\t\t\tframe = animation.StartFrame + animation.Frame;\n\n\t\t\t\t\t\tif (frame == animation.EndFrame) {\n\t\t\t\t\t\t\tanimation.PingGoingForward = false;\n\t\t\t\t\t\t\tanimation.SkipNextFrame = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tframe = animation.EndFrame - animation.Frame;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (frame == animation.StartFrame) {\n\t\t\t\t\t\t\tanimation.PingGoingForward = true;\n\t\t\t\t\t\t\tanimation.SkipNextFrame = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn frame;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/AnimationFrame.cs",
    "content": "﻿using Microsoft.Xna.Framework;\n\nnamespace Lens.graphics.animation {\n\tpublic struct AnimationFrame {\n\t\tpublic float Duration;\n\t\tpublic Rectangle Bounds;\n\t\tpublic TextureRegion Texture;\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/AnimationTag.cs",
    "content": "﻿namespace Lens.graphics.animation {\n\tpublic struct AnimationTag {\n\t\tpublic uint StartFrame;\n\t\tpublic uint EndFrame;\n\t\tpublic AnimationDirection Direction;\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/ColorSet.cs",
    "content": "﻿using Lens.util;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.graphics.animation {\n\tpublic class ColorSet {\n\t\tpublic readonly Color[] From;\n\t\tpublic readonly Color[] To;\n\t\tpublic readonly int Id;\n\n\t\tinternal ColorSet(Color[] from, Color[] to, int id) {\n\t\t\tFrom = from;\n\t\t\tTo = to;\n\t\t\tId = id;\n\n\t\t\tif (from.Length != to.Length) {\n\t\t\t\tLog.Error(\"Invalid colorset\");\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/animation/ColorSets.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.graphics.animation {\n\tpublic static class ColorSets {\n\t\tpublic static List<ColorSet> Colors = new List<ColorSet>();\n\n\t\tpublic static ColorSet New(Color[] from, Color[] to) {\n\t\t\tvar set = new ColorSet(from, to, Colors.Count);\n\t\t\tColors.Add(set);\n\n\t\t\treturn set;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/gamerenderer/DefaultGameRenderer.cs",
    "content": "﻿using Lens.util.camera;\n\nnamespace Lens.graphics.gamerenderer {\n\tpublic class DefaultGameRenderer : GameRenderer {\n\t\tpublic override void Render() {\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, DefaultRasterizerState, GameEffect, \n\t\t\t\tCamera.Instance == null ? Engine.ScreenMatrix : Camera.Instance.Matrix * Engine.ScreenMatrix);\n\t\t\t\n\t\t\tEngine.Instance.State.Render();\n\t\t\t\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/gamerenderer/GameRenderer.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\n\nnamespace Lens.graphics.gamerenderer {\n\tpublic class GameRenderer {\n\t\tpublic static bool EnableBatcher = true;\n\t\t\n\t\tpublic RenderTarget2D GameTarget;\n\t\tpublic RenderTarget2D UiTarget;\n\n\t\tpublic static SpriteSortMode DefaultSortMode = SpriteSortMode.Deferred;\n\n\t\tpublic SpriteSortMode SpriteSortMode = DefaultSortMode;\n\t\tpublic BlendState BlendState = BlendState.NonPremultiplied;\n\t\tpublic SamplerState SamplerState = SamplerState.PointClamp;\n\t\tpublic DepthStencilState DepthStencilState = DepthStencilState.None;\n\t\tpublic RasterizerState DefaultRasterizerState = RasterizerState.CullNone;\n\t\tpublic RasterizerState ClipRasterizerState = new RasterizerState {\n\t\t\tScissorTestEnable = true\n\t\t};\n\t\t\n\t\tpublic Effect GameEffect;\n\t\tpublic Effect UiEffect;\n\t\tpublic Effect SurfaceEffect;\n\t\tpublic Color Bg = Color.Black;\n\n\t\tpublic virtual void Begin() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void End() {\n\t\t\t\n\t\t}\n\t\t\n\t\tpublic virtual void Render() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\tUiTarget?.Dispose();\n\t\t\tGameTarget?.Dispose();\n\t\t}\n\n\t\tpublic virtual void Resize(int width, int height) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/gamerenderer/NativeGameRenderer.cs",
    "content": "using Lens.util.camera;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.graphics.gamerenderer {\n\tpublic class NativeGameRenderer : GameRenderer {\n\t\tpublic override void Render() {\n\t\t\tBegin();\n\t\t\tEngine.Instance.State.Render();\n\t\t\tEnd();\n\t\t\t\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, DefaultRasterizerState, GameEffect, Matrix.Identity * Matrix.CreateScale(2));\n\t\t\tEngine.Instance.State.RenderUi();\n\t\t\tEnd();\n\n\t\t\tEngine.Instance.State.RenderNative();\n\t\t}\n\n\t\tpublic override void Begin() {\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, DefaultRasterizerState, GameEffect, \n\t\t\t\tCamera.Instance == null ? Matrix.Identity : Camera.Instance.Matrix);\n\t\t}\n\n\t\tpublic override void End() {\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/graphics/gamerenderer/PixelPerfectGameRenderer.cs",
    "content": "﻿using Lens.entity.component.logic;\nusing Lens.input;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Graphics;\nusing MonoGame.Extended.Graphics;\n\nnamespace Lens.graphics.gamerenderer {\n\tpublic class PixelPerfectGameRenderer : GameRenderer {\n\t\tpublic static float GameScale;\n\t\tpublic Batcher2D Batcher2D;\n\n\t\tprivate Matrix one = Matrix.Identity;\n\t\tprivate Matrix uiScale = Matrix.Identity;\n\n\t\tprivate bool inUi;\n\n\t\tpublic RasterizerState RasterizerState;\n\t\tpublic bool EnableClip = false;\n\t\tpublic Vector2 ClipPosition;\n\t\tpublic Vector2 ClipSize;\n\n\t\tpublic RasterizerState GetState => EnableClip ? RasterizerState : DefaultRasterizerState;\n\n\t\tpublic PixelPerfectGameRenderer() {\n\t\t\tGameTarget = new RenderTarget2D(\n\t\t\t\tEngine.GraphicsDevice, Display.Width + 1, Display.Height + 1, false,\n\t\t\t\tEngine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents\n\t\t\t);\n\t\t\t\n\t\t\tBatcher2D = new Batcher2D(Engine.GraphicsDevice);\n\t\t\tRasterizerState = new RasterizerState();\n\t\t\tRasterizerState.ScissorTestEnable = true;\n\t\t}\n\n\t\tpublic override void Begin() {\n\t\t\tif (inUi) {\n\t\t\t\tBeginUi();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, DefaultRasterizerState, SurfaceEffect, Camera.Instance?.Matrix ?? one);\n\t\t}\n\n\t\tpublic override void End() {\n\t\t\tGraphics.Batch.End();\n\t\t}\n\t\t\n\t\tpublic void BeginShadows() {\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(UiTarget);\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, EnableClip ? ClipRasterizerState : DefaultRasterizerState, SurfaceEffect, Camera.Instance?.Matrix ?? one);\n\t\t\tGraphics.Clear(Color.Transparent);\n\t\t}\n\n\t\tpublic void EndShadows() {\n\t\t\tGraphics.Batch.End();\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(GameTarget);\n\t\t}\n\n\t\tprivate void RenderGame() {\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(GameTarget);\n\t\t\tBegin();\n\t\t\tGraphics.Clear(Bg);\n\t\t\tEngine.Instance.State?.Render();\n\t\t\tEnd();\n\t\t}\n\n\t\tpublic void BeginUi(bool force = false) {\n\t\t\tif (!force) {\n\t\t\t\tEngine.GraphicsDevice.SetRenderTarget(UiTarget);\n\t\t\t}\n\n\t\t\tGraphics.Batch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, EnableClip ? ClipRasterizerState : DefaultRasterizerState, SurfaceEffect, force ? Matrix.Identity : uiScale);\n\t\t}\n\n\t\tprivate void RenderUi() {\n\t\t\tif (UiTarget == null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBeginUi();\n\t\t\t\n\t\t\tif (Engine.Flashes && Engine.Instance.Flash > 0) {\n\t\t\t\tGraphics.Clear(Engine.Instance.FlashColor);\n\t\t\t} else {\n\t\t\t\tGraphics.Clear(Color.Transparent);\n\t\t\t}\n\t\t\t\n\t\t\tEngine.Instance.State?.RenderUi();\n\t\t\t\n\t\t\tEnd();\n\t\t}\n\t\t\n\t\tpublic override void Render() {\n\t\t\tvar start = EnableBatcher;\n\t\t\t\n\t\t\tif (start) {\n\t\t\t\tBatcher2D.Begin();\n\t\t\t}\n\t\t\t\n\t\t\tRenderGame();\n\t\t\tinUi = true;\n\t\t\tRenderUi();\n\t\t\tinUi = false;\n\n\t\t\tEngine.GraphicsDevice.SetRenderTarget(null);\n\t\t\tvar set = false;\n\n\t\t\tif (EnableClip && Camera.Instance != null) {\n\t\t\t\tvar pos = Camera.Instance.CameraToScreen(ClipPosition) - new Vector2(Camera.Instance.Position.X % 1, Camera.Instance.Position.Y % 1) + Camera.Instance.GetComponent<ShakeComponent>().Position;\n\t\t\t\t\n\t\t\t\tEngine.GraphicsDevice.ScissorRectangle = new Rectangle((int) (pos.X * Engine.Instance.Upscale), (int) (pos.Y * Engine.Instance.Upscale), (int) (ClipSize.X * Engine.Instance.Upscale), (int) (ClipSize.Y * Engine.Instance.Upscale));\n\t\t\t} else {\n\t\t\t\tset = true;\n\t\t\t\tEngine.GraphicsDevice.ScissorRectangle = new Rectangle((int) Engine.Viewport.X, (int) Engine.Viewport.Y,\n\t\t\t\t\t(int) (Display.Width * Engine.Instance.Upscale), (int) (Display.Height * Engine.Instance.Upscale));\n\t\t\t}\n\n\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState, SamplerState, DepthStencilState, ClipRasterizerState, GameEffect, one);\n\n\t\t\tif (Camera.Instance != null) {\n\t\t\t\tvar shake = Camera.Instance.GetComponent<ShakeComponent>();\n\t\t\t\tvar scale = Engine.Instance.Upscale * Camera.Instance.TextureZoom;\n\n\t\t\t\tGraphics.Render(GameTarget,\n\t\t\t\t\tnew Vector2(Engine.Viewport.X + Display.Width / 2f * Engine.Instance.Upscale + scale * shake.Position.X,\n\t\t\t\t\t\tEngine.Viewport.Y + Display.Height / 2f * Engine.Instance.Upscale + scale * shake.Position.Y),\n\t\t\t\t\tshake.Angle,\n\t\t\t\t\tnew Vector2(Camera.Instance.Position.X % 1 + Display.Width / 2f,\n\t\t\t\t\t\tCamera.Instance.Position.Y % 1 + Display.Height / 2f),\n\t\t\t\t\tnew Vector2(scale * GameScale));\n\t\t\t}\n\n\t\t\tGraphics.Batch.End();\n\n\t\t\tif (!set) {\n\t\t\t\tEngine.GraphicsDevice.ScissorRectangle = new Rectangle((int) Engine.Viewport.X, (int) Engine.Viewport.Y,\n\t\t\t\t\t(int) (Display.Width * Engine.Instance.Upscale), (int) (Display.Height * Engine.Instance.Upscale));\n\t\t\t}\n\t\t\t\n\t\t\tif (UiTarget != null) {\n\t\t\t\tGraphics.Batch.Begin(SpriteSortMode.Immediate, BlendState, SamplerState, DepthStencilState, ClipRasterizerState, UiEffect, one);\n\n\t\t\t\tif (UiEffect != null) {\n\t\t\t\t\tUiEffect.Parameters[\"bottom\"].SetValue(1f);\n\t\t\t\t\tGraphics.Render(UiTarget, Engine.Viewport + new Vector2(0, Engine.Instance.UiUpscale));\n\t\t\t\t\tUiEffect.Parameters[\"bottom\"].SetValue(0f);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tGraphics.Render(UiTarget, Engine.Viewport);\n\t\t\t\tGraphics.Batch.End();\n\t\t\t}\n\t\t\t\n\n\t\t\tEngine.Instance.State?.RenderNative();\n\n\t\t\tif (start) {\n\t\t\t\tBatcher2D.End();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Resize(int width, int height) {\n\t\t\tbase.Resize(width, height);\n\n\t\t\tUiTarget?.Dispose();\n\n\t\t\tUiTarget = new RenderTarget2D(\n\t\t\t\tEngine.GraphicsDevice, (int) (Display.UiWidth * Engine.Instance.Upscale),\n\t\t\t\t(int) (Display.UiHeight * Engine.Instance.Upscale), false,\n\t\t\t\tEngine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents\n\t\t\t);\n\t\t\t\n\t\t\tuiScale = Matrix.Identity * Matrix.CreateScale(Engine.Instance.UiUpscale);\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\t\n\t\t\tGameTarget.Dispose();\n\t\t\tUiTarget?.Dispose();\n\t\t\tBatcher2D.Dispose();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/input/GamepadData.cs",
    "content": "﻿using System;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace Lens.input {\n\tpublic class GamepadData {\n\t\tpublic static bool WasChanged;\n\t\t\n\t\tpublic PlayerIndex PlayerIndex;\n\t\tpublic GamePadState PreviousState;\n\t\tpublic GamePadState CurrentState;\n\t\tpublic bool WasAttached;\n\t\tpublic bool Attached;\n\n\t\tpublic static string[] Identifiers;\n\t\t\n\t\tprivate float rumbleStrength;\n\t\tprivate float rumbleTime;\n\n\t\tpublic GamepadData(PlayerIndex playerIndex) {\n\t\t\tPlayerIndex = playerIndex;\n\t\t}\n\n\t\tpublic bool Idle;\n\n\t\tpublic bool AnythingIsDown(GamePadState state) {\n\t\t\tvar d = state.Buttons;\n\t\t\t\n\t\t\tif (d.A == ButtonState.Pressed || d.B == ButtonState.Pressed || d.X == ButtonState.Pressed || d.Y == ButtonState.Pressed) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tvar p = state.DPad;\n\n\t\t\tif (p.Left == ButtonState.Pressed || p.Right == ButtonState.Pressed || p.Up == ButtonState.Pressed || p.Down == ButtonState.Pressed) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool AnythingIsDown() {\n\t\t\treturn AnythingIsDown(CurrentState);\n\t\t}\n\t\t\n\t\tpublic void Update(float dt) {\n\t\t\tPreviousState = CurrentState;\n\t\t\tCurrentState = GamePad.GetState(PlayerIndex);\n\n\t\t\tWasAttached = WasAttached || PreviousState.IsConnected;\n\t\t\tAttached = CurrentState.IsConnected;\n\t\t\t\n\t\t\tif (rumbleTime > 0) {\n\t\t\t\trumbleTime -= dt;\n\t\t\t\trumbleStrength -= dt;\n\n\t\t\t\tif (rumbleTime <= 0 || rumbleStrength < 0) {\n\t\t\t\t\tGamePad.SetVibration(PlayerIndex, 0, 0);\n\t\t\t\t} else {\n\t\t\t\t\tGamePad.SetVibration(PlayerIndex, rumbleStrength, rumbleStrength);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Attached != WasAttached) {\n\t\t\t\tWasChanged = true;\n\t\t\t}\n\n\t\t\tif (PlayerIndex == PlayerIndex.One) {\n\t\t\t\t// Log.Info($\"X: (pressed) {WasPressed(Buttons.X)}, (down) {IsDown(Buttons.X)}\");\n\t\t\t}\n\t\t}\n\n\t\tpublic void Rumble(float strength, float time) {\n\t\t\tif (GamePad.SetVibration(PlayerIndex, strength, strength)) {\n\t\t\t\trumbleStrength = strength;\n\t\t\t\trumbleTime = time;\n\t\t\t}\n\t\t}\n\n\t\tpublic void StopRumble() {\n\t\t\tGamePad.SetVibration(PlayerIndex, 0, 0);\n\t\t\trumbleTime = 0;\n\t\t}\n\n\t\t#region Gamepad butttons\t\n\n\t\tpublic bool Check(Buttons button, Input.CheckType type) {\n\t\t\tswitch (type) {\n\t\t\t\tcase Input.CheckType.PRESSED: return WasPressed(button);\n\t\t\t\tcase Input.CheckType.RELEASED: return WasReleased(button);\n\t\t\t\tcase Input.CheckType.DOWN: return IsDown(button);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic bool IsDown(Buttons button) {\n\t\t\tif (button == Buttons.LeftTrigger) {\n\t\t\t\treturn LeftTriggerCheck();\n\t\t\t} else if (button == Buttons.RightTrigger) {\n\t\t\t\treturn RightTriggerCheck();\n\t\t\t}\n\t\t\t\n\t\t\treturn CurrentState.IsButtonDown(button);\n\t\t}\n\n\t\tpublic bool WasPressed(Buttons button) {\n\t\t\tif (button == Buttons.LeftTrigger) {\n\t\t\t\treturn LeftTriggerWasPressed();\n\t\t\t} else if (button == Buttons.RightTrigger) {\n\t\t\t\treturn RightTriggerWasPressed();\n\t\t\t}\n\t\t\t\n\t\t\treturn CurrentState.IsButtonDown(button) && PreviousState.IsButtonUp(button);\n\t\t}\n\n\t\tpublic bool WasReleased(Buttons button) {\n\t\t\tif (button == Buttons.LeftTrigger) {\n\t\t\t\treturn LeftTriggerWasReleased();\n\t\t\t} else if (button == Buttons.RightTrigger) {\n\t\t\t\treturn RightTriggerWasReleased();\n\t\t\t}\n\t\t\t\n\t\t\treturn CurrentState.IsButtonUp(button) && PreviousState.IsButtonDown(button);\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Gamepad sticks\n\n\t\tpublic Vector2 GetLeftStick() {\n\t\t\tvar ret = CurrentState.ThumbSticks.Left;\n\t\t\tret.Y = -ret.Y;\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tpublic Vector2 GetLeftStick(float deadzone) {\n\t\t\tvar ret = CurrentState.ThumbSticks.Left;\n\n\t\t\tif (ret.LengthSquared() < deadzone * deadzone) {\n\t\t\t\tret = Vector2.Zero;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tret.Y = -ret.Y;\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tpublic Vector2 GetRightStick() {\n\t\t\tvar ret = CurrentState.ThumbSticks.Right;\n\t\t\tret.Y = -ret.Y;\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tpublic Vector2 GetRightStick(float deadzone) {\n\t\t\tvar ret = CurrentState.ThumbSticks.Right;\n\n\t\t\tif (ret.LengthSquared() < deadzone * deadzone) {\n\t\t\t\tret = Vector2.Zero;\n\t\t\t} else {\n\t\t\t\tret.Y = -ret.Y;\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Left stick directions\n\n\t\tpublic bool LeftStickLeftCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X <= -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickLeftWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X <= -deadzone && PreviousState.ThumbSticks.Left.X > -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickLeftWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X > -deadzone && PreviousState.ThumbSticks.Left.X <= -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickRightCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X >= deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickRightWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X >= deadzone && PreviousState.ThumbSticks.Left.X < deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickRightWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.X < deadzone && PreviousState.ThumbSticks.Left.X >= deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickDownCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y <= -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickDownWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y <= -deadzone && PreviousState.ThumbSticks.Left.Y > -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickDownWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y > -deadzone && PreviousState.ThumbSticks.Left.Y <= -deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickUpCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y >= deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickUpWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y >= deadzone && PreviousState.ThumbSticks.Left.Y < deadzone;\n\t\t}\n\n\t\tpublic bool LeftStickUpWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Left.Y < deadzone && PreviousState.ThumbSticks.Left.Y >= deadzone;\n\t\t}\n\n\t\tpublic float LeftStickHorizontal(float deadzone) {\n\t\t\tfloat h = CurrentState.ThumbSticks.Left.X;\n\n\t\t\tif (Math.Abs(h) < deadzone) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn h;\n\t\t}\n\n\t\tpublic float LeftStickVertical(float deadzone) {\n\t\t\tfloat v = CurrentState.ThumbSticks.Left.Y;\n\n\t\t\tif (Math.Abs(v) < deadzone) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn -v;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Right Stick Directions\n\n\t\tpublic bool RightStickLeftCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X <= -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickLeftWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X <= -deadzone && PreviousState.ThumbSticks.Right.X > -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickLeftWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X > -deadzone && PreviousState.ThumbSticks.Right.X <= -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickRightCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X >= deadzone;\n\t\t}\n\n\t\tpublic bool RightStickRightWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X >= deadzone && PreviousState.ThumbSticks.Right.X < deadzone;\n\t\t}\n\n\t\tpublic bool RightStickRightWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.X < deadzone && PreviousState.ThumbSticks.Right.X >= deadzone;\n\t\t}\n\n\t\tpublic bool RightStickUpCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y <= -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickUpWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y <= -deadzone && PreviousState.ThumbSticks.Right.Y > -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickUpWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y > -deadzone && PreviousState.ThumbSticks.Right.Y <= -deadzone;\n\t\t}\n\n\t\tpublic bool RightStickDownCheck(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y >= deadzone;\n\t\t}\n\n\t\tpublic bool RightStickDownWasPressed(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y >= deadzone && PreviousState.ThumbSticks.Right.Y < deadzone;\n\t\t}\n\n\t\tpublic bool RightStickDownWasReleased(float deadzone) {\n\t\t\treturn CurrentState.ThumbSticks.Right.Y < deadzone && PreviousState.ThumbSticks.Right.Y >= deadzone;\n\t\t}\n\n\t\tpublic float RightStickHorizontal(float deadzone) {\n\t\t\tfloat h = CurrentState.ThumbSticks.Right.X;\n\n\t\t\tif (Math.Abs(h) < deadzone) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn h;\n\t\t}\n\n\t\tpublic float RightStickVertical(float deadzone) {\n\t\t\tfloat v = CurrentState.ThumbSticks.Right.Y;\n\n\t\t\tif (Math.Abs(v) < deadzone) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn -v;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region DPad directions\n\n\t\tpublic int DPadHorizontal => CurrentState.DPad.Right == ButtonState.Pressed\n\t\t\t? 1\n\t\t\t: (CurrentState.DPad.Left == ButtonState.Pressed ? -1 : 0);\n\n\t\tpublic int DPadVertical => CurrentState.DPad.Down == ButtonState.Pressed\n\t\t\t? 1\n\t\t\t: (CurrentState.DPad.Up == ButtonState.Pressed ? -1 : 0);\n\n\t\tpublic Vector2 DPad => new Vector2(DPadHorizontal, DPadVertical);\n\n\t\tpublic bool DPadLeftCheck => CurrentState.DPad.Left == ButtonState.Pressed;\n\n\t\tpublic bool DPadLeftWasPressed => CurrentState.DPad.Left == ButtonState.Pressed && PreviousState.DPad.Left == ButtonState.Released;\n\n\t\tpublic bool DPadLeftWasReleased => CurrentState.DPad.Left == ButtonState.Released && PreviousState.DPad.Left == ButtonState.Pressed;\n\n\t\tpublic bool DPadRightCheck => CurrentState.DPad.Right == ButtonState.Pressed;\n\n\t\tpublic bool DPadRightWasPressed => CurrentState.DPad.Right == ButtonState.Pressed && PreviousState.DPad.Right == ButtonState.Released;\n\n\t\tpublic bool DPadRightWasReleased => CurrentState.DPad.Right == ButtonState.Released && PreviousState.DPad.Right == ButtonState.Pressed;\n\n\t\tpublic bool DPadUpCheck => CurrentState.DPad.Up == ButtonState.Pressed;\n\n\t\tpublic bool DPadUpWasPressed => CurrentState.DPad.Up == ButtonState.Pressed && PreviousState.DPad.Up == ButtonState.Released;\n\n\t\tpublic bool DPadUpWasReleased => CurrentState.DPad.Up == ButtonState.Released && PreviousState.DPad.Up == ButtonState.Pressed;\n\n\t\tpublic bool DPadDownCheck => CurrentState.DPad.Down == ButtonState.Pressed;\n\n\t\tpublic bool DPadDownWasPressed => CurrentState.DPad.Down == ButtonState.Pressed && PreviousState.DPad.Down == ButtonState.Released;\n\n\t\tpublic bool DPadDownWasReleased => CurrentState.DPad.Down == ButtonState.Released && PreviousState.DPad.Down == ButtonState.Pressed;\n\n\t\t#endregion\n\n\t\t#region Lef and right triggers\n\n\n\t\tpublic const float TriggerTreshold = 0.05f;\n\t\t\n\t\tpublic bool LeftTriggerCheck(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Left >= threshold;\n\t\t}\n\n\t\tpublic bool LeftTriggerWasPressed(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Left >= threshold && PreviousState.Triggers.Left < threshold;\n\t\t}\n\n\t\tpublic bool LeftTriggerWasReleased(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Left < threshold && PreviousState.Triggers.Left >= threshold;\n\t\t}\n\n\t\tpublic bool RightTriggerCheck(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Right >= threshold;\n\t\t}\n\n\t\tpublic bool RightTriggerWasPressed(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Right >= threshold && PreviousState.Triggers.Right < threshold;\n\t\t}\n\n\t\tpublic bool RightTriggerWasReleased(float threshold = TriggerTreshold) {\n\t\t\treturn CurrentState.Triggers.Right < threshold && PreviousState.Triggers.Right >= threshold;\n\t\t}\n\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Lens/input/Input.cs",
    "content": "﻿using System.Collections.Generic;\nusing Lens.util;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace Lens.input {\n\tpublic static class Input {\n\t\tpublic enum CheckType {\n\t\t\tPRESSED,\n\t\t\tRELEASED,\n\t\t\tDOWN\n\t\t}\n\n\t\tpublic static bool EnableImGuiFocus;\n\n\t\tpublic static KeyboardData Keyboard;\n\t\tpublic static MouseData Mouse;\n\t\tpublic static GamepadData[] Gamepads;\n\t\tpublic static int Blocked;\n\n\t\tprivate static Dictionary<string, InputButton> Buttons = new Dictionary<string, InputButton>();\n\n\t\tpublic static void Init() {\n\t\t\tKeyboard = new KeyboardData();\n\t\t\tMouse = new MouseData();\n\t\t\tGamepads = new GamepadData[4];\n\n\t\t\tfor (int i = 0; i < Gamepads.Length; i++) {\n\t\t\t\tGamepads[i] = new GamepadData((PlayerIndex) i);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Destroy() {\n\t\t\tforeach (var gamepad in Gamepads) {\n\t\t\t\tgamepad.StopRumble();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Update(float dt) {\n\t\t\tGamepadData.WasChanged = false;\n\n\t\t\tKeyboard.Update();\n\t\t\tMouse.Update();\n\n\t\t\tforeach (var gamepad in Gamepads) {\n\t\t\t\tgamepad.Update(dt);\n\t\t\t}\n\t\t}\n\n\t\tpublic static void ClearBindings() {\n\t\t\tButtons.Clear();\n\t\t}\n\n\t\tpublic static void Bind(string id, params Keys[] values) {\n\t\t\tvar button = Buttons.ContainsKey(id) ? Buttons[id] : new InputButton();\n\n\t\t\tif (button.Keys == null) {\n\t\t\t\tbutton.Keys = new List<Keys>();\n\t\t\t}\n\n\t\t\tforeach (var key in values) {\n\t\t\t\tbutton.Keys.Add(key);\n\t\t\t}\n\n\t\t\tButtons[id] = button;\n\t\t}\n\n\t\tpublic static void Bind(string id, params Buttons[] values) {\n\t\t\tvar button = Buttons.ContainsKey(id) ? Buttons[id] : new InputButton();\n\n\t\t\tif (button.Buttons == null) {\n\t\t\t\tbutton.Buttons = new List<Buttons>();\n\t\t\t}\n\n\t\t\tforeach (var b in values) {\n\t\t\t\tbutton.Buttons.Add(b);\n\t\t\t}\n\n\t\t\tButtons[id] = button;\n\t\t}\n\n\t\tpublic static void Bind(string id, params MouseButtons[] values) {\n\t\t\tvar button = Buttons.ContainsKey(id) ? Buttons[id] : new InputButton();\n\n\t\t\tif (button.MouseButtons == null) {\n\t\t\t\tbutton.MouseButtons = new List<MouseButtons>();\n\t\t\t}\n\n\t\t\tforeach (var b in values) {\n\t\t\t\tbutton.MouseButtons.Add(b);\n\t\t\t}\n\n\t\t\tButtons[id] = button;\n\t\t}\n\n\t\tprivate static bool Check(string id, CheckType type, GamepadData data = null, bool ignoreBlock = false) {\n\t\t\tif (Blocked > 0 && !ignoreBlock) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!Buttons.TryGetValue(id, out var button)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (button.Keys != null) {\n\t\t\t\tforeach (var key in button.Keys) {\n\t\t\t\t\tif (Keyboard.Check(key, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data != null && data.Attached && button.Buttons != null) {\n\t\t\t\tforeach (var b in button.Buttons) {\n\t\t\t\t\tif (data.Check(b, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (button.MouseButtons != null) {\n\t\t\t\tforeach (var b in button.MouseButtons) {\n\t\t\t\t\tif (Mouse.Check(b, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tprivate static bool Check(string id, CheckType type, InputComponent data, bool ignoreBlock = false) {\n\t\t\tif (Blocked > 0 && !ignoreBlock) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!Buttons.TryGetValue(id, out var button)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (data.KeyboardEnabled && button.Keys != null) {\n\t\t\t\tforeach (var key in button.Keys) {\n\t\t\t\t\tif (Keyboard.Check(key, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data.GamepadEnabled && data.GamepadData != null && data.GamepadData.Attached && button.Buttons != null) {\n\t\t\t\tforeach (var b in button.Buttons) {\n\t\t\t\t\tif (data.GamepadData.Check(b, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data.KeyboardEnabled && button.MouseButtons != null) {\n\t\t\t\tforeach (var b in button.MouseButtons) {\n\t\t\t\t\tif (Mouse.Check(b, type)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static bool IsDownOnController(string id, GamepadData data) {\n\t\t\tif (!Buttons.TryGetValue(id, out var button)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tif (data != null && data.Attached && button.Buttons != null) {\n\t\t\t\tforeach (var b in button.Buttons) {\n\t\t\t\t\tif (data.IsDown(b)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static bool WasPressed(string id, GamepadData data = null, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.PRESSED, data, ignoreBlock);\n\t\t}\n\n\t\tpublic static bool WasReleased(string id, GamepadData data = null, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.RELEASED, data, ignoreBlock);\n\t\t}\n\n\t\tpublic static bool IsDown(string id, GamepadData data = null, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.DOWN, data, ignoreBlock);\n\t\t}\n\n\t\tpublic static bool WasPressed(string id, InputComponent data, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.PRESSED, data, ignoreBlock);\n\t\t}\n\n\t\tpublic static bool WasReleased(string id, InputComponent data, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.RELEASED, data, ignoreBlock);\n\t\t}\n\n\t\tpublic static bool IsDown(string id, InputComponent data, bool ignoreBlock = false) {\n\t\t\treturn Check(id, CheckType.DOWN, data, ignoreBlock);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/input/InputButton.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace Lens.input {\n\tpublic struct InputButton {\n\t\tpublic List<Keys> Keys;\n\t\tpublic List<Buttons> Buttons;\n\t\tpublic List<MouseButtons> MouseButtons;\n\t}\n}"
  },
  {
    "path": "Lens/input/InputComponent.cs",
    "content": "using System;\nusing Lens.entity.component;\nusing Lens.util.file;\n\nnamespace Lens.input {\n\tpublic class InputComponent : SaveableComponent {\n\t\tpublic byte Index;\n\t\tpublic bool GamepadEnabled = true;\n\t\tpublic bool KeyboardEnabled = true;\n\n\t\tpublic GamepadData GamepadData;\n\t\tpublic Action InitCallback;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\n\t\t\tif (InitCallback != null) {\n\t\t\t\tInitCallback?.Invoke();\n\t\t\t\tInitCallback = null;\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Load(FileReader stream) {\n\t\t\tbase.Load(stream);\n\n\t\t\tIndex = stream.ReadByte();\n\t\t\tGamepadEnabled = stream.ReadBoolean();\n\t\t\tKeyboardEnabled = stream.ReadBoolean();\n\t\t}\n\n\t\tpublic override void Save(FileWriter stream) {\n\t\t\tbase.Save(stream);\n\t\t\t\n\t\t\tstream.WriteByte(Index);\n\t\t\tstream.WriteBoolean(GamepadEnabled);\n\t\t\tstream.WriteBoolean(KeyboardEnabled);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/input/KeyboardData.cs",
    "content": "﻿using ImGuiNET;\nusing Lens.assets;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace Lens.input {\n\tpublic class KeyboardData {\n\t\tpublic KeyboardState PreviousState;\n\t\tpublic KeyboardState State;\n\t\t\n\t\tprivate bool guiBlocksKeyboard;\n\n\t\tpublic KeyboardData() {\n\t\t\tState = Keyboard.GetState();\n\t\t}\n\t\t\n\t\tpublic void Update() {\n\t\t\tPreviousState = State;\n\t\t\tState = Keyboard.GetState();\n\t\t\t\n\t\t\tguiBlocksKeyboard = Assets.ImGuiEnabled && Input.EnableImGuiFocus && ImGui.GetIO().WantCaptureKeyboard;\n\t\t}\n\n\t\tpublic bool Check(Keys key, Input.CheckType type, bool ignoreGui = false) {\n\t\t\tswitch (type) {\n\t\t\t\tcase Input.CheckType.PRESSED: return WasPressed(key, ignoreGui);\n\t\t\t\tcase Input.CheckType.RELEASED: return WasReleased(key, ignoreGui);\n\t\t\t\tcase Input.CheckType.DOWN: return IsDown(key, ignoreGui);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic bool IsDown(Keys key, bool ignoreGui = false) {\n\t\t\treturn (ignoreGui || !guiBlocksKeyboard) && State.IsKeyDown(key);\n\t\t}\n\n\t\tpublic bool WasPressed(Keys key, bool ignoreGui = false) {\n\t\t\treturn (ignoreGui || !guiBlocksKeyboard) && State.IsKeyDown(key) && !PreviousState.IsKeyDown(key);\n\t\t}\n\t\t\n\t\tpublic bool WasReleased(Keys key, bool ignoreGui = false) {\n\t\t\treturn (ignoreGui || !guiBlocksKeyboard) && !State.IsKeyDown(key) && PreviousState.IsKeyDown(key);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/input/MouseButtons.cs",
    "content": "﻿namespace Lens.input {\n\tpublic enum MouseButtons {\n\t\tLeft,\n\t\tRight,\n\t\tMiddle\n\t}\n}"
  },
  {
    "path": "Lens/input/MouseData.cs",
    "content": "﻿using System;\nusing ImGuiNET;\nusing Lens.assets;\nusing Lens.util.camera;\nusing Microsoft.Xna.Framework;\nusing Microsoft.Xna.Framework.Input;\n\nnamespace Lens.input {\n\tpublic class MouseData {\t\t\n\t\tpublic MouseState PreviousState;\n\t\tpublic MouseState CurrentState;\n\t\tpublic static bool HadClick;\n\n\t\tprivate bool blockedByGui;\n\t\t\n\t\tpublic MouseData() {\n\t\t\tPreviousState = new MouseState();\n\t\t\tCurrentState = new MouseState();\n\t\t}\n\n\t\tinternal void Update() {\n\t\t\tPreviousState = CurrentState;\n\t\t\tCurrentState = Mouse.GetState();\n\n\t\t\tblockedByGui = Assets.ImGuiEnabled && Input.EnableImGuiFocus && ImGui.GetIO().WantCaptureMouse;\n\t\t\tHadClick = HadClick || WasPressedLeftButton;\n\t\t}\n\n\t\t#region Buttons\n\n\t\tpublic bool Check(MouseButtons button, Input.CheckType type) {\n\t\t\tif (blockedByGui) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tswitch (type) {\n\t\t\t\tcase Input.CheckType.PRESSED: {\n\t\t\t\t\tswitch (button) {\n\t\t\t\t\t\tcase MouseButtons.Left: return WasPressedLeftButton;\n\t\t\t\t\t\tcase MouseButtons.Right: return WasPressedRightButton;\n\t\t\t\t\t\tcase MouseButtons.Middle: return WasPressedMiddleButton;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tcase Input.CheckType.RELEASED: {\n\t\t\t\t\tswitch (button) {\n\t\t\t\t\t\tcase MouseButtons.Left: return WasReleasedLeftButton;\n\t\t\t\t\t\tcase MouseButtons.Right: return WasReleasedRightButton;\n\t\t\t\t\t\tcase MouseButtons.Middle: return WasReleasedMiddleButton;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tcase Input.CheckType.DOWN: {\n\t\t\t\t\tswitch (button) {\n\t\t\t\t\t\tcase MouseButtons.Left: return CheckLeftButton;\n\t\t\t\t\t\tcase MouseButtons.Right: return CheckRightButton;\n\t\t\t\t\t\tcase MouseButtons.Middle: return CheckMiddleButton;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpublic bool CheckLeftButton => CurrentState.LeftButton == ButtonState.Pressed;\n\t\tpublic bool CheckRightButton => CurrentState.RightButton == ButtonState.Pressed;\n\t\tpublic bool CheckMiddleButton => CurrentState.MiddleButton == ButtonState.Pressed;\n\t\tpublic bool WasPressedLeftButton => CurrentState.LeftButton == ButtonState.Pressed &&\n\t\t                                    PreviousState.LeftButton == ButtonState.Released;\n\t\tpublic bool WasPressedRightButton => CurrentState.RightButton == ButtonState.Pressed &&\n\t\t                                     PreviousState.RightButton == ButtonState.Released;\n\t\tpublic bool WasPressedMiddleButton => CurrentState.MiddleButton == ButtonState.Pressed &&\n\t\t                                      PreviousState.MiddleButton == ButtonState.Released;\n\t\tpublic bool WasReleasedLeftButton => CurrentState.LeftButton == ButtonState.Released &&\n\t\t                                     PreviousState.LeftButton == ButtonState.Pressed;\n\t\tpublic bool WasReleasedRightButton => CurrentState.RightButton == ButtonState.Released &&\n\t\t                                      PreviousState.RightButton == ButtonState.Pressed;\n\t\tpublic bool WasReleasedMiddleButton => CurrentState.MiddleButton == ButtonState.Released &&\n\t\t                                       PreviousState.MiddleButton == ButtonState.Pressed;\n\n\t\t#endregion\n\n\t\t#region Wheel\n\n\t\tpublic int Wheel => CurrentState.ScrollWheelValue;\n\t\tpublic int WheelDelta => CurrentState.ScrollWheelValue - PreviousState.ScrollWheelValue;\n\n\t\t#endregion\n\n\t\t#region Position\n\n\t\tpublic bool WasMoved => CurrentState.X != PreviousState.X\n\t\t\t|| CurrentState.Y != PreviousState.Y;\n\t\t\n\t\tpublic Vector2 PositionDelta => \n\t\t\tVector2.Transform(RawPositionDelta, Matrix.Invert(Matrix.CreateScale(Engine.Instance.Upscale)));\n\t\t\n\t\tpublic Vector2 RawPositionDelta => \n\t\t\tnew Vector2(CurrentState.X - PreviousState.X, CurrentState.Y - PreviousState.Y);\n\n\t\tpublic float X {\n\t\t\tget { return Position.X; }\n\t\t\tset { Position = new Vector2(value, Position.Y); }\n\t\t}\n\n\t\tpublic float Y {\n\t\t\tget { return Position.Y; }\n\t\t\tset { Position = new Vector2(Position.X, value); }\n\t\t}\n\n\t\tpublic Vector2 ScreenPosition => new Vector2(CurrentState.X, CurrentState.Y);\n\t\tpublic Vector2 GamePosition => Camera.Instance.ScreenToCamera(ScreenPosition);\n\t\t\n\t\tpublic Vector2 Position {\n\t\t\tget { return Vector2.Transform(new Vector2(CurrentState.X, CurrentState.Y), Matrix.Invert(Engine.ScreenMatrix)); }\n\n\t\t\tset {\n\t\t\t\tvar vector = Vector2.Transform(value, Engine.ScreenMatrix);\n\t\t\t\tMouse.SetPosition((int) Math.Round(vector.X), (int) Math.Round(vector.Y));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic Vector2 UiPosition {\n\t\t\tget { return Vector2.Transform(new Vector2(CurrentState.X, CurrentState.Y), Matrix.Invert(Engine.UiMatrix)); }\n\n\t\t\tset {\n\t\t\t\tvar vector = Vector2.Transform(value, Engine.UiMatrix);\n\t\t\t\tMouse.SetPosition((int) Math.Round(vector.X), (int) Math.Round(vector.Y));\n\t\t\t}\n\t\t}\n\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Lens/lightJson/JsonArray.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Lens.lightJson.Serialization;\n\nnamespace Lens.lightJson\n{\n\t/// <summary>\n\t/// Represents an ordered collection of JsonValues.\n\t/// </summary>\n\t[DebuggerDisplay(\"Count = {Count}\")]\n\t[DebuggerTypeProxy(typeof(JsonArrayDebugView))]\n\tpublic sealed class JsonArray : IEnumerable<JsonValue>\n\t{\n\t\tprivate IList<JsonValue> items;\n\n\t\t/// <summary>\n\t\t/// Gets the number of values in this collection.\n\t\t/// </summary>\n\t\tpublic int Count\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.items.Count;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets or sets the value at the given index.\n\t\t/// </summary>\n\t\t/// <param name=\"index\">The zero-based index of the value to get or set.</param>\n\t\t/// <remarks>\n\t\t/// The getter will return JsonValue.Null if the given index is out of range.\n\t\t/// </remarks>\n\t\tpublic JsonValue this[int index]\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (index >= 0 && index < this.items.Count)\n\t\t\t\t{\n\t\t\t\t\treturn this.items[index];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn JsonValue.Null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tset\n\t\t\t{\n\t\t\t\tthis.items[index] = value;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonArray.\n\t\t/// </summary>\n\t\tpublic JsonArray()\n\t\t{\n\t\t\tthis.items = new List<JsonValue>();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonArray, adding the given values to the collection.\n\t\t/// </summary>\n\t\t/// <param name=\"values\">The values to be added to this collection.</param>\n\t\tpublic JsonArray(params JsonValue[] values) : this()\n\t\t{\n\t\t\tif (values == null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(nameof(values));\n\t\t\t}\n\n\t\t\tforeach (var value in values)\n\t\t\t{\n\t\t\t\tthis.items.Add(value);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Adds the given value to this collection.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be added.</param>\n\t\t/// <returns>Returns this collection.</returns>\n\t\tpublic JsonArray Add(JsonValue value)\n\t\t{\n\t\t\tthis.items.Add(value);\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Adds the given value to this collection only if the value is not null.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be added.</param>\n\t\t/// <returns>Returns this collection.</returns>\n\t\tpublic JsonArray AddIfNotNull(JsonValue value)\n\t\t{\n\t\t\tif (!value.IsNull)\n\t\t\t{\n\t\t\t\tAdd(value);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Inserts the given value at the given index in this collection.\n\t\t/// </summary>\n\t\t/// <param name=\"index\">The index where the given value will be inserted.</param>\n\t\t/// <param name=\"value\">The value to be inserted into this collection.</param>\n\t\t/// <returns>Returns this collection.</returns>\n\t\tpublic JsonArray Insert(int index, JsonValue value)\n\t\t{\n\t\t\tthis.items.Insert(index, value);\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Inserts the given value at the given index in this collection.\n\t\t/// </summary>\n\t\t/// <param name=\"index\">The index where the given value will be inserted.</param>\n\t\t/// <param name=\"value\">The value to be inserted into this collection.</param>\n\t\t/// <returns>Returns this collection.</returns>\n\t\tpublic JsonArray InsertIfNotNull(int index, JsonValue value)\n\t\t{\n\t\t\tif (!value.IsNull)\n\t\t\t{\n\t\t\t\tInsert(index, value);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Removes the value at the given index.\n\t\t/// </summary>\n\t\t/// <param name=\"index\">The index of the value to be removed.</param>\n\t\t/// <returns>Return this collection.</returns>\n\t\tpublic JsonArray Remove(int index)\n\t\t{\n\t\t\tthis.items.RemoveAt(index);\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Clears the contents of this collection.\n\t\t/// </summary>\n\t\t/// <returns>Returns this collection.</returns>\n\t\tpublic JsonArray Clear()\n\t\t{\n\t\t\tthis.items.Clear();\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines whether the given item is in the JsonArray.\n\t\t/// </summary>\n\t\t/// <param name=\"item\">The item to locate in the JsonArray.</param>\n\t\t/// <returns>Returns true if the item is found; otherwise, false.</returns>\n\t\tpublic bool Contains(JsonValue item)\n\t\t{\n\t\t\treturn this.items.Contains(item);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines the index of the given item in this JsonArray.\n\t\t/// </summary>\n\t\t/// <param name=\"item\">The item to locate in this JsonArray.</param>\n\t\t/// <returns>The index of the item, if found. Otherwise, returns -1.</returns>\n\t\tpublic int IndexOf(JsonValue item)\n\t\t{\n\t\t\treturn this.items.IndexOf(item);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through the collection.\n\t\t/// </summary>\n\t\tpublic IEnumerator<JsonValue> GetEnumerator()\n\t\t{\n\t\t\treturn this.items.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through the collection.\n\t\t/// </summary>\n\t\tSystem.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n\t\t{\n\t\t\treturn this.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the array.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\tpublic override string ToString()\n\t\t{\n\t\t\treturn ToString(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the array.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\t/// <param name=\"pretty\">\n\t\t/// Indicates whether the resulting string should be formatted for human-readability.\n\t\t/// </param>\n\t\tpublic string ToString(bool pretty)\n\t\t{\n\t\t\treturn JsonWriter.Serialize(this, pretty);\n\t\t}\n\n\t\tprivate class JsonArrayDebugView\n\t\t{\n\t\t\tprivate JsonArray jsonArray;\n\n\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n\t\t\tpublic JsonValue[] Items\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\tvar items = new JsonValue[this.jsonArray.Count];\n\n\t\t\t\t\tfor (int i = 0; i < this.jsonArray.Count; i += 1)\n\t\t\t\t\t{\n\t\t\t\t\t\titems[i] = this.jsonArray[i];\n\t\t\t\t\t}\n\n\t\t\t\t\treturn items;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic JsonArrayDebugView(JsonArray jsonArray)\n\t\t\t{\n\t\t\t\tthis.jsonArray = jsonArray;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/JsonObject.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics;\nusing Lens.lightJson.Serialization;\n\nnamespace Lens.lightJson\n{\n\t/// <summary>\n\t/// Represents a key-value pair collection of JsonValue objects.\n\t/// </summary>\n\t[DebuggerDisplay(\"Count = {Count}\")]\n\t[DebuggerTypeProxy(typeof(JsonObjectDebugView))]\n\tpublic sealed class JsonObject : IEnumerable<KeyValuePair<string, JsonValue>>, IEnumerable<JsonValue>\n\t{\n\t\tprivate IDictionary<string, JsonValue> properties;\n\n\t\t/// <summary>\n\t\t/// Gets the number of properties in this JsonObject.\n\t\t/// </summary>\n\t\tpublic int Count\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.properties.Count;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets or sets the property with the given key.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the property to get or set.</param>\n\t\t/// <remarks>\n\t\t/// The getter will return JsonValue.Null if the given key is not assosiated with any value.\n\t\t/// </remarks>\n\t\tpublic JsonValue this[string key]\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (this.properties.TryGetValue(key, out var value))\n\t\t\t\t{\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn JsonValue.Null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tset\n\t\t\t{\n\t\t\t\tthis.properties[key] = value;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonObject.\n\t\t/// </summary>\n\t\tpublic JsonObject()\n\t\t{\n\t\t\tthis.properties = new Dictionary<string, JsonValue>();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Adds a key with a null value to this collection.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the property to be added.</param>\n\t\t/// <remarks>Returns this JsonObject.</remarks>\n\t\tpublic JsonObject Add(string key)\n\t\t{\n\t\t\treturn Add(key, JsonValue.Null);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Adds a value associated with a key to this collection.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the property to be added.</param>\n\t\t/// <param name=\"value\">The value of the property to be added.</param>\n\t\t/// <returns>Returns this JsonObject.</returns>\n\t\tpublic JsonObject Add(string key, JsonValue value)\n\t\t{\n\t\t\tthis.properties.Add(key, value);\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Adds a value associated with a key to this collection only if the value is not null.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the property to be added.</param>\n\t\t/// <param name=\"value\">The value of the property to be added.</param>\n\t\t/// <returns>Returns this JsonObject.</returns>\n\t\tpublic JsonObject AddIfNotNull(string key, JsonValue value)\n\t\t{\n\t\t\tif (!value.IsNull)\n\t\t\t{\n\t\t\t\tAdd(key, value);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Removes a property with the given key.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the property to be removed.</param>\n\t\t/// <returns>\n\t\t/// Returns true if the given key is found and removed; otherwise, false.\n\t\t/// </returns>\n\t\tpublic bool Remove(string key)\n\t\t{\n\t\t\treturn this.properties.Remove(key);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Clears the contents of this collection.\n\t\t/// </summary>\n\t\t/// <returns>Returns this JsonObject.</returns>\n\t\tpublic JsonObject Clear()\n\t\t{\n\t\t\tthis.properties.Clear();\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Changes the key of one of the items in the collection.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// This method has no effects if the <i>oldKey</i> does not exists.\n\t\t/// If the <i>newKey</i> already exists, the value will be overwritten.\n\t\t/// </remarks>\n\t\t/// <param name=\"oldKey\">The name of the key to be changed.</param>\n\t\t/// <param name=\"newKey\">The new name of the key.</param>\n\t\t/// <returns>Returns this JsonObject.</returns>\n\t\tpublic JsonObject Rename(string oldKey, string newKey)\n\t\t{\n\t\t\tif (this.properties.TryGetValue(oldKey, out var value))\n\t\t\t{\n\t\t\t\tRemove(oldKey);\n\t\t\t\tthis[newKey] = value;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines whether this collection contains an item assosiated with the given key.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key to locate in this collection.</param>\n\t\t/// <returns>Returns true if the key is found; otherwise, false.</returns>\n\t\tpublic bool ContainsKey(string key)\n\t\t{\n\t\t\treturn this.properties.ContainsKey(key);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines whether this collection contains an item assosiated with the given key\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key to locate in this collection.</param>\n\t\t/// <param name=\"value\">\n\t\t/// When this method returns, this value gets assigned the JsonValue assosiated with\n\t\t/// the key, if the key is found; otherwise, JsonValue.Null is assigned.\n\t\t/// </param>\n\t\t/// <returns>Returns true if the key is found; otherwise, false.</returns>\n\t\tpublic bool ContainsKey(string key, out JsonValue value)\n\t\t{\n\t\t\treturn this.properties.TryGetValue(key, out value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Determines whether this collection contains the given JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to locate in this collection.</param>\n\t\t/// <returns>Returns true if the value is found; otherwise, false.</returns>\n\t\tpublic bool Contains(JsonValue value)\n\t\t{\n\t\t\treturn this.properties.Values.Contains(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through this collection.\n\t\t/// </summary>\n\t\tpublic IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()\n\t\t{\n\t\t\treturn this.properties.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through this collection.\n\t\t/// </summary>\n\t\tIEnumerator<JsonValue> IEnumerable<JsonValue>.GetEnumerator()\n\t\t{\n\t\t\treturn this.properties.Values.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns an enumerator that iterates through this collection.\n\t\t/// </summary>\n\t\tSystem.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n\t\t{\n\t\t\treturn this.GetEnumerator();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the object.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\tpublic override string ToString()\n\t\t{\n\t\t\treturn ToString(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the object.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\t/// <param name=\"pretty\">\n\t\t/// Indicates whether the resulting string should be formatted for human-readability.\n\t\t/// </param>\n\t\tpublic string ToString(bool pretty)\n\t\t{\n\t\t\treturn JsonWriter.Serialize(this, pretty);\n\t\t}\n\n\t\tprivate class JsonObjectDebugView\n\t\t{\n\t\t\tprivate JsonObject jsonObject;\n\n\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n\t\t\tpublic KeyValuePair[] Keys\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\tvar keys = new KeyValuePair[jsonObject.Count];\n\n\t\t\t\t\tvar i = 0;\n\t\t\t\t\tforeach (var property in jsonObject)\n\t\t\t\t\t{\n\t\t\t\t\t\tkeys[i] = new KeyValuePair(property.Key, property.Value);\n\t\t\t\t\t\ti += 1;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn keys;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic JsonObjectDebugView(JsonObject jsonObject)\n\t\t\t{\n\t\t\t\tthis.jsonObject = jsonObject;\n\t\t\t}\n\n\t\t\t[DebuggerDisplay(\"{value.ToString(),nq}\", Name = \"{key}\", Type = \"JsonValue({Type})\")]\n\t\t\tpublic class KeyValuePair\n\t\t\t{\n\t\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n\t\t\t\tprivate string key;\n\n\t\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n\t\t\t\tprivate JsonValue value;\n\n\t\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n\t\t\t\tprivate JsonValueType Type\n\t\t\t\t{\n\t\t\t\t\tget\n\t\t\t\t\t{\n\t\t\t\t\t\treturn value.Type;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n\t\t\t\tpublic object View\n\t\t\t\t{\n\t\t\t\t\tget\n\t\t\t\t\t{\n\t\t\t\t\t\tif (this.value.IsJsonObject)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn (JsonObject)this.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (this.value.IsJsonArray)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn (JsonArray)this.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn this.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tpublic KeyValuePair(string key, JsonValue value)\n\t\t\t\t{\n\t\t\t\t\tthis.key = key;\n\t\t\t\t\tthis.value = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/JsonValue.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Lens.lightJson.Serialization;\n\nnamespace Lens.lightJson\n{\n\t/// <summary>\n\t/// A wrapper object that contains a valid JSON value.\n\t/// </summary>\n\t[DebuggerDisplay(\"{ToString(),nq}\", Type = \"JsonValue({Type})\")]\n\t[DebuggerTypeProxy(typeof(JsonValueDebugView))]\n\tpublic struct JsonValue\n\t{\n\t\tprivate readonly JsonValueType type;\n\t\tprivate readonly object reference;\n\t\tprivate readonly double value;\n\n\t\t/// <summary>\n\t\t/// Represents a null JsonValue.\n\t\t/// </summary>\n\t\tpublic static readonly JsonValue Null = new JsonValue(JsonValueType.Null, default(double), null);\n\n\t\t/// <summary>\n\t\t/// Gets the type of this JsonValue.\n\t\t/// </summary>\n\t\tpublic JsonValueType Type\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.type;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is Null.\n\t\t/// </summary>\n\t\tpublic bool IsNull\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is a Boolean.\n\t\t/// </summary>\n\t\tpublic bool IsBoolean\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.Boolean;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is an Integer.\n\t\t/// </summary>\n\t\tpublic bool IsInteger\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (!this.IsNumber)\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar value = this.value;\n\n\t\t\t\treturn (value >= Int32.MinValue) && (value <= Int32.MaxValue) && unchecked((Int32)value) == value;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is a Number.\n\t\t/// </summary>\n\t\tpublic bool IsNumber\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.Number;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is a String.\n\t\t/// </summary>\n\t\tpublic bool IsString\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.String;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is a JsonObject.\n\t\t/// </summary>\n\t\tpublic bool IsJsonObject\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.Object;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue is a JsonArray.\n\t\t/// </summary>\n\t\tpublic bool IsJsonArray\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.Type == JsonValueType.Array;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether this JsonValue represents a DateTime.\n\t\t/// </summary>\n\t\tpublic bool IsDateTime\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.AsDateTime != null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as a Boolean type.\n\t\t/// </summary>\n\t\tpublic bool AsBoolean\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tswitch (this.Type)\n\t\t\t\t{\n\t\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\t\t\treturn (this.value == 1);\n\n\t\t\t\t\tcase JsonValueType.Number:\n\t\t\t\t\t\treturn (this.value != 0);\n\n\t\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\t\treturn ((string)this.reference != \"\");\n\n\t\t\t\t\tcase JsonValueType.Object:\n\t\t\t\t\tcase JsonValueType.Array:\n\t\t\t\t\t\treturn true;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as an Integer type.\n\t\t/// </summary>\n\t\tpublic int AsInteger\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tvar value = this.AsNumber;\n\n\t\t\t\t// Prevent overflow if the value doesn't fit.\n\t\t\t\tif (value >= int.MaxValue)\n\t\t\t\t{\n\t\t\t\t\treturn int.MaxValue;\n\t\t\t\t}\n\t\t\t\tif (value <= int.MinValue)\n\t\t\t\t{\n\t\t\t\t\treturn int.MinValue;\n\t\t\t\t}\n\n\t\t\t\treturn (int)value;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as a Number type.\n\t\t/// </summary>\n\t\tpublic double AsNumber\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tswitch (this.Type)\n\t\t\t\t{\n\t\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\t\t\treturn (this.value == 1)\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0;\n\n\t\t\t\t\tcase JsonValueType.Number:\n\t\t\t\t\t\treturn this.value;\n\n\t\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\t\tdouble number;\n\t\t\t\t\t\tif (double.TryParse((string)this.reference, out number))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn number;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgoto default;\n\t\t\t\t\t\t}\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic float Number(float d) {\n\t\t\treturn (float) (Type == JsonValueType.Number ? value : d);\n\t\t}\n\t\t\n\t\tpublic int Int(int d) {\n\t\t\treturn (int) (Type == JsonValueType.Number ? value : d);\n\t\t}\n\n\t\tpublic bool Bool(bool b) {\n\t\t\treturn Type == JsonValueType.Boolean ? (int) value == 1 : b;\n\t\t}\n\n\t\tpublic string String(string s) {\n\t\t\treturn Type == JsonValueType.String ? (string) reference : s;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as a String type.\n\t\t/// </summary>\n\t\tpublic string AsString\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tswitch (this.Type)\n\t\t\t\t{\n\t\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\t\t\treturn (this.value == 1)\n\t\t\t\t\t\t\t? \"true\"\n\t\t\t\t\t\t\t: \"false\";\n\n\t\t\t\t\tcase JsonValueType.Number:\n\t\t\t\t\t\treturn this.value.ToString();\n\n\t\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\t\treturn (string)this.reference;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as an JsonObject.\n\t\t/// </summary>\n\t\tpublic JsonObject AsJsonObject\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn (this.IsJsonObject)\n\t\t\t\t\t? (JsonObject)this.reference\n\t\t\t\t\t: null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as an JsonArray.\n\t\t/// </summary>\n\t\tpublic JsonArray AsJsonArray\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn (this.IsJsonArray)\n\t\t\t\t\t? (JsonArray)this.reference\n\t\t\t\t\t: null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this value as a system.DateTime.\n\t\t/// </summary>\n\t\tpublic DateTime? AsDateTime\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (this.IsString && DateTime.TryParse((string)this.reference, out DateTime value))\n\t\t\t\t{\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets this (inner) value as a System.object.\n\t\t/// </summary>\n\t\tpublic object AsObject\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tswitch (this.Type)\n\t\t\t\t{\n\t\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\t\tcase JsonValueType.Number:\n\t\t\t\t\t\treturn this.value;\n\n\t\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\tcase JsonValueType.Object:\n\t\t\t\t\tcase JsonValueType.Array:\n\t\t\t\t\t\treturn this.reference;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets or sets the value associated with the specified key.\n\t\t/// </summary>\n\t\t/// <param name=\"key\">The key of the value to get or set.</param>\n\t\t/// <exception cref=\"System.InvalidOperationException\">\n\t\t/// Thrown when this JsonValue is not a JsonObject.\n\t\t/// </exception>\n\t\tpublic JsonValue this[string key]\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (this.IsJsonObject)\n\t\t\t\t{\n\t\t\t\t\treturn ((JsonObject)this.reference)[key];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException(\"This value does not represent a JsonObject.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (this.IsJsonObject)\n\t\t\t\t{\n\t\t\t\t\t((JsonObject)this.reference)[key] = value;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException(\"This value does not represent a JsonObject.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets or sets the value at the specified index.\n\t\t/// </summary>\n\t\t/// <param name=\"index\">The zero-based index of the value to get or set.</param>\n\t\t/// <exception cref=\"System.InvalidOperationException\">\n\t\t/// Thrown when this JsonValue is not a JsonArray\n\t\t/// </exception>\n\t\tpublic JsonValue this[int index]\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\tif (this.IsJsonArray)\n\t\t\t\t{\n\t\t\t\t\treturn ((JsonArray)this.reference)[index];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException(\"This value does not represent a JsonArray.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (this.IsJsonArray)\n\t\t\t\t{\n\t\t\t\t\t((JsonArray)this.reference)[index] = value;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new InvalidOperationException(\"This value does not represent a JsonArray.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct.\n\t\t/// </summary>\n\t\t/// <param name=\"type\">The Json type of the JsonValue.</param>\n\t\t/// <param name=\"value\">\n\t\t/// The internal value of the JsonValue.\n\t\t/// This is used when the Json type is Number or Boolean.\n\t\t/// </param>\n\t\t/// <param name=\"reference\">\n\t\t/// The internal value reference of the JsonValue.\n\t\t/// This value is used when the Json type is String, JsonObject, or JsonArray.\n\t\t/// </param>\n\t\tprivate JsonValue(JsonValueType type, double value, object reference)\n\t\t{\n\t\t\tthis.type      = type;\n\t\t\tthis.value     = value;\n\t\t\tthis.reference = reference;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct, representing a Boolean value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be wrapped.</param>\n\t\tpublic JsonValue(bool? value)\n\t\t{\n\t\t\tif (value.HasValue)\n\t\t\t{\n\t\t\t\tthis.reference = null;\n\n\t\t\t\tthis.type = JsonValueType.Boolean;\n\n\t\t\t\tthis.value = value.Value ? 1 : 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis = JsonValue.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct, representing a Number value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be wrapped.</param>\n\t\tpublic JsonValue(double? value)\n\t\t{\n\t\t\tif (value.HasValue)\n\t\t\t{\n\t\t\t\tthis.reference = null;\n\n\t\t\t\tthis.type = JsonValueType.Number;\n\n\t\t\t\tthis.value = value.Value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis = JsonValue.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct, representing a String value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be wrapped.</param>\n\t\tpublic JsonValue(string value)\n\t\t{\n\t\t\tif (value != null)\n\t\t\t{\n\t\t\t\tthis.value = default(double);\n\n\t\t\t\tthis.type = JsonValueType.String;\n\n\t\t\t\tthis.reference = value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis = JsonValue.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct, representing a JsonObject.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be wrapped.</param>\n\t\tpublic JsonValue(JsonObject value)\n\t\t{\n\t\t\tif (value != null)\n\t\t\t{\n\t\t\t\tthis.value = default(double);\n\n\t\t\t\tthis.type = JsonValueType.Object;\n\n\t\t\t\tthis.reference = value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis = JsonValue.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the JsonValue struct, representing a Array reference value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be wrapped.</param>\n\t\tpublic JsonValue(JsonArray value)\n\t\t{\n\t\t\tif (value != null)\n\t\t\t{\n\t\t\t\tthis.value = default(double);\n\n\t\t\t\tthis.type = JsonValueType.Array;\n\n\t\t\t\tthis.reference = value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthis = JsonValue.Null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given nullable boolean into a JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(bool? value)\n\t\t{\n\t\t\treturn new JsonValue(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given nullable double into a JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(double? value)\n\t\t{\n\t\t\treturn new JsonValue(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given string into a JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(string value)\n\t\t{\n\t\t\treturn new JsonValue(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonObject into a JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(JsonObject value)\n\t\t{\n\t\t\treturn new JsonValue(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonArray into a JsonValue.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(JsonArray value)\n\t\t{\n\t\t\treturn new JsonValue(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given DateTime? into a JsonValue.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The DateTime value will be stored as a string using ISO 8601 format,\n\t\t/// since JSON does not define a DateTime type.\n\t\t/// </remarks>\n\t\t/// <param name=\"value\">The value to be converted.</param>\n\t\tpublic static implicit operator JsonValue(DateTime? value)\n\t\t{\n\t\t\tif (value == null)\n\t\t\t{\n\t\t\t\treturn JsonValue.Null;\n\t\t\t}\n\n\t\t\treturn new JsonValue(value.Value.ToString(\"o\"));\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into an Int.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator int(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsInteger)\n\t\t\t{\n\t\t\t\treturn jsonValue.AsInteger;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a nullable Int.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\t/// <exception cref=\"System.InvalidCastException\">\n\t\t/// Throws System.InvalidCastException when the inner value type of the\n\t\t/// JsonValue is not the desired type of the conversion.\n\t\t/// </exception>\n\t\tpublic static implicit operator int?(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn (int)jsonValue;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a Bool.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator bool(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsBoolean)\n\t\t\t{\n\t\t\t\treturn (jsonValue.value == 1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a nullable Bool.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\t/// <exception cref=\"System.InvalidCastException\">\n\t\t/// Throws System.InvalidCastException when the inner value type of the\n\t\t/// JsonValue is not the desired type of the conversion.\n\t\t/// </exception>\n\t\tpublic static implicit operator bool?(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn (bool)jsonValue;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a Double.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator double(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsNumber)\n\t\t\t{\n\t\t\t\treturn jsonValue.value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn double.NaN;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a nullable Double.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\t/// <exception cref=\"System.InvalidCastException\">\n\t\t/// Throws System.InvalidCastException when the inner value type of the\n\t\t/// JsonValue is not the desired type of the conversion.\n\t\t/// </exception>\n\t\tpublic static implicit operator double?(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn (double)jsonValue;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a String.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator string(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsString || jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn jsonValue.reference as string;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a JsonObject.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator JsonObject(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsJsonObject || jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn jsonValue.reference as JsonObject;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a JsonArray.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator JsonArray(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsJsonArray || jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn jsonValue.reference as JsonArray;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a DateTime.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator DateTime(JsonValue jsonValue)\n\t\t{\n\t\t\tvar dateTime = jsonValue.AsDateTime;\n\n\t\t\tif (dateTime.HasValue)\n\t\t\t{\n\t\t\t\treturn dateTime.Value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn DateTime.MinValue;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Converts the given JsonValue into a nullable DateTime.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to be converted.</param>\n\t\tpublic static implicit operator DateTime?(JsonValue jsonValue)\n\t\t{\n\t\t\tif (jsonValue.IsDateTime || jsonValue.IsNull)\n\t\t\t{\n\t\t\t\treturn jsonValue.AsDateTime;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a value indicating whether the two given JsonValues are equal.\n\t\t/// </summary>\n\t\t/// <param name=\"a\">A JsonValue to compare.</param>\n\t\t/// <param name=\"b\">A JsonValue to compare.</param>\n\t\tpublic static bool operator ==(JsonValue a, JsonValue b)\n\t\t{\n\t\t\treturn (a.Type == b.Type)\n\t\t\t\t&& (a.value == b.value)\n\t\t\t\t&& Equals(a.reference, b.reference);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a value indicating whether the two given JsonValues are unequal.\n\t\t/// </summary>\n\t\t/// <param name=\"a\">A JsonValue to compare.</param>\n\t\t/// <param name=\"b\">A JsonValue to compare.</param>\n\t\tpublic static bool operator !=(JsonValue a, JsonValue b)\n\t\t{\n\t\t\treturn !(a == b);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JsonValue by parsing the given string.\n\t\t/// </summary>\n\t\t/// <param name=\"text\">The JSON-formatted string to be parsed.</param>\n\t\tpublic static JsonValue Parse(string text)\n\t\t{\n\t\t\treturn JsonReader.Parse(text);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a value indicating whether this JsonValue is equal to the given object.\n\t\t/// </summary>\n\t\t/// <param name=\"obj\">The object to test.</param>\n\t\tpublic override bool Equals(object obj)\n\t\t{\n\t\t\tif (obj == null)\n\t\t\t{\n\t\t\t\treturn this.IsNull;\n\t\t\t}\n\n\t\t\tvar jsonValue = obj as JsonValue?;\n\n\t\t\tif (jsonValue.HasValue)\n\t\t\t{\n\t\t\t\treturn (this == jsonValue.Value);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a hash code for this JsonValue.\n\t\t/// </summary>\n\t\tpublic override int GetHashCode()\n\t\t{\n\t\t\tif (this.IsNull)\n\t\t\t{\n\t\t\t\treturn this.Type.GetHashCode();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn this.Type.GetHashCode()\n\t\t\t\t\t^ this.value.GetHashCode()\n\t\t\t\t\t^ EqualityComparer<object>.Default.GetHashCode(this.reference);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the object.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\tpublic override string ToString()\n\t\t{\n\t\t\treturn ToString(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Returns a JSON string representing the state of the object.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The resulting string is safe to be inserted as is into dynamically\n\t\t/// generated JavaScript or JSON code.\n\t\t/// </remarks>\n\t\t/// <param name=\"pretty\">\n\t\t/// Indicates whether the resulting string should be formatted for human-readability.\n\t\t/// </param>\n\t\tpublic string ToString(bool pretty)\n\t\t{\n\t\t\treturn JsonWriter.Serialize(this, pretty);\n\t\t}\n\n\t\tprivate class JsonValueDebugView\n\t\t{\n\t\t\tprivate JsonValue jsonValue;\n\n\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n\t\t\tpublic JsonObject ObjectView\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\tif (jsonValue.IsJsonObject)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn (JsonObject)jsonValue.reference;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n\t\t\tpublic JsonArray ArrayView\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\tif (jsonValue.IsJsonArray)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn (JsonArray)jsonValue.reference;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic JsonValueType Type\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\treturn jsonValue.Type;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic object Value\n\t\t\t{\n\t\t\t\tget\n\t\t\t\t{\n\t\t\t\t\tif (jsonValue.IsJsonObject)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn (JsonObject)jsonValue.reference;\n\t\t\t\t\t}\n\t\t\t\t\telse if (jsonValue.IsJsonArray)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn (JsonArray)jsonValue.reference;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn jsonValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic JsonValueDebugView(JsonValue jsonValue)\n\t\t\t{\n\t\t\t\tthis.jsonValue = jsonValue;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/JsonValueType.cs",
    "content": "﻿namespace Lens.lightJson\n{\n\t/// <summary>\n\t/// Enumerates the types of Json values.\n\t/// </summary>\n\tpublic enum JsonValueType : byte\n\t{\n\t\t/// <summary>\n\t\t/// A null value.\n\t\t/// </summary>\n\t\tNull = 0,\n\n\t\t/// <summary>\n\t\t/// A boolean value.\n\t\t/// </summary>\n\t\tBoolean,\n\n\t\t/// <summary>\n\t\t/// A number value.\n\t\t/// </summary>\n\t\tNumber,\n\n\t\t/// <summary>\n\t\t/// A string value.\n\t\t/// </summary>\n\t\tString,\n\n\t\t/// <summary>\n\t\t/// An object value.\n\t\t/// </summary>\n\t\tObject,\n\n\t\t/// <summary>\n\t\t/// An array value.\n\t\t/// </summary>\n\t\tArray,\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/README.md",
    "content": "# Light Json Parser\n\n**This code was not written by me (@egordorichev)**\nFull credit goes to [the author of this amazing library](https://github.com/MarcosLopezC/LightJson).\nAt this point, I have no idea, why I did not install it using NuGet like any other library, this was a long time ago."
  },
  {
    "path": "Lens/lightJson/Serialization/JsonParseException.cs",
    "content": "using System;\n\nnamespace Lens.lightJson.Serialization\n{\n\t/// <summary>\n\t/// The exception that is thrown when a JSON message cannot be parsed.\n\t/// </summary>\n\t/// <remarks>\n\t/// This exception is only intended to be thrown by LightJson.\n\t/// </remarks>\n\tpublic sealed class JsonParseException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Gets the text position where the error occurred.\n\t\t/// </summary>\n\t\tpublic TextPosition Position { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Gets the type of error that caused the exception to be thrown.\n\t\t/// </summary>\n\t\tpublic ErrorType Type { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonParseException.\n\t\t/// </summary>\n\t\tpublic JsonParseException()\n\t\t\t: base(GetDefaultMessage(ErrorType.Unknown)) { }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonParseException with the given error type and position.\n\t\t/// </summary>\n\t\t/// <param name=\"type\">The error type that describes the cause of the error.</param>\n\t\t/// <param name=\"position\">The position in the text where the error occurred.</param>\n\t\tpublic JsonParseException(ErrorType type, TextPosition position)\n\t\t\t: this(GetDefaultMessage(type), type, position) { }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonParseException with the given message, error type, and position.\n\t\t/// </summary>\n\t\t/// <param name=\"message\">The message that describes the error.</param>\n\t\t/// <param name=\"type\">The error type that describes the cause of the error.</param>\n\t\t/// <param name=\"position\">The position in the text where the error occurred.</param>\n\t\tpublic JsonParseException(string message, ErrorType type, TextPosition position)\n\t\t\t: base(message)\n\t\t{\n\t\t\tthis.Type = type;\n\t\t\tthis.Position = position;\n\t\t}\n\n\t\tprivate static string GetDefaultMessage(ErrorType type)\n\t\t{\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\t\tcase ErrorType.IncompleteMessage:\n\t\t\t\t\treturn \"The string ended before a value could be parsed.\";\n\n\t\t\t\tcase ErrorType.InvalidOrUnexpectedCharacter:\n\t\t\t\t\treturn \"The parser encountered an invalid or unexpected character.\";\n\n\t\t\t\tcase ErrorType.DuplicateObjectKeys:\n\t\t\t\t\treturn \"The parser encountered a JsonObject with duplicate keys.\";\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"An error occurred while parsing the JSON message.\";\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Enumerates the types of errors that can occur when parsing a JSON message.\n\t\t/// </summary>\n\t\tpublic enum ErrorType : int\n\t\t{\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the cause of the error is unknown.\n\t\t\t/// </summary>\n\t\t\tUnknown = 0,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the text ended before the message could be parsed.\n\t\t\t/// </summary>\n\t\t\tIncompleteMessage,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that a JsonObject contains more than one key with the same name.\n\t\t\t/// </summary>\n\t\t\tDuplicateObjectKeys,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the parser encountered and invalid or unexpected character.\n\t\t\t/// </summary>\n\t\t\tInvalidOrUnexpectedCharacter,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/Serialization/JsonReader.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.IO;\nusing System.Text;\n\nnamespace Lens.lightJson.Serialization\n{\n\tusing ErrorType = JsonParseException.ErrorType;\n\n\t/// <summary>\n\t/// Represents a reader that can read JsonValues.\n\t/// </summary>\n\tpublic sealed class JsonReader\n\t{\n\t\tprivate TextScanner scanner;\n\n\t\tprivate JsonReader(TextReader reader)\n\t\t{\n\t\t\tthis.scanner = new TextScanner(reader);\n\t\t}\n\n\t\tprivate string ReadJsonKey()\n\t\t{\n\t\t\treturn ReadString();\n\t\t}\n\n\t\tprivate JsonValue ReadJsonValue()\n\t\t{\n\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\tvar next = this.scanner.Peek();\n\n\t\t\tif (char.IsNumber(next))\n\t\t\t{\n\t\t\t\treturn ReadNumber();\n\t\t\t}\n\n\t\t\tswitch (next)\n\t\t\t{\n\t\t\t\tcase '{':\n\t\t\t\t\treturn ReadObject();\n\n\t\t\t\tcase '[':\n\t\t\t\t\treturn ReadArray();\n\n\t\t\t\tcase '\"':\n\t\t\t\t\treturn ReadString();\n\n\t\t\t\tcase '-':\n\t\t\t\t\treturn ReadNumber();\n\n\t\t\t\tcase 't':\n\t\t\t\tcase 'f':\n\t\t\t\t\treturn ReadBoolean();\n\n\t\t\t\tcase 'n':\n\t\t\t\t\treturn ReadNull();\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tprivate JsonValue ReadNull()\n\t\t{\n\t\t\tthis.scanner.Assert(\"null\");\n\t\t\treturn JsonValue.Null;\n\t\t}\n\n\t\tprivate JsonValue ReadBoolean()\n\t\t{\n\t\t\tswitch (this.scanner.Peek())\n\t\t\t{\n\t\t\t\tcase 't':\n\t\t\t\t\tthis.scanner.Assert(\"true\");\n\t\t\t\t\treturn true;\n\n\t\t\t\tcase 'f':\n\t\t\t\t\tthis.scanner.Assert(\"false\");\n\t\t\t\t\treturn false;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tprivate void ReadDigits(StringBuilder builder)\n\t\t{\n\t\t\twhile (this.scanner.CanRead && char.IsDigit(this.scanner.Peek()))\n\t\t\t{\n\t\t\t\tbuilder.Append(this.scanner.Read());\n\t\t\t}\n\t\t}\n\n\t\tprivate JsonValue ReadNumber()\n\t\t{\n\t\t\tvar builder = new StringBuilder();\n\n\t\t\tif (this.scanner.Peek() == '-')\n\t\t\t{\n\t\t\t\tbuilder.Append(this.scanner.Read());\n\t\t\t}\n\n\t\t\tif (this.scanner.Peek() == '0')\n\t\t\t{\n\t\t\t\tbuilder.Append(this.scanner.Read());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tReadDigits(builder);\n\t\t\t}\n\n\t\t\tif (this.scanner.CanRead && this.scanner.Peek() == '.')\n\t\t\t{\n\t\t\t\tbuilder.Append(this.scanner.Read());\n\t\t\t\tReadDigits(builder);\n\t\t\t}\n\n\t\t\tif (this.scanner.CanRead && char.ToLowerInvariant(this.scanner.Peek()) == 'e')\n\t\t\t{\n\t\t\t\tbuilder.Append(this.scanner.Read());\n\n\t\t\t\tvar next = this.scanner.Peek();\n\n\t\t\t\tswitch (next)\n\t\t\t\t{\n\t\t\t\t\tcase '+':\n\t\t\t\t\tcase '-':\n\t\t\t\t\t\tbuilder.Append(this.scanner.Read());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tReadDigits(builder);\n\t\t\t}\n\n\t\t\treturn double.Parse(\n\t\t\t\tbuilder.ToString(),\n\t\t\t\tCultureInfo.InvariantCulture\n\t\t\t);\n\t\t}\n\n\t\tprivate string ReadString()\n\t\t{\n\t\t\tvar builder = new StringBuilder();\n\n\t\t\tthis.scanner.Assert('\"');\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tvar c = this.scanner.Read();\n\n\t\t\t\tif (c == '\\\\')\n\t\t\t\t{\n\t\t\t\t\tc = this.scanner.Read();\n\n\t\t\t\t\tswitch (char.ToLower(c))\n\t\t\t\t\t{\n\t\t\t\t\t\tcase '\"':  // \"\n\t\t\t\t\t\tcase '\\\\': // \\\n\t\t\t\t\t\tcase '/':  // /\n\t\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\t\tbuilder.Append('\\b');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'f':\n\t\t\t\t\t\t\tbuilder.Append('\\f');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'n':\n\t\t\t\t\t\t\tbuilder.Append('\\n');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'r':\n\t\t\t\t\t\t\tbuilder.Append('\\r');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 't':\n\t\t\t\t\t\t\tbuilder.Append('\\t');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'u':\n\t\t\t\t\t\t\tbuilder.Append(ReadUnicodeLiteral());\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (c == '\"')\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (char.IsControl(c))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tbuilder.Append(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn builder.ToString();\n\t\t}\n\n\t\tprivate int ReadHexDigit()\n\t\t{\n\t\t\tswitch (char.ToUpper(this.scanner.Read()))\n\t\t\t{\n\t\t\t\tcase '0':\n\t\t\t\t\treturn 0;\n\n\t\t\t\tcase '1':\n\t\t\t\t\treturn 1;\n\n\t\t\t\tcase '2':\n\t\t\t\t\treturn 2;\n\n\t\t\t\tcase '3':\n\t\t\t\t\treturn 3;\n\n\t\t\t\tcase '4':\n\t\t\t\t\treturn 4;\n\n\t\t\t\tcase '5':\n\t\t\t\t\treturn 5;\n\n\t\t\t\tcase '6':\n\t\t\t\t\treturn 6;\n\n\t\t\t\tcase '7':\n\t\t\t\t\treturn 7;\n\n\t\t\t\tcase '8':\n\t\t\t\t\treturn 8;\n\n\t\t\t\tcase '9':\n\t\t\t\t\treturn 9;\n\n\t\t\t\tcase 'A':\n\t\t\t\t\treturn 10;\n\n\t\t\t\tcase 'B':\n\t\t\t\t\treturn 11;\n\n\t\t\t\tcase 'C':\n\t\t\t\t\treturn 12;\n\n\t\t\t\tcase 'D':\n\t\t\t\t\treturn 13;\n\n\t\t\t\tcase 'E':\n\t\t\t\t\treturn 14;\n\n\t\t\t\tcase 'F':\n\t\t\t\t\treturn 15;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tprivate char ReadUnicodeLiteral()\n\t\t{\n\t\t\tint value = 0;\n\n\t\t\tvalue += ReadHexDigit() * 4096; // 16^3\n\t\t\tvalue += ReadHexDigit() * 256;  // 16^2\n\t\t\tvalue += ReadHexDigit() * 16;   // 16^1\n\t\t\tvalue += ReadHexDigit();        // 16^0\n\n\t\t\treturn (char)value;\n\t\t}\n\n\t\tprivate JsonObject ReadObject()\n\t\t{\n\t\t\treturn ReadObject(new JsonObject());\n\t\t}\n\n\t\tprivate JsonObject ReadObject(JsonObject jsonObject)\n\t\t{\n\t\t\tthis.scanner.Assert('{');\n\n\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\tif (this.scanner.Peek() == '}')\n\t\t\t{\n\t\t\t\tthis.scanner.Read();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tvar key = ReadJsonKey();\n\n\t\t\t\t\tif (jsonObject.ContainsKey(key))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\t\tErrorType.DuplicateObjectKeys,\n\t\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tthis.scanner.Assert(':');\n\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tvar value = ReadJsonValue();\n\n\t\t\t\t\tjsonObject.Add(key, value);\n\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tvar next = this.scanner.Read();\n\n\t\t\t\t\tif (next == '}')\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (next == ',')\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn jsonObject;\n\t\t}\n\n\t\tprivate JsonArray ReadArray()\n\t\t{\n\t\t\treturn ReadArray(new JsonArray());\n\t\t}\n\n\t\tprivate JsonArray ReadArray(JsonArray jsonArray)\n\t\t{\n\t\t\tthis.scanner.Assert('[');\n\n\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\tif (this.scanner.Peek() == ']')\n\t\t\t{\n\t\t\t\tthis.scanner.Read();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tvar value = ReadJsonValue();\n\n\t\t\t\t\tjsonArray.Add(value);\n\n\t\t\t\t\tthis.scanner.SkipWhitespace();\n\n\t\t\t\t\tvar next = this.scanner.Read();\n\n\t\t\t\t\tif (next == ']')\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (next == ',')\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\t\t\tthis.scanner.Position\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn jsonArray;\n\t\t}\n\n\t\tprivate JsonValue Parse()\n\t\t{\n\t\t\tthis.scanner.SkipWhitespace();\n\t\t\treturn ReadJsonValue();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a JsonValue by using the given TextReader.\n\t\t/// </summary>\n\t\t/// <param name=\"reader\">The TextReader used to read a JSON message.</param>\n\t\tpublic static JsonValue Parse(TextReader reader)\n\t\t{\n\t\t\tif (reader == null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"reader\");\n\t\t\t}\n\n\t\t\treturn new JsonReader(reader).Parse();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a JsonValue by reader the JSON message in the given string.\n\t\t/// </summary>\n\t\t/// <param name=\"source\">The string containing the JSON message.</param>\n\t\tpublic static JsonValue Parse(string source)\n\t\t{\n\t\t\tif (source == null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"source\");\n\t\t\t}\n\n\t\t\tusing (var reader = new StringReader(source))\n\t\t\t{\n\t\t\t\treturn new JsonReader(reader).Parse();\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates a JsonValue by reading the given file.\n\t\t/// </summary>\n\t\t/// <param name=\"path\">The file path to be read.</param>\n\t\tpublic static JsonValue ParseFile(string path)\n\t\t{\n\t\t\tif (path == null)\n\t\t\t{\n\t\t\t\tthrow new ArgumentNullException(\"path\");\n\t\t\t}\n\n\t\t\tusing (var reader = new StreamReader(path))\n\t\t\t{\n\t\t\t\treturn new JsonReader(reader).Parse();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/Serialization/JsonSerializationException.cs",
    "content": "﻿using System;\n\nnamespace Lens.lightJson.Serialization\n{\n\t/// <summary>\n\t/// The exception that is thrown when a JSON value cannot be serialized.\n\t/// </summary>\n\t/// <remarks>\n\t/// This exception is only intended to be thrown by LightJson.\n\t/// </remarks>\n\tpublic sealed class JsonSerializationException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Gets the type of error that caused the exception to be thrown.\n\t\t/// </summary>\n\t\tpublic ErrorType Type { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonSerializationException.\n\t\t/// </summary>\n\t\tpublic JsonSerializationException()\n\t\t\t: base(GetDefaultMessage(ErrorType.Unknown)) { }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonSerializationException with the given error type.\n\t\t/// </summary>\n\t\t/// <param name=\"type\">The error type that describes the cause of the error.</param>\n\t\tpublic JsonSerializationException(ErrorType type)\n\t\t\t: this(GetDefaultMessage(type), type) { }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonSerializationException with the given message and error type.\n\t\t/// </summary>\n\t\t/// <param name=\"message\">The message that describes the error.</param>\n\t\t/// <param name=\"type\">The error type that describes the cause of the error.</param>\n\t\tpublic JsonSerializationException(string message, ErrorType type)\n\t\t\t: base(message)\n\t\t{\n\t\t\tthis.Type = type;\n\t\t}\n\n\t\tprivate static string GetDefaultMessage(ErrorType type)\n\t\t{\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\t\tcase ErrorType.InvalidNumber:\n\t\t\t\t\treturn \"The value been serialized contains an invalid number value (NAN, infinity).\";\n\n\t\t\t\tcase ErrorType.InvalidValueType:\n\t\t\t\t\treturn \"The value been serialized contains (or is) an invalid JSON type.\";\n\n\t\t\t\tcase ErrorType.CircularReference:\n\t\t\t\t\treturn \"The value been serialized contains circular references.\";\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"An error occurred during serialization.\";\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Enumerates the types of errors that can occur during serialization.\n\t\t/// </summary>\n\t\tpublic enum ErrorType : int\n\t\t{\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the cause of the error is unknown.\n\t\t\t/// </summary>\n\t\t\tUnknown = 0,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the writer encountered an invalid number value (NAN, infinity) during serialization.\n\t\t\t/// </summary>\n\t\t\tInvalidNumber,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the object been serialized contains an invalid JSON value type.\n\t\t\t/// That is, a value type that is not null, boolean, number, string, object, or array.\n\t\t\t/// </summary>\n\t\t\tInvalidValueType,\n\n\t\t\t/// <summary>\n\t\t\t/// Indicates that the object been serialized contains a circular reference.\n\t\t\t/// </summary>\n\t\t\tCircularReference,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/Serialization/JsonWriter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\n\nnamespace Lens.lightJson.Serialization\n{\n\tusing ErrorType = JsonSerializationException.ErrorType;\n\n\t/// <summary>\n\t/// Represents a TextWriter adapter that can write string representations of JsonValues.\n\t/// </summary>\n\tpublic sealed class JsonWriter\n\t{\n\t\tprivate int indent;\n\t\tprivate bool isNewLine;\n\n\t\t/// <summary>\n\t\t/// A set of containing all the collection objects (JsonObject/JsonArray) being rendered.\n\t\t/// It is used to prevent circular references; since collections that contain themselves\n\t\t/// will never finish rendering.\n\t\t/// </summary>\n\t\tprivate HashSet<IEnumerable<JsonValue>> renderingCollections;\n\n\t\t/// <summary>\n\t\t/// Gets or sets the string representing a indent in the output.\n\t\t/// </summary>\n\t\tpublic string IndentString { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets the string representing a space in the output.\n\t\t/// </summary>\n\t\tpublic string SpacingString { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets the string representing a new line on the output.\n\t\t/// </summary>\n\t\tpublic string NewLineString { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets a value indicating whether JsonObject properties should be written in a deterministic order.\n\t\t/// </summary>\n\t\tpublic bool SortObjects { get; set; }\n\n\t\t/// <summary>\n\t\t/// Gets or sets the TextWriter to which this JsonWriter writes.\n\t\t/// </summary>\n\t\tpublic TextWriter InnerWriter { get; set; }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonWriter.\n\t\t/// </summary>\n\t\t/// <param name=\"innerWriter\">The TextWriter used to write JsonValues.</param>\n\t\tpublic JsonWriter(TextWriter innerWriter) : this(innerWriter, false) { }\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of JsonWriter.\n\t\t/// </summary>\n\t\t/// <param name=\"innerWriter\">The TextWriter used to write JsonValues.</param>\n\t\t/// <param name=\"pretty\">\n\t\t/// A value indicating whether the output of the writer should be human-readable.\n\t\t/// </param>\n\t\tpublic JsonWriter(TextWriter innerWriter, bool pretty)\n\t\t{\n\t\t\tif (pretty)\n\t\t\t{\n\t\t\t\tthis.IndentString = \"\\t\";\n\t\t\t\tthis.SpacingString = \" \";\n\t\t\t\tthis.NewLineString = \"\\n\";\n\t\t\t}\n\n\t\t\trenderingCollections = new HashSet<IEnumerable<JsonValue>>();\n\n\t\t\tInnerWriter = innerWriter;\n\t\t}\n\n\t\tprivate void Write(string text)\n\t\t{\n\t\t\tif (this.isNewLine)\n\t\t\t{\n\t\t\t\tthis.isNewLine = false;\n\t\t\t\tWriteIndentation();\n\t\t\t}\n\n\t\t\tInnerWriter.Write(text);\n\t\t}\n\n\t\tprivate void WriteEncodedJsonValue(JsonValue value)\n\t\t{\n\t\t\tswitch (value.Type)\n\t\t\t{\n\t\t\t\tcase JsonValueType.Null:\n\t\t\t\t\tWrite(\"null\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\t\tWrite(value.AsString);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Number:\n\t\t\t\t\tif (!IsValidNumber(value))\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new JsonSerializationException(ErrorType.InvalidNumber);\n\t\t\t\t\t}\n\n\t\t\t\t\tWrite(((double)value).ToString(CultureInfo.InvariantCulture));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\tWriteEncodedString((string)value);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Object:\n\t\t\t\t\tWrite(string.Format(\"JsonObject[{0}]\", value.AsJsonObject.Count));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Array:\n\t\t\t\t\tWrite(string.Format(\"JsonArray[{0}]\", value.AsJsonArray.Count));\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new InvalidOperationException(\"Invalid value type.\");\n\t\t\t}\n\t\t}\n\n\t\tprivate void WriteEncodedString(string text)\n\t\t{\n\t\t\tWrite(\"\\\"\");\n\n\t\t\tfor (int i = 0; i < text.Length; i += 1)\n\t\t\t{\n\t\t\t\tvar currentChar = text[i];\n\n\t\t\t\t// Encoding special characters.\n\t\t\t\tswitch (currentChar)\n\t\t\t\t{\n\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\\\\\\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\\\\"\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '/':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\/\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\b':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\b\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\f':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\f\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\n\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\r':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\r\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\tInnerWriter.Write(\"\\\\t\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tInnerWriter.Write(currentChar);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tInnerWriter.Write(\"\\\"\");\n\t\t}\n\n\t\tprivate void WriteIndentation()\n\t\t{\n\t\t\tfor (var i = 0; i < this.indent; i += 1)\n\t\t\t{\n\t\t\t\tWrite(this.IndentString);\n\t\t\t}\n\t\t}\n\n\t\tprivate void WriteSpacing()\n\t\t{\n\t\t\tWrite(this.SpacingString);\n\t\t}\n\n\t\tprivate void WriteLine()\n\t\t{\n\t\t\tWrite(this.NewLineString);\n\t\t\tthis.isNewLine = true;\n\t\t}\n\n\t\tprivate void WriteLine(string line)\n\t\t{\n\t\t\tWrite(line);\n\t\t\tWriteLine();\n\t\t}\n\n\t\tprivate void AddRenderingCollection(IEnumerable<JsonValue> value)\n\t\t{\n\t\t\tif (!renderingCollections.Add(value))\n\t\t\t{\n\t\t\t\tthrow new JsonSerializationException(ErrorType.CircularReference);\n\t\t\t}\n\t\t}\n\n\t\tprivate void RemoveRenderingCollection(IEnumerable<JsonValue> value)\n\t\t{\n\t\t\trenderingCollections.Remove(value);\n\t\t}\n\n\t\tprivate void Render(JsonValue value)\n\t\t{\n\t\t\tswitch (value.Type)\n\t\t\t{\n\t\t\t\tcase JsonValueType.Null:\n\t\t\t\tcase JsonValueType.Boolean:\n\t\t\t\tcase JsonValueType.Number:\n\t\t\t\tcase JsonValueType.String:\n\t\t\t\t\tWriteEncodedJsonValue(value);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Object:\n\t\t\t\t\tRender((JsonObject)value);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase JsonValueType.Array:\n\t\t\t\t\tRender((JsonArray)value);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new JsonSerializationException(ErrorType.InvalidValueType);\n\t\t\t}\n\t\t}\n\n\t\tprivate void Render(JsonArray value)\n\t\t{\n\t\t\tAddRenderingCollection(value);\n\n\t\t\tWriteLine(\"[\");\n\n\t\t\tindent += 1;\n\n\t\t\tusing (var enumerator = value.GetEnumerator())\n\t\t\t{\n\t\t\t\tvar hasNext = enumerator.MoveNext();\n\n\t\t\t\twhile (hasNext)\n\t\t\t\t{\n\t\t\t\t\tRender(enumerator.Current);\n\n\t\t\t\t\thasNext = enumerator.MoveNext();\n\n\t\t\t\t\tif (hasNext)\n\t\t\t\t\t{\n\t\t\t\t\t\tWriteLine(\",\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tWriteLine();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tindent -= 1;\n\n\t\t\tWrite(\"]\");\n\n\t\t\tRemoveRenderingCollection(value);\n\t\t}\n\n\t\tprivate void Render(JsonObject value)\n\t\t{\n\t\t\tAddRenderingCollection(value);\n\n\t\t\tWriteLine(\"{\");\n\n\t\t\tindent += 1;\n\n\t\t\tusing(var enumerator = GetJsonObjectEnumerator(value))\n\t\t\t{\n\t\t\t\tvar hasNext = enumerator.MoveNext();\n\n\t\t\t\twhile (hasNext)\n\t\t\t\t{\n\t\t\t\t\tWriteEncodedString(enumerator.Current.Key);\n\t\t\t\t\tWrite(\":\");\n\t\t\t\t\tWriteSpacing();\n\t\t\t\t\tRender(enumerator.Current.Value);\n\n\t\t\t\t\thasNext = enumerator.MoveNext();\n\n\t\t\t\t\tif (hasNext)\n\t\t\t\t\t{\n\t\t\t\t\t\tWriteLine(\",\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tWriteLine();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tindent -= 1;\n\n\t\t\tWrite(\"}\");\n\n\t\t\tRemoveRenderingCollection(value);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets an JsonObject enumarator based on the configuration of this JsonWriter.\n\t\t/// If JsonWriter.SortObjects is set to true, then a ordered enumerator is returned.\n\t\t/// Otherwise, a faster non-deterministic enumerator is returned.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonObject\">The JsonObject for which to get an enumerator.</param>\n\t\tprivate IEnumerator<KeyValuePair<string, JsonValue>> GetJsonObjectEnumerator(JsonObject jsonObject)\n\t\t{\n\t\t\tif (this.SortObjects)\n\t\t\t{\n\t\t\t\tvar sortedDictionary = new SortedDictionary<string, JsonValue>(StringComparer.Ordinal);\n\n\t\t\t\tforeach (var item in jsonObject)\n\t\t\t\t{\n\t\t\t\t\tsortedDictionary.Add(item.Key, item.Value);\n\t\t\t\t}\n\n\t\t\t\treturn sortedDictionary.GetEnumerator();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn jsonObject.GetEnumerator();\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Writes the given value to the InnerWriter.\n\t\t/// </summary>\n\t\t/// <param name=\"jsonValue\">The JsonValue to write.</param>\n\t\tpublic void Write(JsonValue jsonValue)\n\t\t{\n\t\t\tthis.indent = 0;\n\t\t\tthis.isNewLine = true;\n\n\t\t\tRender(jsonValue);\n\n\t\t\tthis.renderingCollections.Clear();\n\t\t}\n\n\t\tprivate static bool IsValidNumber(double number)\n\t\t{\n\t\t\treturn !(double.IsNaN(number) || double.IsInfinity(number));\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Generates a string representation of the given value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to serialize.</param>\n\t\tpublic static string Serialize(JsonValue value)\n\t\t{\n\t\t\treturn Serialize(value, false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Generates a string representation of the given value.\n\t\t/// </summary>\n\t\t/// <param name=\"value\">The value to serialize.</param>\n\t\t/// <param name=\"pretty\">Indicates whether the resulting string should be formatted for human-readability.</param>\n\t\tpublic static string Serialize(JsonValue value, bool pretty)\n\t\t{\n\t\t\tusing (var stringWriter = new StringWriter())\n\t\t\t{\n\t\t\t\tvar jsonWriter = new JsonWriter(stringWriter, pretty);\n\n\t\t\t\tjsonWriter.Write(value);\n\n\t\t\t\treturn stringWriter.ToString();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/Serialization/TextPosition.cs",
    "content": "﻿namespace Lens.lightJson.Serialization\n{\n\t/// <summary>\n\t/// Represents a position within a plain text resource.\n\t/// </summary>\n\tpublic struct TextPosition\n\t{\n\t\t/// <summary>\n\t\t/// The column position, 0-based.\n\t\t/// </summary>\n\t\tpublic long column;\n\n\t\t/// <summary>\n\t\t/// The line position, 0-based.\n\t\t/// </summary>\n\t\tpublic long line;\n\t}\n}\n"
  },
  {
    "path": "Lens/lightJson/Serialization/TextScanner.cs",
    "content": "﻿using System;\nusing System.IO;\n\nnamespace Lens.lightJson.Serialization\n{\n\tusing ErrorType = JsonParseException.ErrorType;\n\n\t/// <summary>\n\t/// Represents a text scanner that reads one character at a time.\n\t/// </summary>\n\tpublic sealed class TextScanner\n\t{\n\t\tprivate TextReader reader;\n\t\tprivate TextPosition position;\n\n\t\t/// <summary>\n\t\t/// Gets the position of the scanner within the text.\n\t\t/// </summary>\n\t\tpublic TextPosition Position\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn this.position;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets a value indicating whether there are still characters to be read.\n\t\t/// </summary>\n\t\tpublic bool CanRead\n\t\t{\n\t\t\tget\n\t\t\t{\n\t\t\t\treturn (this.reader.Peek() != -1);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of TextScanner.\n\t\t/// </summary>\n\t\t/// <param name=\"reader\">The TextReader to read the text.</param>\n\t\tpublic TextScanner(TextReader reader)\n\t\t{\n\t\t\tthis.reader = reader ?? throw new ArgumentNullException(nameof(reader));\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Reads the next character in the stream without changing the current position.\n\t\t/// </summary>\n\t\tpublic char Peek()\n\t\t{\n\t\t\tvar next = reader.Peek();\n\n\t\t\tif (next == -1)\n\t\t\t{\n\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\tErrorType.IncompleteMessage,\n\t\t\t\t\tthis.position\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn (char)next;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Reads the next character in the stream, advancing the text position.\n\t\t/// </summary>\n\t\tpublic char Read()\n\t\t{\n\t\t\tvar next = reader.Read();\n\n\t\t\tif (next == -1)\n\t\t\t{\n\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\tErrorType.IncompleteMessage,\n\t\t\t\t\tthis.position\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tswitch (next)\n\t\t\t{\n\t\t\t\tcase '\\r':\n\t\t\t\t\t// Normalize '\\r\\n' line encoding to '\\n'.\n\t\t\t\t\tif (reader.Peek() == '\\n')\n\t\t\t\t\t{\n\t\t\t\t\t\treader.Read();\n\t\t\t\t\t}\n\t\t\t\t\tgoto case '\\n';\n\n\t\t\t\tcase '\\n':\n\t\t\t\t\tthis.position.line += 1;\n\t\t\t\t\tthis.position.column = 0;\n\t\t\t\t\treturn '\\n';\n\n\t\t\t\tdefault:\n\t\t\t\t\tthis.position.column += 1;\n\t\t\t\t\treturn (char)next;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Advances the scanner to next non-whitespace character.\n\t\t/// </summary>\n\t\tpublic void SkipWhitespace()\n\t\t{\n\t\t\twhile (char.IsWhiteSpace(Peek()))\n\t\t\t{\n\t\t\t\tRead();\n\t\t\t}\n\n\t\t\tif (Peek() == '/') {\n\t\t\t\tRead();\n\n\t\t\t\tif (Peek() != '/') {\n\t\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\t\tErrorType.IncompleteMessage,\n\t\t\t\t\t\tthis.position\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\twhile (Peek() != '\\n')\n\t\t\t\t{\n\t\t\t\t\tRead();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSkipWhitespace();\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Verifies that the given character matches the next character in the stream.\n\t\t/// If the characters do not match, an exception will be thrown.\n\t\t/// </summary>\n\t\t/// <param name=\"next\">The expected character.</param>\n\t\tpublic void Assert(char next)\n\t\t{\n\t\t\tif (Peek() == next)\n\t\t\t{\n\t\t\t\tRead();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\tstring.Format(\"Parser expected '{0}'\", next),\n\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\tthis.position\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Verifies that the given string matches the next characters in the stream.\n\t\t/// If the strings do not match, an exception will be thrown.\n\t\t/// </summary>\n\t\t/// <param name=\"next\">The expected string.</param>\n\t\tpublic void Assert(string next)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tfor (var i = 0; i < next.Length; i += 1)\n\t\t\t\t{\n\t\t\t\t\tAssert(next[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (JsonParseException e) when (e.Type == ErrorType.InvalidOrUnexpectedCharacter)\n\t\t\t{\n\t\t\t\tthrow new JsonParseException(\n\t\t\t\t\tstring.Format(\"Parser expected '{0}'\", next),\n\t\t\t\t\tErrorType.InvalidOrUnexpectedCharacter,\n\t\t\t\t\tthis.position\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"ImGui.NET\" version=\"1.70.0\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.NETCore.Platforms\" version=\"1.1.0\" targetFramework=\"net471\" />\n  <package id=\"Microsoft.Win32.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"MonoGame.Extended\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Content.Pipeline\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Graphics\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Extended.Tiled\" version=\"3.8.0\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.Content.Pipeline.Portable\" version=\"3.7.1.189\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.DesktopGL.Core\" version=\"3.8.0.13\" targetFramework=\"net472\" />\n  <package id=\"MonoGame.Framework.Portable\" version=\"3.7.1.189\" targetFramework=\"net472\" />\n  <package id=\"NAudio\" version=\"1.10.0\" targetFramework=\"net472\" />\n  <package id=\"NETStandard.Library\" version=\"2.0.0\" targetFramework=\"net471\" />\n  <package id=\"Newtonsoft.Json\" version=\"12.0.3\" targetFramework=\"net472\" />\n  <package id=\"SharpFNT\" version=\"1.1.0\" targetFramework=\"net471\" />\n  <package id=\"System.AppContext\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Buffers\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Collections.Concurrent\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Console\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Debug\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.DiagnosticSource\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Tools\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Diagnostics.Tracing\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Globalization\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Globalization.Calendars\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.Compression\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.Compression.ZipFile\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.FileSystem\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.IO.FileSystem.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Linq\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Linq.Expressions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Memory\" version=\"4.5.0-preview2-26406-04\" targetFramework=\"net472\" />\n  <package id=\"System.Net.Http\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Net.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Net.Sockets\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Numerics.Vectors\" version=\"4.4.0\" targetFramework=\"net471\" />\n  <package id=\"System.ObjectModel\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Reflection.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Resources.ResourceManager\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.CompilerServices.Unsafe\" version=\"4.5.0-preview2-26406-04\" targetFramework=\"net472\" />\n  <package id=\"System.Runtime.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.Handles\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.InteropServices\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.InteropServices.RuntimeInformation\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Runtime.Numerics\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Algorithms\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Encoding\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.Primitives\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Security.Cryptography.X509Certificates\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.Encoding\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.Encoding.Extensions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Text.RegularExpressions\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading.Tasks\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Threading.Timer\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.ValueTuple\" version=\"4.5.0\" targetFramework=\"net472\" />\n  <package id=\"System.Xml.ReaderWriter\" version=\"4.3.0\" targetFramework=\"net471\" />\n  <package id=\"System.Xml.XDocument\" version=\"4.3.0\" targetFramework=\"net471\" />\n</packages>"
  },
  {
    "path": "Lens/util/FrameCounter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Lens.util {\n\tpublic class FrameCounter {\n\t\tpublic const int MaximumSamples = 30;\n\n\t\tprivate Queue<float> buffer = new Queue<float>();\n\n\t\tpublic long TotalFrames { get; private set; }\n\t\tpublic float TotalSeconds { get; private set; }\n\t\tpublic int AverageFramesPerSecond { get; private set; }\n\t\tpublic int CurrentFramesPerSecond { get; private set; }\n\n\t\tpublic void Update(float deltaTime) {\n\t\t\tCurrentFramesPerSecond = (int) Math.Round(1.0f / deltaTime);\n\n\t\t\tbuffer.Enqueue(CurrentFramesPerSecond);\n\n\t\t\tif (buffer.Count > MaximumSamples) {\n\t\t\t\tbuffer.Dequeue();\n\t\t\t\tAverageFramesPerSecond = (int) Math.Round(buffer.Average(i => i));\n\t\t\t} else {\n\t\t\t\tAverageFramesPerSecond = CurrentFramesPerSecond;\n\t\t\t}\n\n\t\t\tTotalFrames++;\n\t\t\tTotalSeconds += deltaTime;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/Log.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\n\nnamespace Lens.util {\n\tpublic static class Log {\n\t\tprivate const string LogName = \"burning_log.txt\";\n\n\t\tpublic static bool WriteToFile = !Engine.Debug;\n\t\tprivate static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400);\n\t\tprivate static StreamWriter writer;\n\n\t\tpublic static void Open() {\n\t\t\tif (File.Exists(LogName)) {\n\t\t\t\ttry {\n\t\t\t\t\tFile.Delete(LogName);\n\t\t\t\t} catch (Exception e) {\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (WriteToFile) {\n\t\t\t\twriter = new StreamWriter(new FileStream(LogName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite));\n\t\t\t}\n\t\t}\n\n\t\tpublic static void Close() {\n\t\t\ttry {\n\t\t\t\twriter?.Close();\n\t\t\t\twriter = null;\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void Info(object message) {\n\t\t\tPrint(message, ConsoleColor.Green, \"INF\");\n\t\t}\n\t\t\n\t\tpublic static void Debug(object message) {\n\t\t\tPrint(message, ConsoleColor.Blue, \"DBG\");\n\t\t}\n\t\t\n\t\tpublic static void Error(object message) {\n\t\t\tPrint(message, ConsoleColor.DarkRed, \"ERR\");\n\t\t}\n\t\t\n\t\tpublic static void Warning(object message) {\n\t\t\tPrint(message, ConsoleColor.DarkYellow, \"WRN\");\n\t\t}\n\n\t\tprivate static void Print(object message, ConsoleColor color, string type) {\n\n\t\t\ttry {\n\t\t\t\tvar stackTrace = new StackTrace(true);\n\t\t\t\tvar frame = stackTrace.GetFrame(2);\n\t\t\t\tvar prev = stackTrace.GetFrame(3);\n\n#if DEBUG\n\t\t\t\tvar text = prev == null ? $\"{DateTime.Now:h:mm:ss} {Path.GetFileName(frame.GetFileName())}:{frame.GetMethod().Name}():{frame.GetFileLineNumber()}\" : $\"{DateTime.Now:h:mm:ss} {Path.GetFileName(frame.GetFileName())}:{frame.GetMethod().Name}():{frame.GetFileLineNumber()} <= {Path.GetFileName(prev.GetFileName())}:{prev.GetMethod().Name}():{prev.GetFileLineNumber()} \";\n#else\n\t\t\t\tvar text = prev == null ?  $\"{DateTime.Now:h:mm:ss} {frame.GetMethod().Name}()\" :  $\"{DateTime.Now:h:mm:ss} {frame.GetMethod().Name}() <= {prev.GetMethod().Name}() \";\n#endif\n\n\t\t\t\twriter?.Write($\"{type} {text}\");\n\t\t\t\twriter?.WriteLine(message == null ? \"null\" : message.ToString());\n\n\t\t\t\tConsole.ForegroundColor = color;\n\t\t\t\tConsole.Write($\"{message} \");\n\t\t\t\tConsole.ForegroundColor = ConsoleColor.Gray;\n\t\t\t\tConsole.WriteLine(text);\n\t\t\t} catch (Exception e) {\n\t\t\t\tConsole.WriteLine(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/MathUtils.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.util {\n\tpublic class MathUtils {\n\t\tpublic static Vector2 Normal = new Vector2(1, 1);\n\t\tpublic static Vector2 InvertX = new Vector2(-1, 1);\n\t\tpublic static Vector2 InvertY = new Vector2(1, -1);\n\t\tpublic static Vector2 InvertXY = new Vector2(-1, -1);\n\t\tpublic static Vector2 DoubleScale = new Vector2(2);\n\t\t\n\t\tpublic static Vector2[] Directions = {\n\t\t\tnew Vector2(-1, 0),\n\t\t\tnew Vector2(1, 0),\n\t\t\tnew Vector2(0, 1),\n\t\t\tnew Vector2(0, -1)\n\t\t};\n\t\t\n\t\tpublic static Vector2[] AllDirections = {\n\t\t\tnew Vector2(-1, 0),\n\t\t\tnew Vector2(1, 0),\n\t\t\tnew Vector2(0, 1),\n\t\t\tnew Vector2(0, -1),\n\t\t\tnew Vector2(-1, -1),\n\t\t\tnew Vector2(-1, 1),\n\t\t\tnew Vector2(1, 1),\n\t\t\tnew Vector2(1, -1)\n\t\t};\n\t\t\n\t\tpublic static Vector2[] EntityDirections = {\n\t\t\tnew Vector2(-1, 0),\n\t\t\tnew Vector2(1, 0),\n\t\t\tnew Vector2(0, -1)\n\t\t};\n\n\n\t\tpublic static float Mod(float a, float b) {\n\t\t\treturn (float) (a - b * Math.Floor(a / b));\n\t\t}\n\t\t\n\t\tpublic static double Mod(double a, double b) {\n\t\t\treturn a - b * Math.Floor(a / b);\n\t\t}\n\t\t\n\t\tpublic static float Clamp(float Min, float Max, float Val) {\n\t\t\tif (Min > Max) {\n\t\t\t\tvar tmp = Min;\n\t\t\t\tMin = Max;\n\t\t\t\tMax = tmp;\n\t\t\t}\n\t\t\t\n\t\t\treturn Math.Max(Min, Math.Min(Max, Val));\n\t\t}\n\t\t\n\t\tpublic static int Clamp(int Min, int Max, int Val) {\n\t\t\tif (Min > Max) {\n\t\t\t\tvar tmp = Min;\n\t\t\t\tMin = Max;\n\t\t\t\tMax = tmp;\n\t\t\t}\n\t\t\t\n\t\t\treturn Math.Max(Min, Math.Min(Max, Val));\n\t\t}\n\n\t\tpublic static float Map(float X, float In_min, float In_max, float Out_min, float Out_max) {\n\t\t\treturn (X - In_min) * (Out_max - Out_min) / (In_max - In_min) + Out_min;\n\t\t}\n\n\t\tpublic static double LerpAngle(double a, double to, float dt) {\n\t\t\treturn a + ShortAngleDistance(a, to) * dt;\n\t\t}\n\n\t\tpublic static float Distance(float dx, float dy) {\n\t\t\treturn (float) Math.Sqrt(dx * dx + dy * dy);\n\t\t}\n\n\t\tpublic static float Angle(float dx, float dy) {\n\t\t\treturn (float) Math.Atan2(dy, dx);\n\t\t}\n\t\t\n\t\tpublic static double ShortAngleDistance(double a0, double a1) {\n\t\t\tdouble max = Math.PI * 2;\n\t\t\tdouble da = (a1 - a0) % max;\n\t\t\treturn 2 * da % max - da;\n\t\t}\n\n\t\tpublic static Vector2 RotateAround(Vector2 point, float angle, Vector2 origin) {\n\t\t\tvar s = Math.Sin(angle);\n\t\t\tvar c = Math.Cos(angle);\n\n\t\t\tvar p = point - origin;\n\n\t\t\tp.X = (float) (point.X * c - point.Y * s);\n\t\t\tp.Y = (float) (point.X * s + point.Y * c);\n\t\t\t\n\t\t\treturn p + origin;\n\t\t}\n\n\t\tpublic static Vector2 CreateVector(double angle, float distance) {\n\t\t\treturn new Vector2((float) Math.Cos(angle) * distance, (float) Math.Sin(angle) * distance);\n\t\t}\n\n\t\tpublic static string ToRoman(int number) {\n\t\t\tif (number >= 1000) {\n\t\t\t\treturn \"M\" + ToRoman(number - 1000);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 500) {\n\t\t\t\treturn \"D\" + ToRoman(number - 500);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 100) {\n\t\t\t\treturn \"C\" + ToRoman(number - 100);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 50) {\n\t\t\t\treturn \"L\" + ToRoman(number - 50);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 40) {\n\t\t\t\treturn \"XL\" + ToRoman(number - 40);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 10) {\n\t\t\t\treturn \"X\" + ToRoman(number - 10);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 9) {\n\t\t\t\treturn \"IX\" + ToRoman(number - 9);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 5) {\n\t\t\t\treturn \"V\" + ToRoman(number - 5);\n\t\t\t}\n\t\t\t\n\t\t\tif (number >= 4) {\n\t\t\t\treturn \"IV\" + ToRoman(number - 4);\n\t\t\t}\n\t\t\t\n\t\t\tif (number > 1) {\n\t\t\t\treturn \"I\" + ToRoman(number - 1);\n\t\t\t}\n\n\t\t\tif (number == 1) {\n\t\t\t\treturn \"I\";\n\t\t\t}\n\n\t\t\treturn \"???\";\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/Noise.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace Lens.util {\n\tpublic class Noise {\n\t\t#region fBm functions\n\n\t\tpublic static float Fbm(Vector2 coord, int octave) {\n\t\t\tvar f = 0.0f;\n\t\t\tvar w = 0.5f;\n\t\t\tfor (var i = 0; i < octave; i++) {\n\t\t\t\tf += w * Generate(coord.X, coord.Y);\n\t\t\t\tcoord *= 2.0f;\n\t\t\t\tw *= 0.5f;\n\t\t\t}\n\n\t\t\treturn f;\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Noise functions\n\n\t\tpublic static float Generate(float x) {\n\t\t\tvar X = (int) x & 0xff;\n\t\t\tx -= (int) x;\n\t\t\tvar u = Fade(x);\n\t\t\treturn Lerp(u, Grad(perm[X], x), Grad(perm[X + 1], x - 1)) * 2;\n\t\t}\n\n\t\tpublic static float Generate(float x, float y) {\n\t\t\tvar X = (int) x & 0xff;\n\t\t\tvar Y = (int) y & 0xff;\n\t\t\tx -= (int) x;\n\t\t\ty -= (int) y;\n\t\t\tvar u = Fade(x);\n\t\t\tvar v = Fade(y);\n\t\t\tvar A = (perm[X] + Y) & 0xff;\n\t\t\tvar B = (perm[X + 1] + Y) & 0xff;\n\t\t\treturn Lerp(v, Lerp(u, Grad(perm[A], x, y), Grad(perm[B], x - 1, y)),\n\t\t\t\tLerp(u, Grad(perm[A + 1], x, y - 1), Grad(perm[B + 1], x - 1, y - 1)));\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Private functions\n\n\t\tprivate static float Fade(float t) {\n\t\t\treturn t * t * t * (t * (t * 6 - 15) + 10);\n\t\t}\n\n\t\tprivate static float Lerp(float t, float a, float b) {\n\t\t\treturn a + t * (b - a);\n\t\t}\n\n\t\tprivate static float Grad(int hash, float x) {\n\t\t\treturn (hash & 1) == 0 ? x : -x;\n\t\t}\n\n\t\tprivate static float Grad(int hash, float x, float y) {\n\t\t\treturn ((hash & 1) == 0 ? x : -x) + ((hash & 2) == 0 ? y : -y);\n\t\t}\n\n\t\tprivate static float Grad(int hash, float x, float y, float z) {\n\t\t\tvar h = hash & 15;\n\t\t\tvar u = h < 8 ? x : y;\n\t\t\tvar v = h < 4 ? y : (h == 12 || h == 14 ? x : z);\n\t\t\treturn ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);\n\t\t}\n\n\t\tprivate static int[] perm = {\n\t\t\t151, 160, 137, 91, 90, 15,\n\t\t\t131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23,\n\t\t\t190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,\n\t\t\t88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,\n\t\t\t77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244,\n\t\t\t102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,\n\t\t\t135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123,\n\t\t\t5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,\n\t\t\t223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,\n\t\t\t129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228,\n\t\t\t251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107,\n\t\t\t49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,\n\t\t\t138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,\n\t\t\t151\n\t\t};\n\n\t\t#endregion\n\t}\n}"
  },
  {
    "path": "Lens/util/NumberExtensions.cs",
    "content": "﻿using System;\n\nnamespace Lens.util {\n\tpublic static class NumberExtensions {\n\t\tpublic static double ToRadians(this double val) {\n\t\t\treturn (Math.PI / 180) * val;\n\t\t}\n\t\t\n\t\tpublic static float ToRadians(this float val) {\n\t\t\treturn (float) ((Math.PI / 180) * val);\n\t\t}\n\n\t\tpublic static double ToDegrees(this double val) {\n\t\t\treturn Math.PI * val / 180.0;\n\t\t}\n\t\t\n\t\tpublic static float ToDegrees(this float val) {\n\t\t\treturn (float) (Math.PI * val / 180.0);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/VectorExtension.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.util {\n\tpublic static class VectorExtension {\n\t\tpublic static Vector2 Lerp(this Vector2 self, Vector2 target, float speed) {\n\t\t\tself.X += (target.X - self.X) * speed;\n\t\t\tself.Y += (target.Y - self.Y) * speed;\n\n\t\t\treturn self;\n\t\t}\n\n\t\tpublic static float ToAngle(this Vector2 self) {\n\t\t\treturn (float) Math.Atan2(self.Y, self.X);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/Web.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace Lens.util {\n\tpublic static class Web {\n\t\tpublic static void Open(string url) {\n\t\t\ttry {\n\t\t\t\tLog.Info($\"Navigating to {url}\");\n\t\t\t\tvar webPage = new ProcessStartInfo(url);\n\t\t\t\tProcess.Start(webPage);\n\t\t\t} catch (Exception e) {\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/camera/Camera.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Lens.entity;\nusing Lens.entity.component.logic;\nusing Lens.graphics;\nusing Lens.graphics.gamerenderer;\nusing Microsoft.Xna.Framework;\nusing MonoGame.Extended;\nusing Color = Microsoft.Xna.Framework.Color;\nusing Matrix = Microsoft.Xna.Framework.Matrix;\nusing RectangleF = MonoGame.Extended.RectangleF;\nusing Vector2 = Microsoft.Xna.Framework.Vector2;\nusing Vector3 = Microsoft.Xna.Framework.Vector3;\nusing Viewport = Microsoft.Xna.Framework.Graphics.Viewport;\n\nnamespace Lens.util.camera {\n\tpublic class Camera : Entity {\n\t\tpublic const int TargetPadding = 16;\n\t\t\n\t\tpublic static bool Debug = true;\n\t\tpublic static Camera Instance;\n\n\t\tpublic static Action OnShake;\n\n\t\tpublic Vector2 TopLeft => new Vector2(X, Y);\n\t\t// Todo: count zoom here?\n\t\tpublic new float X {\n\t\t\tget => position.X - Width / 2;\n\t\t\tset => PositionX = value + Width / 2;\n\t\t}\n\n\t\tpublic new float Y {\n\t\t\tget => position.Y - Height / 2;\n\t\t\tset => PositionY = value + Height / 2;\n\t\t}\n\n\t\tpublic new float Right {\n\t\t\tget => position.X + Width / 2;\n\t\t\tset => PositionX = value - Width / 2;\n\t\t}\n\n\t\tpublic new float Bottom {\n\t\t\tget => position.Y + Height / 2;\n\t\t\tset => PositionY = value - Height / 2;\n\t\t}\n\t\t\n\t\tpublic bool Sees(Entity entity) {\n\t\t\treturn !(entity.X - 4 > Right ||\n\t\t\t         entity.Right + 4 < X ||\n\t\t\t         entity.Y - 4 > Bottom ||\n\t\t\t         entity.Bottom + entity.Height < Y);\n\t\t}\n\t\t\n\t\t#region Camera logic\n\n\t\tpublic class Target {\n\t\t\tpublic float Priority;\n\t\t\tpublic Entity Entity;\n\n\t\t\tpublic Target(Entity entity, float priority) {\n\t\t\t\tEntity = entity;\n\t\t\t\tPriority = priority;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic List<Target> Targets = new List<Target>();\n\t\tpublic Entity MainTarget;\n\t\tpublic bool Detached;\n\t\tpublic float TextureZoom = 1f;\n\t\t\n\t\tprivate CameraDriver driver;\n\t\t\n\t\tpublic CameraDriver Driver {\n\t\t\tget => driver;\n\n\t\t\tset {\n\t\t\t\tdriver?.Destroy();\n\t\t\t\tdriver = value;\n\t\t\t\tdriver.Camera = this;\n\t\t\t\tdriver?.Init();\n\t\t\t}\n\t\t}\n\n\t\tpublic Camera(CameraDriver driver) {\n\t\t\tInstance = this;\n\t\t\tDriver = driver;\n\n\t\t\tWidth = Display.Width;\n\t\t\tHeight = Display.Height;\n\n\t\t\tViewport = new Viewport();\n\t\t\tViewport.Width = Display.Width;\n\t\t\tViewport.Height = Display.Height;\n\n\t\t\torigin = new Vector2(Display.Width / 2f, Display.Height / 2f);\n\n\t\t\tAlwaysActive = true;\n\t\t\tAlwaysVisible = true;\n\n\t\t\tchanged = true;\n\t\t}\n\n\t\tpublic void Shake(float a = 1f) {\n\t\t\tvar component = GetComponent<ShakeComponent>();\n\t\t\tcomponent.Amount = Math.Min(component.Amount + a, 20f);\n\t\t\t\n\t\t\tOnShake?.Invoke();\n\t\t}\n\n\t\tpublic void ShakeMax(float a = 1f) {\n\t\t\tvar component = GetComponent<ShakeComponent>();\n\t\t\tcomponent.Amount = Math.Min(Math.Max(component.Amount, a), 20f);\n\t\t\t\n\t\t\tOnShake?.Invoke();\n\t\t}\n\n\t\tpublic void Push(float angle, float force) {\n\t\t\tvar component = GetComponent<ShakeComponent>();\n\t\t\t\n\t\t\tcomponent.Push = force;\n\t\t\tcomponent.PushDirection = new Vector2((float) Math.Cos(angle), (float) Math.Sin(angle));\n\t\t}\n\t\t\n\t\tpublic override void AddComponents() {\n\t\t\tbase.AddComponents();\n\t\t\tAddComponent(new ShakeComponent());\n\t\t}\n\n\t\tpublic void Follow(Entity entity, float priority, bool main = false) {\n\t\t\tif (entity == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tTargets.Add(new Target(entity, priority));\n\n\t\t\tif (main) {\n\t\t\t\tMainTarget = entity;\n\t\t\t}\n\t\t}\n\n\t\tpublic void Unfollow(Entity entity) {\n\t\t\tTarget tar = null;\n\t\t\t\n\t\t\tforeach (var t in Targets) {\n\t\t\t\tif (t.Entity == entity) {\n\t\t\t\t\ttar = t;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tar != null) {\n\t\t\t\tTargets.Remove(tar);\n\t\t\t}\n\n\t\t\tif (MainTarget == entity) {\n\t\t\t\tMainTarget = null;\n\t\t\t}\n\t\t}\n\n\t\tprivate Vector2 lastPosition;\n\t\tpublic Vector2 PositionDelta => Position - lastPosition;\n\n\t\tpublic override void Update(float dt) {\n\t\t\tbase.Update(dt);\n\t\t\t\n\t\t\tif (Engine.Instance.State.Paused) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int i = Targets.Count - 1; i >= 0; i--) {\n\t\t\t\tif (Targets[i].Entity.Done) {\n\t\t\t\t\tTargets.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastPosition = Position;\n\t\t\t\n\t\t\tif (!Detached) {\n\t\t\t\tdriver?.Update(dt);\n\n\t\t\t\tif (MainTarget != null) {\n\t\t\t\t\tX = Math.Min(X, MainTarget.X - TargetPadding);\n\t\t\t\t\tRight = Math.Max(Right, MainTarget.Right + TargetPadding);\n\t\t\t\t\tY = Math.Min(Y, MainTarget.Y - TargetPadding);\n\t\t\t\t\tBottom = Math.Max(Bottom, MainTarget.Bottom + TargetPadding);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (changed) {\n\t\t\t\tUpdateMatrices();\n\t\t\t}\n\t\t}\n\n\t\tpublic override void Destroy() {\n\t\t\tbase.Destroy();\n\t\t\tdriver?.Destroy();\n\t\t\tInstance = null;\n\t\t}\n\n\t\tpublic Vector2 ScreenToCamera(Vector2 position) {\n\t\t\treturn Vector2.Transform(position, Matrix.Invert(Engine.ScreenMatrix) * scaledInverseMatrix);\n\t\t}\n\n\t\tpublic Vector2 CameraToScreen(Vector2 position) {\n\t\t\treturn Vector2.Transform(position, scaledMatrix);\n\t\t}\n\t\t\n\t\tpublic Vector2 CameraToUi(Vector2 position) {\n\t\t\treturn (CameraToScreen(position) - new Vector2(Position.X % 1, \n\t\t\t\t          Position.Y % 1)) * Display.UiScale;\n\t\t}\n\t\t\n\t\tpublic void Approach(Vector2 position, float ease) {\n\t\t\tPosition += (position - Position) * ease;\n\t\t}\n\n\t\tpublic void Approach(Vector2 position, float ease, float maxDistance) {\n\t\t\tvar move = (position - Position) * ease;\n\t\t\t\n\t\t\tif (move.Length() > maxDistance) {\n\t\t\t\tPosition = Vector2.Normalize(move) * maxDistance;\n\t\t\t} else {\n\t\t\t\tPosition += move;\n\t\t\t}\n\t\t}\n\n\t\t#endregion\n\n\t\t#region Camera matrix\n\n\t\tpublic Viewport Viewport;\n\n\t\tprivate Matrix matrix = Matrix.Identity;\n\t\tprivate Matrix scaledMatrix = Matrix.Identity;\n\t\tprivate Matrix scaledInverseMatrix = Matrix.Identity;\n\t\tprivate Matrix inverse = Matrix.Identity;\n\t\tprivate Vector2 position;\n\t\tprivate Vector2 origin;\n\t\tprivate float angle;\n\t\tprivate float zoom = 1f;\n\t\tprivate bool changed;\n\n\t\tpublic Matrix Matrix => matrix;\n\t\t\n\t\tpublic new Vector2 Position {\n\t\t\tget => position;\n\n\t\t\tset {\n\t\t\t\tposition = value;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic float PositionX {\n\t\t\tget => position.X;\n\n\t\t\tset {\n\t\t\t\tposition.X = value;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic float PositionY {\n\t\t\tget => position.Y;\n\n\t\t\tset {\n\t\t\t\tposition.Y = value;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic Vector2 Origin {\n\t\t\tget => origin;\n\n\t\t\tset {\n\t\t\t\torigin = value;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic float Angle {\n\t\t\tget => angle;\n\n\t\t\tset {\n\t\t\t\tangle = value;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic float Zoom {\n\t\t\tget => zoom;\n\n\t\t\tset {\n\t\t\t\tzoom = value;\n\t\t\t\tWidth = Display.Width / zoom;\n\t\t\t\tHeight = Display.Height / zoom;\n\t\t\t\t\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tpublic void UpdateMatrices() {\n\t\t\tvar a = Matrix.Identity *\n\t\t\t        Matrix.CreateTranslation(new Vector3(\n\t\t\t\t        -new Vector2((int) Math.Floor(position.X), (int) Math.Floor(position.Y)), 0)) *\n\t\t\t        Matrix.CreateRotationZ(angle);\n\n\t\t\tvar b = Matrix.CreateTranslation(\n\t\t\t\tnew Vector3(new Vector2((int) Math.Floor(origin.X), (int) Math.Floor(origin.Y)), 0));\n\t\t\t\n\t\t\tmatrix = a * Matrix.CreateScale(new Vector3(zoom, zoom, 1)) * b;\n\t\t\tscaledMatrix = a * Matrix.CreateScale(new Vector3(zoom * PixelPerfectGameRenderer.GameScale, zoom * PixelPerfectGameRenderer.GameScale, 1)) * b;\n\t\t\t               \n\t\t\tinverse = Matrix.Invert(matrix);\n\t\t\tscaledInverseMatrix = Matrix.Invert(scaledMatrix);\n\t\t\tchanged = false;\n\t\t}\n\n\t\t#endregion\n\t\t\n\t\tprivate static Color DebugColor = new Color(1, 1, 1, 0.5f);\n\n\t\tpublic void Jump() {\n\t\t\tposition.X = 0;\n\t\t\tposition.Y = 0;\n\n\t\t\tforeach (var follow in Targets) {\n\t\t\t\tif (follow.Entity is CustomCameraJumper c) {\n\t\t\t\t\tposition += c.Jump(follow);\n\t\t\t\t} else {\n\t\t\t\t\tposition.X += follow.Priority * follow.Entity.CenterX;\n\t\t\t\t\tposition.Y += follow.Priority * follow.Entity.CenterY;\t\t\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchanged = true;\n\t\t}\n\t\t\n\t\tpublic override void RenderDebug() {\n\t\t\tif (!Debug) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t// Graphics.Batch.DrawRectangle(new RectangleF(position.X - Display.Width / 2f, position.Y - Display.Height / 2f, Display.Width, Display.Height), Color.Wheat);\n\t\t\tGraphics.Batch.DrawRectangle(new RectangleF(Display.UiWidth / 2 - 4, Display.UiHeight / 2 - 4, 8, 8), DebugColor);\n\n\t\t\tfor (int x = 1; x < 3; x++) {\n\t\t\t\tfloat xx = x * Display.UiWidth / 3f;\n\t\t\t\tGraphics.Batch.DrawLine(new Vector2(xx, 0), new Vector2(xx, Display.UiHeight), DebugColor);\n\t\t\t}\n\t\t\t\n\t\t\tfor (int y = 1; y < 3; y++) {\n\t\t\t\tfloat yy = y * Display.UiHeight / 3f;\n\t\t\t\tGraphics.Batch.DrawLine(new Vector2(0, yy), new Vector2(Display.UiWidth, yy), DebugColor);\n\t\t\t}\n\n\t\t\tvar center = new Vector2();\n\t\t\tvar sum = 0f;\n\n\t\t\tforeach (var t in Targets) {\n\t\t\t\tvar pos = t.Entity.Center;\n\n\t\t\t\tsum = t.Priority;\n\t\t\t\tcenter += pos * t.Priority;\n\t\t\t\tGraphics.Batch.DrawCircle(new CircleF(new Point2(pos.X, pos.Y), 3f), 10, t.Entity == MainTarget ? Color.Red : Color.Pink);\n\t\t\t}\n\t\t\t\n\t\t\tGraphics.Batch.DrawCircle(new CircleF(new Point2(center.X / sum, center.Y / sum), 5f), 10, Color.Orange);\n\t\t}\n\t\t\n\t\tpublic override bool Overlaps(Entity entity) {\n\t\t\treturn !(entity.X > Right ||\n\t\t\t         entity.Right < X ||\n\t\t\t         entity.Y > Bottom ||\n\t\t\t         entity.Bottom < Y);\n\t\t}\n\t\t\n\t\tpublic override bool Overlaps(Rectangle entity) {\n\t\t\treturn !(entity.X > Right ||\n\t\t\t         entity.Right < X ||\n\t\t\t         entity.Y > Bottom ||\n\t\t\t         entity.Bottom < Y);\n\t\t}\n\n\n\t\tpublic override bool Contains(Entity entity) {\n\t\t\treturn entity.X >= X && entity.Right <= Right\n\t\t\t                     && entity.Y >= Y && entity.Bottom <= Bottom;\n\t\t}\n\n\t\tpublic override bool Contains(Vector2 point) {\n\t\t\treturn point.X >= X && point.X <= Right\n\t\t\t                    && point.Y >= Y && point.Y <= Bottom;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/camera/CameraDriver.cs",
    "content": "﻿namespace Lens.util.camera {\n\tpublic class CameraDriver {\n\t\tpublic Camera Camera;\n\t\t\n\t\tpublic virtual void Init() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Destroy() {\n\t\t\t\n\t\t}\n\n\t\tpublic virtual void Update(float dt) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/camera/CustomCameraJumper.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace Lens.util.camera {\n\tpublic interface CustomCameraJumper {\n\t\tVector2 Jump(Camera.Target target);\n\t}\n}"
  },
  {
    "path": "Lens/util/file/FileHandle.cs",
    "content": "﻿using System;\nusing System.IO;\nusing Lens.assets;\n\nnamespace Lens.util.file {\n\tpublic class FileHandle {\n\t\tprivate string path;\n\t\tpublic string FullPath => Path.GetFullPath(path);\n\t\tpublic string NameWithoutExtension => Path.GetFileNameWithoutExtension(path);\n\t\tpublic string Name => Path.GetFileName(path);\n\t\tpublic string Extension => Path.GetExtension(path);\n\t\tpublic string ParentName => Path.GetDirectoryName(path);\n\t\tpublic FileHandle Parent => new FileHandle(ParentName);\n\t\tpublic long LastModified => File.GetLastWriteTime(FullPath).ToFileTime();\n\n\t\tpublic FileHandle(string path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic static FileHandle FromRoot(string path) {\n\t\t\treturn new FileHandle(Assets.Root + path);\n\t\t}\n\t\t\n\t\tpublic static FileHandle FromNearRoot(string path) {\n\t\t\treturn new FileHandle(Assets.NearRoot + path);\n\t\t}\n\n\t\tpublic void MakeDirectory() {\n\t\t\tDirectory.CreateDirectory(path);\n\t\t}\n\n\t\tpublic void MakeFile() {\n\t\t\tFile.Create(path);\n\t\t}\n\n\t\tpublic string ReadAll() {\n\t\t\treturn File.ReadAllText(path);\n\t\t}\n\n\t\tpublic void Delete() {\n\t\t\tif (IsDirectory()) {\n\t\t\t\tDirectory.Delete(path);\n\t\t\t} else {\n\t\t\t\tFile.Delete(path);\n\t\t\t}\n\t\t}\n\n\t\tpublic FileHandle FindFile(string name) {\n\t\t\tname = Path.GetFileName(name);\n\t\t\tvar names = ListFiles();\n\n\t\t\tforeach (var id in names) {\n\t\t\t\tif (Path.GetFileName(id) == name) {\n\t\t\t\t\treturn new FileHandle(id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic FileHandle FindDirectory(string name) {\n\t\t\tname = Path.GetFileName(name);\n\t\t\tvar names = ListDirectories();\n\n\t\t\tforeach (var id in names) {\n\t\t\t\tif (Path.GetFileName(id) == name) {\n\t\t\t\t\treturn new FileHandle(id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic string[] ListFiles() {\n\t\t\treturn Directory.GetFiles(path);\n\t\t}\n\n\t\tpublic string[] ListDirectories() {\n\t\t\treturn Directory.GetDirectories(path);\n\t\t}\n\n\t\tpublic FileHandle[] ListFileHandles() {\n\t\t\treturn List(ListFiles());\n\t\t}\n\n\t\tpublic FileHandle[] ListDirectoryHandles() {\n\t\t\treturn List(ListDirectories());\n\t\t}\n\n\t\tprotected static FileHandle[] List(string[] names) {\n\t\t\tvar handles = new FileHandle[names.Length];\n\n\t\t\tfor (int i = 0; i < names.Length; i++) {\n\t\t\t\thandles[i] = new FileHandle(names[i]);\n\t\t\t}\n\n\t\t\treturn handles;\n\t\t}\n\n\t\tpublic bool Exists() {\n\t\t\treturn IsDirectory() ? Directory.Exists(path) : File.Exists(path);\n\t\t}\n\n\t\tpublic bool IsDirectory() {\n\t\t\ttry {\n\t\t\t\treturn File.GetAttributes(path).HasFlag(FileAttributes.Directory);\n\t\t\t} catch (Exception) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/file/FileReader.cs",
    "content": "using System;\nusing System.IO;\nusing System.Text;\n\nnamespace Lens.util.file {\n\tpublic class FileReader {\n\t\tprotected byte[] read;\n\t\tpublic byte[] Data => read;\n\n\t\tprivate int position;\n\n\t\tpublic int Position {\n\t\t\tget => position;\n\n\t\t\tset {\n\t\t\t\tposition = Math.Max(0, Math.Min(read.Length - 1, value));\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic FileReader(string path) {\n\t\t\tif (path == null) {\n\t\t\t\tread = new byte[1];\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tReadData(path);\n\t\t}\n\n\t\tprotected virtual void ReadData(string path) {\n\t\t\tvar file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);\n\t\t\tvar stream = new BinaryReader(file);\n\n\t\t\tread = new byte[file.Length];\n\n\t\t\tfor (var i = 0; i < file.Length; i++) {\n\t\t\t\tread[i] = (byte) file.ReadByte();\n\t\t\t}\n\n\t\t\tstream.Close();\n\t\t}\n\n\t\tpublic byte ReadByte() {\n\t\t\tif (read.Length == Position) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\treturn read[Position++];\n\t\t}\n\t\t\n\t\tpublic sbyte ReadSbyte() {\n\t\t\treturn (sbyte) ReadByte();\n\t\t}\n\n\t\tpublic bool ReadBoolean() {\n\t\t\treturn ReadByte() == 1;\n\t\t}\n\n\t\tpublic short ReadInt16() {\n\t\t\treturn (short) ((ReadByte() << 8) | ReadByte());\n\t\t}\n\n\t\tpublic ushort ReadUint16() {\n\t\t\treturn (ushort) ((ReadByte() << 8) | ReadByte());\n\t\t}\n\n\t\tpublic int ReadInt32() {\n\t\t\treturn (ReadByte() << 24) | (ReadByte() << 16) | (ReadByte() << 8) | ReadByte();\n\t\t}\n\n\t\tpublic ushort ReadUInt16() {\n\t\t\treturn (ushort) ((ReadByte() << 8) | ReadByte());\n\t\t}\n\n\t\tpublic uint ReadUInt32() {\n\t\t\treturn (uint) ((ReadByte() << 24) | (ReadByte() << 16) | (ReadByte() << 8) | ReadByte());\n\t\t}\n\n\t\tpublic string ReadString() {\n\t\t\tbyte length = ReadByte();\n\n\t\t\tif (length == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar result = new StringBuilder();\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tresult.Append((char) ReadByte());\n\t\t\t}\n\n\t\t\treturn result.ToString();\n\t\t}\n\n\t\tpublic float ReadFloat() {\n\t\t\treturn BitConverter.ToSingle(new[] { ReadByte(), ReadByte(), ReadByte(), ReadByte() }, 0);\n\t\t}\n\n\t\tpublic void SetData(byte[] data) {\n\t\t\tread = data;\n\t\t\tposition = 0;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/util/file/FileWriter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing BinaryWriter = System.IO.BinaryWriter;\n\nnamespace Lens.util.file {\n\tpublic class FileWriter {\n\t\tprivate BinaryWriter stream;\n\t\tprivate List<byte> cache = new List<byte>();\n\n\t\tpublic int CacheSize => cache.Count;\n\t\tpublic bool Cache;\n\t\t\n\t\tpublic FileWriter(string path, bool append = false) {\n\t\t\tOpenStream(path, append);\n\t\t}\n\n\t\tprotected virtual void OpenStream(string path, bool append) {\n\t\t\tstream = new BinaryWriter(File.Open(path, append ? FileMode.Append : FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite));\n\t\t}\n\n\t\tpublic void Flush() {\n\t\t\tforeach (var b in cache) {\n\t\t\t\tWriteByte(b);\n\t\t\t}\n\n\t\t\tcache.Clear();\n\t\t}\n\n\t\tprotected virtual void Write(byte value) {\n\t\t\tstream.Write(value);\n\t\t}\n\t\t\n\t\tpublic void WriteByte(byte value) {\n\t\t\tif (Cache) {\n\t\t\t\tcache.Add(value);\n\t\t\t} else {\n\t\t\t\tWrite(value);\n\t\t\t}\n\t\t}\n\n\t\tpublic unsafe void WriteSbyte(sbyte value) {\n\t\t\tWriteByte(*((byte*) &value));\n\t\t}\n\n\t\tpublic void WriteBoolean(bool value) {\n\t\t\tWriteByte((byte) (value ? 1 : 0));\n\t\t}\n\n\t\tpublic void WriteInt16(short value) {\n\t\t\tWriteByte((byte) (value >> 8));\n\t\t\tWriteByte((byte) value);\n\t\t}\n\t\t\n\t\tpublic void WriteUint16(ushort value) {\n\t\t\tWriteByte((byte) (value >> 8));\n\t\t\tWriteByte((byte) value);\n\t\t}\n\n\t\tpublic void WriteInt32(int value) {\n\t\t\tWriteByte((byte) ((value >> 24) & 0xFF));\n\t\t\tWriteByte((byte) ((value >> 16) & 0xFF));\n\t\t\tWriteByte((byte) ((value >> 8) & 0xFF));\n\t\t\tWriteByte((byte) (value & 0xFF));\n\t\t}\n\n\t\tpublic void WriteUInt16(ushort value) {\n\t\t\tWriteByte((byte) (value >> 8));\n\t\t\tWriteByte((byte) value);\n\t\t}\n\n\t\tpublic void WriteUInt32(uint value) {\n\t\t\tWriteByte((byte) ((value >> 24) & 0xFF));\n\t\t\tWriteByte((byte) ((value >> 16) & 0xFF));\n\t\t\tWriteByte((byte) ((value >> 8) & 0xFF));\n\t\t\tWriteByte((byte) (value & 0xFF));\n\t\t}\n\n\t\tpublic void WriteString(string str) {\n\t\t\tif (str == null) {\n\t\t\t\tWriteByte(0);\n\t\t\t} else {\n\t\t\t\tif (str.Length > 255) {\n\t\t\t\t\tLog.Error(\"String ${str} is longer than 255 chars! It will be trimmed to fit!\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tWriteByte((byte) str.Length);\n\n\t\t\t\tfor (var i = 0; i < Math.Min(255, str.Length); i++) {\n\t\t\t\t\tWriteByte((byte) str[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic unsafe void WriteFloat(float value) {\n\t\t\tuint val = *((uint*) &value);\n\n\t\t\tWriteByte((byte) (val & 0xFF));\n\t\t\tWriteByte((byte) ((val >> 8) & 0xFF));\n\t\t\tWriteByte((byte) ((val >> 16) & 0xFF));\n\t\t\tWriteByte((byte) ((val >> 24) & 0xFF));\n\t\t}\n\n\t\tpublic virtual void Close() {\n\t\t\ttry {\n\t\t\t\tstream.Close();\n\t\t\t} catch (Exception e) {\n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Lens/util/math/Calc.cs",
    "content": "﻿namespace Lens.util.math {\n\tpublic static class Calc {\n\t\tpublic static float Clamp(float value, float min, float max) {\n\t\t\treturn System.Math.Max(min, System.Math.Min(value, max));\n\t\t}\n\n\t\tpublic static bool IsBitSet(byte b, int pos) {\n\t\t\treturn (b & (1 << pos)) != 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/math/Rnd.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Lens.entity;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.util.math {\n\tpublic static class Rnd {\n\t\tprivate static System.Random random = new System.Random(Guid.NewGuid().GetHashCode());\n\t\tprivate static string seed;\n\t\tprivate static int intSeed;\n\n\t\tpublic static System.Random Generator => random;\n\t\t\n\t\tpublic static string Seed {\n\t\t\tget => seed;\n\n\t\t\tset {\n\t\t\t\tseed = value;\n\t\t\t\tintSeed = ParseSeed(seed);\n\t\t\t\trandom = new Random(intSeed);\n\t\t\t}\n\t\t}\n\n\t\tpublic static int IntSeed => intSeed;\n\t\tpublic static string SeedChars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_\";\n\t\t\n\t\tstatic Rnd() {\n\t\t\tSeed = GenerateSeed();\n\t\t\tLog.Debug($\"Random seed is {seed}\");\n\t\t}\n\t\t\n\t\tpublic static int ParseSeed(string seed) {\n\t\t\tif (seed == null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\tvar value = 0;\n\t\t\tvar i = 0;\n\n\t\t\tforeach (var c in seed) {\n\t\t\t\tvar index = SeedChars.IndexOf(c);\n\n\t\t\t\tif (index == -1) {\n\t\t\t\t\tLog.Error($\"Unknown seed char '{c}' ({(int) c})!\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvalue += index << (i * 4);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\t\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic static string GenerateSeed(int len = 8, int seed = -1) {\n\t\t\tvar builder = new StringBuilder();\n\t\t\tvar r = seed == -1 ? new Random(Environment.TickCount + Guid.NewGuid().GetHashCode()) : new Random(seed);\n\n\t\t\tfor (var i = 0; i < len; i++) {\n\t\t\t\tbuilder.Append(SeedChars[r.Next(SeedChars.Length - 1)]);\n\t\t\t}\n\t\t\t\n\t\t\treturn builder.ToString();\n\t\t}\n\n\t\tpublic static Vector2 Vector(float min, float max) {\n\t\t\tif (min > max) {\n\t\t\t\tvar t = min;\n\t\t\t\t\n\t\t\t\tmin = max;\n\t\t\t\tmax = t;\n\t\t\t}\n\t\t\t\n\t\t\treturn new Vector2(Float(min, max), Float(min, max));\n\t\t}\n\n\t\tpublic static int Int() {\n\t\t\treturn random.Next();\n\t\t}\n\t\t\n\t\tpublic static int Int(int max) {\n\t\t\treturn random.Next(0, max);\n\t\t}\n\t\t\n\t\tpublic static int Int(int min, int max) {\n\t\t\tif (min > max) {\n\t\t\t\tvar t = min;\n\t\t\t\t\n\t\t\t\tmin = max;\n\t\t\t\tmax = t;\n\t\t\t}\n\t\t\n\t\t\treturn random.Next(min, max);\n\t\t}\n\n\t\tpublic static int IntCentred(int min, int max) {\n\t\t\tif (min > max) {\n\t\t\t\tvar t = min;\n\t\t\t\t\n\t\t\t\tmin = max;\n\t\t\t\tmax = t;\n\t\t\t}\n\t\t\t\n\t\t\treturn (int) ((Int(min, max) + Int(min, max)) / 2f - 0.1f);\n\t\t}\n\n\t\tpublic static float Float() {\n\t\t\treturn (float) random.NextDouble();\n\t\t}\n\t\t\n\t\tpublic static float Float(float max) {\n\t\t\treturn (float) (random.NextDouble() * max);\n\t\t}\n\n\t\tpublic static float Float(float min, float max) {\n\t\t\tif (min > max) {\n\t\t\t\tvar t = min;\n\t\t\t\t\n\t\t\t\tmin = max;\n\t\t\t\tmax = t;\n\t\t\t}\n\t\t\t\n\t\t\treturn (float) (random.NextDouble() * (max - min) + min);\n\t\t}\n\n\t\tpublic static Vector2 Offset(float d) {\n\t\t\tvar a = AnglePI();\n\t\t\treturn new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d);\n\t\t}\n\t\t\n\t\tpublic static double Double() {\n\t\t\treturn random.NextDouble();\n\t\t}\n\t\t\n\t\tpublic static double Double(double max) {\n\t\t\treturn random.NextDouble() * max;\n\t\t}\n\n\t\tpublic static double Double(double min, double max) {\n\t\t\treturn random.NextDouble() * (max - min) + min;\n\t\t}\n\n\t\tpublic static bool Bool() {\n\t\t\treturn random.NextDouble() >= 0.5;\n\t\t}\n\n\t\tpublic static bool Chance(float chance = 50) {\n\t\t\treturn random.NextDouble() * 100 <= chance;\n\t\t}\n\n\t\tpublic static float Angle() {\n\t\t\treturn Float(360);\n\t\t}\n\n\t\tpublic static float AnglePI() {\n\t\t\treturn Float((float) (Math.PI * 2));\n\t\t}\n\n\t\tpublic static int Chances(float[] chances) {\n\t\t\tvar length = chances.Length;\n\t\t\tfloat sum = 0;\n\n\t\t\tforeach (var chance in chances) {\n\t\t\t\tsum += chance;\n\t\t\t}\n\n\t\t\tfloat value = Float(sum);\n\t\t\tsum = 0;\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tsum += chances[i];\n\n\t\t\t\tif (value < sum) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tpublic static int Chances(List<float> chances) {\n\t\t\tvar length = chances.Count;\n\t\t\tfloat sum = 0;\n\n\t\t\tforeach (var chance in chances) {\n\t\t\t\tsum += chance;\n\t\t\t}\n\n\t\t\tfloat value = Float(sum);\n\t\t\tsum = 0;\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tsum += chances[i];\n\n\t\t\t\tif (value < sum) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tpublic static int Sign() {\n\t\t\treturn Chance() ? -1 : 1;\n\t\t}\n\n\t\tpublic static T Element<T>(List<T> list, Func<T, bool> filter) where T : Entity {\n\t\t\tvar length = list.Count;\n\t\t\tvar sum = 0;\n\n\t\t\tforeach (var e in list) {\n\t\t\t\tif (filter(e)) {\n\t\t\t\t\tsum++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint value = Int(sum);\n\t\t\tsum = 0;\n\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tif (filter(list[i])) {\n\t\t\t\t\tsum++;\n\t\t\t\t\t\n\t\t\t\t\tif (value < sum) {\n\t\t\t\t\t\treturn list[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/pool/DisposablePool.cs",
    "content": "﻿using System;\n\nnamespace Lens.util.pool {\n\tpublic class DisposablePool<T> : Pool<T> where T: IDisposable {\n\t\tpublic override T Create() {\n\t\t\tthrow new NotImplementedException();\n\t\t}\n\n\t\tpublic override void Destroy(T t) {\n\t\t\tt.Dispose();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/pool/Pool.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Lens.util.pool {\n\tpublic abstract class Pool<T> {\n\t\tpublic List<T> All = new List<T>();\n\t\tprivate List<T> free = new List<T>();\n\t\t\n\t\tpublic T Get() {\n\t\t\tif (free.Count == 0) {\n\t\t\t\tvar t = Create();\n\t\t\t\tAll.Add(t);\n\n\t\t\t\treturn t;\n\t\t\t}\n\n\t\t\tvar tp = free[free.Count - 1];\n\t\t\tfree.RemoveAt(free.Count - 1);\n\t\t\t\n\t\t\treturn tp;\n\t\t}\n\n\t\tpublic void Free(T t) {\n\t\t\tfree.Add(t);\n\t\t}\n\n\t\tpublic void Clear() {\n\t\t\tfree.Clear();\n\n\t\t\tforeach (var p in All) {\n\t\t\t\tDestroy(p);\n\t\t\t}\n\t\t\t\n\t\t\tAll.Clear();\n\t\t}\n\n\t\tpublic abstract T Create();\n\n\t\tpublic virtual void Destroy(T t) {\n\t\t\t\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/timer/Timer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Lens.util.timer {\n\tpublic static class Timer {\n\t\tprivate static List<TimerTask> tasks = new List<TimerTask>();\n\n\t\tpublic static void Cancel(TimerTask task) {\n\t\t\ttasks.Remove(task);\n\t\t}\n\n\t\tpublic static TimerTask Add(Action fn, float Delay) {\n\t\t\tif (Delay <= 0) {\n\t\t\t\tfn();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar t = new TimerTask(fn, Delay);\n\t\t\ttasks.Add(t);\n\n\t\t\treturn t;\n\t\t}\n\n\t\tpublic static void Clear() {\n\t\t\ttasks.Clear();\n\t\t}\n\t\t\n\t\tpublic static void Update(float dt) {\n\t\t\tfor (int i = tasks.Count - 1; i >= 0; i--) {\n\t\t\t\tTimerTask task = tasks[i];\n\n\t\t\t\tif (task == null) {\n\t\t\t\t\ttasks.RemoveAt(i);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttask.Delay -= dt;\n\n\t\t\t\tif (task.Delay <= 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttask.Fn?.Invoke();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tLog.Error(e);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttasks.RemoveAt(i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/timer/TimerTask.cs",
    "content": "﻿using System;\n\nnamespace Lens.util.timer {\n\tpublic class TimerTask {\n\t\tpublic float Delay;\n\t\tpublic Action Fn;\n\n\t\tpublic TimerTask(Action fn, float delay) {\n\t\t\tFn = fn;\n\t\t\tDelay = delay;\n\t\t}\n\t\t\n\t\tpublic void Cancel() {\n\t\t\tTimer.Cancel(this);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/tween/Ease.cs",
    "content": "﻿namespace Lens.util.tween {\n\tpublic static class Ease {\n\t\tprivate const float Pi = 3.14159f;\n\t\tprivate const float Pi2 = Pi / 2;\n\t\tprivate const float B1 = 1 / 2.75f;\n\t\tprivate const float B2 = 2 / 2.75f;\n\t\tprivate const float B3 = 1.5f / 2.75f;\n\t\tprivate const float B4 = 2.5f / 2.75f;\n\t\tprivate const float B5 = 2.25f / 2.75f;\n\t\tprivate const float B6 = 2.625f / 2.75f;\n\n\t\tpublic static float Linear(float t) {\n\t\t\treturn t;\n\t\t}\n\n\t\tpublic static float ElasticIn(float t) {\n\t\t\treturn (float) (System.Math.Sin(13 * Pi2 * t) * System.Math.Pow(2, 10 * (t - 1)));\n\t\t}\n\n\t\tpublic static float ElasticOut(float t) {\n\t\t\treturn (float) (System.Math.Sin(-13 * Pi2 * (t + 1)) * System.Math.Pow(2, -10 * t) + 1);\n\t\t}\n\n\t\tpublic static float ElasticInOut(float t) {\n\t\t\tif (t < 0.5) {\n\t\t\t\treturn (float) (0.5 * System.Math.Sin(13 * Pi2 * (2 * t)) * System.Math.Pow(2, 10 * ((2 * t) - 1)));\n\t\t\t}\n\n\t\t\treturn (float) (0.5 * (System.Math.Sin(-13 * Pi2 * ((2 * t - 1) + 1)) * System.Math.Pow(2, -10 * (2 * t - 1)) + 2));\n\t\t}\n\n\t\tpublic static float QuadIn(float t) {\n\t\t\treturn t * t;\n\t\t}\n\n\t\tpublic static float QuadOut(float t) {\n\t\t\treturn -t * (t - 2);\n\t\t}\n\n\t\tpublic static float QuadInOut(float t) {\n\t\t\treturn t <= .5 ? t * t * 2 : 1 - (--t) * t * 2;\n\t\t}\n\n\t\tpublic static float CubeIn(float t) {\n\t\t\treturn t * t * t;\n\t\t}\n\n\t\tpublic static float CubeOut(float t) {\n\t\t\treturn 1 + (--t) * t * t;\n\t\t}\n\n\t\tpublic static float CubeInOut(float t) {\n\t\t\treturn t <= .5 ? t * t * t * 4 : 1 + (--t) * t * t * 4;\n\t\t}\n\n\t\tpublic static float QuartIn(float t) {\n\t\t\treturn t * t * t * t;\n\t\t}\n\n\t\tpublic static float QuartOut(float t) {\n\t\t\treturn 1 - (t -= 1) * t * t * t;\n\t\t}\n\n\t\tpublic static float QuartInOut(float t) {\n\t\t\treturn (float) (t <= .5 ? t * t * t * t * 8 : (1 - (t = t * 2 - 2) * t * t * t) / 2 + .5);\n\t\t}\n\n\t\tpublic static float QuintIn(float t) {\n\t\t\treturn t * t * t * t * t;\n\t\t}\n\n\t\tpublic static float QuintOut(float t) {\n\t\t\treturn (t = t - 1) * t * t * t * t + 1;\n\t\t}\n\n\t\tpublic static float QuintInOut(float t) {\n\t\t\treturn ((t *= 2) < 1) ? (t * t * t * t * t) / 2 : ((t -= 2) * t * t * t * t + 2) / 2;\n\t\t}\n\n\t\tpublic static float SineIn(float t) {\n\t\t\treturn (float) (-System.Math.Cos(Pi2 * t) + 1);\n\t\t}\n\n\t\tpublic static float SineOut(float t) {\n\t\t\treturn (float) (System.Math.Sin(Pi2 * t));\n\t\t}\n\n\t\tpublic static float SineInOut(float t) {\n\t\t\treturn (float) (-System.Math.Cos(Pi * t) / 2 + .5);\n\t\t}\n\n\t\tpublic static float BounceIn(float t) {\n\t\t\tt = 1 - t;\n\t\t\tif (t < B1) return (float) (1 - 7.5625 * t * t);\n\t\t\tif (t < B2) return (float) (1 - (7.5625 * (t - B3) * (t - B3) + .75));\n\t\t\tif (t < B4) return (float) (1 - (7.5625 * (t - B5) * (t - B5) + .9375));\n\t\t\treturn (float) (1 - (7.5625 * (t - B6) * (t - B6) + .984375));\n\t\t}\n\n\t\tpublic static float BounceOut(float t) {\n\t\t\tif (t < B1) return (float) (7.5625 * t * t);\n\t\t\tif (t < B2) return (float) (7.5625 * (t - B3) * (t - B3) + .75);\n\t\t\tif (t < B4) return (float) (7.5625 * (t - B5) * (t - B5) + .9375);\n\t\t\treturn (float) (7.5625 * (t - B6) * (t - B6) + .984375);\n\t\t}\n\n\t\tpublic static float BounceInOut(float t) {\n\t\t\tif (t < .5) {\n\t\t\t\tt = 1 - t * 2;\n\t\t\t\tif (t < B1) return (float) ((1 - 7.5625 * t * t) / 2);\n\t\t\t\tif (t < B2) return (float) ((1 - (7.5625 * (t - B3) * (t - B3) + .75)) / 2);\n\t\t\t\tif (t < B4) return (float) ((1 - (7.5625 * (t - B5) * (t - B5) + .9375)) / 2);\n\t\t\t\treturn (float) ((1 - (7.5625 * (t - B6) * (t - B6) + .984375)) / 2);\n\t\t\t}\n\n\t\t\tt = t * 2 - 1;\n\t\t\tif (t < B1) return (float) ((7.5625 * t * t) / 2 + .5);\n\t\t\tif (t < B2) return (float) ((7.5625 * (t - B3) * (t - B3) + .75) / 2 + .5);\n\t\t\tif (t < B4) return (float) ((7.5625 * (t - B5) * (t - B5) + .9375) / 2 + .5);\n\t\t\treturn (float) ((7.5625 * (t - B6) * (t - B6) + .984375) / 2 + .5);\n\t\t}\n\n\t\tpublic static float CircIn(float t) {\n\t\t\treturn (float) (-(System.Math.Sqrt(1 - t * t) - 1));\n\t\t}\n\n\t\tpublic static float CircOut(float t) {\n\t\t\treturn (float) (System.Math.Sqrt(1 - (t - 1) * (t - 1)));\n\t\t}\n\n\t\tpublic static float CircInOut(float t) {\n\t\t\treturn (float) (t <= .5\n\t\t\t\t? (System.Math.Sqrt(1 - t * t * 4) - 1) / -2\n\t\t\t\t: (System.Math.Sqrt(1 - (t * 2 - 2) * (t * 2 - 2)) + 1) / 2);\n\t\t}\n\n\t\tpublic static float ExpoIn(float t) {\n\t\t\treturn (float) (System.Math.Pow(2, 10 * (t - 1)));\n\t\t}\n\n\t\tpublic static float ExpoOut(float t) {\n\t\t\treturn (float) (-System.Math.Pow(2, -10 * t) + 1);\n\t\t}\n\n\t\tpublic static float ExpoInOut(float t) {\n\t\t\treturn (float) (t < .5 ? System.Math.Pow(2, 10 * (t * 2 - 1)) / 2 : (-System.Math.Pow(2, -10 * (t * 2 - 1)) + 2) / 2);\n\t\t}\n\n\t\tpublic static float BackIn(float t) {\n\t\t\treturn (float) (t * t * (2.70158 * t - 1.70158));\n\t\t}\n\n\t\tpublic static float BackOut(float t) {\n\t\t\treturn (float) (1 - (--t) * (t) * (-2.70158 * t - 1.70158));\n\t\t}\n\n\t\tpublic static float BackInOut(float t) {\n\t\t\tt *= 2;\n\t\t\t\n\t\t\tif (t < 1) {\n\t\t\t\treturn (float) (t * t * (2.70158 * t - 1.70158) / 2);\n\t\t\t}\n\t\t\t\n\t\t\tt--;\n\t\t\treturn (float) ((1 - (--t) * (t) * (-2.70158 * t - 1.70158)) / 2 + .5);\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/tween/Tween.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.Xna.Framework;\n\nnamespace Lens.util.tween {\n\tpublic static class Tween {\n\t\tprivate static List<TweenTask> tasks = new List<TweenTask>();\n\n\t\tpublic static TweenTask To(float to, float value, Action<float> set, float duration, Func<float, float> ease = null, float delay = 0) {\n\t\t\tif (ease == null) {\n\t\t\t\t// Default ease\n\t\t\t\tease = Ease.QuadOut;\n\t\t\t}\n\t\t\t\n\t\t\tvar task = new TweenTask();\n\t\t\ttasks.Add(task);\n\t\t\t\n\t\t\ttask.Delay = delay;\n\t\t\ttask.Duration = duration;\n\t\t\ttask.EaseFn = ease;\n\t\t\ttask.Single = true;\n\t\t\ttask.From = value;\n\t\t\ttask.To = to;\n\t\t\ttask.Set = set;\n\t\t\n\t\t\treturn task;\n\t\t}\n\n\t\tpublic static TweenTask To<T>(T target, object values, float duration, Func<float, float> ease = null, float delay = 0) {\n\t\t\tif (ease == null) {\n\t\t\t\t// Default ease\n\t\t\t\tease = Ease.QuadOut;\n\t\t\t}\n\t\t\t\n\t\t\tvar task = new TweenTask();\n\t\t\ttasks.Add(task);\n\t\t\t\n\t\t\ttask.Delay = delay;\n\t\t\ttask.Duration = duration;\n\t\t\ttask.EaseFn = ease;\n\t\t\t\n\t\t\tif (values == null) {\n\t\t\t\treturn task;\n\t\t\t}\n\t\t\t\n\t\t\tforeach (var property in values.GetType().GetTypeInfo().DeclaredProperties) {\n\t\t\t\ttry {\n\t\t\t\t\tvar info = new TweenValue(target, property.Name);\n\t\t\t\t\tvar to = Convert.ToSingle(new TweenValue(values, property.Name, false).Value);\n\n\t\t\t\t\tfloat s = Convert.ToSingle(info.Value);\n\t\t\t\t\tfloat r = to - s;\n\n\t\t\t\t\ttask.Vars.Add(info);\n\t\t\t\t\ttask.Start.Add(s);\n\t\t\t\t\ttask.Range.Add(r);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tLog.Error(e);\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\treturn task;\n\t\t}\n\n\t\tpublic static void Remove(TweenTask task) {\n\t\t\tif (task != null) {\n\t\t\t\ttasks.Remove(task);\n\t\t\t}\n\t\t}\n\t\t\n\t\tpublic static void Update(float dt) {\n\t\t\tvar i = tasks.Count - 1;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tfor (; i >= 0; i--) {\n\t\t\t\t\tvar task = tasks[i];\n\n\t\t\t\t\tif (task == null) { // A bug that used to happen somehow\n\t\t\t\t\t\ttasks.RemoveAt(i);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\ttask.Update(dt);\n\n\t\t\t\t\tif (task.Ended) {\n\t\t\t\t\t\ttasks.RemoveAt(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\ttasks.RemoveAt(i);\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/tween/TweenTask.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Lens.util.tween {\n\tpublic class TweenTask {\n\t\tpublic Action OnStart;\n\t\tpublic Action OnEnd;\n\t\tpublic Action OnUpdate;\n\t\tpublic Func<float, float> EaseFn;\n\n\t\tpublic float Timer;\n\t\tpublic float Duration;\n\t\tpublic List<float> Start = new List<float>();\n\t\tpublic List<float> Range = new List<float>();\n\t\tpublic List<TweenValue> Vars = new List<TweenValue>();\n\t\tpublic float Delay;\n\t\tpublic bool Started;\n\t\tpublic bool Ended;\n\t\tpublic bool Single;\n\t\tpublic float From;\n\t\tpublic float To;\n\t\tpublic Action<float> Set;\n\t\t\n\t\tpublic void Update(float dt) {\n\t\t\tif (Delay >= 0) {\n\t\t\t\tDelay -= dt;\n\n\t\t\t\tif (Delay <= 0) {\n\t\t\t\t\tTimer = -Delay;\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!Started) {\n\t\t\t\tStarted = true;\n\t\t\t\tOnStart?.Invoke();\n\t\t\t}\n\t\t\t\n\t\t\tTimer += dt;\n\t\t\tfloat t = Timer / Duration;\n\t\t\tbool callEnd = false;\n\t\t\t\n\t\t\tif (Timer >= Duration) {\n\t\t\t\tTimer = Duration;\n\t\t\t\tt = 1f;\n\t\t\t\tcallEnd = true;\n\t\t\t}\n\n\t\t\tif (EaseFn != null) {\n\t\t\t\tt = EaseFn(t);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tInterpolate(t);\n\t\t\t\tOnUpdate?.Invoke();\n\t\t\t} catch (Exception e) {\n\t\t\t\tt = 1;\n\t\t\t\t\n\t\t\t\tif (EaseFn != null) {\n\t\t\t\t\tt = EaseFn(t);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tInterpolate(t);\n\n\t\t\t\tcallEnd = true;\n\t\t\t\tLog.Error(e);\n\t\t\t}\n\n\t\t\tif (callEnd && !Ended) {\n\t\t\t\tEnded = true;\n\t\t\t\tOnEnd?.Invoke();\n\t\t\t}\n\t\t}\n\t\t\n\t\tprotected void Interpolate(float t) {\n\t\t\tif (Single) {\n\t\t\t\tSet(From + (To - From) * t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\tint i = Vars.Count;\n\t\t\t\n\t\t\twhile (i-- > 0) {\n\t\t\t\tVars[i].Value = Start[i] + Range[i] * t;\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens/util/tween/TweenValue.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Lens.util.tween {\n\tpublic class TweenValue {\n\t\tstatic TweenValue() {\n\t\t\tNumericTypes = new[] {\n\t\t\t\ttypeof(Int16),\n\t\t\t\ttypeof(Int32),\n\t\t\t\ttypeof(Int64),\n\t\t\t\ttypeof(UInt16),\n\t\t\t\ttypeof(UInt32),\n\t\t\t\ttypeof(UInt64),\n\t\t\t\ttypeof(Single),\n\t\t\t\ttypeof(Double),\n\t\t\t\ttypeof(Byte)\n\t\t\t};\n\t\t}\n\n\t\tprivate static readonly Type[] NumericTypes;\n\t\tprivate readonly FieldInfo field;\n\t\tprivate readonly PropertyInfo prop;\n\t\tprivate readonly bool isNumeric;\n\t\tprivate readonly object target;\n\n\t\tpublic string Name { get; private set; }\n\n\t\tpublic object Value {\n\t\t\tget { return field != null ? field.GetValue(target) : prop.GetValue(target, null); }\n\t\t\tset {\n\t\t\t\tif (isNumeric) {\n\t\t\t\t\tType type = null;\n\t\t\t\t\t\n\t\t\t\t\tif (field != null) {\n\t\t\t\t\t\ttype = field.FieldType;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (prop != null) {\n\t\t\t\t\t\ttype = prop.PropertyType;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (AnyEquals(type, NumericTypes)) {\n\t\t\t\t\t\tvalue = Convert.ChangeType(value, type);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (field != null) {\n\t\t\t\t\tfield.SetValue(target, value);\n\t\t\t\t} else {\n\t\t\t\t\tprop?.SetValue(target, value, null);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic TweenValue(object target, string property, bool writeRequired = true) {\n\t\t\tthis.target = target;\n\t\t\tName = property;\n\n\t\t\tType targetType;\n\n\t\t\tif (IsType(target)) {\n\t\t\t\ttargetType = (Type) target;\n\t\t\t}\telse {\n\t\t\t\ttargetType = target.GetType();\n\t\t\t}\n\n\t\t\tfield = targetType.GetTypeInfo().DeclaredFields.FirstOrDefault(f =>\n\t\t\t\tstring.Equals(property, f.Name) && !f.IsStatic);\n\n\t\t\tprop = writeRequired\n\t\t\t\t? targetType.GetTypeInfo().DeclaredProperties.FirstOrDefault(p =>\n\t\t\t\t\tstring.Equals(property, p.Name) && !p.GetMethod.IsStatic && p.CanRead && p.CanWrite)\n\t\t\t\t: targetType.GetTypeInfo().DeclaredProperties.FirstOrDefault(p =>\n\t\t\t\t\tstring.Equals(property, p.Name) && !p.GetMethod.IsStatic && p.CanRead);\n\n\t\t\tif (field == null) {\n\t\t\t\tif (prop == null) {\n\t\t\t\t\t//\tCouldn't find either\n\t\t\t\t\tthrow new Exception(string.Format(\"Field or '{0}' property '{1}' not found on object of type {2}.\",\n\t\t\t\t\t\twriteRequired ? \"read/write\" : \"readable\",\n\t\t\t\t\t\tproperty, targetType.FullName));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar valueType = Value.GetType();\n\t\t\tisNumeric = AnyEquals(valueType, NumericTypes);\n\t\t\tCheckPropertyType(valueType, property, targetType.Name);\n\t\t}\n\n\t\tbool IsType(object target) {\n\t\t\tvar type = target.GetType();\n\t\t\tvar baseType = typeof(Type);\n\n\t\t\tif (type == baseType) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar rootType = typeof(object);\n\n\t\t\twhile (type != null && type != rootType) {\n\t\t\t\tvar info = type.GetTypeInfo();\n\t\t\t\tvar current = info.IsGenericType && info.IsGenericTypeDefinition ? info.GetGenericTypeDefinition() : type;\n\n\t\t\t\tif (baseType == current) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\ttype = info.BaseType;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void CheckPropertyType(Type type, string prop, string targetTypeName) {\n\t\t\tif (!ValidatePropertyType(type)) {\n\t\t\t\tthrow new InvalidCastException(string.Format(\"Property is invalid: ({0} on {1}).\", prop, targetTypeName));\n\t\t\t}\n\t\t}\n\n\t\tprotected virtual bool ValidatePropertyType(Type type) {\n\t\t\treturn isNumeric;\n\t\t}\n\n\t\tstatic bool AnyEquals<T>(T value, params T[] options) {\n\t\t\tforeach (var option in options) {\n\t\t\t\tif (value.Equals(option)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Lens.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Lens\", \"Lens\\Lens.csproj\", \"{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Aseprite\", \"Aseprite\\Aseprite.csproj\", \"{13C6F252-0B3C-4A22-A9DB-270C76657FAB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"BurningKnight\", \"BurningKnight\\BurningKnight.csproj\", \"{D31D0D40-105E-47D5-A5D0-F6E30328BF86}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"VelcroPhysics.MonoGame\", \"VelcroPhysics\\VelcroPhysics.MonoGame.csproj\", \"{4650BD15-4B03-4A7E-98D4-9F8697ED2EB4}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Desktop\", \"Desktop\\Desktop.csproj\", \"{68B0E433-3961-4232-9EB1-393AB85FAF7C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}.Debug|x64.Build.0 = Debug|x64\n\t\t{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}.Release|x64.ActiveCfg = Release|x64\n\t\t{3B26AA2E-0BA2-42DC-AD62-E6C8617F9E4D}.Release|x64.Build.0 = Release|x64\n\t\t{13C6F252-0B3C-4A22-A9DB-270C76657FAB}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{13C6F252-0B3C-4A22-A9DB-270C76657FAB}.Debug|x64.Build.0 = Debug|x64\n\t\t{13C6F252-0B3C-4A22-A9DB-270C76657FAB}.Release|x64.ActiveCfg = Release|x64\n\t\t{13C6F252-0B3C-4A22-A9DB-270C76657FAB}.Release|x64.Build.0 = Release|x64\n\t\t{D31D0D40-105E-47D5-A5D0-F6E30328BF86}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{D31D0D40-105E-47D5-A5D0-F6E30328BF86}.Debug|x64.Build.0 = Debug|x64\n\t\t{D31D0D40-105E-47D5-A5D0-F6E30328BF86}.Release|x64.ActiveCfg = Release|x64\n\t\t{D31D0D40-105E-47D5-A5D0-F6E30328BF86}.Release|x64.Build.0 = Release|x64\n\t\t{4650BD15-4B03-4A7E-98D4-9F8697ED2EB4}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{4650BD15-4B03-4A7E-98D4-9F8697ED2EB4}.Debug|x64.Build.0 = Debug|x64\n\t\t{4650BD15-4B03-4A7E-98D4-9F8697ED2EB4}.Release|x64.ActiveCfg = Release|x64\n\t\t{4650BD15-4B03-4A7E-98D4-9F8697ED2EB4}.Release|x64.Build.0 = Release|x64\n\t\t{68B0E433-3961-4232-9EB1-393AB85FAF7C}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{68B0E433-3961-4232-9EB1-393AB85FAF7C}.Debug|x64.Build.0 = Debug|x64\n\t\t{68B0E433-3961-4232-9EB1-393AB85FAF7C}.Release|x64.ActiveCfg = Release|x64\n\t\t{68B0E433-3961-4232-9EB1-393AB85FAF7C}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# Burning Knight \n\nAvailable on [Steam](https://store.steampowered.com/app/851150/Burning_Knight/) and [itch.io](https://egordorichev.itch.io/bk).\n\nBefore you look at the code: hear me out. Yes, some of it is not the best. Yes, some of it can be redone and improved.\nBut I have to admit, I came so close to dropping this whole project so many times, I still have no idea, how I made it through May of 2020.\nAnyway. Here it is. The source code of C# branch of Burning Knight. **For java branch see [this repo](https://github.com/egordorichev/BurningKnightJava).**\n\n###### (Yes, this is only half of the work, the game was initially written in Java and then rewritten in C#, this code base is relatively nice compared to the Java one).\n\nThis project really quickly moved from the \"nice and relaxing\" to \"constant bugfixing and stress\" type of project.\nYou can clearly see me going mad in some places (do not look at the pull requests I beg you).\nBut its all in the past now. Sadly, the game has done really poorly on the Steam, even tho I've tried my best with marketing and everything else.\nI'm still really really proud of the game, it's THE project I can point people to and say: I've made this. That's one of the reasons why I wanted to open the source of this monster.\n\nThere are not a lot of open source games, that have been released on Steam. So there is not that much where you can go to learn from real released games. Of course, you can decompile games, but it will never compare to the actual source.\nI believe in the power open source. I'm opening this project up with hope, that it might turn out to be useful to someone. So yeah, forgive me my code decisions in some places.\n\nAnyway, onto the juicy stuff.\n\nThe game has a lot of developer tools in it, but to gain access to them, you must build the solution in Debug configuration.\nThis is really important, because **music & sfx wont load in Debug configuration, but dev tools will be enabled**. The assets are dropped in favor of quicker loading time (there is still no hotswap support for Mono on Linux).\n\nTo access the dev tools, you shall press F1 while being in InGameState (while you are normally playing and not watching a loading screen).\nA panel with a bunch of checkboxes should appear, that show different dev tools. Have fun!\n\n##### Why did you merge pull requests into release branch all the time?\n\nYou see, this is how I've set up Github Actions CI. The tool went online in the middle of the first summer of development of the C# branch, and it was such a huge help.\nBefore that, I had to compile all the builds for beta testing by hand, but after 3 days of internal screaming I was able to get the CI working, and from that point I was able just to merge\nmy dev branch into release, and 10 minutes later press a few buttons on Itch/Steam to release the new builds.\n\n##### Building\n\nHey, so I saw a bunch of people complain online about no building instructions. I couldn't be surprised more, since you just open the .sln file in your C# IDE of choice and compile & run the Desktop project. But just in case anyone is still curious, here you go.  \n\nIf you don't have a ready environment for compiling .NET Framework code, check [this](https://github.com/egordorichev/BurningKnight/blob/dev/CompileNetFrameworkOnLinux.md) page. It explains how to install and use all tools needed to compile Burning Knight on Linux.\n\nOr if you prefer to do it from the terminal: install the packages:\n\n```bash\nnuget restore\n```\n\nDebug configuration (disabled sfx & music but has dev tools enabled):\n\n```bash\nmsbuild\ncd Desktop/bin/Debug/\nmono Desktop.exe\n```\n\nRelease configuration (same as on Steam) is a bit more tricky. You gotta install MonoGame Content Pipeline tool and compile the assets (raw sfx -> .xnb).\nIf you are on Linux, you can get it via:\n\nwget https://github.com/MonoGame/MonoGame/releases/download/v3.7.1/monogame-sdk.run\nchmod +x monogame-sdk.run\nsudo ./monogame-sdk.run\nOtherwise, find a binary on the monogame website. After that open BurningKnight/Content/Content.mgcb in the tool and hit build.\n\n![](https://user-images.githubusercontent.com/7851390/96409702-5cb22700-11ee-11eb-8586-0afe349f1473.png)\n\nIf you are on Linux, ignore shader compilation errors, prebuild shaders (via a Windows machine) are already in the repo.\nAfter that build the sources and run:\n\n\n```bash\nmsbuild /p:Configuration=Release\ncd Desktop/bin/Release/\nmono Desktop.exe\n```\n"
  },
  {
    "path": "VelcroPhysics/BreakableBody.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// A type of body that supports multiple fixtures that can break apart.\n    /// </summary>\n    public class BreakableBody\n    {\n        private float[] _angularVelocitiesCache = new float[8];\n        private bool _break;\n        private Vector2[] _velocitiesCache = new Vector2[8];\n        private readonly World _world;\n\n        /// <summary>\n        /// The force needed to break the body apart.\n        /// Default: 500\n        /// </summary>\n        public float Strength { get; set; }\n\n        public BreakableBody(World world, IEnumerable<Vertices> vertices, float density, Vector2 position = new Vector2(), float rotation = 0)\n        {\n            _world = world;\n            _world.ContactManager.PostSolve += PostSolve;\n            Parts = new List<Fixture>(8);\n            MainBody = BodyFactory.CreateBody(_world, position, rotation, BodyType.Dynamic);\n            Strength = 500.0f;\n\n            foreach (Vertices part in vertices)\n            {\n                PolygonShape polygonShape = new PolygonShape(part, density);\n                Fixture fixture = MainBody.CreateFixture(polygonShape);\n                Parts.Add(fixture);\n            }\n        }\n\n        public BreakableBody(World world, IEnumerable<Shape> shapes, Vector2 position = new Vector2(), float rotation = 0)\n        {\n            _world = world;\n            _world.ContactManager.PostSolve += PostSolve;\n            MainBody = BodyFactory.CreateBody(_world, position, rotation, BodyType.Dynamic);\n            Parts = new List<Fixture>(8);\n\n            foreach (Shape part in shapes)\n            {\n                Fixture fixture = MainBody.CreateFixture(part);\n                Parts.Add(fixture);\n            }\n        }\n\n        public bool Broken { get; private set; }\n        public Body MainBody { get; }\n        public List<Fixture> Parts { get; }\n\n        private void PostSolve(Contact contact, ContactVelocityConstraint impulse)\n        {\n            if (!Broken)\n            {\n                if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))\n                {\n                    float maxImpulse = 0.0f;\n                    int count = contact.Manifold.PointCount;\n\n                    for (int i = 0; i < count; ++i)\n                    {\n                        maxImpulse = Math.Max(maxImpulse, impulse.Points[i].NormalImpulse);\n                    }\n\n                    if (maxImpulse > Strength)\n                    {\n                        // Flag the body for breaking.\n                        _break = true;\n                    }\n                }\n            }\n        }\n\n        public void Update()\n        {\n            if (_break)\n            {\n                Decompose();\n                Broken = true;\n                _break = false;\n            }\n\n            // Cache velocities to improve movement on breakage.\n            if (Broken == false)\n            {\n                //Enlarge the cache if needed\n                if (Parts.Count > _angularVelocitiesCache.Length)\n                {\n                    _velocitiesCache = new Vector2[Parts.Count];\n                    _angularVelocitiesCache = new float[Parts.Count];\n                }\n\n                //Cache the linear and angular velocities.\n                for (int i = 0; i < Parts.Count; i++)\n                {\n                    _velocitiesCache[i] = Parts[i].Body.LinearVelocity;\n                    _angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;\n                }\n            }\n        }\n\n        private void Decompose()\n        {\n            //Unsubsribe from the PostSolve delegate\n            _world.ContactManager.PostSolve -= PostSolve;\n\n            for (int i = 0; i < Parts.Count; i++)\n            {\n                Fixture oldFixture = Parts[i];\n\n                Shape shape = oldFixture.Shape.Clone();\n                object userData = oldFixture.UserData;\n\n                MainBody.DestroyFixture(oldFixture);\n\n                Body body = BodyFactory.CreateBody(_world, MainBody.Position, MainBody.Rotation, BodyType.Dynamic, MainBody.UserData);\n\n                Fixture newFixture = body.CreateFixture(shape);\n                newFixture.UserData = userData;\n                Parts[i] = newFixture;\n\n                body.AngularVelocity = _angularVelocitiesCache[i];\n                body.LinearVelocity = _velocitiesCache[i];\n            }\n\n            _world.RemoveBody(MainBody);\n            _world.RemoveBreakableBody(this);\n        }\n\n        public void Break()\n        {\n            _break = true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/AABBHelper.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision\n{\n    public static class AABBHelper\n    {\n        public static void ComputeEdgeAABB(ref Vector2 start, ref Vector2 end, ref Transform transform, out AABB aabb)\n        {\n            Vector2 v1 = MathUtils.Mul(ref transform, ref start);\n            Vector2 v2 = MathUtils.Mul(ref transform, ref end);\n\n            aabb.LowerBound = Vector2.Min(v1, v2);\n            aabb.UpperBound = Vector2.Max(v1, v2);\n\n            Vector2 r = new Vector2(Settings.PolygonRadius, Settings.PolygonRadius);\n            aabb.LowerBound = aabb.LowerBound - r;\n            aabb.UpperBound = aabb.UpperBound + r;\n        }\n\n        public static void ComputeCircleAABB(ref Vector2 pos, float radius, ref Transform transform, out AABB aabb)\n        {\n            Vector2 p = transform.p + MathUtils.Mul(transform.q, pos);\n            aabb.LowerBound = new Vector2(p.X - radius, p.Y - radius);\n            aabb.UpperBound = new Vector2(p.X + radius, p.Y + radius);\n        }\n\n        public static void ComputePolygonAABB(Vertices vertices, ref Transform transform, out AABB aabb)\n        {\n            Vector2 lower = MathUtils.Mul(ref transform, vertices[0]);\n            Vector2 upper = lower;\n\n            for (int i = 1; i < vertices.Count; ++i)\n            {\n                Vector2 v = MathUtils.Mul(ref transform, vertices[i]);\n                lower = Vector2.Min(lower, v);\n                upper = Vector2.Max(upper, v);\n            }\n\n            Vector2 r = new Vector2(Settings.PolygonRadius, Settings.PolygonRadius);\n            aabb.LowerBound = lower - r;\n            aabb.UpperBound = upper + r;\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Collision/Broadphase/DynamicTree.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Broadphase\n{\n    /// <summary>\n    /// A dynamic tree arranges data in a binary tree to accelerate\n    /// queries such as volume queries and ray casts. Leafs are proxies\n    /// with an AABB. In the tree we expand the proxy AABB by Settings.b2_fatAABBFactor\n    /// so that the proxy AABB is bigger than the client object. This allows the client\n    /// object to move by small amounts without triggering a tree update.\n    /// Nodes are pooled and relocatable, so we use node indices rather than pointers.\n    /// </summary>\n    public class DynamicTree<T>\n    {\n        internal const int NullNode = -1;\n        private int _freeList;\n        private int _nodeCapacity;\n        private int _nodeCount;\n        private TreeNode<T>[] _nodes;\n        private Stack<int> _queryStack = new Stack<int>(256);\n        private Stack<int> _raycastStack = new Stack<int>(256);\n        private int _root;\n\n        /// <summary>\n        /// Constructing the tree initializes the node pool.\n        /// </summary>\n        public DynamicTree()\n        {\n            _root = NullNode;\n\n            _nodeCapacity = 16;\n            _nodeCount = 0;\n            _nodes = new TreeNode<T>[_nodeCapacity];\n\n            // Build a linked list for the free list.\n            for (int i = 0; i < _nodeCapacity - 1; ++i)\n            {\n                _nodes[i] = new TreeNode<T>();\n                _nodes[i].ParentOrNext = i + 1;\n                _nodes[i].Height = 1;\n            }\n            _nodes[_nodeCapacity - 1] = new TreeNode<T>();\n            _nodes[_nodeCapacity - 1].ParentOrNext = NullNode;\n            _nodes[_nodeCapacity - 1].Height = 1;\n            _freeList = 0;\n        }\n\n        /// <summary>\n        /// Compute the height of the binary tree in O(N) time. Should not be called often.\n        /// </summary>\n        public int Height\n        {\n            get\n            {\n                if (_root == NullNode)\n                {\n                    return 0;\n                }\n\n                return _nodes[_root].Height;\n            }\n        }\n\n        /// <summary>\n        /// Get the ratio of the sum of the node areas to the root area.\n        /// </summary>\n        public float AreaRatio\n        {\n            get\n            {\n                if (_root == NullNode)\n                {\n                    return 0.0f;\n                }\n\n                TreeNode<T> root = _nodes[_root];\n                float rootArea = root.AABB.Perimeter;\n\n                float totalArea = 0.0f;\n                for (int i = 0; i < _nodeCapacity; ++i)\n                {\n                    TreeNode<T> node = _nodes[i];\n                    if (node.Height < 0)\n                    {\n                        // Free node in pool\n                        continue;\n                    }\n\n                    totalArea += node.AABB.Perimeter;\n                }\n\n                return totalArea / rootArea;\n            }\n        }\n\n        /// <summary>\n        /// Get the maximum balance of an node in the tree. The balance is the difference\n        /// in height of the two children of a node.\n        /// </summary>\n        public int MaxBalance\n        {\n            get\n            {\n                int maxBalance = 0;\n                for (int i = 0; i < _nodeCapacity; ++i)\n                {\n                    TreeNode<T> node = _nodes[i];\n                    if (node.Height <= 1)\n                    {\n                        continue;\n                    }\n\n                    Debug.Assert(node.IsLeaf() == false);\n\n                    int child1 = node.Child1;\n                    int child2 = node.Child2;\n                    int balance = Math.Abs(_nodes[child2].Height - _nodes[child1].Height);\n                    maxBalance = Math.Max(maxBalance, balance);\n                }\n\n                return maxBalance;\n            }\n        }\n\n        /// <summary>\n        /// Create a proxy in the tree as a leaf node. We return the index\n        /// of the node instead of a pointer so that we can grow\n        /// the node pool.\n        /// </summary>\n        /// <param name=\"aabb\">The AABB.</param>\n        /// <param name=\"userData\">The user data.</param>\n        /// <returns>Index of the created proxy</returns>\n        public int AddProxy(ref AABB aabb, T userData)\n        {\n            int proxyId = AllocateNode();\n\n            // Fatten the AABB.\n            Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);\n            _nodes[proxyId].AABB.LowerBound = aabb.LowerBound - r;\n            _nodes[proxyId].AABB.UpperBound = aabb.UpperBound + r;\n            _nodes[proxyId].UserData = userData;\n            _nodes[proxyId].Height = 0;\n\n            InsertLeaf(proxyId);\n\n            return proxyId;\n        }\n\n        /// <summary>\n        /// Destroy a proxy. This asserts if the id is invalid.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        public void RemoveProxy(int proxyId)\n        {\n            Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);\n            Debug.Assert(_nodes[proxyId].IsLeaf());\n\n            RemoveLeaf(proxyId);\n            FreeNode(proxyId);\n        }\n\n        /// <summary>\n        /// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,\n        /// then the proxy is removed from the tree and re-inserted. Otherwise\n        /// the function returns immediately.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        /// <param name=\"aabb\">The AABB.</param>\n        /// <param name=\"displacement\">The displacement.</param>\n        /// <returns>true if the proxy was re-inserted.</returns>\n        public bool MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)\n        {\n            Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);\n\n            Debug.Assert(_nodes[proxyId].IsLeaf());\n\n            if (_nodes[proxyId].AABB.Contains(ref aabb))\n            {\n                return false;\n            }\n\n            RemoveLeaf(proxyId);\n\n            // Extend AABB.\n            AABB b = aabb;\n            Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);\n            b.LowerBound = b.LowerBound - r;\n            b.UpperBound = b.UpperBound + r;\n\n            // Predict AABB displacement.\n            Vector2 d = Settings.AABBMultiplier * displacement;\n\n            if (d.X < 0.0f)\n            {\n                b.LowerBound.X += d.X;\n            }\n            else\n            {\n                b.UpperBound.X += d.X;\n            }\n\n            if (d.Y < 0.0f)\n            {\n                b.LowerBound.Y += d.Y;\n            }\n            else\n            {\n                b.UpperBound.Y += d.Y;\n            }\n\n            _nodes[proxyId].AABB = b;\n\n            InsertLeaf(proxyId);\n            return true;\n        }\n\n        /// <summary>\n        /// Get proxy user data.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        /// <returns>the proxy user data or 0 if the id is invalid.</returns>\n        public T GetUserData(int proxyId)\n        {\n            Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);\n            return _nodes[proxyId].UserData;\n        }\n\n        /// <summary>\n        /// Get the fat AABB for a proxy.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        /// <param name=\"fatAABB\">The fat AABB.</param>\n        public void GetFatAABB(int proxyId, out AABB fatAABB)\n        {\n            Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);\n            fatAABB = _nodes[proxyId].AABB;\n        }\n\n        /// <summary>\n        /// Query an AABB for overlapping proxies. The callback class\n        /// is called for each proxy that overlaps the supplied AABB.\n        /// </summary>\n        /// <param name=\"callback\">The callback.</param>\n        /// <param name=\"aabb\">The AABB.</param>\n        public void Query(Func<int, bool> callback, ref AABB aabb)\n        {\n            _queryStack.Clear();\n            _queryStack.Push(_root);\n\n            while (_queryStack.Count > 0)\n            {\n                int nodeId = _queryStack.Pop();\n                if (nodeId == NullNode)\n                {\n                    continue;\n                }\n\n                TreeNode<T> node = _nodes[nodeId];\n\n                if (AABB.TestOverlap(ref node.AABB, ref aabb))\n                {\n                    if (node.IsLeaf())\n                    {\n                        bool proceed = callback(nodeId);\n                        if (proceed == false)\n                        {\n                            return;\n                        }\n                    }\n                    else\n                    {\n                        _queryStack.Push(node.Child1);\n                        _queryStack.Push(node.Child2);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Ray-cast against the proxies in the tree. This relies on the callback\n        /// to perform a exact ray-cast in the case were the proxy contains a Shape.\n        /// The callback also performs the any collision filtering. This has performance\n        /// roughly equal to k * log(n), where k is the number of collisions and n is the\n        /// number of proxies in the tree.\n        /// </summary>\n        /// <param name=\"callback\">A callback class that is called for each proxy that is hit by the ray.</param>\n        /// <param name=\"input\">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>\n        public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)\n        {\n            Vector2 p1 = input.Point1;\n            Vector2 p2 = input.Point2;\n            Vector2 r = p2 - p1;\n            Debug.Assert(r.LengthSquared() > 0.0f);\n            r.Normalize();\n\n            // v is perpendicular to the segment.\n            Vector2 absV = MathUtils.Abs(new Vector2(-r.Y, r.X)); //Velcro: Inlined the 'v' variable\n\n            // Separating axis for segment (Gino, p80).\n            // |dot(v, p1 - c)| > dot(|v|, h)\n\n            float maxFraction = input.MaxFraction;\n\n            // Build a bounding box for the segment.\n            AABB segmentAABB = new AABB();\n            {\n                Vector2 t = p1 + maxFraction * (p2 - p1);\n                Vector2.Min(ref p1, ref t, out segmentAABB.LowerBound);\n                Vector2.Max(ref p1, ref t, out segmentAABB.UpperBound);\n            }\n\n            _raycastStack.Clear();\n            _raycastStack.Push(_root);\n\n            while (_raycastStack.Count > 0)\n            {\n                int nodeId = _raycastStack.Pop();\n                if (nodeId == NullNode)\n                {\n                    continue;\n                }\n\n                TreeNode<T> node = _nodes[nodeId];\n\n                if (AABB.TestOverlap(ref node.AABB, ref segmentAABB) == false)\n                {\n                    continue;\n                }\n\n                // Separating axis for segment (Gino, p80).\n                // |dot(v, p1 - c)| > dot(|v|, h)\n                Vector2 c = node.AABB.Center;\n                Vector2 h = node.AABB.Extents;\n                float separation = Math.Abs(Vector2.Dot(new Vector2(-r.Y, r.X), p1 - c)) - Vector2.Dot(absV, h);\n                if (separation > 0.0f)\n                {\n                    continue;\n                }\n\n                if (node.IsLeaf())\n                {\n                    RayCastInput subInput;\n                    subInput.Point1 = input.Point1;\n                    subInput.Point2 = input.Point2;\n                    subInput.MaxFraction = maxFraction;\n\n                    float value = callback(subInput, nodeId);\n\n                    if (value == 0.0f)\n                    {\n                        // the client has terminated the raycast.\n                        return;\n                    }\n\n                    if (value > 0.0f)\n                    {\n                        // Update segment bounding box.\n                        maxFraction = value;\n                        Vector2 t = p1 + maxFraction * (p2 - p1);\n                        segmentAABB.LowerBound = Vector2.Min(p1, t);\n                        segmentAABB.UpperBound = Vector2.Max(p1, t);\n                    }\n                }\n                else\n                {\n                    _raycastStack.Push(node.Child1);\n                    _raycastStack.Push(node.Child2);\n                }\n            }\n        }\n\n        private int AllocateNode()\n        {\n            // Expand the node pool as needed.\n            if (_freeList == NullNode)\n            {\n                Debug.Assert(_nodeCount == _nodeCapacity);\n\n                // The free list is empty. Rebuild a bigger pool.\n                TreeNode<T>[] oldNodes = _nodes;\n                _nodeCapacity *= 2;\n                _nodes = new TreeNode<T>[_nodeCapacity];\n                Array.Copy(oldNodes, _nodes, _nodeCount);\n\n                // Build a linked list for the free list. The parent\n                // pointer becomes the \"next\" pointer.\n                for (int i = _nodeCount; i < _nodeCapacity - 1; ++i)\n                {\n                    _nodes[i] = new TreeNode<T>();\n                    _nodes[i].ParentOrNext = i + 1;\n                    _nodes[i].Height = -1;\n                }\n                _nodes[_nodeCapacity - 1] = new TreeNode<T>();\n                _nodes[_nodeCapacity - 1].ParentOrNext = NullNode;\n                _nodes[_nodeCapacity - 1].Height = -1;\n                _freeList = _nodeCount;\n            }\n\n            // Peel a node off the free list.\n            int nodeId = _freeList;\n            _freeList = _nodes[nodeId].ParentOrNext;\n            _nodes[nodeId].ParentOrNext = NullNode;\n            _nodes[nodeId].Child1 = NullNode;\n            _nodes[nodeId].Child2 = NullNode;\n            _nodes[nodeId].Height = 0;\n            _nodes[nodeId].UserData = default(T);\n            ++_nodeCount;\n            return nodeId;\n        }\n\n        private void FreeNode(int nodeId)\n        {\n            Debug.Assert(0 <= nodeId && nodeId < _nodeCapacity);\n            Debug.Assert(0 < _nodeCount);\n            _nodes[nodeId].ParentOrNext = _freeList;\n            _nodes[nodeId].Height = -1;\n            _freeList = nodeId;\n            --_nodeCount;\n        }\n\n        private void InsertLeaf(int leaf)\n        {\n            if (_root == NullNode)\n            {\n                _root = leaf;\n                _nodes[_root].ParentOrNext = NullNode;\n                return;\n            }\n\n            // Find the best sibling for this node\n            AABB leafAABB = _nodes[leaf].AABB;\n            int index = _root;\n            while (_nodes[index].IsLeaf() == false)\n            {\n                int child1 = _nodes[index].Child1;\n                int child2 = _nodes[index].Child2;\n\n                float area = _nodes[index].AABB.Perimeter;\n\n                AABB combinedAABB = new AABB();\n                combinedAABB.Combine(ref _nodes[index].AABB, ref leafAABB);\n                float combinedArea = combinedAABB.Perimeter;\n\n                // Cost of creating a new parent for this node and the new leaf\n                float cost = 2.0f * combinedArea;\n\n                // Minimum cost of pushing the leaf further down the tree\n                float inheritanceCost = 2.0f * (combinedArea - area);\n\n                // Cost of descending into child1\n                float cost1;\n                if (_nodes[child1].IsLeaf())\n                {\n                    AABB aabb = new AABB();\n                    aabb.Combine(ref leafAABB, ref _nodes[child1].AABB);\n                    cost1 = aabb.Perimeter + inheritanceCost;\n                }\n                else\n                {\n                    AABB aabb = new AABB();\n                    aabb.Combine(ref leafAABB, ref _nodes[child1].AABB);\n                    float oldArea = _nodes[child1].AABB.Perimeter;\n                    float newArea = aabb.Perimeter;\n                    cost1 = (newArea - oldArea) + inheritanceCost;\n                }\n\n                // Cost of descending into child2\n                float cost2;\n                if (_nodes[child2].IsLeaf())\n                {\n                    AABB aabb = new AABB();\n                    aabb.Combine(ref leafAABB, ref _nodes[child2].AABB);\n                    cost2 = aabb.Perimeter + inheritanceCost;\n                }\n                else\n                {\n                    AABB aabb = new AABB();\n                    aabb.Combine(ref leafAABB, ref _nodes[child2].AABB);\n                    float oldArea = _nodes[child2].AABB.Perimeter;\n                    float newArea = aabb.Perimeter;\n                    cost2 = newArea - oldArea + inheritanceCost;\n                }\n\n                // Descend according to the minimum cost.\n                if (cost < cost1 && cost1 < cost2)\n                {\n                    break;\n                }\n\n                // Descend\n                if (cost1 < cost2)\n                {\n                    index = child1;\n                }\n                else\n                {\n                    index = child2;\n                }\n            }\n\n            int sibling = index;\n\n            // Create a new parent.\n            int oldParent = _nodes[sibling].ParentOrNext;\n            int newParent = AllocateNode();\n            _nodes[newParent].ParentOrNext = oldParent;\n            _nodes[newParent].UserData = default(T);\n            _nodes[newParent].AABB.Combine(ref leafAABB, ref _nodes[sibling].AABB);\n            _nodes[newParent].Height = _nodes[sibling].Height + 1;\n\n            if (oldParent != NullNode)\n            {\n                // The sibling was not the root.\n                if (_nodes[oldParent].Child1 == sibling)\n                {\n                    _nodes[oldParent].Child1 = newParent;\n                }\n                else\n                {\n                    _nodes[oldParent].Child2 = newParent;\n                }\n\n                _nodes[newParent].Child1 = sibling;\n                _nodes[newParent].Child2 = leaf;\n                _nodes[sibling].ParentOrNext = newParent;\n                _nodes[leaf].ParentOrNext = newParent;\n            }\n            else\n            {\n                // The sibling was the root.\n                _nodes[newParent].Child1 = sibling;\n                _nodes[newParent].Child2 = leaf;\n                _nodes[sibling].ParentOrNext = newParent;\n                _nodes[leaf].ParentOrNext = newParent;\n                _root = newParent;\n            }\n\n            // Walk back up the tree fixing heights and AABBs\n            index = _nodes[leaf].ParentOrNext;\n            while (index != NullNode)\n            {\n                index = Balance(index);\n\n                int child1 = _nodes[index].Child1;\n                int child2 = _nodes[index].Child2;\n\n                Debug.Assert(child1 != NullNode);\n                Debug.Assert(child2 != NullNode);\n\n                _nodes[index].Height = 1 + Math.Max(_nodes[child1].Height, _nodes[child2].Height);\n                _nodes[index].AABB.Combine(ref _nodes[child1].AABB, ref _nodes[child2].AABB);\n\n                index = _nodes[index].ParentOrNext;\n            }\n\n            //Validate();\n        }\n\n        private void RemoveLeaf(int leaf)\n        {\n            if (leaf == _root)\n            {\n                _root = NullNode;\n                return;\n            }\n\n            int parent = _nodes[leaf].ParentOrNext;\n            int grandParent = _nodes[parent].ParentOrNext;\n            int sibling;\n            if (_nodes[parent].Child1 == leaf)\n            {\n                sibling = _nodes[parent].Child2;\n            }\n            else\n            {\n                sibling = _nodes[parent].Child1;\n            }\n\n            if (grandParent != NullNode)\n            {\n                // Destroy parent and connect sibling to grandParent.\n                if (_nodes[grandParent].Child1 == parent)\n                {\n                    _nodes[grandParent].Child1 = sibling;\n                }\n                else\n                {\n                    _nodes[grandParent].Child2 = sibling;\n                }\n                _nodes[sibling].ParentOrNext = grandParent;\n                FreeNode(parent);\n\n                // Adjust ancestor bounds.\n                int index = grandParent;\n                while (index != NullNode)\n                {\n                    index = Balance(index);\n\n                    int child1 = _nodes[index].Child1;\n                    int child2 = _nodes[index].Child2;\n\n                    _nodes[index].AABB.Combine(ref _nodes[child1].AABB, ref _nodes[child2].AABB);\n                    _nodes[index].Height = 1 + Math.Max(_nodes[child1].Height, _nodes[child2].Height);\n\n                    index = _nodes[index].ParentOrNext;\n                }\n            }\n            else\n            {\n                _root = sibling;\n                _nodes[sibling].ParentOrNext = NullNode;\n                FreeNode(parent);\n            }\n\n            //Validate();\n        }\n\n        /// <summary>\n        /// Perform a left or right rotation if node A is imbalanced.\n        /// </summary>\n        /// <param name=\"iA\"></param>\n        /// <returns>the new root index.</returns>\n        private int Balance(int iA)\n        {\n            Debug.Assert(iA != NullNode);\n\n            TreeNode<T> A = _nodes[iA];\n            if (A.IsLeaf() || A.Height < 2)\n            {\n                return iA;\n            }\n\n            int iB = A.Child1;\n            int iC = A.Child2;\n            Debug.Assert(0 <= iB && iB < _nodeCapacity);\n            Debug.Assert(0 <= iC && iC < _nodeCapacity);\n\n            TreeNode<T> B = _nodes[iB];\n            TreeNode<T> C = _nodes[iC];\n\n            int balance = C.Height - B.Height;\n\n            // Rotate C up\n            if (balance > 1)\n            {\n                int iF = C.Child1;\n                int iG = C.Child2;\n                TreeNode<T> F = _nodes[iF];\n                TreeNode<T> G = _nodes[iG];\n                Debug.Assert(0 <= iF && iF < _nodeCapacity);\n                Debug.Assert(0 <= iG && iG < _nodeCapacity);\n\n                // Swap A and C\n                C.Child1 = iA;\n                C.ParentOrNext = A.ParentOrNext;\n                A.ParentOrNext = iC;\n\n                // A's old parent should point to C\n                if (C.ParentOrNext != NullNode)\n                {\n                    if (_nodes[C.ParentOrNext].Child1 == iA)\n                    {\n                        _nodes[C.ParentOrNext].Child1 = iC;\n                    }\n                    else\n                    {\n                        Debug.Assert(_nodes[C.ParentOrNext].Child2 == iA);\n                        _nodes[C.ParentOrNext].Child2 = iC;\n                    }\n                }\n                else\n                {\n                    _root = iC;\n                }\n\n                // Rotate\n                if (F.Height > G.Height)\n                {\n                    C.Child2 = iF;\n                    A.Child2 = iG;\n                    G.ParentOrNext = iA;\n                    A.AABB.Combine(ref B.AABB, ref G.AABB);\n                    C.AABB.Combine(ref A.AABB, ref F.AABB);\n\n                    A.Height = 1 + Math.Max(B.Height, G.Height);\n                    C.Height = 1 + Math.Max(A.Height, F.Height);\n                }\n                else\n                {\n                    C.Child2 = iG;\n                    A.Child2 = iF;\n                    F.ParentOrNext = iA;\n                    A.AABB.Combine(ref B.AABB, ref F.AABB);\n                    C.AABB.Combine(ref A.AABB, ref G.AABB);\n\n                    A.Height = 1 + Math.Max(B.Height, F.Height);\n                    C.Height = 1 + Math.Max(A.Height, G.Height);\n                }\n\n                return iC;\n            }\n\n            // Rotate B up\n            if (balance < -1)\n            {\n                int iD = B.Child1;\n                int iE = B.Child2;\n                TreeNode<T> D = _nodes[iD];\n                TreeNode<T> E = _nodes[iE];\n                Debug.Assert(0 <= iD && iD < _nodeCapacity);\n                Debug.Assert(0 <= iE && iE < _nodeCapacity);\n\n                // Swap A and B\n                B.Child1 = iA;\n                B.ParentOrNext = A.ParentOrNext;\n                A.ParentOrNext = iB;\n\n                // A's old parent should point to B\n                if (B.ParentOrNext != NullNode)\n                {\n                    if (_nodes[B.ParentOrNext].Child1 == iA)\n                    {\n                        _nodes[B.ParentOrNext].Child1 = iB;\n                    }\n                    else\n                    {\n                        Debug.Assert(_nodes[B.ParentOrNext].Child2 == iA);\n                        _nodes[B.ParentOrNext].Child2 = iB;\n                    }\n                }\n                else\n                {\n                    _root = iB;\n                }\n\n                // Rotate\n                if (D.Height > E.Height)\n                {\n                    B.Child2 = iD;\n                    A.Child1 = iE;\n                    E.ParentOrNext = iA;\n                    A.AABB.Combine(ref C.AABB, ref E.AABB);\n                    B.AABB.Combine(ref A.AABB, ref D.AABB);\n\n                    A.Height = 1 + Math.Max(C.Height, E.Height);\n                    B.Height = 1 + Math.Max(A.Height, D.Height);\n                }\n                else\n                {\n                    B.Child2 = iE;\n                    A.Child1 = iD;\n                    D.ParentOrNext = iA;\n                    A.AABB.Combine(ref C.AABB, ref D.AABB);\n                    B.AABB.Combine(ref A.AABB, ref E.AABB);\n\n                    A.Height = 1 + Math.Max(C.Height, D.Height);\n                    B.Height = 1 + Math.Max(A.Height, E.Height);\n                }\n\n                return iB;\n            }\n\n            return iA;\n        }\n\n        /// <summary>\n        /// Compute the height of a sub-tree.\n        /// </summary>\n        /// <param name=\"nodeId\">The node id to use as parent.</param>\n        /// <returns>The height of the tree.</returns>\n        public int ComputeHeight(int nodeId)\n        {\n            Debug.Assert(0 <= nodeId && nodeId < _nodeCapacity);\n            TreeNode<T> node = _nodes[nodeId];\n\n            if (node.IsLeaf())\n            {\n                return 0;\n            }\n\n            int height1 = ComputeHeight(node.Child1);\n            int height2 = ComputeHeight(node.Child2);\n            return 1 + Math.Max(height1, height2);\n        }\n\n        /// <summary>\n        /// Compute the height of the entire tree.\n        /// </summary>\n        /// <returns>The height of the tree.</returns>\n        public int ComputeHeight()\n        {\n            int height = ComputeHeight(_root);\n            return height;\n        }\n\n        public void ValidateStructure(int index)\n        {\n            if (index == NullNode)\n            {\n                return;\n            }\n\n            if (index == _root)\n            {\n                Debug.Assert(_nodes[index].ParentOrNext == NullNode);\n            }\n\n            TreeNode<T> node = _nodes[index];\n\n            int child1 = node.Child1;\n            int child2 = node.Child2;\n\n            if (node.IsLeaf())\n            {\n                Debug.Assert(child1 == NullNode);\n                Debug.Assert(child2 == NullNode);\n                Debug.Assert(node.Height == 0);\n                return;\n            }\n\n            Debug.Assert(0 <= child1 && child1 < _nodeCapacity);\n            Debug.Assert(0 <= child2 && child2 < _nodeCapacity);\n\n            Debug.Assert(_nodes[child1].ParentOrNext == index);\n            Debug.Assert(_nodes[child2].ParentOrNext == index);\n\n            ValidateStructure(child1);\n            ValidateStructure(child2);\n        }\n\n        public void ValidateMetrics(int index)\n        {\n            if (index == NullNode)\n            {\n                return;\n            }\n\n            TreeNode<T> node = _nodes[index];\n\n            int child1 = node.Child1;\n            int child2 = node.Child2;\n\n            if (node.IsLeaf())\n            {\n                Debug.Assert(child1 == NullNode);\n                Debug.Assert(child2 == NullNode);\n                Debug.Assert(node.Height == 0);\n                return;\n            }\n\n            Debug.Assert(0 <= child1 && child1 < _nodeCapacity);\n            Debug.Assert(0 <= child2 && child2 < _nodeCapacity);\n\n            int height1 = _nodes[child1].Height;\n            int height2 = _nodes[child2].Height;\n            int height = 1 + Math.Max(height1, height2);\n            Debug.Assert(node.Height == height);\n\n            AABB AABB = new AABB();\n            AABB.Combine(ref _nodes[child1].AABB, ref _nodes[child2].AABB);\n\n            Debug.Assert(AABB.LowerBound == node.AABB.LowerBound);\n            Debug.Assert(AABB.UpperBound == node.AABB.UpperBound);\n\n            ValidateMetrics(child1);\n            ValidateMetrics(child2);\n        }\n\n        /// <summary>\n        /// Validate this tree. For testing.\n        /// </summary>\n        public void Validate()\n        {\n            ValidateStructure(_root);\n            ValidateMetrics(_root);\n\n            int freeCount = 0;\n            int freeIndex = _freeList;\n            while (freeIndex != NullNode)\n            {\n                Debug.Assert(0 <= freeIndex && freeIndex < _nodeCapacity);\n                freeIndex = _nodes[freeIndex].ParentOrNext;\n                ++freeCount;\n            }\n\n            Debug.Assert(Height == ComputeHeight());\n\n            Debug.Assert(_nodeCount + freeCount == _nodeCapacity);\n        }\n\n        /// <summary>\n        /// Build an optimal tree. Very expensive. For testing.\n        /// </summary>\n        public void RebuildBottomUp()\n        {\n            int[] nodes = new int[_nodeCount];\n            int count = 0;\n\n            // Build array of leaves. Free the rest.\n            for (int i = 0; i < _nodeCapacity; ++i)\n            {\n                if (_nodes[i].Height < 0)\n                {\n                    // free node in pool\n                    continue;\n                }\n\n                if (_nodes[i].IsLeaf())\n                {\n                    _nodes[i].ParentOrNext = NullNode;\n                    nodes[count] = i;\n                    ++count;\n                }\n                else\n                {\n                    FreeNode(i);\n                }\n            }\n\n            while (count > 1)\n            {\n                float minCost = Settings.MaxFloat;\n                int iMin = -1, jMin = -1;\n                for (int i = 0; i < count; ++i)\n                {\n                    AABB AABBi = _nodes[nodes[i]].AABB;\n\n                    for (int j = i + 1; j < count; ++j)\n                    {\n                        AABB AABBj = _nodes[nodes[j]].AABB;\n                        AABB b = new AABB();\n                        b.Combine(ref AABBi, ref AABBj);\n                        float cost = b.Perimeter;\n                        if (cost < minCost)\n                        {\n                            iMin = i;\n                            jMin = j;\n                            minCost = cost;\n                        }\n                    }\n                }\n\n                int index1 = nodes[iMin];\n                int index2 = nodes[jMin];\n                TreeNode<T> child1 = _nodes[index1];\n                TreeNode<T> child2 = _nodes[index2];\n\n                int parentIndex = AllocateNode();\n                TreeNode<T> parent = _nodes[parentIndex];\n                parent.Child1 = index1;\n                parent.Child2 = index2;\n                parent.Height = 1 + Math.Max(child1.Height, child2.Height);\n                parent.AABB.Combine(ref child1.AABB, ref child2.AABB);\n                parent.ParentOrNext = NullNode;\n\n                child1.ParentOrNext = parentIndex;\n                child2.ParentOrNext = parentIndex;\n\n                nodes[jMin] = nodes[count - 1];\n                nodes[iMin] = parentIndex;\n                --count;\n            }\n\n            _root = nodes[0];\n\n            Validate();\n        }\n\n        /// <summary>\n        /// Shift the origin of the nodes\n        /// </summary>\n        /// <param name=\"newOrigin\">The displacement to use.</param>\n        public void ShiftOrigin(Vector2 newOrigin)\n        {\n            // Build array of leaves. Free the rest.\n            for (int i = 0; i < _nodeCapacity; ++i)\n            {\n                _nodes[i].AABB.LowerBound -= newOrigin;\n                _nodes[i].AABB.UpperBound -= newOrigin;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Broadphase/DynamicTreeBroadPhase.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Handlers;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Broadphase\n{\n    /// <summary>\n    /// The broad-phase is used for computing pairs and performing volume queries and ray casts.\n    /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.\n    /// It is up to the client to consume the new pairs and to track subsequent overlap.\n    /// </summary>\n    public class DynamicTreeBroadPhase : IBroadPhase\n    {\n        private const int NullProxy = -1;\n        private int[] _moveBuffer;\n        private int _moveCapacity;\n        private int _moveCount;\n\n        private Pair[] _pairBuffer;\n        private int _pairCapacity;\n        private int _pairCount;\n        private int _proxyCount;\n        private Func<int, bool> _queryCallback;\n        private int _queryProxyId;\n        private DynamicTree<FixtureProxy> _tree = new DynamicTree<FixtureProxy>();\n\n        /// <summary>\n        /// Constructs a new broad phase based on the dynamic tree implementation\n        /// </summary>\n        public DynamicTreeBroadPhase()\n        {\n            _queryCallback = QueryCallback;\n            _proxyCount = 0;\n\n            _pairCapacity = 16;\n            _pairCount = 0;\n            _pairBuffer = new Pair[_pairCapacity];\n\n            _moveCapacity = 16;\n            _moveCount = 0;\n            _moveBuffer = new int[_moveCapacity];\n        }\n\n        /// <summary>\n        /// Get the tree quality based on the area of the tree.\n        /// </summary>\n        public float TreeQuality => _tree.AreaRatio;\n\n        /// <summary>\n        /// Gets the height of the tree.\n        /// </summary>\n        public int TreeHeight => _tree.Height;\n\n        /// <summary>\n        /// Get the number of proxies.\n        /// </summary>\n        /// <value>The proxy count.</value>\n        public int ProxyCount => _proxyCount;\n\n        /// <summary>\n        /// Create a proxy with an initial AABB. Pairs are not reported until\n        /// UpdatePairs is called.\n        /// </summary>\n        /// <param name=\"proxy\">The user data.</param>\n        /// <returns></returns>\n        public int AddProxy(ref FixtureProxy proxy)\n        {\n            int proxyId = _tree.AddProxy(ref proxy.AABB, proxy);\n            ++_proxyCount;\n            BufferMove(proxyId);\n            return proxyId;\n        }\n\n        /// <summary>\n        /// Destroy a proxy. It is up to the client to remove any pairs.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        public void RemoveProxy(int proxyId)\n        {\n            UnBufferMove(proxyId);\n            --_proxyCount;\n            _tree.RemoveProxy(proxyId);\n        }\n\n        /// <summary>\n        /// Call MoveProxy as many times as you like, then when you are done\n        /// call UpdatePairs to finalized the proxy pairs (for your time step).\n        /// </summary>\n        public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)\n        {\n            bool buffer = _tree.MoveProxy(proxyId, ref aabb, displacement);\n            if (buffer)\n                BufferMove(proxyId);\n        }\n\n        /// <summary>\n        /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.\n        /// </summary>\n        public void TouchProxy(int proxyId)\n        {\n            BufferMove(proxyId);\n        }\n\n        /// <summary>\n        /// Get the AABB for a proxy.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        /// <param name=\"aabb\">The AABB.</param>\n        public void GetFatAABB(int proxyId, out AABB aabb)\n        {\n            _tree.GetFatAABB(proxyId, out aabb);\n        }\n\n        /// <summary>\n        /// Get user data from a proxy. Returns null if the id is invalid.\n        /// </summary>\n        /// <param name=\"proxyId\">The proxy id.</param>\n        /// <returns></returns>\n        public FixtureProxy GetProxy(int proxyId)\n        {\n            return _tree.GetUserData(proxyId);\n        }\n\n        /// <summary>\n        /// Test overlap of fat AABBs.\n        /// </summary>\n        /// <param name=\"proxyIdA\">The proxy id A.</param>\n        /// <param name=\"proxyIdB\">The proxy id B.</param>\n        /// <returns></returns>\n        public bool TestOverlap(int proxyIdA, int proxyIdB)\n        {\n            _tree.GetFatAABB(proxyIdA, out AABB aabbA);\n            _tree.GetFatAABB(proxyIdB, out AABB aabbB);\n            return AABB.TestOverlap(ref aabbA, ref aabbB);\n        }\n\n        /// <summary>\n        /// Update the pairs. This results in pair callbacks. This can only add pairs.\n        /// </summary>\n        /// <param name=\"callback\">The callback.</param>\n        public void UpdatePairs(BroadphaseHandler callback)\n        {\n            // Reset pair buffer\n            _pairCount = 0;\n\n            // Perform tree queries for all moving proxies.\n            for (int j = 0; j < _moveCount; ++j)\n            {\n                _queryProxyId = _moveBuffer[j];\n                if (_queryProxyId == NullProxy)\n                    continue;\n\n                // We have to query the tree with the fat AABB so that\n                // we don't fail to create a pair that may touch later.\n                _tree.GetFatAABB(_queryProxyId, out AABB fatAABB);\n\n                // Query tree, create pairs and add them pair buffer.\n                _tree.Query(_queryCallback, ref fatAABB);\n            }\n\n            // Reset move buffer\n            _moveCount = 0;\n\n            // Sort the pair buffer to expose duplicates.\n            Array.Sort(_pairBuffer, 0, _pairCount);\n\n            // Send the pairs back to the client.\n            int i = 0;\n            while (i < _pairCount)\n            {\n                Pair primaryPair = _pairBuffer[i];\n                FixtureProxy userDataA = _tree.GetUserData(primaryPair.ProxyIdA);\n                FixtureProxy userDataB = _tree.GetUserData(primaryPair.ProxyIdB);\n\n                callback(ref userDataA, ref userDataB);\n                ++i;\n\n                // Skip any duplicate pairs.\n                while (i < _pairCount)\n                {\n                    Pair pair = _pairBuffer[i];\n                    if (pair.ProxyIdA != primaryPair.ProxyIdA || pair.ProxyIdB != primaryPair.ProxyIdB)\n                        break;\n\n                    ++i;\n                }\n            }\n\n            // Try to keep the tree balanced.\n            //_tree.Rebalance(4);\n        }\n\n        /// <summary>\n        /// Query an AABB for overlapping proxies. The callback class\n        /// is called for each proxy that overlaps the supplied AABB.\n        /// </summary>\n        /// <param name=\"callback\">The callback.</param>\n        /// <param name=\"aabb\">The AABB.</param>\n        public void Query(Func<int, bool> callback, ref AABB aabb)\n        {\n            _tree.Query(callback, ref aabb);\n        }\n\n        /// <summary>\n        /// Ray-cast against the proxies in the tree. This relies on the callback\n        /// to perform a exact ray-cast in the case were the proxy contains a shape.\n        /// The callback also performs the any collision filtering. This has performance\n        /// roughly equal to k * log(n), where k is the number of collisions and n is the\n        /// number of proxies in the tree.\n        /// </summary>\n        /// <param name=\"callback\">A callback class that is called for each proxy that is hit by the ray.</param>\n        /// <param name=\"input\">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>\n        public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)\n        {\n            _tree.RayCast(callback, ref input);\n        }\n\n        /// <summary>\n        /// Shift the world origin. Useful for large worlds.\n        /// </summary>\n        public void ShiftOrigin(Vector2 newOrigin)\n        {\n            _tree.ShiftOrigin(newOrigin);\n        }\n\n        private void BufferMove(int proxyId)\n        {\n            if (_moveCount == _moveCapacity)\n            {\n                int[] oldBuffer = _moveBuffer;\n                _moveCapacity *= 2;\n                _moveBuffer = new int[_moveCapacity];\n                Array.Copy(oldBuffer, _moveBuffer, _moveCount);\n            }\n\n            _moveBuffer[_moveCount] = proxyId;\n            ++_moveCount;\n        }\n\n        private void UnBufferMove(int proxyId)\n        {\n            for (int i = 0; i < _moveCount; ++i)\n            {\n                if (_moveBuffer[i] == proxyId)\n                    _moveBuffer[i] = NullProxy;\n            }\n        }\n\n        /// <summary>\n        /// This is called from DynamicTree.Query when we are gathering pairs.\n        /// </summary>\n        private bool QueryCallback(int proxyId)\n        {\n            // A proxy cannot form a pair with itself.\n            if (proxyId == _queryProxyId)\n                return true;\n\n            // Grow the pair buffer as needed.\n            if (_pairCount == _pairCapacity)\n            {\n                Pair[] oldBuffer = _pairBuffer;\n                _pairCapacity *= 2;\n                _pairBuffer = new Pair[_pairCapacity];\n                Array.Copy(oldBuffer, _pairBuffer, _pairCount);\n            }\n\n            _pairBuffer[_pairCount].ProxyIdA = Math.Min(proxyId, _queryProxyId);\n            _pairBuffer[_pairCount].ProxyIdB = Math.Max(proxyId, _queryProxyId);\n            ++_pairCount;\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Broadphase/IBroadPhase.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Handlers;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Broadphase\n{\n    public interface IBroadPhase\n    {\n        int ProxyCount { get; }\n        void UpdatePairs(BroadphaseHandler callback);\n\n        bool TestOverlap(int proxyIdA, int proxyIdB);\n\n        int AddProxy(ref FixtureProxy proxy);\n\n        void RemoveProxy(int proxyId);\n\n        void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement);\n\n        FixtureProxy GetProxy(int proxyId);\n\n        void TouchProxy(int proxyId);\n\n        void GetFatAABB(int proxyId, out AABB aabb);\n\n        void Query(Func<int, bool> callback, ref AABB aabb);\n\n        void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input);\n\n        void ShiftOrigin(Vector2 newOrigin);\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Broadphase/Pair.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Collision.Broadphase\n{\n    internal struct Pair : IComparable<Pair>\n    {\n        public int ProxyIdA;\n        public int ProxyIdB;\n\n        #region IComparable<Pair> Members\n\n        public int CompareTo(Pair other)\n        {\n            if (ProxyIdA < other.ProxyIdA)\n            {\n                return -1;\n            }\n            if (ProxyIdA == other.ProxyIdA)\n            {\n                if (ProxyIdB < other.ProxyIdB)\n                {\n                    return -1;\n                }\n                if (ProxyIdB == other.ProxyIdB)\n                {\n                    return 0;\n                }\n            }\n\n            return 1;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Broadphase/TreeNode.cs",
    "content": "using VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Broadphase\n{\n    /// <summary>\n    /// A node in the dynamic tree. The client does not interact with this directly.\n    /// </summary>\n    internal class TreeNode<T>\n    {\n        /// <summary>\n        /// Enlarged AABB\n        /// </summary>\n        internal AABB AABB;\n\n        internal int Child1;\n        internal int Child2;\n\n        internal int Height;\n        internal int ParentOrNext;\n        internal T UserData;\n\n        internal bool IsLeaf()\n        {\n            return Child1 == DynamicTree<T>.NullNode;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/Contact.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Collision.ContactSystem\n{\n    /// <summary>\n    /// The class manages contact between two shapes. A contact exists for each overlapping\n    /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist\n    /// that has no contact points.\n    /// </summary>\n    public class Contact\n    {\n        private static EdgeShape _edge = new EdgeShape();\n\n        private static ContactType[,] _registers =\n        {\n            {\n                ContactType.Circle,\n                ContactType.EdgeAndCircle,\n                ContactType.PolygonAndCircle,\n                ContactType.ChainAndCircle\n            },\n            {\n                ContactType.EdgeAndCircle,\n                ContactType.NotSupported,\n\n                // 1,1 is invalid (no ContactType.Edge)\n                ContactType.EdgeAndPolygon,\n                ContactType.NotSupported\n\n                // 1,3 is invalid (no ContactType.EdgeAndLoop)\n            },\n            {\n                ContactType.PolygonAndCircle,\n                ContactType.EdgeAndPolygon,\n                ContactType.Polygon,\n                ContactType.ChainAndPolygon\n            },\n            {\n                ContactType.ChainAndCircle,\n                ContactType.NotSupported,\n\n                // 3,1 is invalid (no ContactType.EdgeAndLoop)\n                ContactType.ChainAndPolygon,\n                ContactType.NotSupported\n\n                // 3,3 is invalid (no ContactType.Loop)\n            }\n        };\n\n        // Nodes for connecting bodies.\n        internal ContactEdge _nodeA = new ContactEdge();\n        internal ContactEdge _nodeB = new ContactEdge();\n\n        internal float _toi;\n        internal int _toiCount;\n        private ContactType _type;\n\n        public Fixture FixtureA;\n        public Fixture FixtureB;\n\n        /// <summary>\n        /// Get the contact manifold. Do not modify the manifold unless you understand the\n        /// internals of Box2D.\n        /// </summary>\n        public Manifold Manifold;\n\n        private Contact(Fixture fA, int indexA, Fixture fB, int indexB)\n        {\n            Reset(fA, indexA, fB, indexB);\n        }\n\n        public float Friction { get; set; }\n        public float Restitution { get; set; }\n\n        /// <summary>\n        /// Get or set the desired tangent speed for a conveyor belt behavior. In meters per second.\n        /// </summary>\n        public float TangentSpeed { get; set; }\n\n\n        /// <summary>\n        /// Get the child primitive index for fixture A.\n        /// </summary>\n        /// <value>The child index A.</value>\n        public int ChildIndexA { get; private set; }\n\n        /// <summary>\n        /// Get the child primitive index for fixture B.\n        /// </summary>\n        /// <value>The child index B.</value>\n        public int ChildIndexB { get; private set; }\n\n        /// <summary>\n        /// Enable/disable this contact.The contact is only disabled for the current\n        /// time step (or sub-step in continuous collisions).\n        /// </summary>\n        public bool Enabled\n        {\n            get => (_flags & ContactFlags.EnabledFlag) == ContactFlags.EnabledFlag;\n            set\n            {\n                if (value)\n                    _flags |= ContactFlags.EnabledFlag;\n                else\n                    _flags &= ~ContactFlags.EnabledFlag;\n            }\n        }\n\n        internal bool IsTouching => (_flags & ContactFlags.TouchingFlag) == ContactFlags.TouchingFlag;\n        internal bool IslandFlag => (_flags & ContactFlags.IslandFlag) == ContactFlags.IslandFlag;\n        internal bool TOIFlag => (_flags & ContactFlags.TOIFlag) == ContactFlags.TOIFlag;\n        internal bool FilterFlag => (_flags & ContactFlags.FilterFlag) == ContactFlags.FilterFlag;\n\n        internal ContactFlags _flags;\n\n        public void ResetRestitution()\n        {\n            Restitution = Settings.MixRestitution(FixtureA.Restitution, FixtureB.Restitution);\n        }\n\n        public void ResetFriction()\n        {\n            Friction = Settings.MixFriction(FixtureA.Friction, FixtureB.Friction);\n        }\n\n        /// <summary>\n        /// Gets the world manifold.\n        /// </summary>\n        public void GetWorldManifold(out Vector2 normal, out FixedArray2<Vector2> points)\n        {\n            Body bodyA = FixtureA.Body;\n            Body bodyB = FixtureB.Body;\n            Shape shapeA = FixtureA.Shape;\n            Shape shapeB = FixtureB.Shape;\n\n            WorldManifold.Initialize(ref Manifold, ref bodyA._xf, shapeA.Radius, ref bodyB._xf, shapeB.Radius, out normal, out points, out _);\n        }\n\n        private void Reset(Fixture fA, int indexA, Fixture fB, int indexB)\n        {\n            _flags = ContactFlags.EnabledFlag;\n\n            FixtureA = fA;\n            FixtureB = fB;\n\n            ChildIndexA = indexA;\n            ChildIndexB = indexB;\n\n            Manifold.PointCount = 0;\n\n            _nodeA.Contact = null;\n            _nodeA.Prev = null;\n            _nodeA.Next = null;\n            _nodeA.Other = null;\n\n            _nodeB.Contact = null;\n            _nodeB.Prev = null;\n            _nodeB.Next = null;\n            _nodeB.Other = null;\n\n            _toiCount = 0;\n\n            //Velcro: We only set the friction and restitution if we are not destroying the contact\n            if (FixtureA != null && FixtureB != null)\n            {\n                Friction = Settings.MixFriction(FixtureA.Friction, FixtureB.Friction);\n                Restitution = Settings.MixRestitution(FixtureA.Restitution, FixtureB.Restitution);\n            }\n\n            TangentSpeed = 0;\n        }\n\n        /// <summary>\n        /// Update the contact manifold and touching status.\n        /// Note: do not assume the fixture AABBs are overlapping or are valid.\n        /// </summary>\n        /// <param name=\"contactManager\">The contact manager.</param>\n        internal void Update(ContactManager contactManager)\n        {\n            if (FixtureA == null || FixtureB == null)\n                return;\n\n            Body bodyA = FixtureA.Body;\n            Body bodyB = FixtureB.Body;\n\n            Manifold oldManifold = Manifold;\n\n            // Re-enable this contact.\n            _flags |= ContactFlags.EnabledFlag;\n\n            bool touching;\n            bool wasTouching = IsTouching;\n\n            bool sensor = FixtureA.IsSensor || FixtureB.IsSensor;\n\n            // Is this contact a sensor?\n            if (sensor)\n            {\n                Shape shapeA = FixtureA.Shape;\n                Shape shapeB = FixtureB.Shape;\n                touching = Narrowphase.Collision.TestOverlap(shapeA, ChildIndexA, shapeB, ChildIndexB, ref bodyA._xf, ref bodyB._xf);\n\n                // Sensors don't generate manifolds.\n                Manifold.PointCount = 0;\n            }\n            else\n            {\n                Evaluate(ref Manifold, ref bodyA._xf, ref bodyB._xf);\n                touching = Manifold.PointCount > 0;\n\n                // Match old contact ids to new contact ids and copy the\n                // stored impulses to warm start the solver.\n                for (int i = 0; i < Manifold.PointCount; ++i)\n                {\n                    ManifoldPoint mp2 = Manifold.Points[i];\n                    mp2.NormalImpulse = 0.0f;\n                    mp2.TangentImpulse = 0.0f;\n                    ContactID id2 = mp2.Id;\n\n                    for (int j = 0; j < oldManifold.PointCount; ++j)\n                    {\n                        ManifoldPoint mp1 = oldManifold.Points[j];\n\n                        if (mp1.Id.Key == id2.Key)\n                        {\n                            mp2.NormalImpulse = mp1.NormalImpulse;\n                            mp2.TangentImpulse = mp1.TangentImpulse;\n                            break;\n                        }\n                    }\n\n                    Manifold.Points[i] = mp2;\n                }\n\n                if (touching != wasTouching)\n                {\n                    bodyA.Awake = true;\n                    bodyB.Awake = true;\n                }\n            }\n\n            if (touching)\n                _flags |= ContactFlags.TouchingFlag;\n            else\n                _flags &= ~ContactFlags.TouchingFlag;\n\n            if (wasTouching == false && touching)\n            {\n                FixtureA.OnCollision?.Invoke(FixtureA, FixtureB, this);\n                FixtureB.OnCollision?.Invoke(FixtureB, FixtureA, this);\n                contactManager.BeginContact?.Invoke(this);\n\n                // Velcro: If the user disabled the contact (needed to exclude it in TOI solver) at any point by\n                // any of the callbacks, we need to mark it as not touching and call any separation\n                // callbacks for fixtures that didn't explicitly disable the collision.\n                if (!Enabled)\n                    touching = false;\n            }\n\n            if (wasTouching == true && touching == false)\n            {\n                FixtureA?.OnSeparation?.Invoke(FixtureA, FixtureB, this);\n                FixtureB?.OnSeparation?.Invoke(FixtureB, FixtureA, this);\n                contactManager.EndContact?.Invoke(this);\n            }\n\n            if (sensor)\n                return;\n\n            contactManager.PreSolve?.Invoke(this, ref oldManifold);\n        }\n\n        /// <summary>\n        /// Evaluate this contact with your own manifold and transforms.\n        /// </summary>\n        /// <param name=\"manifold\">The manifold.</param>\n        /// <param name=\"transformA\">The first transform.</param>\n        /// <param name=\"transformB\">The second transform.</param>\n        private void Evaluate(ref Manifold manifold, ref Transform transformA, ref Transform transformB)\n        {\n            switch (_type)\n            {\n                case ContactType.Polygon:\n                    CollidePolygon.CollidePolygons(ref manifold, (PolygonShape)FixtureA.Shape, ref transformA, (PolygonShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.PolygonAndCircle:\n                    CollideCircle.CollidePolygonAndCircle(ref manifold, (PolygonShape)FixtureA.Shape, ref transformA, (CircleShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.EdgeAndCircle:\n                    CollideEdge.CollideEdgeAndCircle(ref manifold, (EdgeShape)FixtureA.Shape, ref transformA, (CircleShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.EdgeAndPolygon:\n                    CollideEdge.CollideEdgeAndPolygon(ref manifold, (EdgeShape)FixtureA.Shape, ref transformA, (PolygonShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.ChainAndCircle:\n                    ChainShape chain = (ChainShape)FixtureA.Shape;\n                    chain.GetChildEdge(_edge, ChildIndexA);\n                    CollideEdge.CollideEdgeAndCircle(ref manifold, _edge, ref transformA, (CircleShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.ChainAndPolygon:\n                    ChainShape loop2 = (ChainShape)FixtureA.Shape;\n                    loop2.GetChildEdge(_edge, ChildIndexA);\n                    CollideEdge.CollideEdgeAndPolygon(ref manifold, _edge, ref transformA, (PolygonShape)FixtureB.Shape, ref transformB);\n                    break;\n                case ContactType.Circle:\n                    CollideCircle.CollideCircles(ref manifold, (CircleShape)FixtureA.Shape, ref transformA, (CircleShape)FixtureB.Shape, ref transformB);\n                    break;\n                default:\n                    throw new ArgumentException(\"You are using an unsupported contact type.\");\n            }\n        }\n\n        internal static Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB)\n        {\n            ShapeType type1 = fixtureA.Shape.ShapeType;\n            ShapeType type2 = fixtureB.Shape.ShapeType;\n\n            Debug.Assert(ShapeType.Unknown < type1 && type1 < ShapeType.TypeCount);\n            Debug.Assert(ShapeType.Unknown < type2 && type2 < ShapeType.TypeCount);\n\n            Contact c;\n            Queue<Contact> pool = fixtureA.Body._world._contactPool;\n            if (pool.Count > 0)\n            {\n                c = pool.Dequeue();\n                if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))\n                {\n                    c.Reset(fixtureA, indexA, fixtureB, indexB);\n                }\n                else\n                {\n                    c.Reset(fixtureB, indexB, fixtureA, indexA);\n                }\n            }\n            else\n            {\n                // Edge+Polygon is non-symmetrical due to the way Erin handles collision type registration.\n                if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))\n                {\n                    c = new Contact(fixtureA, indexA, fixtureB, indexB);\n                }\n                else\n                {\n                    c = new Contact(fixtureB, indexB, fixtureA, indexA);\n                }\n            }\n\n            c._type = _registers[(int)type1, (int)type2];\n\n            return c;\n        }\n\n        internal void Destroy()\n        {\n            FixtureA.Body._world._contactPool.Enqueue(this);\n\n            if (Manifold.PointCount > 0 && FixtureA.IsSensor == false && FixtureB.IsSensor == false)\n            {\n                FixtureA.Body.Awake = true;\n                FixtureB.Body.Awake = true;\n            }\n\n            Reset(null, 0, null, 0);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactEdge.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.ContactSystem\n{\n    /// <summary>\n    /// A contact edge is used to connect bodies and contacts together\n    /// in a contact graph where each body is a node and each contact\n    /// is an edge. A contact edge belongs to a doubly linked list\n    /// maintained in each attached body. Each contact has two contact\n    /// nodes, one for each attached body.\n    /// </summary>\n    public sealed class ContactEdge\n    {\n        /// <summary>\n        /// The contact\n        /// </summary>\n        public Contact Contact;\n\n        /// <summary>\n        /// The next contact edge in the body's contact list\n        /// </summary>\n        public ContactEdge Next;\n\n        /// <summary>\n        /// Provides quick access to the other body attached.\n        /// </summary>\n        public Body Other;\n\n        /// <summary>\n        /// The previous contact edge in the body's contact list\n        /// </summary>\n        public ContactEdge Prev;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactFeature.cs",
    "content": "namespace VelcroPhysics.Collision.ContactSystem\n{\n    /// <summary>\n    /// The features that intersect to form the contact point\n    /// This must be 4 bytes or less.\n    /// </summary>\n    public struct ContactFeature\n    {\n        /// <summary>\n        /// Feature index on ShapeA\n        /// </summary>\n        public byte IndexA;\n\n        /// <summary>\n        /// Feature index on ShapeB\n        /// </summary>\n        public byte IndexB;\n\n        /// <summary>\n        /// The feature type on ShapeA\n        /// </summary>\n        public ContactFeatureType TypeA;\n\n        /// <summary>\n        /// The feature type on ShapeB\n        /// </summary>\n        public ContactFeatureType TypeB;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactFeatureType.cs",
    "content": "namespace VelcroPhysics.Collision.ContactSystem\n{\n    public enum ContactFeatureType : byte\n    {\n        Vertex = 0,\n        Face = 1\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactFlags.cs",
    "content": "﻿using System;\n\nnamespace VelcroPhysics.Collision.ContactSystem\n{\n    [Flags]\n    internal enum ContactFlags : byte\n    {\n        Unknown = 0,\n\n        /// <summary>\n        /// Used when crawling contact graph when forming islands.\n        /// </summary>\n        IslandFlag = 1,\n\n        /// <summary>\n        /// Set when the shapes are touching.\n        /// </summary>\n        TouchingFlag = 2,\n\n        /// <summary>\n        /// This contact can be disabled (by user)\n        /// </summary>\n        EnabledFlag = 4,\n\n        /// <summary>\n        /// This contact needs filtering because a fixture filter was changed.\n        /// </summary>\n        FilterFlag = 8,\n\n        /// <summary>\n        /// This bullet contact had a TOI event\n        /// </summary>\n        BulletHitFlag = 16,\n\n        /// <summary>\n        /// This contact has a valid TOI in m_toi\n        /// </summary>\n        TOIFlag = 32\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactID.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace VelcroPhysics.Collision.ContactSystem\n{\n    /// <summary>\n    /// Contact ids to facilitate warm starting.\n    /// </summary>\n    [StructLayout(LayoutKind.Explicit)]\n    public struct ContactID\n    {\n        /// <summary>\n        /// The features that intersect to form the contact point\n        /// </summary>\n        [FieldOffset(0)]\n        public ContactFeature ContactFeature;\n\n        /// <summary>\n        /// Used to quickly compare contact ids.\n        /// </summary>\n        [FieldOffset(0)]\n        public uint Key;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactManager.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Collections.Generic;\nusing VelcroPhysics.Collision.Broadphase;\nusing VelcroPhysics.Collision.Filtering;\nusing VelcroPhysics.Collision.Handlers;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Handlers;\n\nnamespace VelcroPhysics.Collision.ContactSystem\n{\n    public class ContactManager\n    {\n        /// <summary>\n        /// Fires when a contact is created\n        /// </summary>\n        public BeginContactHandler BeginContact;\n\n        /// <summary>\n        /// The filter used by the contact manager.\n        /// </summary>\n        public CollisionFilterHandler ContactFilter;\n\n        /// <summary>\n        /// Fires when a contact is deleted\n        /// </summary>\n        public EndContactHandler EndContact;\n\n        /// <summary>\n        /// Fires when the broadphase detects that two Fixtures are close to each other.\n        /// </summary>\n        public BroadphaseHandler OnBroadphaseCollision;\n\n        /// <summary>\n        /// Fires after the solver has run\n        /// </summary>\n        public PostSolveHandler PostSolve;\n\n        /// <summary>\n        /// Fires before the solver runs\n        /// </summary>\n        public PreSolveHandler PreSolve;\n\n        internal ContactManager(IBroadPhase broadPhase)\n        {\n            BroadPhase = broadPhase;\n            OnBroadphaseCollision = AddPair;\n            ContactList = new List<Contact>(128);\n        }\n\n        public List<Contact> ContactList { get; }\n        public IBroadPhase BroadPhase { get; }\n\n        // Broad-phase callback.\n        private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB)\n        {\n            Fixture fixtureA = proxyA.Fixture;\n            Fixture fixtureB = proxyB.Fixture;\n\n            int indexA = proxyA.ChildIndex;\n            int indexB = proxyB.ChildIndex;\n\n            Body bodyA = fixtureA.Body;\n            Body bodyB = fixtureB.Body;\n\n            // Are the fixtures on the same body?\n            if (bodyA == bodyB)\n            {\n                return;\n            }\n\n            // Does a contact already exist?\n            ContactEdge edge = bodyB.ContactList;\n            while (edge != null)\n            {\n                if (edge.Other == bodyA)\n                {\n                    Fixture fA = edge.Contact.FixtureA;\n                    Fixture fB = edge.Contact.FixtureB;\n                    int iA = edge.Contact.ChildIndexA;\n                    int iB = edge.Contact.ChildIndexB;\n\n                    if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)\n                    {\n                        // A contact already exists.\n                        return;\n                    }\n\n                    if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)\n                    {\n                        // A contact already exists.\n                        return;\n                    }\n                }\n\n                edge = edge.Next;\n            }\n\n            // Does a joint override collision? Is at least one body dynamic?\n            if (bodyB.ShouldCollide(bodyA) == false)\n                return;\n\n            //Check default filter\n            if (ShouldCollide(fixtureA, fixtureB) == false)\n                return;\n\n            // Check user filtering.\n            if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)\n                return;\n\n            //Velcro: BeforeCollision delegate\n            if (fixtureA.BeforeCollision != null && fixtureA.BeforeCollision(fixtureA, fixtureB) == false)\n                return;\n\n            if (fixtureB.BeforeCollision != null && fixtureB.BeforeCollision(fixtureB, fixtureA) == false)\n                return;\n\n            // Call the factory.\n            Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);\n\n            if (c == null)\n                return;\n\n            // Contact creation may swap fixtures.\n            fixtureA = c.FixtureA;\n            fixtureB = c.FixtureB;\n            bodyA = fixtureA.Body;\n            bodyB = fixtureB.Body;\n\n            // Insert into the world.\n            ContactList.Add(c);\n\n            // Connect to island graph.\n\n            // Connect to body A\n            c._nodeA.Contact = c;\n            c._nodeA.Other = bodyB;\n\n            c._nodeA.Prev = null;\n            c._nodeA.Next = bodyA.ContactList;\n            if (bodyA.ContactList != null)\n            {\n                bodyA.ContactList.Prev = c._nodeA;\n            }\n            bodyA.ContactList = c._nodeA;\n\n            // Connect to body B\n            c._nodeB.Contact = c;\n            c._nodeB.Other = bodyA;\n\n            c._nodeB.Prev = null;\n            c._nodeB.Next = bodyB.ContactList;\n            if (bodyB.ContactList != null)\n            {\n                bodyB.ContactList.Prev = c._nodeB;\n            }\n            bodyB.ContactList = c._nodeB;\n\n            // Wake up the bodies\n            if (fixtureA.IsSensor == false && fixtureB.IsSensor == false)\n            {\n                bodyA.Awake = true;\n                bodyB.Awake = true;\n            }\n        }\n\n        internal void FindNewContacts()\n        {\n            BroadPhase.UpdatePairs(OnBroadphaseCollision);\n        }\n\n        internal void Destroy(Contact contact)\n        {\n            if (contact.FixtureA == null || contact.FixtureB == null)\n                return;\n\n            Fixture fixtureA = contact.FixtureA;\n            Fixture fixtureB = contact.FixtureB;\n\n            //Velcro: When contacts are removed, we invoke OnSeparation\n            if (contact.IsTouching)\n            {\n                //Report the separation to both participants:\n                fixtureA.OnSeparation?.Invoke(fixtureA, fixtureB, contact);\n\n                //Reverse the order of the reported fixtures. The first fixture is always the one that the user subscribed to.\n                fixtureB.OnSeparation?.Invoke(fixtureB, fixtureA, contact);\n\n                //The generic handler\n                EndContact?.Invoke(contact);\n            }\n\n            Body bodyA = fixtureA.Body;\n            Body bodyB = fixtureB.Body;\n\n            // Remove from the world.\n            ContactList.Remove(contact);\n\n            // Remove from body 1\n            if (contact._nodeA.Prev != null)\n                contact._nodeA.Prev.Next = contact._nodeA.Next;\n\n            if (contact._nodeA.Next != null)\n                contact._nodeA.Next.Prev = contact._nodeA.Prev;\n\n            if (contact._nodeA == bodyA.ContactList)\n                bodyA.ContactList = contact._nodeA.Next;\n\n            // Remove from body 2\n            if (contact._nodeB.Prev != null)\n                contact._nodeB.Prev.Next = contact._nodeB.Next;\n\n            if (contact._nodeB.Next != null)\n                contact._nodeB.Next.Prev = contact._nodeB.Prev;\n\n            if (contact._nodeB == bodyB.ContactList)\n                bodyB.ContactList = contact._nodeB.Next;\n\n            contact.Destroy();\n        }\n\n        internal void Collide()\n        {\n            // Update awake contacts.\n            for (int i = 0; i < ContactList.Count; i++)\n            {\n                Contact c = ContactList[i];\n                Fixture fixtureA = c.FixtureA;\n                Fixture fixtureB = c.FixtureB;\n                int indexA = c.ChildIndexA;\n                int indexB = c.ChildIndexB;\n                Body bodyA = fixtureA.Body;\n                Body bodyB = fixtureB.Body;\n\n                //Velcro: Do no try to collide disabled bodies\n                if (!bodyA.Enabled || !bodyB.Enabled)\n                    continue;\n\n                // Is this contact flagged for filtering?\n                if (c.FilterFlag)\n                {\n                    // Should these bodies collide?\n                    if (bodyB.ShouldCollide(bodyA) == false)\n                    {\n                        Contact cNuke = c;\n                        Destroy(cNuke);\n                        continue;\n                    }\n\n                    // Check default filtering\n                    if (ShouldCollide(fixtureA, fixtureB) == false)\n                    {\n                        Contact cNuke = c;\n                        Destroy(cNuke);\n                        continue;\n                    }\n\n                    // Check user filtering.\n                    if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)\n                    {\n                        Contact cNuke = c;\n                        Destroy(cNuke);\n                        continue;\n                    }\n\n                    // Clear the filtering flag.\n                    c._flags &= ~ContactFlags.FilterFlag;\n                }\n\n                bool activeA = bodyA.Awake && bodyA.BodyType != BodyType.Static;\n                bool activeB = bodyB.Awake && bodyB.BodyType != BodyType.Static;\n\n                // At least one body must be awake and it must be dynamic or kinematic.\n                if (activeA == false && activeB == false)\n                {\n                    continue;\n                }\n\n                int proxyIdA = fixtureA.Proxies[indexA].ProxyId;\n                int proxyIdB = fixtureB.Proxies[indexB].ProxyId;\n                bool overlap = BroadPhase.TestOverlap(proxyIdA, proxyIdB);\n\n                // Here we destroy contacts that cease to overlap in the broad-phase.\n                if (overlap == false)\n                {\n                    Contact cNuke = c;\n                    Destroy(cNuke);\n                    continue;\n                }\n\n                // The contact persists.\n                c.Update(this);\n            }\n        }\n\n        private static bool ShouldCollide(Fixture fixtureA, Fixture fixtureB)\n        {\n            if (Settings.UseFPECollisionCategories)\n            {\n                if ((fixtureA.CollisionGroup == fixtureB.CollisionGroup) &&\n                    fixtureA.CollisionGroup != 0 && fixtureB.CollisionGroup != 0)\n                    return false;\n\n                if (((fixtureA.CollisionCategories & fixtureB.CollidesWith) ==\n                     Category.None) &\n                    ((fixtureB.CollisionCategories & fixtureA.CollidesWith) ==\n                     Category.None))\n                    return false;\n\n                return true;\n            }\n\n            if (fixtureA.CollisionGroup == fixtureB.CollisionGroup &&\n                fixtureA.CollisionGroup != 0)\n            {\n                return fixtureA.CollisionGroup > 0;\n            }\n\n            bool collide = (fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0 &&\n                           (fixtureA.CollisionCategories & fixtureB.CollidesWith) != 0;\n\n            return collide;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/ContactSystem/ContactType.cs",
    "content": "namespace VelcroPhysics.Collision.ContactSystem\n{\n    public enum ContactType : byte\n    {\n        NotSupported,\n        Polygon,\n        PolygonAndCircle,\n        Circle,\n        EdgeAndPolygon,\n        EdgeAndCircle,\n        ChainAndPolygon,\n        ChainAndCircle\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Distance/DistanceGJK.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Distance\n{\n    /// <summary>\n    /// The Gilbert–Johnson–Keerthi distance algorithm that provides the distance between shapes.\n    /// Using Voronoi regions (Christer Ericson) and Barycentric coordinates.\n    /// </summary>\n    public static class DistanceGJK\n    {\n        /// <summary>\n        /// The number of calls made to the ComputeDistance() function.\n        /// Note: This is only activated when Settings.EnableDiagnostics = true\n        /// </summary>\n        [ThreadStatic]\n        public static int GJKCalls;\n\n        /// <summary>\n        /// The number of iterations that was made on the last call to ComputeDistance().\n        /// Note: This is only activated when Settings.EnableDiagnostics = true\n        /// </summary>\n        [ThreadStatic]\n        public static int GJKIters;\n\n        /// <summary>\n        /// The maximum number of iterations calls to the CompteDistance() function.\n        /// Note: This is only activated when Settings.EnableDiagnostics = true\n        /// </summary>\n        [ThreadStatic]\n        public static int GJKMaxIters;\n\n        public static void ComputeDistance(ref DistanceInput input, out DistanceOutput output, out SimplexCache cache)\n        {\n            cache = new SimplexCache();\n\n            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                ++GJKCalls;\n\n            // Initialize the simplex.\n            Simplex simplex = new Simplex();\n            simplex.ReadCache(ref cache, ref input.ProxyA, ref input.TransformA, ref input.ProxyB, ref input.TransformB);\n\n            // These store the vertices of the last simplex so that we\n            // can check for duplicates and prevent cycling.\n            FixedArray3<int> saveA = new FixedArray3<int>();\n            FixedArray3<int> saveB = new FixedArray3<int>();\n\n            //Velcro: This code was not used anyway.\n            //float distanceSqr1 = Settings.MaxFloat;\n\n            // Main iteration loop.\n            int iter = 0;\n            while (iter < Settings.MaxGJKIterations)\n            {\n                // Copy simplex so we can identify duplicates.\n                int saveCount = simplex.Count;\n                for (int i = 0; i < saveCount; ++i)\n                {\n                    saveA[i] = simplex.V[i].IndexA;\n                    saveB[i] = simplex.V[i].IndexB;\n                }\n\n                switch (simplex.Count)\n                {\n                    case 1:\n                        break;\n                    case 2:\n                        simplex.Solve2();\n                        break;\n                    case 3:\n                        simplex.Solve3();\n                        break;\n                    default:\n                        Debug.Assert(false);\n                        break;\n                }\n\n                // If we have 3 points, then the origin is in the corresponding triangle.\n                if (simplex.Count == 3)\n                {\n                    break;\n                }\n\n                // Get search direction.\n                Vector2 d = simplex.GetSearchDirection();\n\n                // Ensure the search direction is numerically fit.\n                if (d.LengthSquared() < Settings.Epsilon * Settings.Epsilon)\n                {\n                    // The origin is probably contained by a line segment\n                    // or triangle. Thus the shapes are overlapped.\n\n                    // We can't return zero here even though there may be overlap.\n                    // In case the simplex is a point, segment, or triangle it is difficult\n                    // to determine if the origin is contained in the CSO or very close to it.\n                    break;\n                }\n\n                // Compute a tentative new simplex vertex using support points.\n                SimplexVertex vertex = simplex.V[simplex.Count];\n                vertex.IndexA = input.ProxyA.GetSupport(MathUtils.MulT(input.TransformA.q, -d));\n                vertex.WA = MathUtils.Mul(ref input.TransformA, input.ProxyA.Vertices[vertex.IndexA]);\n\n                vertex.IndexB = input.ProxyB.GetSupport(MathUtils.MulT(input.TransformB.q, d));\n                vertex.WB = MathUtils.Mul(ref input.TransformB, input.ProxyB.Vertices[vertex.IndexB]);\n                vertex.W = vertex.WB - vertex.WA;\n                simplex.V[simplex.Count] = vertex;\n\n                // Iteration count is equated to the number of support point calls.\n                ++iter;\n\n                if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                    ++GJKIters;\n\n                // Check for duplicate support points. This is the main termination criteria.\n                bool duplicate = false;\n                for (int i = 0; i < saveCount; ++i)\n                {\n                    if (vertex.IndexA == saveA[i] && vertex.IndexB == saveB[i])\n                    {\n                        duplicate = true;\n                        break;\n                    }\n                }\n\n                // If we found a duplicate support point we must exit to avoid cycling.\n                if (duplicate)\n                {\n                    break;\n                }\n\n                // New vertex is OK and needed.\n                ++simplex.Count;\n            }\n\n            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                GJKMaxIters = Math.Max(GJKMaxIters, iter);\n\n            // Prepare output.\n            simplex.GetWitnessPoints(out output.PointA, out output.PointB);\n            output.Distance = (output.PointA - output.PointB).Length();\n            output.Iterations = iter;\n\n            // Cache the simplex.\n            simplex.WriteCache(ref cache);\n\n            // Apply radii if requested.\n            if (input.UseRadii)\n            {\n                float rA = input.ProxyA.Radius;\n                float rB = input.ProxyB.Radius;\n\n                if (output.Distance > rA + rB && output.Distance > Settings.Epsilon)\n                {\n                    // Shapes are still no overlapped.\n                    // Move the witness points to the outer surface.\n                    output.Distance -= rA + rB;\n                    Vector2 normal = output.PointB - output.PointA;\n                    normal.Normalize();\n                    output.PointA += rA * normal;\n                    output.PointB -= rB * normal;\n                }\n                else\n                {\n                    // Shapes are overlapped when radii are considered.\n                    // Move the witness points to the middle.\n                    Vector2 p = 0.5f * (output.PointA + output.PointB);\n                    output.PointA = p;\n                    output.PointB = p;\n                    output.Distance = 0.0f;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Distance/DistanceInput.cs",
    "content": "using VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Distance\n{\n    /// <summary>\n    /// Input for Distance.ComputeDistance().\n    /// You have to option to use the shape radii in the computation.\n    /// </summary>\n    public struct DistanceInput\n    {\n        public DistanceProxy ProxyA;\n        public DistanceProxy ProxyB;\n        public Transform TransformA;\n        public Transform TransformB;\n        public bool UseRadii;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Distance/DistanceOutput.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.Distance\n{\n    /// <summary>\n    /// Output for Distance.ComputeDistance().\n    /// </summary>\n    public struct DistanceOutput\n    {\n        public float Distance;\n\n        /// <summary>\n        /// Number of GJK iterations used\n        /// </summary>\n        public int Iterations;\n\n        /// <summary>\n        /// Closest point on shapeA\n        /// </summary>\n        public Vector2 PointA;\n\n        /// <summary>\n        /// Closest point on shapeB\n        /// </summary>\n        public Vector2 PointB;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Distance/DistanceProxy.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\n\nnamespace VelcroPhysics.Collision.Distance\n{\n    /// <summary>\n    /// A distance proxy is used by the GJK algorithm.\n    /// It encapsulates any shape.\n    /// </summary>\n    public struct DistanceProxy\n    {\n        internal readonly float Radius;\n        internal readonly Vector2[] Vertices;\n\n        public DistanceProxy(Shape shape, int index)\n        {\n            switch (shape.ShapeType)\n            {\n                case ShapeType.Circle:\n                    {\n                        CircleShape circle = (CircleShape)shape;\n                        Vertices = new Vector2[1];\n                        Vertices[0] = circle.Position;\n                        Radius = circle.Radius;\n                    }\n                    break;\n\n                case ShapeType.Polygon:\n                    {\n                        PolygonShape polygon = (PolygonShape)shape;\n                        Vertices = new Vector2[polygon.Vertices.Count];\n\n                        for (int i = 0; i < polygon.Vertices.Count; i++)\n                        {\n                            Vertices[i] = polygon.Vertices[i];\n                        }\n\n                        Radius = polygon.Radius;\n                    }\n                    break;\n\n                case ShapeType.Chain:\n                    {\n\n                        ChainShape chain = (ChainShape)shape;\n                        Debug.Assert(0 <= index && index < chain.Vertices.Count);\n\n                        Vertices = new Vector2[2];\n                        Vertices[0] = chain.Vertices[index];\n                        Vertices[1] = index + 1 < chain.Vertices.Count ? chain.Vertices[index + 1] : chain.Vertices[0];\n\n                        Radius = chain.Radius;\n                    }\n                    break;\n\n                case ShapeType.Edge:\n                    {\n                        EdgeShape edge = (EdgeShape)shape;\n                        Vertices = new Vector2[2];\n                        Vertices[0] = edge.Vertex1;\n                        Vertices[1] = edge.Vertex2;\n                        Radius = edge.Radius;\n                    }\n                    break;\n\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n\n        /// <summary>\n        /// Get the supporting vertex index in the given direction.\n        /// </summary>\n        /// <param name=\"direction\">The direction.</param>\n        public int GetSupport(Vector2 direction)\n        {\n            int bestIndex = 0;\n            float bestValue = Vector2.Dot(Vertices[0], direction);\n            for (int i = 1; i < Vertices.Length; ++i)\n            {\n                float value = Vector2.Dot(Vertices[i], direction);\n                if (value > bestValue)\n                {\n                    bestIndex = i;\n                    bestValue = value;\n                }\n            }\n\n            return bestIndex;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Filtering/Category.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Collision.Filtering\n{\n    [Flags]\n    public enum Category\n    {\n        None = 0,\n        All = int.MaxValue,\n        Cat1 = 1,\n        Cat2 = 2,\n        Cat3 = 4,\n        Cat4 = 8,\n        Cat5 = 16,\n        Cat6 = 32,\n        Cat7 = 64,\n        Cat8 = 128,\n        Cat9 = 256,\n        Cat10 = 512,\n        Cat11 = 1024,\n        Cat12 = 2048,\n        Cat13 = 4096,\n        Cat14 = 8192,\n        Cat15 = 16384,\n        Cat16 = 32768,\n        Cat17 = 65536,\n        Cat18 = 131072,\n        Cat19 = 262144,\n        Cat20 = 524288,\n        Cat21 = 1048576,\n        Cat22 = 2097152,\n        Cat23 = 4194304,\n        Cat24 = 8388608,\n        Cat25 = 16777216,\n        Cat26 = 33554432,\n        Cat27 = 67108864,\n        Cat28 = 134217728,\n        Cat29 = 268435456,\n        Cat30 = 536870912,\n        Cat31 = 1073741824\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Filtering/Filter.cs",
    "content": "﻿namespace VelcroPhysics.Collision.Filtering\n{\n    public class Filter\n    {\n        public Filter(short group, Category category, Category mask)\n        {\n            Group = group;\n            Category = category;\n            CategoryMask = mask;\n        }\n\n        /// <summary>\n        /// Defaults to 0\n        /// If Settings.UseFPECollisionCategories is set to false:\n        /// Collision groups allow a certain group of objects to never collide (negative)\n        /// or always collide (positive). Zero means no collision group. Non-zero group\n        /// filtering always wins against the mask bits.\n        /// If Settings.UseFPECollisionCategories is set to true:\n        /// If 2 fixtures are in the same collision group, they will not collide.\n        /// </summary>\n        public short Group { get; set; }\n\n        /// <summary>\n        /// Defaults to Category.All\n        /// The collision mask bits. This states the categories that this\n        /// fixture would accept for collision.\n        /// Use Settings.UseFPECollisionCategories to change the behavior.\n        /// </summary>\n        public Category Category { get; set; }\n\n        /// <summary>\n        /// The collision categories this fixture is a part of.\n        /// If Settings.UseFPECollisionCategories is set to false:\n        /// Defaults to Category.Cat1\n        /// If Settings.UseFPECollisionCategories is set to true:\n        /// Defaults to Category.All\n        /// </summary>\n        public Category CategoryMask { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/AfterCollisionHandler.cs",
    "content": "using VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Solver;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate void AfterCollisionHandler(Fixture fixtureA, Fixture fixtureB, Contact contact, ContactVelocityConstraint impulse);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/BeforeCollisionHandler.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate bool BeforeCollisionHandler(Fixture fixtureA, Fixture fixtureB);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/BeginContactHandler.cs",
    "content": "﻿using VelcroPhysics.Collision.ContactSystem;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    /// <summary>\n    /// This delegate is called when a contact is created\n    /// </summary>\n    public delegate bool BeginContactHandler(Contact contact);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/BroadphaseHandler.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate void BroadphaseHandler(ref FixtureProxy proxyA, ref FixtureProxy proxyB);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/CollisionFilterHandler.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate bool CollisionFilterHandler(Fixture fixtureA, Fixture fixtureB);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/EndContactHandler.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing VelcroPhysics.Collision.ContactSystem;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    /// <summary>\n    /// This delegate is called when a contact is deleted\n    /// </summary>\n    public delegate void EndContactHandler(Contact contact);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/OnCollisionHandler.cs",
    "content": "using VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate void OnCollisionHandler(Fixture fixtureA, Fixture fixtureB, Contact contact);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Handlers/OnSeparationHandler.cs",
    "content": "using VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Collision.Handlers\n{\n    public delegate void OnSeparationHandler(Fixture fixtureA, Fixture fixtureB, Contact contact);\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/ClipVertex.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// Used for computing contact manifolds.\n    /// </summary>\n    internal struct ClipVertex\n    {\n        public ContactID ID;\n        public Vector2 V;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/CollideCircle.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    public static class CollideCircle\n    {\n        /// <summary>\n        /// Compute the collision manifold between two circles.\n        /// </summary>\n        public static void CollideCircles(ref Manifold manifold, CircleShape circleA, ref Transform xfA, CircleShape circleB, ref Transform xfB)\n        {\n            manifold.PointCount = 0;\n\n            Vector2 pA = MathUtils.Mul(ref xfA, circleA.Position);\n            Vector2 pB = MathUtils.Mul(ref xfB, circleB.Position);\n\n            Vector2 d = pB - pA;\n            float distSqr = Vector2.Dot(d, d);\n            float rA = circleA.Radius, rB = circleB.Radius;\n            float radius = rA + rB;\n            if (distSqr > radius * radius)\n            {\n                return;\n            }\n\n            manifold.Type = ManifoldType.Circles;\n            manifold.LocalPoint = circleA.Position;\n            manifold.LocalNormal = Vector2.Zero;\n            manifold.PointCount = 1;\n\n            ManifoldPoint p0 = manifold.Points[0];\n            p0.LocalPoint = circleB.Position;\n            p0.Id.Key = 0;\n            manifold.Points[0] = p0;\n        }\n\n        /// <summary>\n        /// Compute the collision manifold between a polygon and a circle.\n        /// </summary>\n        /// <param name=\"manifold\">The manifold.</param>\n        /// <param name=\"polygonA\">The polygon A.</param>\n        /// <param name=\"xfA\">The transform of A.</param>\n        /// <param name=\"circleB\">The circle B.</param>\n        /// <param name=\"xfB\">The transform of B.</param>\n        public static void CollidePolygonAndCircle(ref Manifold manifold, PolygonShape polygonA, ref Transform xfA, CircleShape circleB, ref Transform xfB)\n        {\n            manifold.PointCount = 0;\n\n            // Compute circle position in the frame of the polygon.\n            Vector2 c = MathUtils.Mul(ref xfB, circleB.Position);\n            Vector2 cLocal = MathUtils.MulT(ref xfA, c);\n\n            // Find the min separating edge.\n            int normalIndex = 0;\n            float separation = -Settings.MaxFloat;\n            float radius = polygonA.Radius + circleB.Radius;\n            int vertexCount = polygonA.Vertices.Count;\n            Vertices vertices = polygonA.Vertices;\n            Vertices normals = polygonA.Normals;\n\n            for (int i = 0; i < vertexCount; ++i)\n            {\n                float s = Vector2.Dot(normals[i], cLocal - vertices[i]);\n\n                if (s > radius)\n                {\n                    // Early out.\n                    return;\n                }\n\n                if (s > separation)\n                {\n                    separation = s;\n                    normalIndex = i;\n                }\n            }\n\n            // Vertices that subtend the incident face.\n            int vertIndex1 = normalIndex;\n            int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;\n            Vector2 v1 = vertices[vertIndex1];\n            Vector2 v2 = vertices[vertIndex2];\n\n            // If the center is inside the polygon ...\n            if (separation < Settings.Epsilon)\n            {\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.FaceA;\n                manifold.LocalNormal = normals[normalIndex];\n                manifold.LocalPoint = 0.5f * (v1 + v2);\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                manifold.Points.Value0.Id.Key = 0;\n                return;\n            }\n\n            // Compute barycentric coordinates\n            float u1 = Vector2.Dot(cLocal - v1, v2 - v1);\n            float u2 = Vector2.Dot(cLocal - v2, v1 - v2);\n\n            if (u1 <= 0.0f)\n            {\n                if (Vector2.DistanceSquared(cLocal, v1) > radius * radius)\n                {\n                    return;\n                }\n\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.FaceA;\n                manifold.LocalNormal = cLocal - v1;\n                manifold.LocalNormal.Normalize();\n                manifold.LocalPoint = v1;\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                manifold.Points.Value0.Id.Key = 0;\n            }\n            else if (u2 <= 0.0f)\n            {\n                if (Vector2.DistanceSquared(cLocal, v2) > radius * radius)\n                {\n                    return;\n                }\n\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.FaceA;\n                manifold.LocalNormal = cLocal - v2;\n                manifold.LocalNormal.Normalize();\n                manifold.LocalPoint = v2;\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                manifold.Points.Value0.Id.Key = 0;\n            }\n            else\n            {\n                Vector2 faceCenter = 0.5f * (v1 + v2);\n                float s = Vector2.Dot(cLocal - faceCenter, normals[vertIndex1]);\n                if (s > radius)\n                {\n                    return;\n                }\n\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.FaceA;\n                manifold.LocalNormal = normals[vertIndex1];\n                manifold.LocalPoint = faceCenter;\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                manifold.Points.Value0.Id.Key = 0;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/CollideEdge.cs",
    "content": "﻿using System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    public static class CollideEdge\n    {\n        /// <summary>\n        /// Compute contact points for edge versus circle.\n        /// This accounts for edge connectivity.\n        /// </summary>\n        /// <param name=\"manifold\">The manifold.</param>\n        /// <param name=\"edgeA\">The edge A.</param>\n        /// <param name=\"transformA\">The transform A.</param>\n        /// <param name=\"circleB\">The circle B.</param>\n        /// <param name=\"transformB\">The transform B.</param>\n        public static void CollideEdgeAndCircle(ref Manifold manifold, EdgeShape edgeA, ref Transform transformA, CircleShape circleB, ref Transform transformB)\n        {\n            manifold.PointCount = 0;\n\n            // Compute circle in frame of edge\n            Vector2 Q = MathUtils.MulT(ref transformA, MathUtils.Mul(ref transformB, ref circleB._position));\n\n            Vector2 A = edgeA.Vertex1, B = edgeA.Vertex2;\n            Vector2 e = B - A;\n\n            // Barycentric coordinates\n            float u = Vector2.Dot(e, B - Q);\n            float v = Vector2.Dot(e, Q - A);\n\n            float radius = edgeA.Radius + circleB.Radius;\n\n            ContactFeature cf;\n            cf.IndexB = 0;\n            cf.TypeB = ContactFeatureType.Vertex;\n\n            // Region A\n            if (v <= 0.0f)\n            {\n                Vector2 P1 = A;\n                Vector2 d1 = Q - P1;\n                float dd1 = Vector2.Dot(d1, d1);\n                if (dd1 > radius * radius)\n                {\n                    return;\n                }\n\n                // Is there an edge connected to A?\n                if (edgeA.HasVertex0)\n                {\n                    Vector2 A1 = edgeA.Vertex0;\n                    Vector2 B1 = A;\n                    Vector2 e1 = B1 - A1;\n                    float u1 = Vector2.Dot(e1, B1 - Q);\n\n                    // Is the circle in Region AB of the previous edge?\n                    if (u1 > 0.0f)\n                    {\n                        return;\n                    }\n                }\n\n                cf.IndexA = 0;\n                cf.TypeA = ContactFeatureType.Vertex;\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.Circles;\n                manifold.LocalNormal = Vector2.Zero;\n                manifold.LocalPoint = P1;\n                manifold.Points.Value0.Id.Key = 0;\n                manifold.Points.Value0.Id.ContactFeature = cf;\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                return;\n            }\n\n            // Region B\n            if (u <= 0.0f)\n            {\n                Vector2 P2 = B;\n                Vector2 d2 = Q - P2;\n                float dd2 = Vector2.Dot(d2, d2);\n                if (dd2 > radius * radius)\n                {\n                    return;\n                }\n\n                // Is there an edge connected to B?\n                if (edgeA.HasVertex3)\n                {\n                    Vector2 B2 = edgeA.Vertex3;\n                    Vector2 A2 = B;\n                    Vector2 e2 = B2 - A2;\n                    float v2 = Vector2.Dot(e2, Q - A2);\n\n                    // Is the circle in Region AB of the next edge?\n                    if (v2 > 0.0f)\n                    {\n                        return;\n                    }\n                }\n\n                cf.IndexA = 1;\n                cf.TypeA = (byte)ContactFeatureType.Vertex;\n                manifold.PointCount = 1;\n                manifold.Type = ManifoldType.Circles;\n                manifold.LocalNormal = Vector2.Zero;\n                manifold.LocalPoint = P2;\n                manifold.Points.Value0.Id.Key = 0;\n                manifold.Points.Value0.Id.ContactFeature = cf;\n                manifold.Points.Value0.LocalPoint = circleB.Position;\n                return;\n            }\n\n            // Region AB\n            float den = Vector2.Dot(e, e);\n            Debug.Assert(den > 0.0f);\n            Vector2 P = (1.0f / den) * (u * A + v * B);\n            Vector2 d = Q - P;\n            float dd = Vector2.Dot(d, d);\n            if (dd > radius * radius)\n            {\n                return;\n            }\n\n            Vector2 n = new Vector2(-e.Y, e.X);\n            if (Vector2.Dot(n, Q - A) < 0.0f)\n            {\n                n = new Vector2(-n.X, -n.Y);\n            }\n            n.Normalize();\n\n            cf.IndexA = 0;\n            cf.TypeA = ContactFeatureType.Face;\n            manifold.PointCount = 1;\n            manifold.Type = ManifoldType.FaceA;\n            manifold.LocalNormal = n;\n            manifold.LocalPoint = A;\n            manifold.Points.Value0.Id.Key = 0;\n            manifold.Points.Value0.Id.ContactFeature = cf;\n            manifold.Points.Value0.LocalPoint = circleB.Position;\n        }\n\n        /// <summary>\n        /// Collides and edge and a polygon, taking into account edge adjacency.\n        /// </summary>\n        public static void CollideEdgeAndPolygon(ref Manifold manifold, EdgeShape edgeA, ref Transform xfA, PolygonShape polygonB, ref Transform xfB)\n        {\n            EPCollider.Collide(ref manifold, edgeA, ref xfA, polygonB, ref xfB);\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/CollidePolygon.cs",
    "content": "﻿using System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    public static class CollidePolygon\n    {\n        /// <summary>\n        /// Compute the collision manifold between two polygons.\n        /// </summary>\n        public static void CollidePolygons(ref Manifold manifold, PolygonShape polyA, ref Transform xfA, PolygonShape polyB, ref Transform xfB)\n        {\n            // Find edge normal of max separation on A - return if separating axis is found\n            // Find edge normal of max separation on B - return if separation axis is found\n            // Choose reference edge as min(minA, minB)\n            // Find incident edge\n            // Clip\n\n            manifold.PointCount = 0;\n            float totalRadius = polyA.Radius + polyB.Radius;\n\n            int edgeA;\n            float separationA = FindMaxSeparation(out edgeA, polyA, ref xfA, polyB, ref xfB);\n            if (separationA > totalRadius)\n                return;\n\n            int edgeB;\n            float separationB = FindMaxSeparation(out edgeB, polyB, ref xfB, polyA, ref xfA);\n            if (separationB > totalRadius)\n                return;\n\n            PolygonShape poly1; // reference polygon\n            PolygonShape poly2; // incident polygon\n            Transform xf1, xf2;\n            int edge1; // reference edge\n            bool flip;\n            const float k_tol = 0.1f * Settings.LinearSlop;\n\n            if (separationB > separationA + k_tol)\n            {\n                poly1 = polyB;\n                poly2 = polyA;\n                xf1 = xfB;\n                xf2 = xfA;\n                edge1 = edgeB;\n                manifold.Type = ManifoldType.FaceB;\n                flip = true;\n            }\n            else\n            {\n                poly1 = polyA;\n                poly2 = polyB;\n                xf1 = xfA;\n                xf2 = xfB;\n                edge1 = edgeA;\n                manifold.Type = ManifoldType.FaceA;\n                flip = false;\n            }\n\n            FixedArray2<ClipVertex> incidentEdge;\n            FindIncidentEdge(out incidentEdge, poly1, ref xf1, edge1, poly2, ref xf2);\n\n            int count1 = poly1.Vertices.Count;\n            Vertices vertices1 = poly1.Vertices;\n\n            int iv1 = edge1;\n            int iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;\n\n            Vector2 v11 = vertices1[iv1];\n            Vector2 v12 = vertices1[iv2];\n\n            Vector2 localTangent = v12 - v11;\n            localTangent.Normalize();\n\n            Vector2 localNormal = MathUtils.Cross(localTangent, 1.0f);\n            Vector2 planePoint = 0.5f * (v11 + v12);\n\n            Vector2 tangent = MathUtils.Mul(ref xf1.q, localTangent);\n            Vector2 normal = MathUtils.Cross(tangent, 1.0f);\n\n            v11 = MathUtils.Mul(ref xf1, v11);\n            v12 = MathUtils.Mul(ref xf1, v12);\n\n            // Face offset.\n            float frontOffset = Vector2.Dot(normal, v11);\n\n            // Side offsets, extended by polytope skin thickness.\n            float sideOffset1 = -Vector2.Dot(tangent, v11) + totalRadius;\n            float sideOffset2 = Vector2.Dot(tangent, v12) + totalRadius;\n\n            // Clip incident edge against extruded edge1 side edges.\n            FixedArray2<ClipVertex> clipPoints1;\n            FixedArray2<ClipVertex> clipPoints2;\n\n            // Clip to box side 1\n            int np = Collision.ClipSegmentToLine(out clipPoints1, ref incidentEdge, -tangent, sideOffset1, iv1);\n\n            if (np < 2)\n                return;\n\n            // Clip to negative box side 1\n            np = Collision.ClipSegmentToLine(out clipPoints2, ref clipPoints1, tangent, sideOffset2, iv2);\n\n            if (np < 2)\n            {\n                return;\n            }\n\n            // Now clipPoints2 contains the clipped points.\n            manifold.LocalNormal = localNormal;\n            manifold.LocalPoint = planePoint;\n\n            int pointCount = 0;\n            for (int i = 0; i < Settings.MaxManifoldPoints; ++i)\n            {\n                float separation = Vector2.Dot(normal, clipPoints2[i].V) - frontOffset;\n\n                if (separation <= totalRadius)\n                {\n                    ManifoldPoint cp = manifold.Points[pointCount];\n                    cp.LocalPoint = MathUtils.MulT(ref xf2, clipPoints2[i].V);\n                    cp.Id = clipPoints2[i].ID;\n\n                    if (flip)\n                    {\n                        // Swap features\n                        ContactFeature cf = cp.Id.ContactFeature;\n                        cp.Id.ContactFeature.IndexA = cf.IndexB;\n                        cp.Id.ContactFeature.IndexB = cf.IndexA;\n                        cp.Id.ContactFeature.TypeA = cf.TypeB;\n                        cp.Id.ContactFeature.TypeB = cf.TypeA;\n                    }\n\n                    manifold.Points[pointCount] = cp;\n\n                    ++pointCount;\n                }\n            }\n\n            manifold.PointCount = pointCount;\n        }\n\n        /// <summary>\n        /// Find the max separation between poly1 and poly2 using edge normals from poly1.\n        /// </summary>\n        private static float FindMaxSeparation(out int edgeIndex, PolygonShape poly1, ref Transform xf1, PolygonShape poly2, ref Transform xf2)\n        {\n            int count1 = poly1.Vertices.Count;\n            int count2 = poly2.Vertices.Count;\n            Vertices n1s = poly1.Normals;\n            Vertices v1s = poly1.Vertices;\n            Vertices v2s = poly2.Vertices;\n            Transform xf = MathUtils.MulT(xf2, xf1);\n\n            int bestIndex = 0;\n            float maxSeparation = -Settings.MaxFloat;\n            for (int i = 0; i < count1; ++i)\n            {\n                // Get poly1 normal in frame2.\n                Vector2 n = MathUtils.Mul(ref xf.q, n1s[i]);\n                Vector2 v1 = MathUtils.Mul(ref xf, v1s[i]);\n\n                // Find deepest point for normal i.\n                float si = Settings.MaxFloat;\n                for (int j = 0; j < count2; ++j)\n                {\n                    float sij = Vector2.Dot(n, v2s[j] - v1);\n                    if (sij < si)\n                    {\n                        si = sij;\n                    }\n                }\n\n                if (si > maxSeparation)\n                {\n                    maxSeparation = si;\n                    bestIndex = i;\n                }\n            }\n\n            edgeIndex = bestIndex;\n            return maxSeparation;\n        }\n\n        private static void FindIncidentEdge(out FixedArray2<ClipVertex> c, PolygonShape poly1, ref Transform xf1, int edge1, PolygonShape poly2, ref Transform xf2)\n        {\n            Vertices normals1 = poly1.Normals;\n\n            int count2 = poly2.Vertices.Count;\n            Vertices vertices2 = poly2.Vertices;\n            Vertices normals2 = poly2.Normals;\n\n            Debug.Assert(0 <= edge1 && edge1 < poly1.Vertices.Count);\n\n            // Get the normal of the reference edge in poly2's frame.\n            Vector2 normal1 = MathUtils.MulT(ref xf2.q, MathUtils.Mul(ref xf1.q, normals1[edge1]));\n\n            // Find the incident edge on poly2.\n            int index = 0;\n            float minDot = Settings.MaxFloat;\n            for (int i = 0; i < count2; ++i)\n            {\n                float dot = Vector2.Dot(normal1, normals2[i]);\n                if (dot < minDot)\n                {\n                    minDot = dot;\n                    index = i;\n                }\n            }\n\n            // Build the clip vertices for the incident edge.\n            int i1 = index;\n            int i2 = i1 + 1 < count2 ? i1 + 1 : 0;\n\n            c = new FixedArray2<ClipVertex>();\n            c.Value0.V = MathUtils.Mul(ref xf2, vertices2[i1]);\n            c.Value0.ID.ContactFeature.IndexA = (byte)edge1;\n            c.Value0.ID.ContactFeature.IndexB = (byte)i1;\n            c.Value0.ID.ContactFeature.TypeA = ContactFeatureType.Face;\n            c.Value0.ID.ContactFeature.TypeB = ContactFeatureType.Vertex;\n\n            c.Value1.V = MathUtils.Mul(ref xf2, vertices2[i2]);\n            c.Value1.ID.ContactFeature.IndexA = (byte)edge1;\n            c.Value1.ID.ContactFeature.IndexB = (byte)i2;\n            c.Value1.ID.ContactFeature.TypeA = ContactFeatureType.Face;\n            c.Value1.ID.ContactFeature.TypeB = ContactFeatureType.Vertex;\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/Collision.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Distance;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// Collision methods\n    /// </summary>\n    public static class Collision\n    {\n        /// <summary>\n        /// Test overlap between the two shapes.\n        /// </summary>\n        /// <param name=\"shapeA\">The first shape.</param>\n        /// <param name=\"indexA\">The index for the first shape.</param>\n        /// <param name=\"shapeB\">The second shape.</param>\n        /// <param name=\"indexB\">The index for the second shape.</param>\n        /// <param name=\"xfA\">The transform for the first shape.</param>\n        /// <param name=\"xfB\">The transform for the seconds shape.</param>\n        /// <returns></returns>\n        public static bool TestOverlap(Shape shapeA, int indexA, Shape shapeB, int indexB, ref Transform xfA, ref Transform xfB)\n        {\n            DistanceInput input = new DistanceInput();\n            input.ProxyA = new DistanceProxy(shapeA, indexA);\n            input.ProxyB = new DistanceProxy(shapeB, indexB);\n            input.TransformA = xfA;\n            input.TransformB = xfB;\n            input.UseRadii = true;\n\n            SimplexCache cache;\n            DistanceOutput output;\n            DistanceGJK.ComputeDistance(ref input, out output, out cache);\n\n            return output.Distance < 10.0f * Settings.Epsilon;\n        }\n\n        public static void GetPointStates(out FixedArray2<PointState> state1, out FixedArray2<PointState> state2, ref Manifold manifold1, ref Manifold manifold2)\n        {\n            state1 = new FixedArray2<PointState>();\n            state2 = new FixedArray2<PointState>();\n\n            for (int i = 0; i < Settings.MaxManifoldPoints; ++i)\n            {\n                state1[i] = PointState.Null;\n                state2[i] = PointState.Null;\n            }\n\n            // Detect persists and removes.\n            for (int i = 0; i < manifold1.PointCount; ++i)\n            {\n                ContactID id = manifold1.Points[i].Id;\n\n                state1[i] = PointState.Remove;\n\n                for (int j = 0; j < manifold2.PointCount; ++j)\n                {\n                    if (manifold2.Points[j].Id.Key == id.Key)\n                    {\n                        state1[i] = PointState.Persist;\n                        break;\n                    }\n                }\n            }\n\n            // Detect persists and adds.\n            for (int i = 0; i < manifold2.PointCount; ++i)\n            {\n                ContactID id = manifold2.Points[i].Id;\n\n                state2[i] = PointState.Add;\n\n                for (int j = 0; j < manifold1.PointCount; ++j)\n                {\n                    if (manifold1.Points[j].Id.Key == id.Key)\n                    {\n                        state2[i] = PointState.Persist;\n                        break;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Clipping for contact manifolds.\n        /// </summary>\n        /// <param name=\"vOut\">The v out.</param>\n        /// <param name=\"vIn\">The v in.</param>\n        /// <param name=\"normal\">The normal.</param>\n        /// <param name=\"offset\">The offset.</param>\n        /// <param name=\"vertexIndexA\">The vertex index A.</param>\n        /// <returns></returns>\n        internal static int ClipSegmentToLine(out FixedArray2<ClipVertex> vOut, ref FixedArray2<ClipVertex> vIn, Vector2 normal, float offset, int vertexIndexA)\n        {\n            vOut = new FixedArray2<ClipVertex>();\n\n            // Start with no output points\n            int numOut = 0;\n\n            // Calculate the distance of end points to the line\n            float distance0 = Vector2.Dot(normal, vIn.Value0.V) - offset;\n            float distance1 = Vector2.Dot(normal, vIn.Value1.V) - offset;\n\n            // If the points are behind the plane\n            if (distance0 <= 0.0f) vOut[numOut++] = vIn.Value0;\n            if (distance1 <= 0.0f) vOut[numOut++] = vIn.Value1;\n\n            // If the points are on different sides of the plane\n            if (distance0 * distance1 < 0.0f)\n            {\n                // Find intersection point of edge and plane\n                float interp = distance0 / (distance0 - distance1);\n\n                ClipVertex cv = vOut[numOut];\n                cv.V = vIn.Value0.V + interp * (vIn.Value1.V - vIn.Value0.V);\n\n                // VertexA is hitting edgeB.\n                cv.ID.ContactFeature.IndexA = (byte)vertexIndexA;\n                cv.ID.ContactFeature.IndexB = vIn.Value0.ID.ContactFeature.IndexB;\n                cv.ID.ContactFeature.TypeA = ContactFeatureType.Vertex;\n                cv.ID.ContactFeature.TypeB = ContactFeatureType.Face;\n                vOut[numOut] = cv;\n\n                ++numOut;\n            }\n\n            return numOut;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/EPAxis.cs",
    "content": "namespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// This structure is used to keep track of the best separating axis.\n    /// </summary>\n    public struct EPAxis\n    {\n        public int Index;\n        public float Separation;\n        public EPAxisType Type;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/EPAxisType.cs",
    "content": "namespace VelcroPhysics.Collision.Narrowphase\n{\n    public enum EPAxisType\n    {\n        Unknown,\n        EdgeA,\n        EdgeB\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/EPCollider.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    public static class EPCollider\n    {\n        public static void Collide(ref Manifold manifold, EdgeShape edgeA, ref Transform xfA, PolygonShape polygonB, ref Transform xfB)\n        {\n            // Algorithm:\n            // 1. Classify v1 and v2\n            // 2. Classify polygon centroid as front or back\n            // 3. Flip normal if necessary\n            // 4. Initialize normal range to [-pi, pi] about face normal\n            // 5. Adjust normal range according to adjacent edges\n            // 6. Visit each separating axes, only accept axes within the range\n            // 7. Return if _any_ axis indicates separation\n            // 8. Clip\n            bool front;\n            Vector2 lowerLimit, upperLimit;\n            Vector2 normal;\n            Vector2 normal0 = Vector2.Zero;\n            Vector2 normal2 = Vector2.Zero;\n\n            Transform xf = MathUtils.MulT(xfA, xfB);\n\n            Vector2 centroidB = MathUtils.Mul(ref xf, polygonB.MassData.Centroid);\n\n            Vector2 v0 = edgeA.Vertex0;\n            Vector2 v1 = edgeA._vertex1;\n            Vector2 v2 = edgeA._vertex2;\n            Vector2 v3 = edgeA.Vertex3;\n\n            bool hasVertex0 = edgeA.HasVertex0;\n            bool hasVertex3 = edgeA.HasVertex3;\n\n            Vector2 edge1 = v2 - v1;\n            edge1.Normalize();\n            Vector2 normal1 = new Vector2(edge1.Y, -edge1.X);\n            float offset1 = Vector2.Dot(normal1, centroidB - v1);\n            float offset0 = 0.0f, offset2 = 0.0f;\n            bool convex1 = false, convex2 = false;\n\n            // Is there a preceding edge?\n            if (hasVertex0)\n            {\n                Vector2 edge0 = v1 - v0;\n                edge0.Normalize();\n                normal0 = new Vector2(edge0.Y, -edge0.X);\n                convex1 = MathUtils.Cross(edge0, edge1) >= 0.0f;\n                offset0 = Vector2.Dot(normal0, centroidB - v0);\n            }\n\n            // Is there a following edge?\n            if (hasVertex3)\n            {\n                Vector2 edge2 = v3 - v2;\n                edge2.Normalize();\n                normal2 = new Vector2(edge2.Y, -edge2.X);\n                convex2 = MathUtils.Cross(edge1, edge2) > 0.0f;\n                offset2 = Vector2.Dot(normal2, centroidB - v2);\n            }\n\n            // Determine front or back collision. Determine collision normal limits.\n            if (hasVertex0 && hasVertex3)\n            {\n                if (convex1 && convex2)\n                {\n                    front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal0;\n                        upperLimit = normal2;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal1;\n                        upperLimit = -normal1;\n                    }\n                }\n                else if (convex1)\n                {\n                    front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal0;\n                        upperLimit = normal1;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal2;\n                        upperLimit = -normal1;\n                    }\n                }\n                else if (convex2)\n                {\n                    front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal1;\n                        upperLimit = normal2;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal1;\n                        upperLimit = -normal0;\n                    }\n                }\n                else\n                {\n                    front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal1;\n                        upperLimit = normal1;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal2;\n                        upperLimit = -normal0;\n                    }\n                }\n            }\n            else if (hasVertex0)\n            {\n                if (convex1)\n                {\n                    front = offset0 >= 0.0f || offset1 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal0;\n                        upperLimit = -normal1;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = normal1;\n                        upperLimit = -normal1;\n                    }\n                }\n                else\n                {\n                    front = offset0 >= 0.0f && offset1 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = normal1;\n                        upperLimit = -normal1;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = normal1;\n                        upperLimit = -normal0;\n                    }\n                }\n            }\n            else if (hasVertex3)\n            {\n                if (convex2)\n                {\n                    front = offset1 >= 0.0f || offset2 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = -normal1;\n                        upperLimit = normal2;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal1;\n                        upperLimit = normal1;\n                    }\n                }\n                else\n                {\n                    front = offset1 >= 0.0f && offset2 >= 0.0f;\n                    if (front)\n                    {\n                        normal = normal1;\n                        lowerLimit = -normal1;\n                        upperLimit = normal1;\n                    }\n                    else\n                    {\n                        normal = -normal1;\n                        lowerLimit = -normal2;\n                        upperLimit = normal1;\n                    }\n                }\n            }\n            else\n            {\n                front = offset1 >= 0.0f;\n                if (front)\n                {\n                    normal = normal1;\n                    lowerLimit = -normal1;\n                    upperLimit = -normal1;\n                }\n                else\n                {\n                    normal = -normal1;\n                    lowerLimit = normal1;\n                    upperLimit = normal1;\n                }\n            }\n\n            // Get polygonB in frameA\n            Vector2[] normals = new Vector2[Settings.MaxPolygonVertices];\n            Vector2[] vertices = new Vector2[Settings.MaxPolygonVertices];\n            int count = polygonB.Vertices.Count;\n            for (int i = 0; i < polygonB.Vertices.Count; ++i)\n            {\n                vertices[i] = MathUtils.Mul(ref xf, polygonB.Vertices[i]);\n                normals[i] = MathUtils.Mul(xf.q, polygonB.Normals[i]);\n            }\n\n            float radius = polygonB.Radius + edgeA.Radius;\n\n            manifold.PointCount = 0;\n\n            //Velcro: ComputeEdgeSeparation() was manually inlined here\n            EPAxis edgeAxis;\n            edgeAxis.Type = EPAxisType.EdgeA;\n            edgeAxis.Index = front ? 0 : 1;\n            edgeAxis.Separation = Settings.MaxFloat;\n\n            for (int i = 0; i < count; ++i)\n            {\n                float s = Vector2.Dot(normal, vertices[i] - v1);\n                if (s < edgeAxis.Separation)\n                {\n                    edgeAxis.Separation = s;\n                }\n            }\n\n            // If no valid normal can be found than this edge should not collide.\n            if (edgeAxis.Type == EPAxisType.Unknown)\n            {\n                return;\n            }\n\n            if (edgeAxis.Separation > radius)\n            {\n                return;\n            }\n\n            //Velcro: ComputePolygonSeparation() was manually inlined here\n            EPAxis polygonAxis;\n            polygonAxis.Type = EPAxisType.Unknown;\n            polygonAxis.Index = -1;\n            polygonAxis.Separation = -Settings.MaxFloat;\n\n            Vector2 perp = new Vector2(-normal.Y, normal.X);\n\n            for (int i = 0; i < count; ++i)\n            {\n                Vector2 n = -normals[i];\n\n                float s1 = Vector2.Dot(n, vertices[i] - v1);\n                float s2 = Vector2.Dot(n, vertices[i] - v2);\n                float s = Math.Min(s1, s2);\n\n                if (s > radius)\n                {\n                    // No collision\n                    polygonAxis.Type = EPAxisType.EdgeB;\n                    polygonAxis.Index = i;\n                    polygonAxis.Separation = s;\n                    break;\n                }\n\n                // Adjacency\n                if (Vector2.Dot(n, perp) >= 0.0f)\n                {\n                    if (Vector2.Dot(n - upperLimit, normal) < -Settings.AngularSlop)\n                    {\n                        continue;\n                    }\n                }\n                else\n                {\n                    if (Vector2.Dot(n - lowerLimit, normal) < -Settings.AngularSlop)\n                    {\n                        continue;\n                    }\n                }\n\n                if (s > polygonAxis.Separation)\n                {\n                    polygonAxis.Type = EPAxisType.EdgeB;\n                    polygonAxis.Index = i;\n                    polygonAxis.Separation = s;\n                }\n            }\n\n            if (polygonAxis.Type != EPAxisType.Unknown && polygonAxis.Separation > radius)\n            {\n                return;\n            }\n\n            // Use hysteresis for jitter reduction.\n            const float k_relativeTol = 0.98f;\n            const float k_absoluteTol = 0.001f;\n\n            EPAxis primaryAxis;\n            if (polygonAxis.Type == EPAxisType.Unknown)\n            {\n                primaryAxis = edgeAxis;\n            }\n            else if (polygonAxis.Separation > k_relativeTol * edgeAxis.Separation + k_absoluteTol)\n            {\n                primaryAxis = polygonAxis;\n            }\n            else\n            {\n                primaryAxis = edgeAxis;\n            }\n\n            FixedArray2<ClipVertex> ie = new FixedArray2<ClipVertex>();\n            ReferenceFace rf;\n            if (primaryAxis.Type == EPAxisType.EdgeA)\n            {\n                manifold.Type = ManifoldType.FaceA;\n\n                // Search for the polygon normal that is most anti-parallel to the edge normal.\n                int bestIndex = 0;\n                float bestValue = Vector2.Dot(normal, normals[0]);\n                for (int i = 1; i < count; ++i)\n                {\n                    float value = Vector2.Dot(normal, normals[i]);\n                    if (value < bestValue)\n                    {\n                        bestValue = value;\n                        bestIndex = i;\n                    }\n                }\n\n                int i1 = bestIndex;\n                int i2 = i1 + 1 < count ? i1 + 1 : 0;\n\n                ie.Value0.V = vertices[i1];\n                ie.Value0.ID.ContactFeature.IndexA = 0;\n                ie.Value0.ID.ContactFeature.IndexB = (byte)i1;\n                ie.Value0.ID.ContactFeature.TypeA = ContactFeatureType.Face;\n                ie.Value0.ID.ContactFeature.TypeB = ContactFeatureType.Vertex;\n\n                ie.Value1.V = vertices[i2];\n                ie.Value1.ID.ContactFeature.IndexA = 0;\n                ie.Value1.ID.ContactFeature.IndexB = (byte)i2;\n                ie.Value1.ID.ContactFeature.TypeA = ContactFeatureType.Face;\n                ie.Value1.ID.ContactFeature.TypeB = ContactFeatureType.Vertex;\n\n                if (front)\n                {\n                    rf.i1 = 0;\n                    rf.i2 = 1;\n                    rf.v1 = v1;\n                    rf.v2 = v2;\n                    rf.Normal = normal1;\n                }\n                else\n                {\n                    rf.i1 = 1;\n                    rf.i2 = 0;\n                    rf.v1 = v2;\n                    rf.v2 = v1;\n                    rf.Normal = -normal1;\n                }\n            }\n            else\n            {\n                manifold.Type = ManifoldType.FaceB;\n\n                ie.Value0.V = v1;\n                ie.Value0.ID.ContactFeature.IndexA = 0;\n                ie.Value0.ID.ContactFeature.IndexB = (byte)primaryAxis.Index;\n                ie.Value0.ID.ContactFeature.TypeA = ContactFeatureType.Vertex;\n                ie.Value0.ID.ContactFeature.TypeB = ContactFeatureType.Face;\n\n                ie.Value1.V = v2;\n                ie.Value1.ID.ContactFeature.IndexA = 0;\n                ie.Value1.ID.ContactFeature.IndexB = (byte)primaryAxis.Index;\n                ie.Value1.ID.ContactFeature.TypeA = ContactFeatureType.Vertex;\n                ie.Value1.ID.ContactFeature.TypeB = ContactFeatureType.Face;\n\n                rf.i1 = primaryAxis.Index;\n                rf.i2 = rf.i1 + 1 < count ? rf.i1 + 1 : 0;\n                rf.v1 = vertices[rf.i1];\n                rf.v2 = vertices[rf.i2];\n                rf.Normal = normals[rf.i1];\n            }\n\n            rf.SideNormal1 = new Vector2(rf.Normal.Y, -rf.Normal.X);\n            rf.SideNormal2 = -rf.SideNormal1;\n            rf.SideOffset1 = Vector2.Dot(rf.SideNormal1, rf.v1);\n            rf.SideOffset2 = Vector2.Dot(rf.SideNormal2, rf.v2);\n\n            // Clip incident edge against extruded edge1 side edges.\n            FixedArray2<ClipVertex> clipPoints1;\n            FixedArray2<ClipVertex> clipPoints2;\n            int np;\n\n            // Clip to box side 1\n            np = Collision.ClipSegmentToLine(out clipPoints1, ref ie, rf.SideNormal1, rf.SideOffset1, rf.i1);\n\n            if (np < Settings.MaxManifoldPoints)\n            {\n                return;\n            }\n\n            // Clip to negative box side 1\n            np = Collision.ClipSegmentToLine(out clipPoints2, ref clipPoints1, rf.SideNormal2, rf.SideOffset2, rf.i2);\n\n            if (np < Settings.MaxManifoldPoints)\n            {\n                return;\n            }\n\n            // Now clipPoints2 contains the clipped points.\n            if (primaryAxis.Type == EPAxisType.EdgeA)\n            {\n                manifold.LocalNormal = rf.Normal;\n                manifold.LocalPoint = rf.v1;\n            }\n            else\n            {\n                manifold.LocalNormal = polygonB.Normals[rf.i1];\n                manifold.LocalPoint = polygonB.Vertices[rf.i1];\n            }\n\n            int pointCount = 0;\n            for (int i = 0; i < Settings.MaxManifoldPoints; ++i)\n            {\n                float separation = Vector2.Dot(rf.Normal, clipPoints2[i].V - rf.v1);\n\n                if (separation <= radius)\n                {\n                    ManifoldPoint cp = manifold.Points[pointCount];\n\n                    if (primaryAxis.Type == EPAxisType.EdgeA)\n                    {\n                        cp.LocalPoint = MathUtils.MulT(ref xf, clipPoints2[i].V);\n                        cp.Id = clipPoints2[i].ID;\n                    }\n                    else\n                    {\n                        cp.LocalPoint = clipPoints2[i].V;\n                        cp.Id.ContactFeature.TypeA = clipPoints2[i].ID.ContactFeature.TypeB;\n                        cp.Id.ContactFeature.TypeB = clipPoints2[i].ID.ContactFeature.TypeA;\n                        cp.Id.ContactFeature.IndexA = clipPoints2[i].ID.ContactFeature.IndexB;\n                        cp.Id.ContactFeature.IndexB = clipPoints2[i].ID.ContactFeature.IndexA;\n                    }\n\n                    manifold.Points[pointCount] = cp;\n                    ++pointCount;\n                }\n            }\n\n            manifold.PointCount = pointCount;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/Manifold.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// A manifold for two touching convex Shapes.\n    /// Box2D supports multiple types of contact:\n    /// - Clip point versus plane with radius\n    /// - Point versus point with radius (circles)\n    /// The local point usage depends on the manifold type:\n    /// - ShapeType.Circles: the local center of circleA\n    /// - SeparationFunction.FaceA: the center of faceA\n    /// - SeparationFunction.FaceB: the center of faceB\n    /// Similarly the local normal usage:\n    /// - ShapeType.Circles: not used\n    /// - SeparationFunction.FaceA: the normal on polygonA\n    /// - SeparationFunction.FaceB: the normal on polygonB\n    /// We store contacts in this way so that position correction can\n    /// account for movement, which is critical for continuous physics.\n    /// All contact scenarios must be expressed in one of these types.\n    /// This structure is stored across time steps, so we keep it small.\n    /// </summary>\n    public struct Manifold\n    {\n        /// <summary>\n        /// Not use for Type.SeparationFunction.Points\n        /// </summary>\n        public Vector2 LocalNormal;\n\n        /// <summary>\n        /// Usage depends on manifold type\n        /// </summary>\n        public Vector2 LocalPoint;\n\n        /// <summary>\n        /// The number of manifold points\n        /// </summary>\n        public int PointCount;\n\n        /// <summary>\n        /// The points of contact\n        /// </summary>\n        public FixedArray2<ManifoldPoint> Points;\n\n        public ManifoldType Type;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/ManifoldPoint.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// A manifold point is a contact point belonging to a contact\n    /// manifold. It holds details related to the geometry and dynamics\n    /// of the contact points.\n    /// The local point usage depends on the manifold type:\n    /// -ShapeType.Circles: the local center of circleB\n    /// -SeparationFunction.FaceA: the local center of cirlceB or the clip point of polygonB\n    /// -SeparationFunction.FaceB: the clip point of polygonA\n    /// This structure is stored across time steps, so we keep it small.\n    /// Note: the impulses are used for internal caching and may not\n    /// provide reliable contact forces, especially for high speed collisions.\n    /// </summary>\n    public struct ManifoldPoint\n    {\n        /// <summary>\n        /// Uniquely identifies a contact point between two Shapes\n        /// </summary>\n        public ContactID Id;\n\n        /// <summary>\n        /// Usage depends on manifold type\n        /// </summary>\n        public Vector2 LocalPoint;\n\n        /// <summary>\n        /// The non-penetration impulse\n        /// </summary>\n        public float NormalImpulse;\n\n        /// <summary>\n        /// The friction impulse\n        /// </summary>\n        public float TangentImpulse;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/ManifoldType.cs",
    "content": "namespace VelcroPhysics.Collision.Narrowphase\n{\n    public enum ManifoldType\n    {\n        Circles,\n        FaceA,\n        FaceB\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/PointState.cs",
    "content": "namespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// This is used for determining the state of contact points.\n    /// </summary>\n    public enum PointState\n    {\n        /// <summary>\n        /// Point does not exist\n        /// </summary>\n        Null,\n\n        /// <summary>\n        /// Point was added in the update\n        /// </summary>\n        Add,\n\n        /// <summary>\n        /// Point persisted across the update\n        /// </summary>\n        Persist,\n\n        /// <summary>\n        /// Point was removed in the update\n        /// </summary>\n        Remove\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/ReferenceFace.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// Reference face used for clipping\n    /// </summary>\n    public struct ReferenceFace\n    {\n        public int i1, i2;\n\n        public Vector2 v1, v2;\n\n        public Vector2 Normal;\n\n        public Vector2 SideNormal1;\n        public float SideOffset1;\n\n        public Vector2 SideNormal2;\n        public float SideOffset2;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/Simplex.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Distance;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    internal struct Simplex\n    {\n        internal int Count;\n        internal FixedArray3<SimplexVertex> V;\n\n        internal void ReadCache(ref SimplexCache cache, ref DistanceProxy proxyA, ref Transform transformA, ref DistanceProxy proxyB, ref Transform transformB)\n        {\n            Debug.Assert(cache.Count <= 3);\n\n            // Copy data from cache.\n            Count = cache.Count;\n            for (int i = 0; i < Count; ++i)\n            {\n                SimplexVertex v = V[i];\n                v.IndexA = cache.IndexA[i];\n                v.IndexB = cache.IndexB[i];\n                Vector2 wALocal = proxyA.Vertices[v.IndexA];\n                Vector2 wBLocal = proxyB.Vertices[v.IndexB];\n                v.WA = MathUtils.Mul(ref transformA, wALocal);\n                v.WB = MathUtils.Mul(ref transformB, wBLocal);\n                v.W = v.WB - v.WA;\n                v.A = 0.0f;\n                V[i] = v;\n            }\n\n            // Compute the new simplex metric, if it is substantially different than\n            // old metric then flush the simplex.\n            if (Count > 1)\n            {\n                float metric1 = cache.Metric;\n                float metric2 = GetMetric();\n                if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < Settings.Epsilon)\n                {\n                    // Reset the simplex.\n                    Count = 0;\n                }\n            }\n\n            // If the cache is empty or invalid ...\n            if (Count == 0)\n            {\n                SimplexVertex v = V[0];\n                v.IndexA = 0;\n                v.IndexB = 0;\n                Vector2 wALocal = proxyA.Vertices[0];\n                Vector2 wBLocal = proxyB.Vertices[0];\n                v.WA = MathUtils.Mul(ref transformA, wALocal);\n                v.WB = MathUtils.Mul(ref transformB, wBLocal);\n                v.W = v.WB - v.WA;\n                v.A = 1.0f;\n                V[0] = v;\n                Count = 1;\n            }\n        }\n\n        internal void WriteCache(ref SimplexCache cache)\n        {\n            cache.Metric = GetMetric();\n            cache.Count = (ushort)Count;\n            for (int i = 0; i < Count; ++i)\n            {\n                cache.IndexA[i] = (byte)V[i].IndexA;\n                cache.IndexB[i] = (byte)V[i].IndexB;\n            }\n        }\n\n        internal Vector2 GetSearchDirection()\n        {\n            switch (Count)\n            {\n                case 1:\n                    return -V[0].W;\n\n                case 2:\n                    {\n                        Vector2 e12 = V[1].W - V[0].W;\n                        float sgn = MathUtils.Cross(e12, -V[0].W);\n                        if (sgn > 0.0f)\n                        {\n                            // Origin is left of e12.\n                            return MathUtils.Cross(1.0f, e12);\n                        }\n                        else\n                        {\n                            // Origin is right of e12.\n                            return MathUtils.Cross(e12, 1.0f);\n                        }\n                    }\n\n                default:\n                    Debug.Assert(false);\n                    return Vector2.Zero;\n            }\n        }\n\n        internal Vector2 GetClosestPoint()\n        {\n            switch (Count)\n            {\n                case 0:\n                    Debug.Assert(false);\n                    return Vector2.Zero;\n\n                case 1:\n                    return V[0].W;\n\n                case 2:\n                    return V[0].A * V[0].W + V[1].A * V[1].W;\n\n                case 3:\n                    return Vector2.Zero;\n\n                default:\n                    Debug.Assert(false);\n                    return Vector2.Zero;\n            }\n        }\n\n        internal void GetWitnessPoints(out Vector2 pA, out Vector2 pB)\n        {\n            switch (Count)\n            {\n                case 0:\n                    pA = Vector2.Zero;\n                    pB = Vector2.Zero;\n                    Debug.Assert(false);\n                    break;\n\n                case 1:\n                    pA = V[0].WA;\n                    pB = V[0].WB;\n                    break;\n\n                case 2:\n                    pA = V[0].A * V[0].WA + V[1].A * V[1].WA;\n                    pB = V[0].A * V[0].WB + V[1].A * V[1].WB;\n                    break;\n\n                case 3:\n                    pA = V[0].A * V[0].WA + V[1].A * V[1].WA + V[2].A * V[2].WA;\n                    pB = pA;\n                    break;\n\n                default:\n                    throw new Exception();\n            }\n        }\n\n        internal float GetMetric()\n        {\n            switch (Count)\n            {\n                case 0:\n                    Debug.Assert(false);\n                    return 0.0f;\n                case 1:\n                    return 0.0f;\n\n                case 2:\n                    return (V[0].W - V[1].W).Length();\n\n                case 3:\n                    return MathUtils.Cross(V[1].W - V[0].W, V[2].W - V[0].W);\n\n                default:\n                    Debug.Assert(false);\n                    return 0.0f;\n            }\n        }\n\n        // Solve a line segment using barycentric coordinates.\n        //\n        // p = a1 * w1 + a2 * w2\n        // a1 + a2 = 1\n        //\n        // The vector from the origin to the closest point on the line is\n        // perpendicular to the line.\n        // e12 = w2 - w1\n        // dot(p, e) = 0\n        // a1 * dot(w1, e) + a2 * dot(w2, e) = 0\n        //\n        // 2-by-2 linear system\n        // [1      1     ][a1] = [1]\n        // [w1.e12 w2.e12][a2] = [0]\n        //\n        // Define\n        // d12_1 =  dot(w2, e12)\n        // d12_2 = -dot(w1, e12)\n        // d12 = d12_1 + d12_2\n        //\n        // Solution\n        // a1 = d12_1 / d12\n        // a2 = d12_2 / d12\n\n        internal void Solve2()\n        {\n            Vector2 w1 = V[0].W;\n            Vector2 w2 = V[1].W;\n            Vector2 e12 = w2 - w1;\n\n            // w1 region\n            float d12_2 = -Vector2.Dot(w1, e12);\n            if (d12_2 <= 0.0f)\n            {\n                // a2 <= 0, so we clamp it to 0\n                V.Value0.A = 1.0f;\n                Count = 1;\n                return;\n            }\n\n            // w2 region\n            float d12_1 = Vector2.Dot(w2, e12);\n            if (d12_1 <= 0.0f)\n            {\n                // a1 <= 0, so we clamp it to 0\n                V.Value1.A = 1.0f;\n                Count = 1;\n                V.Value0 = V.Value1;\n                return;\n            }\n\n            // Must be in e12 region.\n            float inv_d12 = 1.0f / (d12_1 + d12_2);\n            V.Value0.A = d12_1 * inv_d12;\n            V.Value1.A = d12_2 * inv_d12;\n            Count = 2;\n        }\n\n        // Possible regions:\n        // - points[2]\n        // - edge points[0]-points[2]\n        // - edge points[1]-points[2]\n        // - inside the triangle\n        internal void Solve3()\n        {\n            Vector2 w1 = V[0].W;\n            Vector2 w2 = V[1].W;\n            Vector2 w3 = V[2].W;\n\n            // Edge12\n            // [1      1     ][a1] = [1]\n            // [w1.e12 w2.e12][a2] = [0]\n            // a3 = 0\n            Vector2 e12 = w2 - w1;\n            float w1e12 = Vector2.Dot(w1, e12);\n            float w2e12 = Vector2.Dot(w2, e12);\n            float d12_1 = w2e12;\n            float d12_2 = -w1e12;\n\n            // Edge13\n            // [1      1     ][a1] = [1]\n            // [w1.e13 w3.e13][a3] = [0]\n            // a2 = 0\n            Vector2 e13 = w3 - w1;\n            float w1e13 = Vector2.Dot(w1, e13);\n            float w3e13 = Vector2.Dot(w3, e13);\n            float d13_1 = w3e13;\n            float d13_2 = -w1e13;\n\n            // Edge23\n            // [1      1     ][a2] = [1]\n            // [w2.e23 w3.e23][a3] = [0]\n            // a1 = 0\n            Vector2 e23 = w3 - w2;\n            float w2e23 = Vector2.Dot(w2, e23);\n            float w3e23 = Vector2.Dot(w3, e23);\n            float d23_1 = w3e23;\n            float d23_2 = -w2e23;\n\n            // Triangle123\n            float n123 = MathUtils.Cross(e12, e13);\n\n            float d123_1 = n123 * MathUtils.Cross(w2, w3);\n            float d123_2 = n123 * MathUtils.Cross(w3, w1);\n            float d123_3 = n123 * MathUtils.Cross(w1, w2);\n\n            // w1 region\n            if (d12_2 <= 0.0f && d13_2 <= 0.0f)\n            {\n                V.Value0.A = 1.0f;\n                Count = 1;\n                return;\n            }\n\n            // e12\n            if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)\n            {\n                float inv_d12 = 1.0f / (d12_1 + d12_2);\n                V.Value0.A = d12_1 * inv_d12;\n                V.Value1.A = d12_2 * inv_d12;\n                Count = 2;\n                return;\n            }\n\n            // e13\n            if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)\n            {\n                float inv_d13 = 1.0f / (d13_1 + d13_2);\n                V.Value0.A = d13_1 * inv_d13;\n                V.Value2.A = d13_2 * inv_d13;\n                Count = 2;\n                V.Value1 = V.Value2;\n                return;\n            }\n\n            // w2 region\n            if (d12_1 <= 0.0f && d23_2 <= 0.0f)\n            {\n                V.Value1.A = 1.0f;\n                Count = 1;\n                V.Value0 = V.Value1;\n                return;\n            }\n\n            // w3 region\n            if (d13_1 <= 0.0f && d23_1 <= 0.0f)\n            {\n                V.Value2.A = 1.0f;\n                Count = 1;\n                V.Value0 = V.Value2;\n                return;\n            }\n\n            // e23\n            if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)\n            {\n                float inv_d23 = 1.0f / (d23_1 + d23_2);\n                V.Value1.A = d23_1 * inv_d23;\n                V.Value2.A = d23_2 * inv_d23;\n                Count = 2;\n                V.Value0 = V.Value2;\n                return;\n            }\n\n            // Must be in triangle123\n            float inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);\n            V.Value0.A = d123_1 * inv_d123;\n            V.Value1.A = d123_2 * inv_d123;\n            V.Value2.A = d123_3 * inv_d123;\n            Count = 3;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/SimplexCache.cs",
    "content": "using VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    /// <summary>\n    /// Used to warm start ComputeDistance.\n    /// Set count to zero on first call.\n    /// </summary>\n    public struct SimplexCache\n    {\n        /// <summary>\n        /// Length or area\n        /// </summary>\n        public ushort Count;\n\n        /// <summary>\n        /// Vertices on shape A\n        /// </summary>\n        public FixedArray3<byte> IndexA;\n\n        /// <summary>\n        /// Vertices on shape B\n        /// </summary>\n        public FixedArray3<byte> IndexB;\n\n        public float Metric;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/SimplexVertex.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    internal struct SimplexVertex\n    {\n        /// <summary>\n        /// Barycentric coordinate for closest point\n        /// </summary>\n        public float A;\n\n        /// <summary>\n        /// wA index\n        /// </summary>\n        public int IndexA;\n\n        /// <summary>\n        /// wB index\n        /// </summary>\n        public int IndexB;\n\n        /// <summary>\n        /// wB - wA\n        /// </summary>\n        public Vector2 W;\n\n        /// <summary>\n        /// Support point in proxyA\n        /// </summary>\n        public Vector2 WA;\n\n        /// <summary>\n        /// Support point in proxyB\n        /// </summary>\n        public Vector2 WB;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Narrowphase/WorldManifold.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Narrowphase\n{\n    public static class WorldManifold\n    {\n        /// <summary>\n        /// Evaluate the manifold with supplied transforms. This assumes\n        /// modest motion from the original state. This does not change the\n        /// point count, impulses, etc. The radii must come from the Shapes\n        /// that generated the manifold.\n        /// </summary>\n        public static void Initialize(ref Manifold manifold, ref Transform xfA, float radiusA, ref Transform xfB, float radiusB, out Vector2 normal, out FixedArray2<Vector2> points, out FixedArray2<float> separations)\n        {\n            normal = Vector2.Zero;\n            points = new FixedArray2<Vector2>();\n            separations = new FixedArray2<float>();\n\n            if (manifold.PointCount == 0)\n            {\n                return;\n            }\n\n            switch (manifold.Type)\n            {\n                case ManifoldType.Circles:\n                    {\n                        normal = new Vector2(1.0f, 0.0f);\n                        Vector2 pointA = MathUtils.Mul(ref xfA, manifold.LocalPoint);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, manifold.Points.Value0.LocalPoint);\n                        if (Vector2.DistanceSquared(pointA, pointB) > Settings.Epsilon * Settings.Epsilon)\n                        {\n                            normal = pointB - pointA;\n                            normal.Normalize();\n                        }\n\n                        Vector2 cA = pointA + radiusA * normal;\n                        Vector2 cB = pointB - radiusB * normal;\n                        points.Value0 = 0.5f * (cA + cB);\n                        separations.Value0 = Vector2.Dot(cB - cA, normal);\n                    }\n                    break;\n\n                case ManifoldType.FaceA:\n                    {\n                        normal = MathUtils.Mul(xfA.q, manifold.LocalNormal);\n                        Vector2 planePoint = MathUtils.Mul(ref xfA, manifold.LocalPoint);\n\n                        for (int i = 0; i < manifold.PointCount; ++i)\n                        {\n                            Vector2 clipPoint = MathUtils.Mul(ref xfB, manifold.Points[i].LocalPoint);\n                            Vector2 cA = clipPoint + (radiusA - Vector2.Dot(clipPoint - planePoint, normal)) * normal;\n                            Vector2 cB = clipPoint - radiusB * normal;\n                            points[i] = 0.5f * (cA + cB);\n                            separations[i] = Vector2.Dot(cB - cA, normal);\n                        }\n                    }\n                    break;\n\n                case ManifoldType.FaceB:\n                    {\n                        normal = MathUtils.Mul(xfB.q, manifold.LocalNormal);\n                        Vector2 planePoint = MathUtils.Mul(ref xfB, manifold.LocalPoint);\n\n                        for (int i = 0; i < manifold.PointCount; ++i)\n                        {\n                            Vector2 clipPoint = MathUtils.Mul(ref xfA, manifold.Points[i].LocalPoint);\n                            Vector2 cB = clipPoint + (radiusB - Vector2.Dot(clipPoint - planePoint, normal)) * normal;\n                            Vector2 cA = clipPoint - radiusA * normal;\n                            points[i] = 0.5f * (cA + cB);\n                            separations[i] = Vector2.Dot(cA - cB, normal);\n                        }\n\n                        // Ensure normal points from A to B.\n                        normal = -normal;\n                    }\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/RayCast/RayCastInput.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.RayCast\n{\n    /// <summary>\n    /// Ray-cast input data.\n    /// </summary>\n    public struct RayCastInput\n    {\n        /// <summary>\n        /// The ray extends from p1 to p1 + maxFraction * (p2 - p1).\n        /// If you supply a max fraction of 1, the ray extends from p1 to p2.\n        /// A max fraction of 0.5 makes the ray go from p1 and half way to p2.\n        /// </summary>\n        public float MaxFraction;\n\n        /// <summary>\n        /// The starting point of the ray.\n        /// </summary>\n        public Vector2 Point1;\n\n        /// <summary>\n        /// The ending point of the ray.\n        /// </summary>\n        public Vector2 Point2;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/RayCast/RayCastOutput.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.RayCast\n{\n    /// <summary>\n    /// Ray-cast output data.\n    /// </summary>\n    public struct RayCastOutput\n    {\n        /// <summary>\n        /// The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 come from RayCastInput.\n        /// Contains the actual fraction of the ray where it has the intersection point.\n        /// </summary>\n        public float Fraction;\n\n        /// <summary>\n        /// The normal of the face of the shape the ray has hit.\n        /// </summary>\n        public Vector2 Normal;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/RayCastHelper.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.RayCast\n{\n    public static class RayCastHelper\n    {\n        public static bool RayCastEdge(ref Vector2 start, ref Vector2 end, ref RayCastInput input, ref Transform transform, out RayCastOutput output)\n        {\n            // p = p1 + t * d\n            // v = v1 + s * e\n            // p1 + t * d = v1 + s * e\n            // s * e - t * d = p1 - v1\n\n            output = new RayCastOutput();\n\n            // Put the ray into the edge's frame of reference.\n            Vector2 p1 = MathUtils.MulT(transform.q, input.Point1 - transform.p);\n            Vector2 p2 = MathUtils.MulT(transform.q, input.Point2 - transform.p);\n            Vector2 d = p2 - p1;\n\n            Vector2 v1 = start;\n            Vector2 v2 = end;\n            Vector2 e = v2 - v1;\n            Vector2 normal = new Vector2(e.Y, -e.X); //TODO: Could possibly cache the normal.\n            normal.Normalize();\n\n            // q = p1 + t * d\n            // dot(normal, q - v1) = 0\n            // dot(normal, p1 - v1) + t * dot(normal, d) = 0\n            float numerator = Vector2.Dot(normal, v1 - p1);\n            float denominator = Vector2.Dot(normal, d);\n\n            if (denominator == 0.0f)\n            {\n                return false;\n            }\n\n            float t = numerator / denominator;\n            if (t < 0.0f || input.MaxFraction < t)\n            {\n                return false;\n            }\n\n            Vector2 q = p1 + t * d;\n\n            // q = v1 + s * r\n            // s = dot(q - v1, r) / dot(r, r)\n            Vector2 r = v2 - v1;\n            float rr = Vector2.Dot(r, r);\n            if (rr == 0.0f)\n            {\n                return false;\n            }\n\n            float s = Vector2.Dot(q - v1, r) / rr;\n            if (s < 0.0f || 1.0f < s)\n            {\n                return false;\n            }\n\n            output.Fraction = t;\n            if (numerator > 0.0f)\n            {\n                output.Normal = -MathUtils.MulT(transform.q, normal);\n            }\n            else\n            {\n                output.Normal = MathUtils.MulT(transform.q, normal);\n            }\n            return true;\n        }\n\n        public static bool RayCastCircle(ref Vector2 pos, float radius, ref RayCastInput input, ref Transform transform, out RayCastOutput output)\n        {\n            // Collision Detection in Interactive 3D Environments by Gino van den Bergen\n            // From Section 3.1.2\n            // x = s + a * r\n            // norm(x) = radius\n\n            output = new RayCastOutput();\n\n            Vector2 position = transform.p + MathUtils.Mul(transform.q, pos);\n            Vector2 s = input.Point1 - position;\n            float b = Vector2.Dot(s, s) - radius * radius;\n\n            // Solve quadratic equation.\n            Vector2 r = input.Point2 - input.Point1;\n            float c = Vector2.Dot(s, r);\n            float rr = Vector2.Dot(r, r);\n            float sigma = c * c - rr * b;\n\n            // Check for negative discriminant and short segment.\n            if (sigma < 0.0f || rr < Settings.Epsilon)\n            {\n                return false;\n            }\n\n            // Find the point of intersection of the line with the circle.\n            float a = -(c + (float)Math.Sqrt(sigma));\n\n            // Is the intersection point on the segment?\n            if (0.0f <= a && a <= input.MaxFraction * rr)\n            {\n                a /= rr;\n                output.Fraction = a;\n                output.Normal = s + a * r;\n                output.Normal.Normalize();\n                return true;\n            }\n\n            return false;\n        }\n\n        public static bool RayCastPolygon(Vertices vertices, Vertices normals, ref RayCastInput input, ref Transform transform,  out RayCastOutput output)\n        {\n            output = new RayCastOutput();\n\n            // Put the ray into the polygon's frame of reference.\n            Vector2 p1 = MathUtils.MulT(transform.q, input.Point1 - transform.p);\n            Vector2 p2 = MathUtils.MulT(transform.q, input.Point2 - transform.p);\n            Vector2 d = p2 - p1;\n\n            float lower = 0.0f, upper = input.MaxFraction;\n\n            int index = -1;\n\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                // p = p1 + a * d\n                // dot(normal, p - v) = 0\n                // dot(normal, p1 - v) + a * dot(normal, d) = 0\n                float numerator = Vector2.Dot(normals[i], vertices[i] - p1);\n                float denominator = Vector2.Dot(normals[i], d);\n\n                if (denominator == 0.0f)\n                {\n                    if (numerator < 0.0f)\n                    {\n                        return false;\n                    }\n                }\n                else\n                {\n                    // Note: we want this predicate without division:\n                    // lower < numerator / denominator, where denominator < 0\n                    // Since denominator < 0, we have to flip the inequality:\n                    // lower < numerator / denominator <==> denominator * lower > numerator.\n                    if (denominator < 0.0f && numerator < lower * denominator)\n                    {\n                        // Increase lower.\n                        // The segment enters this half-space.\n                        lower = numerator / denominator;\n                        index = i;\n                    }\n                    else if (denominator > 0.0f && numerator < upper * denominator)\n                    {\n                        // Decrease upper.\n                        // The segment exits this half-space.\n                        upper = numerator / denominator;\n                    }\n                }\n\n                // The use of epsilon here causes the assert on lower to trip\n                // in some cases. Apparently the use of epsilon was to make edge\n                // shapes work, but now those are handled separately.\n                //if (upper < lower - b2_epsilon)\n                if (upper < lower)\n                {\n                    return false;\n                }\n            }\n\n            Debug.Assert(0.0f <= lower && lower <= input.MaxFraction);\n\n            if (index >= 0)\n            {\n                output.Fraction = lower;\n                output.Normal = MathUtils.Mul(transform.q, normals[index]);\n                return true;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/ChainShape.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// A chain shape is a free form sequence of line segments.\n    /// The chain has two-sided collision, so you can use inside and outside collision.\n    /// Therefore, you may use any winding order.\n    /// Connectivity information is used to create smooth collisions.\n    /// WARNING: The chain will not collide properly if there are self-intersections.\n    /// </summary>\n    public class ChainShape : Shape\n    {\n        private bool _hasPrevVertex, _hasNextVertex;\n        private Vector2 _prevVertex, _nextVertex;\n\n        /// <summary>\n        /// Create a new ChainShape from the vertices.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices to use. Must contain 2 or more vertices.</param>\n        /// <param name=\"createLoop\">\n        /// Set to true to create a closed loop. It connects the first vertex to the last, and\n        /// automatically adjusts connectivity to create smooth collisions along the chain.\n        /// </param>\n        public ChainShape(Vertices vertices, bool createLoop = false) : base(ShapeType.Chain, Settings.PolygonRadius)\n        {\n            Debug.Assert(vertices != null && vertices.Count >= 3);\n            Debug.Assert(vertices[0] != vertices[vertices.Count - 1]); //Velcro. See http://www.box2d.org/forum/viewtopic.php?f=4&t=7973&p=35363\n\n            for (int i = 1; i < vertices.Count; ++i)\n            {\n                // If the code crashes here, it means your vertices are too close together.\n                Debug.Assert(Vector2.DistanceSquared(vertices[i - 1], vertices[i]) > Settings.LinearSlop * Settings.LinearSlop);\n            }\n\n            Vertices = new Vertices(vertices);\n\n            //Velcro: I merged CreateLoop() and CreateChain() to this\n            if (createLoop)\n            {\n                Vertices.Add(vertices[0]);\n                PrevVertex = Vertices[Vertices.Count - 2]; //Velcro: We use the properties instead of the private fields here to set _hasPrevVertex\n                NextVertex = Vertices[1]; //Velcro: We use the properties instead of the private fields here to set _hasNextVertex\n            }\n\n            ComputeProperties();\n        }\n\n        internal ChainShape() : base(ShapeType.Chain, Settings.PolygonRadius) { }\n\n        /// <summary>\n        /// The vertices. These are not owned/freed by the chain Shape.\n        /// </summary>\n        public Vertices Vertices { get; set; }\n\n        /// <summary>\n        /// Edge count = vertex count - 1\n        /// </summary>\n        public override int ChildCount => Vertices.Count - 1;\n\n        /// <summary>\n        /// Establish connectivity to a vertex that precedes the first vertex.\n        /// Don't call this for loops.\n        /// </summary>\n        public Vector2 PrevVertex\n        {\n            get { return _prevVertex; }\n            set\n            {\n                _prevVertex = value;\n                _hasPrevVertex = true;\n            }\n        }\n\n        /// <summary>\n        /// Establish connectivity to a vertex that follows the last vertex.\n        /// Don't call this for loops.\n        /// </summary>\n        public Vector2 NextVertex\n        {\n            get { return _nextVertex; }\n            set\n            {\n                _nextVertex = value;\n                _hasNextVertex = true;\n            }\n        }\n\n        internal void GetChildEdge(EdgeShape edge, int index)\n        {\n            Debug.Assert(0 <= index && index < Vertices.Count - 1);\n            Debug.Assert(edge != null);\n\n            edge.ShapeType = ShapeType.Edge;\n            edge._radius = _radius;\n\n            edge.Vertex1 = Vertices[index + 0];\n            edge.Vertex2 = Vertices[index + 1];\n\n            if (index > 0)\n            {\n                edge.Vertex0 = Vertices[index - 1];\n                edge.HasVertex0 = true;\n            }\n            else\n            {\n                edge.Vertex0 = _prevVertex;\n                edge.HasVertex0 = _hasPrevVertex;\n            }\n\n            if (index < Vertices.Count - 2)\n            {\n                edge.Vertex3 = Vertices[index + 2];\n                edge.HasVertex3 = true;\n            }\n            else\n            {\n                edge.Vertex3 = _nextVertex;\n                edge.HasVertex3 = _hasNextVertex;\n            }\n        }\n\n        public EdgeShape GetChildEdge(int index)\n        {\n            EdgeShape edgeShape = new EdgeShape();\n            GetChildEdge(edgeShape, index);\n            return edgeShape;\n        }\n\n        public override bool TestPoint(ref Transform transform, ref Vector2 point)\n        {\n            return false;\n        }\n\n        public override bool RayCast(ref RayCastInput input, ref Transform transform, int childIndex, out RayCastOutput output)\n        {\n            Debug.Assert(childIndex < Vertices.Count);\n\n            int i1 = childIndex;\n            int i2 = childIndex + 1;\n\n            if (i2 == Vertices.Count)\n                i2 = 0;\n\n            Vector2 v1 = Vertices[i1];\n            Vector2 v2 = Vertices[i2];\n\n            return RayCastHelper.RayCastEdge(ref v1, ref v2, ref input, ref transform, out output);\n        }\n\n        public override void ComputeAABB(ref Transform transform, int childIndex, out AABB aabb)\n        {\n            Debug.Assert(childIndex < Vertices.Count);\n\n            int i1 = childIndex;\n            int i2 = childIndex + 1;\n\n            if (i2 == Vertices.Count)\n                i2 = 0;\n\n            Vector2 v1 = Vertices[i1];\n            Vector2 v2 = Vertices[i2];\n\n            AABBHelper.ComputeEdgeAABB(ref v1, ref v2, ref transform, out aabb);\n        }\n\n        protected sealed override void ComputeProperties()\n        {\n            //Does nothing. Chain shapes don't have properties.\n        }\n\n        /// <summary>\n        /// Compare the chain to another chain\n        /// </summary>\n        /// <param name=\"shape\">The other chain</param>\n        /// <returns>True if the two chain shapes are the same</returns>\n        public bool CompareTo(ChainShape shape)\n        {\n            if (Vertices.Count != shape.Vertices.Count)\n                return false;\n\n            for (int i = 0; i < Vertices.Count; i++)\n            {\n                if (Vertices[i] != shape.Vertices[i])\n                    return false;\n            }\n\n            return PrevVertex == shape.PrevVertex && NextVertex == shape.NextVertex;\n        }\n\n        public override Shape Clone()\n        {\n            ChainShape clone = new ChainShape();\n            clone.ShapeType = ShapeType;\n            clone._density = _density;\n            clone._radius = _radius;\n            clone.PrevVertex = _prevVertex;\n            clone.NextVertex = _nextVertex;\n            clone._hasNextVertex = _hasNextVertex;\n            clone._hasPrevVertex = _hasPrevVertex;\n            clone.Vertices = new Vertices(Vertices);\n            return clone;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/CircleShape.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org\n*\n* This software is provided 'as-is', without any express or implied\n* warranty.  In no event will the authors be held liable for any damages\n* arising from the use of this software.\n* Permission is granted to anyone to use this software for any purpose,\n* including commercial applications, and to alter it and redistribute it\n* freely, subject to the following restrictions:\n* 1. The origin of this software must not be misrepresented; you must not\n* claim that you wrote the original software. If you use this software\n* in a product, an acknowledgment in the product documentation would be\n* appreciated but is not required.\n* 2. Altered source versions must be plainly marked as such, and must not be\n* misrepresented as being the original software.\n* 3. This notice may not be removed or altered from any source distribution.\n*/\n\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// A circle shape.\n    /// </summary>\n    public class CircleShape : Shape\n    {\n        internal Vector2 _position;\n\n        /// <summary>\n        /// Create a new circle with the desired radius and density.\n        /// </summary>\n        /// <param name=\"radius\">The radius of the circle.</param>\n        /// <param name=\"density\">The density of the circle.</param>\n        public CircleShape(float radius, float density) : base(ShapeType.Circle, radius, density)\n        {\n            ComputeProperties();\n        }\n\n        internal CircleShape() : base(ShapeType.Circle) { }\n\n        public override int ChildCount => 1;\n\n        /// <summary>\n        /// Get or set the position of the circle\n        /// </summary>\n        public Vector2 Position\n        {\n            get { return _position; }\n            set\n            {\n                _position = value;\n                ComputeInertia();\n            }\n        }\n\n        public override bool TestPoint(ref Transform transform, ref Vector2 point)\n        {\n            return TestPointHelper.TestPointCircle(ref _position, _radius, ref point, ref transform);\n        }\n\n        public override bool RayCast(ref RayCastInput input, ref Transform transform, int childIndex, out RayCastOutput output)\n        {\n            return RayCastHelper.RayCastCircle(ref _position, Radius, ref input, ref transform, out output);\n        }\n\n        public override void ComputeAABB(ref Transform transform, int childIndex, out AABB aabb)\n        {\n            AABBHelper.ComputeCircleAABB(ref _position, _radius, ref transform, out aabb);\n        }\n\n        protected sealed override void ComputeProperties()\n        {\n            ComputeMass();\n            ComputeInertia();\n        }\n\n        private void ComputeMass()\n        {\n            //Velcro: We calculate area for later consumption\n            float area = Settings.Pi * _2radius;\n            MassData.Area = area;\n            MassData.Mass = Density * area;\n        }\n\n        private void ComputeInertia()\n        {\n            MassData.Centroid = Position;\n\n            // inertia about the local origin\n            MassData.Inertia = MassData.Mass * (0.5f * _2radius + Vector2.Dot(Position, Position));\n        }\n\n        /// <summary>\n        /// Compare the circle to another circle\n        /// </summary>\n        /// <param name=\"shape\">The other circle</param>\n        /// <returns>True if the two circles are the same size and have the same position</returns>\n        public bool CompareTo(CircleShape shape)\n        {\n            return Radius == shape.Radius && Position == shape.Position;\n        }\n\n        public override Shape Clone()\n        {\n            CircleShape clone = new CircleShape();\n            clone.ShapeType = ShapeType;\n            clone._radius = Radius;\n            clone._2radius = _2radius; //Velcro note: We also copy the cache\n            clone._density = _density;\n            clone._position = _position;\n            clone.MassData = MassData;\n            return clone;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/EdgeShape.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// A line segment (edge) shape. These can be connected in chains or loops to other edge shapes.\n    /// The connectivity information is used to ensure correct contact normals.\n    /// </summary>\n    public class EdgeShape : Shape\n    {\n        internal Vector2 _vertex1;\n        internal Vector2 _vertex2;\n\n        /// <summary>\n        /// Create a new EdgeShape with the specified start and end.\n        /// </summary>\n        /// <param name=\"start\">The start of the edge.</param>\n        /// <param name=\"end\">The end of the edge.</param>\n        public EdgeShape(Vector2 start, Vector2 end) : base(ShapeType.Edge, Settings.PolygonRadius)\n        {\n            Set(start, end);\n            ComputeProperties();\n        }\n\n        internal EdgeShape() : base(ShapeType.Edge, Settings.PolygonRadius) { }\n\n        public override int ChildCount => 1;\n\n        /// <summary>\n        /// Is true if the edge is connected to an adjacent vertex before vertex 1.\n        /// </summary>\n        public bool HasVertex0 { get; set; }\n\n        /// <summary>\n        /// Is true if the edge is connected to an adjacent vertex after vertex2.\n        /// </summary>\n        public bool HasVertex3 { get; set; }\n\n        /// <summary>\n        /// Optional adjacent vertices. These are used for smooth collision.\n        /// </summary>\n        public Vector2 Vertex0 { get; set; }\n\n        /// <summary>\n        /// Optional adjacent vertices. These are used for smooth collision.\n        /// </summary>\n        public Vector2 Vertex3 { get; set; }\n\n        /// <summary>\n        /// These are the edge vertices\n        /// </summary>\n        public Vector2 Vertex1\n        {\n            get { return _vertex1; }\n            set\n            {\n                _vertex1 = value;\n                ComputeProperties();\n            }\n        }\n\n        /// <summary>\n        /// These are the edge vertices\n        /// </summary>\n        public Vector2 Vertex2\n        {\n            get { return _vertex2; }\n            set\n            {\n                _vertex2 = value;\n                ComputeProperties();\n            }\n        }\n\n        /// <summary>\n        /// Set this as an isolated edge.\n        /// </summary>\n        /// <param name=\"start\">The start.</param>\n        /// <param name=\"end\">The end.</param>\n        public void Set(Vector2 start, Vector2 end)\n        {\n            _vertex1 = start;\n            _vertex2 = end;\n            HasVertex0 = false;\n            HasVertex3 = false;\n\n            ComputeProperties();\n        }\n\n        public override bool TestPoint(ref Transform transform, ref Vector2 point)\n        {\n            return false;\n        }\n\n        public override bool RayCast(ref RayCastInput input, ref Transform transform, int childIndex, out RayCastOutput output)\n        {\n            return RayCastHelper.RayCastEdge(ref _vertex1, ref _vertex2, ref input, ref transform, out output);\n        }\n\n        public override void ComputeAABB(ref Transform transform, int childIndex, out AABB aabb)\n        {\n            AABBHelper.ComputeEdgeAABB(ref _vertex1, ref _vertex2, ref transform, out aabb);\n        }\n\n        protected sealed override void ComputeProperties()\n        {\n            MassData.Centroid = 0.5f * (_vertex1 + _vertex2);\n        }\n\n        public bool CompareTo(EdgeShape shape)\n        {\n            return HasVertex0 == shape.HasVertex0 &&\n                   HasVertex3 == shape.HasVertex3 &&\n                   Vertex0 == shape.Vertex0 &&\n                   Vertex1 == shape.Vertex1 &&\n                   Vertex2 == shape.Vertex2 &&\n                   Vertex3 == shape.Vertex3;\n        }\n\n        public override Shape Clone()\n        {\n            EdgeShape clone = new EdgeShape();\n            clone.ShapeType = ShapeType;\n            clone._radius = _radius;\n            clone._density = _density;\n            clone.HasVertex0 = HasVertex0;\n            clone.HasVertex3 = HasVertex3;\n            clone.Vertex0 = Vertex0;\n            clone._vertex1 = _vertex1;\n            clone._vertex2 = _vertex2;\n            clone.Vertex3 = Vertex3;\n            clone.MassData = MassData;\n            return clone;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/MassData.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// This holds the mass data computed for a shape.\n    /// </summary>\n    public struct MassData : IEquatable<MassData>\n    {\n        /// <summary>\n        /// The area of the shape\n        /// </summary>\n        public float Area { get; set; }\n\n        /// <summary>\n        /// The position of the shape's centroid relative to the shape's origin.\n        /// </summary>\n        public Vector2 Centroid { get; set; }\n\n        /// <summary>\n        /// The rotational inertia of the shape about the local origin.\n        /// </summary>\n        public float Inertia { get; set; }\n\n        /// <summary>\n        /// The mass of the shape, usually in kilograms.\n        /// </summary>\n        public float Mass { get; set; }\n\n        /// <summary>\n        /// The equal operator\n        /// </summary>\n        /// <param name=\"left\"></param>\n        /// <param name=\"right\"></param>\n        /// <returns></returns>\n        public static bool operator ==(MassData left, MassData right)\n        {\n            return left.Area == right.Area && left.Mass == right.Mass && left.Centroid == right.Centroid && left.Inertia == right.Inertia;\n        }\n\n        /// <summary>\n        /// The not equal operator\n        /// </summary>\n        /// <param name=\"left\"></param>\n        /// <param name=\"right\"></param>\n        /// <returns></returns>\n        public static bool operator !=(MassData left, MassData right)\n        {\n            return !(left == right);\n        }\n\n        public bool Equals(MassData other)\n        {\n            return this == other;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj))\n                return false;\n\n            if (obj.GetType() != typeof(MassData))\n                return false;\n\n            return Equals((MassData)obj);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                int result = Area.GetHashCode();\n                result = (result * 397) ^ Centroid.GetHashCode();\n                result = (result * 397) ^ Inertia.GetHashCode();\n                result = (result * 397) ^ Mass.GetHashCode();\n                return result;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/PolygonShape.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.ConvexHull.GiftWrap;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// Represents a simple non-self intersecting convex polygon.\n    /// Create a convex hull from the given array of points.\n    /// </summary>\n    public class PolygonShape : Shape\n    {\n        private Vertices _normals;\n        private Vertices _vertices;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PolygonShape\" /> class.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"density\">The density.</param>\n        public PolygonShape(Vertices vertices, float density) : base(ShapeType.Polygon, Settings.PolygonRadius, density)\n        {\n            Vertices = vertices; //This assignment will call ComputeProperties()\n        }\n\n        /// <summary>\n        /// Create a new PolygonShape with the specified density.\n        /// </summary>\n        /// <param name=\"density\">The density.</param>\n        public PolygonShape(float density) : base(ShapeType.Polygon, Settings.PolygonRadius, density) { }\n\n        internal PolygonShape() : base(ShapeType.Polygon, Settings.PolygonRadius) { }\n\n        /// <summary>\n        /// Create a convex hull from the given array of local points.\n        /// The number of vertices must be in the range [3, Settings.MaxPolygonVertices].\n        /// Warning: the points may be re-ordered, even if they form a convex polygon\n        /// Warning: collinear points are handled but not removed. Collinear points may lead to poor stacking behavior.\n        /// </summary>\n        public Vertices Vertices\n        {\n            get { return _vertices; }\n            set\n            {\n                Debug.Assert(value.Count >= 3 && value.Count <= Settings.MaxPolygonVertices);\n\n                if (Settings.UseConvexHullPolygons)\n                {\n                    //Velcro: This check is required as the GiftWrap algorithm early exits on triangles\n                    //So instead of giftwrapping a triangle, we just force it to be clock wise.\n                    if (value.Count <= 3)\n                    {\n                        _vertices = new Vertices(value);\n                        _vertices.ForceCounterClockWise();\n                    }\n                    else\n                        _vertices = GiftWrap.GetConvexHull(value);\n                }\n                else\n                {\n                    _vertices = new Vertices(value);\n                }\n\n                _normals = new Vertices(_vertices.Count);\n\n                // Compute normals. Ensure the edges have non-zero length.\n                for (int i = 0; i < _vertices.Count; ++i)\n                {\n                    int i1 = i;\n                    int i2 = i + 1 < _vertices.Count ? i + 1 : 0;\n                    Vector2 edge = _vertices[i2] - _vertices[i1];\n                    Debug.Assert(edge.LengthSquared() > Settings.Epsilon * Settings.Epsilon);\n                    Vector2 temp = MathUtils.Cross(edge, 1.0f);\n                    temp.Normalize();\n                    _normals.Add(temp);\n                }\n\n                // Compute the polygon mass data\n                ComputeProperties();\n            }\n        }\n\n        public Vertices Normals => _normals;\n\n        public override int ChildCount => 1;\n\n        protected sealed override void ComputeProperties()\n        {\n            // Polygon mass, centroid, and inertia.\n            // Let rho be the polygon density in mass per unit area.\n            // Then:\n            // mass = rho * int(dA)\n            // centroid.x = (1/mass) * rho * int(x * dA)\n            // centroid.y = (1/mass) * rho * int(y * dA)\n            // I = rho * int((x*x + y*y) * dA)\n            //\n            // We can compute these integrals by summing all the integrals\n            // for each triangle of the polygon. To evaluate the integral\n            // for a single triangle, we make a change of variables to\n            // the (u,v) coordinates of the triangle:\n            // x = x0 + e1x * u + e2x * v\n            // y = y0 + e1y * u + e2y * v\n            // where 0 <= u && 0 <= v && u + v <= 1.\n            //\n            // We integrate u from [0,1-v] and then v from [0,1].\n            // We also need to use the Jacobian of the transformation:\n            // D = cross(e1, e2)\n            //\n            // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)\n            //\n            // The rest of the derivation is handled by computer algebra.\n\n            Debug.Assert(Vertices.Count >= 3);\n\n            //Velcro optimization: Early exit as polygons with 0 density does not have any properties.\n            if (_density <= 0)\n                return;\n\n            //Velcro optimization: Consolidated the calculate centroid and mass code to a single method.\n            Vector2 center = Vector2.Zero;\n            float area = 0.0f;\n            float I = 0.0f;\n\n            //Velcro: We change the reference point to be inside the polygon\n\n            // pRef is the reference point for forming triangles.\n            // It's location doesn't change the result (except for rounding error).\n            Vector2 s = Vector2.Zero;\n\n            // This code would put the reference point inside the polygon.\n            for (int i = 0; i < Vertices.Count; ++i)\n            {\n                s += Vertices[i];\n            }\n            s *= 1.0f / Vertices.Count;\n\n            const float k_inv3 = 1.0f / 3.0f;\n\n            for (int i = 0; i < Vertices.Count; ++i)\n            {\n                // Triangle vertices.\n                Vector2 e1 = Vertices[i] - s;\n                Vector2 e2 = i + 1 < Vertices.Count ? Vertices[i + 1] - s : Vertices[0] - s;\n\n                float D = MathUtils.Cross(e1, e2);\n\n                float triangleArea = 0.5f * D;\n                area += triangleArea;\n\n                // Area weighted centroid\n                center += triangleArea * k_inv3 * (e1 + e2);\n\n                float ex1 = e1.X, ey1 = e1.Y;\n                float ex2 = e2.X, ey2 = e2.Y;\n\n                float intx2 = ex1 * ex1 + ex2 * ex1 + ex2 * ex2;\n                float inty2 = ey1 * ey1 + ey2 * ey1 + ey2 * ey2;\n\n                I += (0.25f * k_inv3 * D) * (intx2 + inty2);\n            }\n\n            //The area is too small for the engine to handle.\n            Debug.Assert(area > Settings.Epsilon);\n\n            // We save the area\n            MassData.Area = area;\n\n            // Total mass\n            MassData.Mass = _density * area;\n\n            // Center of mass\n            center *= 1.0f / area;\n            MassData.Centroid = center + s;\n\n            // Inertia tensor relative to the local origin (point s).\n            MassData.Inertia = _density * I;\n\n            // Shift to center of mass then to original body origin.\n            MassData.Inertia += MassData.Mass * (Vector2.Dot(MassData.Centroid, MassData.Centroid) - Vector2.Dot(center, center));\n        }\n\n        public override bool TestPoint(ref Transform transform, ref Vector2 point)\n        {\n            return TestPointHelper.TestPointPolygon(_vertices, _normals, ref point, ref transform);\n        }\n\n        public override bool RayCast(ref RayCastInput input, ref Transform transform, int childIndex, out RayCastOutput output)\n        {\n            return RayCastHelper.RayCastPolygon(_vertices, _normals, ref input, ref transform, out output);\n        }\n\n        /// <summary>\n        /// Given a transform, compute the associated axis aligned bounding box for a child shape.\n        /// </summary>\n        /// <param name=\"transform\">The world transform of the shape.</param>\n        /// <param name=\"childIndex\">The child shape index.</param>\n        /// <param name=\"aabb\">The AABB results.</param>\n        public override void ComputeAABB(ref Transform transform, int childIndex, out AABB aabb)\n        {\n            AABBHelper.ComputePolygonAABB(_vertices, ref transform, out aabb);\n        }\n\n        public bool CompareTo(PolygonShape shape)\n        {\n            if (Vertices.Count != shape.Vertices.Count)\n                return false;\n\n            for (int i = 0; i < Vertices.Count; i++)\n            {\n                if (Vertices[i] != shape.Vertices[i])\n                    return false;\n            }\n\n            return Radius == shape.Radius && MassData == shape.MassData;\n        }\n\n        public override Shape Clone()\n        {\n            PolygonShape clone = new PolygonShape();\n            clone.ShapeType = ShapeType;\n            clone._radius = _radius;\n            clone._density = _density;\n            clone._vertices = new Vertices(_vertices);\n            clone._normals = new Vertices(_normals);\n            clone.MassData = MassData;\n            return clone;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/Shape.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.Shapes\n{\n    /// <summary>\n    /// A shape is used for collision detection. You can create a shape however you like.\n    /// Shapes used for simulation in World are created automatically when a Fixture\n    /// is created. Shapes may encapsulate a one or more child shapes.\n    /// </summary>\n    public abstract class Shape\n    {\n        internal float _2radius;\n        internal float _density;\n        internal float _radius;\n\n        /// <summary>\n        /// Contains the properties of the shape such as:\n        /// - Area of the shape\n        /// - Centroid\n        /// - Inertia\n        /// - Mass\n        /// </summary>\n        public MassData MassData;\n\n        protected Shape(ShapeType type, float radius = 0, float density = 0)\n        {\n            Debug.Assert(radius >= 0);\n            Debug.Assert(density >= 0);\n\n            ShapeType = type;\n            _radius = radius;\n            _2radius = _radius * _radius;\n            _density = density;\n        }\n\n        /// <summary>\n        /// Get the type of this shape.\n        /// </summary>\n        /// <value>The type of the shape.</value>\n        public ShapeType ShapeType { get; internal set; }\n\n        /// <summary>\n        /// Get the number of child primitives.\n        /// </summary>\n        /// <value></value>\n        public abstract int ChildCount { get; }\n\n        /// <summary>\n        /// Gets or sets the density.\n        /// Changing the density causes a recalculation of shape properties.\n        /// </summary>\n        /// <value>The density.</value>\n        public float Density\n        {\n            get { return _density; }\n            set\n            {\n                Debug.Assert(value >= 0);\n\n                _density = value;\n                ComputeProperties();\n            }\n        }\n\n        /// <summary>\n        /// Radius of the Shape\n        /// Changing the radius causes a recalculation of shape properties.\n        /// </summary>\n        public float Radius\n        {\n            get { return _radius; }\n            set\n            {\n                Debug.Assert(value >= 0);\n\n                _radius = value;\n                _2radius = _radius * _radius;\n\n                ComputeProperties();\n            }\n        }\n\n        /// <summary>\n        /// Clone the concrete shape\n        /// </summary>\n        /// <returns>A clone of the shape</returns>\n        public abstract Shape Clone();\n\n        /// <summary>\n        /// Test a point for containment in this shape.\n        /// Note: This only works for convex shapes.\n        /// </summary>\n        /// <param name=\"transform\">The shape world transform.</param>\n        /// <param name=\"point\">A point in world coordinates.</param>\n        /// <returns>True if the point is inside the shape</returns>\n        public abstract bool TestPoint(ref Transform transform, ref Vector2 point);\n\n        /// <summary>\n        /// Cast a ray against a child shape.\n        /// </summary>\n        /// <param name=\"input\">The ray-cast input parameters.</param>\n        /// <param name=\"transform\">The transform to be applied to the shape.</param>\n        /// <param name=\"childIndex\">The child shape index.</param>\n        /// <param name=\"output\">The ray-cast results.</param>\n        /// <returns>True if the ray-cast hits the shape</returns>\n        public abstract bool RayCast(ref RayCastInput input, ref Transform transform, int childIndex, out RayCastOutput output);\n\n        /// <summary>\n        /// Given a transform, compute the associated axis aligned bounding box for a child shape.\n        /// </summary>\n        /// <param name=\"transform\">The world transform of the shape.</param>\n        /// <param name=\"childIndex\">The child shape index.</param>\n        /// <param name=\"aabb\">The AABB results.</param>\n        public abstract void ComputeAABB(ref Transform transform, int childIndex, out AABB aabb);\n\n        /// <summary>\n        /// Compute the mass properties of this shape using its dimensions and density.\n        /// The inertia tensor is computed about the local origin, not the centroid.\n        /// </summary>\n        protected abstract void ComputeProperties();\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/Shapes/ShapeType.cs",
    "content": "namespace VelcroPhysics.Collision.Shapes\n{\n    public enum ShapeType\n    {\n        Unknown = -1,\n        Circle = 0,\n        Edge = 1,\n        Polygon = 2,\n        Chain = 3,\n        TypeCount = 4\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/SeparationFunction.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Distance;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.TOI\n{\n    public static class SeparationFunction\n    {\n        public static void Initialize(ref SimplexCache cache, DistanceProxy proxyA, ref Sweep sweepA, DistanceProxy proxyB, ref Sweep sweepB, float t1, out Vector2 axis, out Vector2 localPoint, out SeparationFunctionType type)\n        {\n            int count = cache.Count;\n            Debug.Assert(0 < count && count < 3);\n\n            Transform xfA, xfB;\n            sweepA.GetTransform(out xfA, t1);\n            sweepB.GetTransform(out xfB, t1);\n\n            if (count == 1)\n            {\n                localPoint = Vector2.Zero;\n                type = SeparationFunctionType.Points;\n                Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];\n                Vector2 localPointB = proxyB.Vertices[cache.IndexB[0]];\n                Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n                Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n                axis = pointB - pointA;\n                axis.Normalize();\n            }\n            else if (cache.IndexA[0] == cache.IndexA[1])\n            {\n                // Two points on B and one on A.\n                type = SeparationFunctionType.FaceB;\n                Vector2 localPointB1 = proxyB.Vertices[cache.IndexB[0]];\n                Vector2 localPointB2 = proxyB.Vertices[cache.IndexB[1]];\n\n                Vector2 a = localPointB2 - localPointB1;\n                axis = new Vector2(a.Y, -a.X);\n                axis.Normalize();\n                Vector2 normal = MathUtils.Mul(ref xfB.q, axis);\n\n                localPoint = 0.5f * (localPointB1 + localPointB2);\n                Vector2 pointB = MathUtils.Mul(ref xfB, localPoint);\n\n                Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];\n                Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n\n                float s = Vector2.Dot(pointA - pointB, normal);\n                if (s < 0.0f)\n                {\n                    axis = -axis;\n                }\n            }\n            else\n            {\n                // Two points on A and one or two points on B.\n                type = SeparationFunctionType.FaceA;\n                Vector2 localPointA1 = proxyA.Vertices[cache.IndexA[0]];\n                Vector2 localPointA2 = proxyA.Vertices[cache.IndexA[1]];\n\n                Vector2 a = localPointA2 - localPointA1;\n                axis = new Vector2(a.Y, -a.X);\n                axis.Normalize();\n                Vector2 normal = MathUtils.Mul(ref xfA.q, axis);\n\n                localPoint = 0.5f * (localPointA1 + localPointA2);\n                Vector2 pointA = MathUtils.Mul(ref xfA, localPoint);\n\n                Vector2 localPointB = proxyB.Vertices[cache.IndexB[0]];\n                Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n\n                float s = Vector2.Dot(pointB - pointA, normal);\n                if (s < 0.0f)\n                {\n                    axis = -axis;\n                }\n            }\n\n            //Velcro note: the returned value that used to be here has been removed, as it was not used.\n        }\n\n        public static float FindMinSeparation(out int indexA, out int indexB, float t, DistanceProxy proxyA, ref Sweep sweepA, DistanceProxy proxyB, ref Sweep sweepB, ref Vector2 axis, ref Vector2 localPoint, SeparationFunctionType type)\n        {\n            Transform xfA, xfB;\n            sweepA.GetTransform(out xfA, t);\n            sweepB.GetTransform(out xfB, t);\n\n            switch (type)\n            {\n                case SeparationFunctionType.Points:\n                    {\n                        Vector2 axisA = MathUtils.MulT(ref xfA.q, axis);\n                        Vector2 axisB = MathUtils.MulT(ref xfB.q, -axis);\n\n                        indexA = proxyA.GetSupport(axisA);\n                        indexB = proxyB.GetSupport(axisB);\n\n                        Vector2 localPointA = proxyA.Vertices[indexA];\n                        Vector2 localPointB = proxyB.Vertices[indexB];\n\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n\n                        float separation = Vector2.Dot(pointB - pointA, axis);\n                        return separation;\n                    }\n\n                case SeparationFunctionType.FaceA:\n                    {\n                        Vector2 normal = MathUtils.Mul(ref xfA.q, axis);\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPoint);\n\n                        Vector2 axisB = MathUtils.MulT(ref xfB.q, -normal);\n\n                        indexA = -1;\n                        indexB = proxyB.GetSupport(axisB);\n\n                        Vector2 localPointB = proxyB.Vertices[indexB];\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n\n                        float separation = Vector2.Dot(pointB - pointA, normal);\n                        return separation;\n                    }\n\n                case SeparationFunctionType.FaceB:\n                    {\n                        Vector2 normal = MathUtils.Mul(ref xfB.q, axis);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPoint);\n\n                        Vector2 axisA = MathUtils.MulT(ref xfA.q, -normal);\n\n                        indexB = -1;\n                        indexA = proxyA.GetSupport(axisA);\n\n                        Vector2 localPointA = proxyA.Vertices[indexA];\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n\n                        float separation = Vector2.Dot(pointA - pointB, normal);\n                        return separation;\n                    }\n\n                default:\n                    Debug.Assert(false);\n                    indexA = -1;\n                    indexB = -1;\n                    return 0.0f;\n            }\n        }\n\n        public static float Evaluate(int indexA, int indexB, float t, DistanceProxy proxyA, ref Sweep sweepA, DistanceProxy proxyB, ref Sweep sweepB, ref Vector2 axis, ref Vector2 localPoint, SeparationFunctionType type)\n        {\n            Transform xfA, xfB;\n            sweepA.GetTransform(out xfA, t);\n            sweepB.GetTransform(out xfB, t);\n\n            switch (type)\n            {\n                case SeparationFunctionType.Points:\n                    {\n                        Vector2 localPointA = proxyA.Vertices[indexA];\n                        Vector2 localPointB = proxyB.Vertices[indexB];\n\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n                        float separation = Vector2.Dot(pointB - pointA, axis);\n\n                        return separation;\n                    }\n                case SeparationFunctionType.FaceA:\n                    {\n                        Vector2 normal = MathUtils.Mul(ref xfA.q, axis);\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPoint);\n\n                        Vector2 localPointB = proxyB.Vertices[indexB];\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);\n\n                        float separation = Vector2.Dot(pointB - pointA, normal);\n                        return separation;\n                    }\n                case SeparationFunctionType.FaceB:\n                    {\n                        Vector2 normal = MathUtils.Mul(ref xfB.q, axis);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, localPoint);\n\n                        Vector2 localPointA = proxyA.Vertices[indexA];\n                        Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);\n\n                        float separation = Vector2.Dot(pointA - pointB, normal);\n                        return separation;\n                    }\n                default:\n                    Debug.Assert(false);\n                    return 0.0f;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/SeparationFunctionType.cs",
    "content": "namespace VelcroPhysics.Collision.TOI\n{\n    public enum SeparationFunctionType\n    {\n        Points,\n        FaceA,\n        FaceB\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/Sweep.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision.TOI\n{\n    /// <summary>\n    /// This describes the motion of a body/shape for TOI computation.\n    /// Shapes are defined with respect to the body origin, which may\n    /// no coincide with the center of mass. However, to support dynamics\n    /// we must interpolate the center of mass position.\n    /// </summary>\n    public struct Sweep\n    {\n        /// <summary>\n        /// World angles\n        /// </summary>\n        public float A;\n\n        public float A0;\n\n        /// <summary>\n        /// Fraction of the current time step in the range [0,1]\n        /// c0 and a0 are the positions at alpha0.\n        /// </summary>\n        public float Alpha0;\n\n        /// <summary>\n        /// Center world positions\n        /// </summary>\n        public Vector2 C;\n\n        public Vector2 C0;\n\n        /// <summary>\n        /// Local center of mass position\n        /// </summary>\n        public Vector2 LocalCenter;\n\n        /// <summary>\n        /// Get the interpolated transform at a specific time.\n        /// </summary>\n        /// <param name=\"xfb\">The transform.</param>\n        /// <param name=\"beta\">beta is a factor in [0,1], where 0 indicates alpha0.</param>\n        public void GetTransform(out Transform xfb, float beta)\n        {\n            xfb = new Transform();\n            xfb.p.X = (1.0f - beta) * C0.X + beta * C.X;\n            xfb.p.Y = (1.0f - beta) * C0.Y + beta * C.Y;\n            float angle = (1.0f - beta) * A0 + beta * A;\n            xfb.q.Set(angle);\n\n            // Shift to origin\n            xfb.p -= MathUtils.Mul(xfb.q, LocalCenter);\n        }\n\n        /// <summary>\n        /// Advance the sweep forward, yielding a new initial state.\n        /// </summary>\n        /// <param name=\"alpha\">new initial time</param>\n        public void Advance(float alpha)\n        {\n            Debug.Assert(Alpha0 < 1.0f);\n            float beta = (alpha - Alpha0) / (1.0f - Alpha0);\n            C0 += beta * (C - C0);\n            A0 += beta * (A - A0);\n            Alpha0 = alpha;\n        }\n\n        /// <summary>\n        /// Normalize the angles.\n        /// </summary>\n        public void Normalize()\n        {\n            float d = MathHelper.TwoPi * (float)Math.Floor(A0 / MathHelper.TwoPi);\n            A0 -= d;\n            A -= d;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/TOIInput.cs",
    "content": "using VelcroPhysics.Collision.Distance;\n\nnamespace VelcroPhysics.Collision.TOI\n{\n    /// <summary>\n    /// Input parameters for CalculateTimeOfImpact\n    /// </summary>\n    public struct TOIInput\n    {\n        public DistanceProxy ProxyA;\n        public DistanceProxy ProxyB;\n        public Sweep SweepA;\n        public Sweep SweepB;\n        public float TMax; // defines sweep interval [0, tMax]\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/TOIOutput.cs",
    "content": "namespace VelcroPhysics.Collision.TOI\n{\n    public struct TOIOutput\n    {\n        public TOIOutputState State;\n        public float T;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/TOIOutputState.cs",
    "content": "namespace VelcroPhysics.Collision.TOI\n{\n    public enum TOIOutputState\n    {\n        Unknown,\n        Failed,\n        Overlapped,\n        Touching,\n        Seperated\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TOI/TimeOfImpact.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Distance;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Collision.TOI\n{\n    public static class TimeOfImpact\n    {\n        // CCD via the local separating axis method. This seeks progression\n        // by computing the largest time at which separation is maintained.\n\n        [ThreadStatic]\n        public static int TOICalls,\n                          TOIIters,\n                          TOIMaxIters;\n\n        [ThreadStatic]\n        public static int TOIRootIters,\n                          TOIMaxRootIters;\n\n        /// <summary>\n        /// Compute the upper bound on time before two shapes penetrate. Time is represented as\n        /// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,\n        /// non-tunneling collision. If you change the time interval, you should call this function\n        /// again.\n        /// Note: use Distance() to compute the contact point and normal at the time of impact.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"output\">The output.</param>\n        public static void CalculateTimeOfImpact(ref TOIInput input, out TOIOutput output)\n        {\n            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                ++TOICalls;\n\n            output = new TOIOutput();\n            output.State = TOIOutputState.Unknown;\n            output.T = input.TMax;\n\n            Sweep sweepA = input.SweepA;\n            Sweep sweepB = input.SweepB;\n\n            // Large rotations can make the root finder fail, so we normalize the\n            // sweep angles.\n            sweepA.Normalize();\n            sweepB.Normalize();\n\n            float tMax = input.TMax;\n\n            float totalRadius = input.ProxyA.Radius + input.ProxyB.Radius;\n            float target = Math.Max(Settings.LinearSlop, totalRadius - 3.0f * Settings.LinearSlop);\n            const float tolerance = 0.25f * Settings.LinearSlop;\n            Debug.Assert(target > tolerance);\n\n            float t1 = 0.0f;\n            const int k_maxIterations = 20;\n            int iter = 0;\n\n            // Prepare input for distance query.\n            DistanceInput distanceInput = new DistanceInput();\n            distanceInput.ProxyA = input.ProxyA;\n            distanceInput.ProxyB = input.ProxyB;\n            distanceInput.UseRadii = false;\n\n            // The outer loop progressively attempts to compute new separating axes.\n            // This loop terminates when an axis is repeated (no progress is made).\n            for (;;)\n            {\n                Transform xfA, xfB;\n                sweepA.GetTransform(out xfA, t1);\n                sweepB.GetTransform(out xfB, t1);\n\n                // Get the distance between shapes. We can also use the results\n                // to get a separating axis.\n                distanceInput.TransformA = xfA;\n                distanceInput.TransformB = xfB;\n                DistanceOutput distanceOutput;\n                SimplexCache cache;\n                DistanceGJK.ComputeDistance(ref distanceInput, out distanceOutput, out cache);\n\n                // If the shapes are overlapped, we give up on continuous collision.\n                if (distanceOutput.Distance <= 0.0f)\n                {\n                    // Failure!\n                    output.State = TOIOutputState.Overlapped;\n                    output.T = 0.0f;\n                    break;\n                }\n\n                if (distanceOutput.Distance < target + tolerance)\n                {\n                    // Victory!\n                    output.State = TOIOutputState.Touching;\n                    output.T = t1;\n                    break;\n                }\n\n                SeparationFunction.Initialize(ref cache, input.ProxyA, ref sweepA, input.ProxyB, ref sweepB, t1, out Vector2 axis, out Vector2 localPoint, out SeparationFunctionType type);\n\n                // Compute the TOI on the separating axis. We do this by successively\n                // resolving the deepest point. This loop is bounded by the number of vertices.\n                bool done = false;\n                float t2 = tMax;\n                int pushBackIter = 0;\n                for (;;)\n                {\n                    // Find the deepest point at t2. Store the witness point indices.\n                    int indexA, indexB;\n                    float s2 = SeparationFunction.FindMinSeparation(out indexA, out indexB, t2, input.ProxyA, ref sweepA, input.ProxyB, ref sweepB, ref axis, ref localPoint, type);\n\n                    // Is the final configuration separated?\n                    if (s2 > target + tolerance)\n                    {\n                        // Victory!\n                        output.State = TOIOutputState.Seperated;\n                        output.T = tMax;\n                        done = true;\n                        break;\n                    }\n\n                    // Has the separation reached tolerance?\n                    if (s2 > target - tolerance)\n                    {\n                        // Advance the sweeps\n                        t1 = t2;\n                        break;\n                    }\n\n                    // Compute the initial separation of the witness points.\n                    float s1 = SeparationFunction.Evaluate(indexA, indexB, t1, input.ProxyA, ref sweepA, input.ProxyB, ref sweepB, ref axis, ref localPoint, type);\n\n                    // Check for initial overlap. This might happen if the root finder\n                    // runs out of iterations.\n                    if (s1 < target - tolerance)\n                    {\n                        output.State = TOIOutputState.Failed;\n                        output.T = t1;\n                        done = true;\n                        break;\n                    }\n\n                    // Check for touching\n                    if (s1 <= target + tolerance)\n                    {\n                        // Victory! t1 should hold the TOI (could be 0.0).\n                        output.State = TOIOutputState.Touching;\n                        output.T = t1;\n                        done = true;\n                        break;\n                    }\n\n                    // Compute 1D root of: f(x) - target = 0\n                    int rootIterCount = 0;\n                    float a1 = t1, a2 = t2;\n                    for (;;)\n                    {\n                        // Use a mix of the secant rule and bisection.\n                        float t;\n                        if ((rootIterCount & 1) != 0)\n                        {\n                            // Secant rule to improve convergence.\n                            t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);\n                        }\n                        else\n                        {\n                            // Bisection to guarantee progress.\n                            t = 0.5f * (a1 + a2);\n                        }\n\n                        ++rootIterCount;\n\n                        if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                            ++TOIRootIters;\n\n                        float s = SeparationFunction.Evaluate(indexA, indexB, t, input.ProxyA, ref sweepA, input.ProxyB, ref sweepB, ref axis, ref localPoint, type);\n\n                        if (Math.Abs(s - target) < tolerance)\n                        {\n                            // t2 holds a tentative value for t1\n                            t2 = t;\n                            break;\n                        }\n\n                        // Ensure we continue to bracket the root.\n                        if (s > target)\n                        {\n                            a1 = t;\n                            s1 = s;\n                        }\n                        else\n                        {\n                            a2 = t;\n                            s2 = s;\n                        }\n\n                        if (rootIterCount == 50)\n                        {\n                            break;\n                        }\n                    }\n\n                    if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                        TOIMaxRootIters = Math.Max(TOIMaxRootIters, rootIterCount);\n\n                    ++pushBackIter;\n\n                    if (pushBackIter == Settings.MaxPolygonVertices)\n                    {\n                        break;\n                    }\n                }\n\n                ++iter;\n\n                if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                    ++TOIIters;\n\n                if (done)\n                {\n                    break;\n                }\n\n                if (iter == k_maxIterations)\n                {\n                    // Root finder got stuck. Semi-victory.\n                    output.State = TOIOutputState.Failed;\n                    output.T = t1;\n                    break;\n                }\n            }\n\n            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled\n                TOIMaxIters = Math.Max(TOIMaxIters, iter);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Collision/TestPointHelper.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Collision\n{\n    public static class TestPointHelper\n    {\n        public static bool TestPointCircle(ref Vector2 pos, float radius, ref Vector2 point, ref Transform transform)\n        {\n            Vector2 center = transform.p + MathUtils.Mul(transform.q, pos);\n            Vector2 d = point - center;\n            return Vector2.Dot(d, d) <= radius * radius;\n        }\n\n        public static bool TestPointPolygon(Vertices vertices, Vertices normals, ref Vector2 point, ref Transform transform)\n        {\n            Vector2 pLocal = MathUtils.MulT(transform.q, point - transform.p);\n\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                float dot = Vector2.Dot(normals[i], pLocal - vertices[i]);\n                if (dot > 0.0f)\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Dynamics/Body.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Broadphase;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Filtering;\nusing VelcroPhysics.Collision.Handlers;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Collision.TOI;\nusing VelcroPhysics.Dynamics.Joints;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\nusing VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Templates;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics\n{\n    public class Body\n    {\n        private BodyType _type;\n        private float _inertia;\n        private float _mass;\n\n        internal BodyFlags _flags;\n        internal float _invI;\n        internal float _invMass;\n        internal Vector2 _force;\n        internal Vector2 _linearVelocity;\n        internal float _angularVelocity;\n        internal Sweep _sweep; // the swept motion for CCD\n        internal float _torque;\n        internal World _world;\n        public Transform _xf; // the body origin transform\n\n        internal Body(World world, BodyTemplate template)\n        {\n            FixtureList = new List<Fixture>(1);\n\n            if (template.AllowCCD)\n                _flags |= BodyFlags.BulletFlag;\n            if (template.AllowRotation)\n                _flags |= BodyFlags.FixedRotationFlag;\n            if (template.AllowSleep)\n                _flags |= BodyFlags.AutoSleepFlag;\n            if (template.Awake)\n                _flags |= BodyFlags.AwakeFlag;\n            if (template.Active)\n                _flags |= BodyFlags.Enabled;\n\n            _world = world;\n\n            _xf.p = template.Position;\n            _xf.q.Set(template.Angle);\n\n            _sweep.C0 = _xf.p;\n            _sweep.C = _xf.p;\n            _sweep.A0 = template.Angle;\n            _sweep.A = template.Angle;\n\n            _linearVelocity = template.LinearVelocity;\n            _angularVelocity = template.AngularVelocity;\n\n            LinearDamping = template.LinearDamping;\n            AngularDamping = template.AngularDamping;\n            GravityScale = 1.0f;\n\n            _type = template.Type;\n\n            if (_type == BodyType.Dynamic)\n            {\n                _mass = 1.0f;\n                _invMass = 1.0f;\n            }\n            else\n            {\n                _mass = 0.0f;\n                _invMass = 0.0f;\n            }\n\n            UserData = template.UserData;\n        }\n\n        public ControllerFilter ControllerFilter { get; set; }\n\n        public PhysicsLogicFilter PhysicsLogicFilter { get; set; }\n\n        /// <summary>\n        /// A unique id for this body.\n        /// </summary>\n        public int BodyId { get; internal set; }\n\n        public float SleepTime { get; set; }\n\n        public int IslandIndex { get; set; }\n\n        /// <summary>\n        /// Scale the gravity applied to this body.\n        /// Defaults to 1. A value of 2 means double the gravity is applied to this body.\n        /// </summary>\n        public float GravityScale { get; set; }\n\n        /// <summary>\n        /// Set the user data. Use this to store your application specific data.\n        /// </summary>\n        /// <value>The user data.</value>\n        public object UserData { get; set; }\n\n        /// <summary>\n        /// Gets the total number revolutions the body has made.\n        /// </summary>\n        /// <value>The revolutions.</value>\n        public float Revolutions => Rotation / (float)Math.PI;\n\n        /// <summary>\n        /// Gets or sets the body type.\n        /// Warning: Calling this mid-update might cause a crash.\n        /// </summary>\n        /// <value>The type of body.</value>\n        public BodyType BodyType\n        {\n            get { return _type; }\n            set\n            {\n                if (value == _type)\n                    return;\n\n                _type = value;\n\n                ResetMassData();\n\n                if (_type == BodyType.Static)\n                {\n                    _linearVelocity = Vector2.Zero;\n                    _angularVelocity = 0.0f;\n                    _sweep.A0 = _sweep.A;\n                    _sweep.C0 = _sweep.C;\n                    SynchronizeFixtures();\n                }\n\n                Awake = true;\n\n                _force = Vector2.Zero;\n                _torque = 0.0f;\n\n                // Delete the attached contacts.\n                ContactEdge ce = ContactList;\n                while (ce != null)\n                {\n                    ContactEdge ce0 = ce;\n                    ce = ce.Next;\n                    _world.ContactManager.Destroy(ce0.Contact);\n                }\n\n                ContactList = null;\n\n                // Touch the proxies so that new contacts will be created (when appropriate)\n                IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n                foreach (Fixture fixture in FixtureList)\n                {\n                    int proxyCount = fixture.ProxyCount;\n                    for (int j = 0; j < proxyCount; j++)\n                    {\n                        broadPhase.TouchProxy(fixture.Proxies[j].ProxyId);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get or sets the linear velocity of the center of mass.\n        /// </summary>\n        /// <value>The linear velocity.</value>\n        public Vector2 LinearVelocity\n        {\n            get { return _linearVelocity; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value.X) && !float.IsNaN(value.Y));\n\n                if (_type == BodyType.Static)\n                    return;\n\n                if (Vector2.Dot(value, value) > 0.0f)\n                    Awake = true;\n\n                _linearVelocity = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the angular velocity. Radians/second.\n        /// </summary>\n        /// <value>The angular velocity.</value>\n        public float AngularVelocity\n        {\n            get { return _angularVelocity; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                if (_type == BodyType.Static)\n                    return;\n\n                if (value * value > 0.0f)\n                    Awake = true;\n\n                _angularVelocity = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the linear damping.\n        /// </summary>\n        /// <value>The linear damping.</value>\n        public float LinearDamping { get; set; }\n\n        /// <summary>\n        /// Gets or sets the angular damping.\n        /// </summary>\n        /// <value>The angular damping.</value>\n        public float AngularDamping { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this body should be included in the CCD solver.\n        /// </summary>\n        /// <value><c>true</c> if this instance is included in CCD; otherwise, <c>false</c>.</value>\n        public bool IsBullet\n        {\n            get { return (_flags & BodyFlags.BulletFlag) == BodyFlags.BulletFlag; }\n            set\n            {\n                if (value)\n                    _flags |= BodyFlags.BulletFlag;\n                else\n                    _flags &= ~BodyFlags.BulletFlag;\n            }\n        }\n\n        /// <summary>\n        /// You can disable sleeping on this body. If you disable sleeping, the\n        /// body will be woken.\n        /// </summary>\n        /// <value><c>true</c> if sleeping is allowed; otherwise, <c>false</c>.</value>\n        public bool SleepingAllowed\n        {\n            get { return (_flags & BodyFlags.AutoSleepFlag) == BodyFlags.AutoSleepFlag; }\n            set\n            {\n                if (value)\n                    _flags |= BodyFlags.AutoSleepFlag;\n                else\n                {\n                    _flags &= ~BodyFlags.AutoSleepFlag;\n                    Awake = true;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Set the sleep state of the body. A sleeping body has very\n        /// low CPU cost.\n        /// </summary>\n        /// <value><c>true</c> if awake; otherwise, <c>false</c>.</value>\n        public bool Awake\n        {\n            get { return (_flags & BodyFlags.AwakeFlag) == BodyFlags.AwakeFlag; }\n            set\n            {\n                if (value)\n                {\n                    _flags |= BodyFlags.AwakeFlag;\n                    SleepTime = 0.0f;\n                }\n                else\n                {\n                    _flags &= ~BodyFlags.AwakeFlag;\n                    ResetDynamics();\n                    SleepTime = 0.0f;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Set the active state of the body. An inactive body is not\n        /// simulated and cannot be collided with or woken up.\n        /// If you pass a flag of true, all fixtures will be added to the\n        /// broad-phase.\n        /// If you pass a flag of false, all fixtures will be removed from\n        /// the broad-phase and all contacts will be destroyed.\n        /// Fixtures and joints are otherwise unaffected. You may continue\n        /// to create/destroy fixtures and joints on inactive bodies.\n        /// Fixtures on an inactive body are implicitly inactive and will\n        /// not participate in collisions, ray-casts, or queries.\n        /// Joints connected to an inactive body are implicitly inactive.\n        /// An inactive body is still owned by a b2World object and remains\n        /// in the body list.\n        /// </summary>\n        /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>\n        public bool Enabled\n        {\n            get { return (_flags & BodyFlags.Enabled) == BodyFlags.Enabled; }\n\n            set\n            {\n                if (value == Enabled)\n                    return;\n\n                if (value)\n                {\n                    _flags |= BodyFlags.Enabled;\n\n                    // Create all proxies.\n                    IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n                    for (int i = 0; i < FixtureList.Count; i++)\n                    {\n                        FixtureList[i].CreateProxies(broadPhase, ref _xf);\n                    }\n\n                    // Contacts are created the next time step.\n                }\n                else\n                {\n                    _flags &= ~BodyFlags.Enabled;\n\n                    // Destroy all proxies.\n                    IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n\n                    for (int i = 0; i < FixtureList.Count; i++)\n                    {\n                        FixtureList[i].DestroyProxies(broadPhase);\n                    }\n\n                    // Destroy the attached contacts.\n                    ContactEdge ce = ContactList;\n                    while (ce != null)\n                    {\n                        ContactEdge ce0 = ce;\n                        ce = ce.Next;\n                        _world.ContactManager.Destroy(ce0.Contact);\n                    }\n                    ContactList = null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Set this body to have fixed rotation. This causes the mass\n        /// to be reset.\n        /// </summary>\n        /// <value><c>true</c> if it has fixed rotation; otherwise, <c>false</c>.</value>\n        public bool FixedRotation\n        {\n            get { return (_flags & BodyFlags.FixedRotationFlag) == BodyFlags.FixedRotationFlag; }\n            set\n            {\n                if (value == FixedRotation)\n                    return;\n\n                if (value)\n                    _flags |= BodyFlags.FixedRotationFlag;\n                else\n                    _flags &= ~BodyFlags.FixedRotationFlag;\n\n                _angularVelocity = 0f;\n                ResetMassData();\n            }\n        }\n\n        /// <summary>\n        /// Gets all the fixtures attached to this body.\n        /// </summary>\n        /// <value>The fixture list.</value>\n        public List<Fixture> FixtureList { get; internal set; }\n\n        /// <summary>\n        /// Get the list of all joints attached to this body.\n        /// </summary>\n        /// <value>The joint list.</value>\n        public JointEdge JointList { get; internal set; }\n\n        /// <summary>\n        /// Get the list of all contacts attached to this body.\n        /// Warning: this list changes during the time step and you may\n        /// miss some collisions if you don't use ContactListener.\n        /// </summary>\n        /// <value>The contact list.</value>\n        public ContactEdge ContactList { get; internal set; }\n\n        /// <summary>\n        /// Get the world body origin position.\n        /// </summary>\n        /// <returns>Return the world position of the body's origin.</returns>\n        public Vector2 Position\n        {\n            get { return _xf.p; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value.X) && !float.IsNaN(value.Y));\n\n                SetTransform(ref value, Rotation);\n            }\n        }\n\n        /// <summary>\n        /// Get the angle in radians.\n        /// </summary>\n        /// <returns>Return the current world rotation angle in radians.</returns>\n        public float Rotation\n        {\n            get { return _sweep.A; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                SetTransform(ref _xf.p, value);\n            }\n        }\n\n        //Velcro: We don't add a setter here since it requires a branch, and we only use it internally\n        internal bool IsIsland => (_flags & BodyFlags.IslandFlag) == BodyFlags.IslandFlag;\n\n        public bool IsStatic => _type == BodyType.Static;\n\n        public bool IsKinematic => _type == BodyType.Kinematic;\n\n        public bool IsDynamic => _type == BodyType.Dynamic;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this body ignores gravity.\n        /// </summary>\n        /// <value><c>true</c> if it ignores gravity; otherwise, <c>false</c>.</value>\n        public bool IgnoreGravity\n        {\n            get { return (_flags & BodyFlags.IgnoreGravity) == BodyFlags.IgnoreGravity; }\n            set\n            {\n                if (value)\n                    _flags |= BodyFlags.IgnoreGravity;\n                else\n                    _flags &= ~BodyFlags.IgnoreGravity;\n            }\n        }\n\n        /// <summary>\n        /// Get the world position of the center of mass.\n        /// </summary>\n        /// <value>The world position.</value>\n        public Vector2 WorldCenter => _sweep.C;\n\n        /// <summary>\n        /// Get the local position of the center of mass.\n        /// </summary>\n        /// <value>The local position.</value>\n        public Vector2 LocalCenter\n        {\n            get { return _sweep.LocalCenter; }\n            set\n            {\n                if (_type != BodyType.Dynamic)\n                    return;\n\n                //Velcro: We support setting the mass independently\n\n                // Move center of mass.\n                Vector2 oldCenter = _sweep.C;\n                _sweep.LocalCenter = value;\n                _sweep.C0 = _sweep.C = MathUtils.Mul(ref _xf, ref _sweep.LocalCenter);\n\n                // Update center of mass velocity.\n                Vector2 a = _sweep.C - oldCenter;\n                _linearVelocity += new Vector2(-_angularVelocity * a.Y, _angularVelocity * a.X);\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the mass. Usually in kilograms (kg).\n        /// </summary>\n        /// <value>The mass.</value>\n        public float Mass\n        {\n            get { return _mass; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                if (_type != BodyType.Dynamic)\n                    return;\n\n                //Velcro: We support setting the mass independently\n                _mass = value;\n\n                if (_mass <= 0.0f)\n                    _mass = 1.0f;\n\n                _invMass = 1.0f / _mass;\n            }\n        }\n\n        /// <summary>\n        /// Get or set the rotational inertia of the body about the local origin. usually in kg-m^2.\n        /// </summary>\n        /// <value>The inertia.</value>\n        public float Inertia\n        {\n            get { return _inertia + _mass * Vector2.Dot(_sweep.LocalCenter, _sweep.LocalCenter); }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                if (_type != BodyType.Dynamic)\n                    return;\n\n                //Velcro: We support setting the inertia independently\n                if (value > 0.0f && !FixedRotation)\n                {\n                    _inertia = value - _mass * Vector2.Dot(_sweep.LocalCenter, _sweep.LocalCenter);\n                    Debug.Assert(_inertia > 0.0f);\n                    _invI = 1.0f / _inertia;\n                }\n            }\n        }\n\n        public float Restitution\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.Restitution = value;\n                }\n            }\n        }\n\n        public float Friction\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.Friction = value;\n                }\n            }\n        }\n\n        public Category CollisionCategories\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.CollisionCategories = value;\n                }\n            }\n        }\n\n        public Category CollidesWith\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.CollidesWith = value;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Body objects can define which categories of bodies they wish to ignore CCD with.\n        /// This allows certain bodies to be configured to ignore CCD with objects that\n        /// aren't a penetration problem due to the way content has been prepared.\n        /// This is compared against the other Body's fixture CollisionCategories within World.SolveTOI().\n        /// </summary>\n        public Category IgnoreCCDWith\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.IgnoreCCDWith = value;\n                }\n            }\n        }\n\n        public short CollisionGroup\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.CollisionGroup = value;\n                }\n            }\n        }\n\n        public bool IsSensor\n        {\n            set\n            {\n                for (int i = 0; i < FixtureList.Count; i++)\n                {\n                    Fixture f = FixtureList[i];\n                    f.IsSensor = value;\n                }\n            }\n        }\n\n        public bool IgnoreCCD\n        {\n            get { return (_flags & BodyFlags.IgnoreCCD) == BodyFlags.IgnoreCCD; }\n            set\n            {\n                if (value)\n                    _flags |= BodyFlags.IgnoreCCD;\n                else\n                    _flags &= ~BodyFlags.IgnoreCCD;\n            }\n        }\n\n        /// <summary>\n        /// Resets the dynamics of this body.\n        /// Sets torque, force and linear/angular velocity to 0\n        /// </summary>\n        public void ResetDynamics()\n        {\n            _torque = 0;\n            _angularVelocity = 0;\n            _force = Vector2.Zero;\n            _linearVelocity = Vector2.Zero;\n        }\n\n        /// <summary>\n        /// Creates a fixture and attach it to this body.\n        /// If the density is non-zero, this function automatically updates the mass of the body.\n        /// Contacts are not created until the next time step.\n        /// Warning: This function is locked during callbacks.\n        /// </summary>\n        public Fixture CreateFixture(FixtureTemplate template)\n        {\n            Fixture f = new Fixture(this, template);\n            f.FixtureId = _world._fixtureIdCounter++;\n            return f;\n        }\n\n        public Fixture CreateFixture(Shape shape, object userData = null)\n        {\n            FixtureTemplate template = new FixtureTemplate();\n            template.Shape = shape;\n            template.UserData = userData;\n\n            return CreateFixture(template);\n        }\n\n        /// <summary>\n        /// Destroy a fixture. This removes the fixture from the broad-phase and\n        /// destroys all contacts associated with this fixture. This will\n        /// automatically adjust the mass of the body if the body is dynamic and the\n        /// fixture has positive density.\n        /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.\n        /// Warning: This function is locked during callbacks.\n        /// </summary>\n        /// <param name=\"fixture\">The fixture to be removed.</param>\n        public void DestroyFixture(Fixture fixture)\n        {\n            if (fixture == null)\n                return;\n\n            Debug.Assert(fixture.Body == this);\n\n            // Remove the fixture from this body's singly linked list.\n            Debug.Assert(FixtureList.Count > 0);\n\n            // You tried to remove a fixture that not present in the fixturelist.\n            Debug.Assert(FixtureList.Contains(fixture));\n\n            // Destroy any contacts associated with the fixture.\n            ContactEdge edge = ContactList;\n            while (edge != null)\n            {\n                Contact c = edge.Contact;\n                edge = edge.Next;\n\n                Fixture fixtureA = c.FixtureA;\n                Fixture fixtureB = c.FixtureB;\n\n                if (fixture == fixtureA || fixture == fixtureB)\n                {\n                    // This destroys the contact and removes it from\n                    // this body's contact list.\n                    _world.ContactManager.Destroy(c);\n                }\n            }\n\n            if (Enabled)\n            {\n                IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n                fixture.DestroyProxies(broadPhase);\n            }\n\n            FixtureList.Remove(fixture);\n            fixture.Destroy();\n            fixture.Body = null;\n\n            ResetMassData();\n        }\n\n        /// <summary>\n        /// Set the position of the body's origin and rotation.\n        /// This breaks any contacts and wakes the other bodies.\n        /// Manipulating a body's transform may cause non-physical behavior.\n        /// </summary>\n        /// <param name=\"position\">The world position of the body's local origin.</param>\n        /// <param name=\"rotation\">The world rotation in radians.</param>\n        public void SetTransform(ref Vector2 position, float rotation)\n        {\n            SetTransformIgnoreContacts(ref position, rotation);\n\n            //Velcro: We check for new contacts after a body has been moved.\n            _world.ContactManager.FindNewContacts();\n        }\n\n        /// <summary>\n        /// Set the position of the body's origin and rotation.\n        /// This breaks any contacts and wakes the other bodies.\n        /// Manipulating a body's transform may cause non-physical behavior.\n        /// </summary>\n        /// <param name=\"position\">The world position of the body's local origin.</param>\n        /// <param name=\"rotation\">The world rotation in radians.</param>\n        public void SetTransform(Vector2 position, float rotation)\n        {\n            SetTransform(ref position, rotation);\n        }\n\n        /// <summary>\n        /// For teleporting a body without considering new contacts immediately.\n        /// </summary>\n        /// <param name=\"position\">The position.</param>\n        /// <param name=\"angle\">The angle.</param>\n        public void SetTransformIgnoreContacts(ref Vector2 position, float angle)\n        {\n            _xf.q.Set(angle);\n            _xf.p = position;\n\n            _sweep.C = MathUtils.Mul(ref _xf, _sweep.LocalCenter);\n            _sweep.A = angle;\n\n            _sweep.C0 = _sweep.C;\n            _sweep.A0 = angle;\n\n            IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n            for (int i = 0; i < FixtureList.Count; i++)\n            {\n                FixtureList[i].Synchronize(broadPhase, ref _xf, ref _xf);\n            }\n        }\n\n        /// <summary>\n        /// Get the body transform for the body's origin.\n        /// </summary>\n        /// <param name=\"transform\">The transform of the body's origin.</param>\n        public void GetTransform(out Transform transform)\n        {\n            transform = _xf;\n        }\n\n        /// <summary>\n        /// Apply a force at a world point. If the force is not\n        /// applied at the center of mass, it will generate a torque and\n        /// affect the angular velocity. This wakes up the body.\n        /// </summary>\n        /// <param name=\"force\">The world force vector, usually in Newtons (N).</param>\n        /// <param name=\"point\">The world position of the point of application.</param>\n        public void ApplyForce(Vector2 force, Vector2 point)\n        {\n            ApplyForce(ref force, ref point);\n        }\n\n        /// <summary>\n        /// Applies a force at the center of mass.\n        /// </summary>\n        /// <param name=\"force\">The force.</param>\n        public void ApplyForce(ref Vector2 force)\n        {\n            ApplyForce(ref force, ref _xf.p);\n        }\n\n        /// <summary>\n        /// Applies a force at the center of mass.\n        /// </summary>\n        /// <param name=\"force\">The force.</param>\n        public void ApplyForce(Vector2 force)\n        {\n            ApplyForce(ref force, ref _xf.p);\n        }\n\n        /// <summary>\n        /// Apply a force at a world point. If the force is not\n        /// applied at the center of mass, it will generate a torque and\n        /// affect the angular velocity. This wakes up the body.\n        /// </summary>\n        /// <param name=\"force\">The world force vector, usually in Newtons (N).</param>\n        /// <param name=\"point\">The world position of the point of application.</param>\n        public void ApplyForce(ref Vector2 force, ref Vector2 point)\n        {\n            Debug.Assert(!float.IsNaN(force.X));\n            Debug.Assert(!float.IsNaN(force.Y));\n            Debug.Assert(!float.IsNaN(point.X));\n            Debug.Assert(!float.IsNaN(point.Y));\n\n            if (_type != BodyType.Dynamic)\n                return;\n\n            //Velcro: We always wake the body. You told it to move.\n            if (Awake == false)\n                Awake = true;\n\n            _force += force;\n            _torque += MathUtils.Cross(point - _sweep.C, force);\n        }\n\n        /// <summary>\n        /// Apply a torque. This affects the angular velocity\n        /// without affecting the linear velocity of the center of mass.\n        /// </summary>\n        /// <param name=\"torque\">The torque about the z-axis (out of the screen), usually in N-m.</param>\n        public void ApplyTorque(float torque)\n        {\n            Debug.Assert(!float.IsNaN(torque));\n\n            if (BodyType != BodyType.Dynamic)\n                return;\n\n            //Velcro: We always wake the body. You told it to move.\n            if (Awake == false)\n                Awake = true;\n\n            _torque += torque;\n        }\n\n        /// <summary>\n        /// Apply an impulse at a point. This immediately modifies the velocity.\n        /// This wakes up the body.\n        /// </summary>\n        /// <param name=\"impulse\">The world impulse vector, usually in N-seconds or kg-m/s.</param>\n        public void ApplyLinearImpulse(Vector2 impulse)\n        {\n            ApplyLinearImpulse(ref impulse);\n        }\n\n        /// <summary>\n        /// Apply an impulse at a point. This immediately modifies the velocity.\n        /// It also modifies the angular velocity if the point of application\n        /// is not at the center of mass.\n        /// This wakes up the body.\n        /// </summary>\n        /// <param name=\"impulse\">The world impulse vector, usually in N-seconds or kg-m/s.</param>\n        /// <param name=\"point\">The world position of the point of application.</param>\n        public void ApplyLinearImpulse(Vector2 impulse, Vector2 point)\n        {\n            ApplyLinearImpulse(ref impulse, ref point);\n        }\n\n        /// <summary>\n        /// Apply an impulse at a point. This immediately modifies the velocity.\n        /// This wakes up the body.\n        /// </summary>\n        /// <param name=\"impulse\">The world impulse vector, usually in N-seconds or kg-m/s.</param>\n        public void ApplyLinearImpulse(ref Vector2 impulse)\n        {\n            if (_type != BodyType.Dynamic)\n                return;\n\n            //Velcro: We always wake the body. You told it to move.\n            if (Awake == false)\n                Awake = true;\n\n            _linearVelocity += _invMass * impulse;\n        }\n\n        /// <summary>\n        /// Apply an impulse at a point. This immediately modifies the velocity.\n        /// It also modifies the angular velocity if the point of application\n        /// is not at the center of mass.\n        /// This wakes up the body.\n        /// </summary>\n        /// <param name=\"impulse\">The world impulse vector, usually in N-seconds or kg-m/s.</param>\n        /// <param name=\"point\">The world position of the point of application.</param>\n        public void ApplyLinearImpulse(ref Vector2 impulse, ref Vector2 point)\n        {\n            if (_type != BodyType.Dynamic)\n                return;\n\n            //Velcro: We always wake the body. You told it to move.\n            if (Awake == false)\n                Awake = true;\n\n            _linearVelocity += _invMass * impulse;\n            _angularVelocity += _invI * MathUtils.Cross(point - _sweep.C, impulse);\n        }\n\n        /// <summary>\n        /// Apply an angular impulse.\n        /// </summary>\n        /// <param name=\"impulse\">The angular impulse in units of kg*m*m/s.</param>\n        public void ApplyAngularImpulse(float impulse)\n        {\n            if (_type != BodyType.Dynamic)\n                return;\n\n            //Velcro: We always wake the body. You told it to move.\n            if (Awake == false)\n                Awake = true;\n\n            _angularVelocity += _invI * impulse;\n        }\n\n        /// <summary>\n        /// This resets the mass properties to the sum of the mass properties of the fixtures.\n        /// This normally does not need to be called unless you called SetMassData to override\n        /// the mass and you later want to reset the mass.\n        /// </summary>\n        public void ResetMassData()\n        {\n            // Compute mass data from shapes. Each shape has its own density.\n            _mass = 0.0f;\n            _invMass = 0.0f;\n            _inertia = 0.0f;\n            _invI = 0.0f;\n            _sweep.LocalCenter = Vector2.Zero;\n\n            //Velcro: We have mass on static bodies to support attaching joints to them\n            // Kinematic bodies have zero mass.\n            if (BodyType == BodyType.Kinematic)\n            {\n                _sweep.C0 = _xf.p;\n                _sweep.C = _xf.p;\n                _sweep.A0 = _sweep.A;\n                return;\n            }\n\n            Debug.Assert(BodyType == BodyType.Dynamic || BodyType == BodyType.Static);\n\n            // Accumulate mass over all fixtures.\n            Vector2 localCenter = Vector2.Zero;\n            foreach (Fixture f in FixtureList)\n            {\n                if (f.Shape._density == 0.0f)\n                    continue;\n\n                MassData massData = f.Shape.MassData;\n                _mass += massData.Mass;\n                localCenter += massData.Mass * massData.Centroid;\n                _inertia += massData.Inertia;\n            }\n\n            //Velcro: Static bodies only have mass, they don't have other properties. A little hacky tho...\n            if (BodyType == BodyType.Static)\n            {\n                _sweep.C0 = _sweep.C = _xf.p;\n                return;\n            }\n\n            // Compute center of mass.\n            if (_mass > 0.0f)\n            {\n                _invMass = 1.0f / _mass;\n                localCenter *= _invMass;\n            }\n            else\n            {\n                // Force all bodies to have a positive mass.\n                _mass = 1.0f;\n                _invMass = 1.0f;\n            }\n\n            if (_inertia > 0.0f && (_flags & BodyFlags.FixedRotationFlag) == 0)\n            {\n                // Center the inertia about the center of mass.\n                _inertia -= _mass * Vector2.Dot(localCenter, localCenter);\n\n                Debug.Assert(_inertia > 0.0f);\n                _invI = 1.0f / _inertia;\n            }\n            else\n            {\n                _inertia = 0.0f;\n                _invI = 0.0f;\n            }\n\n            // Move center of mass.\n            Vector2 oldCenter = _sweep.C;\n            _sweep.LocalCenter = localCenter;\n            _sweep.C0 = _sweep.C = MathUtils.Mul(ref _xf, ref _sweep.LocalCenter);\n\n            // Update center of mass velocity.\n            Vector2 a = _sweep.C - oldCenter;\n            _linearVelocity += new Vector2(-_angularVelocity * a.Y, _angularVelocity * a.X);\n        }\n\n        /// <summary>\n        /// Get the world coordinates of a point given the local coordinates.\n        /// </summary>\n        /// <param name=\"localPoint\">A point on the body measured relative the body's origin.</param>\n        /// <returns>The same point expressed in world coordinates.</returns>\n        public Vector2 GetWorldPoint(ref Vector2 localPoint)\n        {\n            return MathUtils.Mul(ref _xf, ref localPoint);\n        }\n\n        /// <summary>\n        /// Get the world coordinates of a point given the local coordinates.\n        /// </summary>\n        /// <param name=\"localPoint\">A point on the body measured relative the body's origin.</param>\n        /// <returns>The same point expressed in world coordinates.</returns>\n        public Vector2 GetWorldPoint(Vector2 localPoint)\n        {\n            return GetWorldPoint(ref localPoint);\n        }\n\n        /// <summary>\n        /// Get the world coordinates of a vector given the local coordinates.\n        /// Note that the vector only takes the rotation into account, not the position.\n        /// </summary>\n        /// <param name=\"localVector\">A vector fixed in the body.</param>\n        /// <returns>The same vector expressed in world coordinates.</returns>\n        public Vector2 GetWorldVector(ref Vector2 localVector)\n        {\n            return MathUtils.Mul(ref _xf.q, localVector);\n        }\n\n        /// <summary>\n        /// Get the world coordinates of a vector given the local coordinates.\n        /// </summary>\n        /// <param name=\"localVector\">A vector fixed in the body.</param>\n        /// <returns>The same vector expressed in world coordinates.</returns>\n        public Vector2 GetWorldVector(Vector2 localVector)\n        {\n            return GetWorldVector(ref localVector);\n        }\n\n        /// <summary>\n        /// Gets a local point relative to the body's origin given a world point.\n        /// Note that the vector only takes the rotation into account, not the position.\n        /// </summary>\n        /// <param name=\"worldPoint\">A point in world coordinates.</param>\n        /// <returns>The corresponding local point relative to the body's origin.</returns>\n        public Vector2 GetLocalPoint(ref Vector2 worldPoint)\n        {\n            return MathUtils.MulT(ref _xf, worldPoint);\n        }\n\n        /// <summary>\n        /// Gets a local point relative to the body's origin given a world point.\n        /// </summary>\n        /// <param name=\"worldPoint\">A point in world coordinates.</param>\n        /// <returns>The corresponding local point relative to the body's origin.</returns>\n        public Vector2 GetLocalPoint(Vector2 worldPoint)\n        {\n            return GetLocalPoint(ref worldPoint);\n        }\n\n        /// <summary>\n        /// Gets a local vector given a world vector.\n        /// Note that the vector only takes the rotation into account, not the position.\n        /// </summary>\n        /// <param name=\"worldVector\">A vector in world coordinates.</param>\n        /// <returns>The corresponding local vector.</returns>\n        public Vector2 GetLocalVector(ref Vector2 worldVector)\n        {\n            return MathUtils.MulT(_xf.q, worldVector);\n        }\n\n        /// <summary>\n        /// Gets a local vector given a world vector.\n        /// Note that the vector only takes the rotation into account, not the position.\n        /// </summary>\n        /// <param name=\"worldVector\">A vector in world coordinates.</param>\n        /// <returns>The corresponding local vector.</returns>\n        public Vector2 GetLocalVector(Vector2 worldVector)\n        {\n            return GetLocalVector(ref worldVector);\n        }\n\n        /// <summary>\n        /// Get the world linear velocity of a world point attached to this body.\n        /// </summary>\n        /// <param name=\"worldPoint\">A point in world coordinates.</param>\n        /// <returns>The world velocity of a point.</returns>\n        public Vector2 GetLinearVelocityFromWorldPoint(Vector2 worldPoint)\n        {\n            return GetLinearVelocityFromWorldPoint(ref worldPoint);\n        }\n\n        /// <summary>\n        /// Get the world linear velocity of a world point attached to this body.\n        /// </summary>\n        /// <param name=\"worldPoint\">A point in world coordinates.</param>\n        /// <returns>The world velocity of a point.</returns>\n        public Vector2 GetLinearVelocityFromWorldPoint(ref Vector2 worldPoint)\n        {\n            return _linearVelocity + MathUtils.Cross(_angularVelocity, worldPoint - _sweep.C);\n        }\n\n        /// <summary>\n        /// Get the world velocity of a local point.\n        /// </summary>\n        /// <param name=\"localPoint\">A point in local coordinates.</param>\n        /// <returns>The world velocity of a point.</returns>\n        public Vector2 GetLinearVelocityFromLocalPoint(Vector2 localPoint)\n        {\n            return GetLinearVelocityFromLocalPoint(ref localPoint);\n        }\n\n        /// <summary>\n        /// Get the world velocity of a local point.\n        /// </summary>\n        /// <param name=\"localPoint\">A point in local coordinates.</param>\n        /// <returns>The world velocity of a point.</returns>\n        public Vector2 GetLinearVelocityFromLocalPoint(ref Vector2 localPoint)\n        {\n            return GetLinearVelocityFromWorldPoint(GetWorldPoint(ref localPoint));\n        }\n\n        internal void SynchronizeFixtures()\n        {\n            Transform xf1 = new Transform();\n            xf1.q.Set(_sweep.A0);\n            xf1.p = _sweep.C0 - MathUtils.Mul(xf1.q, _sweep.LocalCenter);\n\n            IBroadPhase broadPhase = _world.ContactManager.BroadPhase;\n            for (int i = 0; i < FixtureList.Count; i++)\n            {\n                FixtureList[i].Synchronize(broadPhase, ref xf1, ref _xf);\n            }\n        }\n\n        internal void SynchronizeTransform()\n        {\n            _xf.q.Set(_sweep.A);\n            _xf.p = _sweep.C - MathUtils.Mul(_xf.q, _sweep.LocalCenter);\n        }\n\n        /// <summary>\n        /// This is used to prevent connected bodies from colliding.\n        /// It may lie, depending on the collideConnected flag.\n        /// </summary>\n        /// <param name=\"other\">The other body.</param>\n        internal bool ShouldCollide(Body other)\n        {\n            // At least one body should be dynamic.\n            if (_type != BodyType.Dynamic && other._type != BodyType.Dynamic)\n            {\n                return false;\n            }\n\n            // Does a joint prevent collision?\n            for (JointEdge jn = JointList; jn != null; jn = jn.Next)\n            {\n                if (jn.Other == other)\n                {\n                    if (jn.Joint.CollideConnected == false)\n                    {\n                        return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n\n        internal void Advance(float alpha)\n        {\n            // Advance to the new safe time. This doesn't sync the broad-phase.\n            _sweep.Advance(alpha);\n            _sweep.C = _sweep.C0;\n            _sweep.A = _sweep.A0;\n            _xf.q.Set(_sweep.A);\n            _xf.p = _sweep.C - MathUtils.Mul(_xf.q, _sweep.LocalCenter);\n        }\n\n        public event OnCollisionHandler OnCollision\n        {\n            add\n            {\n                foreach (Fixture f in FixtureList)\n                {\n                    f.OnCollision += value;\n                }\n            }\n            remove\n            {\n                foreach (Fixture f in FixtureList)\n                {\n                    f.OnCollision -= value;\n                }\n            }\n        }\n\n        public event OnSeparationHandler OnSeparation\n        {\n            add\n            {\n                foreach (Fixture f in FixtureList)\n                {\n                    f.OnSeparation += value;\n                }\n            }\n            remove\n            {\n                foreach (Fixture f in FixtureList)\n                {\n                    f.OnSeparation -= value;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/BodyFlags.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Dynamics\n{\n    [Flags]\n    public enum BodyFlags : byte\n    {\n        Unknown = 0,\n        IslandFlag = 1,\n        AwakeFlag = 2,\n        AutoSleepFlag = 4,\n        BulletFlag = 8,\n        FixedRotationFlag = 16,\n        Enabled = 32,\n        IgnoreGravity = 64,\n        IgnoreCCD = 128\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/BodyType.cs",
    "content": "namespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// The body type.\n    /// </summary>\n    public enum BodyType\n    {\n        /// <summary>\n        /// Zero velocity, may be manually moved. Note: even static bodies have mass.\n        /// </summary>\n        Static,\n\n        /// <summary>\n        /// Zero mass, non-zero velocity set by user, moved by solver\n        /// </summary>\n        Kinematic,\n\n        /// <summary>\n        /// Positive mass, non-zero velocity determined by forces, moved by solver\n        /// </summary>\n        Dynamic\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Fixture.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Broadphase;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Filtering;\nusing VelcroPhysics.Collision.Handlers;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Templates;\n\nnamespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// A fixture is used to attach a Shape to a body for collision detection. A fixture\n    /// inherits its transform from its parent. Fixtures hold additional non-geometric data\n    /// such as friction, collision filters, etc.\n    /// Fixtures are created via Body.CreateFixture.\n    /// Warning: You cannot reuse fixtures.\n    /// </summary>\n    public class Fixture\n    {\n        internal Category _collidesWith;\n        internal Category _collisionCategories;\n        internal short _collisionGroup;\n        private float _friction;\n        private bool _isSensor;\n        private float _restitution;\n\n        /// <summary>\n        /// Fires after two shapes has collided and are solved. This gives you a chance to get the impact force.\n        /// </summary>\n        public AfterCollisionHandler AfterCollision;\n\n        /// <summary>\n        /// Fires when two fixtures are close to each other.\n        /// Due to how the broadphase works, this can be quite inaccurate as shapes are approximated using AABBs.\n        /// </summary>\n        public BeforeCollisionHandler BeforeCollision;\n\n        public Category IgnoreCCDWith;\n\n        /// <summary>\n        /// Fires when two shapes collide and a contact is created between them.\n        /// Note that the first fixture argument is always the fixture that the delegate is subscribed to.\n        /// </summary>\n        public OnCollisionHandler OnCollision;\n\n        /// <summary>\n        /// Fires when two shapes separate and a contact is removed between them.\n        /// Note: This can in some cases be called multiple times, as a fixture can have multiple contacts.\n        /// Note The first fixture argument is always the fixture that the delegate is subscribed to.\n        /// </summary>\n        public OnSeparationHandler OnSeparation;\n\n        public FixtureProxy[] Proxies;\n        public int ProxyCount;\n\n        internal Fixture()\n        {\n            _collisionCategories = Settings.DefaultFixtureCollisionCategories;\n            _collidesWith = Settings.DefaultFixtureCollidesWith;\n            _collisionGroup = 0;\n\n            IgnoreCCDWith = Settings.DefaultFixtureIgnoreCCDWith;\n        }\n\n        internal Fixture(Body body, FixtureTemplate template) : this()\n        {\n            UserData = template.UserData;\n            Friction = template.Friction;\n            Restitution = template.Restitution;\n\n            Body = body;\n            IsSensor = template.IsSensor;\n            Shape = template.Shape.Clone();\n\n            RegisterFixture();\n        }\n\n        /// <summary>\n        /// Defaults to 0\n        /// If Settings.UseFPECollisionCategories is set to false:\n        /// Collision groups allow a certain group of objects to never collide (negative)\n        /// or always collide (positive). Zero means no collision group. Non-zero group\n        /// filtering always wins against the mask bits.\n        /// If Settings.UseFPECollisionCategories is set to true:\n        /// If 2 fixtures are in the same collision group, they will not collide.\n        /// </summary>\n        public short CollisionGroup\n        {\n            set\n            {\n                if (_collisionGroup == value)\n                    return;\n\n                _collisionGroup = value;\n                Refilter();\n            }\n            get { return _collisionGroup; }\n        }\n\n        /// <summary>\n        /// Defaults to Category.All\n        /// The collision mask bits. This states the categories that this\n        /// fixture would accept for collision.\n        /// Use Settings.UseFPECollisionCategories to change the behavior.\n        /// </summary>\n        public Category CollidesWith\n        {\n            get { return _collidesWith; }\n\n            set\n            {\n                if (_collidesWith == value)\n                    return;\n\n                _collidesWith = value;\n                Refilter();\n            }\n        }\n\n        /// <summary>\n        /// The collision categories this fixture is a part of.\n        /// If Settings.UseFPECollisionCategories is set to false:\n        /// Defaults to Category.Cat1\n        /// If Settings.UseFPECollisionCategories is set to true:\n        /// Defaults to Category.All\n        /// </summary>\n        public Category CollisionCategories\n        {\n            get { return _collisionCategories; }\n\n            set\n            {\n                if (_collisionCategories == value)\n                    return;\n\n                _collisionCategories = value;\n                Refilter();\n            }\n        }\n\n        /// <summary>\n        /// Get the child Shape. You can modify the child Shape, however you should not change the\n        /// number of vertices because this will crash some collision caching mechanisms.\n        /// </summary>\n        /// <value>The shape.</value>\n        public Shape Shape { get; internal set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this fixture is a sensor.\n        /// </summary>\n        /// <value><c>true</c> if this instance is a sensor; otherwise, <c>false</c>.</value>\n        public bool IsSensor\n        {\n            get { return _isSensor; }\n            set\n            {\n                if (Body != null)\n                    Body.Awake = true;\n\n                _isSensor = value;\n            }\n        }\n\n        /// <summary>\n        /// Get the parent body of this fixture. This is null if the fixture is not attached.\n        /// </summary>\n        /// <value>The body.</value>\n        public Body Body { get; internal set; }\n\n        /// <summary>\n        /// Set the user data. Use this to store your application specific data.\n        /// </summary>\n        /// <value>The user data.</value>\n        public object UserData { get; set; }\n\n        /// <summary>\n        /// Set the coefficient of friction. This will _not_ change the friction of\n        /// existing contacts.\n        /// </summary>\n        /// <value>The friction.</value>\n        public float Friction\n        {\n            get { return _friction; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                _friction = value;\n            }\n        }\n\n        /// <summary>\n        /// Set the coefficient of restitution. This will not change the restitution of\n        /// existing contacts.\n        /// </summary>\n        /// <value>The restitution.</value>\n        public float Restitution\n        {\n            get { return _restitution; }\n            set\n            {\n                Debug.Assert(!float.IsNaN(value));\n\n                _restitution = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets a unique ID for this fixture.\n        /// </summary>\n        /// <value>The fixture id.</value>\n        public int FixtureId { get; internal set; }\n\n        /// <summary>\n        /// Contacts are persistent and will keep being persistent unless they are\n        /// flagged for filtering.\n        /// This methods flags all contacts associated with the body for filtering.\n        /// </summary>\n        private void Refilter()\n        {\n            // Flag associated contacts for filtering.\n            ContactEdge edge = Body.ContactList;\n            while (edge != null)\n            {\n                Contact contact = edge.Contact;\n                Fixture fixtureA = contact.FixtureA;\n                Fixture fixtureB = contact.FixtureB;\n                if (fixtureA == this || fixtureB == this)\n                {\n                    contact._flags |= ContactFlags.FilterFlag;\n                }\n\n                edge = edge.Next;\n            }\n\n            World world = Body._world;\n\n            if (world == null)\n            {\n                return;\n            }\n\n            // Touch each proxy so that new pairs may be created\n            IBroadPhase broadPhase = world.ContactManager.BroadPhase;\n            for (int i = 0; i < ProxyCount; ++i)\n            {\n                broadPhase.TouchProxy(Proxies[i].ProxyId);\n            }\n        }\n\n        private void RegisterFixture()\n        {\n            // Reserve proxy space\n            Proxies = new FixtureProxy[Shape.ChildCount];\n            ProxyCount = 0;\n\n            if (Body.Enabled)\n            {\n                IBroadPhase broadPhase = Body._world.ContactManager.BroadPhase;\n                CreateProxies(broadPhase, ref Body._xf);\n            }\n\n            Body.FixtureList.Add(this);\n\n            // Adjust mass properties if needed.\n            if (Shape._density > 0.0f)\n            {\n                Body.ResetMassData();\n            }\n\n            // Let the world know we have a new fixture. This will cause new contacts\n            // to be created at the beginning of the next time step.\n            Body._world._worldHasNewFixture = true;\n\n            //Velcro: Added event\n            Body._world.FixtureAdded?.Invoke(this);\n        }\n\n        /// <summary>\n        /// Test a point for containment in this fixture.\n        /// </summary>\n        /// <param name=\"point\">A point in world coordinates.</param>\n        /// <returns></returns>\n        public bool TestPoint(ref Vector2 point)\n        {\n            return Shape.TestPoint(ref Body._xf, ref point);\n        }\n\n        /// <summary>\n        /// Cast a ray against this Shape.\n        /// </summary>\n        /// <param name=\"output\">The ray-cast results.</param>\n        /// <param name=\"input\">The ray-cast input parameters.</param>\n        /// <param name=\"childIndex\">Index of the child.</param>\n        /// <returns></returns>\n        public bool RayCast(out RayCastOutput output, ref RayCastInput input, int childIndex)\n        {\n            return Shape.RayCast(ref input, ref Body._xf, childIndex, out output);\n        }\n\n        /// <summary>\n        /// Get the fixture's AABB. This AABB may be enlarge and/or stale.\n        /// If you need a more accurate AABB, compute it using the Shape and\n        /// the body transform.\n        /// </summary>\n        /// <param name=\"aabb\">The AABB.</param>\n        /// <param name=\"childIndex\">Index of the child.</param>\n        public void GetAABB(out AABB aabb, int childIndex)\n        {\n            Debug.Assert(0 <= childIndex && childIndex < ProxyCount);\n            aabb = Proxies[childIndex].AABB;\n        }\n\n        internal void Destroy()\n        {\n            // The proxies must be destroyed before calling this.\n            Debug.Assert(ProxyCount == 0);\n\n            // Free the proxy array.\n            Proxies = null;\n            Shape = null;\n\n            //Velcro: We set the userdata to null here to help prevent bugs related to stale references in GC\n            UserData = null;\n\n            BeforeCollision = null;\n            OnCollision = null;\n            OnSeparation = null;\n            AfterCollision = null;\n\n            Body._world.FixtureRemoved?.Invoke(this);\n\n            Body._world.FixtureAdded = null;\n            Body._world.FixtureRemoved = null;\n            OnSeparation = null;\n            OnCollision = null;\n        }\n\n        // These support body activation/deactivation.\n        internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf)\n        {\n            Debug.Assert(ProxyCount == 0);\n\n            // Create proxies in the broad-phase.\n            ProxyCount = Shape.ChildCount;\n\n            for (int i = 0; i < ProxyCount; ++i)\n            {\n                FixtureProxy proxy = new FixtureProxy();\n                Shape.ComputeAABB(ref xf, i, out proxy.AABB);\n                proxy.Fixture = this;\n                proxy.ChildIndex = i;\n\n                //Velcro note: This line needs to be after the previous two because FixtureProxy is a struct\n                proxy.ProxyId = broadPhase.AddProxy(ref proxy);\n\n                Proxies[i] = proxy;\n            }\n        }\n\n        internal void DestroyProxies(IBroadPhase broadPhase)\n        {\n            // Destroy proxies in the broad-phase.\n            for (int i = 0; i < ProxyCount; ++i)\n            {\n                broadPhase.RemoveProxy(Proxies[i].ProxyId);\n                Proxies[i].ProxyId = -1;\n            }\n\n            ProxyCount = 0;\n        }\n\n        internal void Synchronize(IBroadPhase broadPhase, ref Transform transform1, ref Transform transform2)\n        {\n            if (ProxyCount == 0)\n            {\n                return;\n            }\n\n            for (int i = 0; i < ProxyCount; ++i)\n            {\n                FixtureProxy proxy = Proxies[i];\n\n                // Compute an AABB that covers the swept Shape (may miss some rotation effect).\n                AABB aabb1, aabb2;\n                Shape.ComputeAABB(ref transform1, proxy.ChildIndex, out aabb1);\n                Shape.ComputeAABB(ref transform2, proxy.ChildIndex, out aabb2);\n\n                proxy.AABB.Combine(ref aabb1, ref aabb2);\n\n                Vector2 displacement = transform2.p - transform1.p;\n\n                broadPhase.MoveProxy(proxy.ProxyId, ref proxy.AABB, displacement);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/FixtureProxy.cs",
    "content": "using VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// This proxy is used internally to connect fixtures to the broad-phase.\n    /// </summary>\n    public struct FixtureProxy\n    {\n        public AABB AABB;\n        public int ChildIndex;\n        public Fixture Fixture;\n        public int ProxyId;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/BodyHandler.cs",
    "content": "namespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void BodyHandler(Body body);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/ControllerHandler.cs",
    "content": "using VelcroPhysics.Extensions.Controllers.ControllerBase;\n\nnamespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void ControllerHandler(Controller controller);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/FixtureHandler.cs",
    "content": "namespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void FixtureHandler(Fixture fixture);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/JointHandler.cs",
    "content": "using VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void JointHandler(Joint joint);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/PostSolveHandler.cs",
    "content": "using VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Dynamics.Solver;\n\nnamespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void PostSolveHandler(Contact contact, ContactVelocityConstraint impulse);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Handlers/PreSolveHandler.cs",
    "content": "﻿using VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Narrowphase;\n\nnamespace VelcroPhysics.Dynamics.Handlers\n{\n    public delegate void PreSolveHandler(Contact contact, ref Manifold oldManifold);\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/AngleJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    /// <summary>\n    /// Maintains a fixed angle between two bodies\n    /// </summary>\n    public class AngleJoint : Joint\n    {\n        private float _bias;\n        private float _jointError;\n        private float _massFactor;\n        private float _targetAngle;\n\n        internal AngleJoint()\n        {\n            JointType = JointType.Angle;\n        }\n\n        /// <summary>\n        /// Constructor for AngleJoint\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        public AngleJoint(Body bodyA, Body bodyB)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Angle;\n            BiasFactor = .2f;\n            MaxImpulse = float.MaxValue;\n        }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.Position; }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.Position; }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        /// <summary>\n        /// The desired angle between BodyA and BodyB\n        /// </summary>\n        public float TargetAngle\n        {\n            get { return _targetAngle; }\n            set\n            {\n                if (value != _targetAngle)\n                {\n                    _targetAngle = value;\n                    WakeBodies();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the bias factor.\n        /// Defaults to 0.2\n        /// </summary>\n        public float BiasFactor { get; set; }\n\n        /// <summary>\n        /// Gets or sets the maximum impulse\n        /// Defaults to float.MaxValue\n        /// </summary>\n        public float MaxImpulse { get; set; }\n\n        /// <summary>\n        /// Gets or sets the softness of the joint\n        /// Defaults to 0\n        /// </summary>\n        public float Softness { get; set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            //TODO\n            //return _inv_dt * _impulse;\n            return Vector2.Zero;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return 0;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            int indexA = BodyA.IslandIndex;\n            int indexB = BodyB.IslandIndex;\n\n            float aW = data.Positions[indexA].A;\n            float bW = data.Positions[indexB].A;\n\n            _jointError = (bW - aW - TargetAngle);\n            _bias = -BiasFactor * data.Step.inv_dt * _jointError;\n            _massFactor = (1 - Softness) / (BodyA._invI + BodyB._invI);\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            int indexA = BodyA.IslandIndex;\n            int indexB = BodyB.IslandIndex;\n\n            float p = (_bias - data.Velocities[indexB].W + data.Velocities[indexA].W) * _massFactor;\n\n            data.Velocities[indexA].W -= BodyA._invI * Math.Sign(p) * Math.Min(Math.Abs(p), MaxImpulse);\n            data.Velocities[indexB].W += BodyB._invI * Math.Sign(p) * Math.Min(Math.Abs(p), MaxImpulse);\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            //no position solving for this joint\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/DistanceJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // 1-D rained system\n    // m (v2 - v1) = lambda\n    // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.\n    // x2 = x1 + h * v2\n\n    // 1-D mass-damper-spring system\n    // m (v2 - v1) + h * d * v2 + h * k * \n\n    // C = norm(p2 - p1) - L\n    // u = (p2 - p1) / norm(p2 - p1)\n    // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))\n    // J = [-u -cross(r1, u) u cross(r2, u)]\n    // K = J * invM * JT\n    //   = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2\n\n    /// <summary>\n    /// A distance joint rains two points on two bodies\n    /// to remain at a fixed distance from each other. You can view\n    /// this as a massless, rigid rod.\n    /// </summary>\n    public class DistanceJoint : Joint\n    {\n        // Solver shared\n        private float _bias;\n\n        private float _gamma;\n        private float _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private float _mass;\n        private Vector2 _rA;\n        private Vector2 _rB;\n        private Vector2 _u;\n\n        internal DistanceJoint()\n        {\n            JointType = JointType.Distance;\n        }\n\n        /// <summary>\n        /// This requires defining an\n        /// anchor point on both bodies and the non-zero length of the\n        /// distance joint. If you don't supply a length, the local anchor points\n        /// is used so that the initial configuration can violate the constraint\n        /// slightly. This helps when saving and loading a game.\n        /// Warning Do not use a zero or short length.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        /// <param name=\"anchorA\">The first body anchor</param>\n        /// <param name=\"anchorB\">The second body anchor</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public DistanceJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Distance;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = bodyA.GetLocalPoint(ref anchorA);\n                LocalAnchorB = bodyB.GetLocalPoint(ref anchorB);\n                Length = (anchorB - anchorA).Length();\n            }\n            else\n            {\n                LocalAnchorA = anchorA;\n                LocalAnchorB = anchorB;\n                Length = (BodyB.GetWorldPoint(ref anchorB) - BodyA.GetWorldPoint(ref anchorA)).Length();\n            }\n        }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public sealed override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        public sealed override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        /// <summary>\n        /// The natural length between the anchor points.\n        /// Manipulating the length can lead to non-physical behavior when the frequency is zero.\n        /// </summary>\n        public float Length { get; set; }\n\n        /// <summary>\n        /// The mass-spring-damper frequency in Hertz. A value of 0\n        /// disables softness.\n        /// </summary>\n        public float Frequency { get; set; }\n\n        /// <summary>\n        /// The damping ratio. 0 = no damping, 1 = critical damping.\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// Get the reaction force given the inverse time step. Unit is N.\n        /// </summary>\n        /// <param name=\"invDt\"></param>\n        /// <returns></returns>\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            Vector2 F = (invDt * _impulse) * _u;\n            return F;\n        }\n\n        /// <summary>\n        /// Get the reaction torque given the inverse time step.\n        /// Unit is N*m. This is always zero for a distance joint.\n        /// </summary>\n        /// <param name=\"invDt\"></param>\n        /// <returns></returns>\n        public override float GetReactionTorque(float invDt)\n        {\n            return 0.0f;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            _u = cB + _rB - cA - _rA;\n\n            // Handle singularity.\n            float length = _u.Length();\n            if (length > Settings.LinearSlop)\n            {\n                _u *= 1.0f / length;\n            }\n            else\n            {\n                _u = Vector2.Zero;\n            }\n\n            float crAu = MathUtils.Cross(_rA, _u);\n            float crBu = MathUtils.Cross(_rB, _u);\n            float invMass = _invMassA + _invIA * crAu * crAu + _invMassB + _invIB * crBu * crBu;\n\n            // Compute the effective mass matrix.\n            _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;\n\n            if (Frequency > 0.0f)\n            {\n                float C = length - Length;\n\n                // Frequency\n                float omega = 2.0f * Settings.Pi * Frequency;\n\n                // Damping coefficient\n                float d = 2.0f * _mass * DampingRatio * omega;\n\n                // Spring stiffness\n                float k = _mass * omega * omega;\n\n                // magic formulas\n                float h = data.Step.dt;\n                _gamma = h * (d + h * k);\n                _gamma = _gamma != 0.0f ? 1.0f / _gamma : 0.0f;\n                _bias = C * h * k * _gamma;\n\n                invMass += _gamma;\n                _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;\n            }\n            else\n            {\n                _gamma = 0.0f;\n                _bias = 0.0f;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale the impulse to support a variable time step.\n                _impulse *= data.Step.dtRatio;\n\n                Vector2 P = _impulse * _u;\n                vA -= _invMassA * P;\n                wA -= _invIA * MathUtils.Cross(_rA, P);\n                vB += _invMassB * P;\n                wB += _invIB * MathUtils.Cross(_rB, P);\n            }\n            else\n            {\n                _impulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            // Cdot = dot(u, v + cross(w, r))\n            Vector2 vpA = vA + MathUtils.Cross(wA, _rA);\n            Vector2 vpB = vB + MathUtils.Cross(wB, _rB);\n            float Cdot = Vector2.Dot(_u, vpB - vpA);\n\n            float impulse = -_mass * (Cdot + _bias + _gamma * _impulse);\n            _impulse += impulse;\n\n            Vector2 P = impulse * _u;\n            vA -= _invMassA * P;\n            wA -= _invIA * MathUtils.Cross(_rA, P);\n            vB += _invMassB * P;\n            wB += _invIB * MathUtils.Cross(_rB, P);\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            if (Frequency > 0.0f)\n            {\n                // There is no position correction for soft distance constraints.\n                return true;\n            }\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 u = cB + rB - cA - rA;\n\n            float length = u.Length();\n            u.Normalize();\n            float C = length - Length;\n            C = MathUtils.Clamp(C, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);\n\n            float impulse = -_mass * C;\n            Vector2 P = impulse * u;\n\n            cA -= _invMassA * P;\n            aA -= _invIA * MathUtils.Cross(rA, P);\n            cB += _invMassB * P;\n            aB += _invIB * MathUtils.Cross(rB, P);\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return Math.Abs(C) < Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/FixedMouseJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // p = attached point, m = mouse point\n    // C = p - m\n    // Cdot = v\n    //      = v + cross(w, r)\n    // J = [I r_skew]\n    // Identity used:\n    // w k % (rx i + ry j) = w * (-ry i + rx j)\n\n    /// <summary>\n    /// A mouse joint is used to make a point on a body track a\n    /// specified world point. This a soft constraint with a maximum\n    /// force. This allows the constraint to stretch and without\n    /// applying huge forces.\n    /// NOTE: this joint is not documented in the manual because it was\n    /// developed to be used in the testbed. If you want to learn how to\n    /// use the mouse joint, look at the testbed.\n    /// </summary>\n    public class FixedMouseJoint : Joint\n    {\n        private float _beta;\n        private Vector2 _C;\n        private float _dampingRatio;\n        private float _frequency;\n        private float _gamma;\n\n        // Solver shared\n        private Vector2 _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private float _invIA;\n        private float _invMassA;\n        private Vector2 _localCenterA;\n        private Mat22 _mass;\n        private float _maxForce;\n        private Vector2 _rA;\n        private Vector2 _worldAnchor;\n\n        /// <summary>\n        /// This requires a world target point,\n        /// tuning parameters, and the time step.\n        /// </summary>\n        /// <param name=\"body\">The body.</param>\n        /// <param name=\"worldAnchor\">The target.</param>\n        public FixedMouseJoint(Body body, Vector2 worldAnchor)\n            : base(body)\n        {\n            JointType = JointType.FixedMouse;\n            Frequency = 5.0f;\n            DampingRatio = 0.7f;\n            MaxForce = 1000 * body.Mass;\n\n            Debug.Assert(worldAnchor.IsValid());\n\n            _worldAnchor = worldAnchor;\n            LocalAnchorA = MathUtils.MulT(BodyA._xf, worldAnchor);\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return _worldAnchor; }\n            set\n            {\n                WakeBodies();\n                _worldAnchor = value;\n            }\n        }\n\n        /// <summary>\n        /// The maximum constraint force that can be exerted\n        /// to move the candidate body. Usually you will express\n        /// as some multiple of the weight (multiplier * mass * gravity).\n        /// </summary>\n        public float MaxForce\n        {\n            get { return _maxForce; }\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value) && value >= 0.0f);\n                _maxForce = value;\n            }\n        }\n\n        /// <summary>\n        /// The response speed.\n        /// </summary>\n        public float Frequency\n        {\n            get { return _frequency; }\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value) && value >= 0.0f);\n                _frequency = value;\n            }\n        }\n\n        /// <summary>\n        /// The damping ratio. 0 = no damping, 1 = critical damping.\n        /// </summary>\n        public float DampingRatio\n        {\n            get { return _dampingRatio; }\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value) && value >= 0.0f);\n                _dampingRatio = value;\n            }\n        }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * _impulse;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * 0.0f;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invIA = BodyA._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Rot qA = new Rot(aA);\n\n            float mass = BodyA.Mass;\n\n            // Frequency\n            float omega = 2.0f * Settings.Pi * Frequency;\n\n            // Damping coefficient\n            float d = 2.0f * mass * DampingRatio * omega;\n\n            // Spring stiffness\n            float k = mass * (omega * omega);\n\n            // magic formulas\n            // gamma has units of inverse mass.\n            // beta has units of inverse time.\n            float h = data.Step.dt;\n            Debug.Assert(d + h * k > Settings.Epsilon);\n            _gamma = h * (d + h * k);\n            if (_gamma != 0.0f)\n            {\n                _gamma = 1.0f / _gamma;\n            }\n\n            _beta = h * k * _gamma;\n\n            // Compute the effective mass matrix.\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n\n            // K    = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]\n            //      = [1/m1+1/m2     0    ] + invI1 * [r1.Y*r1.Y -r1.X*r1.Y] + invI2 * [r1.Y*r1.Y -r1.X*r1.Y]\n            //        [    0     1/m1+1/m2]           [-r1.X*r1.Y r1.X*r1.X]           [-r1.X*r1.Y r1.X*r1.X]\n            Mat22 K = new Mat22();\n            K.ex.X = _invMassA + _invIA * _rA.Y * _rA.Y + _gamma;\n            K.ex.Y = -_invIA * _rA.X * _rA.Y;\n            K.ey.X = K.ex.Y;\n            K.ey.Y = _invMassA + _invIA * _rA.X * _rA.X + _gamma;\n\n            _mass = K.Inverse;\n\n            _C = cA + _rA - _worldAnchor;\n            _C *= _beta;\n\n            // Cheat with some damping\n            wA *= 0.98f;\n\n            if (Settings.EnableWarmstarting)\n            {\n                _impulse *= data.Step.dtRatio;\n                vA += _invMassA * _impulse;\n                wA += _invIA * MathUtils.Cross(_rA, _impulse);\n            }\n            else\n            {\n                _impulse = Vector2.Zero;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            // Cdot = v + cross(w, r)\n            Vector2 Cdot = vA + MathUtils.Cross(wA, _rA);\n            Vector2 impulse = MathUtils.Mul(ref _mass, -(Cdot + _C + _gamma * _impulse));\n\n            Vector2 oldImpulse = _impulse;\n            _impulse += impulse;\n            float maxImpulse = data.Step.dt * MaxForce;\n            if (_impulse.LengthSquared() > maxImpulse * maxImpulse)\n            {\n                _impulse *= maxImpulse / _impulse.Length();\n            }\n            impulse = _impulse - oldImpulse;\n\n            vA += _invMassA * impulse;\n            wA += _invIA * MathUtils.Cross(_rA, impulse);\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/FrictionJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Point-to-point constraint\n    // Cdot = v2 - v1\n    //      = v2 + cross(w2, r2) - v1 - cross(w1, r1)\n    // J = [-I -r1_skew I r2_skew ]\n    // Identity used:\n    // w k % (rx i + ry j) = w * (-ry i + rx j)\n\n    // Angle constraint\n    // Cdot = w2 - w1\n    // J = [0 0 -1 0 0 1]\n    // K = invI1 + invI2\n\n    /// <summary>\n    /// Friction joint. This is used for top-down friction.\n    /// It provides 2D translational friction and angular friction.\n    /// </summary>\n    public class FrictionJoint : Joint\n    {\n        private float _angularImpulse;\n        private float _angularMass;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n\n        private float _invMassB;\n\n        // Solver shared\n        private Vector2 _linearImpulse;\n\n        private Mat22 _linearMass;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private Vector2 _rA;\n        private Vector2 _rB;\n\n        internal FrictionJoint()\n        {\n            JointType = JointType.Friction;\n        }\n\n        /// <summary>\n        /// Constructor for FrictionJoint.\n        /// </summary>\n        /// <param name=\"bodyA\"></param>\n        /// <param name=\"bodyB\"></param>\n        /// <param name=\"anchor\"></param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public FrictionJoint(Body bodyA, Body bodyB, Vector2 anchor, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Friction;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = BodyA.GetLocalPoint(anchor);\n                LocalAnchorB = BodyB.GetLocalPoint(anchor);\n            }\n            else\n            {\n                LocalAnchorA = anchor;\n                LocalAnchorB = anchor;\n            }\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// The maximum friction force in N.\n        /// </summary>\n        public float MaxForce { get; set; }\n\n        /// <summary>\n        /// The maximum friction torque in N-m.\n        /// </summary>\n        public float MaxTorque { get; set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * _linearImpulse;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _angularImpulse;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            // Compute the effective mass matrix.\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            // J = [-I -r1_skew I r2_skew]\n            //     [ 0       -1 0       1]\n            // r_skew = [-ry; rx]\n\n            // Matlab\n            // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]\n            //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]\n            //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Mat22 K = new Mat22();\n            K.ex.X = mA + mB + iA * _rA.Y * _rA.Y + iB * _rB.Y * _rB.Y;\n            K.ex.Y = -iA * _rA.X * _rA.Y - iB * _rB.X * _rB.Y;\n            K.ey.X = K.ex.Y;\n            K.ey.Y = mA + mB + iA * _rA.X * _rA.X + iB * _rB.X * _rB.X;\n\n            _linearMass = K.Inverse;\n\n            _angularMass = iA + iB;\n            if (_angularMass > 0.0f)\n            {\n                _angularMass = 1.0f / _angularMass;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale impulses to support a variable time step.\n                _linearImpulse *= data.Step.dtRatio;\n                _angularImpulse *= data.Step.dtRatio;\n\n                Vector2 P = new Vector2(_linearImpulse.X, _linearImpulse.Y);\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + _angularImpulse);\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + _angularImpulse);\n            }\n            else\n            {\n                _linearImpulse = Vector2.Zero;\n                _angularImpulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            float h = data.Step.dt;\n\n            // Solve angular friction\n            {\n                float Cdot = wB - wA;\n                float impulse = -_angularMass * Cdot;\n\n                float oldImpulse = _angularImpulse;\n                float maxImpulse = h * MaxTorque;\n                _angularImpulse = MathUtils.Clamp(_angularImpulse + impulse, -maxImpulse, maxImpulse);\n                impulse = _angularImpulse - oldImpulse;\n\n                wA -= iA * impulse;\n                wB += iB * impulse;\n            }\n\n            // Solve linear friction\n            {\n                Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);\n\n                Vector2 impulse = -MathUtils.Mul(ref _linearMass, Cdot);\n                Vector2 oldImpulse = _linearImpulse;\n                _linearImpulse += impulse;\n\n                float maxImpulse = h * MaxForce;\n\n                if (_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)\n                {\n                    _linearImpulse.Normalize();\n                    _linearImpulse *= maxImpulse;\n                }\n\n                impulse = _linearImpulse - oldImpulse;\n\n                vA -= mA * impulse;\n                wA -= iA * MathUtils.Cross(_rA, impulse);\n\n                vB += mB * impulse;\n                wB += iB * MathUtils.Cross(_rB, impulse);\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/GearJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Gear Joint:\n    // C0 = (coordinate1 + ratio * coordinate2)_initial\n    // C = (coordinate1 + ratio * coordinate2) - C0 = 0\n    // J = [J1 ratio * J2]\n    // K = J * invM * JT\n    //   = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T\n    //\n    // Revolute:\n    // coordinate = rotation\n    // Cdot = angularVelocity\n    // J = [0 0 1]\n    // K = J * invM * JT = invI\n    //\n    // Prismatic:\n    // coordinate = dot(p - pg, ug)\n    // Cdot = dot(v + cross(w, r), ug)\n    // J = [ug cross(r, ug)]\n    // K = J * invM * JT = invMass + invI * cross(r, ug)^2\n\n    /// <summary>\n    /// A gear joint is used to connect two joints together.\n    /// Either joint can be a revolute or prismatic joint.\n    /// You specify a gear ratio to bind the motions together:\n    /// <![CDATA[coordinate1 + ratio * coordinate2 = ant]]>\n    /// The ratio can be negative or positive. If one joint is a revolute joint\n    /// and the other joint is a prismatic joint, then the ratio will have units\n    /// of length or units of 1/length.\n    /// Warning: You have to manually destroy the gear joint if jointA or jointB is destroyed.\n    /// </summary>\n    public class GearJoint : Joint\n    {\n        private Body _bodyA;\n        private Body _bodyB;\n        private Body _bodyC;\n        private Body _bodyD;\n\n        private float _constant;\n        private float _iA, _iB, _iC, _iD;\n\n        private float _impulse;\n\n        // Solver temp\n        private int _indexA, _indexB, _indexC, _indexD;\n\n        private Vector2 _JvAC, _JvBD;\n        private float _JwA, _JwB, _JwC, _JwD;\n        private Vector2 _lcA, _lcB, _lcC, _lcD;\n\n        // Solver shared\n        private Vector2 _localAnchorA;\n\n        private Vector2 _localAnchorB;\n        private Vector2 _localAnchorC;\n        private Vector2 _localAnchorD;\n\n        private Vector2 _localAxisC;\n        private Vector2 _localAxisD;\n        private float _mA, _mB, _mC, _mD;\n        private float _mass;\n        private float _ratio;\n\n        private float _referenceAngleA;\n        private float _referenceAngleB;\n        private JointType _typeA;\n        private JointType _typeB;\n\n        /// <summary>\n        /// Requires two existing revolute or prismatic joints (any combination will work).\n        /// The provided joints must attach a dynamic body to a static body.\n        /// </summary>\n        /// <param name=\"jointA\">The first joint.</param>\n        /// <param name=\"jointB\">The second joint.</param>\n        /// <param name=\"ratio\">The ratio.</param>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        public GearJoint(Body bodyA, Body bodyB, Joint jointA, Joint jointB, float ratio = 1f)\n        {\n            JointType = JointType.Gear;\n            BodyA = bodyA;\n            BodyB = bodyB;\n            JointA = jointA;\n            JointB = jointB;\n            Ratio = ratio;\n\n            _typeA = jointA.JointType;\n            _typeB = jointB.JointType;\n\n            Debug.Assert(_typeA == JointType.Revolute || _typeA == JointType.Prismatic || _typeA == JointType.FixedRevolute || _typeA == JointType.FixedPrismatic);\n            Debug.Assert(_typeB == JointType.Revolute || _typeB == JointType.Prismatic || _typeB == JointType.FixedRevolute || _typeB == JointType.FixedPrismatic);\n\n            float coordinateA, coordinateB;\n\n            // TODO_ERIN there might be some problem with the joint edges in b2Joint.\n\n            _bodyC = JointA.BodyA;\n            _bodyA = JointA.BodyB;\n\n            // Get geometry of joint1\n            Transform xfA = _bodyA._xf;\n            float aA = _bodyA._sweep.A;\n            Transform xfC = _bodyC._xf;\n            float aC = _bodyC._sweep.A;\n\n            if (_typeA == JointType.Revolute)\n            {\n                RevoluteJoint revolute = (RevoluteJoint)jointA;\n                _localAnchorC = revolute.LocalAnchorA;\n                _localAnchorA = revolute.LocalAnchorB;\n                _referenceAngleA = revolute.ReferenceAngle;\n                _localAxisC = Vector2.Zero;\n\n                coordinateA = aA - aC - _referenceAngleA;\n            }\n            else\n            {\n                PrismaticJoint prismatic = (PrismaticJoint)jointA;\n                _localAnchorC = prismatic.LocalAnchorA;\n                _localAnchorA = prismatic.LocalAnchorB;\n                _referenceAngleA = prismatic.ReferenceAngle;\n                _localAxisC = prismatic.LocalXAxis;\n\n                Vector2 pC = _localAnchorC;\n                Vector2 pA = MathUtils.MulT(xfC.q, MathUtils.Mul(xfA.q, _localAnchorA) + (xfA.p - xfC.p));\n                coordinateA = Vector2.Dot(pA - pC, _localAxisC);\n            }\n\n            _bodyD = JointB.BodyA;\n            _bodyB = JointB.BodyB;\n\n            // Get geometry of joint2\n            Transform xfB = _bodyB._xf;\n            float aB = _bodyB._sweep.A;\n            Transform xfD = _bodyD._xf;\n            float aD = _bodyD._sweep.A;\n\n            if (_typeB == JointType.Revolute)\n            {\n                RevoluteJoint revolute = (RevoluteJoint)jointB;\n                _localAnchorD = revolute.LocalAnchorA;\n                _localAnchorB = revolute.LocalAnchorB;\n                _referenceAngleB = revolute.ReferenceAngle;\n                _localAxisD = Vector2.Zero;\n\n                coordinateB = aB - aD - _referenceAngleB;\n            }\n            else\n            {\n                PrismaticJoint prismatic = (PrismaticJoint)jointB;\n                _localAnchorD = prismatic.LocalAnchorA;\n                _localAnchorB = prismatic.LocalAnchorB;\n                _referenceAngleB = prismatic.ReferenceAngle;\n                _localAxisD = prismatic.LocalXAxis;\n\n                Vector2 pD = _localAnchorD;\n                Vector2 pB = MathUtils.MulT(xfD.q, MathUtils.Mul(xfB.q, _localAnchorB) + (xfB.p - xfD.p));\n                coordinateB = Vector2.Dot(pB - pD, _localAxisD);\n            }\n\n            _ratio = ratio;\n            _constant = coordinateA + _ratio * coordinateB;\n            _impulse = 0.0f;\n        }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return _bodyA.GetWorldPoint(_localAnchorA); }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return _bodyB.GetWorldPoint(_localAnchorB); }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        /// <summary>\n        /// The gear ratio.\n        /// </summary>\n        public float Ratio\n        {\n            get { return _ratio; }\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value));\n                _ratio = value;\n            }\n        }\n\n        /// <summary>\n        /// The first revolute/prismatic joint attached to the gear joint.\n        /// </summary>\n        public Joint JointA { get; private set; }\n\n        /// <summary>\n        /// The second revolute/prismatic joint attached to the gear joint.\n        /// </summary>\n        public Joint JointB { get; private set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            Vector2 P = _impulse * _JvAC;\n            return invDt * P;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            float L = _impulse * _JwA;\n            return invDt * L;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = _bodyA.IslandIndex;\n            _indexB = _bodyB.IslandIndex;\n            _indexC = _bodyC.IslandIndex;\n            _indexD = _bodyD.IslandIndex;\n            _lcA = _bodyA._sweep.LocalCenter;\n            _lcB = _bodyB._sweep.LocalCenter;\n            _lcC = _bodyC._sweep.LocalCenter;\n            _lcD = _bodyD._sweep.LocalCenter;\n            _mA = _bodyA._invMass;\n            _mB = _bodyB._invMass;\n            _mC = _bodyC._invMass;\n            _mD = _bodyD._invMass;\n            _iA = _bodyA._invI;\n            _iB = _bodyB._invI;\n            _iC = _bodyC._invI;\n            _iD = _bodyD._invI;\n\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float aC = data.Positions[_indexC].A;\n            Vector2 vC = data.Velocities[_indexC].V;\n            float wC = data.Velocities[_indexC].W;\n\n            float aD = data.Positions[_indexD].A;\n            Vector2 vD = data.Velocities[_indexD].V;\n            float wD = data.Velocities[_indexD].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD);\n\n            _mass = 0.0f;\n\n            if (_typeA == JointType.Revolute)\n            {\n                _JvAC = Vector2.Zero;\n                _JwA = 1.0f;\n                _JwC = 1.0f;\n                _mass += _iA + _iC;\n            }\n            else\n            {\n                Vector2 u = MathUtils.Mul(qC, _localAxisC);\n                Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC);\n                Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA);\n                _JvAC = u;\n                _JwC = MathUtils.Cross(rC, u);\n                _JwA = MathUtils.Cross(rA, u);\n                _mass += _mC + _mA + _iC * _JwC * _JwC + _iA * _JwA * _JwA;\n            }\n\n            if (_typeB == JointType.Revolute)\n            {\n                _JvBD = Vector2.Zero;\n                _JwB = _ratio;\n                _JwD = _ratio;\n                _mass += _ratio * _ratio * (_iB + _iD);\n            }\n            else\n            {\n                Vector2 u = MathUtils.Mul(qD, _localAxisD);\n                Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD);\n                Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB);\n                _JvBD = _ratio * u;\n                _JwD = _ratio * MathUtils.Cross(rD, u);\n                _JwB = _ratio * MathUtils.Cross(rB, u);\n                _mass += _ratio * _ratio * (_mD + _mB) + _iD * _JwD * _JwD + _iB * _JwB * _JwB;\n            }\n\n            // Compute effective mass.\n            _mass = _mass > 0.0f ? 1.0f / _mass : 0.0f;\n\n            if (Settings.EnableWarmstarting)\n            {\n                vA += (_mA * _impulse) * _JvAC;\n                wA += _iA * _impulse * _JwA;\n                vB += (_mB * _impulse) * _JvBD;\n                wB += _iB * _impulse * _JwB;\n                vC -= (_mC * _impulse) * _JvAC;\n                wC -= _iC * _impulse * _JwC;\n                vD -= (_mD * _impulse) * _JvBD;\n                wD -= _iD * _impulse * _JwD;\n            }\n            else\n            {\n                _impulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n            data.Velocities[_indexC].V = vC;\n            data.Velocities[_indexC].W = wC;\n            data.Velocities[_indexD].V = vD;\n            data.Velocities[_indexD].W = wD;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n            Vector2 vC = data.Velocities[_indexC].V;\n            float wC = data.Velocities[_indexC].W;\n            Vector2 vD = data.Velocities[_indexD].V;\n            float wD = data.Velocities[_indexD].W;\n\n            float Cdot = Vector2.Dot(_JvAC, vA - vC) + Vector2.Dot(_JvBD, vB - vD);\n            Cdot += (_JwA * wA - _JwC * wC) + (_JwB * wB - _JwD * wD);\n\n            float impulse = -_mass * Cdot;\n            _impulse += impulse;\n\n            vA += (_mA * impulse) * _JvAC;\n            wA += _iA * impulse * _JwA;\n            vB += (_mB * impulse) * _JvBD;\n            wB += _iB * impulse * _JwB;\n            vC -= (_mC * impulse) * _JvAC;\n            wC -= _iC * impulse * _JwC;\n            vD -= (_mD * impulse) * _JvBD;\n            wD -= _iD * impulse * _JwD;\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n            data.Velocities[_indexC].V = vC;\n            data.Velocities[_indexC].W = wC;\n            data.Velocities[_indexD].V = vD;\n            data.Velocities[_indexD].W = wD;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 cC = data.Positions[_indexC].C;\n            float aC = data.Positions[_indexC].A;\n            Vector2 cD = data.Positions[_indexD].C;\n            float aD = data.Positions[_indexD].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD);\n\n            const float linearError = 0.0f;\n\n            float coordinateA, coordinateB;\n\n            Vector2 JvAC, JvBD;\n            float JwA, JwB, JwC, JwD;\n            float mass = 0.0f;\n\n            if (_typeA == JointType.Revolute)\n            {\n                JvAC = Vector2.Zero;\n                JwA = 1.0f;\n                JwC = 1.0f;\n                mass += _iA + _iC;\n\n                coordinateA = aA - aC - _referenceAngleA;\n            }\n            else\n            {\n                Vector2 u = MathUtils.Mul(qC, _localAxisC);\n                Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC);\n                Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA);\n                JvAC = u;\n                JwC = MathUtils.Cross(rC, u);\n                JwA = MathUtils.Cross(rA, u);\n                mass += _mC + _mA + _iC * JwC * JwC + _iA * JwA * JwA;\n\n                Vector2 pC = _localAnchorC - _lcC;\n                Vector2 pA = MathUtils.MulT(qC, rA + (cA - cC));\n                coordinateA = Vector2.Dot(pA - pC, _localAxisC);\n            }\n\n            if (_typeB == JointType.Revolute)\n            {\n                JvBD = Vector2.Zero;\n                JwB = _ratio;\n                JwD = _ratio;\n                mass += _ratio * _ratio * (_iB + _iD);\n\n                coordinateB = aB - aD - _referenceAngleB;\n            }\n            else\n            {\n                Vector2 u = MathUtils.Mul(qD, _localAxisD);\n                Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD);\n                Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB);\n                JvBD = _ratio * u;\n                JwD = _ratio * MathUtils.Cross(rD, u);\n                JwB = _ratio * MathUtils.Cross(rB, u);\n                mass += _ratio * _ratio * (_mD + _mB) + _iD * JwD * JwD + _iB * JwB * JwB;\n\n                Vector2 pD = _localAnchorD - _lcD;\n                Vector2 pB = MathUtils.MulT(qD, rB + (cB - cD));\n                coordinateB = Vector2.Dot(pB - pD, _localAxisD);\n            }\n\n            float C = (coordinateA + _ratio * coordinateB) - _constant;\n\n            float impulse = 0.0f;\n            if (mass > 0.0f)\n            {\n                impulse = -C / mass;\n            }\n\n            cA += _mA * impulse * JvAC;\n            aA += _iA * impulse * JwA;\n            cB += _mB * impulse * JvBD;\n            aB += _iB * impulse * JwB;\n            cC -= _mC * impulse * JvAC;\n            aC -= _iC * impulse * JwC;\n            cD -= _mD * impulse * JvBD;\n            aD -= _iD * impulse * JwD;\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n            data.Positions[_indexC].C = cC;\n            data.Positions[_indexC].A = aC;\n            data.Positions[_indexD].C = cD;\n            data.Positions[_indexD].A = aD;\n\n            // TODO_ERIN not implemented\n            return linearError < Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/Joint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    public abstract class Joint\n    {\n        private float _breakpoint;\n        private double _breakpointSquared;\n\n        internal JointEdge EdgeA = new JointEdge();\n        internal JointEdge EdgeB = new JointEdge();\n\n        /// <summary>\n        /// Indicate if this join is enabled or not. Disabling a joint\n        /// means it is still in the simulation, but inactive.\n        /// </summary>\n        public bool Enabled = true;\n\n        internal bool IslandFlag;\n\n        protected Joint()\n        {\n            Breakpoint = float.MaxValue;\n\n            //Connected bodies should not collide by default\n            CollideConnected = false;\n        }\n\n        protected Joint(Body bodyA, Body bodyB) : this()\n        {\n            //Can't connect a joint to the same body twice.\n            Debug.Assert(bodyA != bodyB);\n\n            BodyA = bodyA;\n            BodyB = bodyB;\n        }\n\n        /// <summary>\n        /// Constructor for fixed joint\n        /// </summary>\n        protected Joint(Body body) : this()\n        {\n            BodyA = body;\n        }\n\n        /// <summary>\n        /// Gets or sets the type of the joint.\n        /// </summary>\n        /// <value>The type of the joint.</value>\n        public JointType JointType { get; protected set; }\n\n        /// <summary>\n        /// Get the first body attached to this joint.\n        /// </summary>\n        public Body BodyA { get; internal set; }\n\n        /// <summary>\n        /// Get the second body attached to this joint.\n        /// </summary>\n        public Body BodyB { get; internal set; }\n\n        /// <summary>\n        /// Get the anchor point on bodyA in world coordinates.\n        /// On some joints, this value indicate the anchor point within the world.\n        /// </summary>\n        public abstract Vector2 WorldAnchorA { get; set; }\n\n        /// <summary>\n        /// Get the anchor point on bodyB in world coordinates.\n        /// On some joints, this value indicate the anchor point within the world.\n        /// </summary>\n        public abstract Vector2 WorldAnchorB { get; set; }\n\n        /// <summary>\n        /// Set the user data pointer.\n        /// </summary>\n        /// <value>The data.</value>\n        public object UserData { get; set; }\n\n        /// <summary>\n        /// Set this flag to true if the attached bodies should collide.\n        /// </summary>\n        public bool CollideConnected { get; set; }\n\n        /// <summary>\n        /// The Breakpoint simply indicates the maximum Value the JointError can be before it breaks.\n        /// The default value is float.MaxValue, which means it never breaks.\n        /// </summary>\n        public float Breakpoint\n        {\n            get { return _breakpoint; }\n            set\n            {\n                _breakpoint = value;\n                _breakpointSquared = _breakpoint * _breakpoint;\n            }\n        }\n\n        /// <summary>\n        /// Fires when the joint is broken.\n        /// </summary>\n        public event Action<Joint, float> Broke;\n\n        /// <summary>\n        /// Get the reaction force on body at the joint anchor in Newtons.\n        /// </summary>\n        /// <param name=\"invDt\">The inverse delta time.</param>\n        public abstract Vector2 GetReactionForce(float invDt);\n\n        /// <summary>\n        /// Get the reaction torque on the body at the joint anchor in N*m.\n        /// </summary>\n        /// <param name=\"invDt\">The inverse delta time.</param>\n        public abstract float GetReactionTorque(float invDt);\n\n        protected void WakeBodies()\n        {\n            if (BodyA != null)\n                BodyA.Awake = true;\n\n            if (BodyB != null)\n                BodyB.Awake = true;\n        }\n\n        /// <summary>\n        /// Return true if the joint is a fixed type.\n        /// </summary>\n        public bool IsFixedType()\n        {\n            return JointType == JointType.FixedRevolute ||\n                   JointType == JointType.FixedDistance ||\n                   JointType == JointType.FixedPrismatic ||\n                   JointType == JointType.FixedLine ||\n                   JointType == JointType.FixedMouse ||\n                   JointType == JointType.FixedAngle ||\n                   JointType == JointType.FixedFriction;\n        }\n\n        internal abstract void InitVelocityConstraints(ref SolverData data);\n\n        internal void Validate(float invDt)\n        {\n            if (!Enabled)\n                return;\n\n            float jointErrorSquared = GetReactionForce(invDt).LengthSquared();\n\n            if (Math.Abs(jointErrorSquared) <= _breakpointSquared)\n                return;\n\n            Enabled = false;\n\n            Broke?.Invoke(this, (float)Math.Sqrt(jointErrorSquared));\n        }\n\n        internal abstract void SolveVelocityConstraints(ref SolverData data);\n\n        /// <summary>\n        /// Solves the position constraints.\n        /// </summary>\n        /// <param name=\"data\"></param>\n        /// <returns>returns true if the position errors are within tolerance.</returns>\n        internal abstract bool SolvePositionConstraints(ref SolverData data);\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/JointEdge.cs",
    "content": "namespace VelcroPhysics.Dynamics.Joints\n{\n    /// <summary>\n    /// A joint edge is used to connect bodies and joints together\n    /// in a joint graph where each body is a node and each joint\n    /// is an edge. A joint edge belongs to a doubly linked list\n    /// maintained in each attached body. Each joint has two joint\n    /// nodes, one for each attached body.\n    /// </summary>\n    public sealed class JointEdge\n    {\n        /// <summary>\n        /// The joint.\n        /// </summary>\n        public Joint Joint;\n\n        /// <summary>\n        /// The next joint edge in the body's joint list.\n        /// </summary>\n        public JointEdge Next;\n\n        /// <summary>\n        /// Provides quick access to the other body attached.\n        /// </summary>\n        public Body Other;\n\n        /// <summary>\n        /// The previous joint edge in the body's joint list.\n        /// </summary>\n        public JointEdge Prev;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/JointType.cs",
    "content": "namespace VelcroPhysics.Dynamics.Joints\n{\n    public enum JointType\n    {\n        Unknown,\n        Revolute,\n        Prismatic,\n        Distance,\n        Pulley,\n\n        //Mouse, <- We have fixed mouse\n        Gear,\n        Wheel,\n        Weld,\n        Friction,\n        Rope,\n        Motor,\n\n        //Velcro note: From here on and down, it is only FPE joints\n        Angle,\n        FixedMouse,\n        FixedRevolute,\n        FixedDistance,\n        FixedLine,\n        FixedPrismatic,\n        FixedAngle,\n        FixedFriction\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/LimitState.cs",
    "content": "namespace VelcroPhysics.Dynamics.Joints\n{\n    public enum LimitState\n    {\n        Inactive,\n        AtLower,\n        AtUpper,\n        Equal\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/MotorJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    /// <summary>\n    /// A motor joint is used to control the relative motion\n    /// between two bodies. A typical usage is to control the movement\n    /// of a dynamic body with respect to the ground.\n    /// </summary>\n    public class MotorJoint : Joint\n    {\n        private float _angularError;\n        private float _angularImpulse;\n        private float _angularMass;\n        private float _angularOffset;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Vector2 _linearError;\n        private Vector2 _linearImpulse;\n\n        private Mat22 _linearMass;\n\n        // Solver shared\n        private Vector2 _linearOffset;\n\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private float _maxForce;\n        private float _maxTorque;\n        private Vector2 _rA;\n        private Vector2 _rB;\n\n        internal MotorJoint()\n        {\n            JointType = JointType.Motor;\n        }\n\n        /// <summary>\n        /// Constructor for MotorJoint.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public MotorJoint(Body bodyA, Body bodyB, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Motor;\n\n            Vector2 xB = BodyB.Position;\n\n            if (useWorldCoordinates)\n                _linearOffset = BodyA.GetLocalPoint(xB);\n            else\n                _linearOffset = xB;\n\n            //Defaults\n            //_angularOffset = 0.0f;\n            _maxForce = 1.0f;\n            _maxTorque = 1.0f;\n            CorrectionFactor = 0.3f;\n\n            _angularOffset = BodyB.Rotation - BodyA.Rotation;\n        }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.Position; }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.Position; }\n            set { Debug.Assert(false, \"You can't set the world anchor on this joint type.\"); }\n        }\n\n        /// <summary>\n        /// The maximum amount of force that can be applied to BodyA\n        /// </summary>\n        public float MaxForce\n        {\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value) && value >= 0.0f);\n                _maxForce = value;\n            }\n            get { return _maxForce; }\n        }\n\n        /// <summary>\n        /// The maximum amount of torque that can be applied to BodyA\n        /// </summary>\n        public float MaxTorque\n        {\n            set\n            {\n                Debug.Assert(MathUtils.IsValid(value) && value >= 0.0f);\n                _maxTorque = value;\n            }\n            get { return _maxTorque; }\n        }\n\n        /// <summary>\n        /// The linear (translation) offset.\n        /// </summary>\n        public Vector2 LinearOffset\n        {\n            set\n            {\n                if (_linearOffset.X != value.X || _linearOffset.Y != value.Y)\n                {\n                    WakeBodies();\n                    _linearOffset = value;\n                }\n            }\n            get { return _linearOffset; }\n        }\n\n        /// <summary>\n        /// Get or set the angular offset.\n        /// </summary>\n        public float AngularOffset\n        {\n            set\n            {\n                if (_angularOffset != value)\n                {\n                    WakeBodies();\n                    _angularOffset = value;\n                }\n            }\n            get { return _angularOffset; }\n        }\n\n        //Velcro note: Used for serialization.\n        internal float CorrectionFactor { get; set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * _linearImpulse;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _angularImpulse;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA);\n            Rot qB = new Rot(aB);\n\n            // Compute the effective mass matrix.\n            _rA = MathUtils.Mul(qA, -_localCenterA);\n            _rB = MathUtils.Mul(qB, -_localCenterB);\n\n            // J = [-I -r1_skew I r2_skew]\n            //     [ 0       -1 0       1]\n            // r_skew = [-ry; rx]\n\n            // Matlab\n            // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]\n            //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]\n            //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Mat22 K = new Mat22();\n            K.ex.X = mA + mB + iA * _rA.Y * _rA.Y + iB * _rB.Y * _rB.Y;\n            K.ex.Y = -iA * _rA.X * _rA.Y - iB * _rB.X * _rB.Y;\n            K.ey.X = K.ex.Y;\n            K.ey.Y = mA + mB + iA * _rA.X * _rA.X + iB * _rB.X * _rB.X;\n\n            _linearMass = K.Inverse;\n\n            _angularMass = iA + iB;\n            if (_angularMass > 0.0f)\n            {\n                _angularMass = 1.0f / _angularMass;\n            }\n\n            _linearError = cB + _rB - cA - _rA - MathUtils.Mul(qA, _linearOffset);\n            _angularError = aB - aA - _angularOffset;\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale impulses to support a variable time step.\n                _linearImpulse *= data.Step.dtRatio;\n                _angularImpulse *= data.Step.dtRatio;\n\n                Vector2 P = new Vector2(_linearImpulse.X, _linearImpulse.Y);\n\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + _angularImpulse);\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + _angularImpulse);\n            }\n            else\n            {\n                _linearImpulse = Vector2.Zero;\n                _angularImpulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            float h = data.Step.dt;\n            float inv_h = data.Step.inv_dt;\n\n            // Solve angular friction\n            {\n                float Cdot = wB - wA + inv_h * CorrectionFactor * _angularError;\n                float impulse = -_angularMass * Cdot;\n\n                float oldImpulse = _angularImpulse;\n                float maxImpulse = h * _maxTorque;\n                _angularImpulse = MathUtils.Clamp(_angularImpulse + impulse, -maxImpulse, maxImpulse);\n                impulse = _angularImpulse - oldImpulse;\n\n                wA -= iA * impulse;\n                wB += iB * impulse;\n            }\n\n            // Solve linear friction\n            {\n                Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA) + inv_h * CorrectionFactor * _linearError;\n\n                Vector2 impulse = -MathUtils.Mul(ref _linearMass, ref Cdot);\n                Vector2 oldImpulse = _linearImpulse;\n                _linearImpulse += impulse;\n\n                float maxImpulse = h * _maxForce;\n\n                if (_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)\n                {\n                    _linearImpulse.Normalize();\n                    _linearImpulse *= maxImpulse;\n                }\n\n                impulse = _linearImpulse - oldImpulse;\n\n                vA -= mA * impulse;\n                wA -= iA * MathUtils.Cross(_rA, impulse);\n\n                vB += mB * impulse;\n                wB += iB * MathUtils.Cross(_rB, impulse);\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/PrismaticJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Linear constraint (point-to-line)\n    // d = p2 - p1 = x2 + r2 - x1 - r1\n    // C = dot(perp, d)\n    // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))\n    //      = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)\n    // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]\n    //\n    // Angular constraint\n    // C = a2 - a1 + a_initial\n    // Cdot = w2 - w1\n    // J = [0 0 -1 0 0 1]\n    //\n    // K = J * invM * JT\n    //\n    // J = [-a -s1 a s2]\n    //     [0  -1  0  1]\n    // a = perp\n    // s1 = cross(d + r1, a) = cross(p2 - x1, a)\n    // s2 = cross(r2, a) = cross(p2 - x2, a)\n    // Motor/Limit linear constraint\n    // C = dot(ax1, d)\n    // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)\n    // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]\n    // Block Solver\n    // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even\n    // when the mass has poor distribution (leading to large torques about the joint anchor points).\n    //\n    // The Jacobian has 3 rows:\n    // J = [-uT -s1 uT s2] // linear\n    //     [0   -1   0  1] // angular\n    //     [-vT -a1 vT a2] // limit\n    //\n    // u = perp\n    // v = axis\n    // s1 = cross(d + r1, u), s2 = cross(r2, u)\n    // a1 = cross(d + r1, v), a2 = cross(r2, v)\n    // M * (v2 - v1) = JT * df\n    // J * v2 = bias\n    //\n    // v2 = v1 + invM * JT * df\n    // J * (v1 + invM * JT * df) = bias\n    // K * df = bias - J * v1 = -Cdot\n    // K = J * invM * JT\n    // Cdot = J * v1 - bias\n    //\n    // Now solve for f2.\n    // df = f2 - f1\n    // K * (f2 - f1) = -Cdot\n    // f2 = invK * (-Cdot) + f1\n    //\n    // Clamp accumulated limit impulse.\n    // lower: f2(3) = max(f2(3), 0)\n    // upper: f2(3) = min(f2(3), 0)\n    //\n    // Solve for correct f2(1:2)\n    // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1\n    //                       = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)\n    // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)\n    // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)\n    //\n    // Now compute impulse to be applied:\n    // df = f2 - f1\n\n    /// <summary>\n    /// A prismatic joint. This joint provides one degree of freedom: translation\n    /// along an axis fixed in bodyA. Relative rotation is prevented. You can\n    /// use a joint limit to restrict the range of motion and a joint motor to\n    /// drive the motion or to model joint friction.\n    /// </summary>\n    public class PrismaticJoint : Joint\n    {\n        private float _a1, _a2;\n        private Vector2 _axis, _perp;\n        private Vector2 _axis1;\n        private bool _enableLimit;\n        private bool _enableMotor;\n        private Vector3 _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Mat33 _K;\n        private LimitState _limitState;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private Vector2 _localYAxisA;\n        private float _lowerTranslation;\n        private float _maxMotorForce;\n        private float _motorMass;\n        private float _motorSpeed;\n        private float _s1, _s2;\n        private float _upperTranslation;\n\n        internal PrismaticJoint()\n        {\n            JointType = JointType.Prismatic;\n        }\n\n        /// <summary>\n        /// This requires defining a line of\n        /// motion using an axis and an anchor point. The definition uses local\n        /// anchor points and a local axis so that the initial configuration\n        /// can violate the constraint slightly. The joint translation is zero\n        /// when the local anchor points coincide in world space. Using local\n        /// anchors and a local axis helps when saving and loading a game.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body.</param>\n        /// <param name=\"bodyB\">The second body.</param>\n        /// <param name=\"anchorA\">The first body anchor.</param>\n        /// <param name=\"anchorB\">The second body anchor.</param>\n        /// <param name=\"axis\">The axis.</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public PrismaticJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, Vector2 axis, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            Initialize(anchorA, anchorB, axis, useWorldCoordinates);\n        }\n\n        public PrismaticJoint(Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            Initialize(anchor, anchor, axis, useWorldCoordinates);\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// Get the current joint translation, usually in meters.\n        /// </summary>\n        /// <value></value>\n        public float JointTranslation\n        {\n            get\n            {\n                Vector2 d = BodyB.GetWorldPoint(LocalAnchorB) - BodyA.GetWorldPoint(LocalAnchorA);\n                Vector2 axis = BodyA.GetWorldVector(LocalXAxis);\n\n                return Vector2.Dot(d, axis);\n            }\n        }\n\n        /// <summary>\n        /// Get the current joint translation speed, usually in meters per second.\n        /// </summary>\n        /// <value></value>\n        public float JointSpeed\n        {\n            get\n            {\n                Transform xf1, xf2;\n                BodyA.GetTransform(out xf1);\n                BodyB.GetTransform(out xf2);\n\n                Vector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - BodyA.LocalCenter);\n                Vector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - BodyB.LocalCenter);\n                Vector2 p1 = BodyA._sweep.C + r1;\n                Vector2 p2 = BodyB._sweep.C + r2;\n                Vector2 d = p2 - p1;\n                Vector2 axis = BodyA.GetWorldVector(LocalXAxis);\n\n                Vector2 v1 = BodyA._linearVelocity;\n                Vector2 v2 = BodyB._linearVelocity;\n                float w1 = BodyA._angularVelocity;\n                float w2 = BodyB._angularVelocity;\n\n                float speed = Vector2.Dot(d, MathUtils.Cross(w1, axis)) + Vector2.Dot(axis, v2 + MathUtils.Cross(w2, r2) - v1 - MathUtils.Cross(w1, r1));\n                return speed;\n            }\n        }\n\n        /// <summary>\n        /// Is the joint limit enabled?\n        /// </summary>\n        /// <value><c>true</c> if [limit enabled]; otherwise, <c>false</c>.</value>\n        public bool LimitEnabled\n        {\n            get { return _enableLimit; }\n            set\n            {\n                Debug.Assert(BodyA.FixedRotation == false || BodyB.FixedRotation == false, \"Warning: limits does currently not work with fixed rotation\");\n\n                if (value == _enableLimit)\n                    return;\n\n                WakeBodies();\n                _enableLimit = value;\n                _impulse.Z = 0;\n            }\n        }\n\n        /// <summary>\n        /// Get the lower joint limit, usually in meters.\n        /// </summary>\n        /// <value></value>\n        public float LowerLimit\n        {\n            get { return _lowerTranslation; }\n            set\n            {\n                if (value == _lowerTranslation)\n                    return;\n\n                WakeBodies();\n                _lowerTranslation = value;\n                _impulse.Z = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Get the upper joint limit, usually in meters.\n        /// </summary>\n        /// <value></value>\n        public float UpperLimit\n        {\n            get { return _upperTranslation; }\n            set\n            {\n                if (value == _upperTranslation)\n                    return;\n\n                WakeBodies();\n                _upperTranslation = value;\n                _impulse.Z = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Is the joint motor enabled?\n        /// </summary>\n        /// <value><c>true</c> if [motor enabled]; otherwise, <c>false</c>.</value>\n        public bool MotorEnabled\n        {\n            get { return _enableMotor; }\n            set\n            {\n                if (value == _enableMotor)\n                    return;\n\n                WakeBodies();\n                _enableMotor = value;\n            }\n        }\n\n        /// <summary>\n        /// Set the motor speed, usually in meters per second.\n        /// </summary>\n        /// <value>The speed.</value>\n        public float MotorSpeed\n        {\n            set\n            {\n                if (value == _motorSpeed)\n                    return;\n\n                WakeBodies();\n                _motorSpeed = value;\n            }\n            get { return _motorSpeed; }\n        }\n\n        /// <summary>\n        /// Set the maximum motor force, usually in N.\n        /// </summary>\n        /// <value>The force.</value>\n        public float MaxMotorForce\n        {\n            get { return _maxMotorForce; }\n            set\n            {\n                if (value == _maxMotorForce)\n                    return;\n\n                WakeBodies();\n                _maxMotorForce = value;\n            }\n        }\n\n        /// <summary>\n        /// Get the current motor impulse, usually in N.\n        /// </summary>\n        /// <value></value>\n        public float MotorImpulse { get; set; }\n\n        /// <summary>\n        /// The axis at which the joint moves.\n        /// </summary>\n        public Vector2 Axis\n        {\n            get { return _axis1; }\n            set\n            {\n                _axis1 = value;\n                LocalXAxis = BodyA.GetLocalVector(_axis1);\n                LocalXAxis.Normalize();\n                _localYAxisA = MathUtils.Cross(1.0f, LocalXAxis);\n            }\n        }\n\n        /// <summary>\n        /// The axis in local coordinates relative to BodyA\n        /// </summary>\n        public Vector2 LocalXAxis { get; private set; }\n\n        /// <summary>\n        /// The reference angle.\n        /// </summary>\n        public float ReferenceAngle { get; set; }\n\n        private void Initialize(Vector2 localAnchorA, Vector2 localAnchorB, Vector2 axis, bool useWorldCoordinates)\n        {\n            JointType = JointType.Prismatic;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = BodyA.GetLocalPoint(localAnchorA);\n                LocalAnchorB = BodyB.GetLocalPoint(localAnchorB);\n            }\n            else\n            {\n                LocalAnchorA = localAnchorA;\n                LocalAnchorB = localAnchorB;\n            }\n\n            Axis = axis; //Velcro only: store the orignal value for use in Serialization\n            ReferenceAngle = BodyB.Rotation - BodyA.Rotation;\n\n            _limitState = LimitState.Inactive;\n        }\n\n        /// <summary>\n        /// Set the joint limits, usually in meters.\n        /// </summary>\n        /// <param name=\"lower\">The lower limit</param>\n        /// <param name=\"upper\">The upper limit</param>\n        public void SetLimits(float lower, float upper)\n        {\n            if (upper == _upperTranslation && lower == _lowerTranslation)\n                return;\n\n            WakeBodies();\n            _upperTranslation = upper;\n            _lowerTranslation = lower;\n            _impulse.Z = 0.0f;\n        }\n\n        /// <summary>\n        /// Gets the motor force.\n        /// </summary>\n        /// <param name=\"invDt\">The inverse delta time</param>\n        public float GetMotorForce(float invDt)\n        {\n            return invDt * MotorImpulse;\n        }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * (_impulse.X * _perp + (MotorImpulse + _impulse.Z) * _axis);\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _impulse.Y;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            // Compute the effective masses.\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 d = (cB - cA) + rB - rA;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            // Compute motor Jacobian and effective mass.\n            {\n                _axis = MathUtils.Mul(qA, LocalXAxis);\n                _a1 = MathUtils.Cross(d + rA, _axis);\n                _a2 = MathUtils.Cross(rB, _axis);\n\n                _motorMass = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2;\n                if (_motorMass > 0.0f)\n                {\n                    _motorMass = 1.0f / _motorMass;\n                }\n            }\n\n            // Prismatic constraint.\n            {\n                _perp = MathUtils.Mul(qA, _localYAxisA);\n\n                _s1 = MathUtils.Cross(d + rA, _perp);\n                _s2 = MathUtils.Cross(rB, _perp);\n\n                float k11 = mA + mB + iA * _s1 * _s1 + iB * _s2 * _s2;\n                float k12 = iA * _s1 + iB * _s2;\n                float k13 = iA * _s1 * _a1 + iB * _s2 * _a2;\n                float k22 = iA + iB;\n                if (k22 == 0.0f)\n                {\n                    // For bodies with fixed rotation.\n                    k22 = 1.0f;\n                }\n                float k23 = iA * _a1 + iB * _a2;\n                float k33 = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2;\n\n                _K.ex = new Vector3(k11, k12, k13);\n                _K.ey = new Vector3(k12, k22, k23);\n                _K.ez = new Vector3(k13, k23, k33);\n            }\n\n            // Compute motor and limit terms.\n            if (_enableLimit)\n            {\n                float jointTranslation = Vector2.Dot(_axis, d);\n                if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)\n                {\n                    _limitState = LimitState.Equal;\n                }\n                else if (jointTranslation <= _lowerTranslation)\n                {\n                    if (_limitState != LimitState.AtLower)\n                    {\n                        _limitState = LimitState.AtLower;\n                        _impulse.Z = 0.0f;\n                    }\n                }\n                else if (jointTranslation >= _upperTranslation)\n                {\n                    if (_limitState != LimitState.AtUpper)\n                    {\n                        _limitState = LimitState.AtUpper;\n                        _impulse.Z = 0.0f;\n                    }\n                }\n                else\n                {\n                    _limitState = LimitState.Inactive;\n                    _impulse.Z = 0.0f;\n                }\n            }\n            else\n            {\n                _limitState = LimitState.Inactive;\n                _impulse.Z = 0.0f;\n            }\n\n            if (_enableMotor == false)\n            {\n                MotorImpulse = 0.0f;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Account for variable time step.\n                _impulse *= data.Step.dtRatio;\n                MotorImpulse *= data.Step.dtRatio;\n\n                Vector2 P = _impulse.X * _perp + (MotorImpulse + _impulse.Z) * _axis;\n                float LA = _impulse.X * _s1 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a1;\n                float LB = _impulse.X * _s2 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a2;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n            else\n            {\n                _impulse = Vector3.Zero;\n                MotorImpulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            // Solve linear motor constraint.\n            if (_enableMotor && _limitState != LimitState.Equal)\n            {\n                float Cdot = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA;\n                float impulse = _motorMass * (_motorSpeed - Cdot);\n                float oldImpulse = MotorImpulse;\n                float maxImpulse = data.Step.dt * _maxMotorForce;\n                MotorImpulse = MathUtils.Clamp(MotorImpulse + impulse, -maxImpulse, maxImpulse);\n                impulse = MotorImpulse - oldImpulse;\n\n                Vector2 P = impulse * _axis;\n                float LA = impulse * _a1;\n                float LB = impulse * _a2;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n\n            Vector2 Cdot1 = new Vector2();\n            Cdot1.X = Vector2.Dot(_perp, vB - vA) + _s2 * wB - _s1 * wA;\n            Cdot1.Y = wB - wA;\n\n            if (_enableLimit && _limitState != LimitState.Inactive)\n            {\n                // Solve prismatic and limit constraint in block form.\n                float Cdot2;\n                Cdot2 = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA;\n                Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);\n\n                Vector3 f1 = _impulse;\n                Vector3 df = _K.Solve33(-Cdot);\n                _impulse += df;\n\n                if (_limitState == LimitState.AtLower)\n                {\n                    _impulse.Z = Math.Max(_impulse.Z, 0.0f);\n                }\n                else if (_limitState == LimitState.AtUpper)\n                {\n                    _impulse.Z = Math.Min(_impulse.Z, 0.0f);\n                }\n\n                // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)\n                Vector2 b = -Cdot1 - (_impulse.Z - f1.Z) * new Vector2(_K.ez.X, _K.ez.Y);\n                Vector2 f2r = _K.Solve22(b) + new Vector2(f1.X, f1.Y);\n                _impulse.X = f2r.X;\n                _impulse.Y = f2r.Y;\n\n                df = _impulse - f1;\n\n                Vector2 P = df.X * _perp + df.Z * _axis;\n                float LA = df.X * _s1 + df.Y + df.Z * _a1;\n                float LB = df.X * _s2 + df.Y + df.Z * _a2;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n            else\n            {\n                // Limit is inactive, just solve the prismatic constraint in block form.\n                Vector2 df = _K.Solve22(-Cdot1);\n                _impulse.X += df.X;\n                _impulse.Y += df.Y;\n\n                Vector2 P = df.X * _perp;\n                float LA = df.X * _s1 + df.Y;\n                float LB = df.X * _s2 + df.Y;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            // Compute fresh Jacobians\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 d = cB + rB - cA - rA;\n\n            Vector2 axis = MathUtils.Mul(qA, LocalXAxis);\n            float a1 = MathUtils.Cross(d + rA, axis);\n            float a2 = MathUtils.Cross(rB, axis);\n            Vector2 perp = MathUtils.Mul(qA, _localYAxisA);\n\n            float s1 = MathUtils.Cross(d + rA, perp);\n            float s2 = MathUtils.Cross(rB, perp);\n\n            Vector3 impulse;\n            Vector2 C1 = new Vector2();\n            C1.X = Vector2.Dot(perp, d);\n            C1.Y = aB - aA - ReferenceAngle;\n\n            float linearError = Math.Abs(C1.X);\n            float angularError = Math.Abs(C1.Y);\n\n            bool active = false;\n            float C2 = 0.0f;\n            if (_enableLimit)\n            {\n                float translation = Vector2.Dot(axis, d);\n                if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)\n                {\n                    // Prevent large angular corrections\n                    C2 = MathUtils.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);\n                    linearError = Math.Max(linearError, Math.Abs(translation));\n                    active = true;\n                }\n                else if (translation <= _lowerTranslation)\n                {\n                    // Prevent large linear corrections and allow some slop.\n                    C2 = MathUtils.Clamp(translation - _lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);\n                    linearError = Math.Max(linearError, _lowerTranslation - translation);\n                    active = true;\n                }\n                else if (translation >= _upperTranslation)\n                {\n                    // Prevent large linear corrections and allow some slop.\n                    C2 = MathUtils.Clamp(translation - _upperTranslation - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection);\n                    linearError = Math.Max(linearError, translation - _upperTranslation);\n                    active = true;\n                }\n            }\n\n            if (active)\n            {\n                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;\n                float k12 = iA * s1 + iB * s2;\n                float k13 = iA * s1 * a1 + iB * s2 * a2;\n                float k22 = iA + iB;\n                if (k22 == 0.0f)\n                {\n                    // For fixed rotation\n                    k22 = 1.0f;\n                }\n                float k23 = iA * a1 + iB * a2;\n                float k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;\n\n                Mat33 K = new Mat33();\n                K.ex = new Vector3(k11, k12, k13);\n                K.ey = new Vector3(k12, k22, k23);\n                K.ez = new Vector3(k13, k23, k33);\n\n                Vector3 C = new Vector3();\n                C.X = C1.X;\n                C.Y = C1.Y;\n                C.Z = C2;\n\n                impulse = K.Solve33(-C);\n            }\n            else\n            {\n                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;\n                float k12 = iA * s1 + iB * s2;\n                float k22 = iA + iB;\n                if (k22 == 0.0f)\n                {\n                    k22 = 1.0f;\n                }\n\n                Mat22 K = new Mat22();\n                K.ex = new Vector2(k11, k12);\n                K.ey = new Vector2(k12, k22);\n\n                Vector2 impulse1 = K.Solve(-C1);\n                impulse = new Vector3();\n                impulse.X = impulse1.X;\n                impulse.Y = impulse1.Y;\n                impulse.Z = 0.0f;\n            }\n\n            Vector2 P = impulse.X * perp + impulse.Z * axis;\n            float LA = impulse.X * s1 + impulse.Y + impulse.Z * a1;\n            float LB = impulse.X * s2 + impulse.Y + impulse.Z * a2;\n\n            cA -= mA * P;\n            aA -= iA * LA;\n            cB += mB * P;\n            aB += iB * LB;\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/PulleyJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Pulley:\n    // length1 = norm(p1 - s1)\n    // length2 = norm(p2 - s2)\n    // C0 = (length1 + ratio * length2)_initial\n    // C = C0 - (length1 + ratio * length2)\n    // u1 = (p1 - s1) / norm(p1 - s1)\n    // u2 = (p2 - s2) / norm(p2 - s2)\n    // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))\n    // J = -[u1 cross(r1, u1) ratio * u2  ratio * cross(r2, u2)]\n    // K = J * invM * JT\n    //   = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)\n\n    /// <summary>\n    /// The pulley joint is connected to two bodies and two fixed world points.\n    /// The pulley supports a ratio such that:\n    /// <![CDATA[length1 + ratio * length2 <= constant]]>\n    /// Yes, the force transmitted is scaled by the ratio.\n    /// Warning: the pulley joint can get a bit squirrelly by itself. They often\n    /// work better when combined with prismatic joints. You should also cover the\n    /// the anchor points with static shapes to prevent one side from going to zero length.\n    /// </summary>\n    public class PulleyJoint : Joint\n    {\n        // Solver shared\n        private float _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private float _mass;\n        private Vector2 _rA;\n        private Vector2 _rB;\n        private Vector2 _uA;\n        private Vector2 _uB;\n\n        internal PulleyJoint()\n        {\n            JointType = JointType.Pulley;\n        }\n\n        /// <summary>\n        /// Constructor for PulleyJoint.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body.</param>\n        /// <param name=\"bodyB\">The second body.</param>\n        /// <param name=\"anchorA\">The anchor on the first body.</param>\n        /// <param name=\"anchorB\">The anchor on the second body.</param>\n        /// <param name=\"worldAnchorA\">The world anchor for the first body.</param>\n        /// <param name=\"worldAnchorB\">The world anchor for the second body.</param>\n        /// <param name=\"ratio\">The ratio.</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public PulleyJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, Vector2 worldAnchorA, Vector2 worldAnchorB, float ratio, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Pulley;\n\n            WorldAnchorA = worldAnchorA;\n            WorldAnchorB = worldAnchorB;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = BodyA.GetLocalPoint(anchorA);\n                LocalAnchorB = BodyB.GetLocalPoint(anchorB);\n\n                Vector2 dA = anchorA - worldAnchorA;\n                LengthA = dA.Length();\n                Vector2 dB = anchorB - worldAnchorB;\n                LengthB = dB.Length();\n            }\n            else\n            {\n                LocalAnchorA = anchorA;\n                LocalAnchorB = anchorB;\n\n                Vector2 dA = anchorA - BodyA.GetLocalPoint(worldAnchorA);\n                LengthA = dA.Length();\n                Vector2 dB = anchorB - BodyB.GetLocalPoint(worldAnchorB);\n                LengthB = dB.Length();\n            }\n\n            Debug.Assert(ratio != 0.0f);\n            Debug.Assert(ratio > Settings.Epsilon);\n\n            Ratio = ratio;\n            Constant = LengthA + ratio * LengthB;\n            _impulse = 0.0f;\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// Get the first world anchor.\n        /// </summary>\n        /// <value></value>\n        public sealed override Vector2 WorldAnchorA { get; set; }\n\n        /// <summary>\n        /// Get the second world anchor.\n        /// </summary>\n        /// <value></value>\n        public sealed override Vector2 WorldAnchorB { get; set; }\n\n        /// <summary>\n        /// Get the current length of the segment attached to body1.\n        /// </summary>\n        /// <value></value>\n        public float LengthA { get; set; }\n\n        /// <summary>\n        /// Get the current length of the segment attached to body2.\n        /// </summary>\n        /// <value></value>\n        public float LengthB { get; set; }\n\n        /// <summary>\n        /// The current length between the anchor point on BodyA and WorldAnchorA\n        /// </summary>\n        public float CurrentLengthA\n        {\n            get\n            {\n                Vector2 p = BodyA.GetWorldPoint(LocalAnchorA);\n                Vector2 s = WorldAnchorA;\n                Vector2 d = p - s;\n                return d.Length();\n            }\n        }\n\n        /// <summary>\n        /// The current length between the anchor point on BodyB and WorldAnchorB\n        /// </summary>\n        public float CurrentLengthB\n        {\n            get\n            {\n                Vector2 p = BodyB.GetWorldPoint(LocalAnchorB);\n                Vector2 s = WorldAnchorB;\n                Vector2 d = p - s;\n                return d.Length();\n            }\n        }\n\n        /// <summary>\n        /// Get the pulley ratio.\n        /// </summary>\n        /// <value></value>\n        public float Ratio { get; set; }\n\n        //Velcro note: Only used for serialization.\n        internal float Constant { get; set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            Vector2 P = _impulse * _uB;\n            return invDt * P;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return 0.0f;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            // Get the pulley axes.\n            _uA = cA + _rA - WorldAnchorA;\n            _uB = cB + _rB - WorldAnchorB;\n\n            float lengthA = _uA.Length();\n            float lengthB = _uB.Length();\n\n            if (lengthA > 10.0f * Settings.LinearSlop)\n            {\n                _uA *= 1.0f / lengthA;\n            }\n            else\n            {\n                _uA = Vector2.Zero;\n            }\n\n            if (lengthB > 10.0f * Settings.LinearSlop)\n            {\n                _uB *= 1.0f / lengthB;\n            }\n            else\n            {\n                _uB = Vector2.Zero;\n            }\n\n            // Compute effective mass.\n            float ruA = MathUtils.Cross(_rA, _uA);\n            float ruB = MathUtils.Cross(_rB, _uB);\n\n            float mA = _invMassA + _invIA * ruA * ruA;\n            float mB = _invMassB + _invIB * ruB * ruB;\n\n            _mass = mA + Ratio * Ratio * mB;\n\n            if (_mass > 0.0f)\n            {\n                _mass = 1.0f / _mass;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale impulses to support variable time steps.\n                _impulse *= data.Step.dtRatio;\n\n                // Warm starting.\n                Vector2 PA = -(_impulse) * _uA;\n                Vector2 PB = (-Ratio * _impulse) * _uB;\n\n                vA += _invMassA * PA;\n                wA += _invIA * MathUtils.Cross(_rA, PA);\n                vB += _invMassB * PB;\n                wB += _invIB * MathUtils.Cross(_rB, PB);\n            }\n            else\n            {\n                _impulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Vector2 vpA = vA + MathUtils.Cross(wA, _rA);\n            Vector2 vpB = vB + MathUtils.Cross(wB, _rB);\n\n            float Cdot = -Vector2.Dot(_uA, vpA) - Ratio * Vector2.Dot(_uB, vpB);\n            float impulse = -_mass * Cdot;\n            _impulse += impulse;\n\n            Vector2 PA = -impulse * _uA;\n            Vector2 PB = -Ratio * impulse * _uB;\n            vA += _invMassA * PA;\n            wA += _invIA * MathUtils.Cross(_rA, PA);\n            vB += _invMassB * PB;\n            wB += _invIB * MathUtils.Cross(_rB, PB);\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            // Get the pulley axes.\n            Vector2 uA = cA + rA - WorldAnchorA;\n            Vector2 uB = cB + rB - WorldAnchorB;\n\n            float lengthA = uA.Length();\n            float lengthB = uB.Length();\n\n            if (lengthA > 10.0f * Settings.LinearSlop)\n            {\n                uA *= 1.0f / lengthA;\n            }\n            else\n            {\n                uA = Vector2.Zero;\n            }\n\n            if (lengthB > 10.0f * Settings.LinearSlop)\n            {\n                uB *= 1.0f / lengthB;\n            }\n            else\n            {\n                uB = Vector2.Zero;\n            }\n\n            // Compute effective mass.\n            float ruA = MathUtils.Cross(rA, uA);\n            float ruB = MathUtils.Cross(rB, uB);\n\n            float mA = _invMassA + _invIA * ruA * ruA;\n            float mB = _invMassB + _invIB * ruB * ruB;\n\n            float mass = mA + Ratio * Ratio * mB;\n\n            if (mass > 0.0f)\n            {\n                mass = 1.0f / mass;\n            }\n\n            float C = Constant - lengthA - Ratio * lengthB;\n            float linearError = Math.Abs(C);\n\n            float impulse = -mass * C;\n\n            Vector2 PA = -impulse * uA;\n            Vector2 PB = -Ratio * impulse * uB;\n\n            cA += _invMassA * PA;\n            aA += _invIA * MathUtils.Cross(rA, PA);\n            cB += _invMassB * PB;\n            aB += _invIB * MathUtils.Cross(rB, PB);\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return linearError < Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/RevoluteJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    /// <summary>\n    /// A revolute joint constrains to bodies to share a common point while they\n    /// are free to rotate about the point. The relative rotation about the shared\n    /// point is the joint angle. You can limit the relative rotation with\n    /// a joint limit that specifies a lower and upper angle. You can use a motor\n    /// to drive the relative rotation about the shared point. A maximum motor torque\n    /// is provided so that infinite forces are not generated.\n    /// </summary>\n    public class RevoluteJoint : Joint\n    {\n        private bool _enableLimit;\n\n        private bool _enableMotor;\n\n        // Solver shared\n        private Vector3 _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private LimitState _limitState;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private float _lowerAngle;\n        private Mat33 _mass; // effective mass for point-to-point constraint.\n        private float _maxMotorTorque;\n        private float _motorImpulse;\n        private float _motorMass; // effective mass for motor/limit angular constraint.\n        private float _motorSpeed;\n        private Vector2 _rA;\n        private Vector2 _rB;\n        private float _referenceAngle;\n        private float _upperAngle;\n\n        internal RevoluteJoint()\n        {\n            JointType = JointType.Revolute;\n        }\n\n        /// <summary>\n        /// Constructor of RevoluteJoint.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body.</param>\n        /// <param name=\"bodyB\">The second body.</param>\n        /// <param name=\"anchorA\">The first body anchor.</param>\n        /// <param name=\"anchorB\">The second anchor.</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public RevoluteJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Revolute;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = BodyA.GetLocalPoint(anchorA);\n                LocalAnchorB = BodyB.GetLocalPoint(anchorB);\n            }\n            else\n            {\n                LocalAnchorA = anchorA;\n                LocalAnchorB = anchorB;\n            }\n\n            ReferenceAngle = BodyB.Rotation - BodyA.Rotation;\n\n            _impulse = Vector3.Zero;\n            _limitState = LimitState.Inactive;\n        }\n\n        /// <summary>\n        /// Constructor of RevoluteJoint.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body.</param>\n        /// <param name=\"bodyB\">The second body.</param>\n        /// <param name=\"anchor\">The shared anchor.</param>\n        /// <param name=\"useWorldCoordinates\"></param>\n        public RevoluteJoint(Body bodyA, Body bodyB, Vector2 anchor, bool useWorldCoordinates = false)\n            : this(bodyA, bodyB, anchor, anchor, useWorldCoordinates) { }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// The referance angle computed as BodyB angle minus BodyA angle.\n        /// </summary>\n        public float ReferenceAngle\n        {\n            get { return _referenceAngle; }\n            set\n            {\n                WakeBodies();\n                _referenceAngle = value;\n            }\n        }\n\n        /// <summary>\n        /// Get the current joint angle in radians.\n        /// </summary>\n        public float JointAngle\n        {\n            get { return BodyB._sweep.A - BodyA._sweep.A - ReferenceAngle; }\n        }\n\n        /// <summary>\n        /// Get the current joint angle speed in radians per second.\n        /// </summary>\n        public float JointSpeed\n        {\n            get { return BodyB._angularVelocity - BodyA._angularVelocity; }\n        }\n\n        /// <summary>\n        /// Is the joint limit enabled?\n        /// </summary>\n        /// <value><c>true</c> if [limit enabled]; otherwise, <c>false</c>.</value>\n        public bool LimitEnabled\n        {\n            get { return _enableLimit; }\n            set\n            {\n                if (_enableLimit == value)\n                    return;\n\n                WakeBodies();\n                _enableLimit = value;\n                _impulse.Z = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Get the lower joint limit in radians.\n        /// </summary>\n        public float LowerLimit\n        {\n            get { return _lowerAngle; }\n            set\n            {\n                if (_lowerAngle == value)\n                    return;\n\n                WakeBodies();\n                _lowerAngle = value;\n                _impulse.Z = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Get the upper joint limit in radians.\n        /// </summary>\n        public float UpperLimit\n        {\n            get { return _upperAngle; }\n            set\n            {\n                if (_upperAngle == value)\n                    return;\n\n                WakeBodies();\n                _upperAngle = value;\n                _impulse.Z = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Is the joint motor enabled?\n        /// </summary>\n        /// <value><c>true</c> if [motor enabled]; otherwise, <c>false</c>.</value>\n        public bool MotorEnabled\n        {\n            get { return _enableMotor; }\n            set\n            {\n                if (value == _enableMotor)\n                    return;\n\n                WakeBodies();\n                _enableMotor = value;\n            }\n        }\n\n        /// <summary>\n        /// Get or set the motor speed in radians per second.\n        /// </summary>\n        public float MotorSpeed\n        {\n            set\n            {\n                if (value == _motorSpeed)\n                    return;\n\n                WakeBodies();\n                _motorSpeed = value;\n            }\n            get { return _motorSpeed; }\n        }\n\n        /// <summary>\n        /// Get or set the maximum motor torque, usually in N-m.\n        /// </summary>\n        public float MaxMotorTorque\n        {\n            set\n            {\n                if (value == _maxMotorTorque)\n                    return;\n\n                WakeBodies();\n                _maxMotorTorque = value;\n            }\n            get { return _maxMotorTorque; }\n        }\n\n        /// <summary>\n        /// Get or set the current motor impulse, usually in N-m.\n        /// </summary>\n        public float MotorImpulse\n        {\n            get { return _motorImpulse; }\n            set\n            {\n                if (value == _motorImpulse)\n                    return;\n\n                WakeBodies();\n                _motorImpulse = value;\n            }\n        }\n\n        /// <summary>\n        /// Set the joint limits, usually in meters.\n        /// </summary>\n        /// <param name=\"lower\">The lower limit</param>\n        /// <param name=\"upper\">The upper limit</param>\n        public void SetLimits(float lower, float upper)\n        {\n            if (lower == _lowerAngle && upper == _upperAngle)\n                return;\n\n            WakeBodies();\n            _upperAngle = upper;\n            _lowerAngle = lower;\n            _impulse.Z = 0.0f;\n        }\n\n        /// <summary>\n        /// Gets the motor torque in N-m.\n        /// </summary>\n        /// <param name=\"invDt\">The inverse delta time</param>\n        public float GetMotorTorque(float invDt)\n        {\n            return invDt * _motorImpulse;\n        }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            Vector2 p = new Vector2(_impulse.X, _impulse.Y);\n            return invDt * p;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _impulse.Z;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            // J = [-I -r1_skew I r2_skew]\n            //     [ 0       -1 0       1]\n            // r_skew = [-ry; rx]\n\n            // Matlab\n            // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]\n            //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]\n            //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            bool fixedRotation = (iA + iB == 0.0f);\n\n            _mass.ex.X = mA + mB + _rA.Y * _rA.Y * iA + _rB.Y * _rB.Y * iB;\n            _mass.ey.X = -_rA.Y * _rA.X * iA - _rB.Y * _rB.X * iB;\n            _mass.ez.X = -_rA.Y * iA - _rB.Y * iB;\n            _mass.ex.Y = _mass.ey.X;\n            _mass.ey.Y = mA + mB + _rA.X * _rA.X * iA + _rB.X * _rB.X * iB;\n            _mass.ez.Y = _rA.X * iA + _rB.X * iB;\n            _mass.ex.Z = _mass.ez.X;\n            _mass.ey.Z = _mass.ez.Y;\n            _mass.ez.Z = iA + iB;\n\n            _motorMass = iA + iB;\n            if (_motorMass > 0.0f)\n            {\n                _motorMass = 1.0f / _motorMass;\n            }\n\n            if (_enableMotor == false || fixedRotation)\n            {\n                _motorImpulse = 0.0f;\n            }\n\n            if (_enableLimit && fixedRotation == false)\n            {\n                float jointAngle = aB - aA - ReferenceAngle;\n                if (Math.Abs(_upperAngle - _lowerAngle) < 2.0f * Settings.AngularSlop)\n                {\n                    _limitState = LimitState.Equal;\n                }\n                else if (jointAngle <= _lowerAngle)\n                {\n                    if (_limitState != LimitState.AtLower)\n                    {\n                        _impulse.Z = 0.0f;\n                    }\n                    _limitState = LimitState.AtLower;\n                }\n                else if (jointAngle >= _upperAngle)\n                {\n                    if (_limitState != LimitState.AtUpper)\n                    {\n                        _impulse.Z = 0.0f;\n                    }\n                    _limitState = LimitState.AtUpper;\n                }\n                else\n                {\n                    _limitState = LimitState.Inactive;\n                    _impulse.Z = 0.0f;\n                }\n            }\n            else\n            {\n                _limitState = LimitState.Inactive;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale impulses to support a variable time step.\n                _impulse *= data.Step.dtRatio;\n                _motorImpulse *= data.Step.dtRatio;\n\n                Vector2 P = new Vector2(_impulse.X, _impulse.Y);\n\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + MotorImpulse + _impulse.Z);\n\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + MotorImpulse + _impulse.Z);\n            }\n            else\n            {\n                _impulse = Vector3.Zero;\n                _motorImpulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            bool fixedRotation = (iA + iB == 0.0f);\n\n            // Solve motor constraint.\n            if (_enableMotor && _limitState != LimitState.Equal && fixedRotation == false)\n            {\n                float Cdot = wB - wA - _motorSpeed;\n                float impulse = _motorMass * (-Cdot);\n                float oldImpulse = _motorImpulse;\n                float maxImpulse = data.Step.dt * _maxMotorTorque;\n                _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);\n                impulse = _motorImpulse - oldImpulse;\n\n                wA -= iA * impulse;\n                wB += iB * impulse;\n            }\n\n            // Solve limit constraint.\n            if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false)\n            {\n                Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);\n                float Cdot2 = wB - wA;\n                Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);\n\n                Vector3 impulse = -_mass.Solve33(Cdot);\n\n                if (_limitState == LimitState.Equal)\n                {\n                    _impulse += impulse;\n                }\n                else if (_limitState == LimitState.AtLower)\n                {\n                    float newImpulse = _impulse.Z + impulse.Z;\n                    if (newImpulse < 0.0f)\n                    {\n                        Vector2 rhs = -Cdot1 + _impulse.Z * new Vector2(_mass.ez.X, _mass.ez.Y);\n                        Vector2 reduced = _mass.Solve22(rhs);\n                        impulse.X = reduced.X;\n                        impulse.Y = reduced.Y;\n                        impulse.Z = -_impulse.Z;\n                        _impulse.X += reduced.X;\n                        _impulse.Y += reduced.Y;\n                        _impulse.Z = 0.0f;\n                    }\n                    else\n                    {\n                        _impulse += impulse;\n                    }\n                }\n                else if (_limitState == LimitState.AtUpper)\n                {\n                    float newImpulse = _impulse.Z + impulse.Z;\n                    if (newImpulse > 0.0f)\n                    {\n                        Vector2 rhs = -Cdot1 + _impulse.Z * new Vector2(_mass.ez.X, _mass.ez.Y);\n                        Vector2 reduced = _mass.Solve22(rhs);\n                        impulse.X = reduced.X;\n                        impulse.Y = reduced.Y;\n                        impulse.Z = -_impulse.Z;\n                        _impulse.X += reduced.X;\n                        _impulse.Y += reduced.Y;\n                        _impulse.Z = 0.0f;\n                    }\n                    else\n                    {\n                        _impulse += impulse;\n                    }\n                }\n\n                Vector2 P = new Vector2(impulse.X, impulse.Y);\n\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z);\n\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z);\n            }\n            else\n            {\n                // Solve point-to-point constraint\n                Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);\n                Vector2 impulse = _mass.Solve22(-Cdot);\n\n                _impulse.X += impulse.X;\n                _impulse.Y += impulse.Y;\n\n                vA -= mA * impulse;\n                wA -= iA * MathUtils.Cross(_rA, impulse);\n\n                vB += mB * impulse;\n                wB += iB * MathUtils.Cross(_rB, impulse);\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            float angularError = 0.0f;\n            float positionError;\n\n            bool fixedRotation = (_invIA + _invIB == 0.0f);\n\n            // Solve angular limit constraint.\n            if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false)\n            {\n                float angle = aB - aA - ReferenceAngle;\n                float limitImpulse = 0.0f;\n\n                if (_limitState == LimitState.Equal)\n                {\n                    // Prevent large angular corrections\n                    float C = MathUtils.Clamp(angle - _lowerAngle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);\n                    limitImpulse = -_motorMass * C;\n                    angularError = Math.Abs(C);\n                }\n                else if (_limitState == LimitState.AtLower)\n                {\n                    float C = angle - _lowerAngle;\n                    angularError = -C;\n\n                    // Prevent large angular corrections and allow some slop.\n                    C = MathUtils.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);\n                    limitImpulse = -_motorMass * C;\n                }\n                else if (_limitState == LimitState.AtUpper)\n                {\n                    float C = angle - _upperAngle;\n                    angularError = C;\n\n                    // Prevent large angular corrections and allow some slop.\n                    C = MathUtils.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);\n                    limitImpulse = -_motorMass * C;\n                }\n\n                aA -= _invIA * limitImpulse;\n                aB += _invIB * limitImpulse;\n            }\n\n            // Solve point-to-point constraint.\n            {\n                qA.Set(aA);\n                qB.Set(aB);\n                Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n                Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n                Vector2 C = cB + rB - cA - rA;\n                positionError = C.Length();\n\n                float mA = _invMassA, mB = _invMassB;\n                float iA = _invIA, iB = _invIB;\n\n                Mat22 K = new Mat22();\n                K.ex.X = mA + mB + iA * rA.Y * rA.Y + iB * rB.Y * rB.Y;\n                K.ex.Y = -iA * rA.X * rA.Y - iB * rB.X * rB.Y;\n                K.ey.X = K.ex.Y;\n                K.ey.Y = mA + mB + iA * rA.X * rA.X + iB * rB.X * rB.X;\n\n                Vector2 impulse = -K.Solve(C);\n\n                cA -= mA * impulse;\n                aA -= iA * MathUtils.Cross(rA, impulse);\n\n                cB += mB * impulse;\n                aB += iB * MathUtils.Cross(rB, impulse);\n            }\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/RopeJoint.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Limit:\n    // C = norm(pB - pA) - L\n    // u = (pB - pA) / norm(pB - pA)\n    // Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA))\n    // J = [-u -cross(rA, u) u cross(rB, u)]\n    // K = J * invM * JT\n    //   = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2\n\n    /// <summary>\n    /// A rope joint enforces a maximum distance between two points on two bodies. It has no other effect.\n    /// It can be used on ropes that are made up of several connected bodies, and if there is a need to support a heavy body.\n    /// This joint is used for stabilization of heavy objects on soft constraint joints.\n    /// Warning: if you attempt to change the maximum length during the simulation you will get some non-physical behavior.\n    /// Use the DistanceJoint instead if you want to dynamically control the length.\n    /// </summary>\n    public class RopeJoint : Joint\n    {\n        // Solver shared\n        private float _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private float _length;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private float _mass;\n        private Vector2 _rA, _rB;\n        private Vector2 _u;\n\n        internal RopeJoint()\n        {\n            JointType = JointType.Rope;\n        }\n\n        /// <summary>\n        /// Constructor for RopeJoint.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        /// <param name=\"anchorA\">The anchor on the first body</param>\n        /// <param name=\"anchorB\">The anchor on the second body</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public RopeJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Rope;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = bodyA.GetLocalPoint(anchorA);\n                LocalAnchorB = bodyB.GetLocalPoint(anchorB);\n            }\n            else\n            {\n                LocalAnchorA = anchorA;\n                LocalAnchorB = anchorB;\n            }\n\n            //Velcro feature: Setting default MaxLength\n            Vector2 d = WorldAnchorB - WorldAnchorA;\n            MaxLength = d.Length();\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public sealed override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public sealed override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// Get or set the maximum length of the rope.\n        /// By default, it is the distance between the two anchor points.\n        /// </summary>\n        public float MaxLength { get; set; }\n\n        /// <summary>\n        /// Gets the state of the joint.\n        /// </summary>\n        public LimitState State { get; private set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return (invDt * _impulse) * _u;\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return 0;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            _u = cB + _rB - cA - _rA;\n\n            _length = _u.Length();\n\n            float C = _length - MaxLength;\n            if (C > 0.0f)\n            {\n                State = LimitState.AtUpper;\n            }\n            else\n            {\n                State = LimitState.Inactive;\n            }\n\n            if (_length > Settings.LinearSlop)\n            {\n                _u *= 1.0f / _length;\n            }\n            else\n            {\n                _u = Vector2.Zero;\n                _mass = 0.0f;\n                _impulse = 0.0f;\n                return;\n            }\n\n            // Compute effective mass.\n            float crA = MathUtils.Cross(_rA, _u);\n            float crB = MathUtils.Cross(_rB, _u);\n            float invMass = _invMassA + _invIA * crA * crA + _invMassB + _invIB * crB * crB;\n\n            _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale the impulse to support a variable time step.\n                _impulse *= data.Step.dtRatio;\n\n                Vector2 P = _impulse * _u;\n                vA -= _invMassA * P;\n                wA -= _invIA * MathUtils.Cross(_rA, P);\n                vB += _invMassB * P;\n                wB += _invIB * MathUtils.Cross(_rB, P);\n            }\n            else\n            {\n                _impulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            // Cdot = dot(u, v + cross(w, r))\n            Vector2 vpA = vA + MathUtils.Cross(wA, _rA);\n            Vector2 vpB = vB + MathUtils.Cross(wB, _rB);\n            float C = _length - MaxLength;\n            float Cdot = Vector2.Dot(_u, vpB - vpA);\n\n            // Predictive constraint.\n            if (C < 0.0f)\n            {\n                Cdot += data.Step.inv_dt * C;\n            }\n\n            float impulse = -_mass * Cdot;\n            float oldImpulse = _impulse;\n            _impulse = Math.Min(0.0f, _impulse + impulse);\n            impulse = _impulse - oldImpulse;\n\n            Vector2 P = impulse * _u;\n            vA -= _invMassA * P;\n            wA -= _invIA * MathUtils.Cross(_rA, P);\n            vB += _invMassB * P;\n            wB += _invIB * MathUtils.Cross(_rB, P);\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 u = cB + rB - cA - rA;\n\n            float length = u.Length();\n            u.Normalize();\n            float C = length - MaxLength;\n\n            C = MathUtils.Clamp(C, 0.0f, Settings.MaxLinearCorrection);\n\n            float impulse = -_mass * C;\n            Vector2 P = impulse * u;\n\n            cA -= _invMassA * P;\n            aA -= _invIA * MathUtils.Cross(rA, P);\n            cB += _invMassB * P;\n            aB += _invIB * MathUtils.Cross(rB, P);\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return length - MaxLength < Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/WeldJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Point-to-point constraint\n    // C = p2 - p1\n    // Cdot = v2 - v1\n    //      = v2 + cross(w2, r2) - v1 - cross(w1, r1)\n    // J = [-I -r1_skew I r2_skew ]\n    // Identity used:\n    // w k % (rx i + ry j) = w * (-ry i + rx j)\n\n    // Angle constraint\n    // C = angle2 - angle1 - referenceAngle\n    // Cdot = w2 - w1\n    // J = [0 0 -1 0 0 1]\n    // K = invI1 + invI2\n\n    /// <summary>\n    /// A weld joint essentially glues two bodies together. A weld joint may\n    /// distort somewhat because the island constraint solver is approximate.\n    /// The joint is soft constraint based, which means the two bodies will move\n    /// relative to each other, when a force is applied. To combine two bodies\n    /// in a rigid fashion, combine the fixtures to a single body instead.\n    /// </summary>\n    public class WeldJoint : Joint\n    {\n        private float _bias;\n\n        private float _gamma;\n\n        // Solver shared\n        private Vector3 _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Vector2 _localCenterA;\n        private Vector2 _localCenterB;\n        private Mat33 _mass;\n        private Vector2 _rA;\n        private Vector2 _rB;\n\n        internal WeldJoint()\n        {\n            JointType = JointType.Weld;\n        }\n\n        /// <summary>\n        /// You need to specify an anchor point where they are attached.\n        /// The position of the anchor point is important for computing the reaction torque.\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        /// <param name=\"anchorA\">The first body anchor.</param>\n        /// <param name=\"anchorB\">The second body anchor.</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public WeldJoint(Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Weld;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = bodyA.GetLocalPoint(anchorA);\n                LocalAnchorB = bodyB.GetLocalPoint(anchorB);\n            }\n            else\n            {\n                LocalAnchorA = anchorA;\n                LocalAnchorB = anchorB;\n            }\n\n            ReferenceAngle = BodyB.Rotation - BodyA.Rotation;\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// The bodyB angle minus bodyA angle in the reference state (radians).\n        /// </summary>\n        public float ReferenceAngle { get; set; }\n\n        /// <summary>\n        /// The frequency of the joint. A higher frequency means a stiffer joint, but\n        /// a too high value can cause the joint to oscillate.\n        /// Default is 0, which means the joint does no spring calculations.\n        /// </summary>\n        public float FrequencyHz { get; set; }\n\n        /// <summary>\n        /// The damping on the joint. The damping is only used when\n        /// the joint has a frequency (> 0). A higher value means more damping.\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * new Vector2(_impulse.X, _impulse.Y);\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _impulse.Z;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            // J = [-I -r1_skew I r2_skew]\n            //     [ 0       -1 0       1]\n            // r_skew = [-ry; rx]\n\n            // Matlab\n            // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]\n            //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]\n            //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Mat33 K = new Mat33();\n            K.ex.X = mA + mB + _rA.Y * _rA.Y * iA + _rB.Y * _rB.Y * iB;\n            K.ey.X = -_rA.Y * _rA.X * iA - _rB.Y * _rB.X * iB;\n            K.ez.X = -_rA.Y * iA - _rB.Y * iB;\n            K.ex.Y = K.ey.X;\n            K.ey.Y = mA + mB + _rA.X * _rA.X * iA + _rB.X * _rB.X * iB;\n            K.ez.Y = _rA.X * iA + _rB.X * iB;\n            K.ex.Z = K.ez.X;\n            K.ey.Z = K.ez.Y;\n            K.ez.Z = iA + iB;\n\n            if (FrequencyHz > 0.0f)\n            {\n                K.GetInverse22(ref _mass);\n\n                float invM = iA + iB;\n                float m = invM > 0.0f ? 1.0f / invM : 0.0f;\n\n                float C = aB - aA - ReferenceAngle;\n\n                // Frequency\n                float omega = 2.0f * Settings.Pi * FrequencyHz;\n\n                // Damping coefficient\n                float d = 2.0f * m * DampingRatio * omega;\n\n                // Spring stiffness\n                float k = m * omega * omega;\n\n                // magic formulas\n                float h = data.Step.dt;\n                _gamma = h * (d + h * k);\n                _gamma = _gamma != 0.0f ? 1.0f / _gamma : 0.0f;\n                _bias = C * h * k * _gamma;\n\n                invM += _gamma;\n                _mass.ez.Z = invM != 0.0f ? 1.0f / invM : 0.0f;\n            }\n            else if (K.ez.Z == 0.0f)\n            {\n                K.GetInverse22(ref _mass);\n                _gamma = 0.0f;\n                _bias = 0.0f;\n            }\n            else\n            {\n                K.GetSymInverse33(ref _mass);\n                _gamma = 0.0f;\n                _bias = 0.0f;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Scale impulses to support a variable time step.\n                _impulse *= data.Step.dtRatio;\n\n                Vector2 P = new Vector2(_impulse.X, _impulse.Y);\n\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + _impulse.Z);\n\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + _impulse.Z);\n            }\n            else\n            {\n                _impulse = Vector3.Zero;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            if (FrequencyHz > 0.0f)\n            {\n                float Cdot2 = wB - wA;\n\n                float impulse2 = -_mass.ez.Z * (Cdot2 + _bias + _gamma * _impulse.Z);\n                _impulse.Z += impulse2;\n\n                wA -= iA * impulse2;\n                wB += iB * impulse2;\n\n                Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);\n\n                Vector2 impulse1 = -MathUtils.Mul22(_mass, Cdot1);\n                _impulse.X += impulse1.X;\n                _impulse.Y += impulse1.Y;\n\n                Vector2 P = impulse1;\n\n                vA -= mA * P;\n                wA -= iA * MathUtils.Cross(_rA, P);\n\n                vB += mB * P;\n                wB += iB * MathUtils.Cross(_rB, P);\n            }\n            else\n            {\n                Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);\n                float Cdot2 = wB - wA;\n                Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);\n\n                Vector3 impulse = -MathUtils.Mul(_mass, Cdot);\n                _impulse += impulse;\n\n                Vector2 P = new Vector2(impulse.X, impulse.Y);\n\n                vA -= mA * P;\n                wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z);\n\n                vB += mB * P;\n                wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z);\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n\n            float positionError, angularError;\n\n            Mat33 K = new Mat33();\n            K.ex.X = mA + mB + rA.Y * rA.Y * iA + rB.Y * rB.Y * iB;\n            K.ey.X = -rA.Y * rA.X * iA - rB.Y * rB.X * iB;\n            K.ez.X = -rA.Y * iA - rB.Y * iB;\n            K.ex.Y = K.ey.X;\n            K.ey.Y = mA + mB + rA.X * rA.X * iA + rB.X * rB.X * iB;\n            K.ez.Y = rA.X * iA + rB.X * iB;\n            K.ex.Z = K.ez.X;\n            K.ey.Z = K.ez.Y;\n            K.ez.Z = iA + iB;\n\n            if (FrequencyHz > 0.0f)\n            {\n                Vector2 C1 = cB + rB - cA - rA;\n\n                positionError = C1.Length();\n                angularError = 0.0f;\n\n                Vector2 P = -K.Solve22(C1);\n\n                cA -= mA * P;\n                aA -= iA * MathUtils.Cross(rA, P);\n\n                cB += mB * P;\n                aB += iB * MathUtils.Cross(rB, P);\n            }\n            else\n            {\n                Vector2 C1 = cB + rB - cA - rA;\n                float C2 = aB - aA - ReferenceAngle;\n\n                positionError = C1.Length();\n                angularError = Math.Abs(C2);\n\n                Vector3 C = new Vector3(C1.X, C1.Y, C2);\n\n                Vector3 impulse;\n                if (K.ez.Z > 0.0f)\n                {\n                    impulse = -K.Solve33(C);\n                }\n                else\n                {\n                    Vector2 impulse2 = -K.Solve22(C1);\n                    impulse = new Vector3(impulse2.X, impulse2.Y, 0.0f);\n                }\n\n                Vector2 P = new Vector2(impulse.X, impulse.Y);\n\n                cA -= mA * P;\n                aA -= iA * (MathUtils.Cross(rA, P) + impulse.Z);\n\n                cB += mB * P;\n                aB += iB * (MathUtils.Cross(rB, P) + impulse.Z);\n            }\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Joints/WheelJoint.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Joints\n{\n    // Linear constraint (point-to-line)\n    // d = pB - pA = xB + rB - xA - rA\n    // C = dot(ay, d)\n    // Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))\n    //      = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)\n    // J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]\n\n    // Spring linear constraint\n    // C = dot(ax, d)\n    // Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)\n    // J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]\n\n    // Motor rotational constraint\n    // Cdot = wB - wA\n    // J = [0 0 -1 0 0 1]\n\n    /// <summary>\n    /// A wheel joint. This joint provides two degrees of freedom: translation\n    /// along an axis fixed in bodyA and rotation in the plane. You can use a\n    /// joint limit to restrict the range of motion and a joint motor to drive\n    /// the rotation or to model rotational friction.\n    /// This joint is designed for vehicle suspensions.\n    /// </summary>\n    public class WheelJoint : Joint\n    {\n        private Vector2 _ax, _ay;\n        private Vector2 _axis;\n\n        private float _bias;\n        private bool _enableMotor;\n        private float _gamma;\n\n        private float _impulse;\n\n        // Solver temp\n        private int _indexA;\n\n        private int _indexB;\n        private float _invIA;\n        private float _invIB;\n        private float _invMassA;\n        private float _invMassB;\n        private Vector2 _localCenterA;\n\n        private Vector2 _localCenterB;\n\n        // Solver shared\n        private Vector2 _localYAxis;\n\n        private float _mass;\n\n        private float _maxMotorTorque;\n        private float _motorImpulse;\n        private float _motorMass;\n        private float _motorSpeed;\n        private float _sAx, _sBx;\n        private float _sAy, _sBy;\n        private float _springImpulse;\n        private float _springMass;\n\n        internal WheelJoint()\n        {\n            JointType = JointType.Wheel;\n        }\n\n        /// <summary>\n        /// Constructor for WheelJoint\n        /// </summary>\n        /// <param name=\"bodyA\">The first body</param>\n        /// <param name=\"bodyB\">The second body</param>\n        /// <param name=\"anchor\">The anchor point</param>\n        /// <param name=\"axis\">The axis</param>\n        /// <param name=\"useWorldCoordinates\">Set to true if you are using world coordinates as anchors.</param>\n        public WheelJoint(Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)\n            : base(bodyA, bodyB)\n        {\n            JointType = JointType.Wheel;\n\n            if (useWorldCoordinates)\n            {\n                LocalAnchorA = bodyA.GetLocalPoint(anchor);\n                LocalAnchorB = bodyB.GetLocalPoint(anchor);\n            }\n            else\n            {\n                LocalAnchorA = bodyA.GetLocalPoint(bodyB.GetWorldPoint(anchor));\n                LocalAnchorB = anchor;\n            }\n\n            Axis = axis; //Velcro only: We maintain the original value as it is supposed to.\n        }\n\n        /// <summary>\n        /// The local anchor point on BodyA\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point on BodyB\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override Vector2 WorldAnchorA\n        {\n            get { return BodyA.GetWorldPoint(LocalAnchorA); }\n            set { LocalAnchorA = BodyA.GetLocalPoint(value); }\n        }\n\n        public override Vector2 WorldAnchorB\n        {\n            get { return BodyB.GetWorldPoint(LocalAnchorB); }\n            set { LocalAnchorB = BodyB.GetLocalPoint(value); }\n        }\n\n        /// <summary>\n        /// The axis at which the suspension moves.\n        /// </summary>\n        public Vector2 Axis\n        {\n            get { return _axis; }\n            set\n            {\n                _axis = value;\n                LocalXAxis = BodyA.GetLocalVector(_axis);\n                _localYAxis = MathUtils.Cross(1.0f, LocalXAxis);\n            }\n        }\n\n        /// <summary>\n        /// The axis in local coordinates relative to BodyA\n        /// </summary>\n        public Vector2 LocalXAxis { get; private set; }\n\n        /// <summary>\n        /// The desired motor speed in radians per second.\n        /// </summary>\n        public float MotorSpeed\n        {\n            get { return _motorSpeed; }\n            set\n            {\n                if (value == _motorSpeed)\n                    return;\n\n                WakeBodies();\n                _motorSpeed = value;\n            }\n        }\n\n        /// <summary>\n        /// The maximum motor torque, usually in N-m.\n        /// </summary>\n        public float MaxMotorTorque\n        {\n            get { return _maxMotorTorque; }\n            set\n            {\n                if (value == _maxMotorTorque)\n                    return;\n\n                WakeBodies();\n                _maxMotorTorque = value;\n            }\n        }\n\n        /// <summary>\n        /// Suspension frequency, zero indicates no suspension\n        /// </summary>\n        public float Frequency { get; set; }\n\n        /// <summary>\n        /// Suspension damping ratio, one indicates critical damping\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// Gets the translation along the axis\n        /// </summary>\n        public float JointTranslation\n        {\n            get\n            {\n                Body bA = BodyA;\n                Body bB = BodyB;\n\n                Vector2 pA = bA.GetWorldPoint(LocalAnchorA);\n                Vector2 pB = bB.GetWorldPoint(LocalAnchorB);\n                Vector2 d = pB - pA;\n                Vector2 axis = bA.GetWorldVector(LocalXAxis);\n\n                float translation = Vector2.Dot(d, axis);\n                return translation;\n            }\n        }\n\n        public float JointLinearSpeed\n        {\n            get\n            {\n                Body bA = BodyA;\n                Body bB = BodyB;\n\n                Transform xfA;\n                bA.GetTransform(out xfA);\n\n                Transform xfB;\n                bB.GetTransform(out xfB);\n\n                Vector2 rA = MathUtils.Mul(xfA.q, LocalAnchorA - bA._sweep.LocalCenter);\n                Vector2 rB = MathUtils.Mul(xfB.q, LocalAnchorB - bB._sweep.LocalCenter);\n                Vector2 p1 = bA._sweep.C + rA;\n                Vector2 p2 = bB._sweep.C + rB;\n                Vector2 d = p2 - p1;\n                Vector2 axis = MathUtils.Mul(xfA.q, LocalXAxis);\n\n                Vector2 vA = bA.LinearVelocity;\n                Vector2 vB = bB.LinearVelocity;\n                float wA = bA.AngularVelocity;\n                float wB = bB.AngularVelocity;\n\n                float speed = Vector2.Dot(d, MathUtils.Cross(wA, axis)) + Vector2.Dot(axis, vB + MathUtils.Cross(wB, rB) - vA - MathUtils.Cross(wA, rA));\n                return speed;\n            }\n        }\n\n        public float JointAngle\n        {\n            get\n            {\n                Body bA = BodyA;\n                Body bB = BodyB;\n                return bB._sweep.A - bA._sweep.A;\n            }\n        }\n\n        /// <summary>\n        /// Gets the angular velocity of the joint\n        /// </summary>\n        public float JointAngularSpeed\n        {\n            get\n            {\n                float wA = BodyA.AngularVelocity;\n                float wB = BodyB.AngularVelocity;\n                return wB - wA;\n            }\n        }\n\n        /// <summary>\n        /// Enable/disable the joint motor.\n        /// </summary>\n        public bool MotorEnabled\n        {\n            get { return _enableMotor; }\n            set\n            {\n                if (value == _enableMotor)\n                    return;\n\n                WakeBodies();\n                _enableMotor = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets the torque of the motor\n        /// </summary>\n        /// <param name=\"invDt\">inverse delta time</param>\n        public float GetMotorTorque(float invDt)\n        {\n            return invDt * _motorImpulse;\n        }\n\n        public override Vector2 GetReactionForce(float invDt)\n        {\n            return invDt * (_impulse * _ay + _springImpulse * _ax);\n        }\n\n        public override float GetReactionTorque(float invDt)\n        {\n            return invDt * _motorImpulse;\n        }\n\n        internal override void InitVelocityConstraints(ref SolverData data)\n        {\n            _indexA = BodyA.IslandIndex;\n            _indexB = BodyB.IslandIndex;\n            _localCenterA = BodyA._sweep.LocalCenter;\n            _localCenterB = BodyB._sweep.LocalCenter;\n            _invMassA = BodyA._invMass;\n            _invMassB = BodyB._invMass;\n            _invIA = BodyA._invI;\n            _invIB = BodyB._invI;\n\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            // Compute the effective masses.\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 d1 = cB + rB - cA - rA;\n\n            // Point to line constraint\n            {\n                _ay = MathUtils.Mul(qA, _localYAxis);\n                _sAy = MathUtils.Cross(d1 + rA, _ay);\n                _sBy = MathUtils.Cross(rB, _ay);\n\n                _mass = mA + mB + iA * _sAy * _sAy + iB * _sBy * _sBy;\n\n                if (_mass > 0.0f)\n                {\n                    _mass = 1.0f / _mass;\n                }\n            }\n\n            // Spring constraint\n            _springMass = 0.0f;\n            _bias = 0.0f;\n            _gamma = 0.0f;\n            if (Frequency > 0.0f)\n            {\n                _ax = MathUtils.Mul(qA, LocalXAxis);\n                _sAx = MathUtils.Cross(d1 + rA, _ax);\n                _sBx = MathUtils.Cross(rB, _ax);\n\n                float invMass = mA + mB + iA * _sAx * _sAx + iB * _sBx * _sBx;\n\n                if (invMass > 0.0f)\n                {\n                    _springMass = 1.0f / invMass;\n\n                    float C = Vector2.Dot(d1, _ax);\n\n                    // Frequency\n                    float omega = 2.0f * Settings.Pi * Frequency;\n\n                    // Damping coefficient\n                    float d = 2.0f * _springMass * DampingRatio * omega;\n\n                    // Spring stiffness\n                    float k = _springMass * omega * omega;\n\n                    // magic formulas\n                    float h = data.Step.dt;\n                    _gamma = h * (d + h * k);\n                    if (_gamma > 0.0f)\n                    {\n                        _gamma = 1.0f / _gamma;\n                    }\n\n                    _bias = C * h * k * _gamma;\n\n                    _springMass = invMass + _gamma;\n                    if (_springMass > 0.0f)\n                    {\n                        _springMass = 1.0f / _springMass;\n                    }\n                }\n            }\n            else\n            {\n                _springImpulse = 0.0f;\n            }\n\n            // Rotational motor\n            if (_enableMotor)\n            {\n                _motorMass = iA + iB;\n                if (_motorMass > 0.0f)\n                {\n                    _motorMass = 1.0f / _motorMass;\n                }\n            }\n            else\n            {\n                _motorMass = 0.0f;\n                _motorImpulse = 0.0f;\n            }\n\n            if (Settings.EnableWarmstarting)\n            {\n                // Account for variable time step.\n                _impulse *= data.Step.dtRatio;\n                _springImpulse *= data.Step.dtRatio;\n                _motorImpulse *= data.Step.dtRatio;\n\n                Vector2 P = _impulse * _ay + _springImpulse * _ax;\n                float LA = _impulse * _sAy + _springImpulse * _sAx + _motorImpulse;\n                float LB = _impulse * _sBy + _springImpulse * _sBx + _motorImpulse;\n\n                vA -= _invMassA * P;\n                wA -= _invIA * LA;\n\n                vB += _invMassB * P;\n                wB += _invIB * LB;\n            }\n            else\n            {\n                _impulse = 0.0f;\n                _springImpulse = 0.0f;\n                _motorImpulse = 0.0f;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override void SolveVelocityConstraints(ref SolverData data)\n        {\n            float mA = _invMassA, mB = _invMassB;\n            float iA = _invIA, iB = _invIB;\n\n            Vector2 vA = data.Velocities[_indexA].V;\n            float wA = data.Velocities[_indexA].W;\n            Vector2 vB = data.Velocities[_indexB].V;\n            float wB = data.Velocities[_indexB].W;\n\n            // Solve spring constraint\n            {\n                float Cdot = Vector2.Dot(_ax, vB - vA) + _sBx * wB - _sAx * wA;\n                float impulse = -_springMass * (Cdot + _bias + _gamma * _springImpulse);\n                _springImpulse += impulse;\n\n                Vector2 P = impulse * _ax;\n                float LA = impulse * _sAx;\n                float LB = impulse * _sBx;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n\n            // Solve rotational motor constraint\n            {\n                float Cdot = wB - wA - _motorSpeed;\n                float impulse = -_motorMass * Cdot;\n\n                float oldImpulse = _motorImpulse;\n                float maxImpulse = data.Step.dt * _maxMotorTorque;\n                _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);\n                impulse = _motorImpulse - oldImpulse;\n\n                wA -= iA * impulse;\n                wB += iB * impulse;\n            }\n\n            // Solve point to line constraint\n            {\n                float Cdot = Vector2.Dot(_ay, vB - vA) + _sBy * wB - _sAy * wA;\n                float impulse = -_mass * Cdot;\n                _impulse += impulse;\n\n                Vector2 P = impulse * _ay;\n                float LA = impulse * _sAy;\n                float LB = impulse * _sBy;\n\n                vA -= mA * P;\n                wA -= iA * LA;\n\n                vB += mB * P;\n                wB += iB * LB;\n            }\n\n            data.Velocities[_indexA].V = vA;\n            data.Velocities[_indexA].W = wA;\n            data.Velocities[_indexB].V = vB;\n            data.Velocities[_indexB].W = wB;\n        }\n\n        internal override bool SolvePositionConstraints(ref SolverData data)\n        {\n            Vector2 cA = data.Positions[_indexA].C;\n            float aA = data.Positions[_indexA].A;\n            Vector2 cB = data.Positions[_indexB].C;\n            float aB = data.Positions[_indexB].A;\n\n            Rot qA = new Rot(aA), qB = new Rot(aB);\n\n            Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);\n            Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);\n            Vector2 d = (cB - cA) + rB - rA;\n\n            Vector2 ay = MathUtils.Mul(qA, _localYAxis);\n\n            float sAy = MathUtils.Cross(d + rA, ay);\n            float sBy = MathUtils.Cross(rB, ay);\n\n            float C = Vector2.Dot(d, ay);\n\n            float k = _invMassA + _invMassB + _invIA * _sAy * _sAy + _invIB * _sBy * _sBy;\n\n            float impulse;\n            if (k != 0.0f)\n            {\n                impulse = -C / k;\n            }\n            else\n            {\n                impulse = 0.0f;\n            }\n\n            Vector2 P = impulse * ay;\n            float LA = impulse * sAy;\n            float LB = impulse * sBy;\n\n            cA -= _invMassA * P;\n            aA -= _invIA * LA;\n            cB += _invMassB * P;\n            aB += _invIB * LB;\n\n            data.Positions[_indexA].C = cA;\n            data.Positions[_indexA].A = aA;\n            data.Positions[_indexB].C = cB;\n            data.Positions[_indexB].A = aB;\n\n            return Math.Abs(C) <= Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/ContactPositionConstraint.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Narrowphase;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    public sealed class ContactPositionConstraint\n    {\n        public int IndexA;\n        public int IndexB;\n        public float InvIA, InvIB;\n        public float InvMassA, InvMassB;\n        public Vector2 LocalCenterA, LocalCenterB;\n        public Vector2 LocalNormal;\n        public Vector2 LocalPoint;\n        public Vector2[] LocalPoints = new Vector2[Settings.MaxManifoldPoints];\n        public int PointCount;\n        public float RadiusA, RadiusB;\n        public ManifoldType Type;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/ContactSolver.cs",
    "content": "//#define B2_DEBUG_SOLVER\n/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    public class ContactSolver\n    {\n        private Contact[] _contacts;\n        private int _count;\n        private ContactPositionConstraint[] _positionConstraints;\n        private Position[] _positions;\n        private TimeStep _step;\n        private Velocity[] _velocities;\n        public ContactVelocityConstraint[] VelocityConstraints;\n\n        public void Reset(TimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities)\n        {\n            _step = step;\n            _count = count;\n            _positions = positions;\n            _velocities = velocities;\n            _contacts = contacts;\n\n            // grow the array\n            if (VelocityConstraints == null || VelocityConstraints.Length < count)\n            {\n                VelocityConstraints = new ContactVelocityConstraint[count * 2];\n                _positionConstraints = new ContactPositionConstraint[count * 2];\n\n                for (int i = 0; i < VelocityConstraints.Length; i++)\n                {\n                    VelocityConstraints[i] = new ContactVelocityConstraint();\n                }\n\n                for (int i = 0; i < _positionConstraints.Length; i++)\n                {\n                    _positionConstraints[i] = new ContactPositionConstraint();\n                }\n            }\n\n            // Initialize position independent portions of the constraints.\n            for (int i = 0; i < _count; ++i)\n            {\n                Contact contact = contacts[i];\n\n                Fixture fixtureA = contact.FixtureA;\n                Fixture fixtureB = contact.FixtureB;\n                Shape shapeA = fixtureA.Shape;\n                Shape shapeB = fixtureB.Shape;\n                float radiusA = shapeA.Radius;\n                float radiusB = shapeB.Radius;\n                Body bodyA = fixtureA.Body;\n                Body bodyB = fixtureB.Body;\n                Manifold manifold = contact.Manifold;\n\n                int pointCount = manifold.PointCount;\n                Debug.Assert(pointCount > 0);\n\n                ContactVelocityConstraint vc = VelocityConstraints[i];\n                vc.Friction = contact.Friction;\n                vc.Restitution = contact.Restitution;\n                vc.TangentSpeed = contact.TangentSpeed;\n                vc.IndexA = bodyA.IslandIndex;\n                vc.IndexB = bodyB.IslandIndex;\n                vc.InvMassA = bodyA._invMass;\n                vc.InvMassB = bodyB._invMass;\n                vc.InvIA = bodyA._invI;\n                vc.InvIB = bodyB._invI;\n                vc.ContactIndex = i;\n                vc.PointCount = pointCount;\n                vc.K.SetZero();\n                vc.NormalMass.SetZero();\n\n                ContactPositionConstraint pc = _positionConstraints[i];\n                pc.IndexA = bodyA.IslandIndex;\n                pc.IndexB = bodyB.IslandIndex;\n                pc.InvMassA = bodyA._invMass;\n                pc.InvMassB = bodyB._invMass;\n                pc.LocalCenterA = bodyA._sweep.LocalCenter;\n                pc.LocalCenterB = bodyB._sweep.LocalCenter;\n                pc.InvIA = bodyA._invI;\n                pc.InvIB = bodyB._invI;\n                pc.LocalNormal = manifold.LocalNormal;\n                pc.LocalPoint = manifold.LocalPoint;\n                pc.PointCount = pointCount;\n                pc.RadiusA = radiusA;\n                pc.RadiusB = radiusB;\n                pc.Type = manifold.Type;\n\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    ManifoldPoint cp = manifold.Points[j];\n                    VelocityConstraintPoint vcp = vc.Points[j];\n\n                    if (Settings.EnableWarmstarting)\n                    {\n                        vcp.NormalImpulse = _step.dtRatio * cp.NormalImpulse;\n                        vcp.TangentImpulse = _step.dtRatio * cp.TangentImpulse;\n                    }\n                    else\n                    {\n                        vcp.NormalImpulse = 0.0f;\n                        vcp.TangentImpulse = 0.0f;\n                    }\n\n                    vcp.rA = Vector2.Zero;\n                    vcp.rB = Vector2.Zero;\n                    vcp.NormalMass = 0.0f;\n                    vcp.TangentMass = 0.0f;\n                    vcp.VelocityBias = 0.0f;\n\n                    pc.LocalPoints[j] = cp.LocalPoint;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Initialize position dependent portions of the velocity constraints.\n        /// </summary>\n        public void InitializeVelocityConstraints()\n        {\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactVelocityConstraint vc = VelocityConstraints[i];\n                ContactPositionConstraint pc = _positionConstraints[i];\n\n                float radiusA = pc.RadiusA;\n                float radiusB = pc.RadiusB;\n                Manifold manifold = _contacts[vc.ContactIndex].Manifold;\n\n                int indexA = vc.IndexA;\n                int indexB = vc.IndexB;\n\n                float mA = vc.InvMassA;\n                float mB = vc.InvMassB;\n                float iA = vc.InvIA;\n                float iB = vc.InvIB;\n                Vector2 localCenterA = pc.LocalCenterA;\n                Vector2 localCenterB = pc.LocalCenterB;\n\n                Vector2 cA = _positions[indexA].C;\n                float aA = _positions[indexA].A;\n                Vector2 vA = _velocities[indexA].V;\n                float wA = _velocities[indexA].W;\n\n                Vector2 cB = _positions[indexB].C;\n                float aB = _positions[indexB].A;\n                Vector2 vB = _velocities[indexB].V;\n                float wB = _velocities[indexB].W;\n\n                Debug.Assert(manifold.PointCount > 0);\n\n                Transform xfA = new Transform();\n                Transform xfB = new Transform();\n                xfA.q.Set(aA);\n                xfB.q.Set(aB);\n                xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);\n                xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);\n\n                WorldManifold.Initialize(ref manifold, ref xfA, radiusA, ref xfB, radiusB, out Vector2 normal, out FixedArray2<Vector2> points, out _);\n\n                vc.Normal = normal;\n\n                int pointCount = vc.PointCount;\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    VelocityConstraintPoint vcp = vc.Points[j];\n\n                    vcp.rA = points[j] - cA;\n                    vcp.rB = points[j] - cB;\n\n                    float rnA = MathUtils.Cross(vcp.rA, vc.Normal);\n                    float rnB = MathUtils.Cross(vcp.rB, vc.Normal);\n\n                    float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;\n\n                    vcp.NormalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;\n\n                    Vector2 tangent = MathUtils.Cross(vc.Normal, 1.0f);\n\n                    float rtA = MathUtils.Cross(vcp.rA, tangent);\n                    float rtB = MathUtils.Cross(vcp.rB, tangent);\n\n                    float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;\n\n                    vcp.TangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;\n\n                    // Setup a velocity bias for restitution.\n                    vcp.VelocityBias = 0.0f;\n                    float vRel = Vector2.Dot(vc.Normal, vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA));\n                    if (vRel < -Settings.VelocityThreshold)\n                    {\n                        vcp.VelocityBias = -vc.Restitution * vRel;\n                    }\n                }\n\n                // If we have two points, then prepare the block solver.\n                if (vc.PointCount == 2 && Settings.BlockSolve)\n                {\n                    VelocityConstraintPoint vcp1 = vc.Points[0];\n                    VelocityConstraintPoint vcp2 = vc.Points[1];\n\n                    float rn1A = MathUtils.Cross(vcp1.rA, vc.Normal);\n                    float rn1B = MathUtils.Cross(vcp1.rB, vc.Normal);\n                    float rn2A = MathUtils.Cross(vcp2.rA, vc.Normal);\n                    float rn2B = MathUtils.Cross(vcp2.rB, vc.Normal);\n\n                    float k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;\n                    float k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;\n                    float k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;\n\n                    // Ensure a reasonable condition number.\n                    const float k_maxConditionNumber = 1000.0f;\n                    if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))\n                    {\n                        // K is safe to invert.\n                        vc.K.ex = new Vector2(k11, k12);\n                        vc.K.ey = new Vector2(k12, k22);\n                        vc.NormalMass = vc.K.Inverse;\n                    }\n                    else\n                    {\n                        // The constraints are redundant, just use one.\n                        // TODO_ERIN use deepest?\n                        vc.PointCount = 1;\n                    }\n                }\n            }\n        }\n\n        public void WarmStart()\n        {\n            // Warm start.\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactVelocityConstraint vc = VelocityConstraints[i];\n\n                int indexA = vc.IndexA;\n                int indexB = vc.IndexB;\n                float mA = vc.InvMassA;\n                float iA = vc.InvIA;\n                float mB = vc.InvMassB;\n                float iB = vc.InvIB;\n                int pointCount = vc.PointCount;\n\n                Vector2 vA = _velocities[indexA].V;\n                float wA = _velocities[indexA].W;\n                Vector2 vB = _velocities[indexB].V;\n                float wB = _velocities[indexB].W;\n\n                Vector2 normal = vc.Normal;\n                Vector2 tangent = MathUtils.Cross(normal, 1.0f);\n\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    VelocityConstraintPoint vcp = vc.Points[j];\n                    Vector2 P = vcp.NormalImpulse * normal + vcp.TangentImpulse * tangent;\n                    wA -= iA * MathUtils.Cross(vcp.rA, P);\n                    vA -= mA * P;\n                    wB += iB * MathUtils.Cross(vcp.rB, P);\n                    vB += mB * P;\n                }\n\n                _velocities[indexA].V = vA;\n                _velocities[indexA].W = wA;\n                _velocities[indexB].V = vB;\n                _velocities[indexB].W = wB;\n            }\n        }\n\n        public void SolveVelocityConstraints()\n        {\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactVelocityConstraint vc = VelocityConstraints[i];\n\n                int indexA = vc.IndexA;\n                int indexB = vc.IndexB;\n                float mA = vc.InvMassA;\n                float iA = vc.InvIA;\n                float mB = vc.InvMassB;\n                float iB = vc.InvIB;\n                int pointCount = vc.PointCount;\n\n                Vector2 vA = _velocities[indexA].V;\n                float wA = _velocities[indexA].W;\n                Vector2 vB = _velocities[indexB].V;\n                float wB = _velocities[indexB].W;\n\n                Vector2 normal = vc.Normal;\n                Vector2 tangent = MathUtils.Cross(normal, 1.0f);\n                float friction = vc.Friction;\n\n                Debug.Assert(pointCount == 1 || pointCount == 2);\n\n                // Solve tangent constraints first because non-penetration is more important\n                // than friction.\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    VelocityConstraintPoint vcp = vc.Points[j];\n\n                    // Relative velocity at contact\n                    Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);\n\n                    // Compute tangent force\n                    float vt = Vector2.Dot(dv, tangent) - vc.TangentSpeed;\n                    float lambda = vcp.TangentMass * (-vt);\n\n                    // b2Clamp the accumulated force\n                    float maxFriction = friction * vcp.NormalImpulse;\n                    float newImpulse = MathUtils.Clamp(vcp.TangentImpulse + lambda, -maxFriction, maxFriction);\n                    lambda = newImpulse - vcp.TangentImpulse;\n                    vcp.TangentImpulse = newImpulse;\n\n                    // Apply contact impulse\n                    Vector2 P = lambda * tangent;\n\n                    vA -= mA * P;\n                    wA -= iA * MathUtils.Cross(vcp.rA, P);\n\n                    vB += mB * P;\n                    wB += iB * MathUtils.Cross(vcp.rB, P);\n                }\n\n                // Solve normal constraints\n                if (pointCount == 1 || Settings.BlockSolve == false)\n                {\n                    for (int j = 0; j < pointCount; ++j)\n                    {\n                        VelocityConstraintPoint vcp = vc.Points[j];\n\n                        // Relative velocity at contact\n                        Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);\n\n                        // Compute normal impulse\n                        float vn = Vector2.Dot(dv, normal);\n                        float lambda = -vcp.NormalMass * (vn - vcp.VelocityBias);\n\n                        // b2Clamp the accumulated impulse\n                        float newImpulse = Math.Max(vcp.NormalImpulse + lambda, 0.0f);\n                        lambda = newImpulse - vcp.NormalImpulse;\n                        vcp.NormalImpulse = newImpulse;\n\n                        // Apply contact impulse\n                        Vector2 P = lambda * normal;\n                        vA -= mA * P;\n                        wA -= iA * MathUtils.Cross(vcp.rA, P);\n\n                        vB += mB * P;\n                        wB += iB * MathUtils.Cross(vcp.rB, P);\n                    }\n                }\n                else\n                {\n                    // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).\n                    // Build the mini LCP for this contact patch\n                    //\n                    // vn = A * x + b, vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2\n                    //\n                    // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )\n                    // b = vn0 - velocityBias\n                    //\n                    // The system is solved using the \"Total enumeration method\" (s. Murty). The complementary constraint vn_i * x_i\n                    // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases\n                    // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid\n                    // solution that satisfies the problem is chosen.\n                    // \n                    // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires\n                    // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).\n                    //\n                    // Substitute:\n                    // \n                    // x = a + d\n                    // \n                    // a := old total impulse\n                    // x := new total impulse\n                    // d := incremental impulse \n                    //\n                    // For the current iteration we extend the formula for the incremental impulse\n                    // to compute the new total impulse:\n                    //\n                    // vn = A * d + b\n                    //    = A * (x - a) + b\n                    //    = A * x + b - A * a\n                    //    = A * x + b'\n                    // b' = b - A * a;\n\n                    VelocityConstraintPoint cp1 = vc.Points[0];\n                    VelocityConstraintPoint cp2 = vc.Points[1];\n\n                    Vector2 a = new Vector2(cp1.NormalImpulse, cp2.NormalImpulse);\n                    Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);\n\n                    // Relative velocity at contact\n                    Vector2 dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);\n                    Vector2 dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);\n\n                    // Compute normal velocity\n                    float vn1 = Vector2.Dot(dv1, normal);\n                    float vn2 = Vector2.Dot(dv2, normal);\n\n                    Vector2 b = Vector2.Zero;\n                    b.X = vn1 - cp1.VelocityBias;\n                    b.Y = vn2 - cp2.VelocityBias;\n\n                    const float k_errorTol = 1e-3f;\n\n                    // Compute b'\n                    b -= MathUtils.Mul(ref vc.K, a);\n\n                    for (;;)\n                    {\n                        //\n                        // Case 1: vn = 0\n                        //\n                        // 0 = A * x + b'\n                        //\n                        // Solve for x:\n                        //\n                        // x = - inv(A) * b'\n                        //\n                        Vector2 x = -MathUtils.Mul(ref vc.NormalMass, b);\n\n                        if (x.X >= 0.0f && x.Y >= 0.0f)\n                        {\n                            // Get the incremental impulse\n                            Vector2 d = x - a;\n\n                            // Apply incremental impulse\n                            Vector2 P1 = d.X * normal;\n                            Vector2 P2 = d.Y * normal;\n                            vA -= mA * (P1 + P2);\n                            wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));\n\n                            vB += mB * (P1 + P2);\n                            wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));\n\n                            // Accumulate\n                            cp1.NormalImpulse = x.X;\n                            cp2.NormalImpulse = x.Y;\n\n#if B2_DEBUG_SOLVER\n                            // Postconditions\n                            dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);\n                            dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);\n\n                            // Compute normal velocity\n                            vn1 = Vector2.Dot(dv1, normal);\n                            vn2 = Vector2.Dot(dv2, normal);\n\n                            Debug.Assert(Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);\n                            Debug.Assert(Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);\n#endif\n                            break;\n                        }\n\n                        //\n                        // Case 2: vn1 = 0 and x2 = 0\n                        //\n                        //   0 = a11 * x1 + a12 * 0 + b1' \n                        // vn2 = a21 * x1 + a22 * 0 + b2'\n                        //\n                        x.X = -cp1.NormalMass * b.X;\n                        x.Y = 0.0f;\n                        vn1 = 0.0f;\n                        vn2 = vc.K.ex.Y * x.X + b.Y;\n\n                        if (x.X >= 0.0f && vn2 >= 0.0f)\n                        {\n                            // Get the incremental impulse\n                            Vector2 d = x - a;\n\n                            // Apply incremental impulse\n                            Vector2 P1 = d.X * normal;\n                            Vector2 P2 = d.Y * normal;\n                            vA -= mA * (P1 + P2);\n                            wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));\n\n                            vB += mB * (P1 + P2);\n                            wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));\n\n                            // Accumulate\n                            cp1.NormalImpulse = x.X;\n                            cp2.NormalImpulse = x.Y;\n\n#if B2_DEBUG_SOLVER\n                            // Postconditions\n                            dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);\n\n                            // Compute normal velocity\n                            vn1 = Vector2.Dot(dv1, normal);\n\n                            Debug.Assert(Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);\n#endif\n                            break;\n                        }\n\n                        //\n                        // Case 3: vn2 = 0 and x1 = 0\n                        //\n                        // vn1 = a11 * 0 + a12 * x2 + b1' \n                        //   0 = a21 * 0 + a22 * x2 + b2'\n                        //\n                        x.X = 0.0f;\n                        x.Y = -cp2.NormalMass * b.Y;\n                        vn1 = vc.K.ey.X * x.Y + b.X;\n                        vn2 = 0.0f;\n\n                        if (x.Y >= 0.0f && vn1 >= 0.0f)\n                        {\n                            // Resubstitute for the incremental impulse\n                            Vector2 d = x - a;\n\n                            // Apply incremental impulse\n                            Vector2 P1 = d.X * normal;\n                            Vector2 P2 = d.Y * normal;\n                            vA -= mA * (P1 + P2);\n                            wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));\n\n                            vB += mB * (P1 + P2);\n                            wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));\n\n                            // Accumulate\n                            cp1.NormalImpulse = x.X;\n                            cp2.NormalImpulse = x.Y;\n\n#if B2_DEBUG_SOLVER\n                            // Postconditions\n                            dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);\n\n                            // Compute normal velocity\n                            vn2 = Vector2.Dot(dv2, normal);\n\n                            Debug.Assert(Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);\n#endif\n                            break;\n                        }\n\n                        //\n                        // Case 4: x1 = 0 and x2 = 0\n                        // \n                        // vn1 = b1\n                        // vn2 = b2;\n                        x.X = 0.0f;\n                        x.Y = 0.0f;\n                        vn1 = b.X;\n                        vn2 = b.Y;\n\n                        if (vn1 >= 0.0f && vn2 >= 0.0f)\n                        {\n                            // Resubstitute for the incremental impulse\n                            Vector2 d = x - a;\n\n                            // Apply incremental impulse\n                            Vector2 P1 = d.X * normal;\n                            Vector2 P2 = d.Y * normal;\n                            vA -= mA * (P1 + P2);\n                            wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));\n\n                            vB += mB * (P1 + P2);\n                            wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));\n\n                            // Accumulate\n                            cp1.NormalImpulse = x.X;\n                            cp2.NormalImpulse = x.Y;\n\n                            break;\n                        }\n\n                        // No solution, give up. This is hit sometimes, but it doesn't seem to matter.\n                        break;\n                    }\n                }\n\n                _velocities[indexA].V = vA;\n                _velocities[indexA].W = wA;\n                _velocities[indexB].V = vB;\n                _velocities[indexB].W = wB;\n            }\n        }\n\n        public void StoreImpulses()\n        {\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactVelocityConstraint vc = VelocityConstraints[i];\n                Manifold manifold = _contacts[vc.ContactIndex].Manifold;\n\n                for (int j = 0; j < vc.PointCount; ++j)\n                {\n                    ManifoldPoint point = manifold.Points[j];\n                    point.NormalImpulse = vc.Points[j].NormalImpulse;\n                    point.TangentImpulse = vc.Points[j].TangentImpulse;\n                    manifold.Points[j] = point;\n                }\n\n                _contacts[vc.ContactIndex].Manifold = manifold;\n            }\n        }\n\n        public bool SolvePositionConstraints()\n        {\n            float minSeparation = 0.0f;\n\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactPositionConstraint pc = _positionConstraints[i];\n\n                int indexA = pc.IndexA;\n                int indexB = pc.IndexB;\n                Vector2 localCenterA = pc.LocalCenterA;\n                float mA = pc.InvMassA;\n                float iA = pc.InvIA;\n                Vector2 localCenterB = pc.LocalCenterB;\n                float mB = pc.InvMassB;\n                float iB = pc.InvIB;\n                int pointCount = pc.PointCount;\n\n                Vector2 cA = _positions[indexA].C;\n                float aA = _positions[indexA].A;\n\n                Vector2 cB = _positions[indexB].C;\n                float aB = _positions[indexB].A;\n\n                // Solve normal constraints\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    Transform xfA = new Transform();\n                    Transform xfB = new Transform();\n                    xfA.q.Set(aA);\n                    xfB.q.Set(aB);\n                    xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);\n                    xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);\n\n                    PositionSolverManifold.Initialize(pc, xfA, xfB, j, out Vector2 normal, out Vector2 point, out float separation);\n\n                    Vector2 rA = point - cA;\n                    Vector2 rB = point - cB;\n\n                    // Track max constraint error.\n                    minSeparation = Math.Min(minSeparation, separation);\n\n                    // Prevent large corrections and allow slop.\n                    float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);\n\n                    // Compute the effective mass.\n                    float rnA = MathUtils.Cross(rA, normal);\n                    float rnB = MathUtils.Cross(rB, normal);\n                    float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;\n\n                    // Compute normal impulse\n                    float impulse = K > 0.0f ? -C / K : 0.0f;\n\n                    Vector2 P = impulse * normal;\n\n                    cA -= mA * P;\n                    aA -= iA * MathUtils.Cross(rA, P);\n\n                    cB += mB * P;\n                    aB += iB * MathUtils.Cross(rB, P);\n                }\n\n                _positions[indexA].C = cA;\n                _positions[indexA].A = aA;\n\n                _positions[indexB].C = cB;\n                _positions[indexB].A = aB;\n            }\n\n            // We can't expect minSpeparation >= -b2_linearSlop because we don't\n            // push the separation above -b2_linearSlop.\n            return minSeparation >= -3.0f * Settings.LinearSlop;\n        }\n\n        // Sequential position solver for position constraints.\n        public bool SolveTOIPositionConstraints(int toiIndexA, int toiIndexB)\n        {\n            float minSeparation = 0.0f;\n\n            for (int i = 0; i < _count; ++i)\n            {\n                ContactPositionConstraint pc = _positionConstraints[i];\n\n                int indexA = pc.IndexA;\n                int indexB = pc.IndexB;\n                Vector2 localCenterA = pc.LocalCenterA;\n                Vector2 localCenterB = pc.LocalCenterB;\n                int pointCount = pc.PointCount;\n\n                float mA = 0.0f;\n                float iA = 0.0f;\n                if (indexA == toiIndexA || indexA == toiIndexB)\n                {\n                    mA = pc.InvMassA;\n                    iA = pc.InvIA;\n                }\n\n                float mB = 0.0f;\n                float iB = 0.0f;\n                if (indexB == toiIndexA || indexB == toiIndexB)\n                {\n                    mB = pc.InvMassB;\n                    iB = pc.InvIB;\n                }\n\n                Vector2 cA = _positions[indexA].C;\n                float aA = _positions[indexA].A;\n\n                Vector2 cB = _positions[indexB].C;\n                float aB = _positions[indexB].A;\n\n                // Solve normal constraints\n                for (int j = 0; j < pointCount; ++j)\n                {\n                    Transform xfA = new Transform();\n                    Transform xfB = new Transform();\n                    xfA.q.Set(aA);\n                    xfB.q.Set(aB);\n                    xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);\n                    xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);\n\n                    PositionSolverManifold.Initialize(pc, xfA, xfB, j, out Vector2 normal, out Vector2 point, out float separation);\n\n                    Vector2 rA = point - cA;\n                    Vector2 rB = point - cB;\n\n                    // Track max constraint error.\n                    minSeparation = Math.Min(minSeparation, separation);\n\n                    // Prevent large corrections and allow slop.\n                    float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);\n\n                    // Compute the effective mass.\n                    float rnA = MathUtils.Cross(rA, normal);\n                    float rnB = MathUtils.Cross(rB, normal);\n                    float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;\n\n                    // Compute normal impulse\n                    float impulse = K > 0.0f ? -C / K : 0.0f;\n\n                    Vector2 P = impulse * normal;\n\n                    cA -= mA * P;\n                    aA -= iA * MathUtils.Cross(rA, P);\n\n                    cB += mB * P;\n                    aB += iB * MathUtils.Cross(rB, P);\n                }\n\n                _positions[indexA].C = cA;\n                _positions[indexA].A = aA;\n\n                _positions[indexB].C = cB;\n                _positions[indexB].A = aB;\n            }\n\n            // We can't expect minSpeparation >= -b2_linearSlop because we don't\n            // push the separation above -b2_linearSlop.\n            return minSeparation >= -1.5f * Settings.LinearSlop;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/ContactVelocityConstraint.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    public sealed class ContactVelocityConstraint\n    {\n        public int ContactIndex;\n        public float Friction;\n        public int IndexA;\n        public int IndexB;\n        public float InvIA, InvIB;\n        public float InvMassA, InvMassB;\n        public Mat22 K;\n        public Vector2 Normal;\n        public Mat22 NormalMass;\n        public int PointCount;\n        public VelocityConstraintPoint[] Points = new VelocityConstraintPoint[Settings.MaxManifoldPoints];\n        public float Restitution;\n        public float TangentSpeed;\n\n        public ContactVelocityConstraint()\n        {\n            for (int i = 0; i < Settings.MaxManifoldPoints; i++)\n            {\n                Points[i] = new VelocityConstraintPoint();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/Island.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Dynamics.Joints;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    /// <summary>\n    /// This is an internal class.\n    /// </summary>\n    public class Island\n    {\n        private const float LinTolSqr = Settings.LinearSleepTolerance * Settings.LinearSleepTolerance;\n        private const float AngTolSqr = Settings.AngularSleepTolerance * Settings.AngularSleepTolerance;\n        private ContactManager _contactManager;\n        private Contact[] _contacts;\n        private ContactSolver _contactSolver = new ContactSolver();\n        private Joint[] _joints;\n        private Stopwatch _watch = new Stopwatch();\n\n        public Body[] Bodies;\n        public Position[] Positions;\n        public Velocity[] Velocities;\n        public int BodyCapacity;\n        public int BodyCount;\n        public int ContactCapacity;\n        public int ContactCount;\n        public int JointCapacity;\n        public int JointCount;\n        public float JointUpdateTime;\n\n        public void Reset(int bodyCapacity, int contactCapacity, int jointCapacity, ContactManager contactManager)\n        {\n            BodyCapacity = bodyCapacity;\n            ContactCapacity = contactCapacity;\n            JointCapacity = jointCapacity;\n            BodyCount = 0;\n            ContactCount = 0;\n            JointCount = 0;\n\n            _contactManager = contactManager;\n\n            if (Bodies == null || Bodies.Length < bodyCapacity)\n            {\n                Bodies = new Body[bodyCapacity];\n                Velocities = new Velocity[bodyCapacity];\n                Positions = new Position[bodyCapacity];\n            }\n\n            if (_contacts == null || _contacts.Length < contactCapacity)\n            {\n                _contacts = new Contact[contactCapacity * 2];\n            }\n\n            if (_joints == null || _joints.Length < jointCapacity)\n            {\n                _joints = new Joint[jointCapacity * 2];\n            }\n        }\n\n        public void Clear()\n        {\n            BodyCount = 0;\n            ContactCount = 0;\n            JointCount = 0;\n        }\n\n        public void Solve(ref TimeStep step, ref Vector2 gravity)\n        {\n            float h = step.dt;\n\n            // Integrate velocities and apply damping. Initialize the body state.\n            for (int i = 0; i < BodyCount; ++i)\n            {\n                Body b = Bodies[i];\n\n                Vector2 c = b._sweep.C;\n                float a = b._sweep.A;\n                Vector2 v = b._linearVelocity;\n                float w = b._angularVelocity;\n\n                // Store positions for continuous collision.\n                b._sweep.C0 = b._sweep.C;\n                b._sweep.A0 = b._sweep.A;\n\n                if (b.BodyType == BodyType.Dynamic)\n                {\n                    // Integrate velocities.\n\n                    //Velcro: Only apply gravity if the body wants it.\n                    if (b.IgnoreGravity)\n                        v += h * (b._invMass * b._force);\n                    else\n                        v += h * (b.GravityScale * gravity + b._invMass * b._force);\n\n                    w += h * b._invI * b._torque;\n\n                    // Apply damping.\n                    // ODE: dv/dt + c * v = 0\n                    // Solution: v(t) = v0 * exp(-c * t)\n                    // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)\n                    // v2 = exp(-c * dt) * v1\n                    // Taylor expansion:\n                    // v2 = (1.0f - c * dt) * v1\n                    v *= MathUtils.Clamp(1.0f - h * b.LinearDamping, 0.0f, 1.0f);\n                    w *= MathUtils.Clamp(1.0f - h * b.AngularDamping, 0.0f, 1.0f);\n                }\n\n                Positions[i].C = c;\n                Positions[i].A = a;\n                Velocities[i].V = v;\n                Velocities[i].W = w;\n            }\n\n            // Solver data\n            SolverData solverData = new SolverData();\n            solverData.Step = step;\n            solverData.Positions = Positions;\n            solverData.Velocities = Velocities;\n\n            _contactSolver.Reset(step, ContactCount, _contacts, Positions, Velocities);\n            _contactSolver.InitializeVelocityConstraints();\n\n            if (Settings.EnableWarmstarting)\n            {\n                _contactSolver.WarmStart();\n            }\n\n            if (Settings.EnableDiagnostics)\n                _watch.Start();\n\n            for (int i = 0; i < JointCount; ++i)\n            {\n                if (_joints[i].Enabled)\n                    _joints[i].InitVelocityConstraints(ref solverData);\n            }\n\n            if (Settings.EnableDiagnostics)\n                _watch.Stop();\n\n            // Solve velocity constraints.\n            for (int i = 0; i < Settings.VelocityIterations; ++i)\n            {\n                for (int j = 0; j < JointCount; ++j)\n                {\n                    Joint joint = _joints[j];\n\n                    if (!joint.Enabled)\n                        continue;\n\n                    if (Settings.EnableDiagnostics)\n                        _watch.Start();\n\n                    joint.SolveVelocityConstraints(ref solverData);\n                    joint.Validate(step.inv_dt);\n\n                    if (Settings.EnableDiagnostics)\n                        _watch.Stop();\n                }\n\n                _contactSolver.SolveVelocityConstraints();\n            }\n\n            // Store impulses for warm starting.\n            _contactSolver.StoreImpulses();\n\n            // Integrate positions\n            for (int i = 0; i < BodyCount; ++i)\n            {\n                Vector2 c = Positions[i].C;\n                float a = Positions[i].A;\n                Vector2 v = Velocities[i].V;\n                float w = Velocities[i].W;\n\n                // Check for large velocities\n                Vector2 translation = h * v;\n                if (Vector2.Dot(translation, translation) > Settings.MaxTranslationSquared)\n                {\n                    float ratio = Settings.MaxTranslation / translation.Length();\n                    v *= ratio;\n                }\n\n                float rotation = h * w;\n                if (rotation * rotation > Settings.MaxRotationSquared)\n                {\n                    float ratio = Settings.MaxRotation / Math.Abs(rotation);\n                    w *= ratio;\n                }\n\n                // Integrate\n                c += h * v;\n                a += h * w;\n\n                Positions[i].C = c;\n                Positions[i].A = a;\n                Velocities[i].V = v;\n                Velocities[i].W = w;\n            }\n\n            // Solve position constraints\n            bool positionSolved = false;\n            for (int i = 0; i < Settings.PositionIterations; ++i)\n            {\n                bool contactsOkay = _contactSolver.SolvePositionConstraints();\n\n                bool jointsOkay = true;\n                for (int j = 0; j < JointCount; ++j)\n                {\n                    Joint joint = _joints[j];\n\n                    if (!joint.Enabled)\n                        continue;\n\n                    if (Settings.EnableDiagnostics)\n                        _watch.Start();\n\n                    bool jointOkay = joint.SolvePositionConstraints(ref solverData);\n\n                    if (Settings.EnableDiagnostics)\n                        _watch.Stop();\n\n                    jointsOkay = jointsOkay && jointOkay;\n                }\n\n                if (contactsOkay && jointsOkay)\n                {\n                    // Exit early if the position errors are small.\n                    positionSolved = true;\n                    break;\n                }\n            }\n\n            if (Settings.EnableDiagnostics)\n            {\n                JointUpdateTime = _watch.ElapsedTicks;\n                _watch.Reset();\n            }\n\n            // Copy state buffers back to the bodies\n            for (int i = 0; i < BodyCount; ++i)\n            {\n                Body body = Bodies[i];\n                body._sweep.C = Positions[i].C;\n                body._sweep.A = Positions[i].A;\n                body._linearVelocity = Velocities[i].V;\n                body._angularVelocity = Velocities[i].W;\n                body.SynchronizeTransform();\n            }\n\n            Report(_contactSolver.VelocityConstraints);\n\n            if (Settings.AllowSleep)\n            {\n                float minSleepTime = Settings.MaxFloat;\n\n                for (int i = 0; i < BodyCount; ++i)\n                {\n                    Body b = Bodies[i];\n\n                    if (b.BodyType == BodyType.Static)\n                        continue;\n\n                    if (!b.SleepingAllowed || b._angularVelocity * b._angularVelocity > AngTolSqr || Vector2.Dot(b._linearVelocity, b._linearVelocity) > LinTolSqr)\n                    {\n                        b.SleepTime = 0.0f;\n                        minSleepTime = 0.0f;\n                    }\n                    else\n                    {\n                        b.SleepTime += h;\n                        minSleepTime = Math.Min(minSleepTime, b.SleepTime);\n                    }\n                }\n\n                if (minSleepTime >= Settings.TimeToSleep && positionSolved)\n                {\n                    for (int i = 0; i < BodyCount; ++i)\n                    {\n                        Body b = Bodies[i];\n                        b.Awake = false;\n                    }\n                }\n            }\n        }\n\n        internal void SolveTOI(ref TimeStep subStep, int toiIndexA, int toiIndexB)\n        {\n            Debug.Assert(toiIndexA < BodyCount);\n            Debug.Assert(toiIndexB < BodyCount);\n\n            // Initialize the body state.\n            for (int i = 0; i < BodyCount; ++i)\n            {\n                Body b = Bodies[i];\n                Positions[i].C = b._sweep.C;\n                Positions[i].A = b._sweep.A;\n                Velocities[i].V = b._linearVelocity;\n                Velocities[i].W = b._angularVelocity;\n            }\n\n            _contactSolver.Reset(subStep, ContactCount, _contacts, Positions, Velocities);\n\n            // Solve position constraints.\n            for (int i = 0; i < Settings.TOIPositionIterations; ++i)\n            {\n                bool contactsOkay = _contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);\n                if (contactsOkay)\n                {\n                    break;\n                }\n            }\n\n            // Leap of faith to new safe state.\n            Bodies[toiIndexA]._sweep.C0 = Positions[toiIndexA].C;\n            Bodies[toiIndexA]._sweep.A0 = Positions[toiIndexA].A;\n            Bodies[toiIndexB]._sweep.C0 = Positions[toiIndexB].C;\n            Bodies[toiIndexB]._sweep.A0 = Positions[toiIndexB].A;\n\n            // No warm starting is needed for TOI events because warm\n            // starting impulses were applied in the discrete solver.\n            _contactSolver.InitializeVelocityConstraints();\n\n            // Solve velocity constraints.\n            for (int i = 0; i < Settings.TOIVelocityIterations; ++i)\n            {\n                _contactSolver.SolveVelocityConstraints();\n            }\n\n            // Don't store the TOI contact forces for warm starting\n            // because they can be quite large.\n\n            float h = subStep.dt;\n\n            // Integrate positions.\n            for (int i = 0; i < BodyCount; ++i)\n            {\n                Vector2 c = Positions[i].C;\n                float a = Positions[i].A;\n                Vector2 v = Velocities[i].V;\n                float w = Velocities[i].W;\n\n                // Check for large velocities\n                Vector2 translation = h * v;\n                if (Vector2.Dot(translation, translation) > Settings.MaxTranslationSquared)\n                {\n                    float ratio = Settings.MaxTranslation / translation.Length();\n                    v *= ratio;\n                }\n\n                float rotation = h * w;\n                if (rotation * rotation > Settings.MaxRotationSquared)\n                {\n                    float ratio = Settings.MaxRotation / Math.Abs(rotation);\n                    w *= ratio;\n                }\n\n                // Integrate\n                c += h * v;\n                a += h * w;\n\n                Positions[i].C = c;\n                Positions[i].A = a;\n                Velocities[i].V = v;\n                Velocities[i].W = w;\n\n                // Sync bodies\n                Body body = Bodies[i];\n                body._sweep.C = c;\n                body._sweep.A = a;\n                body._linearVelocity = v;\n                body._angularVelocity = w;\n                body.SynchronizeTransform();\n            }\n\n            Report(_contactSolver.VelocityConstraints);\n        }\n\n        public void Add(Body body)\n        {\n            Debug.Assert(BodyCount < BodyCapacity);\n            body.IslandIndex = BodyCount;\n            Bodies[BodyCount++] = body;\n        }\n\n        public void Add(Contact contact)\n        {\n            Debug.Assert(ContactCount < ContactCapacity);\n            _contacts[ContactCount++] = contact;\n        }\n\n        public void Add(Joint joint)\n        {\n            Debug.Assert(JointCount < JointCapacity);\n            _joints[JointCount++] = joint;\n        }\n\n        private void Report(ContactVelocityConstraint[] constraints)\n        {\n            if (_contactManager == null)\n                return;\n\n            for (int i = 0; i < ContactCount; ++i)\n            {\n                Contact c = _contacts[i];\n\n                //Velcro optimization: We don't store the impulses and send it to the delegate. We just send the whole contact.\n                //Velcro feature: added after collision\n                c.FixtureA.AfterCollision?.Invoke(c.FixtureA, c.FixtureB, c, constraints[i]);\n\n                c.FixtureB.AfterCollision?.Invoke(c.FixtureB, c.FixtureA, c, constraints[i]);\n\n                _contactManager.PostSolve?.Invoke(c, constraints[i]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/Position.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    /// This is an internal structure.\n    public struct Position\n    {\n        public Vector2 C;\n        public float A;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/PositionSolverManifold.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Narrowphase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    public static class PositionSolverManifold\n    {\n        public static void Initialize(ContactPositionConstraint pc, Transform xfA, Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)\n        {\n            Debug.Assert(pc.PointCount > 0);\n\n            switch (pc.Type)\n            {\n                case ManifoldType.Circles:\n                    {\n                        Vector2 pointA = MathUtils.Mul(ref xfA, pc.LocalPoint);\n                        Vector2 pointB = MathUtils.Mul(ref xfB, pc.LocalPoints[0]);\n                        normal = pointB - pointA;\n\n                        //Velcro: Fix to handle zero normalization\n                        if (normal != Vector2.Zero)\n                            normal.Normalize();\n\n                        point = 0.5f * (pointA + pointB);\n                        separation = Vector2.Dot(pointB - pointA, normal) - pc.RadiusA - pc.RadiusB;\n                    }\n                    break;\n\n                case ManifoldType.FaceA:\n                    {\n                        normal = MathUtils.Mul(xfA.q, pc.LocalNormal);\n                        Vector2 planePoint = MathUtils.Mul(ref xfA, pc.LocalPoint);\n\n                        Vector2 clipPoint = MathUtils.Mul(ref xfB, pc.LocalPoints[index]);\n                        separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.RadiusA - pc.RadiusB;\n                        point = clipPoint;\n                    }\n                    break;\n\n                case ManifoldType.FaceB:\n                    {\n                        normal = MathUtils.Mul(xfB.q, pc.LocalNormal);\n                        Vector2 planePoint = MathUtils.Mul(ref xfB, pc.LocalPoint);\n\n                        Vector2 clipPoint = MathUtils.Mul(ref xfA, pc.LocalPoints[index]);\n                        separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.RadiusA - pc.RadiusB;\n                        point = clipPoint;\n\n                        // Ensure normal points from A to B\n                        normal = -normal;\n                    }\n                    break;\n                default:\n                    normal = Vector2.Zero;\n                    point = Vector2.Zero;\n                    separation = 0;\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/SolverData.cs",
    "content": "namespace VelcroPhysics.Dynamics.Solver\n{\n    /// Solver Data\n    public struct SolverData\n    {\n        public TimeStep Step;\n        public Position[] Positions;\n        public Velocity[] Velocities;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/Velocity.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    /// This is an internal structure.\n    public struct Velocity\n    {\n        public Vector2 V;\n        public float W;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/Solver/VelocityConstraintPoint.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Dynamics.Solver\n{\n    public sealed class VelocityConstraintPoint\n    {\n        public float NormalImpulse;\n        public float NormalMass;\n        public Vector2 rA;\n        public Vector2 rB;\n        public float TangentImpulse;\n        public float TangentMass;\n        public float VelocityBias;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/TimeStep.cs",
    "content": "﻿/*\n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nnamespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// This is an internal structure.\n    /// </summary>\n    public struct TimeStep\n    {\n        /// <summary>\n        /// Time step (Delta time)\n        /// </summary>\n        public float dt;\n\n        /// <summary>\n        /// dt * inv_dt0\n        /// </summary>\n        public float dtRatio;\n\n        /// <summary>\n        /// Inverse time step (0 if dt == 0).\n        /// </summary>\n        public float inv_dt;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Dynamics/World.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Broadphase;\nusing VelcroPhysics.Collision.ContactSystem;\nusing VelcroPhysics.Collision.Distance;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Collision.TOI;\nusing VelcroPhysics.Dynamics.Handlers;\nusing VelcroPhysics.Dynamics.Joints;\nusing VelcroPhysics.Dynamics.Solver;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Templates;\n\nnamespace VelcroPhysics.Dynamics\n{\n    /// <summary>\n    /// The world class manages all physics entities, dynamic simulation,\n    /// and asynchronous queries.\n    /// </summary>\n    public class World\n    {\n        private float _invDt0;\n        private Body[] _stack = new Body[64];\n        private bool _stepComplete;\n        private HashSet<Body> _bodyAddList = new HashSet<Body>();\n        private HashSet<Body> _bodyRemoveList = new HashSet<Body>();\n        private HashSet<Joint> _jointAddList = new HashSet<Joint>();\n        private HashSet<Joint> _jointRemoveList = new HashSet<Joint>();\n        private Func<Fixture, bool> _queryAABBCallback;\n        private Func<int, bool> _queryAABBCallbackWrapper;\n        private Fixture _myFixture;\n        private Vector2 _point1;\n        private Vector2 _point2;\n        private List<Fixture> _testPointAllFixtures;\n        private Stopwatch _watch = new Stopwatch();\n        private Func<Fixture, Vector2, Vector2, float, float> _rayCastCallback;\n        private Func<RayCastInput, int, float> _rayCastCallbackWrapper;\n\n        internal Queue<Contact> _contactPool = new Queue<Contact>(256);\n        internal bool _worldHasNewFixture;\n\n        internal int _bodyIdCounter;\n        internal int _fixtureIdCounter;\n\n        /// <summary>\n        /// Fires whenever a body has been added\n        /// </summary>\n        public BodyHandler BodyAdded;\n\n        /// <summary>\n        /// Fires whenever a body has been removed\n        /// </summary>\n        public BodyHandler BodyRemoved;\n\n        /// <summary>\n        /// Fires whenever a fixture has been added\n        /// </summary>\n        public FixtureHandler FixtureAdded;\n\n        /// <summary>\n        /// Fires whenever a fixture has been removed\n        /// </summary>\n        public FixtureHandler FixtureRemoved;\n\n        /// <summary>\n        /// Fires whenever a joint has been added\n        /// </summary>\n        public JointHandler JointAdded;\n\n        /// <summary>\n        /// Fires whenever a joint has been removed\n        /// </summary>\n        public JointHandler JointRemoved;\n\n        /// <summary>\n        /// Fires every time a controller is added to the World.\n        /// </summary>\n        public ControllerHandler ControllerAdded;\n\n        /// <summary>\n        /// Fires every time a controller is removed form the World.\n        /// </summary>\n        public ControllerHandler ControllerRemoved;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"World\" /> class.\n        /// </summary>\n        public World(Vector2 gravity)\n        {\n            Island = new Island();\n            Enabled = true;\n            ControllerList = new List<Controller>();\n            BreakableBodyList = new List<BreakableBody>();\n            BodyList = new List<Body>(32);\n            JointList = new List<Joint>(32);\n\n            _queryAABBCallbackWrapper = QueryAABBCallbackWrapper;\n            _rayCastCallbackWrapper = RayCastCallbackWrapper;\n\n            ContactManager = new ContactManager(new DynamicTreeBroadPhase());\n            Gravity = gravity;\n        }\n\n        private void ProcessRemovedJoints()\n        {\n            if (_jointRemoveList.Count > 0)\n            {\n                foreach (Joint joint in _jointRemoveList)\n                {\n                    bool collideConnected = joint.CollideConnected;\n\n                    // Remove from the world list.\n                    JointList.Remove(joint);\n\n                    // Disconnect from island graph.\n                    Body bodyA = joint.BodyA;\n                    Body bodyB = joint.BodyB;\n\n                    // Wake up connected bodies.\n                    bodyA.Awake = true;\n\n                    // WIP David\n                    if (!joint.IsFixedType())\n                    {\n                        bodyB.Awake = true;\n                    }\n\n                    // Remove from body 1.\n                    if (joint.EdgeA.Prev != null)\n                    {\n                        joint.EdgeA.Prev.Next = joint.EdgeA.Next;\n                    }\n\n                    if (joint.EdgeA.Next != null)\n                    {\n                        joint.EdgeA.Next.Prev = joint.EdgeA.Prev;\n                    }\n\n                    if (joint.EdgeA == bodyA.JointList)\n                    {\n                        bodyA.JointList = joint.EdgeA.Next;\n                    }\n\n                    joint.EdgeA.Prev = null;\n                    joint.EdgeA.Next = null;\n\n                    // WIP David\n                    if (!joint.IsFixedType())\n                    {\n                        // Remove from body 2\n                        if (joint.EdgeB.Prev != null)\n                        {\n                            joint.EdgeB.Prev.Next = joint.EdgeB.Next;\n                        }\n\n                        if (joint.EdgeB.Next != null)\n                        {\n                            joint.EdgeB.Next.Prev = joint.EdgeB.Prev;\n                        }\n\n                        if (joint.EdgeB == bodyB.JointList)\n                        {\n                            bodyB.JointList = joint.EdgeB.Next;\n                        }\n\n                        joint.EdgeB.Prev = null;\n                        joint.EdgeB.Next = null;\n\n                        // If the joint prevents collisions, then flag any contacts for filtering.\n                        if (collideConnected == false)\n                        {\n                            ContactEdge edge = bodyB.ContactList;\n                            while (edge != null)\n                            {\n                                if (edge.Other == bodyA)\n                                {\n                                    // Flag the contact for filtering at the next time step (where either\n                                    // body is awake).\n                                    edge.Contact._flags |= ContactFlags.FilterFlag;\n                                }\n\n                                edge = edge.Next;\n                            }\n                        }\n                    }\n\n                    JointRemoved?.Invoke(joint);\n                }\n\n                _jointRemoveList.Clear();\n            }\n        }\n\n        private void ProcessAddedJoints()\n        {\n            if (_jointAddList.Count > 0)\n            {\n                foreach (Joint joint in _jointAddList)\n                {\n                    // Connect to the world list.\n                    JointList.Add(joint);\n\n                    // Connect to the bodies' doubly linked lists.\n                    joint.EdgeA.Joint = joint;\n                    joint.EdgeA.Other = joint.BodyB;\n                    joint.EdgeA.Prev = null;\n                    joint.EdgeA.Next = joint.BodyA.JointList;\n\n                    if (joint.BodyA.JointList != null)\n                        joint.BodyA.JointList.Prev = joint.EdgeA;\n\n                    joint.BodyA.JointList = joint.EdgeA;\n\n                    // WIP David\n                    if (!joint.IsFixedType())\n                    {\n                        joint.EdgeB.Joint = joint;\n                        joint.EdgeB.Other = joint.BodyA;\n                        joint.EdgeB.Prev = null;\n                        joint.EdgeB.Next = joint.BodyB.JointList;\n\n                        if (joint.BodyB.JointList != null)\n                            joint.BodyB.JointList.Prev = joint.EdgeB;\n\n                        joint.BodyB.JointList = joint.EdgeB;\n\n                        Body bodyA = joint.BodyA;\n                        Body bodyB = joint.BodyB;\n\n                        // If the joint prevents collisions, then flag any contacts for filtering.\n                        if (joint.CollideConnected == false)\n                        {\n                            ContactEdge edge = bodyB.ContactList;\n                            while (edge != null)\n                            {\n                                if (edge.Other == bodyA)\n                                {\n                                    // Flag the contact for filtering at the next time step (where either\n                                    // body is awake).\n                                    edge.Contact._flags |= ContactFlags.FilterFlag;\n                                }\n\n                                edge = edge.Next;\n                            }\n                        }\n                    }\n\n                    JointAdded?.Invoke(joint);\n\n                    // Note: creating a joint doesn't wake the bodies.\n                }\n\n                _jointAddList.Clear();\n            }\n        }\n\n        private void ProcessAddedBodies()\n        {\n            if (_bodyAddList.Count > 0)\n            {\n                foreach (Body body in _bodyAddList)\n                {\n                    // Add to world list.\n                    BodyList.Add(body);\n\n                    BodyAdded?.Invoke(body);\n                }\n\n                _bodyAddList.Clear();\n            }\n        }\n\n        private void ProcessRemovedBodies()\n        {\n            if (_bodyRemoveList.Count > 0)\n            {\n                foreach (Body body in _bodyRemoveList) {\n                    Debug.Assert(BodyList.Count > 0);\n\n                    // You tried to remove a body that is not contained in the BodyList.\n                    // Are you removing the body more than once?\n                    Debug.Assert(BodyList.Contains(body));\n\n                    // Delete the attached joints.\n                    if (body.JointList != null) {\n                        JointEdge je = body.JointList;\n\n                        while (je != null) {\n                            JointEdge je0 = je;\n                            je = je.Next;\n\n                            RemoveJoint(je0.Joint, false);\n                        }\n\n                        body.JointList = null;\n                    }\n\n                    // Delete the attached contacts.\n                    ContactEdge ce = body.ContactList;\n                    \n                    while (ce != null)\n                    {\n                        ContactEdge ce0 = ce;\n                        ce = ce.Next;\n\n                        ContactManager.Destroy(ce0.Contact);\n                    }\n                    \n                    \n                    body.ContactList = null;\n\n                    // Delete the attached fixtures. This destroys broad-phase proxies.\n                    if (body.FixtureList != null) {\n                        for (int i = 0; i < body.FixtureList.Count; i++) {\n                            body.FixtureList[i].DestroyProxies(ContactManager.BroadPhase);\n                            body.FixtureList[i].Destroy();\n                        }\n                    }\n\n                    body.FixtureList = null;\n\n                    // Remove world body list.\n                    BodyList.Remove(body);\n\n                    BodyRemoved?.Invoke(body);\n                }\n\n                _bodyRemoveList.Clear();\n            }\n        }\n\n        private bool QueryAABBCallbackWrapper(int proxyId)\n        {\n            FixtureProxy proxy = ContactManager.BroadPhase.GetProxy(proxyId);\n            return _queryAABBCallback(proxy.Fixture);\n        }\n\n        private float RayCastCallbackWrapper(RayCastInput rayCastInput, int proxyId)\n        {\n            FixtureProxy proxy = ContactManager.BroadPhase.GetProxy(proxyId);\n            Fixture fixture = proxy.Fixture;\n            int index = proxy.ChildIndex;\n            RayCastOutput output;\n            bool hit = fixture.RayCast(out output, ref rayCastInput, index);\n\n            if (hit)\n            {\n                float fraction = output.Fraction;\n                Vector2 point = (1.0f - fraction) * rayCastInput.Point1 + fraction * rayCastInput.Point2;\n                return _rayCastCallback(fixture, point, output.Normal, fraction);\n            }\n\n            return rayCastInput.MaxFraction;\n        }\n\n        private void Solve(ref TimeStep step)\n        {\n            // Size the island for the worst case.\n            Island.Reset(BodyList.Count,\n                ContactManager.ContactList.Count,\n                JointList.Count,\n                ContactManager);\n\n            // Clear all the island flags.\n            foreach (Body b in BodyList)\n            {\n                b._flags &= ~BodyFlags.IslandFlag;\n            }\n\n            foreach (Contact c in ContactManager.ContactList)\n            {\n                c._flags &= ~ContactFlags.IslandFlag;\n            }\n\n            foreach (Joint j in JointList)\n            {\n                j.IslandFlag = false;\n            }\n\n            // Build and simulate all awake islands.\n            int stackSize = BodyList.Count;\n            if (stackSize > _stack.Length)\n                _stack = new Body[Math.Max(_stack.Length * 2, stackSize)];\n\n            for (int index = BodyList.Count - 1; index >= 0; index--)\n            {\n                Body seed = BodyList[index];\n                if ((seed._flags & BodyFlags.IslandFlag) == BodyFlags.IslandFlag)\n                {\n                    continue;\n                }\n\n                if (seed.Awake == false || seed.Enabled == false)\n                {\n                    continue;\n                }\n\n                // The seed can be dynamic or kinematic.\n                if (seed.BodyType == BodyType.Static)\n                {\n                    continue;\n                }\n\n                // Reset island and stack.\n                Island.Clear();\n                int stackCount = 0;\n                _stack[stackCount++] = seed;\n\n                seed._flags |= BodyFlags.IslandFlag;\n\n                // Perform a depth first search (DFS) on the constraint graph.\n                while (stackCount > 0)\n                {\n                    // Grab the next body off the stack and add it to the island.\n                    Body b = _stack[--stackCount];\n                    Debug.Assert(b.Enabled);\n                    Island.Add(b);\n\n                    // Make sure the body is awake (without resetting sleep timer).\n                    b._flags |= BodyFlags.AwakeFlag;\n\n                    // To keep islands as small as possible, we don't\n                    // propagate islands across static bodies.\n                    if (b.BodyType == BodyType.Static)\n                    {\n                        continue;\n                    }\n\n                    // Search all contacts connected to this body.\n                    for (ContactEdge ce = b.ContactList; ce != null; ce = ce.Next)\n                    {\n                        Contact contact = ce.Contact;\n\n                        // Has this contact already been added to an island?\n                        if (contact.IslandFlag)\n                        {\n                            continue;\n                        }\n\n                        // Is this contact solid and touching?\n                        if (ce.Contact.Enabled == false || ce.Contact.IsTouching == false)\n                        {\n                            continue;\n                        }\n\n                        // Skip sensors.\n                        bool sensorA = contact.FixtureA.IsSensor;\n                        bool sensorB = contact.FixtureB.IsSensor;\n                        if (sensorA || sensorB)\n                        {\n                            continue;\n                        }\n\n                        Island.Add(contact);\n                        contact._flags |= ContactFlags.IslandFlag;\n\n                        Body other = ce.Other;\n\n                        // Was the other body already added to this island?\n                        if (other.IsIsland)\n                        {\n                            continue;\n                        }\n\n                        Debug.Assert(stackCount < stackSize);\n                        _stack[stackCount++] = other;\n\n                        other._flags |= BodyFlags.IslandFlag;\n                    }\n\n                    // Search all joints connect to this body.\n                    for (JointEdge je = b.JointList; je != null; je = je.Next)\n                    {\n                        if (je.Joint.IslandFlag)\n                        {\n                            continue;\n                        }\n\n                        Body other = je.Other;\n\n                        // WIP David\n                        //Enter here when it's a non-fixed joint. Non-fixed joints have a other body.\n                        if (other != null)\n                        {\n                            // Don't simulate joints connected to inactive bodies.\n                            if (other.Enabled == false)\n                            {\n                                continue;\n                            }\n\n                            Island.Add(je.Joint);\n                            je.Joint.IslandFlag = true;\n\n                            if (other.IsIsland)\n                            {\n                                continue;\n                            }\n\n                            Debug.Assert(stackCount < stackSize);\n                            _stack[stackCount++] = other;\n\n                            other._flags |= BodyFlags.IslandFlag;\n                        }\n                        else\n                        {\n                            Island.Add(je.Joint);\n                            je.Joint.IslandFlag = true;\n                        }\n                    }\n                }\n\n                Island.Solve(ref step, ref Gravity);\n\n                // Post solve cleanup.\n                for (int i = 0; i < Island.BodyCount; ++i)\n                {\n                    // Allow static bodies to participate in other islands.\n                    Body b = Island.Bodies[i];\n                    if (b.BodyType == BodyType.Static)\n                    {\n                        b._flags &= ~BodyFlags.IslandFlag;\n                    }\n                }\n            }\n\n            // Synchronize fixtures, check for out of range bodies.\n\n            foreach (Body b in BodyList)\n            {\n                // If a body was not in an island then it did not move.\n                if (!b.IsIsland)\n                {\n                    continue;\n                }\n\n                if (b.BodyType == BodyType.Static)\n                {\n                    continue;\n                }\n\n                // Update fixtures (for broad-phase).\n                b.SynchronizeFixtures();\n            }\n\n            // Look for new contacts.\n            ContactManager.FindNewContacts();\n        }\n\n        private void SolveTOI(ref TimeStep step)\n        {\n            Island.Reset(2 * Settings.MaxTOIContacts, Settings.MaxTOIContacts, 0, ContactManager);\n\n            if (_stepComplete)\n            {\n                for (int i = 0; i < BodyList.Count; i++)\n                {\n                    BodyList[i]._flags &= ~BodyFlags.IslandFlag;\n                    BodyList[i]._sweep.Alpha0 = 0.0f;\n                }\n\n                for (int i = 0; i < ContactManager.ContactList.Count; i++)\n                {\n                    Contact c = ContactManager.ContactList[i];\n\n                    // Invalidate TOI\n                    c._flags &= ~ContactFlags.IslandFlag;\n                    c._flags &= ~ContactFlags.TOIFlag;\n                    c._toiCount = 0;\n                    c._toi = 1.0f;\n                }\n            }\n\n            // Find TOI events and solve them.\n            for (;;)\n            {\n                // Find the first TOI.\n                Contact minContact = null;\n                float minAlpha = 1.0f;\n\n                for (int i = 0; i < ContactManager.ContactList.Count; i++)\n                {\n                    Contact c = ContactManager.ContactList[i];\n\n                    // Is this contact disabled?\n                    if (c.Enabled == false)\n                    {\n                        continue;\n                    }\n\n                    // Prevent excessive sub-stepping.\n                    if (c._toiCount > Settings.MaxSubSteps)\n                    {\n                        continue;\n                    }\n\n                    float alpha;\n                    if (c.TOIFlag)\n                    {\n                        // This contact has a valid cached TOI.\n                        alpha = c._toi;\n                    }\n                    else\n                    {\n                        Fixture fA = c.FixtureA;\n                        Fixture fB = c.FixtureB;\n\n                        // Is there a sensor?\n                        if (fA.IsSensor || fB.IsSensor)\n                        {\n                            continue;\n                        }\n\n                        Body bA = fA.Body;\n                        Body bB = fB.Body;\n\n                        BodyType typeA = bA.BodyType;\n                        BodyType typeB = bB.BodyType;\n                        Debug.Assert(typeA == BodyType.Dynamic || typeB == BodyType.Dynamic);\n\n                        bool activeA = bA.Awake && typeA != BodyType.Static;\n                        bool activeB = bB.Awake && typeB != BodyType.Static;\n\n                        // Is at least one body active (awake and dynamic or kinematic)?\n                        if (activeA == false && activeB == false)\n                        {\n                            continue;\n                        }\n\n                        bool collideA = (bA.IsBullet || typeA != BodyType.Dynamic) && (fA.IgnoreCCDWith & fB.CollisionCategories) == 0 && !bA.IgnoreCCD;\n                        bool collideB = (bB.IsBullet || typeB != BodyType.Dynamic) && (fB.IgnoreCCDWith & fA.CollisionCategories) == 0 && !bB.IgnoreCCD;\n\n                        // Are these two non-bullet dynamic bodies?\n                        if (collideA == false && collideB == false)\n                        {\n                            continue;\n                        }\n\n                        // Compute the TOI for this contact.\n                        // Put the sweeps onto the same time interval.\n                        float alpha0 = bA._sweep.Alpha0;\n\n                        if (bA._sweep.Alpha0 < bB._sweep.Alpha0)\n                        {\n                            alpha0 = bB._sweep.Alpha0;\n                            bA._sweep.Advance(alpha0);\n                        }\n                        else if (bB._sweep.Alpha0 < bA._sweep.Alpha0)\n                        {\n                            alpha0 = bA._sweep.Alpha0;\n                            bB._sweep.Advance(alpha0);\n                        }\n\n                        Debug.Assert(alpha0 < 1.0f);\n\n                        // Compute the time of impact in interval [0, minTOI]\n                        TOIInput input = new TOIInput();\n                        input.ProxyA = new DistanceProxy(fA.Shape, c.ChildIndexA);\n                        input.ProxyB = new DistanceProxy(fB.Shape, c.ChildIndexB);\n                        input.SweepA = bA._sweep;\n                        input.SweepB = bB._sweep;\n                        input.TMax = 1.0f;\n\n                        TOIOutput output;\n                        TimeOfImpact.CalculateTimeOfImpact(ref input, out output);\n\n                        // Beta is the fraction of the remaining portion of the .\n                        float beta = output.T;\n                        if (output.State == TOIOutputState.Touching)\n                        {\n                            alpha = Math.Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);\n                        }\n                        else\n                        {\n                            alpha = 1.0f;\n                        }\n\n                        c._toi = alpha;\n                        c._flags &= ~ContactFlags.TOIFlag;\n                    }\n\n                    if (alpha < minAlpha)\n                    {\n                        // This is the minimum TOI found so far.\n                        minContact = c;\n                        minAlpha = alpha;\n                    }\n                }\n\n                if (minContact == null || 1.0f - 10.0f * Settings.Epsilon < minAlpha)\n                {\n                    // No more TOI events. Done!\n                    _stepComplete = true;\n                    break;\n                }\n\n                // Advance the bodies to the TOI.\n                Fixture fA1 = minContact.FixtureA;\n                Fixture fB1 = minContact.FixtureB;\n                Body bA0 = fA1.Body;\n                Body bB0 = fB1.Body;\n\n                Sweep backup1 = bA0._sweep;\n                Sweep backup2 = bB0._sweep;\n\n                bA0.Advance(minAlpha);\n                bB0.Advance(minAlpha);\n\n                // The TOI contact likely has some new contact points.\n                minContact.Update(ContactManager);\n                minContact._flags &= ~ContactFlags.TOIFlag;\n                ++minContact._toiCount;\n\n                // Is the contact solid?\n                if (minContact.Enabled == false || minContact.IsTouching == false)\n                {\n                    // Restore the sweeps.\n                    minContact._flags &= ~ContactFlags.EnabledFlag;\n                    bA0._sweep = backup1;\n                    bB0._sweep = backup2;\n                    bA0.SynchronizeTransform();\n                    bB0.SynchronizeTransform();\n                    continue;\n                }\n\n                bA0.Awake = true;\n                bB0.Awake = true;\n\n                // Build the island\n                Island.Clear();\n                Island.Add(bA0);\n                Island.Add(bB0);\n                Island.Add(minContact);\n\n                bA0._flags |= BodyFlags.IslandFlag;\n                bB0._flags |= BodyFlags.IslandFlag;\n                minContact._flags &= ~ContactFlags.IslandFlag;\n\n                // Get contacts on bodyA and bodyB.\n                Body[] bodies = { bA0, bB0 };\n                for (int i = 0; i < 2; ++i)\n                {\n                    Body body = bodies[i];\n                    if (body.BodyType == BodyType.Dynamic)\n                    {\n                        for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)\n                        {\n                            Contact contact = ce.Contact;\n\n                            if (Island.BodyCount == Island.BodyCapacity)\n                            {\n                                break;\n                            }\n\n                            if (Island.ContactCount == Island.ContactCapacity)\n                            {\n                                break;\n                            }\n\n                            // Has this contact already been added to the island?\n                            if (contact.IslandFlag)\n                            {\n                                continue;\n                            }\n\n                            // Only add static, kinematic, or bullet bodies.\n                            Body other = ce.Other;\n                            if (other.BodyType == BodyType.Dynamic &&\n                                body.IsBullet == false && other.IsBullet == false)\n                            {\n                                continue;\n                            }\n\n                            // Skip sensors.\n                            if (contact.FixtureA.IsSensor || contact.FixtureB.IsSensor)\n                            {\n                                continue;\n                            }\n\n                            // Tentatively advance the body to the TOI.\n                            Sweep backup = other._sweep;\n                            if (!other.IsIsland)\n                            {\n                                other.Advance(minAlpha);\n                            }\n\n                            // Update the contact points\n                            contact.Update(ContactManager);\n\n                            // Was the contact disabled by the user?\n                            if (contact.Enabled == false)\n                            {\n                                other._sweep = backup;\n                                other.SynchronizeTransform();\n                                continue;\n                            }\n\n                            // Are there contact points?\n                            if (contact.IsTouching == false)\n                            {\n                                other._sweep = backup;\n                                other.SynchronizeTransform();\n                                continue;\n                            }\n\n                            // Add the contact to the island\n                            minContact._flags |= ContactFlags.IslandFlag;\n                            Island.Add(contact);\n\n                            // Has the other body already been added to the island?\n                            if (other.IsIsland)\n                            {\n                                continue;\n                            }\n\n                            // Add the other body to the island.\n                            other._flags |= BodyFlags.IslandFlag;\n\n                            if (other.BodyType != BodyType.Static)\n                            {\n                                other.Awake = true;\n                            }\n\n                            Island.Add(other);\n                        }\n                    }\n                }\n\n                TimeStep subStep;\n                subStep.dt = (1.0f - minAlpha) * step.dt;\n                subStep.inv_dt = 1.0f / subStep.dt;\n                subStep.dtRatio = 1.0f;\n                Island.SolveTOI(ref subStep, bA0.IslandIndex, bB0.IslandIndex);\n\n                // Reset island flags and synchronize broad-phase proxies.\n                for (int i = 0; i < Island.BodyCount; ++i)\n                {\n                    Body body = Island.Bodies[i];\n                    body._flags &= ~BodyFlags.IslandFlag;\n\n                    if (body.BodyType != BodyType.Dynamic)\n                    {\n                        continue;\n                    }\n\n                    body.SynchronizeFixtures();\n\n                    // Invalidate all contact TOIs on this displaced body.\n                    for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)\n                    {\n                        ce.Contact._flags &= ~ContactFlags.TOIFlag;\n                        ce.Contact._flags &= ~ContactFlags.IslandFlag;\n                    }\n                }\n\n                // Commit fixture proxy movements to the broad-phase so that new contacts are created.\n                // Also, some contacts can be destroyed.\n                ContactManager.FindNewContacts();\n\n                if (Settings.EnableSubStepping)\n                {\n                    _stepComplete = false;\n                    break;\n                }\n            }\n        }\n\n        public List<Controller> ControllerList { get; private set; }\n\n        public List<BreakableBody> BreakableBodyList { get; private set; }\n\n        public float UpdateTime { get; private set; }\n\n        public float ContinuousPhysicsTime { get; private set; }\n\n        public float ControllersUpdateTime { get; private set; }\n\n        public float AddRemoveTime { get; private set; }\n\n        public float NewContactsTime { get; private set; }\n\n        public float ContactsUpdateTime { get; private set; }\n\n        public float SolveUpdateTime { get; private set; }\n\n        /// <summary>\n        /// Get the number of broad-phase proxies.\n        /// </summary>\n        /// <value>The proxy count.</value>\n        public int ProxyCount\n        {\n            get { return ContactManager.BroadPhase.ProxyCount; }\n        }\n\n        /// <summary>\n        /// Change the global gravity vector.\n        /// </summary>\n        /// <value>The gravity.</value>\n        public Vector2 Gravity;\n\n        /// <summary>\n        /// Get the contact manager for testing.\n        /// </summary>\n        /// <value>The contact manager.</value>\n        public ContactManager ContactManager { get; private set; }\n\n        /// <summary>\n        /// Get the world body list.\n        /// </summary>\n        /// <value>The head of the world body list.</value>\n        public List<Body> BodyList { get; private set; }\n\n        /// <summary>\n        /// Get the world joint list.\n        /// </summary>\n        /// <value>The joint list.</value>\n        public List<Joint> JointList { get; private set; }\n\n        /// <summary>\n        /// Get the world contact list. With the returned contact, use Contact.GetNext to get\n        /// the next contact in the world list. A null contact indicates the end of the list.\n        /// </summary>\n        /// <value>The head of the world contact list.</value>\n        public List<Contact> ContactList\n        {\n            get { return ContactManager.ContactList; }\n        }\n\n        /// <summary>\n        /// If false, the whole simulation stops. It still processes added and removed geometries.\n        /// </summary>\n        public bool Enabled { get; set; }\n\n        public Island Island { get; private set; }\n\n        /// <summary>\n        /// Add a rigid body.\n        /// </summary>\n        /// <returns></returns>\n        internal void AddBody(Body body)\n        {\n            Debug.Assert(!_bodyAddList.Contains(body), \"You are adding the same body more than once.\");\n\n            if (!_bodyAddList.Contains(body))\n                _bodyAddList.Add(body);\n        }\n\n        /// <summary>\n        /// Destroy a rigid body.\n        /// Warning: This automatically deletes all associated shapes and joints.\n        /// </summary>\n        /// <param name=\"body\">The body.</param>\n        public void RemoveBody(Body body)\n        {\n            Debug.Assert(!_bodyRemoveList.Contains(body), \"The body is already marked for removal. You are removing the body more than once.\");\n\n            if (!_bodyRemoveList.Contains(body))\n                _bodyRemoveList.Add(body);\n        }\n\n        /// <summary>\n        /// Create a joint to constrain bodies together. This may cause the connected bodies to cease colliding.\n        /// </summary>\n        /// <param name=\"joint\">The joint.</param>\n        public void AddJoint(Joint joint)\n        {\n            Debug.Assert(!_jointAddList.Contains(joint), \"You are adding the same joint more than once.\");\n\n            if (!_jointAddList.Contains(joint))\n                _jointAddList.Add(joint);\n        }\n\n        private void RemoveJoint(Joint joint, bool doCheck)\n        {\n            if (doCheck)\n            {\n                Debug.Assert(!_jointRemoveList.Contains(joint),\n                    \"The joint is already marked for removal. You are removing the joint more than once.\");\n            }\n\n            if (!_jointRemoveList.Contains(joint))\n                _jointRemoveList.Add(joint);\n        }\n\n        /// <summary>\n        /// Destroy a joint. This may cause the connected bodies to begin colliding.\n        /// </summary>\n        /// <param name=\"joint\">The joint.</param>\n        public void RemoveJoint(Joint joint)\n        {\n            RemoveJoint(joint, true);\n        }\n\n        /// <summary>\n        /// All adds and removes are cached by the World during a World step.\n        /// To process the changes before the world updates again, call this method.\n        /// </summary>\n        public void ProcessChanges()\n        {\n            ProcessAddedBodies();\n            ProcessAddedJoints();\n\n            ProcessRemovedBodies();\n            ProcessRemovedJoints();\n        }\n\n        /// <summary>\n        /// Take a time step. This performs collision detection, integration,\n        /// and constraint solution.\n        /// </summary>\n        /// <param name=\"dt\">The amount of time to simulate, this should not vary.</param>\n        public void Step(float dt)\n        {\n            if (!Enabled)\n                return;\n\n            if (Settings.EnableDiagnostics)\n                _watch.Start();\n\n            ProcessChanges();\n\n            if (Settings.EnableDiagnostics)\n                AddRemoveTime = _watch.ElapsedTicks;\n\n            // If new fixtures were added, we need to find the new contacts.\n            if (_worldHasNewFixture)\n            {\n                ContactManager.FindNewContacts();\n                _worldHasNewFixture = false;\n            }\n\n            if (Settings.EnableDiagnostics)\n                NewContactsTime = _watch.ElapsedTicks - AddRemoveTime;\n\n            //Velcro only: moved position and velocity iterations into Settings.cs\n            TimeStep step;\n            step.inv_dt = dt > 0.0f ? 1.0f / dt : 0.0f;\n            step.dt = dt;\n            step.dtRatio = _invDt0 * dt;\n\n            //Update controllers\n            for (int i = 0; i < ControllerList.Count; i++)\n            {\n                ControllerList[i].Update(dt);\n            }\n\n            if (Settings.EnableDiagnostics)\n                ControllersUpdateTime = _watch.ElapsedTicks - (AddRemoveTime + NewContactsTime);\n\n            // Update contacts. This is where some contacts are destroyed.\n            ContactManager.Collide();\n\n            if (Settings.EnableDiagnostics)\n                ContactsUpdateTime = _watch.ElapsedTicks - (AddRemoveTime + NewContactsTime + ControllersUpdateTime);\n\n            // Integrate velocities, solve velocity constraints, and integrate positions.\n            Solve(ref step);\n\n            if (Settings.EnableDiagnostics)\n                SolveUpdateTime = _watch.ElapsedTicks - (AddRemoveTime + NewContactsTime + ControllersUpdateTime + ContactsUpdateTime);\n\n            // Handle TOI events.\n            if (Settings.ContinuousPhysics)\n            {\n                SolveTOI(ref step);\n            }\n\n            if (Settings.EnableDiagnostics)\n                ContinuousPhysicsTime = _watch.ElapsedTicks - (AddRemoveTime + NewContactsTime + ControllersUpdateTime + ContactsUpdateTime + SolveUpdateTime);\n\n            if (Settings.AutoClearForces)\n                ClearForces();\n\n            for (int i = 0; i < BreakableBodyList.Count; i++)\n            {\n                BreakableBodyList[i].Update();\n            }\n\n            _invDt0 = step.inv_dt;\n\n            if (Settings.EnableDiagnostics)\n            {\n                _watch.Stop();\n                UpdateTime = _watch.ElapsedTicks;\n                _watch.Reset();\n            }\n        }\n\n        /// <summary>\n        /// Call this after you are done with time steps to clear the forces. You normally\n        /// call this after each call to Step, unless you are performing sub-steps. By default,\n        /// forces will be automatically cleared, so you don't need to call this function.\n        /// </summary>\n        public void ClearForces()\n        {\n            for (int i = 0; i < BodyList.Count; i++)\n            {\n                Body body = BodyList[i];\n                body._force = Vector2.Zero;\n                body._torque = 0.0f;\n            }\n        }\n\n        /// <summary>\n        /// Query the world for all fixtures that potentially overlap the provided AABB.\n        /// Inside the callback:\n        /// Return true: Continues the query\n        /// Return false: Terminate the query\n        /// </summary>\n        /// <param name=\"callback\">A user implemented callback class.</param>\n        /// <param name=\"aabb\">The AABB query box.</param>\n        public void QueryAABB(Func<Fixture, bool> callback, ref AABB aabb)\n        {\n            _queryAABBCallback = callback;\n            ContactManager.BroadPhase.Query(_queryAABBCallbackWrapper, ref aabb);\n            _queryAABBCallback = null;\n        }\n\n        /// <summary>\n        /// Query the world for all fixtures that potentially overlap the provided AABB.\n        /// Use the overload with a callback for filtering and better performance.\n        /// </summary>\n        /// <param name=\"aabb\">The AABB query box.</param>\n        /// <returns>A list of fixtures that were in the affected area.</returns>\n        public List<Fixture> QueryAABB(ref AABB aabb)\n        {\n            List<Fixture> affected = new List<Fixture>();\n\n            QueryAABB(fixture =>\n            {\n                affected.Add(fixture);\n                return true;\n            }, ref aabb);\n\n            return affected;\n        }\n\n        /// <summary>\n        /// Ray-cast the world for all fixtures in the path of the ray. Your callback\n        /// controls whether you get the closest point, any point, or n-points.\n        /// The ray-cast ignores shapes that contain the starting point.\n        /// Inside the callback:\n        /// return -1: ignore this fixture and continue\n        /// return 0: terminate the ray cast\n        /// return fraction: clip the ray to this point\n        /// return 1: don't clip the ray and continue\n        /// </summary>\n        /// <param name=\"callback\">A user implemented callback class.</param>\n        /// <param name=\"point1\">The ray starting point.</param>\n        /// <param name=\"point2\">The ray ending point.</param>\n        public void RayCast(Func<Fixture, Vector2, Vector2, float, float> callback, Vector2 point1, Vector2 point2)\n        {\n            RayCastInput input = new RayCastInput();\n            input.MaxFraction = 1.0f;\n            input.Point1 = point1;\n            input.Point2 = point2;\n\n            _rayCastCallback = callback;\n            ContactManager.BroadPhase.RayCast(_rayCastCallbackWrapper, ref input);\n            _rayCastCallback = null;\n        }\n\n        public List<Fixture> RayCast(Vector2 point1, Vector2 point2)\n        {\n            List<Fixture> affected = new List<Fixture>();\n\n            RayCast((f, p, n, fr) =>\n            {\n                affected.Add(f);\n                return 1;\n            }, point1, point2);\n\n            return affected;\n        }\n\n        public void AddController(Controller controller)\n        {\n            Debug.Assert(!ControllerList.Contains(controller), \"You are adding the same controller more than once.\");\n\n            controller.World = this;\n            ControllerList.Add(controller);\n\n            ControllerAdded?.Invoke(controller);\n        }\n\n        public void RemoveController(Controller controller)\n        {\n            Debug.Assert(ControllerList.Contains(controller),\n                \"You are removing a controller that is not in the simulation.\");\n\n            if (ControllerList.Contains(controller))\n            {\n                ControllerList.Remove(controller);\n\n                ControllerRemoved?.Invoke(controller);\n            }\n        }\n\n        public void AddBreakableBody(BreakableBody breakableBody)\n        {\n            BreakableBodyList.Add(breakableBody);\n        }\n\n        public void RemoveBreakableBody(BreakableBody breakableBody)\n        {\n            //The breakable body list does not contain the body you tried to remove.\n            Debug.Assert(BreakableBodyList.Contains(breakableBody));\n\n            BreakableBodyList.Remove(breakableBody);\n        }\n\n        public Fixture TestPoint(Vector2 point)\n        {\n            AABB aabb;\n            Vector2 d = new Vector2(Settings.Epsilon, Settings.Epsilon);\n            aabb.LowerBound = point - d;\n            aabb.UpperBound = point + d;\n\n            _myFixture = null;\n            _point1 = point;\n\n            // Query the world for overlapping shapes.\n            QueryAABB(TestPointCallback, ref aabb);\n\n            return _myFixture;\n        }\n\n        private bool TestPointCallback(Fixture fixture)\n        {\n            bool inside = fixture.TestPoint(ref _point1);\n            if (inside)\n            {\n                _myFixture = fixture;\n                return false;\n            }\n\n            // Continue the query.\n            return true;\n        }\n\n        /// <summary>\n        /// Returns a list of fixtures that are at the specified point.\n        /// </summary>\n        /// <param name=\"point\">The point.</param>\n        /// <returns></returns>\n        public List<Fixture> TestPointAll(Vector2 point)\n        {\n            AABB aabb;\n            Vector2 d = new Vector2(Settings.Epsilon, Settings.Epsilon);\n            aabb.LowerBound = point - d;\n            aabb.UpperBound = point + d;\n\n            _point2 = point;\n            _testPointAllFixtures = new List<Fixture>();\n\n            // Query the world for overlapping shapes.\n            QueryAABB(TestPointAllCallback, ref aabb);\n\n            return _testPointAllFixtures;\n        }\n\n        private bool TestPointAllCallback(Fixture fixture)\n        {\n            bool inside = fixture.TestPoint(ref _point2);\n            if (inside)\n                _testPointAllFixtures.Add(fixture);\n\n            // Continue the query.\n            return true;\n        }\n\n        /// Shift the world origin. Useful for large worlds.\n        /// The body shift formula is: position -= newOrigin\n        /// @param newOrigin the new origin with respect to the old origin\n        /// Warning: Calling this method mid-update might cause a crash.\n        public void ShiftOrigin(Vector2 newOrigin)\n        {\n            foreach (Body b in BodyList)\n            {\n                b._xf.p -= newOrigin;\n                b._sweep.C0 -= newOrigin;\n                b._sweep.C -= newOrigin;\n            }\n\n            foreach (Joint joint in JointList)\n            {\n                //joint.ShiftOrigin(newOrigin); //TODO: uncomment\n            }\n\n            ContactManager.BroadPhase.ShiftOrigin(newOrigin);\n        }\n\n        public void Clear()\n        {\n            ProcessChanges();\n\n            for (int i = BodyList.Count - 1; i >= 0; i--)\n            {\n                RemoveBody(BodyList[i]);\n            }\n\n            for (int i = ControllerList.Count - 1; i >= 0; i--)\n            {\n                RemoveController(ControllerList[i]);\n            }\n\n            for (int i = BreakableBodyList.Count - 1; i >= 0; i--)\n            {\n                RemoveBreakableBody(BreakableBodyList[i]);\n            }\n\n            ProcessChanges();\n        }\n\n        internal Body CreateBody(BodyTemplate template)\n        {\n            Body b = new Body(this, template);\n            b.BodyId = _bodyIdCounter++;\n\n            AddBody(b);\n            return b;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Buoyancy/BuoyancyController.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Extensions.Controllers.Buoyancy\n{\n    public sealed class BuoyancyController : Controller\n    {\n        private AABB _container;\n\n        private Vector2 _gravity;\n        private Vector2 _normal;\n        private float _offset;\n        private Dictionary<int, Body> _uniqueBodies = new Dictionary<int, Body>();\n\n        /// <summary>\n        /// Controls the rotational drag that the fluid exerts on the bodies within it. Use higher values will simulate thick\n        /// fluid, like honey, lower values to\n        /// simulate water-like fluids.\n        /// </summary>\n        public float AngularDragCoefficient;\n\n        /// <summary>\n        /// Density of the fluid. Higher values will make things more buoyant, lower values will cause things to sink.\n        /// </summary>\n        public float Density;\n\n        /// <summary>\n        /// Controls the linear drag that the fluid exerts on the bodies within it.  Use higher values will simulate thick fluid,\n        /// like honey, lower values to\n        /// simulate water-like fluids.\n        /// </summary>\n        public float LinearDragCoefficient;\n\n        /// <summary>\n        /// Acts like waterflow. Defaults to 0,0.\n        /// </summary>\n        public Vector2 Velocity;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BuoyancyController\" /> class.\n        /// </summary>\n        /// <param name=\"container\">Only bodies inside this AABB will be influenced by the controller</param>\n        /// <param name=\"density\">Density of the fluid</param>\n        /// <param name=\"linearDragCoefficient\">Linear drag coefficient of the fluid</param>\n        /// <param name=\"rotationalDragCoefficient\">Rotational drag coefficient of the fluid</param>\n        /// <param name=\"gravity\">The direction gravity acts. Buoyancy force will act in opposite direction of gravity.</param>\n        public BuoyancyController(AABB container, float density, float linearDragCoefficient, float rotationalDragCoefficient, Vector2 gravity)\n            : base(ControllerType.BuoyancyController)\n        {\n            Container = container;\n            _normal = new Vector2(0, 1);\n            Density = density;\n            LinearDragCoefficient = linearDragCoefficient;\n            AngularDragCoefficient = rotationalDragCoefficient;\n            _gravity = gravity;\n        }\n\n        public AABB Container\n        {\n            get { return _container; }\n            set\n            {\n                _container = value;\n                _offset = _container.UpperBound.Y;\n            }\n        }\n\n        public override void Update(float dt)\n        {\n            _uniqueBodies.Clear();\n            World.QueryAABB(fixture =>\n            {\n                if (fixture.Body.IsStatic || !fixture.Body.Awake)\n                    return true;\n\n                if (!_uniqueBodies.ContainsKey(fixture.Body.BodyId))\n                    _uniqueBodies.Add(fixture.Body.BodyId, fixture.Body);\n\n                return true;\n            }, ref _container);\n\n            foreach (KeyValuePair<int, Body> kv in _uniqueBodies)\n            {\n                Body body = kv.Value;\n\n                Vector2 areac = Vector2.Zero;\n                Vector2 massc = Vector2.Zero;\n                float area = 0;\n                float mass = 0;\n\n                for (int j = 0; j < body.FixtureList.Count; j++)\n                {\n                    Fixture fixture = body.FixtureList[j];\n\n                    if (fixture.Shape.ShapeType != ShapeType.Polygon && fixture.Shape.ShapeType != ShapeType.Circle)\n                        continue;\n\n                    Shape shape = fixture.Shape;\n\n                    Vector2 sc;\n                    float sarea = ComputeSubmergedArea(shape, ref _normal, _offset, ref body._xf, out sc);\n                    area += sarea;\n                    areac.X += sarea * sc.X;\n                    areac.Y += sarea * sc.Y;\n\n                    mass += sarea * shape.Density;\n                    massc.X += sarea * sc.X * shape.Density;\n                    massc.Y += sarea * sc.Y * shape.Density;\n                }\n\n                areac.X /= area;\n                areac.Y /= area;\n                massc.X /= mass;\n                massc.Y /= mass;\n\n                if (area < Settings.Epsilon)\n                    continue;\n\n                //Buoyancy\n                Vector2 buoyancyForce = -Density * area * _gravity;\n                body.ApplyForce(buoyancyForce, massc);\n\n                //Linear drag\n                Vector2 dragForce = body.GetLinearVelocityFromWorldPoint(areac) - Velocity;\n                dragForce *= -LinearDragCoefficient * area;\n                body.ApplyForce(dragForce, areac);\n\n                //Angular drag\n                body.ApplyTorque(-body.Inertia / body.Mass * area * body.AngularVelocity * AngularDragCoefficient);\n            }\n        }\n\n        private float ComputeSubmergedArea(Shape shape, ref Vector2 normal, float offset, ref Transform xf, out Vector2 sc)\n        {\n            switch (shape.ShapeType)\n            {\n                case ShapeType.Circle:\n                    {\n                        CircleShape circleShape = (CircleShape)shape;\n\n                        sc = Vector2.Zero;\n\n                        Vector2 p = MathUtils.Mul(ref xf, circleShape.Position);\n                        float l = -(Vector2.Dot(normal, p) - offset);\n                        if (l < -circleShape.Radius + Settings.Epsilon)\n                        {\n                            //Completely dry\n                            return 0;\n                        }\n                        if (l > circleShape.Radius)\n                        {\n                            //Completely wet\n                            sc = p;\n                            return Settings.Pi * circleShape._2radius;\n                        }\n\n                        //Magic\n                        float l2 = l * l;\n                        float area = circleShape._2radius * (float)((Math.Asin(l / circleShape.Radius) + Settings.Pi / 2) + l * Math.Sqrt(circleShape._2radius - l2));\n                        float com = -2.0f / 3.0f * (float)Math.Pow(circleShape._2radius - l2, 1.5f) / area;\n\n                        sc.X = p.X + normal.X * com;\n                        sc.Y = p.Y + normal.Y * com;\n\n                        return area;\n                    }\n                case ShapeType.Edge:\n                    sc = Vector2.Zero;\n                    return 0;\n                case ShapeType.Polygon:\n                    {\n                        sc = Vector2.Zero;\n\n                        PolygonShape polygonShape = (PolygonShape)shape;\n\n                        //Transform plane into shape co-ordinates\n                        Vector2 normalL = MathUtils.MulT(xf.q, normal);\n                        float offsetL = offset - Vector2.Dot(normal, xf.p);\n\n                        float[] depths = new float[Settings.MaxPolygonVertices];\n                        int diveCount = 0;\n                        int intoIndex = -1;\n                        int outoIndex = -1;\n\n                        bool lastSubmerged = false;\n                        int i;\n                        for (i = 0; i < polygonShape.Vertices.Count; i++)\n                        {\n                            depths[i] = Vector2.Dot(normalL, polygonShape.Vertices[i]) - offsetL;\n                            bool isSubmerged = depths[i] < -Settings.Epsilon;\n                            if (i > 0)\n                            {\n                                if (isSubmerged)\n                                {\n                                    if (!lastSubmerged)\n                                    {\n                                        intoIndex = i - 1;\n                                        diveCount++;\n                                    }\n                                }\n                                else\n                                {\n                                    if (lastSubmerged)\n                                    {\n                                        outoIndex = i - 1;\n                                        diveCount++;\n                                    }\n                                }\n                            }\n                            lastSubmerged = isSubmerged;\n                        }\n                        switch (diveCount)\n                        {\n                            case 0:\n                                if (lastSubmerged)\n                                {\n                                    //Completely submerged\n                                    sc = MathUtils.Mul(ref xf, polygonShape.MassData.Centroid);\n                                    return polygonShape.MassData.Mass / Density;\n                                }\n\n                                //Completely dry\n                                return 0;\n                            case 1:\n                                if (intoIndex == -1)\n                                {\n                                    intoIndex = polygonShape.Vertices.Count - 1;\n                                }\n                                else\n                                {\n                                    outoIndex = polygonShape.Vertices.Count - 1;\n                                }\n                                break;\n                        }\n\n                        int intoIndex2 = (intoIndex + 1) % polygonShape.Vertices.Count;\n                        int outoIndex2 = (outoIndex + 1) % polygonShape.Vertices.Count;\n\n                        float intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]);\n                        float outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]);\n\n                        Vector2 intoVec = new Vector2(polygonShape.Vertices[intoIndex].X * (1 - intoLambda) + polygonShape.Vertices[intoIndex2].X * intoLambda, polygonShape.Vertices[intoIndex].Y * (1 - intoLambda) + polygonShape.Vertices[intoIndex2].Y * intoLambda);\n                        Vector2 outoVec = new Vector2(polygonShape.Vertices[outoIndex].X * (1 - outoLambda) + polygonShape.Vertices[outoIndex2].X * outoLambda, polygonShape.Vertices[outoIndex].Y * (1 - outoLambda) + polygonShape.Vertices[outoIndex2].Y * outoLambda);\n\n                        //Initialize accumulator\n                        float area = 0;\n                        Vector2 center = new Vector2(0, 0);\n                        Vector2 p2 = polygonShape.Vertices[intoIndex2];\n\n                        const float k_inv3 = 1.0f / 3.0f;\n\n                        //An awkward loop from intoIndex2+1 to outIndex2\n                        i = intoIndex2;\n                        while (i != outoIndex2)\n                        {\n                            i = (i + 1) % polygonShape.Vertices.Count;\n                            Vector2 p3;\n                            if (i == outoIndex2)\n                                p3 = outoVec;\n                            else\n                                p3 = polygonShape.Vertices[i];\n\n                            //Add the triangle formed by intoVec,p2,p3\n                            {\n                                Vector2 e1 = p2 - intoVec;\n                                Vector2 e2 = p3 - intoVec;\n\n                                float D = MathUtils.Cross(e1, e2);\n\n                                float triangleArea = 0.5f * D;\n\n                                area += triangleArea;\n\n                                // Area weighted centroid\n                                center += triangleArea * k_inv3 * (intoVec + p2 + p3);\n                            }\n\n                            p2 = p3;\n                        }\n\n                        //Normalize and transform centroid\n                        center *= 1.0f / area;\n\n                        sc = MathUtils.Mul(ref xf, center);\n\n                        return area;\n                    }\n                case ShapeType.Chain:\n                    sc = Vector2.Zero;\n                    return 0;\n                case ShapeType.Unknown:\n                case ShapeType.TypeCount:\n                    throw new NotSupportedException();\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/ControllerBase/Controller.cs",
    "content": "﻿using VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase;\n\nnamespace VelcroPhysics.Extensions.Controllers.ControllerBase\n{\n    public abstract class Controller : FilterData\n    {\n        private ControllerType _type;\n        public bool Enabled;\n        public World World;\n\n        public Controller(ControllerType controllerType)\n        {\n            _type = controllerType;\n        }\n\n        public override bool IsActiveOn(Body body)\n        {\n            if (body.ControllerFilter.IsControllerIgnored(_type))\n                return false;\n\n            return base.IsActiveOn(body);\n        }\n\n        public abstract void Update(float dt);\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/ControllerBase/ControllerFilter.cs",
    "content": "namespace VelcroPhysics.Extensions.Controllers.ControllerBase\n{\n    public struct ControllerFilter\n    {\n        public ControllerType ControllerFlags;\n\n        /// <summary>\n        /// Ignores the controller. The controller has no effect on this body.\n        /// </summary>\n        /// <param name=\"controller\">The controller type.</param>\n        public void IgnoreController(ControllerType controller)\n        {\n            ControllerFlags |= controller;\n        }\n\n        /// <summary>\n        /// Restore the controller. The controller affects this body.\n        /// </summary>\n        /// <param name=\"controller\">The controller type.</param>\n        public void RestoreController(ControllerType controller)\n        {\n            ControllerFlags &= ~controller;\n        }\n\n        /// <summary>\n        /// Determines whether this body ignores the specified controller.\n        /// </summary>\n        /// <param name=\"controller\">The controller type.</param>\n        /// <returns>\n        /// <c>true</c> if the body has the specified flag; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsControllerIgnored(ControllerType controller)\n        {\n            return (ControllerFlags & controller) == controller;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/ControllerBase/ControllerType.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Extensions.Controllers.ControllerBase\n{\n    [Flags]\n    public enum ControllerType\n    {\n        GravityController = (1 << 0),\n        VelocityLimitController = (1 << 1),\n        AbstractForceController = (1 << 2),\n        BuoyancyController = (1 << 3)\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Gravity/GravityController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\n\nnamespace VelcroPhysics.Extensions.Controllers.Gravity\n{\n    public class GravityController : Controller\n    {\n        public GravityController(float strength)\n            : base(ControllerType.GravityController)\n        {\n            Strength = strength;\n            MaxRadius = float.MaxValue;\n            GravityType = GravityType.DistanceSquared;\n            Points = new List<Vector2>();\n            Bodies = new List<Body>();\n        }\n\n        public GravityController(float strength, float maxRadius, float minRadius)\n            : base(ControllerType.GravityController)\n        {\n            MinRadius = minRadius;\n            MaxRadius = maxRadius;\n            Strength = strength;\n            GravityType = GravityType.DistanceSquared;\n            Points = new List<Vector2>();\n            Bodies = new List<Body>();\n        }\n\n        public float MinRadius { get; set; }\n        public float MaxRadius { get; set; }\n        public float Strength { get; set; }\n        public GravityType GravityType { get; set; }\n        public List<Body> Bodies { get; set; }\n        public List<Vector2> Points { get; set; }\n\n        public override void Update(float dt)\n        {\n            Vector2 f = Vector2.Zero;\n\n            foreach (Body worldBody in World.BodyList)\n            {\n                if (!IsActiveOn(worldBody))\n                    continue;\n\n                foreach (Body controllerBody in Bodies)\n                {\n                    if (worldBody == controllerBody || (worldBody.IsStatic && controllerBody.IsStatic) || !controllerBody.Enabled)\n                        continue;\n\n                    Vector2 d = controllerBody.Position - worldBody.Position;\n                    float r2 = d.LengthSquared();\n\n                    if (r2 <= Settings.Epsilon || r2 > MaxRadius * MaxRadius || r2 < MinRadius * MinRadius)\n                        continue;\n\n                    switch (GravityType)\n                    {\n                        case GravityType.DistanceSquared:\n                            f = Strength / r2 * worldBody.Mass * controllerBody.Mass * d;\n                            break;\n                        case GravityType.Linear:\n                            f = Strength / (float)Math.Sqrt(r2) * worldBody.Mass * controllerBody.Mass * d;\n                            break;\n                    }\n\n                    worldBody.ApplyForce(ref f);\n                }\n\n                foreach (Vector2 point in Points)\n                {\n                    Vector2 d = point - worldBody.Position;\n                    float r2 = d.LengthSquared();\n\n                    if (r2 <= Settings.Epsilon || r2 > MaxRadius * MaxRadius || r2 < MinRadius * MinRadius)\n                        continue;\n\n                    switch (GravityType)\n                    {\n                        case GravityType.DistanceSquared:\n                            f = Strength / r2 * worldBody.Mass * d;\n                            break;\n                        case GravityType.Linear:\n                            f = Strength / (float)Math.Sqrt(r2) * worldBody.Mass * d;\n                            break;\n                    }\n\n                    worldBody.ApplyForce(ref f);\n                }\n            }\n        }\n\n        public void AddBody(Body body)\n        {\n            Bodies.Add(body);\n        }\n\n        public void AddPoint(Vector2 point)\n        {\n            Points.Add(point);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Gravity/GravityType.cs",
    "content": "namespace VelcroPhysics.Extensions.Controllers.Gravity\n{\n    public enum GravityType\n    {\n        Linear,\n        DistanceSquared\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Velocity/VelocityLimitController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\n\nnamespace VelcroPhysics.Extensions.Controllers.Velocity\n{\n    /// <summary>\n    /// Put a limit on the linear (translation - the move speed) and angular (rotation) velocity\n    /// of bodies added to this controller.\n    /// </summary>\n    public class VelocityLimitController : Controller\n    {\n        private List<Body> _bodies = new List<Body>();\n        private float _maxAngularSqared;\n        private float _maxAngularVelocity;\n        private float _maxLinearSqared;\n        private float _maxLinearVelocity;\n        public bool LimitAngularVelocity = true;\n        public bool LimitLinearVelocity = true;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"VelocityLimitController\" /> class.\n        /// Sets the max linear velocity to Settings.MaxTranslation\n        /// Sets the max angular velocity to Settings.MaxRotation\n        /// </summary>\n        public VelocityLimitController()\n            : base(ControllerType.VelocityLimitController)\n        {\n            MaxLinearVelocity = Settings.MaxTranslation;\n            MaxAngularVelocity = Settings.MaxRotation;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"VelocityLimitController\" /> class.\n        /// Pass in 0 or float.MaxValue to disable the limit.\n        /// maxAngularVelocity = 0 will disable the angular velocity limit.\n        /// </summary>\n        /// <param name=\"maxLinearVelocity\">The max linear velocity.</param>\n        /// <param name=\"maxAngularVelocity\">The max angular velocity.</param>\n        public VelocityLimitController(float maxLinearVelocity, float maxAngularVelocity)\n            : base(ControllerType.VelocityLimitController)\n        {\n            if (maxLinearVelocity == 0 || maxLinearVelocity == float.MaxValue)\n                LimitLinearVelocity = false;\n\n            if (maxAngularVelocity == 0 || maxAngularVelocity == float.MaxValue)\n                LimitAngularVelocity = false;\n\n            MaxLinearVelocity = maxLinearVelocity;\n            MaxAngularVelocity = maxAngularVelocity;\n        }\n\n        /// <summary>\n        /// Gets or sets the max angular velocity.\n        /// </summary>\n        /// <value>The max angular velocity.</value>\n        public float MaxAngularVelocity\n        {\n            get { return _maxAngularVelocity; }\n            set\n            {\n                _maxAngularVelocity = value;\n                _maxAngularSqared = _maxAngularVelocity * _maxAngularVelocity;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the max linear velocity.\n        /// </summary>\n        /// <value>The max linear velocity.</value>\n        public float MaxLinearVelocity\n        {\n            get { return _maxLinearVelocity; }\n            set\n            {\n                _maxLinearVelocity = value;\n                _maxLinearSqared = _maxLinearVelocity * _maxLinearVelocity;\n            }\n        }\n\n        public override void Update(float dt)\n        {\n            foreach (Body body in _bodies)\n            {\n                if (!IsActiveOn(body))\n                    continue;\n\n                if (LimitLinearVelocity)\n                {\n                    //Translation\n                    // Check for large velocities.\n                    float translationX = dt * body._linearVelocity.X;\n                    float translationY = dt * body._linearVelocity.Y;\n                    float result = translationX * translationX + translationY * translationY;\n\n                    if (result > dt * _maxLinearSqared)\n                    {\n                        float sq = (float)Math.Sqrt(result);\n\n                        float ratio = _maxLinearVelocity / sq;\n                        body._linearVelocity.X *= ratio;\n                        body._linearVelocity.Y *= ratio;\n                    }\n                }\n\n                if (LimitAngularVelocity)\n                {\n                    //Rotation\n                    float rotation = dt * body._angularVelocity;\n                    if (rotation * rotation > _maxAngularSqared)\n                    {\n                        float ratio = _maxAngularVelocity / Math.Abs(rotation);\n                        body._angularVelocity *= ratio;\n                    }\n                }\n            }\n        }\n\n        public void AddBody(Body body)\n        {\n            _bodies.Add(body);\n        }\n\n        public void RemoveBody(Body body)\n        {\n            _bodies.Remove(body);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Wind/AbstractForceController.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.Controllers.ControllerBase;\n\nnamespace VelcroPhysics.Extensions.Controllers.Wind\n{\n    public abstract class AbstractForceController : Controller\n    {\n        #region DecayModes enum\n\n        /// <summary>\n        /// Modes for Decay. Actual Decay must be implemented in inheriting\n        /// classes\n        /// </summary>\n        public enum DecayModes\n        {\n            None,\n            Step,\n            Linear,\n            InverseSquare,\n            Curve\n        }\n\n        #endregion\n\n        #region ForceTypes enum\n\n        /// <summary>\n        /// Forcetypes are used in the decay math to properly get the distance.\n        /// They are also used to draw a representation in DebugView\n        /// </summary>\n        public enum ForceTypes\n        {\n            Point,\n            Line,\n            Area\n        }\n\n        #endregion\n\n        #region TimingModes enum\n\n        /// <summary>\n        /// Timing Modes\n        /// Switched: Standard on/off mode using the baseclass enabled property\n        /// Triggered: When the Trigger() method is called the force is active\n        /// for a specified Impulse Length\n        /// Curve: Still to be defined. The basic idea is having a Trigger\n        /// combined with a curve for the strength\n        /// </summary>\n        public enum TimingModes\n        {\n            Switched,\n            Triggered,\n            Curve\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Curve to be used for Decay in Curve mode\n        /// </summary>\n        public Curve DecayCurve;\n\n        /// <summary>\n        /// The Forcetype of the instance\n        /// </summary>\n        public ForceTypes ForceType;\n\n        /// <summary>\n        /// Provided for reuse to provide Variation functionality in\n        /// inheriting classes\n        /// </summary>\n        protected Random Randomize;\n\n        /// <summary>\n        /// Curve used by Curve Mode as an animated multiplier for the force\n        /// strength.\n        /// Only positions between 0 and 1 are considered as that range is\n        /// stretched to have ImpulseLength.\n        /// </summary>\n        public Curve StrengthCurve;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public AbstractForceController()\n            : base(ControllerType.AbstractForceController)\n        {\n            Enabled = true;\n\n            Strength = 1.0f;\n            Position = new Vector2(0, 0);\n            MaximumSpeed = 100.0f;\n            TimingMode = TimingModes.Switched;\n            ImpulseTime = 0.0f;\n            ImpulseLength = 1.0f;\n            Triggered = false;\n            StrengthCurve = new Curve();\n            Variation = 0.0f;\n            Randomize = new Random(1234);\n            DecayMode = DecayModes.None;\n            DecayCurve = new Curve();\n            DecayStart = 0.0f;\n            DecayEnd = 0.0f;\n\n            StrengthCurve.Keys.Add(new CurveKey(0, 5));\n            StrengthCurve.Keys.Add(new CurveKey(0.1f, 5));\n            StrengthCurve.Keys.Add(new CurveKey(0.2f, -4));\n            StrengthCurve.Keys.Add(new CurveKey(1f, 0));\n        }\n\n        /// <summary>\n        /// Overloaded Contstructor with supplying Timing Mode\n        /// </summary>\n        /// <param name=\"mode\"></param>\n        public AbstractForceController(TimingModes mode)\n            : base(ControllerType.AbstractForceController)\n        {\n            TimingMode = mode;\n            switch (mode)\n            {\n                case TimingModes.Switched:\n                    Enabled = true;\n                    break;\n                case TimingModes.Triggered:\n                    Enabled = false;\n                    break;\n                case TimingModes.Curve:\n                    Enabled = false;\n                    break;\n            }\n        }\n\n        /// <summary>\n        /// Global Strength of the force to be applied\n        /// </summary>\n        public float Strength { get; set; }\n\n        /// <summary>\n        /// Position of the Force. Can be ignored (left at (0,0) for forces\n        /// that are not position-dependent\n        /// </summary>\n        public Vector2 Position { get; set; }\n\n        /// <summary>\n        /// Maximum speed of the bodies. Bodies that are travelling faster are\n        /// supposed to be ignored\n        /// </summary>\n        public float MaximumSpeed { get; set; }\n\n        /// <summary>\n        /// Maximum Force to be applied. As opposed to Maximum Speed this is\n        /// independent of the velocity of\n        /// the affected body\n        /// </summary>\n        public float MaximumForce { get; set; }\n\n        /// <summary>\n        /// Timing Mode of the force instance\n        /// </summary>\n        public TimingModes TimingMode { get; set; }\n\n        /// <summary>\n        /// Time of the current impulse. Incremented in update till\n        /// ImpulseLength is reached\n        /// </summary>\n        public float ImpulseTime { get; private set; }\n\n        /// <summary>\n        /// Length of a triggered impulse. Used in both Triggered and Curve Mode\n        /// </summary>\n        public float ImpulseLength { get; set; }\n\n        /// <summary>\n        /// Indicating if we are currently during an Impulse\n        /// (Triggered and Curve Mode)\n        /// </summary>\n        public bool Triggered { get; private set; }\n\n        /// <summary>\n        /// Variation of the force applied to each body affected\n        /// !! Must be used in inheriting classes properly !!\n        /// </summary>\n        public float Variation { get; set; }\n\n        /// <summary>\n        /// See DecayModes\n        /// </summary>\n        public DecayModes DecayMode { get; set; }\n\n        /// <summary>\n        /// Start of the distance based Decay. To set a non decaying area\n        /// </summary>\n        public float DecayStart { get; set; }\n\n        /// <summary>\n        /// Maximum distance a force should be applied\n        /// </summary>\n        public float DecayEnd { get; set; }\n\n        /// <summary>\n        /// Calculate the Decay for a given body. Meant to ease force\n        /// development and stick to the DRY principle and provide unified and\n        /// predictable decay math.\n        /// </summary>\n        /// <param name=\"body\">The body to calculate decay for</param>\n        /// <returns>\n        /// A multiplier to multiply the force with to add decay\n        /// support in inheriting classes\n        /// </returns>\n        protected float GetDecayMultiplier(Body body)\n        {\n            //TODO: Consider ForceType in distance calculation!\n            float distance = (body.Position - Position).Length();\n            switch (DecayMode)\n            {\n                case DecayModes.None:\n                {\n                    return 1.0f;\n                }\n                case DecayModes.Step:\n                {\n                    if (distance < DecayEnd)\n                        return 1.0f;\n                    else\n                        return 0.0f;\n                }\n                case DecayModes.Linear:\n                {\n                    if (distance < DecayStart)\n                        return 1.0f;\n                    if (distance > DecayEnd)\n                        return 0.0f;\n                    return (DecayEnd - DecayStart / distance - DecayStart);\n                }\n                case DecayModes.InverseSquare:\n                {\n                    if (distance < DecayStart)\n                        return 1.0f;\n                    else\n                        return 1.0f / ((distance - DecayStart) * (distance - DecayStart));\n                }\n                case DecayModes.Curve:\n                {\n                    if (distance < DecayStart)\n                        return 1.0f;\n                    else\n                        return DecayCurve.Evaluate(distance - DecayStart);\n                }\n                default:\n                    return 1.0f;\n            }\n        }\n\n        /// <summary>\n        /// Triggers the trigger modes (Trigger and Curve)\n        /// </summary>\n        public void Trigger()\n        {\n            Triggered = true;\n            ImpulseTime = 0;\n        }\n\n        /// <summary>\n        /// Inherited from Controller\n        /// Depending on the TimingMode perform timing logic and call ApplyForce()\n        /// </summary>\n        /// <param name=\"dt\"></param>\n        public override void Update(float dt)\n        {\n            switch (TimingMode)\n            {\n                case TimingModes.Switched:\n                {\n                    if (Enabled)\n                    {\n                        ApplyForce(dt, Strength);\n                    }\n                    break;\n                }\n                case TimingModes.Triggered:\n                {\n                    if (Enabled && Triggered)\n                    {\n                        if (ImpulseTime < ImpulseLength)\n                        {\n                            ApplyForce(dt, Strength);\n                            ImpulseTime += dt;\n                        }\n                        else\n                        {\n                            Triggered = false;\n                        }\n                    }\n                    break;\n                }\n                case TimingModes.Curve:\n                {\n                    if (Enabled && Triggered)\n                    {\n                        if (ImpulseTime < ImpulseLength)\n                        {\n                            ApplyForce(dt, Strength * StrengthCurve.Evaluate(ImpulseTime));\n                            ImpulseTime += dt;\n                        }\n                        else\n                        {\n                            Triggered = false;\n                        }\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Apply the force supplying strength which is modified in Update()\n        /// according to the TimingMode\n        /// </summary>\n        /// <param name=\"dt\"></param>\n        /// <param name=\"strength\">The strength</param>\n        public abstract void ApplyForce(float dt, float strength);\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/Controllers/Wind/SimpleWindForce.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Extensions.Controllers.Wind\n{\n    /// <summary>\n    /// Reference implementation for forces based on AbstractForceController\n    /// It supports all features provided by the base class and illustrates proper\n    /// usage as an easy to understand example.\n    /// As a side-effect it is a nice and easy to use wind force for your projects\n    /// </summary>\n    public class SimpleWindForce : AbstractForceController\n    {\n        /// <summary>\n        /// Direction of the windforce\n        /// </summary>\n        public Vector2 Direction { get; set; }\n\n        /// <summary>\n        /// The amount of Direction randomization. Allowed range is 0-1.\n        /// </summary>\n        public float Divergence { get; set; }\n\n        /// <summary>\n        /// Ignore the position and apply the force. If off only in the \"front\" (relative to position and direction)\n        /// will be affected\n        /// </summary>\n        public bool IgnorePosition { get; set; }\n\n        public override void ApplyForce(float dt, float strength)\n        {\n            foreach (Body body in World.BodyList)\n            {\n                //TODO: Consider Force Type\n                float decayMultiplier = GetDecayMultiplier(body);\n\n                if (decayMultiplier != 0)\n                {\n                    Vector2 forceVector;\n\n                    if (ForceType == ForceTypes.Point)\n                    {\n                        forceVector = body.Position - Position;\n                    }\n                    else\n                    {\n                        Direction.Normalize();\n\n                        forceVector = Direction;\n\n                        if (forceVector.Length() == 0)\n                            forceVector = new Vector2(0, 1);\n                    }\n\n                    //TODO: Consider Divergence:\n                    //forceVector = Vector2.Transform(forceVector, Matrix.CreateRotationZ((MathHelper.Pi - MathHelper.Pi/2) * (float)Randomize.NextDouble()));\n\n                    // Calculate random Variation\n                    if (Variation != 0)\n                    {\n                        float strengthVariation = (float)Randomize.NextDouble() * MathHelper.Clamp(Variation, 0, 1);\n                        forceVector.Normalize();\n                        body.ApplyForce(forceVector * strength * decayMultiplier * strengthVariation);\n                    }\n                    else\n                    {\n                        forceVector.Normalize();\n                        body.ApplyForce(forceVector * strength * decayMultiplier);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/DebugView/DebugViewBase.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n*/\n\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Extensions.DebugView\n{\n    /// Implement and register this class with a World to provide debug drawing of physics\n    /// entities in your game.\n    public abstract class DebugViewBase\n    {\n        protected DebugViewBase(World world)\n        {\n            World = world;\n        }\n\n        protected World World { get; }\n\n        /// <summary>\n        /// Gets or sets the debug view flags.\n        /// </summary>\n        /// <value>The flags.</value>\n        public DebugViewFlags Flags { get; set; }\n\n        /// <summary>\n        /// Append flags to the current flags.\n        /// </summary>\n        /// <param name=\"flags\">The flags.</param>\n        public void AppendFlags(DebugViewFlags flags)\n        {\n            Flags |= flags;\n        }\n\n        /// <summary>\n        /// Remove flags from the current flags.\n        /// </summary>\n        /// <param name=\"flags\">The flags.</param>\n        public void RemoveFlags(DebugViewFlags flags)\n        {\n            Flags &= ~flags;\n        }\n\n        /// <summary>\n        /// Draw a closed polygon provided in CCW order.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"count\">The vertex count.</param>\n        /// <param name=\"red\">The red value.</param>\n        /// <param name=\"blue\">The blue value.</param>\n        /// <param name=\"green\">The green value.</param>\n        public abstract void DrawPolygon(Vector2[] vertices, int count, float red, float blue, float green, bool closed = true);\n\n        /// <summary>\n        /// Draw a solid closed polygon provided in CCW order.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"count\">The vertex count.</param>\n        /// <param name=\"red\">The red value.</param>\n        /// <param name=\"blue\">The blue value.</param>\n        /// <param name=\"green\">The green value.</param>\n        public abstract void DrawSolidPolygon(Vector2[] vertices, int count, float red, float blue, float green);\n\n        /// <summary>\n        /// Draw a circle.\n        /// </summary>\n        /// <param name=\"center\">The center.</param>\n        /// <param name=\"radius\">The radius.</param>\n        /// <param name=\"red\">The red value.</param>\n        /// <param name=\"blue\">The blue value.</param>\n        /// <param name=\"green\">The green value.</param>\n        public abstract void DrawCircle(Vector2 center, float radius, float red, float blue, float green);\n\n        /// <summary>\n        /// Draw a solid circle.\n        /// </summary>\n        /// <param name=\"center\">The center.</param>\n        /// <param name=\"radius\">The radius.</param>\n        /// <param name=\"axis\">The axis.</param>\n        /// <param name=\"red\">The red value.</param>\n        /// <param name=\"blue\">The blue value.</param>\n        /// <param name=\"green\">The green value.</param>\n        public abstract void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, float red, float blue,\n                                             float green);\n\n        /// <summary>\n        /// Draw a line segment.\n        /// </summary>\n        /// <param name=\"start\">The start.</param>\n        /// <param name=\"end\">The end.</param>\n        /// <param name=\"red\">The red value.</param>\n        /// <param name=\"blue\">The blue value.</param>\n        /// <param name=\"green\">The green value.</param>\n        public abstract void DrawSegment(Vector2 start, Vector2 end, float red, float blue, float green);\n\n        /// <summary>\n        /// Draw a transform. Choose your own length scale.\n        /// </summary>\n        /// <param name=\"transform\">The transform.</param>\n        public abstract void DrawTransform(ref Transform transform);\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/DebugView/DebugViewFlags.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Extensions.DebugView\n{\n    [Flags]\n    public enum DebugViewFlags\n    {\n        /// <summary>\n        /// Draw shapes.\n        /// </summary>\n        Shape = (1 << 0),\n\n        /// <summary>\n        /// Draw joint connections.\n        /// </summary>\n        Joint = (1 << 1),\n\n        /// <summary>\n        /// Draw axis aligned bounding boxes.\n        /// </summary>\n        AABB = (1 << 2),\n\n        /// <summary>\n        /// Draw broad-phase pairs.\n        /// </summary>\n        //Pair = (1 << 3),\n        /// <summary>\n        /// Draw center of mass frame.\n        /// </summary>\n        CenterOfMass = (1 << 4),\n\n        /// <summary>\n        /// Draw useful debug data such as timings and number of bodies, joints, contacts and more.\n        /// </summary>\n        DebugPanel = (1 << 5),\n\n        /// <summary>\n        /// Draw contact points between colliding bodies.\n        /// </summary>\n        ContactPoints = (1 << 6),\n\n        /// <summary>\n        /// Draw contact normals. Need ContactPoints to be enabled first.\n        /// </summary>\n        ContactNormals = (1 << 7),\n\n        /// <summary>\n        /// Draws the vertices of polygons.\n        /// </summary>\n        PolygonPoints = (1 << 8),\n\n        /// <summary>\n        /// Draws the performance graph.\n        /// </summary>\n        PerformanceGraph = (1 << 9),\n\n        /// <summary>\n        /// Draws controllers.\n        /// </summary>\n        Controllers = (1 << 10)\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/Explosion/RayDataComparer.cs",
    "content": "using System.Collections.Generic;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.Explosion\n{\n    /// <summary>\n    /// This is a comparer used for\n    /// detecting angle difference between rays\n    /// </summary>\n    internal class RayDataComparer : IComparer<float>\n    {\n        #region IComparer<float> Members\n\n        int IComparer<float>.Compare(float a, float b)\n        {\n            float diff = (a - b);\n            if (diff > 0)\n                return 1;\n            if (diff < 0)\n                return -1;\n            return 0;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/Explosion/RealExplosion.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.Explosion\n{\n    // Original Code by Steven Lu - see http://www.box2d.org/forum/viewtopic.php?f=3&t=1688\n    // Ported by Nicols Hormazbal\n\n    /* Methodology:\n     * Force applied at a ray is inversely proportional to the square of distance from source\n     * AABB is used to query for shapes that may be affected\n     * For each RIGID BODY (not shape -- this is an optimization) that is matched, loop through its vertices to determine\n     *\t\tthe extreme points -- if there is structure that contains outlining polygon, use that as an additional optimization\n     * Evenly cast a number of rays against the shape - number roughly proportional to the arc coverage\n     *\t\t- Something like every 3 degrees should do the trick although this can be altered depending on the distance (if really close don't need such a high density of rays)\n     *\t\t- There should be a minimum number of rays (3-5?) applied to each body so that small bodies far away are still accurately modeled\n     *\t\t- Be sure to have the forces of each ray be proportional to the average arc length covered by each.\n     * For each ray that actually intersects with the shape (non intersections indicate something blocking the path of explosion):\n     *\t\t- Apply the appropriate force dotted with the negative of the collision normal at the collision point\n     *\t\t- Optionally apply linear interpolation between aforementioned Normal force and the original explosion force in the direction of ray to simulate \"surface friction\" of sorts\n     */\n\n    /// <summary>\n    /// Creates a realistic explosion based on raycasting. Objects in the open will be affected, but objects behind\n    /// static bodies will not. A body that is half in cover, half in the open will get half the force applied to the end in\n    /// the open.\n    /// </summary>\n    public sealed class RealExplosion : PhysicsLogic\n    {\n        /// <summary>\n        /// Two degrees: maximum angle from edges to first ray tested\n        /// </summary>\n        private const float MaxEdgeOffset = MathHelper.Pi / 90;\n\n        private List<ShapeData> _data = new List<ShapeData>();\n        private RayDataComparer _rdc;\n\n        /// <summary>\n        /// Ratio of arc length to angle from edges to first ray tested.\n        /// Defaults to 1/40.\n        /// </summary>\n        public float EdgeRatio = 1.0f / 40.0f;\n\n        /// <summary>\n        /// Ignore Explosion if it happens inside a shape.\n        /// Default value is false.\n        /// </summary>\n        public bool IgnoreWhenInsideShape = false;\n\n        /// <summary>\n        /// Max angle between rays (used when segment is large).\n        /// Defaults to 15 degrees\n        /// </summary>\n        public float MaxAngle = MathHelper.Pi / 15;\n\n        /// <summary>\n        /// Maximum number of shapes involved in the explosion.\n        /// Defaults to 100\n        /// </summary>\n        public int MaxShapes = 100;\n\n        /// <summary>\n        /// How many rays per shape/body/segment.\n        /// Defaults to 5\n        /// </summary>\n        public int MinRays = 5;\n\n        public RealExplosion(World world)\n            : base(world, PhysicsLogicType.Explosion)\n        {\n            _rdc = new RayDataComparer();\n            _data = new List<ShapeData>();\n        }\n\n        /// <summary>\n        /// Activate the explosion at the specified position.\n        /// </summary>\n        /// <param name=\"pos\">The position where the explosion happens </param>\n        /// <param name=\"radius\">The explosion radius </param>\n        /// <param name=\"maxForce\">\n        /// The explosion force at the explosion point (then is inversely proportional to the square of the\n        /// distance)\n        /// </param>\n        /// <returns>A list of bodies and the amount of force that was applied to them.</returns>\n        public Dictionary<Fixture, Vector2> Activate(Vector2 pos, float radius, float maxForce)\n        {\n            AABB aabb;\n            aabb.LowerBound = pos + new Vector2(-radius, -radius);\n            aabb.UpperBound = pos + new Vector2(radius, radius);\n            Fixture[] shapes = new Fixture[MaxShapes];\n\n            // More than 5 shapes in an explosion could be possible, but still strange.\n            Fixture[] containedShapes = new Fixture[5];\n            bool exit = false;\n\n            int shapeCount = 0;\n            int containedShapeCount = 0;\n\n            // Query the world for overlapping shapes.\n            World.QueryAABB(\n                fixture =>\n                {\n                    if (fixture.TestPoint(ref pos))\n                    {\n                        if (IgnoreWhenInsideShape)\n                        {\n                            exit = true;\n                            return false;\n                        }\n\n                        containedShapes[containedShapeCount++] = fixture;\n                    }\n                    else\n                    {\n                        shapes[shapeCount++] = fixture;\n                    }\n\n                    // Continue the query.\n                    return true;\n                }, ref aabb);\n\n            if (exit)\n                return new Dictionary<Fixture, Vector2>();\n\n            Dictionary<Fixture, Vector2> exploded = new Dictionary<Fixture, Vector2>(shapeCount + containedShapeCount);\n\n            // Per shape max/min angles for now.\n            float[] vals = new float[shapeCount * 2];\n            int valIndex = 0;\n            for (int i = 0; i < shapeCount; ++i)\n            {\n                PolygonShape ps;\n                CircleShape cs = shapes[i].Shape as CircleShape;\n                if (cs != null)\n                {\n                    // We create a \"diamond\" approximation of the circle\n                    Vertices v = new Vertices();\n                    Vector2 vec = Vector2.Zero + new Vector2(cs.Radius, 0);\n                    v.Add(vec);\n                    vec = Vector2.Zero + new Vector2(0, cs.Radius);\n                    v.Add(vec);\n                    vec = Vector2.Zero + new Vector2(-cs.Radius, cs.Radius);\n                    v.Add(vec);\n                    vec = Vector2.Zero + new Vector2(0, -cs.Radius);\n                    v.Add(vec);\n                    ps = new PolygonShape(v, 0);\n                }\n                else\n                    ps = shapes[i].Shape as PolygonShape;\n\n                if ((shapes[i].Body.BodyType == BodyType.Dynamic) && ps != null)\n                {\n                    Vector2 toCentroid = shapes[i].Body.GetWorldPoint(ps.MassData.Centroid) - pos;\n                    float angleToCentroid = (float)Math.Atan2(toCentroid.Y, toCentroid.X);\n                    float min = float.MaxValue;\n                    float max = float.MinValue;\n                    float minAbsolute = 0.0f;\n                    float maxAbsolute = 0.0f;\n\n                    for (int j = 0; j < ps.Vertices.Count; ++j)\n                    {\n                        Vector2 toVertex = (shapes[i].Body.GetWorldPoint(ps.Vertices[j]) - pos);\n                        float newAngle = (float)Math.Atan2(toVertex.Y, toVertex.X);\n                        float diff = (newAngle - angleToCentroid);\n\n                        diff = (diff - MathHelper.Pi) % (2 * MathHelper.Pi);\n\n                        // the minus pi is important. It means cutoff for going other direction is at 180 deg where it needs to be\n\n                        if (diff < 0.0f)\n                            diff += 2 * MathHelper.Pi; // correction for not handling negs\n\n                        diff -= MathHelper.Pi;\n\n                        if (Math.Abs(diff) > MathHelper.Pi)\n                            continue; // Something's wrong, point not in shape but exists angle diff > 180\n\n                        if (diff > max)\n                        {\n                            max = diff;\n                            maxAbsolute = newAngle;\n                        }\n                        if (diff < min)\n                        {\n                            min = diff;\n                            minAbsolute = newAngle;\n                        }\n                    }\n\n                    vals[valIndex] = minAbsolute;\n                    ++valIndex;\n                    vals[valIndex] = maxAbsolute;\n                    ++valIndex;\n                }\n            }\n\n            Array.Sort(vals, 0, valIndex, _rdc);\n            _data.Clear();\n            bool rayMissed = true;\n\n            for (int i = 0; i < valIndex; ++i)\n            {\n                Fixture fixture = null;\n                float midpt;\n\n                int iplus = (i == valIndex - 1 ? 0 : i + 1);\n                if (vals[i] == vals[iplus])\n                    continue;\n\n                if (i == valIndex - 1)\n                {\n                    // the single edgecase\n                    midpt = (vals[0] + MathHelper.Pi * 2 + vals[i]);\n                }\n                else\n                {\n                    midpt = (vals[i + 1] + vals[i]);\n                }\n\n                midpt = midpt / 2;\n\n                Vector2 p1 = pos;\n                Vector2 p2 = radius * new Vector2((float)Math.Cos(midpt), (float)Math.Sin(midpt)) + pos;\n\n                // RaycastOne\n                bool hitClosest = false;\n                World.RayCast((f, p, n, fr) =>\n                {\n                    Body body = f.Body;\n\n                    if (!IsActiveOn(body))\n                        return 0;\n\n                    hitClosest = true;\n                    fixture = f;\n                    return fr;\n                }, p1, p2);\n\n                //draws radius points\n                if ((hitClosest) && (fixture.Body.BodyType == BodyType.Dynamic))\n                {\n                    if ((_data.Any()) && (_data.Last().Body == fixture.Body) && (!rayMissed))\n                    {\n                        int laPos = _data.Count - 1;\n                        ShapeData la = _data[laPos];\n                        la.Max = vals[iplus];\n                        _data[laPos] = la;\n                    }\n                    else\n                    {\n                        // make new\n                        ShapeData d;\n                        d.Body = fixture.Body;\n                        d.Min = vals[i];\n                        d.Max = vals[iplus];\n                        _data.Add(d);\n                    }\n\n                    if ((_data.Count > 1)\n                        && (i == valIndex - 1)\n                        && (_data.Last().Body == _data.First().Body)\n                        && (_data.Last().Max == _data.First().Min))\n                    {\n                        ShapeData fi = _data[0];\n                        fi.Min = _data.Last().Min;\n                        _data.RemoveAt(_data.Count - 1);\n                        _data[0] = fi;\n                        while (_data.First().Min >= _data.First().Max)\n                        {\n                            fi.Min -= MathHelper.Pi * 2;\n                            _data[0] = fi;\n                        }\n                    }\n\n                    int lastPos = _data.Count - 1;\n                    ShapeData last = _data[lastPos];\n                    while ((_data.Count > 0)\n                           && (_data.Last().Min >= _data.Last().Max)) // just making sure min<max\n                    {\n                        last.Min = _data.Last().Min - 2 * MathHelper.Pi;\n                        _data[lastPos] = last;\n                    }\n                    rayMissed = false;\n                }\n                else\n                {\n                    rayMissed = true; // raycast did not find a shape\n                }\n            }\n\n            for (int i = 0; i < _data.Count; ++i)\n            {\n                if (!IsActiveOn(_data[i].Body))\n                    continue;\n\n                float arclen = _data[i].Max - _data[i].Min;\n\n                float first = MathHelper.Min(MaxEdgeOffset, EdgeRatio * arclen);\n                int insertedRays = (int)Math.Ceiling(((arclen - 2.0f * first) - (MinRays - 1) * MaxAngle) / MaxAngle);\n\n                if (insertedRays < 0)\n                    insertedRays = 0;\n\n                float offset = (arclen - first * 2.0f) / ((float)MinRays + insertedRays - 1);\n\n                //Note: This loop can go into infinite as it operates on floats.\n                //Added FloatEquals with a large epsilon.\n                for (float j = _data[i].Min + first;\n                     j < _data[i].Max || MathUtils.FloatEquals(j, _data[i].Max, 0.0001f);\n                     j += offset)\n                {\n                    Vector2 p1 = pos;\n                    Vector2 p2 = pos + radius * new Vector2((float)Math.Cos(j), (float)Math.Sin(j));\n                    Vector2 hitpoint = Vector2.Zero;\n                    float minlambda = float.MaxValue;\n\n                    List<Fixture> fl = _data[i].Body.FixtureList;\n                    for (int x = 0; x < fl.Count; x++)\n                    {\n                        Fixture f = fl[x];\n                        RayCastInput ri;\n                        ri.Point1 = p1;\n                        ri.Point2 = p2;\n                        ri.MaxFraction = 50f;\n\n                        RayCastOutput ro;\n                        if (f.RayCast(out ro, ref ri, 0))\n                        {\n                            if (minlambda > ro.Fraction)\n                            {\n                                minlambda = ro.Fraction;\n                                hitpoint = ro.Fraction * p2 + (1 - ro.Fraction) * p1;\n                            }\n                        }\n\n                        // the force that is to be applied for this particular ray.\n                        // offset is angular coverage. lambda*length of segment is distance.\n                        float impulse = (arclen / (MinRays + insertedRays)) * maxForce * 180.0f / MathHelper.Pi * (1.0f - Math.Min(1.0f, minlambda));\n\n                        // We Apply the impulse!!!\n                        Vector2 vectImp = Vector2.Dot(impulse * new Vector2((float)Math.Cos(j), (float)Math.Sin(j)), -ro.Normal) * new Vector2((float)Math.Cos(j), (float)Math.Sin(j));\n                        _data[i].Body.ApplyLinearImpulse(ref vectImp, ref hitpoint);\n\n                        // We gather the fixtures for returning them\n                        if (exploded.ContainsKey(f))\n                            exploded[f] += vectImp;\n                        else\n                            exploded.Add(f, vectImp);\n\n                        if (minlambda > 1.0f)\n                            hitpoint = p2;\n                    }\n                }\n            }\n\n            // We check contained shapes\n            for (int i = 0; i < containedShapeCount; ++i)\n            {\n                Fixture fix = containedShapes[i];\n\n                if (!IsActiveOn(fix.Body))\n                    continue;\n\n                float impulse = MinRays * maxForce * 180.0f / MathHelper.Pi;\n                Vector2 hitPoint;\n\n                CircleShape circShape = fix.Shape as CircleShape;\n                if (circShape != null)\n                {\n                    hitPoint = fix.Body.GetWorldPoint(circShape.Position);\n                }\n                else\n                {\n                    PolygonShape shape = fix.Shape as PolygonShape;\n                    hitPoint = fix.Body.GetWorldPoint(shape.MassData.Centroid);\n                }\n\n                Vector2 vectImp = impulse * (hitPoint - pos);\n\n                fix.Body.ApplyLinearImpulse(ref vectImp, ref hitPoint);\n\n                if (!exploded.ContainsKey(fix))\n                    exploded.Add(fix, vectImp);\n            }\n\n            return exploded;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/Explosion/SimpleExplosion.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.Explosion\n{\n    /// <summary>\n    /// Creates a simple explosion that ignores other bodies hiding behind static bodies.\n    /// </summary>\n    public sealed class SimpleExplosion : PhysicsLogic\n    {\n        public SimpleExplosion(World world)\n            : base(world, PhysicsLogicType.Explosion)\n        {\n            Power = 1; //linear\n        }\n\n        /// <summary>\n        /// This is the power used in the power function. A value of 1 means the force\n        /// applied to bodies in the explosion is linear. A value of 2 means it is exponential.\n        /// </summary>\n        public float Power { get; set; }\n\n        /// <summary>\n        /// Activate the explosion at the specified position.\n        /// </summary>\n        /// <param name=\"pos\">The position (center) of the explosion.</param>\n        /// <param name=\"radius\">The radius of the explosion.</param>\n        /// <param name=\"force\">The force applied</param>\n        /// <param name=\"maxForce\">A maximum amount of force. When force gets over this value, it will be equal to maxForce</param>\n        /// <returns>A list of bodies and the amount of force that was applied to them.</returns>\n        public Dictionary<Body, Vector2> Activate(Vector2 pos, float radius, float force, float maxForce = float.MaxValue)\n        {\n            HashSet<Body> affectedBodies = new HashSet<Body>();\n\n            AABB aabb;\n            aabb.LowerBound = pos - new Vector2(radius);\n            aabb.UpperBound = pos + new Vector2(radius);\n\n            // Query the world for bodies within the radius.\n            World.QueryAABB(fixture =>\n            {\n                if (Vector2.Distance(fixture.Body.Position, pos) <= radius)\n                {\n                    if (!affectedBodies.Contains(fixture.Body))\n                        affectedBodies.Add(fixture.Body);\n                }\n\n                return true;\n            }, ref aabb);\n\n            return ApplyImpulse(pos, radius, force, maxForce, affectedBodies);\n        }\n\n        private Dictionary<Body, Vector2> ApplyImpulse(Vector2 pos, float radius, float force, float maxForce, HashSet<Body> overlappingBodies)\n        {\n            Dictionary<Body, Vector2> forces = new Dictionary<Body, Vector2>(overlappingBodies.Count);\n\n            foreach (Body overlappingBody in overlappingBodies)\n            {\n                if (IsActiveOn(overlappingBody))\n                {\n                    float distance = Vector2.Distance(pos, overlappingBody.Position);\n                    float forcePercent = GetPercent(distance, radius);\n\n                    Vector2 forceVector = pos - overlappingBody.Position;\n                    forceVector *= 1f / (float)Math.Sqrt(forceVector.X * forceVector.X + forceVector.Y * forceVector.Y);\n                    forceVector *= MathHelper.Min(force * forcePercent, maxForce);\n                    forceVector *= -1;\n\n                    overlappingBody.ApplyLinearImpulse(forceVector);\n                    forces.Add(overlappingBody, forceVector);\n                }\n            }\n\n            return forces;\n        }\n\n        private float GetPercent(float distance, float radius)\n        {\n            //(1-(distance/radius))^power-1\n            float percent = (float)Math.Pow(1 - ((distance - radius) / radius), Power) - 1;\n\n            if (float.IsNaN(percent))\n                return 0f;\n\n            return MathHelper.Clamp(percent, 0f, 1f);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/PhysicsLogicBase/FilterData.cs",
    "content": "﻿using VelcroPhysics.Collision.Filtering;\nusing VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase\n{\n    /// <summary>\n    /// Contains filter data that can determine whether an object should be processed or not.\n    /// </summary>\n    public abstract class FilterData\n    {\n        /// <summary>\n        /// Disable the logic on specific categories.\n        /// Category.None by default.\n        /// </summary>\n        public Category DisabledOnCategories = Category.None;\n\n        /// <summary>\n        /// Disable the logic on specific groups\n        /// </summary>\n        public int DisabledOnGroup;\n\n        /// <summary>\n        /// Enable the logic on specific categories\n        /// Category.All by default.\n        /// </summary>\n        public Category EnabledOnCategories = Category.All;\n\n        /// <summary>\n        /// Enable the logic on specific groups.\n        /// </summary>\n        public int EnabledOnGroup;\n\n        /// <summary>\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <returns></returns>\n        public virtual bool IsActiveOn(Body body)\n        {\n            if (body == null || !body.Enabled || body.IsStatic)\n                return false;\n\n            if (body.FixtureList == null)\n                return false;\n\n            foreach (Fixture fixture in body.FixtureList)\n            {\n                //Disable\n                if ((fixture.CollisionGroup == DisabledOnGroup) && fixture.CollisionGroup != 0 && DisabledOnGroup != 0)\n                    return false;\n\n                if ((fixture.CollisionCategories & DisabledOnCategories) != Category.None)\n                    return false;\n\n                if (EnabledOnGroup != 0 || EnabledOnCategories != Category.All)\n                {\n                    //Enable\n                    if ((fixture.CollisionGroup == EnabledOnGroup) && fixture.CollisionGroup != 0 && EnabledOnGroup != 0)\n                        return true;\n\n                    if ((fixture.CollisionCategories & EnabledOnCategories) != Category.None &&\n                        EnabledOnCategories != Category.All)\n                        return true;\n                }\n                else\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Adds the category.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        public void AddDisabledCategory(Category category)\n        {\n            DisabledOnCategories |= category;\n        }\n\n        /// <summary>\n        /// Removes the category.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        public void RemoveDisabledCategory(Category category)\n        {\n            DisabledOnCategories &= ~category;\n        }\n\n        /// <summary>\n        /// Determines whether this body ignores the the specified controller.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        /// <returns>\n        /// <c>true</c> if the object has the specified category; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsInDisabledCategory(Category category)\n        {\n            return (DisabledOnCategories & category) == category;\n        }\n\n        /// <summary>\n        /// Adds the category.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        public void AddEnabledCategory(Category category)\n        {\n            EnabledOnCategories |= category;\n        }\n\n        /// <summary>\n        /// Removes the category.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        public void RemoveEnabledCategory(Category category)\n        {\n            EnabledOnCategories &= ~category;\n        }\n\n        /// <summary>\n        /// Determines whether this body ignores the the specified controller.\n        /// </summary>\n        /// <param name=\"category\">The category.</param>\n        /// <returns>\n        /// <c>true</c> if the object has the specified category; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsInEnabledInCategory(Category category)\n        {\n            return (EnabledOnCategories & category) == category;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/PhysicsLogicBase/PhysicsLogic.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase\n{\n    public abstract class PhysicsLogic : FilterData\n    {\n        private PhysicsLogicType _type;\n        public World World;\n\n        public PhysicsLogic(World world, PhysicsLogicType type)\n        {\n            _type = type;\n            World = world;\n        }\n\n        public override bool IsActiveOn(Body body)\n        {\n            if (body.PhysicsLogicFilter.IsPhysicsLogicIgnored(_type))\n                return false;\n\n            return base.IsActiveOn(body);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/PhysicsLogicBase/PhysicsLogicFilter.cs",
    "content": "namespace VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase\n{\n    public struct PhysicsLogicFilter\n    {\n        public PhysicsLogicType ControllerIgnores;\n\n        /// <summary>\n        /// Ignores the controller. The controller has no effect on this body.\n        /// </summary>\n        /// <param name=\"type\">The logic type.</param>\n        public void IgnorePhysicsLogic(PhysicsLogicType type)\n        {\n            ControllerIgnores |= type;\n        }\n\n        /// <summary>\n        /// Restore the controller. The controller affects this body.\n        /// </summary>\n        /// <param name=\"type\">The logic type.</param>\n        public void RestorePhysicsLogic(PhysicsLogicType type)\n        {\n            ControllerIgnores &= ~type;\n        }\n\n        /// <summary>\n        /// Determines whether this body ignores the specified controller.\n        /// </summary>\n        /// <param name=\"type\">The logic type.</param>\n        /// <returns>\n        /// <c>true</c> if the body has the specified flag; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsPhysicsLogicIgnored(PhysicsLogicType type)\n        {\n            return (ControllerIgnores & type) == type;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/PhysicsLogicBase/PhysicsLogicType.cs",
    "content": "using System;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase\n{\n    [Flags]\n    public enum PhysicsLogicType\n    {\n        Explosion = 1 << 0\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Extensions/PhysicsLogics/PhysicsLogicBase/ShapeData.cs",
    "content": "using VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Extensions.PhysicsLogics.PhysicsLogicBase\n{\n    public struct ShapeData\n    {\n        public Body Body;\n        public float Max;\n        public float Min; // absolute angles\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Factories/BodyFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Templates;\nusing VelcroPhysics.Tools.Triangulation.TriangulationBase;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Factories\n{\n    public static class BodyFactory\n    {\n        public static Body CreateBody(World world, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            BodyTemplate template = new BodyTemplate();\n            template.Position = position;\n            template.Angle = rotation;\n            template.Type = bodyType;\n            template.UserData = userData;\n\n            return world.CreateBody(template);\n        }\n\n        public static Body CreateEdge(World world, Vector2 start, Vector2 end, object userData = null)\n        {\n            Body body = CreateBody(world);\n            body.UserData = userData;\n\n            FixtureFactory.AttachEdge(start, end, body);\n            return body;\n        }\n\n        public static Body CreateChainShape(World world, Vertices vertices, Vector2 position = new Vector2(), object userData = null)\n        {\n            Body body = CreateBody(world, position);\n            body.UserData = userData;\n\n            FixtureFactory.AttachChainShape(vertices, body);\n            return body;\n        }\n\n        public static Body CreateLoopShape(World world, Vertices vertices, Vector2 position = new Vector2(), object userData = null)\n        {\n            Body body = CreateBody(world, position);\n            body.UserData = userData;\n\n            FixtureFactory.AttachLoopShape(vertices, body);\n            return body;\n        }\n\n        public static Body CreateRectangle(World world, float width, float height, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            if (width <= 0)\n                throw new ArgumentOutOfRangeException(nameof(width), \"Width must be more than 0 meters\");\n\n            if (height <= 0)\n                throw new ArgumentOutOfRangeException(nameof(height), \"Height must be more than 0 meters\");\n\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n\n            Vertices rectangleVertices = PolygonUtils.CreateRectangle(width / 2, height / 2);\n            FixtureFactory.AttachPolygon(rectangleVertices, density, body);\n\n            return body;\n        }\n\n        public static Body CreateCircle(World world, float radius, float density, Vector2 position = new Vector2(), BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Body body = CreateBody(world, position, 0, bodyType, userData);\n            FixtureFactory.AttachCircle(radius, density, body);\n            return body;\n        }\n\n        public static Body CreateEllipse(World world, float xRadius, float yRadius, int edges, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n            FixtureFactory.AttachEllipse(xRadius, yRadius, edges, density, body);\n            return body;\n        }\n\n        public static Body CreatePolygon(World world, Vertices vertices, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n            FixtureFactory.AttachPolygon(vertices, density, body);\n            return body;\n        }\n\n        public static Body CreateCompoundPolygon(World world, List<Vertices> list, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            //We create a single body\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n            FixtureFactory.AttachCompoundPolygon(list, density, body);\n            return body;\n        }\n\n        public static Body CreateGear(World world, float radius, int numberOfTeeth, float tipPercentage, float toothHeight, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Vertices gearPolygon = PolygonUtils.CreateGear(radius, numberOfTeeth, tipPercentage, toothHeight);\n\n            //Gears can in some cases be convex\n            if (!gearPolygon.IsConvex())\n            {\n                //Decompose the gear:\n                List<Vertices> list = Triangulate.ConvexPartition(gearPolygon, TriangulationAlgorithm.Earclip);\n\n                return CreateCompoundPolygon(world, list, density, position, rotation, bodyType, userData);\n            }\n\n            return CreatePolygon(world, gearPolygon, density, position, rotation, bodyType, userData);\n        }\n\n        public static Body CreateCapsule(World world, float height, float topRadius, int topEdges, float bottomRadius, int bottomEdges, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Vertices verts = PolygonUtils.CreateCapsule(height, topRadius, topEdges, bottomRadius, bottomEdges);\n\n            //There are too many vertices in the capsule. We decompose it.\n            if (verts.Count >= Settings.MaxPolygonVertices)\n            {\n                List<Vertices> vertList = Triangulate.ConvexPartition(verts, TriangulationAlgorithm.Earclip);\n                return CreateCompoundPolygon(world, vertList, density, position, rotation, bodyType, userData);\n            }\n\n            return CreatePolygon(world, verts, density, position, rotation, bodyType, userData);\n        }\n\n        public static Body CreateCapsule(World world, float height, float endRadius, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            //Create the middle rectangle\n            Vertices rectangle = PolygonUtils.CreateRectangle(endRadius, height / 2);\n\n            List<Vertices> list = new List<Vertices>();\n            list.Add(rectangle);\n\n            Body body = CreateCompoundPolygon(world, list, density, position, rotation, bodyType, userData);\n            FixtureFactory.AttachCircle(endRadius, density, body, new Vector2(0, height / 2));\n            FixtureFactory.AttachCircle(endRadius, density, body, new Vector2(0, -(height / 2)));\n\n            //Create the two circles\n            //CircleShape topCircle = new CircleShape(endRadius, density);\n            //topCircle.Position = new Vector2(0, height / 2);\n            //body.CreateFixture(topCircle);\n\n            //CircleShape bottomCircle = new CircleShape(endRadius, density);\n            //bottomCircle.Position = new Vector2(0, -(height / 2));\n            //body.CreateFixture(bottomCircle);\n            return body;\n        }\n\n        public static Body CreateRoundedRectangle(World world, float width, float height, float xRadius, float yRadius, int segments, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Vertices verts = PolygonUtils.CreateRoundedRectangle(width, height, xRadius, yRadius, segments);\n\n            //There are too many vertices in the capsule. We decompose it.\n            if (verts.Count >= Settings.MaxPolygonVertices)\n            {\n                List<Vertices> vertList = Triangulate.ConvexPartition(verts, TriangulationAlgorithm.Earclip);\n                return CreateCompoundPolygon(world, vertList, density, position, rotation, bodyType, userData);\n            }\n\n            return CreatePolygon(world, verts, density, position, rotation, bodyType, userData);\n        }\n\n        public static Body CreateLineArc(World world, float radians, int sides, float radius, bool closed = false, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n            FixtureFactory.AttachLineArc(radians, sides, radius, closed, body);\n            return body;\n        }\n\n        public static Body CreateSolidArc(World world, float density, float radians, int sides, float radius, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static, object userData = null)\n        {\n            Body body = CreateBody(world, position, rotation, bodyType, userData);\n            FixtureFactory.AttachSolidArc(density, radians, sides, radius, body);\n\n            return body;\n        }\n\n        public static BreakableBody CreateBreakableBody(World world, Vertices vertices, float density, Vector2 position = new Vector2(), float rotation = 0)\n        {\n            //TODO: Implement a Voronoi diagram algorithm to split up the vertices\n            List<Vertices> triangles = Triangulate.ConvexPartition(vertices, TriangulationAlgorithm.Earclip);\n\n            BreakableBody breakableBody = new BreakableBody(world, triangles, density, position, rotation);\n            breakableBody.MainBody.Position = position;\n            world.AddBreakableBody(breakableBody);\n            return breakableBody;\n        }\n\n        public static BreakableBody CreateBreakableBody(World world, IEnumerable<Shape> shapes, Vector2 position = new Vector2(), float rotation = 0)\n        {\n            BreakableBody breakableBody = new BreakableBody(world, shapes, position, rotation);\n            breakableBody.MainBody.Position = position;\n            world.AddBreakableBody(breakableBody);\n            return breakableBody;\n        }\n\n        public static Body CreateFromTemplate(World world, BodyTemplate bodyTemplate)\n        {\n            return world.CreateBody(bodyTemplate);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Factories/FixtureFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Templates;\nusing VelcroPhysics.Tools.Triangulation.TriangulationBase;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Factories\n{\n    /// <summary>\n    /// An easy to use factory for creating bodies\n    /// </summary>\n    public static class FixtureFactory\n    {\n        public static Fixture AttachEdge(Vector2 start, Vector2 end, Body body, object userData = null)\n        {\n            EdgeShape edgeShape = new EdgeShape(start, end);\n            return body.CreateFixture(edgeShape, userData);\n        }\n\n        public static Fixture AttachChainShape(Vertices vertices, Body body, object userData = null)\n        {\n            ChainShape shape = new ChainShape(vertices);\n            return body.CreateFixture(shape, userData);\n        }\n\n        public static Fixture AttachLoopShape(Vertices vertices, Body body, object userData = null)\n        {\n            ChainShape shape = new ChainShape(vertices, true);\n            return body.CreateFixture(shape, userData);\n        }\n\n        public static Fixture AttachRectangle(float width, float height, float density, Vector2 offset, Body body, object userData = null)\n        {\n            Vertices rectangleVertices = PolygonUtils.CreateRectangle(width / 2, height / 2);\n            rectangleVertices.Translate(ref offset);\n            PolygonShape rectangleShape = new PolygonShape(rectangleVertices, density);\n            return body.CreateFixture(rectangleShape, userData);\n        }\n\n        public static Fixture AttachCircle(float radius, float density, Body body, object userData = null)\n        {\n            if (radius <= 0)\n                throw new ArgumentOutOfRangeException(nameof(radius), \"Radius must be more than 0 meters\");\n\n            CircleShape circleShape = new CircleShape(radius, density);\n            return body.CreateFixture(circleShape, userData);\n        }\n\n        public static Fixture AttachCircle(float radius, float density, Body body, Vector2 offset, object userData = null)\n        {\n            if (radius <= 0)\n                throw new ArgumentOutOfRangeException(nameof(radius), \"Radius must be more than 0 meters\");\n\n            CircleShape circleShape = new CircleShape(radius, density);\n            circleShape.Position = offset;\n            return body.CreateFixture(circleShape, userData);\n        }\n\n        public static Fixture AttachPolygon(Vertices vertices, float density, Body body, object userData = null)\n        {\n            if (vertices.Count <= 1)\n                throw new ArgumentOutOfRangeException(nameof(vertices), \"Too few points to be a polygon\");\n\n            PolygonShape polygon = new PolygonShape(vertices, density);\n            return body.CreateFixture(polygon, userData);\n        }\n\n        public static Fixture AttachEllipse(float xRadius, float yRadius, int edges, float density, Body body, object userData = null)\n        {\n            if (xRadius <= 0)\n                throw new ArgumentOutOfRangeException(nameof(xRadius), \"X-radius must be more than 0\");\n\n            if (yRadius <= 0)\n                throw new ArgumentOutOfRangeException(nameof(yRadius), \"Y-radius must be more than 0\");\n\n            Vertices ellipseVertices = PolygonUtils.CreateEllipse(xRadius, yRadius, edges);\n            PolygonShape polygonShape = new PolygonShape(ellipseVertices, density);\n            return body.CreateFixture(polygonShape, userData);\n        }\n\n        public static List<Fixture> AttachCompoundPolygon(List<Vertices> list, float density, Body body, object userData = null)\n        {\n            List<Fixture> res = new List<Fixture>(list.Count);\n\n            //Then we create several fixtures using the body\n            foreach (Vertices vertices in list)\n            {\n                if (vertices.Count == 2)\n                {\n                    EdgeShape shape = new EdgeShape(vertices[0], vertices[1]);\n                    res.Add(body.CreateFixture(shape, userData));\n                }\n                else\n                {\n                    PolygonShape shape = new PolygonShape(vertices, density);\n                    res.Add(body.CreateFixture(shape, userData));\n                }\n            }\n\n            return res;\n        }\n\n        public static Fixture AttachLineArc(float radians, int sides, float radius, bool closed, Body body)\n        {\n            Vertices arc = PolygonUtils.CreateArc(radians, sides, radius);\n            arc.Rotate((MathHelper.Pi - radians) / 2);\n            return closed ? AttachLoopShape(arc, body) : AttachChainShape(arc, body);\n        }\n\n        public static List<Fixture> AttachSolidArc(float density, float radians, int sides, float radius, Body body)\n        {\n            Vertices arc = PolygonUtils.CreateArc(radians, sides, radius);\n            arc.Rotate((MathHelper.Pi - radians) / 2);\n\n            //Close the arc\n            arc.Add(arc[0]);\n\n            List<Vertices> triangles = Triangulate.ConvexPartition(arc, TriangulationAlgorithm.Earclip);\n\n            return AttachCompoundPolygon(triangles, density, body);\n        }\n\n        public static Fixture CreateFromTemplate(Body body, FixtureTemplate f1)\n        {\n            return body.CreateFixture(f1);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Factories/JointFactory.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Factories\n{\n    /// <summary>\n    /// An easy to use factory for using joints.\n    /// </summary>\n    public static class JointFactory\n    {\n        #region Motor Joint\n\n        public static MotorJoint CreateMotorJoint(World world, Body bodyA, Body bodyB, bool useWorldCoordinates = false)\n        {\n            MotorJoint joint = new MotorJoint(bodyA, bodyB, useWorldCoordinates);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        #endregion\n\n        #region Rope Joint\n\n        public static RopeJoint CreateRopeJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n        {\n            RopeJoint ropeJoint = new RopeJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);\n            world.AddJoint(ropeJoint);\n            return ropeJoint;\n        }\n\n        #endregion\n\n        #region Weld Joint\n\n        public static WeldJoint CreateWeldJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n        {\n            WeldJoint weldJoint = new WeldJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);\n            world.AddJoint(weldJoint);\n            return weldJoint;\n        }\n\n        #endregion\n\n        #region Prismatic Joint\n\n        public static PrismaticJoint CreatePrismaticJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)\n        {\n            PrismaticJoint joint = new PrismaticJoint(bodyA, bodyB, anchor, axis, useWorldCoordinates);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        #endregion\n\n        #region Angle Joint\n\n        public static AngleJoint CreateAngleJoint(World world, Body bodyA, Body bodyB)\n        {\n            AngleJoint angleJoint = new AngleJoint(bodyA, bodyB);\n            world.AddJoint(angleJoint);\n            return angleJoint;\n        }\n\n        #endregion\n\n        #region Gear Joint\n\n        public static GearJoint CreateGearJoint(World world, Body bodyA, Body bodyB, Joint jointA, Joint jointB, float ratio)\n        {\n            GearJoint gearJoint = new GearJoint(bodyA, bodyB, jointA, jointB, ratio);\n            world.AddJoint(gearJoint);\n            return gearJoint;\n        }\n\n        #endregion\n\n        #region Pulley Joint\n\n        public static PulleyJoint CreatePulleyJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, Vector2 worldAnchorA, Vector2 worldAnchorB, float ratio, bool useWorldCoordinates = false)\n        {\n            PulleyJoint pulleyJoint = new PulleyJoint(bodyA, bodyB, anchorA, anchorB, worldAnchorA, worldAnchorB, ratio, useWorldCoordinates);\n            world.AddJoint(pulleyJoint);\n            return pulleyJoint;\n        }\n\n        #endregion\n\n        #region MouseJoint\n\n        public static FixedMouseJoint CreateFixedMouseJoint(World world, Body body, Vector2 worldAnchor)\n        {\n            FixedMouseJoint joint = new FixedMouseJoint(body, worldAnchor);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        #endregion\n\n        #region Revolute Joint\n\n        public static RevoluteJoint CreateRevoluteJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n        {\n            RevoluteJoint joint = new RevoluteJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        public static RevoluteJoint CreateRevoluteJoint(World world, Body bodyA, Body bodyB, Vector2 anchor)\n        {\n            Vector2 localanchorA = bodyA.GetLocalPoint(bodyB.GetWorldPoint(anchor));\n            RevoluteJoint joint = new RevoluteJoint(bodyA, bodyB, localanchorA, anchor);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        #endregion\n\n        #region Wheel Joint\n\n        public static WheelJoint CreateWheelJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)\n        {\n            WheelJoint joint = new WheelJoint(bodyA, bodyB, anchor, axis, useWorldCoordinates);\n            world.AddJoint(joint);\n            return joint;\n        }\n\n        public static WheelJoint CreateWheelJoint(World world, Body bodyA, Body bodyB, Vector2 axis)\n        {\n            return CreateWheelJoint(world, bodyA, bodyB, Vector2.Zero, axis);\n        }\n\n        #endregion\n\n        #region Distance Joint\n\n        public static DistanceJoint CreateDistanceJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)\n        {\n            DistanceJoint distanceJoint = new DistanceJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);\n            world.AddJoint(distanceJoint);\n            return distanceJoint;\n        }\n\n        public static DistanceJoint CreateDistanceJoint(World world, Body bodyA, Body bodyB)\n        {\n            return CreateDistanceJoint(world, bodyA, bodyB, Vector2.Zero, Vector2.Zero);\n        }\n\n        #endregion\n\n        #region Friction Joint\n\n        public static FrictionJoint CreateFrictionJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, bool useWorldCoordinates = false)\n        {\n            FrictionJoint frictionJoint = new FrictionJoint(bodyA, bodyB, anchor, useWorldCoordinates);\n            world.AddJoint(frictionJoint);\n            return frictionJoint;\n        }\n\n        public static FrictionJoint CreateFrictionJoint(World world, Body bodyA, Body bodyB)\n        {\n            return CreateFrictionJoint(world, bodyA, bodyB, Vector2.Zero);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Primitives/Curve.cs",
    "content": "﻿#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright © 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nAuthors:\nOlivier Dufour (Duff)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\n\nnamespace Microsoft.Xna.Framework\n{\n    public class Curve\n    {\n        #region Private Fields\n\n        private CurveKeyCollection keys;\n        private CurveLoopType postLoop;\n        private CurveLoopType preLoop;\n\n        #endregion Private Fields\n\n        #region Public Properties\n\n        public bool IsConstant\n        {\n            get { return keys.Count <= 1; }\n        }\n\n        public CurveKeyCollection Keys\n        {\n            get { return keys; }\n        }\n\n        public CurveLoopType PostLoop\n        {\n            get { return postLoop; }\n            set { postLoop = value; }\n        }\n\n        public CurveLoopType PreLoop\n        {\n            get { return preLoop; }\n            set { preLoop = value; }\n        }\n\n        #endregion Public Properties\n\n        #region Public Constructors\n\n        public Curve()\n        {\n            keys = new CurveKeyCollection();\n        }\n\n        #endregion Public Constructors\n\n        #region Public Methods\n\n        public void ComputeTangent(int keyIndex, CurveTangent tangentInType, CurveTangent tangentOutType)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void ComputeTangent(int keyIndex, CurveTangent tangentType)\n        {\n            ComputeTangent(keyIndex, tangentType, tangentType);\n        }\n\n        public void ComputeTangents(CurveTangent tangentInType, CurveTangent tangentOutType)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void ComputeTangents(CurveTangent tangentType)\n        {\n            ComputeTangents(tangentType, tangentType);\n        }\n\n        public Curve Clone()\n        {\n            Curve curve = new Curve();\n\n            curve.keys = keys.Clone();\n            curve.preLoop = preLoop;\n            curve.postLoop = postLoop;\n\n            return curve;\n        }\n\n        public float Evaluate(float position)\n        {\n            CurveKey first = keys[0];\n            CurveKey last = keys[keys.Count - 1];\n\n            if (position < first.Position)\n            {\n                switch (PreLoop)\n                {\n                    case CurveLoopType.Constant:\n                        //constant\n                        return first.Value;\n\n                    case CurveLoopType.Linear:\n                        // linear y = a*x +b with a tangeant of last point\n                        return first.Value - first.TangentIn * (first.Position - position);\n\n                    case CurveLoopType.Cycle:\n                        //start -> end / start -> end\n                        int cycle = GetNumberOfCycle(position);\n                        float virtualPos = position - (cycle * (last.Position - first.Position));\n                        return GetCurvePosition(virtualPos);\n\n                    case CurveLoopType.CycleOffset:\n                        //make the curve continue (with no step) so must up the curve each cycle of delta(value)\n                        cycle = GetNumberOfCycle(position);\n                        virtualPos = position - (cycle * (last.Position - first.Position));\n                        return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value));\n\n                    case CurveLoopType.Oscillate:\n                        //go back on curve from end and target start \n                        // start-> end / end -> start\n                        cycle = GetNumberOfCycle(position);\n                        if (0 == cycle % 2f) //if pair\n                            virtualPos = position - (cycle * (last.Position - first.Position));\n                        else\n                            virtualPos = last.Position - position + first.Position +\n                                         (cycle * (last.Position - first.Position));\n                        return GetCurvePosition(virtualPos);\n                }\n            }\n            else if (position > last.Position)\n            {\n                int cycle;\n                switch (PostLoop)\n                {\n                    case CurveLoopType.Constant:\n                        //constant\n                        return last.Value;\n\n                    case CurveLoopType.Linear:\n                        // linear y = a*x +b with a tangeant of last point\n                        return last.Value + first.TangentOut * (position - last.Position);\n\n                    case CurveLoopType.Cycle:\n                        //start -> end / start -> end\n                        cycle = GetNumberOfCycle(position);\n                        float virtualPos = position - (cycle * (last.Position - first.Position));\n                        return GetCurvePosition(virtualPos);\n\n                    case CurveLoopType.CycleOffset:\n                        //make the curve continue (with no step) so must up the curve each cycle of delta(value)\n                        cycle = GetNumberOfCycle(position);\n                        virtualPos = position - (cycle * (last.Position - first.Position));\n                        return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value));\n\n                    case CurveLoopType.Oscillate:\n                        //go back on curve from end and target start \n                        // start-> end / end -> start\n                        cycle = GetNumberOfCycle(position);\n                        virtualPos = position - (cycle * (last.Position - first.Position));\n                        if (0 == cycle % 2f) //if pair\n                            virtualPos = position - (cycle * (last.Position - first.Position));\n                        else\n                            virtualPos = last.Position - position + first.Position +\n                                         (cycle * (last.Position - first.Position));\n                        return GetCurvePosition(virtualPos);\n                }\n            }\n\n            //in curve\n            return GetCurvePosition(position);\n        }\n\n        #endregion Public Methods\n\n        #region Private Methods\n\n        private int GetNumberOfCycle(float position)\n        {\n            float cycle = (position - keys[0].Position) / (keys[keys.Count - 1].Position - keys[0].Position);\n            if (cycle < 0f)\n                cycle--;\n            return (int)cycle;\n        }\n\n        private float GetCurvePosition(float position)\n        {\n            //only for position in curve\n            CurveKey prev = keys[0];\n            CurveKey next;\n            for (int i = 1; i < keys.Count; i++)\n            {\n                next = Keys[i];\n                if (next.Position >= position)\n                {\n                    if (prev.Continuity == CurveContinuity.Step)\n                    {\n                        if (position >= 1f)\n                        {\n                            return next.Value;\n                        }\n                        return prev.Value;\n                    }\n                    float t = (position - prev.Position) / (next.Position - prev.Position); //to have t in [0,1]\n                    float ts = t * t;\n                    float tss = ts * t;\n                    //After a lot of search on internet I have found all about spline function\n                    // and bezier (phi'sss ancien) but finaly use hermite curve \n                    //http://en.wikipedia.org/wiki/Cubic_Hermite_spline\n                    //P(t) = (2*t^3 - 3t^2 + 1)*P0 + (t^3 - 2t^2 + t)m0 + (-2t^3 + 3t^2)P1 + (t^3-t^2)m1\n                    //with P0.value = prev.value , m0 = prev.tangentOut, P1= next.value, m1 = next.TangentIn\n                    return (2 * tss - 3 * ts + 1f) * prev.Value + (tss - 2 * ts + t) * prev.TangentOut + (3 * ts - 2 * tss) * next.Value +\n                           (tss - ts) * next.TangentIn;\n                }\n                prev = next;\n            }\n            return 0f;\n        }\n\n        #endregion\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/CurveContinuity.cs",
    "content": "namespace Microsoft.Xna.Framework\n{\n    public enum CurveContinuity\n    {\n        Smooth,\n        Step\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Primitives/CurveKey.cs",
    "content": "﻿#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright © 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nAuthors:\nOlivier Dufour (Duff)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\n\nnamespace Microsoft.Xna.Framework\n{\n    public class CurveKey : IEquatable<CurveKey>, IComparable<CurveKey>\n    {\n        #region Private Fields\n\n        private CurveContinuity continuity;\n        private float position;\n        private float tangentIn;\n        private float tangentOut;\n        private float value;\n\n        #endregion Private Fields\n\n        #region Properties\n\n        public CurveContinuity Continuity\n        {\n            get { return continuity; }\n            set { continuity = value; }\n        }\n\n        public float Position\n        {\n            get { return position; }\n        }\n\n        public float TangentIn\n        {\n            get { return tangentIn; }\n            set { tangentIn = value; }\n        }\n\n        public float TangentOut\n        {\n            get { return tangentOut; }\n            set { tangentOut = value; }\n        }\n\n        public float Value\n        {\n            get { return value; }\n            set { this.value = value; }\n        }\n\n        #endregion\n\n        #region Constructors\n\n        public CurveKey(float position, float value)\n            : this(position, value, 0, 0, CurveContinuity.Smooth)\n        {\n        }\n\n        public CurveKey(float position, float value, float tangentIn, float tangentOut)\n            : this(position, value, tangentIn, tangentOut, CurveContinuity.Smooth)\n        {\n        }\n\n        public CurveKey(float position, float value, float tangentIn, float tangentOut, CurveContinuity continuity)\n        {\n            this.position = position;\n            this.value = value;\n            this.tangentIn = tangentIn;\n            this.tangentOut = tangentOut;\n            this.continuity = continuity;\n        }\n\n        #endregion Constructors\n\n        #region Public Methods\n\n        #region IComparable<CurveKey> Members\n\n        public int CompareTo(CurveKey other)\n        {\n            return position.CompareTo(other.position);\n        }\n\n        #endregion\n\n        #region IEquatable<CurveKey> Members\n\n        public bool Equals(CurveKey other)\n        {\n            return (this == other);\n        }\n\n        #endregion\n\n        public static bool operator !=(CurveKey a, CurveKey b)\n        {\n            return !(a == b);\n        }\n\n        public static bool operator ==(CurveKey a, CurveKey b)\n        {\n            if (Equals(a, null))\n                return Equals(b, null);\n\n            if (Equals(b, null))\n                return Equals(a, null);\n\n            return (a.position == b.position)\n                   && (a.value == b.value)\n                   && (a.tangentIn == b.tangentIn)\n                   && (a.tangentOut == b.tangentOut)\n                   && (a.continuity == b.continuity);\n        }\n\n        public CurveKey Clone()\n        {\n            return new CurveKey(position, value, tangentIn, tangentOut, continuity);\n        }\n\n        public override bool Equals(object obj)\n        {\n            return (obj is CurveKey) ? ((CurveKey)obj) == this : false;\n        }\n\n        public override int GetHashCode()\n        {\n            return position.GetHashCode() ^ value.GetHashCode() ^ tangentIn.GetHashCode() ^\n                   tangentOut.GetHashCode() ^ continuity.GetHashCode();\n        }\n\n        #endregion\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/CurveKeyCollection.cs",
    "content": "﻿#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright © 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nAuthors:\nOlivier Dufour (Duff)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Xna.Framework\n{\n    public class CurveKeyCollection : ICollection<CurveKey>, IEnumerable<CurveKey>, IEnumerable\n    {\n        #region Private Fields\n\n        private List<CurveKey> innerlist;\n        private bool isReadOnly = false;\n\n        #endregion Private Fields\n\n        #region Properties\n\n        public CurveKey this[int index]\n        {\n            get { return innerlist[index]; }\n            set\n            {\n                if (value == null)\n                    throw new ArgumentNullException();\n\n                if (index >= innerlist.Count)\n                    throw new IndexOutOfRangeException();\n\n                if (innerlist[index].Position == value.Position)\n                    innerlist[index] = value;\n                else\n                {\n                    innerlist.RemoveAt(index);\n                    innerlist.Add(value);\n                }\n            }\n        }\n\n        public int Count\n        {\n            get { return innerlist.Count; }\n        }\n\n        public bool IsReadOnly\n        {\n            get { return isReadOnly; }\n        }\n\n        #endregion Properties\n\n        #region Constructors\n\n        public CurveKeyCollection()\n        {\n            innerlist = new List<CurveKey>();\n        }\n\n        #endregion Constructors\n\n        #region Public Methods\n\n        public void Add(CurveKey item)\n        {\n            if (item == null)\n                throw new ArgumentNullException(\"Value cannot be null.\", (Exception)null);\n\n            if (innerlist.Count == 0)\n            {\n                innerlist.Add(item);\n                return;\n            }\n\n            for (int i = 0; i < innerlist.Count; i++)\n            {\n                if (item.Position < innerlist[i].Position)\n                {\n                    innerlist.Insert(i, item);\n                    return;\n                }\n            }\n\n            innerlist.Add(item);\n        }\n\n        public void Clear()\n        {\n            innerlist.Clear();\n        }\n\n        public bool Contains(CurveKey item)\n        {\n            return innerlist.Contains(item);\n        }\n\n        public void CopyTo(CurveKey[] array, int arrayIndex)\n        {\n            innerlist.CopyTo(array, arrayIndex);\n        }\n\n        public IEnumerator<CurveKey> GetEnumerator()\n        {\n            return innerlist.GetEnumerator();\n        }\n\n        public bool Remove(CurveKey item)\n        {\n            return innerlist.Remove(item);\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return innerlist.GetEnumerator();\n        }\n\n        public CurveKeyCollection Clone()\n        {\n            CurveKeyCollection ckc = new CurveKeyCollection();\n            foreach (CurveKey key in innerlist)\n                ckc.Add(key);\n            return ckc;\n        }\n\n        public int IndexOf(CurveKey item)\n        {\n            return innerlist.IndexOf(item);\n        }\n\n        public void RemoveAt(int index)\n        {\n            if (index != Count && index > -1)\n                innerlist.RemoveAt(index);\n            else\n                throw new ArgumentOutOfRangeException(\n                    \"Index was out of range. Must be non-negative and less than the size of the collection.\\r\\nParameter name: index\",\n                    (Exception)null);\n        }\n\n        #endregion Public Methods\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/CurveLoopType.cs",
    "content": "namespace Microsoft.Xna.Framework\n{\n    public enum CurveLoopType\n    {\n        Constant,\n        Cycle,\n        CycleOffset,\n        Oscillate,\n        Linear\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Primitives/CurveTangent.cs",
    "content": "namespace Microsoft.Xna.Framework\n{\n    public enum CurveTangent\n    {\n        Flat,\n        Linear,\n        Smooth\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Primitives/MathHelper.cs",
    "content": "#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright  2006 The Mono.Xna Team\n\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\n\nnamespace Microsoft.Xna.Framework\n{\n    public static class MathHelper\n    {\n        public const float E = (float)Math.E;\n        public const float Log10E = 0.4342945f;\n        public const float Log2E = 1.442695f;\n        public const float Pi = (float)Math.PI;\n        public const float PiOver2 = (float)(Math.PI / 2.0);\n        public const float PiOver4 = (float)(Math.PI / 4.0);\n        public const float TwoPi = (float)(Math.PI * 2.0);\n\n        public static float Barycentric(float value1, float value2, float value3, float amount1, float amount2)\n        {\n            return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;\n        }\n\n        public static float CatmullRom(float value1, float value2, float value3, float value4, float amount)\n        {\n            // Using formula from http://www.mvps.org/directx/articles/catmull/\n            // Internally using doubles not to lose precission\n            double amountSquared = amount * amount;\n            double amountCubed = amountSquared * amount;\n            return (float)(0.5 * (2.0 * value2 +\n                                 (value3 - value1) * amount +\n                                 (2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared +\n                                 (3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed));\n        }\n\n        public static float Clamp(float value, float min, float max)\n        {\n            // First we check to see if we're greater than the max\n            value = (value > max) ? max : value;\n\n            // Then we check to see if we're less than the min.\n            value = (value < min) ? min : value;\n\n            // There's no check to see if min > max.\n            return value;\n        }\n\n        public static float Distance(float value1, float value2)\n        {\n            return Math.Abs(value1 - value2);\n        }\n\n        public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount)\n        {\n            // All transformed to double not to lose precission\n            // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity\n            double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result;\n            double sCubed = s * s * s;\n            double sSquared = s * s;\n\n            if (amount == 0f)\n                result = value1;\n            else if (amount == 1f)\n                result = value2;\n            else\n                result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +\n                         (3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +\n                         t1 * s +\n                         v1;\n            return (float)result;\n        }\n\n        public static float Lerp(float value1, float value2, float amount)\n        {\n            return value1 + (value2 - value1) * amount;\n        }\n\n        public static float Max(float value1, float value2)\n        {\n            return Math.Max(value1, value2);\n        }\n\n        public static float Min(float value1, float value2)\n        {\n            return Math.Min(value1, value2);\n        }\n\n        public static float SmoothStep(float value1, float value2, float amount)\n        {\n            // It is expected that 0 < amount < 1\n            // If amount < 0, return value1\n            // If amount > 1, return value2\n            float result = Clamp(amount, 0f, 1f);\n            result = Hermite(value1, 0f, value2, 0f, result);\n            return result;\n        }\n\n        public static float ToDegrees(float radians)\n        {\n            // This method uses double precission internally,\n            // though it returns single float\n            // Factor = 180 / pi\n            return (float)(radians * 57.295779513082320876798154814105);\n        }\n\n        public static float ToRadians(float degrees)\n        {\n            // This method uses double precission internally,\n            // though it returns single float\n            // Factor = pi / 180\n            return (float)(degrees * 0.017453292519943295769236907684886);\n        }\n\n        public static float WrapAngle(float angle)\n        {\n            angle = (float)Math.IEEERemainder((double)angle, 6.2831854820251465); //2xPi precission is double\n            if (angle <= -3.141593f)\n            {\n                angle += 6.283185f;\n                return angle;\n            }\n            if (angle > 3.141593f)\n            {\n                angle -= 6.283185f;\n            }\n            return angle;\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/Matrix.cs",
    "content": "// To prevent https://github.com/egordorichev/BurningKnight/issues/228 (for some reason MONOGAME flag is not always set?)\n#define MONOGAME\n\n#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright � 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\nusing System.Runtime.InteropServices;\n\nnamespace Microsoft.Xna.Framework\n{\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Matrix : IEquatable<Matrix>\n    {\n        #region Public Fields\n\n        public float M11;\n        public float M12;\n        public float M13;\n        public float M14;\n        public float M21;\n        public float M22;\n        public float M23;\n        public float M24;\n        public float M31;\n        public float M32;\n        public float M33;\n        public float M34;\n        public float M41;\n        public float M42;\n        public float M43;\n        public float M44;\n\n        #endregion Public Fields\n\n        #region Static Properties\n\n        private static Matrix identity = new Matrix(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f);\n\n        public static Matrix Identity\n        {\n            get { return identity; }\n        }\n\n        #endregion Static Properties\n\n        #region Public Properties\n\n        public Vector3 Backward\n        {\n            get { return new Vector3(M31, M32, M33); }\n            set\n            {\n                M31 = value.X;\n                M32 = value.Y;\n                M33 = value.Z;\n            }\n        }\n\n        public Vector3 Down\n        {\n            get { return new Vector3(-M21, -M22, -M23); }\n            set\n            {\n                M21 = -value.X;\n                M22 = -value.Y;\n                M23 = -value.Z;\n            }\n        }\n\n        public Vector3 Forward\n        {\n            get { return new Vector3(-M31, -M32, -M33); }\n            set\n            {\n                M31 = -value.X;\n                M32 = -value.Y;\n                M33 = -value.Z;\n            }\n        }\n\n        public Vector3 Left\n        {\n            get { return new Vector3(-M11, -M12, -M13); }\n            set\n            {\n                M11 = -value.X;\n                M12 = -value.Y;\n                M13 = -value.Z;\n            }\n        }\n\n        public Vector3 Right\n        {\n            get { return new Vector3(M11, M12, M13); }\n            set\n            {\n                M11 = value.X;\n                M12 = value.Y;\n                M13 = value.Z;\n            }\n        }\n\n        public Vector3 Translation\n        {\n            get { return new Vector3(M41, M42, M43); }\n            set\n            {\n                M41 = value.X;\n                M42 = value.Y;\n                M43 = value.Z;\n            }\n        }\n\n        public Vector3 Up\n        {\n            get { return new Vector3(M21, M22, M23); }\n            set\n            {\n                M21 = value.X;\n                M22 = value.Y;\n                M23 = value.Z;\n            }\n        }\n\n        #endregion Public Properties\n\n        #region Constructors\n\n        /// <summary>\n        /// Constructor for 4x4 Matrix\n        /// </summary>\n        /// <param name=\"m11\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m12\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m13\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m14\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m21\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m22\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m23\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m24\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m31\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m32\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m33\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m34\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m41\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m42\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m43\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"m44\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        public Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,\n                      float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)\n        {\n            M11 = m11;\n            M12 = m12;\n            M13 = m13;\n            M14 = m14;\n            M21 = m21;\n            M22 = m22;\n            M23 = m23;\n            M24 = m24;\n            M31 = m31;\n            M32 = m32;\n            M33 = m33;\n            M34 = m34;\n            M41 = m41;\n            M42 = m42;\n            M43 = m43;\n            M44 = m44;\n        }\n\n        #endregion Constructors\n\n        #region Public Static Methods\n\n        public static Matrix CreateWorld(Vector3 position, Vector3 forward, Vector3 up)\n        {\n            Matrix ret;\n            CreateWorld(ref position, ref forward, ref up, out ret);\n            return ret;\n        }\n\n        public static void CreateWorld(ref Vector3 position, ref Vector3 forward, ref Vector3 up, out Matrix result)\n        {\n            Vector3 x, y, z;\n            Vector3.Normalize(ref forward, out z);\n            Vector3.Cross(ref forward, ref up, out x);\n            Vector3.Cross(ref x, ref forward, out y);\n            x.Normalize();\n            y.Normalize();\n\n            result = new Matrix();\n            result.Right = x;\n            result.Up = y;\n            result.Forward = z;\n            result.Translation = position;\n            result.M44 = 1f;\n        }\n\n        /// <summary>\n        /// Adds second matrix to the first.\n        /// </summary>\n        /// <param name=\"matrix1\">\n        /// A <see cref=\"Matrix\"/>\n        /// </param>\n        /// <param name=\"matrix2\">\n        /// A <see cref=\"Matrix\"/>\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Matrix\"/>\n        /// </returns>\n        public static Matrix Add(Matrix matrix1, Matrix matrix2)\n        {\n            matrix1.M11 += matrix2.M11;\n            matrix1.M12 += matrix2.M12;\n            matrix1.M13 += matrix2.M13;\n            matrix1.M14 += matrix2.M14;\n            matrix1.M21 += matrix2.M21;\n            matrix1.M22 += matrix2.M22;\n            matrix1.M23 += matrix2.M23;\n            matrix1.M24 += matrix2.M24;\n            matrix1.M31 += matrix2.M31;\n            matrix1.M32 += matrix2.M32;\n            matrix1.M33 += matrix2.M33;\n            matrix1.M34 += matrix2.M34;\n            matrix1.M41 += matrix2.M41;\n            matrix1.M42 += matrix2.M42;\n            matrix1.M43 += matrix2.M43;\n            matrix1.M44 += matrix2.M44;\n            return matrix1;\n        }\n\n\n        /// <summary>\n        /// Adds two Matrix and save to the result Matrix\n        /// </summary>\n        /// <param name=\"matrix1\">\n        /// A <see cref=\"Matrix\"/>\n        /// </param>\n        /// <param name=\"matrix2\">\n        /// A <see cref=\"Matrix\"/>\n        /// </param>\n        /// <param name=\"result\">\n        /// A <see cref=\"Matrix\"/>\n        /// </param>\n        public static void Add(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)\n        {\n            result.M11 = matrix1.M11 + matrix2.M11;\n            result.M12 = matrix1.M12 + matrix2.M12;\n            result.M13 = matrix1.M13 + matrix2.M13;\n            result.M14 = matrix1.M14 + matrix2.M14;\n            result.M21 = matrix1.M21 + matrix2.M21;\n            result.M22 = matrix1.M22 + matrix2.M22;\n            result.M23 = matrix1.M23 + matrix2.M23;\n            result.M24 = matrix1.M24 + matrix2.M24;\n            result.M31 = matrix1.M31 + matrix2.M31;\n            result.M32 = matrix1.M32 + matrix2.M32;\n            result.M33 = matrix1.M33 + matrix2.M33;\n            result.M34 = matrix1.M34 + matrix2.M34;\n            result.M41 = matrix1.M41 + matrix2.M41;\n            result.M42 = matrix1.M42 + matrix2.M42;\n            result.M43 = matrix1.M43 + matrix2.M43;\n            result.M44 = matrix1.M44 + matrix2.M44;\n        }\n\n\n        public static Matrix CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition,\n                                             Vector3 cameraUpVector, Nullable<Vector3> cameraForwardVector)\n        {\n            Matrix ret;\n            CreateBillboard(ref objectPosition, ref cameraPosition, ref cameraUpVector, cameraForwardVector, out ret);\n            return ret;\n        }\n\n        public static void CreateBillboard(ref Vector3 objectPosition, ref Vector3 cameraPosition,\n                                           ref Vector3 cameraUpVector, Vector3? cameraForwardVector, out Matrix result)\n        {\n            Vector3 translation = objectPosition - cameraPosition;\n            Vector3 backwards, right, up;\n            Vector3.Normalize(ref translation, out backwards);\n            Vector3.Normalize(ref cameraUpVector, out up);\n            Vector3.Cross(ref backwards, ref up, out right);\n            Vector3.Cross(ref backwards, ref right, out up);\n            result = Identity;\n            result.Backward = backwards;\n            result.Right = right;\n            result.Up = up;\n            result.Translation = translation;\n        }\n\n        public static Matrix CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition,\n                                                        Vector3 rotateAxis, Nullable<Vector3> cameraForwardVector,\n                                                        Nullable<Vector3> objectForwardVector)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static void CreateConstrainedBillboard(ref Vector3 objectPosition, ref Vector3 cameraPosition,\n                                                      ref Vector3 rotateAxis, Vector3? cameraForwardVector,\n                                                      Vector3? objectForwardVector, out Matrix result)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static Matrix CreateFromAxisAngle(Vector3 axis, float angle)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static void CreateFromAxisAngle(ref Vector3 axis, float angle, out Matrix result)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static Matrix CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)\n        {\n            Matrix ret;\n            CreateLookAt(ref cameraPosition, ref cameraTarget, ref cameraUpVector, out ret);\n            return ret;\n        }\n\n\n        public static void CreateLookAt(ref Vector3 cameraPosition, ref Vector3 cameraTarget, ref Vector3 cameraUpVector,\n                                        out Matrix result)\n        {\n            // http://msdn.microsoft.com/en-us/library/bb205343(v=VS.85).aspx\n\n            Vector3 vz = Vector3.Normalize(cameraPosition - cameraTarget);\n            Vector3 vx = Vector3.Normalize(Vector3.Cross(cameraUpVector, vz));\n            Vector3 vy = Vector3.Cross(vz, vx);\n            result = Identity;\n            result.M11 = vx.X;\n            result.M12 = vy.X;\n            result.M13 = vz.X;\n            result.M21 = vx.Y;\n            result.M22 = vy.Y;\n            result.M23 = vz.Y;\n            result.M31 = vx.Z;\n            result.M32 = vy.Z;\n            result.M33 = vz.Z;\n            result.M41 = -Vector3.Dot(vx, cameraPosition);\n            result.M42 = -Vector3.Dot(vy, cameraPosition);\n            result.M43 = -Vector3.Dot(vz, cameraPosition);\n        }\n\n        public static Matrix CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane)\n        {\n            Matrix ret;\n            CreateOrthographic(width, height, zNearPlane, zFarPlane, out ret);\n            return ret;\n        }\n\n\n        public static void CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane,\n                                              out Matrix result)\n        {\n            result.M11 = 2 / width;\n            result.M12 = 0;\n            result.M13 = 0;\n            result.M14 = 0;\n            result.M21 = 0;\n            result.M22 = 2 / height;\n            result.M23 = 0;\n            result.M24 = 0;\n            result.M31 = 0;\n            result.M32 = 0;\n            result.M33 = 1 / (zNearPlane - zFarPlane);\n            result.M34 = 0;\n            result.M41 = 0;\n            result.M42 = 0;\n            result.M43 = zNearPlane / (zNearPlane - zFarPlane);\n            result.M44 = 1;\n        }\n\n\n        public static Matrix CreateOrthographicOffCenter(float left, float right, float bottom, float top,\n                                                         float zNearPlane, float zFarPlane)\n        {\n            Matrix ret;\n            CreateOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane, out ret);\n            return ret;\n        }\n\n\n        public static void CreateOrthographicOffCenter(float left, float right, float bottom, float top,\n                                                       float zNearPlane, float zFarPlane, out Matrix result)\n        {\n            result.M11 = 2 / (right - left);\n            result.M12 = 0;\n            result.M13 = 0;\n            result.M14 = 0;\n            result.M21 = 0;\n            result.M22 = 2 / (top - bottom);\n            result.M23 = 0;\n            result.M24 = 0;\n            result.M31 = 0;\n            result.M32 = 0;\n            result.M33 = 1 / (zNearPlane - zFarPlane);\n            result.M34 = 0;\n            result.M41 = (left + right) / (left - right);\n            result.M42 = (bottom + top) / (bottom - top);\n            result.M43 = zNearPlane / (zNearPlane - zFarPlane);\n            result.M44 = 1;\n        }\n\n\n        public static Matrix CreatePerspective(float width, float height, float zNearPlane, float zFarPlane)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static void CreatePerspective(float width, float height, float zNearPlane, float zFarPlane,\n                                             out Matrix result)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static Matrix CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance,\n                                                          float farPlaneDistance)\n        {\n            Matrix ret;\n            CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance, out ret);\n            return ret;\n        }\n\n\n        public static void CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance,\n                                                        float farPlaneDistance, out Matrix result)\n        {\n            // http://msdn.microsoft.com/en-us/library/bb205351(v=VS.85).aspx\n            // http://msdn.microsoft.com/en-us/library/bb195665.aspx\n\n            result = new Matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n            if (fieldOfView < 0 || fieldOfView > 3.14159262f)\n                throw new ArgumentOutOfRangeException(\"fieldOfView\",\n                                                      \"fieldOfView takes a value between 0 and Pi (180 degrees) in radians.\");\n\n            if (nearPlaneDistance <= 0.0f)\n                throw new ArgumentOutOfRangeException(\"nearPlaneDistance\",\n                                                      \"You should specify positive value for nearPlaneDistance.\");\n\n            if (farPlaneDistance <= 0.0f)\n                throw new ArgumentOutOfRangeException(\"farPlaneDistance\",\n                                                      \"You should specify positive value for farPlaneDistance.\");\n\n            if (farPlaneDistance <= nearPlaneDistance)\n                throw new ArgumentOutOfRangeException(\"nearPlaneDistance\",\n                                                      \"Near plane distance is larger than Far plane distance. Near plane distance must be smaller than Far plane distance.\");\n\n            float yscale = (float)1 / (float)Math.Tan(fieldOfView / 2);\n            float xscale = yscale / aspectRatio;\n\n            result.M11 = xscale;\n            result.M22 = yscale;\n            result.M33 = farPlaneDistance / (nearPlaneDistance - farPlaneDistance);\n            result.M34 = -1;\n            result.M43 = nearPlaneDistance * farPlaneDistance / (nearPlaneDistance - farPlaneDistance);\n        }\n\n\n        public static Matrix CreatePerspectiveOffCenter(float left, float right, float bottom, float top,\n                                                        float zNearPlane, float zFarPlane)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static void CreatePerspectiveOffCenter(float left, float right, float bottom, float top,\n                                                      float nearPlaneDistance, float farPlaneDistance, out Matrix result)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static Matrix CreateRotationX(float radians)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M22 = (float)Math.Cos(radians);\n            returnMatrix.M23 = (float)Math.Sin(radians);\n            returnMatrix.M32 = -returnMatrix.M23;\n            returnMatrix.M33 = returnMatrix.M22;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateRotationX(float radians, out Matrix result)\n        {\n            result = Identity;\n\n            result.M22 = (float)Math.Cos(radians);\n            result.M23 = (float)Math.Sin(radians);\n            result.M32 = -result.M23;\n            result.M33 = result.M22;\n        }\n\n\n        public static Matrix CreateRotationY(float radians)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M11 = (float)Math.Cos(radians);\n            returnMatrix.M13 = (float)Math.Sin(radians);\n            returnMatrix.M31 = -returnMatrix.M13;\n            returnMatrix.M33 = returnMatrix.M11;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateRotationY(float radians, out Matrix result)\n        {\n            result = Identity;\n\n            result.M11 = (float)Math.Cos(radians);\n            result.M13 = (float)Math.Sin(radians);\n            result.M31 = -result.M13;\n            result.M33 = result.M11;\n        }\n\n\n        public static Matrix CreateRotationZ(float radians)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M11 = (float)Math.Cos(radians);\n            returnMatrix.M12 = (float)Math.Sin(radians);\n            returnMatrix.M21 = -returnMatrix.M12;\n            returnMatrix.M22 = returnMatrix.M11;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateRotationZ(float radians, out Matrix result)\n        {\n            result = Identity;\n\n            result.M11 = (float)Math.Cos(radians);\n            result.M12 = (float)Math.Sin(radians);\n            result.M21 = -result.M12;\n            result.M22 = result.M11;\n        }\n\n\n        public static Matrix CreateScale(float scale)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M11 = scale;\n            returnMatrix.M22 = scale;\n            returnMatrix.M33 = scale;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateScale(float scale, out Matrix result)\n        {\n            result = Identity;\n\n            result.M11 = scale;\n            result.M22 = scale;\n            result.M33 = scale;\n        }\n\n\n        public static Matrix CreateScale(float xScale, float yScale, float zScale)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M11 = xScale;\n            returnMatrix.M22 = yScale;\n            returnMatrix.M33 = zScale;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateScale(float xScale, float yScale, float zScale, out Matrix result)\n        {\n            result = Identity;\n\n            result.M11 = xScale;\n            result.M22 = yScale;\n            result.M33 = zScale;\n        }\n\n\n        public static Matrix CreateScale(Vector3 scales)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M11 = scales.X;\n            returnMatrix.M22 = scales.Y;\n            returnMatrix.M33 = scales.Z;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateScale(ref Vector3 scales, out Matrix result)\n        {\n            result = Identity;\n\n            result.M11 = scales.X;\n            result.M22 = scales.Y;\n            result.M33 = scales.Z;\n        }\n\n\n        public static Matrix CreateTranslation(float xPosition, float yPosition, float zPosition)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M41 = xPosition;\n            returnMatrix.M42 = yPosition;\n            returnMatrix.M43 = zPosition;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateTranslation(float xPosition, float yPosition, float zPosition, out Matrix result)\n        {\n            result = Identity;\n\n            result.M41 = xPosition;\n            result.M42 = yPosition;\n            result.M43 = zPosition;\n        }\n\n\n        public static Matrix CreateTranslation(Vector3 position)\n        {\n            Matrix returnMatrix = Identity;\n\n            returnMatrix.M41 = position.X;\n            returnMatrix.M42 = position.Y;\n            returnMatrix.M43 = position.Z;\n\n            return returnMatrix;\n        }\n\n\n        public static void CreateTranslation(ref Vector3 position, out Matrix result)\n        {\n            result = Identity;\n\n            result.M41 = position.X;\n            result.M42 = position.Y;\n            result.M43 = position.Z;\n        }\n\n        public static Matrix Divide(Matrix matrix1, Matrix matrix2)\n        {\n            Matrix ret;\n            Divide(ref matrix1, ref matrix2, out ret);\n            return ret;\n        }\n\n\n        public static void Divide(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)\n        {\n            Matrix inverse = Invert(matrix2);\n            Multiply(ref matrix1, ref inverse, out result);\n        }\n\n\n        public static Matrix Divide(Matrix matrix1, float divider)\n        {\n            Matrix ret;\n            Divide(ref matrix1, divider, out ret);\n            return ret;\n        }\n\n\n        public static void Divide(ref Matrix matrix1, float divider, out Matrix result)\n        {\n            float inverseDivider = 1f / divider;\n            Multiply(ref matrix1, inverseDivider, out result);\n        }\n\n        public static Matrix Invert(Matrix matrix)\n        {\n            Invert(ref matrix, out matrix);\n            return matrix;\n        }\n\n\n        public static void Invert(ref Matrix matrix, out Matrix result)\n        {\n            //\n            // Use Laplace expansion theorem to calculate the inverse of a 4x4 matrix\n            // \n            // 1. Calculate the 2x2 determinants needed and the 4x4 determinant based on the 2x2 determinants \n            // 2. Create the adjugate matrix, which satisfies: A * adj(A) = det(A) * I\n            // 3. Divide adjugate matrix with the determinant to find the inverse\n\n            float det1 = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21;\n            float det2 = matrix.M11 * matrix.M23 - matrix.M13 * matrix.M21;\n            float det3 = matrix.M11 * matrix.M24 - matrix.M14 * matrix.M21;\n            float det4 = matrix.M12 * matrix.M23 - matrix.M13 * matrix.M22;\n            float det5 = matrix.M12 * matrix.M24 - matrix.M14 * matrix.M22;\n            float det6 = matrix.M13 * matrix.M24 - matrix.M14 * matrix.M23;\n            float det7 = matrix.M31 * matrix.M42 - matrix.M32 * matrix.M41;\n            float det8 = matrix.M31 * matrix.M43 - matrix.M33 * matrix.M41;\n            float det9 = matrix.M31 * matrix.M44 - matrix.M34 * matrix.M41;\n            float det10 = matrix.M32 * matrix.M43 - matrix.M33 * matrix.M42;\n            float det11 = matrix.M32 * matrix.M44 - matrix.M34 * matrix.M42;\n            float det12 = matrix.M33 * matrix.M44 - matrix.M34 * matrix.M43;\n\n            float detMatrix = (float)(det1 * det12 - det2 * det11 + det3 * det10 + det4 * det9 - det5 * det8 + det6 * det7);\n\n            float invDetMatrix = 1f / detMatrix;\n\n            Matrix ret; // Allow for matrix and result to point to the same structure\n\n            ret.M11 = (matrix.M22 * det12 - matrix.M23 * det11 + matrix.M24 * det10) * invDetMatrix;\n            ret.M12 = (-matrix.M12 * det12 + matrix.M13 * det11 - matrix.M14 * det10) * invDetMatrix;\n            ret.M13 = (matrix.M42 * det6 - matrix.M43 * det5 + matrix.M44 * det4) * invDetMatrix;\n            ret.M14 = (-matrix.M32 * det6 + matrix.M33 * det5 - matrix.M34 * det4) * invDetMatrix;\n            ret.M21 = (-matrix.M21 * det12 + matrix.M23 * det9 - matrix.M24 * det8) * invDetMatrix;\n            ret.M22 = (matrix.M11 * det12 - matrix.M13 * det9 + matrix.M14 * det8) * invDetMatrix;\n            ret.M23 = (-matrix.M41 * det6 + matrix.M43 * det3 - matrix.M44 * det2) * invDetMatrix;\n            ret.M24 = (matrix.M31 * det6 - matrix.M33 * det3 + matrix.M34 * det2) * invDetMatrix;\n            ret.M31 = (matrix.M21 * det11 - matrix.M22 * det9 + matrix.M24 * det7) * invDetMatrix;\n            ret.M32 = (-matrix.M11 * det11 + matrix.M12 * det9 - matrix.M14 * det7) * invDetMatrix;\n            ret.M33 = (matrix.M41 * det5 - matrix.M42 * det3 + matrix.M44 * det1) * invDetMatrix;\n            ret.M34 = (-matrix.M31 * det5 + matrix.M32 * det3 - matrix.M34 * det1) * invDetMatrix;\n            ret.M41 = (-matrix.M21 * det10 + matrix.M22 * det8 - matrix.M23 * det7) * invDetMatrix;\n            ret.M42 = (matrix.M11 * det10 - matrix.M12 * det8 + matrix.M13 * det7) * invDetMatrix;\n            ret.M43 = (-matrix.M41 * det4 + matrix.M42 * det2 - matrix.M43 * det1) * invDetMatrix;\n            ret.M44 = (matrix.M31 * det4 - matrix.M32 * det2 + matrix.M33 * det1) * invDetMatrix;\n\n            result = ret;\n        }\n\n\n        public static Matrix Lerp(Matrix matrix1, Matrix matrix2, float amount)\n        {\n            throw new NotImplementedException();\n        }\n\n\n        public static void Lerp(ref Matrix matrix1, ref Matrix matrix2, float amount, out Matrix result)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static Matrix Multiply(Matrix matrix1, Matrix matrix2)\n        {\n            Matrix ret;\n            Multiply(ref matrix1, ref matrix2, out ret);\n            return ret;\n        }\n\n\n        public static void Multiply(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)\n        {\n            result.M11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31 +\n                         matrix1.M14 * matrix2.M41;\n            result.M12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M32 +\n                         matrix1.M14 * matrix2.M42;\n            result.M13 = matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 + matrix1.M13 * matrix2.M33 +\n                         matrix1.M14 * matrix2.M43;\n            result.M14 = matrix1.M11 * matrix2.M14 + matrix1.M12 * matrix2.M24 + matrix1.M13 * matrix2.M34 +\n                         matrix1.M14 * matrix2.M44;\n\n            result.M21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M23 * matrix2.M31 +\n                         matrix1.M24 * matrix2.M41;\n            result.M22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M32 +\n                         matrix1.M24 * matrix2.M42;\n            result.M23 = matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M23 * matrix2.M33 +\n                         matrix1.M24 * matrix2.M43;\n            result.M24 = matrix1.M21 * matrix2.M14 + matrix1.M22 * matrix2.M24 + matrix1.M23 * matrix2.M34 +\n                         matrix1.M24 * matrix2.M44;\n\n            result.M31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix1.M33 * matrix2.M31 +\n                         matrix1.M34 * matrix2.M41;\n            result.M32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M32 +\n                         matrix1.M34 * matrix2.M42;\n            result.M33 = matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 + matrix1.M33 * matrix2.M33 +\n                         matrix1.M34 * matrix2.M43;\n            result.M34 = matrix1.M31 * matrix2.M14 + matrix1.M32 * matrix2.M24 + matrix1.M33 * matrix2.M34 +\n                         matrix1.M34 * matrix2.M44;\n\n            result.M41 = matrix1.M41 * matrix2.M11 + matrix1.M42 * matrix2.M21 + matrix1.M43 * matrix2.M31 +\n                         matrix1.M44 * matrix2.M41;\n            result.M42 = matrix1.M41 * matrix2.M12 + matrix1.M42 * matrix2.M22 + matrix1.M43 * matrix2.M32 +\n                         matrix1.M44 * matrix2.M42;\n            result.M43 = matrix1.M41 * matrix2.M13 + matrix1.M42 * matrix2.M23 + matrix1.M43 * matrix2.M33 +\n                         matrix1.M44 * matrix2.M43;\n            result.M44 = matrix1.M41 * matrix2.M14 + matrix1.M42 * matrix2.M24 + matrix1.M43 * matrix2.M34 +\n                         matrix1.M44 * matrix2.M44;\n        }\n\n\n        public static Matrix Multiply(Matrix matrix1, float factor)\n        {\n            matrix1.M11 *= factor;\n            matrix1.M12 *= factor;\n            matrix1.M13 *= factor;\n            matrix1.M14 *= factor;\n            matrix1.M21 *= factor;\n            matrix1.M22 *= factor;\n            matrix1.M23 *= factor;\n            matrix1.M24 *= factor;\n            matrix1.M31 *= factor;\n            matrix1.M32 *= factor;\n            matrix1.M33 *= factor;\n            matrix1.M34 *= factor;\n            matrix1.M41 *= factor;\n            matrix1.M42 *= factor;\n            matrix1.M43 *= factor;\n            matrix1.M44 *= factor;\n            return matrix1;\n        }\n\n\n        public static void Multiply(ref Matrix matrix1, float factor, out Matrix result)\n        {\n            result.M11 = matrix1.M11 * factor;\n            result.M12 = matrix1.M12 * factor;\n            result.M13 = matrix1.M13 * factor;\n            result.M14 = matrix1.M14 * factor;\n            result.M21 = matrix1.M21 * factor;\n            result.M22 = matrix1.M22 * factor;\n            result.M23 = matrix1.M23 * factor;\n            result.M24 = matrix1.M24 * factor;\n            result.M31 = matrix1.M31 * factor;\n            result.M32 = matrix1.M32 * factor;\n            result.M33 = matrix1.M33 * factor;\n            result.M34 = matrix1.M34 * factor;\n            result.M41 = matrix1.M41 * factor;\n            result.M42 = matrix1.M42 * factor;\n            result.M43 = matrix1.M43 * factor;\n            result.M44 = matrix1.M44 * factor;\n        }\n\n\n        public static Matrix Negate(Matrix matrix)\n        {\n            Multiply(ref matrix, -1.0f, out matrix);\n            return matrix;\n        }\n\n\n        public static void Negate(ref Matrix matrix, out Matrix result)\n        {\n            Multiply(ref matrix, -1.0f, out result);\n        }\n\n        public static Matrix Subtract(Matrix matrix1, Matrix matrix2)\n        {\n            matrix1.M11 -= matrix2.M11;\n            matrix1.M12 -= matrix2.M12;\n            matrix1.M13 -= matrix2.M13;\n            matrix1.M14 -= matrix2.M14;\n            matrix1.M21 -= matrix2.M21;\n            matrix1.M22 -= matrix2.M22;\n            matrix1.M23 -= matrix2.M23;\n            matrix1.M24 -= matrix2.M24;\n            matrix1.M31 -= matrix2.M31;\n            matrix1.M32 -= matrix2.M32;\n            matrix1.M33 -= matrix2.M33;\n            matrix1.M34 -= matrix2.M34;\n            matrix1.M41 -= matrix2.M41;\n            matrix1.M42 -= matrix2.M42;\n            matrix1.M43 -= matrix2.M43;\n            matrix1.M44 -= matrix2.M44;\n            return matrix1;\n        }\n\n        public static void Subtract(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)\n        {\n            result.M11 = matrix1.M11 - matrix2.M11;\n            result.M12 = matrix1.M12 - matrix2.M12;\n            result.M13 = matrix1.M13 - matrix2.M13;\n            result.M14 = matrix1.M14 - matrix2.M14;\n            result.M21 = matrix1.M21 - matrix2.M21;\n            result.M22 = matrix1.M22 - matrix2.M22;\n            result.M23 = matrix1.M23 - matrix2.M23;\n            result.M24 = matrix1.M24 - matrix2.M24;\n            result.M31 = matrix1.M31 - matrix2.M31;\n            result.M32 = matrix1.M32 - matrix2.M32;\n            result.M33 = matrix1.M33 - matrix2.M33;\n            result.M34 = matrix1.M34 - matrix2.M34;\n            result.M41 = matrix1.M41 - matrix2.M41;\n            result.M42 = matrix1.M42 - matrix2.M42;\n            result.M43 = matrix1.M43 - matrix2.M43;\n            result.M44 = matrix1.M44 - matrix2.M44;\n        }\n\n        public static Matrix Transpose(Matrix matrix)\n        {\n            Matrix ret;\n            Transpose(ref matrix, out ret);\n            return ret;\n        }\n\n\n        public static void Transpose(ref Matrix matrix, out Matrix result)\n        {\n            result.M11 = matrix.M11;\n            result.M12 = matrix.M21;\n            result.M13 = matrix.M31;\n            result.M14 = matrix.M41;\n\n            result.M21 = matrix.M12;\n            result.M22 = matrix.M22;\n            result.M23 = matrix.M32;\n            result.M24 = matrix.M42;\n\n            result.M31 = matrix.M13;\n            result.M32 = matrix.M23;\n            result.M33 = matrix.M33;\n            result.M34 = matrix.M43;\n\n            result.M41 = matrix.M14;\n            result.M42 = matrix.M24;\n            result.M43 = matrix.M34;\n            result.M44 = matrix.M44;\n        }\n\n        #endregion Public Static Methods\n\n        #region Public Methods\n\n        public float Determinant()\n        {\n            float minor1, minor2, minor3, minor4, minor5, minor6;\n\n            minor1 = M31 * M42 - M32 * M41;\n            minor2 = M31 * M43 - M33 * M41;\n            minor3 = M31 * M44 - M34 * M41;\n            minor4 = M32 * M43 - M33 * M42;\n            minor5 = M32 * M44 - M34 * M42;\n            minor6 = M33 * M44 - M34 * M43;\n\n            return M11 * (M22 * minor6 - M23 * minor5 + M24 * minor4) -\n                   M12 * (M21 * minor6 - M23 * minor3 + M24 * minor2) +\n                   M13 * (M21 * minor5 - M22 * minor3 + M24 * minor1) -\n                   M14 * (M21 * minor4 - M22 * minor2 + M23 * minor1);\n        }\n\n        public bool Equals(Matrix other)\n        {\n            return this == other;\n        }\n\n        #endregion Public Methods\n\n        #region Operators\n\n        public static Matrix operator +(Matrix matrix1, Matrix matrix2)\n        {\n            Add(ref matrix1, ref matrix2, out matrix1);\n            return matrix1;\n        }\n\n        public static Matrix operator /(Matrix matrix1, Matrix matrix2)\n        {\n            Matrix ret;\n            Divide(ref matrix1, ref matrix2, out ret);\n            return ret;\n        }\n\n        public static Matrix operator /(Matrix matrix1, float divider)\n        {\n            Matrix ret;\n            Divide(ref matrix1, divider, out ret);\n            return ret;\n        }\n\n        public static bool operator ==(Matrix matrix1, Matrix matrix2)\n        {\n            return (matrix1.M11 == matrix2.M11) && (matrix1.M12 == matrix2.M12) &&\n                   (matrix1.M13 == matrix2.M13) && (matrix1.M14 == matrix2.M14) &&\n                   (matrix1.M21 == matrix2.M21) && (matrix1.M22 == matrix2.M22) &&\n                   (matrix1.M23 == matrix2.M23) && (matrix1.M24 == matrix2.M24) &&\n                   (matrix1.M31 == matrix2.M31) && (matrix1.M32 == matrix2.M32) &&\n                   (matrix1.M33 == matrix2.M33) && (matrix1.M34 == matrix2.M34) &&\n                   (matrix1.M41 == matrix2.M41) && (matrix1.M42 == matrix2.M42) &&\n                   (matrix1.M43 == matrix2.M43) && (matrix1.M44 == matrix2.M44);\n        }\n\n        public static bool operator !=(Matrix matrix1, Matrix matrix2)\n        {\n            return !(matrix1 == matrix2);\n        }\n\n        public static Matrix operator *(Matrix matrix1, Matrix matrix2)\n        {\n            Matrix returnMatrix = new Matrix();\n            Multiply(ref matrix1, ref matrix2, out returnMatrix);\n            return returnMatrix;\n        }\n\n        public static Matrix operator *(Matrix matrix, float scaleFactor)\n        {\n            Multiply(ref matrix, scaleFactor, out matrix);\n            return matrix;\n        }\n\n        public static Matrix operator *(float scaleFactor, Matrix matrix)\n        {\n            Matrix target;\n            target.M11 = matrix.M11 * scaleFactor;\n            target.M12 = matrix.M12 * scaleFactor;\n            target.M13 = matrix.M13 * scaleFactor;\n            target.M14 = matrix.M14 * scaleFactor;\n            target.M21 = matrix.M21 * scaleFactor;\n            target.M22 = matrix.M22 * scaleFactor;\n            target.M23 = matrix.M23 * scaleFactor;\n            target.M24 = matrix.M24 * scaleFactor;\n            target.M31 = matrix.M31 * scaleFactor;\n            target.M32 = matrix.M32 * scaleFactor;\n            target.M33 = matrix.M33 * scaleFactor;\n            target.M34 = matrix.M34 * scaleFactor;\n            target.M41 = matrix.M41 * scaleFactor;\n            target.M42 = matrix.M42 * scaleFactor;\n            target.M43 = matrix.M43 * scaleFactor;\n            target.M44 = matrix.M44 * scaleFactor;\n            return target;\n        }\n\n        public static Matrix operator -(Matrix matrix1, Matrix matrix2)\n        {\n            Matrix returnMatrix = new Matrix();\n            Subtract(ref matrix1, ref matrix2, out returnMatrix);\n            return returnMatrix;\n        }\n\n\n        public static Matrix operator -(Matrix matrix1)\n        {\n            Negate(ref matrix1, out matrix1);\n            return matrix1;\n        }\n\n        #endregion\n\n        #region Object Overrides\n\n        public override bool Equals(object obj)\n        {\n            return this == (Matrix)obj;\n        }\n\n        public override int GetHashCode()\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToString()\n        {\n            return \"{ {M11:\" + M11 + \" M12:\" + M12 + \" M13:\" + M13 + \" M14:\" + M14 + \"}\" +\n                   \" {M21:\" + M21 + \" M22:\" + M22 + \" M23:\" + M23 + \" M24:\" + M24 + \"}\" +\n                   \" {M31:\" + M31 + \" M32:\" + M32 + \" M33:\" + M33 + \" M34:\" + M34 + \"}\" +\n                   \" {M41:\" + M41 + \" M42:\" + M42 + \" M43:\" + M43 + \" M44:\" + M44 + \"} }\";\n        }\n\n        #endregion\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/Vector2.cs",
    "content": "﻿#if false\n#region License\n\n/*\nMIT License\nCopyright © 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nAuthors\n * Alan McGovern\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Microsoft.Xna.Framework\n{\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Vector2 : IEquatable<Vector2>\n    {\n        #region Private Fields\n\n        private static Vector2 zeroVector = new Vector2(0f, 0f);\n        private static Vector2 unitVector = new Vector2(1f, 1f);\n        private static Vector2 unitXVector = new Vector2(1f, 0f);\n        private static Vector2 unitYVector = new Vector2(0f, 1f);\n\n        #endregion Private Fields\n\n        #region Public Fields\n\n        public float X;\n        public float Y;\n\n        #endregion Public Fields\n\n        #region Properties\n\n        public static Vector2 Zero\n        {\n            get { return zeroVector; }\n        }\n\n        public static Vector2 One\n        {\n            get { return unitVector; }\n        }\n\n        public static Vector2 UnitX\n        {\n            get { return unitXVector; }\n        }\n\n        public static Vector2 UnitY\n        {\n            get { return unitYVector; }\n        }\n\n        #endregion Properties\n\n        #region Constructors\n\n        /// <summary>\n        /// Constructor foe standard 2D vector.\n        /// </summary>\n        /// <param name=\"x\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        /// <param name=\"y\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        public Vector2(float x, float y)\n        {\n            X = x;\n            Y = y;\n        }\n\n        /// <summary>\n        /// Constructor for \"square\" vector.\n        /// </summary>\n        /// <param name=\"value\">\n        /// A <see cref=\"System.Single\"/>\n        /// </param>\n        public Vector2(float value)\n        {\n            X = value;\n            Y = value;\n        }\n\n        #endregion Constructors\n\n        #region Public Methods\n\n        public static void Reflect(ref Vector2 vector, ref Vector2 normal, out Vector2 result)\n        {\n            float dot = Dot(vector, normal);\n            result.X = vector.X - ((2f * dot) * normal.X);\n            result.Y = vector.Y - ((2f * dot) * normal.Y);\n        }\n\n        public static Vector2 Reflect(Vector2 vector, Vector2 normal)\n        {\n            Vector2 result;\n            Reflect(ref vector, ref normal, out result);\n            return result;\n        }\n\n        public static Vector2 Add(Vector2 value1, Vector2 value2)\n        {\n            value1.X += value2.X;\n            value1.Y += value2.Y;\n            return value1;\n        }\n\n        public static void Add(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result.X = value1.X + value2.X;\n            result.Y = value1.Y + value2.Y;\n        }\n\n        public static Vector2 Barycentric(Vector2 value1, Vector2 value2, Vector2 value3, float amount1, float amount2)\n        {\n            return new Vector2(\n                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),\n                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));\n        }\n\n        public static void Barycentric(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, float amount1,\n                                       float amount2, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),\n                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));\n        }\n\n        public static Vector2 CatmullRom(Vector2 value1, Vector2 value2, Vector2 value3, Vector2 value4, float amount)\n        {\n            return new Vector2(\n                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),\n                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));\n        }\n\n        public static void CatmullRom(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, ref Vector2 value4,\n                                      float amount, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),\n                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));\n        }\n\n        public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max)\n        {\n            return new Vector2(\n                MathHelper.Clamp(value1.X, min.X, max.X),\n                MathHelper.Clamp(value1.Y, min.Y, max.Y));\n        }\n\n        public static void Clamp(ref Vector2 value1, ref Vector2 min, ref Vector2 max, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.Clamp(value1.X, min.X, max.X),\n                MathHelper.Clamp(value1.Y, min.Y, max.Y));\n        }\n\n        /// <summary>\n        /// Returns float precison distanve between two vectors\n        /// </summary>\n        /// <param name=\"value1\">\n        /// A <see cref=\"Vector2\"/>\n        /// </param>\n        /// <param name=\"value2\">\n        /// A <see cref=\"Vector2\"/>\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"System.Single\"/>\n        /// </returns>\n        public static float Distance(Vector2 value1, Vector2 value2)\n        {\n            float result;\n            DistanceSquared(ref value1, ref value2, out result);\n            return (float)Math.Sqrt(result);\n        }\n\n\n        public static void Distance(ref Vector2 value1, ref Vector2 value2, out float result)\n        {\n            DistanceSquared(ref value1, ref value2, out result);\n            result = (float)Math.Sqrt(result);\n        }\n\n        public static float DistanceSquared(Vector2 value1, Vector2 value2)\n        {\n            float result;\n            DistanceSquared(ref value1, ref value2, out result);\n            return result;\n        }\n\n        public static void DistanceSquared(ref Vector2 value1, ref Vector2 value2, out float result)\n        {\n            result = (value1.X - value2.X) * (value1.X - value2.X) + (value1.Y - value2.Y) * (value1.Y - value2.Y);\n        }\n\n        /// <summary>\n        /// Devide first vector with the secund vector\n        /// </summary>\n        /// <param name=\"value1\">\n        /// A <see cref=\"Vector2\"/>\n        /// </param>\n        /// <param name=\"value2\">\n        /// A <see cref=\"Vector2\"/>\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Vector2\"/>\n        /// </returns>\n        public static Vector2 Divide(Vector2 value1, Vector2 value2)\n        {\n            value1.X /= value2.X;\n            value1.Y /= value2.Y;\n            return value1;\n        }\n\n        public static void Divide(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result.X = value1.X / value2.X;\n            result.Y = value1.Y / value2.Y;\n        }\n\n        public static Vector2 Divide(Vector2 value1, float divider)\n        {\n            float factor = 1 / divider;\n            value1.X *= factor;\n            value1.Y *= factor;\n            return value1;\n        }\n\n        public static void Divide(ref Vector2 value1, float divider, out Vector2 result)\n        {\n            float factor = 1 / divider;\n            result.X = value1.X * factor;\n            result.Y = value1.Y * factor;\n        }\n\n        public static float Dot(Vector2 value1, Vector2 value2)\n        {\n            return value1.X * value2.X + value1.Y * value2.Y;\n        }\n\n        public static void Dot(ref Vector2 value1, ref Vector2 value2, out float result)\n        {\n            result = value1.X * value2.X + value1.Y * value2.Y;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return (obj is Vector2) ? this == ((Vector2)obj) : false;\n        }\n\n        public bool Equals(Vector2 other)\n        {\n            return this == other;\n        }\n\n        public override int GetHashCode()\n        {\n            return (int)(X + Y);\n        }\n\n        public static Vector2 Hermite(Vector2 value1, Vector2 tangent1, Vector2 value2, Vector2 tangent2, float amount)\n        {\n            Vector2 result = new Vector2();\n            Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);\n            return result;\n        }\n\n        public static void Hermite(ref Vector2 value1, ref Vector2 tangent1, ref Vector2 value2, ref Vector2 tangent2,\n                                   float amount, out Vector2 result)\n        {\n            result.X = MathHelper.Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);\n            result.Y = MathHelper.Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);\n        }\n\n        public float Length()\n        {\n            float result;\n            DistanceSquared(ref this, ref zeroVector, out result);\n            return (float)Math.Sqrt(result);\n        }\n\n        public float LengthSquared()\n        {\n            float result;\n            DistanceSquared(ref this, ref zeroVector, out result);\n            return result;\n        }\n\n        public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount)\n        {\n            return new Vector2(\n                MathHelper.Lerp(value1.X, value2.X, amount),\n                MathHelper.Lerp(value1.Y, value2.Y, amount));\n        }\n\n        public static void Lerp(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.Lerp(value1.X, value2.X, amount),\n                MathHelper.Lerp(value1.Y, value2.Y, amount));\n        }\n\n        public static Vector2 Max(Vector2 value1, Vector2 value2)\n        {\n            return new Vector2(\n                MathHelper.Max(value1.X, value2.X),\n                MathHelper.Max(value1.Y, value2.Y));\n        }\n\n        public static void Max(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.Max(value1.X, value2.X),\n                MathHelper.Max(value1.Y, value2.Y));\n        }\n\n        public static Vector2 Min(Vector2 value1, Vector2 value2)\n        {\n            return new Vector2(\n                MathHelper.Min(value1.X, value2.X),\n                MathHelper.Min(value1.Y, value2.Y));\n        }\n\n        public static void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.Min(value1.X, value2.X),\n                MathHelper.Min(value1.Y, value2.Y));\n        }\n\n        public static Vector2 Multiply(Vector2 value1, Vector2 value2)\n        {\n            value1.X *= value2.X;\n            value1.Y *= value2.Y;\n            return value1;\n        }\n\n        public static Vector2 Multiply(Vector2 value1, float scaleFactor)\n        {\n            value1.X *= scaleFactor;\n            value1.Y *= scaleFactor;\n            return value1;\n        }\n\n        public static void Multiply(ref Vector2 value1, float scaleFactor, out Vector2 result)\n        {\n            result.X = value1.X * scaleFactor;\n            result.Y = value1.Y * scaleFactor;\n        }\n\n        public static void Multiply(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result.X = value1.X * value2.X;\n            result.Y = value1.Y * value2.Y;\n        }\n\n        public static Vector2 Negate(Vector2 value)\n        {\n            value.X = -value.X;\n            value.Y = -value.Y;\n            return value;\n        }\n\n        public static void Negate(ref Vector2 value, out Vector2 result)\n        {\n            result.X = -value.X;\n            result.Y = -value.Y;\n        }\n\n        public void Normalize()\n        {\n            Normalize(ref this, out this);\n        }\n\n        public static Vector2 Normalize(Vector2 value)\n        {\n            Normalize(ref value, out value);\n            return value;\n        }\n\n        public static void Normalize(ref Vector2 value, out Vector2 result)\n        {\n            float factor;\n            DistanceSquared(ref value, ref zeroVector, out factor);\n            factor = 1f / (float)Math.Sqrt(factor);\n            result.X = value.X * factor;\n            result.Y = value.Y * factor;\n        }\n\n        public static Vector2 SmoothStep(Vector2 value1, Vector2 value2, float amount)\n        {\n            return new Vector2(\n                MathHelper.SmoothStep(value1.X, value2.X, amount),\n                MathHelper.SmoothStep(value1.Y, value2.Y, amount));\n        }\n\n        public static void SmoothStep(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)\n        {\n            result = new Vector2(\n                MathHelper.SmoothStep(value1.X, value2.X, amount),\n                MathHelper.SmoothStep(value1.Y, value2.Y, amount));\n        }\n\n        public static Vector2 Subtract(Vector2 value1, Vector2 value2)\n        {\n            value1.X -= value2.X;\n            value1.Y -= value2.Y;\n            return value1;\n        }\n\n        public static void Subtract(ref Vector2 value1, ref Vector2 value2, out Vector2 result)\n        {\n            result.X = value1.X - value2.X;\n            result.Y = value1.Y - value2.Y;\n        }\n\n        public static Vector2 Transform(Vector2 position, Matrix matrix)\n        {\n            Transform(ref position, ref matrix, out position);\n            return position;\n        }\n\n        public static void Transform(ref Vector2 position, ref Matrix matrix, out Vector2 result)\n        {\n            result = new Vector2((position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41,\n                                 (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42);\n        }\n\n        public static void Transform(Vector2[] sourceArray, ref Matrix matrix, Vector2[] destinationArray)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static void Transform(Vector2[] sourceArray, int sourceIndex, ref Matrix matrix,\n                                     Vector2[] destinationArray, int destinationIndex, int length)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static Vector2 TransformNormal(Vector2 normal, Matrix matrix)\n        {\n            TransformNormal(ref normal, ref matrix, out normal);\n            return normal;\n        }\n\n        public static void TransformNormal(ref Vector2 normal, ref Matrix matrix, out Vector2 result)\n        {\n            result = new Vector2((normal.X * matrix.M11) + (normal.Y * matrix.M21),\n                                 (normal.X * matrix.M12) + (normal.Y * matrix.M22));\n        }\n\n        public static void TransformNormal(Vector2[] sourceArray, ref Matrix matrix, Vector2[] destinationArray)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static void TransformNormal(Vector2[] sourceArray, int sourceIndex, ref Matrix matrix,\n                                           Vector2[] destinationArray, int destinationIndex, int length)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder(24);\n            sb.Append(\"{X:\");\n            sb.Append(X);\n            sb.Append(\" Y:\");\n            sb.Append(Y);\n            sb.Append(\"}\");\n            return sb.ToString();\n        }\n\n        #endregion Public Methods\n\n        #region Operators\n\n        public static Vector2 operator -(Vector2 value)\n        {\n            value.X = -value.X;\n            value.Y = -value.Y;\n            return value;\n        }\n\n\n        public static bool operator ==(Vector2 value1, Vector2 value2)\n        {\n            return value1.X == value2.X && value1.Y == value2.Y;\n        }\n\n\n        public static bool operator !=(Vector2 value1, Vector2 value2)\n        {\n            return value1.X != value2.X || value1.Y != value2.Y;\n        }\n\n\n        public static Vector2 operator +(Vector2 value1, Vector2 value2)\n        {\n            value1.X += value2.X;\n            value1.Y += value2.Y;\n            return value1;\n        }\n\n\n        public static Vector2 operator -(Vector2 value1, Vector2 value2)\n        {\n            value1.X -= value2.X;\n            value1.Y -= value2.Y;\n            return value1;\n        }\n\n\n        public static Vector2 operator *(Vector2 value1, Vector2 value2)\n        {\n            value1.X *= value2.X;\n            value1.Y *= value2.Y;\n            return value1;\n        }\n\n\n        public static Vector2 operator *(Vector2 value, float scaleFactor)\n        {\n            value.X *= scaleFactor;\n            value.Y *= scaleFactor;\n            return value;\n        }\n\n\n        public static Vector2 operator *(float scaleFactor, Vector2 value)\n        {\n            value.X *= scaleFactor;\n            value.Y *= scaleFactor;\n            return value;\n        }\n\n\n        public static Vector2 operator /(Vector2 value1, Vector2 value2)\n        {\n            value1.X /= value2.X;\n            value1.Y /= value2.Y;\n            return value1;\n        }\n\n\n        public static Vector2 operator /(Vector2 value1, float divider)\n        {\n            float factor = 1 / divider;\n            value1.X *= factor;\n            value1.Y *= factor;\n            return value1;\n        }\n\n        #endregion Operators\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Primitives/Vector3.cs",
    "content": "﻿#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID && !MONOGAME\n\n#region License\n\n/*\nMIT License\nCopyright © 2006 The Mono.Xna Team\n\nAll rights reserved.\n\nAuthors:\n * Alan McGovern\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#endregion License\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Microsoft.Xna.Framework\n{\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Vector3 : IEquatable<Vector3>\n    {\n        #region Private Fields\n\n        private static Vector3 zero = new Vector3(0f, 0f, 0f);\n        private static Vector3 one = new Vector3(1f, 1f, 1f);\n        private static Vector3 unitX = new Vector3(1f, 0f, 0f);\n        private static Vector3 unitY = new Vector3(0f, 1f, 0f);\n        private static Vector3 unitZ = new Vector3(0f, 0f, 1f);\n        private static Vector3 up = new Vector3(0f, 1f, 0f);\n        private static Vector3 down = new Vector3(0f, -1f, 0f);\n        private static Vector3 right = new Vector3(1f, 0f, 0f);\n        private static Vector3 left = new Vector3(-1f, 0f, 0f);\n        private static Vector3 forward = new Vector3(0f, 0f, -1f);\n        private static Vector3 backward = new Vector3(0f, 0f, 1f);\n\n        #endregion Private Fields\n\n        #region Public Fields\n\n        public float X;\n        public float Y;\n        public float Z;\n\n        #endregion Public Fields\n\n        #region Properties\n\n        public static Vector3 Zero\n        {\n            get { return zero; }\n        }\n\n        public static Vector3 One\n        {\n            get { return one; }\n        }\n\n        public static Vector3 UnitX\n        {\n            get { return unitX; }\n        }\n\n        public static Vector3 UnitY\n        {\n            get { return unitY; }\n        }\n\n        public static Vector3 UnitZ\n        {\n            get { return unitZ; }\n        }\n\n        public static Vector3 Up\n        {\n            get { return up; }\n        }\n\n        public static Vector3 Down\n        {\n            get { return down; }\n        }\n\n        public static Vector3 Right\n        {\n            get { return right; }\n        }\n\n        public static Vector3 Left\n        {\n            get { return left; }\n        }\n\n        public static Vector3 Forward\n        {\n            get { return forward; }\n        }\n\n        public static Vector3 Backward\n        {\n            get { return backward; }\n        }\n\n        #endregion Properties\n\n        #region Constructors\n\n        public Vector3(float x, float y, float z)\n        {\n            X = x;\n            Y = y;\n            Z = z;\n        }\n\n\n        public Vector3(float value)\n        {\n            X = value;\n            Y = value;\n            Z = value;\n        }\n\n\n        public Vector3(Vector2 value, float z)\n        {\n            X = value.X;\n            Y = value.Y;\n            Z = z;\n        }\n\n        #endregion Constructors\n\n        #region Public Methods\n\n        public static Vector3 Add(Vector3 value1, Vector3 value2)\n        {\n            value1.X += value2.X;\n            value1.Y += value2.Y;\n            value1.Z += value2.Z;\n            return value1;\n        }\n\n        public static void Add(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result.X = value1.X + value2.X;\n            result.Y = value1.Y + value2.Y;\n            result.Z = value1.Z + value2.Z;\n        }\n\n        public static Vector3 Barycentric(Vector3 value1, Vector3 value2, Vector3 value3, float amount1, float amount2)\n        {\n            return new Vector3(\n                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),\n                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),\n                MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));\n        }\n\n        public static void Barycentric(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, float amount1,\n                                       float amount2, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),\n                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),\n                MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));\n        }\n\n        public static Vector3 CatmullRom(Vector3 value1, Vector3 value2, Vector3 value3, Vector3 value4, float amount)\n        {\n            return new Vector3(\n                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),\n                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),\n                MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));\n        }\n\n        public static void CatmullRom(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, ref Vector3 value4,\n                                      float amount, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),\n                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),\n                MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));\n        }\n\n        public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max)\n        {\n            return new Vector3(\n                MathHelper.Clamp(value1.X, min.X, max.X),\n                MathHelper.Clamp(value1.Y, min.Y, max.Y),\n                MathHelper.Clamp(value1.Z, min.Z, max.Z));\n        }\n\n        public static void Clamp(ref Vector3 value1, ref Vector3 min, ref Vector3 max, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.Clamp(value1.X, min.X, max.X),\n                MathHelper.Clamp(value1.Y, min.Y, max.Y),\n                MathHelper.Clamp(value1.Z, min.Z, max.Z));\n        }\n\n        public static Vector3 Cross(Vector3 vector1, Vector3 vector2)\n        {\n            Cross(ref vector1, ref vector2, out vector1);\n            return vector1;\n        }\n\n        public static void Cross(ref Vector3 vector1, ref Vector3 vector2, out Vector3 result)\n        {\n            result = new Vector3(vector1.Y * vector2.Z - vector2.Y * vector1.Z,\n                                 -(vector1.X * vector2.Z - vector2.X * vector1.Z),\n                                 vector1.X * vector2.Y - vector2.X * vector1.Y);\n        }\n\n        public static float Distance(Vector3 vector1, Vector3 vector2)\n        {\n            float result;\n            DistanceSquared(ref vector1, ref vector2, out result);\n            return (float)Math.Sqrt(result);\n        }\n\n        public static void Distance(ref Vector3 value1, ref Vector3 value2, out float result)\n        {\n            DistanceSquared(ref value1, ref value2, out result);\n            result = (float)Math.Sqrt(result);\n        }\n\n        public static float DistanceSquared(Vector3 value1, Vector3 value2)\n        {\n            float result;\n            DistanceSquared(ref value1, ref value2, out result);\n            return result;\n        }\n\n        public static void DistanceSquared(ref Vector3 value1, ref Vector3 value2, out float result)\n        {\n            result = (value1.X - value2.X) * (value1.X - value2.X) +\n                     (value1.Y - value2.Y) * (value1.Y - value2.Y) +\n                     (value1.Z - value2.Z) * (value1.Z - value2.Z);\n        }\n\n        public static Vector3 Divide(Vector3 value1, Vector3 value2)\n        {\n            value1.X /= value2.X;\n            value1.Y /= value2.Y;\n            value1.Z /= value2.Z;\n            return value1;\n        }\n\n        public static Vector3 Divide(Vector3 value1, float value2)\n        {\n            float factor = 1 / value2;\n            value1.X *= factor;\n            value1.Y *= factor;\n            value1.Z *= factor;\n            return value1;\n        }\n\n        public static void Divide(ref Vector3 value1, float divisor, out Vector3 result)\n        {\n            float factor = 1 / divisor;\n            result.X = value1.X * factor;\n            result.Y = value1.Y * factor;\n            result.Z = value1.Z * factor;\n        }\n\n        public static void Divide(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result.X = value1.X / value2.X;\n            result.Y = value1.Y / value2.Y;\n            result.Z = value1.Z / value2.Z;\n        }\n\n        public static float Dot(Vector3 vector1, Vector3 vector2)\n        {\n            return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;\n        }\n\n        public static void Dot(ref Vector3 vector1, ref Vector3 vector2, out float result)\n        {\n            result = vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return (obj is Vector3) ? this == (Vector3)obj : false;\n        }\n\n        public bool Equals(Vector3 other)\n        {\n            return this == other;\n        }\n\n        public override int GetHashCode()\n        {\n            return (int)(X + Y + Z);\n        }\n\n        public static Vector3 Hermite(Vector3 value1, Vector3 tangent1, Vector3 value2, Vector3 tangent2, float amount)\n        {\n            Vector3 result = new Vector3();\n            Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);\n            return result;\n        }\n\n        public static void Hermite(ref Vector3 value1, ref Vector3 tangent1, ref Vector3 value2, ref Vector3 tangent2,\n                                   float amount, out Vector3 result)\n        {\n            result.X = MathHelper.Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);\n            result.Y = MathHelper.Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);\n            result.Z = MathHelper.Hermite(value1.Z, tangent1.Z, value2.Z, tangent2.Z, amount);\n        }\n\n        public float Length()\n        {\n            float result;\n            DistanceSquared(ref this, ref zero, out result);\n            return (float)Math.Sqrt(result);\n        }\n\n        public float LengthSquared()\n        {\n            float result;\n            DistanceSquared(ref this, ref zero, out result);\n            return result;\n        }\n\n        public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount)\n        {\n            return new Vector3(\n                MathHelper.Lerp(value1.X, value2.X, amount),\n                MathHelper.Lerp(value1.Y, value2.Y, amount),\n                MathHelper.Lerp(value1.Z, value2.Z, amount));\n        }\n\n        public static void Lerp(ref Vector3 value1, ref Vector3 value2, float amount, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.Lerp(value1.X, value2.X, amount),\n                MathHelper.Lerp(value1.Y, value2.Y, amount),\n                MathHelper.Lerp(value1.Z, value2.Z, amount));\n        }\n\n        public static Vector3 Max(Vector3 value1, Vector3 value2)\n        {\n            return new Vector3(\n                MathHelper.Max(value1.X, value2.X),\n                MathHelper.Max(value1.Y, value2.Y),\n                MathHelper.Max(value1.Z, value2.Z));\n        }\n\n        public static void Max(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.Max(value1.X, value2.X),\n                MathHelper.Max(value1.Y, value2.Y),\n                MathHelper.Max(value1.Z, value2.Z));\n        }\n\n        public static Vector3 Min(Vector3 value1, Vector3 value2)\n        {\n            return new Vector3(\n                MathHelper.Min(value1.X, value2.X),\n                MathHelper.Min(value1.Y, value2.Y),\n                MathHelper.Min(value1.Z, value2.Z));\n        }\n\n        public static void Min(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.Min(value1.X, value2.X),\n                MathHelper.Min(value1.Y, value2.Y),\n                MathHelper.Min(value1.Z, value2.Z));\n        }\n\n        public static Vector3 Multiply(Vector3 value1, Vector3 value2)\n        {\n            value1.X *= value2.X;\n            value1.Y *= value2.Y;\n            value1.Z *= value2.Z;\n            return value1;\n        }\n\n        public static Vector3 Multiply(Vector3 value1, float scaleFactor)\n        {\n            value1.X *= scaleFactor;\n            value1.Y *= scaleFactor;\n            value1.Z *= scaleFactor;\n            return value1;\n        }\n\n        public static void Multiply(ref Vector3 value1, float scaleFactor, out Vector3 result)\n        {\n            result.X = value1.X * scaleFactor;\n            result.Y = value1.Y * scaleFactor;\n            result.Z = value1.Z * scaleFactor;\n        }\n\n        public static void Multiply(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result.X = value1.X * value2.X;\n            result.Y = value1.Y * value2.Y;\n            result.Z = value1.Z * value2.Z;\n        }\n\n        public static Vector3 Negate(Vector3 value)\n        {\n            value = new Vector3(-value.X, -value.Y, -value.Z);\n            return value;\n        }\n\n        public static void Negate(ref Vector3 value, out Vector3 result)\n        {\n            result = new Vector3(-value.X, -value.Y, -value.Z);\n        }\n\n        public void Normalize()\n        {\n            Normalize(ref this, out this);\n        }\n\n        public static Vector3 Normalize(Vector3 vector)\n        {\n            Normalize(ref vector, out vector);\n            return vector;\n        }\n\n        public static void Normalize(ref Vector3 value, out Vector3 result)\n        {\n            float factor;\n            Distance(ref value, ref zero, out factor);\n            factor = 1f / factor;\n            result.X = value.X * factor;\n            result.Y = value.Y * factor;\n            result.Z = value.Z * factor;\n        }\n\n        public static Vector3 Reflect(Vector3 vector, Vector3 normal)\n        {\n            Vector3 result;\n            Reflect(ref vector, ref normal, out result);\n            return result;\n        }\n\n        public static void Reflect(ref Vector3 vector, ref Vector3 normal, out Vector3 result)\n        {\n            float dot = Dot(vector, normal);\n            result.X = vector.X - ((2f * dot) * normal.X);\n            result.Y = vector.Y - ((2f * dot) * normal.Y);\n            result.Z = vector.Z - ((2f * dot) * normal.Z);\n        }\n\n        public static Vector3 SmoothStep(Vector3 value1, Vector3 value2, float amount)\n        {\n            return new Vector3(\n                MathHelper.SmoothStep(value1.X, value2.X, amount),\n                MathHelper.SmoothStep(value1.Y, value2.Y, amount),\n                MathHelper.SmoothStep(value1.Z, value2.Z, amount));\n        }\n\n        public static void SmoothStep(ref Vector3 value1, ref Vector3 value2, float amount, out Vector3 result)\n        {\n            result = new Vector3(\n                MathHelper.SmoothStep(value1.X, value2.X, amount),\n                MathHelper.SmoothStep(value1.Y, value2.Y, amount),\n                MathHelper.SmoothStep(value1.Z, value2.Z, amount));\n        }\n\n        public static Vector3 Subtract(Vector3 value1, Vector3 value2)\n        {\n            value1.X -= value2.X;\n            value1.Y -= value2.Y;\n            value1.Z -= value2.Z;\n            return value1;\n        }\n\n        public static void Subtract(ref Vector3 value1, ref Vector3 value2, out Vector3 result)\n        {\n            result.X = value1.X - value2.X;\n            result.Y = value1.Y - value2.Y;\n            result.Z = value1.Z - value2.Z;\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder(32);\n            sb.Append(\"{X:\");\n            sb.Append(X);\n            sb.Append(\" Y:\");\n            sb.Append(Y);\n            sb.Append(\" Z:\");\n            sb.Append(Z);\n            sb.Append(\"}\");\n            return sb.ToString();\n        }\n\n        public static Vector3 Transform(Vector3 position, Matrix matrix)\n        {\n            Transform(ref position, ref matrix, out position);\n            return position;\n        }\n\n        public static void Transform(ref Vector3 position, ref Matrix matrix, out Vector3 result)\n        {\n            result =\n                new Vector3((position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31) + matrix.M41,\n                            (position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32) + matrix.M42,\n                            (position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33) + matrix.M43);\n        }\n\n        public static void Transform(Vector3[] sourceArray, ref Matrix matrix, Vector3[] destinationArray)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static void Transform(Vector3[] sourceArray, int sourceIndex, ref Matrix matrix,\n                                     Vector3[] destinationArray, int destinationIndex, int length)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static void TransformNormal(Vector3[] sourceArray, ref Matrix matrix, Vector3[] destinationArray)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static void TransformNormal(Vector3[] sourceArray, int sourceIndex, ref Matrix matrix,\n                                           Vector3[] destinationArray, int destinationIndex, int length)\n        {\n            throw new NotImplementedException();\n        }\n\n        public static Vector3 TransformNormal(Vector3 normal, Matrix matrix)\n        {\n            TransformNormal(ref normal, ref matrix, out normal);\n            return normal;\n        }\n\n        public static void TransformNormal(ref Vector3 normal, ref Matrix matrix, out Vector3 result)\n        {\n            result = new Vector3((normal.X * matrix.M11) + (normal.Y * matrix.M21) + (normal.Z * matrix.M31),\n                                 (normal.X * matrix.M12) + (normal.Y * matrix.M22) + (normal.Z * matrix.M32),\n                                 (normal.X * matrix.M13) + (normal.Y * matrix.M23) + (normal.Z * matrix.M33));\n        }\n\n        #endregion Public methods\n\n        #region Operators\n\n        public static bool operator ==(Vector3 value1, Vector3 value2)\n        {\n            return value1.X == value2.X\n                   && value1.Y == value2.Y\n                   && value1.Z == value2.Z;\n        }\n\n        public static bool operator !=(Vector3 value1, Vector3 value2)\n        {\n            return !(value1 == value2);\n        }\n\n        public static Vector3 operator +(Vector3 value1, Vector3 value2)\n        {\n            value1.X += value2.X;\n            value1.Y += value2.Y;\n            value1.Z += value2.Z;\n            return value1;\n        }\n\n        public static Vector3 operator -(Vector3 value)\n        {\n            value = new Vector3(-value.X, -value.Y, -value.Z);\n            return value;\n        }\n\n        public static Vector3 operator -(Vector3 value1, Vector3 value2)\n        {\n            value1.X -= value2.X;\n            value1.Y -= value2.Y;\n            value1.Z -= value2.Z;\n            return value1;\n        }\n\n        public static Vector3 operator *(Vector3 value1, Vector3 value2)\n        {\n            value1.X *= value2.X;\n            value1.Y *= value2.Y;\n            value1.Z *= value2.Z;\n            return value1;\n        }\n\n        public static Vector3 operator *(Vector3 value, float scaleFactor)\n        {\n            value.X *= scaleFactor;\n            value.Y *= scaleFactor;\n            value.Z *= scaleFactor;\n            return value;\n        }\n\n        public static Vector3 operator *(float scaleFactor, Vector3 value)\n        {\n            value.X *= scaleFactor;\n            value.Y *= scaleFactor;\n            value.Z *= scaleFactor;\n            return value;\n        }\n\n        public static Vector3 operator /(Vector3 value1, Vector3 value2)\n        {\n            value1.X /= value2.X;\n            value1.Y /= value2.Y;\n            value1.Z /= value2.Z;\n            return value1;\n        }\n\n        public static Vector3 operator /(Vector3 value, float divider)\n        {\n            float factor = 1 / divider;\n            value.X *= factor;\n            value.Y *= factor;\n            value.Z *= factor;\n            return value;\n        }\n\n        #endregion\n    }\n}\n\n#endif"
  },
  {
    "path": "VelcroPhysics/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"VelcroPhysics.ContentPipeline.SVGImport\")]"
  },
  {
    "path": "VelcroPhysics/README.md",
    "content": "# Velcro Physics engine\n\n**This code is mostly written by other people (not @egordorichev)**\nThis is a slightly modified Velcro Physics engine (Box2d rewritten in C#), I've experienced some edge-case bugs,\nthat I had to patch by hand."
  },
  {
    "path": "VelcroPhysics/Settings.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing VelcroPhysics.Collision.Filtering;\n\nnamespace VelcroPhysics\n{\n    public static class Settings\n    {\n        public const float MaxFloat = float.MaxValue;\n        public const float Epsilon = 1.192092896e-07f;\n        public const float Pi = 3.14159265359f;\n\n        // Common\n\n        /// <summary>\n        /// Enabling diagnostics causes the engine to gather timing information.\n        /// You can see how much time it took to solve the contacts, solve CCD\n        /// and update the controllers.\n        /// NOTE: If you are using a debug view that shows performance counters,\n        /// you might want to enable this.\n        /// </summary>\n        public const bool EnableDiagnostics = true;\n\n        /// <summary>\n        /// Set this to true to skip sanity checks in the engine. This will speed up the\n        /// tools by removing the overhead of the checks, but you will need to handle checks\n        /// yourself where it is needed.\n        /// </summary>\n        public const bool SkipSanityChecks = false;\n\n        /// <summary>\n        /// Maximum number of sub-steps per contact in continuous physics simulation.\n        /// </summary>\n        public const int MaxSubSteps = 8;\n\n        /// <summary>\n        /// Enable/Disable warm-starting\n        /// </summary>\n        public const bool EnableWarmstarting = true;\n\n        /// <summary>\n        /// The maximum number of contact points between two convex shapes.\n        /// DO NOT CHANGE THIS VALUE!\n        /// </summary>\n        public const int MaxManifoldPoints = 2;\n\n        /// <summary>\n        /// This is used to fatten AABBs in the dynamic tree. This allows proxies\n        /// to move by a small amount without triggering a tree adjustment.\n        /// This is in meters.\n        /// </summary>\n        public const float AABBExtension = 0.1f;\n\n        /// <summary>\n        /// This is used to fatten AABBs in the dynamic tree. This is used to predict\n        /// the future position based on the current displacement.\n        /// This is a dimensionless multiplier.\n        /// </summary>\n        public const float AABBMultiplier = 2.0f;\n\n        /// <summary>\n        /// A small length used as a collision and constraint tolerance. Usually it is\n        /// chosen to be numerically significant, but visually insignificant.\n        /// </summary>\n        public const float LinearSlop = 0.005f;\n\n        /// <summary>\n        /// A small angle used as a collision and constraint tolerance. Usually it is\n        /// chosen to be numerically significant, but visually insignificant.\n        /// </summary>\n        public const float AngularSlop = (2.0f / 180.0f * Pi);\n\n        /// <summary>\n        /// The radius of the polygon/edge shape skin. This should not be modified. Making\n        /// this smaller means polygons will have an insufficient buffer for continuous collision.\n        /// Making it larger may create artifacts for vertex collision.\n        /// </summary>\n        public const float PolygonRadius = (2.0f * LinearSlop);\n\n        // Dynamics\n\n        /// <summary>\n        /// Maximum number of contacts to be handled to solve a TOI impact.\n        /// </summary>\n        public const int MaxTOIContacts = 32;\n\n        /// <summary>\n        /// A velocity threshold for elastic collisions. Any collision with a relative linear\n        /// velocity below this threshold will be treated as inelastic.\n        /// </summary>\n        public const float VelocityThreshold = 1.0f;\n\n        /// <summary>\n        /// The maximum linear position correction used when solving constraints. This helps to\n        /// prevent overshoot.\n        /// </summary>\n        public const float MaxLinearCorrection = 0.2f;\n\n        /// <summary>\n        /// The maximum angular position correction used when solving constraints. This helps to\n        /// prevent overshoot.\n        /// </summary>\n        public const float MaxAngularCorrection = (8.0f / 180.0f * Pi);\n\n        /// <summary>\n        /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so\n        /// that overlap is removed in one time step. However using values close to 1 often lead\n        /// to overshoot.\n        /// </summary>\n        public const float Baumgarte = 0.2f;\n\n        // Sleep\n        /// <summary>\n        /// The time that a body must be still before it will go to sleep.\n        /// </summary>\n        public const float TimeToSleep = 0.5f;\n\n        /// <summary>\n        /// A body cannot sleep if its linear velocity is above this tolerance.\n        /// </summary>\n        public const float LinearSleepTolerance = 0.01f;\n\n        /// <summary>\n        /// A body cannot sleep if its angular velocity is above this tolerance.\n        /// </summary>\n        public const float AngularSleepTolerance = (2.0f / 180.0f * Pi);\n\n        /// <summary>\n        /// The maximum linear velocity of a body. This limit is very large and is used\n        /// to prevent numerical problems. You shouldn't need to adjust this.\n        /// </summary>\n        public const float MaxTranslation = 2.0f;\n\n        public const float MaxTranslationSquared = (MaxTranslation * MaxTranslation);\n\n        /// <summary>\n        /// The maximum angular velocity of a body. This limit is very large and is used\n        /// to prevent numerical problems. You shouldn't need to adjust this.\n        /// </summary>\n        public const float MaxRotation = (0.5f * Pi);\n\n        public const float MaxRotationSquared = (MaxRotation * MaxRotation);\n\n        /// <summary>\n        /// Defines the maximum number of iterations made by the GJK algorithm.\n        /// </summary>\n        public const int MaxGJKIterations = 20;\n\n        /// <summary>\n        /// This is only for debugging the solver\n        /// </summary>\n        public const bool EnableSubStepping = false;\n\n        /// <summary>\n        /// By default, forces are cleared automatically after each call to Step.\n        /// The default behavior is modified with this setting.\n        /// The purpose of this setting is to support sub-stepping. Sub-stepping is often used to maintain\n        /// a fixed sized time step under a variable frame-rate.\n        /// When you perform sub-stepping you should disable auto clearing of forces and instead call\n        /// ClearForces after all sub-steps are complete in one pass of your game loop.\n        /// </summary>\n        public const bool AutoClearForces = true;\n\n        /// <summary>\n        /// The number of velocity iterations used in the solver.\n        /// </summary>\n        public static int VelocityIterations = 8;\n\n        /// <summary>\n        /// The number of position iterations used in the solver.\n        /// </summary>\n        public static int PositionIterations = 3;\n\n        /// <summary>\n        /// Enable/Disable Continuous Collision Detection (CCD)\n        /// </summary>\n        public static bool ContinuousPhysics = true;\n\n        /// <summary>\n        /// If true, it will run a GiftWrap convex hull on all polygon inputs.\n        /// This makes for a more stable engine when given random input,\n        /// but if speed of the creation of polygons are more important,\n        /// you might want to set this to false.\n        /// </summary>\n        public static bool UseConvexHullPolygons = true;\n\n        /// <summary>\n        /// The number of velocity iterations in the TOI solver\n        /// </summary>\n        public static int TOIVelocityIterations = VelocityIterations;\n\n        /// <summary>\n        /// The number of position iterations in the TOI solver\n        /// </summary>\n        public static int TOIPositionIterations = 20;\n\n        /// <summary>\n        /// Enable/Disable sleeping\n        /// </summary>\n        public static bool AllowSleep = true;\n\n        /// <summary>\n        /// The maximum number of vertices on a convex polygon.\n        /// </summary>\n        public static int MaxPolygonVertices = 8;\n\n        /// <summary>\n        /// Velcro Physics has a different way of filtering fixtures than Box2d.\n        /// We have both FPE and Box2D filtering in the engine. If you are upgrading\n        /// from earlier versions of FPE, set this to true and DefaultFixtureCollisionCategories\n        /// to Category.All.\n        /// </summary>\n        public static bool UseFPECollisionCategories;\n\n        /// <summary>\n        /// This is used by the Fixture constructor as the default value\n        /// for Fixture.CollisionCategories member. Note that you may need to change this depending\n        /// on the setting of UseFPECollisionCategories, above.\n        /// </summary>\n        public static Category DefaultFixtureCollisionCategories = Category.Cat1;\n\n        /// <summary>\n        /// This is used by the Fixture constructor as the default value\n        /// for Fixture.CollidesWith member.\n        /// </summary>\n        public static Category DefaultFixtureCollidesWith = Category.All;\n\n        /// <summary>\n        /// This is used by the Fixture constructor as the default value\n        /// for Fixture.IgnoreCCDWith member.\n        /// </summary>\n        public static Category DefaultFixtureIgnoreCCDWith = Category.None;\n\n        public const bool BlockSolve = true;\n\n        /// <summary>\n        /// Friction mixing law. Feel free to customize this.\n        /// </summary>\n        /// <param name=\"friction1\">The friction1.</param>\n        /// <param name=\"friction2\">The friction2.</param>\n        /// <returns></returns>\n        public static float MixFriction(float friction1, float friction2)\n        {\n            return (float)Math.Sqrt(friction1 * friction2);\n        }\n\n        /// <summary>\n        /// Restitution mixing law. Feel free to customize this.\n        /// </summary>\n        /// <param name=\"restitution1\">The restitution1.</param>\n        /// <param name=\"restitution2\">The restitution2.</param>\n        /// <returns></returns>\n        public static float MixRestitution(float restitution1, float restitution2)\n        {\n            return restitution1 > restitution2 ? restitution1 : restitution2;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/AABB.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.RayCast;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// An axis aligned bounding box.\n    /// </summary>\n    public struct AABB\n    {\n        /// <summary>\n        /// The lower vertex\n        /// </summary>\n        public Vector2 LowerBound;\n\n        /// <summary>\n        /// The upper vertex\n        /// </summary>\n        public Vector2 UpperBound;\n\n        public AABB(Vector2 min, Vector2 max)\n            : this(ref min, ref max) { }\n\n        public AABB(Vector2 center, float width, float height)\n            : this(center - new Vector2(width / 2, height / 2), center + new Vector2(width / 2, height / 2))\n        {\n        }\n\n        public AABB(ref Vector2 min, ref Vector2 max)\n        {\n            LowerBound = new Vector2(Math.Min(min.X, max.X), Math.Min(min.Y, max.Y));\n            UpperBound = new Vector2(Math.Max(min.X, max.X), Math.Max(min.Y, max.Y));\n        }\n\n        public float Width => UpperBound.X - LowerBound.X;\n\n        public float Height => UpperBound.Y - LowerBound.Y;\n\n        /// <summary>\n        /// Get the center of the AABB.\n        /// </summary>\n        public Vector2 Center => 0.5f * (LowerBound + UpperBound);\n\n        /// <summary>\n        /// Get the extents of the AABB (half-widths).\n        /// </summary>\n        public Vector2 Extents => 0.5f * (UpperBound - LowerBound);\n\n        /// <summary>\n        /// Get the perimeter length\n        /// </summary>\n        public float Perimeter\n        {\n            get\n            {\n                float wx = UpperBound.X - LowerBound.X;\n                float wy = UpperBound.Y - LowerBound.Y;\n                return 2.0f * (wx + wy);\n            }\n        }\n\n        /// <summary>\n        /// Gets the vertices of the AABB.\n        /// </summary>\n        /// <value>The corners of the AABB</value>\n        public Vertices Vertices\n        {\n            get\n            {\n                Vertices vertices = new Vertices(4);\n                vertices.Add(UpperBound);\n                vertices.Add(new Vector2(UpperBound.X, LowerBound.Y));\n                vertices.Add(LowerBound);\n                vertices.Add(new Vector2(LowerBound.X, UpperBound.Y));\n                return vertices;\n            }\n        }\n\n        /// <summary>\n        /// First quadrant\n        /// </summary>\n        public AABB Q1 => new AABB(Center, UpperBound);\n\n        /// <summary>\n        /// Second quadrant\n        /// </summary>\n        public AABB Q2 => new AABB(new Vector2(LowerBound.X, Center.Y), new Vector2(Center.X, UpperBound.Y));\n\n        /// <summary>\n        /// Third quadrant\n        /// </summary>\n        public AABB Q3 => new AABB(LowerBound, Center);\n\n        /// <summary>\n        /// Forth quadrant\n        /// </summary>\n        public AABB Q4 => new AABB(new Vector2(Center.X, LowerBound.Y), new Vector2(UpperBound.X, Center.Y));\n\n        /// <summary>\n        /// Verify that the bounds are sorted. And the bounds are valid numbers (not NaN).\n        /// </summary>\n        /// <returns>\n        /// <c>true</c> if this instance is valid; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsValid()\n        {\n            Vector2 d = UpperBound - LowerBound;\n            bool valid = d.X >= 0.0f && d.Y >= 0.0f;\n            return valid && LowerBound.IsValid() && UpperBound.IsValid();\n        }\n\n        /// <summary>\n        /// Combine an AABB into this one.\n        /// </summary>\n        /// <param name=\"aabb\">The AABB.</param>\n        public void Combine(ref AABB aabb)\n        {\n            LowerBound = Vector2.Min(LowerBound, aabb.LowerBound);\n            UpperBound = Vector2.Max(UpperBound, aabb.UpperBound);\n        }\n\n        /// <summary>\n        /// Combine two AABBs into this one.\n        /// </summary>\n        /// <param name=\"aabb1\">The aabb1.</param>\n        /// <param name=\"aabb2\">The aabb2.</param>\n        public void Combine(ref AABB aabb1, ref AABB aabb2)\n        {\n            LowerBound = Vector2.Min(aabb1.LowerBound, aabb2.LowerBound);\n            UpperBound = Vector2.Max(aabb1.UpperBound, aabb2.UpperBound);\n        }\n\n        /// <summary>\n        /// Does this AABB contain the provided AABB.\n        /// </summary>\n        /// <param name=\"aabb\">The AABB.</param>\n        /// <returns>\n        /// <c>true</c> if it contains the specified AABB; otherwise, <c>false</c>.\n        /// </returns>\n        public bool Contains(ref AABB aabb)\n        {\n            bool result = LowerBound.X <= aabb.LowerBound.X;\n            result = result && LowerBound.Y <= aabb.LowerBound.Y;\n            result = result && aabb.UpperBound.X <= UpperBound.X;\n            result = result && aabb.UpperBound.Y <= UpperBound.Y;\n            return result;\n        }\n\n        /// <summary>\n        /// Determines whether the AABB contains the specified point.\n        /// </summary>\n        /// <param name=\"point\">The point.</param>\n        /// <returns>\n        /// <c>true</c> if it contains the specified point; otherwise, <c>false</c>.\n        /// </returns>\n        public bool Contains(ref Vector2 point)\n        {\n            //using epsilon to try and guard against float rounding errors.\n            return (point.X > (LowerBound.X + float.Epsilon) && point.X < (UpperBound.X - float.Epsilon) &&\n                    (point.Y > (LowerBound.Y + float.Epsilon) && point.Y < (UpperBound.Y - float.Epsilon)));\n        }\n\n        /// <summary>\n        /// Test if the two AABBs overlap.\n        /// </summary>\n        /// <param name=\"a\">The first AABB.</param>\n        /// <param name=\"b\">The second AABB.</param>\n        /// <returns>True if they are overlapping.</returns>\n        public static bool TestOverlap(ref AABB a, ref AABB b)\n        {\n            Vector2 d1 = b.LowerBound - a.UpperBound;\n            Vector2 d2 = a.LowerBound - b.UpperBound;\n\n            return (d1.X <= 0) && (d1.Y <= 0) && (d2.X <= 0) && (d2.Y <= 0);\n        }\n\n        /// <summary>\n        /// Raycast against this AABB using the specified points and maxfraction (found in input)\n        /// </summary>\n        /// <param name=\"output\">The results of the raycast.</param>\n        /// <param name=\"input\">The parameters for the raycast.</param>\n        /// <returns>True if the ray intersects the AABB</returns>\n        public bool RayCast(out RayCastOutput output, ref RayCastInput input, bool doInteriorCheck = true)\n        {\n            // From Real-time Collision Detection, p179.\n\n            output = new RayCastOutput();\n\n            float tmin = -Settings.MaxFloat;\n            float tmax = Settings.MaxFloat;\n\n            Vector2 p = input.Point1;\n            Vector2 d = input.Point2 - input.Point1;\n            Vector2 absD = MathUtils.Abs(d);\n\n            Vector2 normal = Vector2.Zero;\n\n            for (int i = 0; i < 2; ++i)\n            {\n                float absD_i = i == 0 ? absD.X : absD.Y;\n                float lowerBound_i = i == 0 ? LowerBound.X : LowerBound.Y;\n                float upperBound_i = i == 0 ? UpperBound.X : UpperBound.Y;\n                float p_i = i == 0 ? p.X : p.Y;\n\n                if (absD_i < Settings.Epsilon)\n                {\n                    // Parallel.\n                    if (p_i < lowerBound_i || upperBound_i < p_i)\n                    {\n                        return false;\n                    }\n                }\n                else\n                {\n                    float d_i = i == 0 ? d.X : d.Y;\n\n                    float inv_d = 1.0f / d_i;\n                    float t1 = (lowerBound_i - p_i) * inv_d;\n                    float t2 = (upperBound_i - p_i) * inv_d;\n\n                    // Sign of the normal vector.\n                    float s = -1.0f;\n\n                    if (t1 > t2)\n                    {\n                        MathUtils.Swap(ref t1, ref t2);\n                        s = 1.0f;\n                    }\n\n                    // Push the min up\n                    if (t1 > tmin)\n                    {\n                        if (i == 0)\n                        {\n                            normal.X = s;\n                        }\n                        else\n                        {\n                            normal.Y = s;\n                        }\n\n                        tmin = t1;\n                    }\n\n                    // Pull the max down\n                    tmax = Math.Min(tmax, t2);\n\n                    if (tmin > tmax)\n                    {\n                        return false;\n                    }\n                }\n            }\n\n            // Does the ray start inside the box?\n            // Does the ray intersect beyond the max fraction?\n            if (doInteriorCheck && (tmin < 0.0f || input.MaxFraction < tmin))\n            {\n                return false;\n            }\n\n            // Intersection.\n            output.Fraction = tmin;\n            output.Normal = normal;\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Benchmark.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Shared\n{\n    public static class Benchmark\n    {\n        private static readonly Dictionary<string, long> _results = new Dictionary<string, long>();\n        private static readonly Pool<BenchmarkRun> _runPool = new Pool<BenchmarkRun>(() => new BenchmarkRun());\n\n        public static BenchmarkRun StartRun(string area)\n        {\n            BenchmarkRun run = _runPool.GetFromPool();\n            run.SetData(area);\n            return run;\n        }\n\n        public static void RecordResults(string area, long results)\n        {\n            if (!Settings.EnableDiagnostics)\n                return;\n\n            if (!_results.ContainsKey(area))\n                _results.Add(area, results);\n            else\n                _results[area] += results;\n        }\n\n        public static long ResetResults(string area)\n        {\n            if (!Settings.EnableDiagnostics)\n                return 0;\n\n            long oldVal = _results[area];\n            _results[area] = 0;\n            return oldVal;\n        }\n\n        public static long GetResults(string area)\n        {\n            if (!Settings.EnableDiagnostics)\n                return 0;\n\n            return _results.TryGetValue(area, out long value) ? value : 0;\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Shared/BenchmarkRun.cs",
    "content": "using System.Diagnostics;\nusing VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Shared\n{\n    public class BenchmarkRun : IPoolable<BenchmarkRun>\n    {\n        private string _area;\n        private readonly Stopwatch _stopwatch = new Stopwatch();\n        private bool _resultsRecorded;\n\n        public void SetData(string area)\n        {\n            _area = area;\n            _stopwatch.Start();\n        }\n\n        public void Dispose()\n        {\n            RecordResults();\n            Pool.ReturnToPool(this);\n        }\n\n        public void RecordResults()\n        {\n            if (_resultsRecorded)\n                return;\n\n            _stopwatch.Stop();\n            Benchmark.RecordResults(_area, _stopwatch.ElapsedTicks);\n            _resultsRecorded = true;\n        }\n\n        public void Reset()\n        {\n            _stopwatch.Reset();\n        }\n\n        public Pool<BenchmarkRun> Pool { private get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Contracts/Contract.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n\nnamespace VelcroPhysics.Shared.Contracts\n{\n    public static class Contract\n    {\n        [Conditional(\"DEBUG\")]\n        public static void Requires(bool condition, string message)\n        {\n            if (condition)\n                return;\n\n            message = BuildMessage(\"REQUIRED\", message);\n            throw new RequiredException(message);\n        }\n\n        [Conditional(\"DEBUG\")]\n        public static void Warn(bool condition, string message)\n        {\n            message = BuildMessage(\"WARNING\", message);\n            Debug.WriteLineIf(!condition, message);\n        }\n\n        [Conditional(\"DEBUG\")]\n        public static void Ensures(bool condition, string message)\n        {\n            if (condition)\n                return;\n\n            message = BuildMessage(\"ENSURANCE\", message);\n            throw new EnsuresException(message);\n        }\n\n        [Conditional(\"DEBUG\")]\n        public static void RequireForAll<T>(IEnumerable<T> value, Predicate<T> check)\n        {\n            foreach (T item in value)\n            {\n                Requires(check(item), \"Failed on: \" + item);\n            }\n        }\n\n        [Conditional(\"DEBUG\")]\n        public static void Fail(string message)\n        {\n            message = BuildMessage(\"FAILURE\", message);\n            throw new RequiredException(message);\n        }\n\n        private static string BuildMessage(string type, string message)\n        {\n            string stackTrace = string.Join(Environment.NewLine, Environment.StackTrace.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Skip(3));\n            return message == null ? string.Empty : type + \": \" + message + Environment.NewLine + stackTrace;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Contracts/EnsuresException.cs",
    "content": "﻿using System;\n\nnamespace VelcroPhysics.Shared.Contracts\n{\n    public class EnsuresException : Exception\n    {\n        public EnsuresException(string message) : base(message) { }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Contracts/RequiredException.cs",
    "content": "﻿using System;\n\nnamespace VelcroPhysics.Shared.Contracts\n{\n    public class RequiredException : Exception\n    {\n        public RequiredException(string message) : base(message) { }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Graph.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing VelcroPhysics.Shared.Contracts;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// This graph is a doubly linked circular list. It is circular to avoid branches in Add/Remove methods.\n    /// </summary>\n    public class Graph<T, T1> : IEnumerable<T>\n    {\n        private readonly EqualityComparer<T> _comparer;\n\n        public Graph()\n        {\n            _comparer = EqualityComparer<T>.Default;\n        }\n\n        public Graph(EqualityComparer<T> comparer)\n        {\n            Contract.Requires(comparer != null, \"You supplied a null comparer\");\n\n            _comparer = comparer;\n        }\n\n        /// <summary>\n        /// The number of items in the graph\n        /// </summary>\n        public int Count { get; private set; }\n\n        /// <summary>\n        /// The first node in the graph\n        /// </summary>\n        public GraphNode<T, T1> First { get; private set; }\n\n        /// <summary>\n        /// Add a value to the graph\n        /// </summary>\n        /// <remarks>Note that this method is O(n) in worst case.</remarks>\n        /// <returns>The node that represents the value</returns>\n        public GraphNode<T,T1> Add(T value)\n        {\n            GraphNode<T, T1> result = new GraphNode<T, T1>(value);\n            Add(result);\n            return result;\n        }\n\n        /// <summary>\n        /// Add a node to the graph\n        /// </summary>\n        /// <remarks>Note that this method is O(1) in worst case.</remarks>\n        public void Add(GraphNode<T, T1> node)\n        {\n            Contract.Requires(node != null, nameof(node) + \" must not be null\");\n\n            if (First == null)\n            {\n                node.Next = node;\n                node.Prev = node;\n                First = node;\n                Count++;\n            }\n            else\n            {\n                node.Next = First;\n                node.Prev = First.Prev;\n                First.Prev.Next = node;\n                First.Prev = node;\n                Count++;\n            }\n        }\n\n        /// <summary>\n        /// Check if the specified value is contained within the graph.\n        /// </summary>\n        /// <remarks>Note that this method is O(n) in worst case.</remarks>\n        /// <returns>True if it found the value, otherwise false.</returns>\n        public bool Contains(T value)\n        {\n            return Find(value) != null;\n        }\n\n        /// <summary>\n        /// Finds the specified value\n        /// </summary>\n        /// <remarks>Note that this method is O(n) in worst case.</remarks>\n        /// <returns>The graph node that was found if any. Otherwise it returns null.</returns>\n        public GraphNode<T, T1> Find(T value)\n        {\n            GraphNode<T, T1> node = First;\n\n            if (node == null)\n                return null;\n\n            if (value != null)\n            {\n                do\n                {\n                    if (_comparer.Equals(node.Item, value))\n                        return node;\n\n                    node = node.Next;\n                } while (node != First);\n            }\n            else\n            {\n                do\n                {\n                    if (node.Item == null)\n                        return node;\n\n                    node = node.Next;\n                } while (node != First);\n            }\n            return null;\n        }\n\n        public void Clear()\n        {\n            GraphNode<T, T1> node = First;\n\n            for (int i = 0; i < Count; i++)\n            {\n                GraphNode<T, T1> node0 = node;\n                node = node.Next;\n                node0.Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Remove the specified value\n        /// </summary>\n        /// <remarks>Note that this method is O(n) in worst case.</remarks>\n        /// <returns>True if the value was removed, otherwise false.</returns>\n        public bool Remove(T value)\n        {\n            GraphNode<T, T1> node = Find(value);\n\n            if (node == null)\n                return false;\n\n            Remove(node);\n            return true;\n        }\n\n        /// <summary>\n        /// Remove the specified node from the graph.\n        /// </summary>\n        /// <remarks>Note that this method is O(1) in worst case.</remarks>\n        public void Remove(GraphNode<T, T1> node)\n        {\n            Contract.Requires(node != null, nameof(node) + \" must not be null\");\n            Contract.Warn(First != null, \"You are trying to remove an item from an empty list.\");\n\n            //Invalid node\n            if (node.Next == null && node.Prev == null)\n                return;\n\n            if (node.Next == node)\n            {\n                First = null;\n            }\n            else\n            {\n                node.Next.Prev = node.Prev;\n                node.Prev.Next = node.Next;\n\n                if (First == node)\n                    First = node.Next;\n            }\n\n            node.Invalidate();\n            Count--;\n        }\n\n        public IEnumerator<T> GetEnumerator()\n        {\n            GraphNode<T, T1> node = First;\n\n            for (int i = 0; i < Count; i++)\n            {\n                GraphNode<T, T1> node0 = node;\n                node = node.Next;\n                yield return node0.Item;\n            }\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        public IEnumerable<GraphNode<T, T1>> GetNodes()\n        {\n            GraphNode<T, T1> node = First;\n\n            for (int i = 0; i < Count; i++)\n            {\n                GraphNode<T, T1> node0 = node;\n                node = node.Next;\n                yield return node0;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/GraphNode.cs",
    "content": "﻿namespace VelcroPhysics.Shared\n{\n    public class GraphNode<T, T1>\n    {\n        public GraphNode(T item = default(T))\n        {\n            Item = item;\n        }\n\n        /// <summary>\n        /// The item.\n        /// </summary>\n        public T Item { get; set; }\n\n        /// <summary>\n        /// The next item in the list.\n        /// </summary>\n        public GraphNode<T, T1> Next { get; set; }\n\n        /// <summary>\n        /// The previous item in the list.\n        /// </summary>\n        public GraphNode<T, T1> Prev { get; set; }\n\n        public T1 Other { get; set; }\n\n        internal void Invalidate()\n        {\n            Next = null;\n            Prev = null;\n        }\n\n        public void Clear()\n        {\n            Item = default(T);\n            Invalidate();\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Mat22.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// A 2-by-2 matrix. Stored in column-major order.\n    /// </summary>\n    public struct Mat22\n    {\n        public Vector2 ex, ey;\n\n        /// <summary>\n        /// Construct this matrix using columns.\n        /// </summary>\n        /// <param name=\"c1\">The c1.</param>\n        /// <param name=\"c2\">The c2.</param>\n        public Mat22(Vector2 c1, Vector2 c2)\n        {\n            ex = c1;\n            ey = c2;\n        }\n\n        /// <summary>\n        /// Construct this matrix using scalars.\n        /// </summary>\n        /// <param name=\"a11\">The a11.</param>\n        /// <param name=\"a12\">The a12.</param>\n        /// <param name=\"a21\">The a21.</param>\n        /// <param name=\"a22\">The a22.</param>\n        public Mat22(float a11, float a12, float a21, float a22)\n        {\n            ex = new Vector2(a11, a21);\n            ey = new Vector2(a12, a22);\n        }\n\n        public Mat22 Inverse\n        {\n            get\n            {\n                float a = ex.X, b = ey.X, c = ex.Y, d = ey.Y;\n                float det = a * d - b * c;\n                if (det != 0.0f)\n                {\n                    det = 1.0f / det;\n                }\n\n                Mat22 result = new Mat22();\n                result.ex.X = det * d;\n                result.ex.Y = -det * c;\n\n                result.ey.X = -det * b;\n                result.ey.Y = det * a;\n\n                return result;\n            }\n        }\n\n        /// <summary>\n        /// Initialize this matrix using columns.\n        /// </summary>\n        /// <param name=\"c1\">The c1.</param>\n        /// <param name=\"c2\">The c2.</param>\n        public void Set(Vector2 c1, Vector2 c2)\n        {\n            ex = c1;\n            ey = c2;\n        }\n\n        /// <summary>\n        /// Set this to the identity matrix.\n        /// </summary>\n        public void SetIdentity()\n        {\n            ex.X = 1.0f;\n            ey.X = 0.0f;\n            ex.Y = 0.0f;\n            ey.Y = 1.0f;\n        }\n\n        /// <summary>\n        /// Set this matrix to all zeros.\n        /// </summary>\n        public void SetZero()\n        {\n            ex.X = 0.0f;\n            ey.X = 0.0f;\n            ex.Y = 0.0f;\n            ey.Y = 0.0f;\n        }\n\n        /// <summary>\n        /// Solve A * x = b, where b is a column vector. This is more efficient\n        /// than computing the inverse in one-shot cases.\n        /// </summary>\n        /// <param name=\"b\">The b.</param>\n        /// <returns></returns>\n        public Vector2 Solve(Vector2 b)\n        {\n            float a11 = ex.X, a12 = ey.X, a21 = ex.Y, a22 = ey.Y;\n            float det = a11 * a22 - a12 * a21;\n            if (det != 0.0f)\n            {\n                det = 1.0f / det;\n            }\n\n            return new Vector2(det * (a22 * b.X - a12 * b.Y), det * (a11 * b.Y - a21 * b.X));\n        }\n\n        public static void Add(ref Mat22 A, ref Mat22 B, out Mat22 R)\n        {\n            R.ex = A.ex + B.ex;\n            R.ey = A.ey + B.ey;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Mat33.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// A 3-by-3 matrix. Stored in column-major order.\n    /// </summary>\n    public struct Mat33\n    {\n        public Vector3 ex, ey, ez;\n\n        /// <summary>\n        /// Construct this matrix using columns.\n        /// </summary>\n        /// <param name=\"c1\">The c1.</param>\n        /// <param name=\"c2\">The c2.</param>\n        /// <param name=\"c3\">The c3.</param>\n        public Mat33(Vector3 c1, Vector3 c2, Vector3 c3)\n        {\n            ex = c1;\n            ey = c2;\n            ez = c3;\n        }\n\n        /// <summary>\n        /// Set this matrix to all zeros.\n        /// </summary>\n        public void SetZero()\n        {\n            ex = Vector3.Zero;\n            ey = Vector3.Zero;\n            ez = Vector3.Zero;\n        }\n\n        /// <summary>\n        /// Solve A * x = b, where b is a column vector. This is more efficient\n        /// than computing the inverse in one-shot cases.\n        /// </summary>\n        /// <param name=\"b\">The b.</param>\n        /// <returns></returns>\n        public Vector3 Solve33(Vector3 b)\n        {\n            float det = Vector3.Dot(ex, Vector3.Cross(ey, ez));\n            if (det != 0.0f)\n            {\n                det = 1.0f / det;\n            }\n\n            return new Vector3(det * Vector3.Dot(b, Vector3.Cross(ey, ez)), det * Vector3.Dot(ex, Vector3.Cross(b, ez)), det * Vector3.Dot(ex, Vector3.Cross(ey, b)));\n        }\n\n        /// <summary>\n        /// Solve A * x = b, where b is a column vector. This is more efficient\n        /// than computing the inverse in one-shot cases. Solve only the upper\n        /// 2-by-2 matrix equation.\n        /// </summary>\n        /// <param name=\"b\">The b.</param>\n        /// <returns></returns>\n        public Vector2 Solve22(Vector2 b)\n        {\n            float a11 = ex.X, a12 = ey.X, a21 = ex.Y, a22 = ey.Y;\n            float det = a11 * a22 - a12 * a21;\n\n            if (det != 0.0f)\n            {\n                det = 1.0f / det;\n            }\n\n            return new Vector2(det * (a22 * b.X - a12 * b.Y), det * (a11 * b.Y - a21 * b.X));\n        }\n\n        /// Get the inverse of this matrix as a 2-by-2.\n        /// Returns the zero matrix if singular.\n        public void GetInverse22(ref Mat33 M)\n        {\n            float a = ex.X, b = ey.X, c = ex.Y, d = ey.Y;\n            float det = a * d - b * c;\n            if (det != 0.0f)\n            {\n                det = 1.0f / det;\n            }\n\n            M.ex.X = det * d;\n            M.ey.X = -det * b;\n            M.ex.Z = 0.0f;\n            M.ex.Y = -det * c;\n            M.ey.Y = det * a;\n            M.ey.Z = 0.0f;\n            M.ez.X = 0.0f;\n            M.ez.Y = 0.0f;\n            M.ez.Z = 0.0f;\n        }\n\n        /// Get the symmetric inverse of this matrix as a 3-by-3.\n        /// Returns the zero matrix if singular.\n        public void GetSymInverse33(ref Mat33 M)\n        {\n            float det = MathUtils.Dot(ex, MathUtils.Cross((Vector3)ey, ez));\n            if (det != 0.0f)\n            {\n                det = 1.0f / det;\n            }\n\n            float a11 = ex.X, a12 = ey.X, a13 = ez.X;\n            float a22 = ey.Y, a23 = ez.Y;\n            float a33 = ez.Z;\n\n            M.ex.X = det * (a22 * a33 - a23 * a23);\n            M.ex.Y = det * (a13 * a23 - a12 * a33);\n            M.ex.Z = det * (a12 * a23 - a13 * a22);\n\n            M.ey.X = M.ex.Y;\n            M.ey.Y = det * (a11 * a33 - a13 * a13);\n            M.ey.Z = det * (a13 * a12 - a11 * a23);\n\n            M.ez.X = M.ex.Z;\n            M.ez.Y = M.ey.Z;\n            M.ez.Z = det * (a11 * a22 - a12 * a12);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Optimization/FixedArray2.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Shared.Optimization\n{\n    public struct FixedArray2<T> : IEnumerable<T>\n    {\n        public T Value0, Value1;\n\n        public T this[int index]\n        {\n            get\n            {\n                switch (index)\n                {\n                    case 0:\n                        return Value0;\n                    case 1:\n                        return Value1;\n                    default:\n                        throw new IndexOutOfRangeException();\n                }\n            }\n            set\n            {\n                switch (index)\n                {\n                    case 0:\n                        Value0 = value;\n                        break;\n                    case 1:\n                        Value1 = value;\n                        break;\n                    default:\n                        throw new IndexOutOfRangeException();\n                }\n            }\n        }\n\n        public IEnumerator<T> GetEnumerator()\n        {\n            return Enumerate().GetEnumerator();\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        public int IndexOf(T value)\n        {\n            for (int i = 0; i < 2; ++i)\n                if (this[i].Equals(value))\n                    return i;\n            return -1;\n        }\n\n        public void Clear()\n        {\n            Value0 = Value1 = default(T);\n        }\n\n        private IEnumerable<T> Enumerate()\n        {\n            for (int i = 0; i < 2; ++i)\n                yield return this[i];\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Optimization/FixedArray3.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Shared.Optimization\n{\n    public struct FixedArray3<T> : IEnumerable<T>\n    {\n        public T Value0, Value1, Value2;\n\n        public T this[int index]\n        {\n            get\n            {\n                switch (index)\n                {\n                    case 0:\n                        return Value0;\n                    case 1:\n                        return Value1;\n                    case 2:\n                        return Value2;\n                    default:\n                        throw new IndexOutOfRangeException();\n                }\n            }\n            set\n            {\n                switch (index)\n                {\n                    case 0:\n                        Value0 = value;\n                        break;\n                    case 1:\n                        Value1 = value;\n                        break;\n                    case 2:\n                        Value2 = value;\n                        break;\n                    default:\n                        throw new IndexOutOfRangeException();\n                }\n            }\n        }\n\n        public IEnumerator<T> GetEnumerator()\n        {\n            return Enumerate().GetEnumerator();\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        public int IndexOf(T value)\n        {\n            for (int i = 0; i < 3; ++i)\n                if (this[i].Equals(value))\n                    return i;\n            return -1;\n        }\n\n        public void Clear()\n        {\n            Value0 = Value1 = Value2 = default(T);\n        }\n\n        private IEnumerable<T> Enumerate()\n        {\n            for (int i = 0; i < 3; ++i)\n                yield return this[i];\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Optimization/IPoolable.cs",
    "content": "﻿using System;\n\nnamespace VelcroPhysics.Shared.Optimization\n{\n    public interface IPoolable<T> : IDisposable where T : IPoolable<T>\n    {\n        void Reset();\n\n        Pool<T> Pool { set; }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Shared/PolygonError.cs",
    "content": "namespace VelcroPhysics.Shared\n{\n    public enum PolygonError\n    {\n        /// <summary>\n        /// There were no errors in the polygon\n        /// </summary>\n        NoError,\n\n        /// <summary>\n        /// Polygon must have between 3 and Settings.MaxPolygonVertices vertices.\n        /// </summary>\n        InvalidAmountOfVertices,\n\n        /// <summary>\n        /// Polygon must be simple. This means no overlapping edges.\n        /// </summary>\n        NotSimple,\n\n        /// <summary>\n        /// Polygon must have a counter clockwise winding.\n        /// </summary>\n        NotCounterClockWise,\n\n        /// <summary>\n        /// The polygon is concave, it needs to be convex.\n        /// </summary>\n        NotConvex,\n\n        /// <summary>\n        /// Polygon area is too small.\n        /// </summary>\n        AreaTooSmall,\n\n        /// <summary>\n        /// The polygon has a side that is too short.\n        /// </summary>\n        SideTooSmall\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Pool.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing VelcroPhysics.Shared.Optimization;\n\nnamespace VelcroPhysics.Shared\n{\n    public class Pool<T> where T : IPoolable<T>\n    {\n        private readonly Queue<T> _queue;\n        private readonly Func<T> _objectCreator;\n\n        public Pool(Func<T> objectCreator, int capacity = 16, bool preCreateInstances = true)\n        {\n            _objectCreator = objectCreator;\n            _queue = new Queue<T>(capacity);\n\n            if (!preCreateInstances)\n                return;\n\n            for (int i = 0; i < capacity; i++)\n            {\n                T obj = objectCreator();\n                obj.Pool = this;\n                _queue.Enqueue(obj);\n            }\n        }\n\n        public int LeftInPool => _queue.Count;\n\n        public T GetFromPool()\n        {\n            if (_queue.Count == 0)\n                return _objectCreator();\n\n            return _queue.Dequeue();\n        }\n\n        public IEnumerable<T> GetManyFromPool(int count)\n        {\n            Debug.Assert(count != 0);\n\n            for (int i = 0; i < count; i++)\n            {\n                yield return GetFromPool();\n            }\n        }\n\n        public void ReturnToPool(T obj)\n        {\n            obj.Reset();\n            _queue.Enqueue(obj);\n        }\n\n        public void ReturnToPool(IEnumerable<T> objs)\n        {\n            foreach (T obj in objs)\n            {\n                obj.Reset();\n                _queue.Enqueue(obj);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VelcroPhysics/Shared/Rot.cs",
    "content": "using System;\nusing Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// Rotation\n    /// </summary>\n    public struct Rot\n    {\n        /// Sine and cosine\n        public float s,\n                     c;\n\n        /// <summary>\n        /// Initialize from an angle in radians\n        /// </summary>\n        /// <param name=\"angle\">Angle in radians</param>\n        public Rot(float angle)\n        {\n            // TODO_ERIN optimize\n            s = (float)Math.Sin(angle);\n            c = (float)Math.Cos(angle);\n        }\n\n        /// <summary>\n        /// Set using an angle in radians.\n        /// </summary>\n        /// <param name=\"angle\"></param>\n        public void Set(float angle)\n        {\n            //Velcro: Optimization\n            if (angle == 0)\n            {\n                s = 0;\n                c = 1;\n            }\n            else\n            {\n                // TODO_ERIN optimize\n                s = (float)Math.Sin(angle);\n                c = (float)Math.Cos(angle);\n            }\n        }\n\n        /// <summary>\n        /// Set to the identity rotation\n        /// </summary>\n        public void SetIdentity()\n        {\n            s = 0.0f;\n            c = 1.0f;\n        }\n\n        /// <summary>\n        /// Get the angle in radians\n        /// </summary>\n        public float GetAngle()\n        {\n            return (float)Math.Atan2(s, c);\n        }\n\n        /// <summary>\n        /// Get the x-axis\n        /// </summary>\n        public Vector2 GetXAxis()\n        {\n            return new Vector2(c, s);\n        }\n\n        /// <summary>\n        /// Get the y-axis\n        /// </summary>\n        public Vector2 GetYAxis()\n        {\n            return new Vector2(-s, c);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Transform.cs",
    "content": "using Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Shared\n{\n    /// <summary>\n    /// A transform contains translation and rotation. It is used to represent\n    /// the position and orientation of rigid frames.\n    /// </summary>\n    public struct Transform\n    {\n        public Vector2 p;\n        public Rot q;\n\n        /// <summary>\n        /// Initialize using a position vector and a rotation matrix.\n        /// </summary>\n        /// <param name=\"position\">The position.</param>\n        /// <param name=\"rotation\">The r.</param>\n        public Transform(ref Vector2 position, ref Rot rotation)\n        {\n            p = position;\n            q = rotation;\n        }\n\n        /// <summary>\n        /// Set this to the identity transform.\n        /// </summary>\n        public void SetIdentity()\n        {\n            p = Vector2.Zero;\n            q.SetIdentity();\n        }\n\n        /// <summary>\n        /// Set this based on the position and angle.\n        /// </summary>\n        /// <param name=\"position\">The position.</param>\n        /// <param name=\"angle\">The angle.</param>\n        public void Set(Vector2 position, float angle)\n        {\n            p = position;\n            q.Set(angle);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Shared/Vertices.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Text;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Shared\n{\n    [DebuggerDisplay(\"Count = {Count} Vertices = {ToString()}\")]\n    public class Vertices : List<Vector2>\n    {\n        public Vertices() { }\n\n        public Vertices(int capacity) : base(capacity) { }\n\n        public Vertices(IEnumerable<Vector2> vertices)\n        {\n            AddRange(vertices);\n        }\n\n        internal bool AttachedToBody { get; set; }\n\n        /// <summary>\n        /// You can add holes to this collection.\n        /// It will get respected by some of the triangulation algoithms, but otherwise not used.\n        /// </summary>\n        public List<Vertices> Holes { get; set; }\n\n        /// <summary>\n        /// Gets the next index. Used for iterating all the edges with wrap-around.\n        /// </summary>\n        /// <param name=\"index\">The current index</param>\n        public int NextIndex(int index)\n        {\n            return (index + 1 > Count - 1) ? 0 : index + 1;\n        }\n\n        /// <summary>\n        /// Gets the next vertex. Used for iterating all the edges with wrap-around.\n        /// </summary>\n        /// <param name=\"index\">The current index</param>\n        public Vector2 NextVertex(int index)\n        {\n            return this[NextIndex(index)];\n        }\n\n        /// <summary>\n        /// Gets the previous index. Used for iterating all the edges with wrap-around.\n        /// </summary>\n        /// <param name=\"index\">The current index</param>\n        public int PreviousIndex(int index)\n        {\n            return index - 1 < 0 ? Count - 1 : index - 1;\n        }\n\n        /// <summary>\n        /// Gets the previous vertex. Used for iterating all the edges with wrap-around.\n        /// </summary>\n        /// <param name=\"index\">The current index</param>\n        public Vector2 PreviousVertex(int index)\n        {\n            return this[PreviousIndex(index)];\n        }\n\n        /// <summary>\n        /// Gets the signed area.\n        /// If the area is less than 0, it indicates that the polygon is clockwise winded.\n        /// </summary>\n        /// <returns>The signed area</returns>\n        public float GetSignedArea()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return 0;\n\n            int i;\n            float area = 0;\n\n            for (i = 0; i < Count; i++)\n            {\n                int j = (i + 1) % Count;\n\n                Vector2 vi = this[i];\n                Vector2 vj = this[j];\n\n                area += vi.X * vj.Y;\n                area -= vi.Y * vj.X;\n            }\n            area /= 2.0f;\n            return area;\n        }\n\n        /// <summary>\n        /// Gets the area.\n        /// </summary>\n        /// <returns></returns>\n        public float GetArea()\n        {\n            float area = GetSignedArea();\n            return (area < 0 ? -area : area);\n        }\n\n        /// <summary>\n        /// Gets the centroid.\n        /// </summary>\n        /// <returns></returns>\n        public Vector2 GetCentroid()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return new Vector2(float.NaN, float.NaN);\n\n            // Same algorithm is used by Box2D\n            Vector2 c = Vector2.Zero;\n            float area = 0.0f;\n            const float inv3 = 1.0f / 3.0f;\n\n            for (int i = 0; i < Count; ++i)\n            {\n                // Triangle vertices.\n                Vector2 current = this[i];\n                Vector2 next = (i + 1 < Count ? this[i + 1] : this[0]);\n\n                float triangleArea = 0.5f * (current.X * next.Y - current.Y * next.X);\n                area += triangleArea;\n\n                // Area weighted centroid\n                c += triangleArea * inv3 * (current + next);\n            }\n\n            // Centroid\n            c *= 1.0f / area;\n            return c;\n        }\n\n        /// <summary>\n        /// Returns an AABB that fully contains this polygon.\n        /// </summary>\n        public AABB GetAABB()\n        {\n            AABB aabb;\n            Vector2 lowerBound = new Vector2(float.MaxValue, float.MaxValue);\n            Vector2 upperBound = new Vector2(float.MinValue, float.MinValue);\n\n            for (int i = 0; i < Count; ++i)\n            {\n                if (this[i].X < lowerBound.X)\n                {\n                    lowerBound.X = this[i].X;\n                }\n                if (this[i].X > upperBound.X)\n                {\n                    upperBound.X = this[i].X;\n                }\n\n                if (this[i].Y < lowerBound.Y)\n                {\n                    lowerBound.Y = this[i].Y;\n                }\n                if (this[i].Y > upperBound.Y)\n                {\n                    upperBound.Y = this[i].Y;\n                }\n            }\n\n            aabb.LowerBound = lowerBound;\n            aabb.UpperBound = upperBound;\n\n            return aabb;\n        }\n\n        /// <summary>\n        /// Translates the vertices with the specified vector.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        public void Translate(Vector2 value)\n        {\n            Translate(ref value);\n        }\n\n        /// <summary>\n        /// Translates the vertices with the specified vector.\n        /// </summary>\n        /// <param name=\"value\">The vector.</param>\n        public void Translate(ref Vector2 value)\n        {\n            Debug.Assert(!AttachedToBody, \"Translating vertices that are used by a Body can result in unstable behavior. Use Body.Position instead.\");\n\n            for (int i = 0; i < Count; i++)\n                this[i] = Vector2.Add(this[i], value);\n\n            if (Holes != null && Holes.Count > 0)\n            {\n                foreach (Vertices hole in Holes)\n                {\n                    hole.Translate(ref value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Scales the vertices with the specified vector.\n        /// </summary>\n        /// <param name=\"value\">The Value.</param>\n        public void Scale(Vector2 value)\n        {\n            Scale(ref value);\n        }\n\n        /// <summary>\n        /// Scales the vertices with the specified vector.\n        /// </summary>\n        /// <param name=\"value\">The Value.</param>\n        public void Scale(ref Vector2 value)\n        {\n            Debug.Assert(!AttachedToBody, \"Scaling vertices that are used by a Body can result in unstable behavior.\");\n\n            for (int i = 0; i < Count; i++)\n                this[i] = Vector2.Multiply(this[i], value);\n\n            if (Holes != null && Holes.Count > 0)\n            {\n                foreach (Vertices hole in Holes)\n                {\n                    hole.Scale(ref value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Rotate the vertices with the defined value in radians.\n        /// Warning: Using this method on an active set of vertices of a Body,\n        /// will cause problems with collisions. Use Body.Rotation instead.\n        /// </summary>\n        /// <param name=\"value\">The amount to rotate by in radians.</param>\n        public void Rotate(float value)\n        {\n            Debug.Assert(!AttachedToBody, \"Rotating vertices that are used by a Body can result in unstable behavior.\");\n\n            float num1 = (float)Math.Cos(value);\n            float num2 = (float)Math.Sin(value);\n\n            for (int i = 0; i < Count; i++)\n            {\n                Vector2 position = this[i];\n                this[i] = new Vector2((position.X * num1 + position.Y * -num2), (position.X * num2 + position.Y * num1));\n            }\n\n            if (Holes != null && Holes.Count > 0)\n            {\n                foreach (Vertices hole in Holes)\n                {\n                    hole.Rotate(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Determines whether the polygon is convex.\n        /// O(n^2) running time.\n        /// Assumptions:\n        /// - The polygon is in counter clockwise order\n        /// - The polygon has no overlapping edges\n        /// </summary>\n        /// <returns>\n        /// <c>true</c> if it is convex; otherwise, <c>false</c>.\n        /// </returns>\n        public bool IsConvex()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return false;\n\n            //Triangles are always convex\n            if (Count == 3)\n                return true;\n\n            // Checks the polygon is convex and the interior is to the left of each edge.\n            for (int i = 0; i < Count; ++i)\n            {\n                int next = i + 1 < Count ? i + 1 : 0;\n                Vector2 edge = this[next] - this[i];\n\n                for (int j = 0; j < Count; ++j)\n                {\n                    // Don't check vertices on the current edge.\n                    if (j == i || j == next)\n                        continue;\n\n                    Vector2 r = this[j] - this[i];\n\n                    float s = edge.X * r.Y - edge.Y * r.X;\n\n                    if (s <= 0.0f)\n                        return false;\n                }\n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Indicates if the vertices are in counter clockwise order.\n        /// Warning: If the area of the polygon is 0, it is unable to determine the winding.\n        /// </summary>\n        public bool IsCounterClockWise()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return false;\n\n            return (GetSignedArea() > 0.0f);\n        }\n\n        /// <summary>\n        /// Forces the vertices to be counter clock wise order.\n        /// </summary>\n        public void ForceCounterClockWise()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return;\n\n            if (!IsCounterClockWise())\n                Reverse();\n        }\n\n        /// <summary>\n        /// Checks if the vertices forms an simple polygon by checking for edge crossings.\n        /// </summary>\n        public bool IsSimple()\n        {\n            //The simplest polygon which can exist in the Euclidean plane has 3 sides.\n            if (Count < 3)\n                return false;\n\n            for (int i = 0; i < Count; ++i)\n            {\n                Vector2 a1 = this[i];\n                Vector2 a2 = NextVertex(i);\n                for (int j = i + 1; j < Count; ++j)\n                {\n                    Vector2 b1 = this[j];\n                    Vector2 b2 = NextVertex(j);\n\n                    Vector2 temp;\n\n                    if (LineUtils.LineIntersect2(ref a1, ref a2, ref b1, ref b2, out temp))\n                        return false;\n                }\n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Checks if the polygon is valid for use in the engine.\n        /// Performs a full check, for simplicity, convexity,\n        /// orientation, minimum angle, and volume.\n        /// From Eric Jordan's convex decomposition library\n        /// </summary>\n        /// <returns>PolygonError.NoError if there were no error.</returns>\n        public PolygonError CheckPolygon()\n        {\n            //TODO: TBM\n            //if (Count < 3 || Count > Settings.MaxPolygonVertices)\n            //    return PolygonError.InvalidAmountOfVertices;\n\n            if (!IsSimple())\n                return PolygonError.NotSimple;\n\n            if (GetArea() <= float.Epsilon)\n                return PolygonError.AreaTooSmall;\n\n            if (!IsConvex())\n                return PolygonError.NotConvex;\n\n            //Check if the sides are of adequate length.\n            for (int i = 0; i < Count; ++i)\n            {\n                int next = i + 1 < Count ? i + 1 : 0;\n                Vector2 edge = this[next] - this[i];\n                if (edge.LengthSquared() <= float.Epsilon * float.Epsilon)\n                {\n                    return PolygonError.SideTooSmall;\n                }\n            }\n\n            if (!IsCounterClockWise())\n                return PolygonError.NotCounterClockWise;\n\n            return PolygonError.NoError;\n        }\n\n        /// <summary>\n        /// Projects to axis.\n        /// </summary>\n        /// <param name=\"axis\">The axis.</param>\n        /// <param name=\"min\">The min.</param>\n        /// <param name=\"max\">The max.</param>\n        public void ProjectToAxis(ref Vector2 axis, out float min, out float max)\n        {\n            // To project a point on an axis use the dot product\n            float dotProduct = Vector2.Dot(axis, this[0]);\n            min = dotProduct;\n            max = dotProduct;\n\n            for (int i = 0; i < Count; i++)\n            {\n                dotProduct = Vector2.Dot(this[i], axis);\n                if (dotProduct < min)\n                {\n                    min = dotProduct;\n                }\n                else\n                {\n                    if (dotProduct > max)\n                    {\n                        max = dotProduct;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Winding number test for a point in a polygon.\n        /// </summary>\n        /// See more info about the algorithm here: http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm\n        /// <param name=\"point\">The point to be tested.</param>\n        /// <returns>\n        /// -1 if the winding number is zero and the point is outside\n        /// the polygon, 1 if the point is inside the polygon, and 0 if the point\n        /// is on the polygons edge.\n        /// </returns>\n        public int PointInPolygon(ref Vector2 point)\n        {\n            // Winding number\n            int wn = 0;\n\n            // Iterate through polygon's edges\n            for (int i = 0; i < Count; i++)\n            {\n                // Get points\n                Vector2 p1 = this[i];\n                Vector2 p2 = this[NextIndex(i)];\n\n                // Test if a point is directly on the edge\n                Vector2 edge = p2 - p1;\n                float area = MathUtils.Area(ref p1, ref p2, ref point);\n                if (area == 0f && Vector2.Dot(point - p1, edge) >= 0f && Vector2.Dot(point - p2, edge) <= 0f)\n                {\n                    return 0;\n                }\n\n                // Test edge for intersection with ray from point\n                if (p1.Y <= point.Y)\n                {\n                    if (p2.Y > point.Y && area > 0f)\n                    {\n                        ++wn;\n                    }\n                }\n                else\n                {\n                    if (p2.Y <= point.Y && area < 0f)\n                    {\n                        --wn;\n                    }\n                }\n            }\n            return (wn == 0 ? -1 : 1);\n        }\n\n        /// <summary>\n        /// Compute the sum of the angles made between the test point and each pair of points making up the polygon.\n        /// If this sum is 2pi then the point is an interior point, if 0 then the point is an exterior point.\n        /// ref: http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/  - Solution 2\n        /// </summary>\n        public bool PointInPolygonAngle(ref Vector2 point)\n        {\n            double angle = 0;\n\n            // Iterate through polygon's edges\n            for (int i = 0; i < Count; i++)\n            {\n                // Get points\n                Vector2 p1 = this[i] - point;\n                Vector2 p2 = this[NextIndex(i)] - point;\n\n                angle += MathUtils.VectorAngle(ref p1, ref p2);\n            }\n\n            if (Math.Abs(angle) < Math.PI)\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Transforms the polygon using the defined matrix.\n        /// </summary>\n        /// <param name=\"transform\">The matrix to use as transformation.</param>\n        public void Transform(ref Matrix transform)\n        {\n            // Transform main polygon\n            for (int i = 0; i < Count; i++)\n                this[i] = Vector2.Transform(this[i], transform);\n\n            // Transform holes\n            if (Holes != null && Holes.Count > 0)\n            {\n                for (int i = 0; i < Holes.Count; i++)\n                {\n                    Vector2[] temp = Holes[i].ToArray();\n                    Vector2.Transform(temp, ref transform, temp);\n\n                    Holes[i] = new Vertices(temp);\n                }\n            }\n        }\n\n        public override string ToString()\n        {\n            StringBuilder builder = new StringBuilder();\n            for (int i = 0; i < Count; i++)\n            {\n                builder.Append(this[i]);\n                if (i < Count - 1)\n                {\n                    builder.Append(\" \");\n                }\n            }\n            return builder.ToString();\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/BodyTemplate.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\n\nnamespace VelcroPhysics.Templates\n{\n    public class BodyTemplate : IDefaults\n    {\n        public BodyTemplate()\n        {\n            SetDefaults();\n        }\n        \n        /// <summary>\n        /// Is this body initially awake or sleeping?\n        /// </summary>\n        public bool Awake;\n\n        /// <summary>\n        /// Does this body start out active?\n        /// </summary>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Is this a fast moving body that should be prevented from tunneling through\n        /// other moving bodies? Note that all bodies are prevented from tunneling through\n        /// kinematic and static bodies. This setting is only considered on dynamic bodies.\n        /// <remarks>Warning: You should use this flag sparingly since it increases processing time.</remarks>\n        /// </summary>\n        public bool AllowCCD { get; set; }\n\n        /// <summary>\n        /// Should this body be prevented from rotating?\n        /// </summary>\n        public bool AllowRotation { get; set; }\n\n        /// <summary>\n        /// Set this flag to false if this body should never fall asleep.\n        /// <remarks>Note: Setting this to false increases CPU usage.</remarks>\n        /// </summary>\n        public bool AllowSleep { get; set; }\n\n        /// <summary>\n        /// The world angle of the body in radians.\n        /// </summary>\n        public float Angle { get; set; }\n\n        /// <summary>\n        /// Angular damping is use to reduce the angular velocity. The damping parameter\n        /// can be larger than 1.0f but the damping effect becomes sensitive to the\n        /// time step when the damping parameter is large.\n        /// </summary>\n        public float AngularDamping { get; set; }\n\n        /// <summary>\n        /// The angular velocity of the body.\n        /// </summary>\n        public float AngularVelocity { get; set; }\n\n        /// <summary>\n        /// Scale the gravity applied to this body.\n        /// </summary>\n        public float GravityScale { get; set; }\n\n        /// <summary>\n        /// Linear damping is use to reduce the linear velocity. The damping parameter\n        /// can be larger than 1.0f but the damping effect becomes sensitive to the\n        /// time step when the damping parameter is large.\n        /// </summary>\n        public float LinearDamping { get; set; }\n\n        /// <summary>\n        /// The linear velocity of the body's origin in world co-ordinates.\n        /// </summary>\n        public Vector2 LinearVelocity { get; set; }\n\n        /// <summary>\n        /// The world position of the body.\n        /// </summary>\n        public Vector2 Position { get; set; }\n\n        /// <summary>\n        /// Set the type of body\n        /// <remarks>Note: if a dynamic body would have zero mass, the mass is set to one.</remarks>\n        /// </summary>\n        public BodyType Type { get; set; }\n\n        /// <summary>\n        /// Use this to store application specific body data.\n        /// </summary>\n        public object UserData { get; set; }\n\n        public void SetDefaults()\n        {\n            AllowSleep = true;\n            Awake = true;\n            Type = BodyType.Static;\n            Active = true;\n            GravityScale = 1.0f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/FixtureTemplate.cs",
    "content": "using VelcroPhysics.Collision.Filtering;\nusing VelcroPhysics.Collision.Shapes;\n\nnamespace VelcroPhysics.Templates\n{\n    public class FixtureTemplate : IDefaults\n    {\n        public FixtureTemplate()\n        {\n            SetDefaults();\n        }\n\n        /// <summary>\n        /// The density, usually in kg/m^2.\n        /// </summary>\n        public float Density { get; set; }\n\n        /// <summary>\n        /// Contact filtering data.\n        /// </summary>\n        public Filter Filter { get; set; }\n\n        /// <summary>\n        /// The friction coefficient, usually in the range [0,1].\n        /// </summary>\n        public float Friction { get; set; }\n\n        /// <summary>\n        /// A sensor shape collects contact information but never generates a collision response.\n        /// </summary>\n        public bool IsSensor { get; set; }\n\n        /// <summary>\n        /// The restitution (elasticity) usually in the range [0,1].\n        /// </summary>\n        public float Restitution { get; set; }\n\n        /// <summary>\n        /// The shape, this must be set. The shape will be cloned, so you can create the shape on the stack.\n        /// </summary>\n        public Shape Shape { get; set; }\n\n        /// <summary>\n        /// Use this to store application specific fixture data.\n        /// </summary>\n        public object UserData { get; set; }\n\n        public void SetDefaults()\n        {\n            Friction = 0.2f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/IDefaults.cs",
    "content": "namespace VelcroPhysics.Templates\n{\n    public interface IDefaults\n    {\n        void SetDefaults();\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/DistanceJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Distance joint definition. This requires defining an\n    /// anchor point on both bodies and the non-zero length of the\n    /// distance joint. The definition uses local anchor points\n    /// so that the initial configuration can violate the constraint\n    /// slightly. This helps when saving and loading a game.\n    /// <remarks>Do not use a zero or a short length.</remarks>\n    /// </summary>\n    public class DistanceJointTemplate : JointTemplate\n    {\n        public DistanceJointTemplate() : base(JointType.Distance) { }\n\n        /// <summary>\n        /// The damping ratio. 0 = no damping, 1 = critical damping.\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// The mass-spring-damper frequency in Hertz. A value of 0 disables softness.\n        /// </summary>\n        public float FrequencyHz { get; set; }\n\n        /// <summary>\n        /// The natural length between the anchor points.\n        /// </summary>\n        public float Length { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        public override void SetDefaults()\n        {\n            Length = 1.0f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/FrictionJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    public class FrictionJointTemplate : JointTemplate\n    {\n        public FrictionJointTemplate() : base(JointType.Friction) { }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The maximum friction force in N.\n        /// </summary>\n        public float MaxForce { get; set; }\n\n        /// <summary>\n        /// The maximum friction torque in N-m.\n        /// </summary>\n        public float MaxTorque { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/GearJointTemplate.cs",
    "content": "using VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    public class GearJointTemplate : JointTemplate\n    {\n        public GearJointTemplate() : base(JointType.Gear) { }\n\n        /// <summary>\n        /// The first revolute/prismatic joint attached to the gear joint.\n        /// </summary>\n        public Joint JointA { get; set; }\n\n        /// <summary>\n        /// The second revolute/prismatic joint attached to the gear joint.\n        /// </summary>\n        public Joint JointB { get; set; }\n\n        /// <summary>\n        /// The gear ratio.\n        /// </summary>\n        public float Ratio { get; set; }\n\n        public override void SetDefaults()\n        {\n            Ratio = 1.0f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/JointTemplate.cs",
    "content": "using VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    public class JointTemplate : IDefaults\n    {\n        public JointTemplate(JointType type)\n        {\n            Type = type;\n        }\n\n        /// <summary>\n        /// The first attached body.\n        /// </summary>\n        public Body BodyA { get; set; }\n\n        /// <summary>\n        /// The second attached body.\n        /// </summary>\n        public Body BodyB { get; set; }\n\n        /// <summary>\n        /// Set this flag to true if the attached bodies should collide.\n        /// </summary>\n        public bool CollideConnected { get; set; }\n\n        /// <summary>\n        /// The joint type is set automatically for concrete joint types.\n        /// </summary>\n        public JointType Type { get; }\n\n        /// <summary>\n        /// Use this to attach application specific data.\n        /// </summary>\n        public object UserData { get; set; }\n\n        public virtual void SetDefaults() { }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/MotorJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    public class MotorJointTemplate : JointTemplate\n    {\n        public MotorJointTemplate() : base(JointType.Motor) { }\n\n        /// <summary>\n        /// The bodyB angle minus bodyA angle in radians.\n        /// </summary>\n        public float AngularOffset { get; set; }\n\n        /// <summary>\n        /// Position correction factor in the range [0,1].\n        /// </summary>\n        public float CorrectionFactor { get; set; }\n\n        /// <summary>\n        /// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters.\n        /// </summary>\n        public Vector2 LinearOffset { get; set; }\n\n        /// <summary>\n        /// The maximum motor force in N.\n        /// </summary>\n        public float MaxForce { get; set; }\n\n        /// <summary>\n        /// The maximum motor torque in N-m.\n        /// </summary>\n        public float MaxTorque { get; set; }\n\n        public override void SetDefaults()\n        {\n            MaxForce = 1.0f;\n            MaxTorque = 1.0f;\n            CorrectionFactor = 0.3f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/MouseJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Mouse joint definition. This requires a world target point,\n    /// tuning parameters, and the time step.\n    /// </summary>\n    public class MouseJointTemplate : JointTemplate\n    {\n        public MouseJointTemplate() : base(JointType.FixedMouse) { }\n\n        /// <summary>\n        /// The damping ratio. 0 = no damping, 1 = critical damping.\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// The response speed.\n        /// </summary>\n        public float FrequencyHz { get; set; }\n\n        /// <summary>\n        /// The maximum constraint force that can be exerted\n        /// to move the candidate body. Usually you will express\n        /// as some multiple of the weight (multiplier * mass * gravity).\n        /// </summary>\n        public float MaxForce { get; set; }\n\n        /// <summary>\n        /// The initial world target point. This is assumed\n        /// to coincide with the body anchor initially.\n        /// </summary>\n        public Vector2 Target { get; set; }\n\n        public override void SetDefaults()\n        {\n            FrequencyHz = 5.0f;\n            DampingRatio = 0.7f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/PrismaticJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Prismatic joint definition. This requires defining a line of\n    /// motion using an axis and an anchor point. The definition uses local\n    /// anchor points and a local axis so that the initial configuration\n    /// can violate the constraint slightly. The joint translation is zero\n    /// when the local anchor points coincide in world space. Using local\n    /// anchors and a local axis helps when saving and loading a game.\n    /// </summary>\n    public class PrismaticJointTemplate : JointTemplate\n    {\n        public PrismaticJointTemplate() : base(JointType.Prismatic) { }\n\n        /// <summary>\n        /// Enable/disable the joint limit.\n        /// </summary>\n        public bool EnableLimit { get; set; }\n\n        /// <summary>\n        /// Enable/disable the joint motor.\n        /// </summary>\n        public bool EnableMotor { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The local translation unit axis in bodyA.\n        /// </summary>\n        public Vector2 LocalAxisA { get; set; }\n\n        /// <summary>\n        /// The lower translation limit, usually in meters.\n        /// </summary>\n        public float LowerTranslation { get; set; }\n\n        /// <summary>\n        /// The maximum motor torque, usually in N-m.\n        /// </summary>\n        public float MaxMotorForce { get; set; }\n\n        /// <summary>\n        /// The desired motor speed in radians per second.\n        /// </summary>\n        public float MotorSpeed { get; set; }\n\n        /// <summary>\n        /// The constrained angle between the bodies: bodyB_angle - bodyA_angle.\n        /// </summary>\n        public float ReferenceAngle { get; set; }\n\n        /// <summary>\n        /// The upper translation limit, usually in meters.\n        /// </summary>\n        public float UpperTranslation { get; set; }\n\n        public override void SetDefaults()\n        {\n            LocalAxisA = new Vector2(1.0f, 0.0f);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/PulleyJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Pulley joint definition. This requires two ground anchors,\n    /// two dynamic body anchor points, and a pulley ratio.\n    /// </summary>\n    public class PulleyJointTemplate : JointTemplate\n    {\n        public PulleyJointTemplate() : base(JointType.Pulley) { }\n\n        /// <summary>\n        /// The first ground anchor in world coordinates. This point never moves.\n        /// </summary>\n        public Vector2 GroundAnchorA { get; set; }\n\n        /// <summary>\n        /// The second ground anchor in world coordinates. This point never moves.\n        /// </summary>\n        public Vector2 GroundAnchorB { get; set; }\n\n        /// <summary>\n        /// The a reference length for the segment attached to bodyA.\n        /// </summary>\n        public float LengthA { get; set; }\n\n        /// <summary>\n        /// The a reference length for the segment attached to bodyB.\n        /// </summary>\n        public float LengthB { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The pulley ratio, used to simulate a block-and-tackle.\n        /// </summary>\n        public float Ratio { get; set; }\n\n        public override void SetDefaults()\n        {\n            GroundAnchorA = new Vector2(-1.0f, 1.0f);\n            GroundAnchorB = new Vector2(1.0f, 1.0f);\n            LocalAnchorA = new Vector2(-1.0f, 0.0f);\n            LocalAnchorB = new Vector2(1.0f, 0.0f);\n            Ratio = 1.0f;\n            CollideConnected = true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/RevoluteJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Revolute joint definition. This requires defining an\n    /// anchor point where the bodies are joined. The definition\n    /// uses local anchor points so that the initial configuration\n    /// can violate the constraint slightly. You also need to\n    /// specify the initial relative angle for joint limits. This\n    /// helps when saving and loading a game.\n    /// The local anchor points are measured from the body's origin\n    /// rather than the center of mass because:\n    /// 1. you might not know where the center of mass will be.\n    /// 2. if you add/remove shapes from a body and recompute the mass,\n    /// the joints will be broken.\n    /// </summary>\n    public class RevoluteJointTemplate : JointTemplate\n    {\n        public RevoluteJointTemplate() : base(JointType.Revolute) { }\n\n        /// <summary>\n        /// A flag to enable joint limits.\n        /// </summary>\n        public bool EnableLimit { get; set; }\n\n        /// <summary>\n        /// A flag to enable the joint motor.\n        /// </summary>\n        public bool EnableMotor { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The lower angle for the joint limit (radians).\n        /// </summary>\n        public float LowerAngle { get; set; }\n\n        /// <summary>\n        /// The maximum motor torque used to achieve the desired motor speed. Usually in N-m.\n        /// </summary>\n        public float MaxMotorTorque { get; set; }\n\n        /// <summary>\n        /// The desired motor speed. Usually in radians per second.\n        /// </summary>\n        public float MotorSpeed { get; set; }\n\n        /// <summary>\n        /// The bodyB angle minus bodyA angle in the reference state (radians).\n        /// </summary>\n        public float ReferenceAngle { get; set; }\n\n        /// <summary>\n        /// The upper angle for the joint limit (radians).\n        /// </summary>\n        public float UpperAngle { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/RopeJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Rope joint definition. This requires two body anchor points and\n    /// a maximum lengths.\n    /// <remarks>By default the connected objects will not collide.</remarks>\n    /// </summary>\n    public class RopeJointTemplate : JointTemplate\n    {\n        public RopeJointTemplate() : base(JointType.Rope) { }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The maximum length of the rope.\n        /// <remarks>This must be larger than Settings.LinearSlop or the joint will have no effect.</remarks>\n        /// </summary>\n        public float MaxLength { get; set; }\n\n        public override void SetDefaults()\n        {\n            LocalAnchorA = new Vector2(-1.0f, 0.0f);\n            LocalAnchorB = new Vector2(1.0f, 0.0f);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/WeldJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Weld joint definition. You need to specify local anchor points\n    /// where they are attached and the relative body angle. The position\n    /// of the anchor points is important for computing the reaction torque.\n    /// </summary>\n    public class WeldJointTemplate : JointTemplate\n    {\n        public WeldJointTemplate() : base(JointType.Weld) { }\n\n        /// <summary>\n        /// The damping ratio. 0 = no damping, 1 = critical damping.\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// The mass-spring-damper frequency in Hertz. Rotation only.\n        /// Disable softness with a value of 0.\n        /// </summary>\n        public float FrequencyHz { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The bodyB angle minus bodyA angle in the reference state (radians).\n        /// </summary>\n        public float ReferenceAngle { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Joints/WheelJointTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics.Joints;\n\nnamespace VelcroPhysics.Templates.Joints\n{\n    /// <summary>\n    /// Wheel joint definition. This requires defining a line of\n    /// motion using an axis and an anchor point. The definition uses local\n    /// anchor points and a local axis so that the initial configuration\n    /// can violate the constraint slightly. The joint translation is zero\n    /// when the local anchor points coincide in world space. Using local\n    /// anchors and a local axis helps when saving and loading a game.\n    /// </summary>\n    public class WheelJointTemplate : JointTemplate\n    {\n        public WheelJointTemplate() : base(JointType.Wheel) { }\n\n        /// <summary>\n        /// Suspension damping ratio, one indicates critical damping\n        /// </summary>\n        public float DampingRatio { get; set; }\n\n        /// <summary>\n        /// Enable/disable the joint motor.\n        /// </summary>\n        public bool EnableMotor { get; set; }\n\n        /// <summary>\n        /// Suspension frequency, zero indicates no suspension\n        /// </summary>\n        public float FrequencyHz { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyA's origin.\n        /// </summary>\n        public Vector2 LocalAnchorA { get; set; }\n\n        /// <summary>\n        /// The local anchor point relative to bodyB's origin.\n        /// </summary>\n        public Vector2 LocalAnchorB { get; set; }\n\n        /// <summary>\n        /// The local translation axis in bodyA.\n        /// </summary>\n        public Vector2 LocalAxisA { get; set; }\n\n        /// <summary>\n        /// The maximum motor torque, usually in N-m.\n        public float MaxMotorTorque { get; set; }\n\n        /// <summary>\n        /// The desired motor speed in radians per second.\n        /// </summary>\n        public float MotorSpeed { get; set; }\n\n        public override void SetDefaults()\n        {\n            LocalAxisA = new Vector2(1.0f, 0.0f);\n            FrequencyHz = 2.0f;\n            DampingRatio = 0.7f;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Shapes/ChainShapeTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Templates.Shapes\n{\n    /// <summary>\n    /// A chain shape is a free form sequence of line segments.\n    /// The chain has two-sided collision, so you can use inside and outside collision.\n    /// Therefore, you may use any winding order.\n    /// Connectivity information is used to create smooth collisions.\n    /// <remarks>WARNING: The chain will not collide properly if there are self-intersections.</remarks>\n    /// </summary>\n    public class ChainShapeTemplate : ShapeTemplate\n    {\n        public ChainShapeTemplate() : base(ShapeType.Chain) { }\n\n        /// <summary>\n        /// Establish connectivity to a vertex that follows the last vertex.\n        /// <remarks>Don't call this for loops.</remarks>\n        /// </summary>\n        public Vector2 NextVertex { get; set; }\n\n        /// <summary>\n        /// Establish connectivity to a vertex that precedes the first vertex.\n        /// <remarks>Don't call this for loops.</remarks>\n        /// </summary>\n        public Vector2 PrevVertex { get; set; }\n\n        /// <summary>\n        /// The vertices. These are not owned/freed by the chain Shape.\n        /// </summary>\n        public Vertices Vertices { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Shapes/CircleShapeTemplate.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\n\nnamespace VelcroPhysics.Templates.Shapes\n{\n    public class CircleShapeTemplate : ShapeTemplate\n    {\n        public CircleShapeTemplate() : base(ShapeType.Circle) { }\n\n        /// <summary>\n        /// Get or set the position of the circle\n        /// </summary>\n        public Vector2 Position { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Shapes/EdgeShapeTemplate.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\n\nnamespace VelcroPhysics.Templates.Shapes\n{\n    /// <summary>\n    /// A line segment (edge) shape. These can be connected in chains or loops to other edge shapes.\n    /// The connectivity information is used to ensure correct contact normals.\n    /// </summary>\n    public class EdgeShapeTemplate : ShapeTemplate\n    {\n        public EdgeShapeTemplate() : base(ShapeType.Edge) { }\n\n        /// <summary>\n        /// Is true if the edge is connected to an adjacent vertex before vertex 1.\n        /// </summary>\n        public bool HasVertex0 { get; set; }\n\n        /// <summary>\n        /// Is true if the edge is connected to an adjacent vertex after vertex2.\n        /// </summary>\n        public bool HasVertex3 { get; set; }\n\n        /// <summary>\n        /// Optional adjacent vertices. These are used for smooth collision.\n        /// </summary>\n        public Vector2 Vertex0 { get; set; }\n\n        /// <summary>\n        /// These are the edge vertices\n        /// </summary>\n        public Vector2 Vertex1 { get; set; }\n\n        /// <summary>\n        /// These are the edge vertices\n        /// </summary>\n        public Vector2 Vertex2 { get; set; }\n\n        /// <summary>\n        /// Optional adjacent vertices. These are used for smooth collision.\n        /// </summary>\n        public Vector2 Vertex3 { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Shapes/PolygonShapeTemplate.cs",
    "content": "using VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Templates.Shapes\n{\n    public class PolygonShapeTemplate : ShapeTemplate\n    {\n        public PolygonShapeTemplate() : base(ShapeType.Polygon) { }\n\n        public Vertices Vertices { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Templates/Shapes/ShapeTemplate.cs",
    "content": "﻿using VelcroPhysics.Collision.Shapes;\n\nnamespace VelcroPhysics.Templates.Shapes\n{\n    public class ShapeTemplate\n    {\n        public ShapeTemplate(ShapeType type)\n        {\n            ShapeType = type;\n        }\n\n        /// <summary>\n        /// Gets or sets the density.\n        /// </summary>\n        public float Density { get; set; }\n\n        /// <summary>\n        /// Radius of the Shape\n        /// </summary>\n        public float Radius { get; set; }\n\n        /// <summary>\n        /// Get the type of this shape.\n        /// </summary>\n        public ShapeType ShapeType { get; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/ConvexHull/ChainHull/ChainHull.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.ConvexHull.ChainHull\n{\n    /// <summary>\n    /// Andrew's Monotone Chain Convex Hull algorithm.\n    /// Used to get the convex hull of a point cloud.\n    /// Source: http://www.softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm\n    /// </summary>\n    public static class ChainHull\n    {\n        //Copyright 2001, softSurfer (www.softsurfer.com)\n\n        private static PointComparer _pointComparer = new PointComparer();\n\n        /// <summary>\n        /// Returns the convex hull from the given vertices..\n        /// </summary>\n        public static Vertices GetConvexHull(Vertices vertices)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            Vertices pointSet = new Vertices(vertices);\n\n            //Sort by X-axis\n            pointSet.Sort(_pointComparer);\n\n            Vector2[] h = new Vector2[pointSet.Count];\n            Vertices res;\n\n            int top = -1; // indices for bottom and top of the stack\n            int i; // array scan index\n\n            // Get the indices of points with min x-coord and min|max y-coord\n            const int minmin = 0;\n            float xmin = pointSet[0].X;\n            for (i = 1; i < pointSet.Count; i++)\n            {\n                if (pointSet[i].X != xmin)\n                    break;\n            }\n\n            // degenerate case: all x-coords == xmin\n            int minmax = i - 1;\n            if (minmax == pointSet.Count - 1)\n            {\n                h[++top] = pointSet[minmin];\n\n                if (pointSet[minmax].Y != pointSet[minmin].Y) // a nontrivial segment\n                    h[++top] = pointSet[minmax];\n\n                h[++top] = pointSet[minmin]; // add polygon endpoint\n\n                res = new Vertices(top + 1);\n                for (int j = 0; j < top + 1; j++)\n                {\n                    res.Add(h[j]);\n                }\n\n                return res;\n            }\n\n            top = -1;\n\n            // Get the indices of points with max x-coord and min|max y-coord\n            int maxmax = pointSet.Count - 1;\n            float xmax = pointSet[pointSet.Count - 1].X;\n            for (i = pointSet.Count - 2; i >= 0; i--)\n            {\n                if (pointSet[i].X != xmax)\n                    break;\n            }\n            int maxmin = i + 1;\n\n            // Compute the lower hull on the stack H\n            h[++top] = pointSet[minmin]; // push minmin point onto stack\n            i = minmax;\n            while (++i <= maxmin)\n            {\n                // the lower line joins P[minmin] with P[maxmin]\n                if (MathUtils.Area(pointSet[minmin], pointSet[maxmin], pointSet[i]) >= 0 && i < maxmin)\n                    continue; // ignore P[i] above or on the lower line\n\n                while (top > 0) // there are at least 2 points on the stack\n                {\n                    // test if P[i] is left of the line at the stack top\n                    if (MathUtils.Area(h[top - 1], h[top], pointSet[i]) > 0)\n                        break; // P[i] is a new hull vertex\n\n                    top--; // pop top point off stack\n                }\n                h[++top] = pointSet[i]; // push P[i] onto stack\n            }\n\n            // Next, compute the upper hull on the stack H above the bottom hull\n            if (maxmax != maxmin) // if distinct xmax points\n                h[++top] = pointSet[maxmax]; // push maxmax point onto stack\n            int bot = top;\n            i = maxmin;\n            while (--i >= minmax)\n            {\n                // the upper line joins P[maxmax] with P[minmax]\n                if (MathUtils.Area(pointSet[maxmax], pointSet[minmax], pointSet[i]) >= 0 && i > minmax)\n                    continue; // ignore P[i] below or on the upper line\n\n                while (top > bot) // at least 2 points on the upper stack\n                {\n                    // test if P[i] is left of the line at the stack top\n                    if (MathUtils.Area(h[top - 1], h[top], pointSet[i]) > 0)\n                        break; // P[i] is a new hull vertex\n\n                    top--; // pop top point off stack\n                }\n\n                h[++top] = pointSet[i]; // push P[i] onto stack\n            }\n\n            if (minmax != minmin)\n                h[++top] = pointSet[minmin]; // push joining endpoint onto stack\n\n            res = new Vertices(top + 1);\n\n            for (int j = 0; j < top + 1; j++)\n            {\n                res.Add(h[j]);\n            }\n\n            return res;\n        }\n\n        private class PointComparer : Comparer<Vector2>\n        {\n            public override int Compare(Vector2 a, Vector2 b)\n            {\n                int f = a.X.CompareTo(b.X);\n                return f != 0 ? f : a.Y.CompareTo(b.Y);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/ConvexHull/GiftWrap/GiftWrap.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.ConvexHull.GiftWrap\n{\n    /// <summary>\n    /// Giftwrap convex hull algorithm.\n    /// O(n * h) time complexity, where n is the number of points and h is the number of points on the convex hull.\n    /// See http://en.wikipedia.org/wiki/Gift_wrapping_algorithm for more details.\n    /// </summary>\n    public static class GiftWrap\n    {\n        //Extracted from Box2D\n\n        /// <summary>\n        /// Returns the convex hull from the given vertices.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        public static Vertices GetConvexHull(Vertices vertices)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            // Find the right most point on the hull\n            int i0 = 0;\n            float x0 = vertices[0].X;\n            for (int i = 1; i < vertices.Count; ++i)\n            {\n                float x = vertices[i].X;\n                if (x > x0 || (x == x0 && vertices[i].Y < vertices[i0].Y))\n                {\n                    i0 = i;\n                    x0 = x;\n                }\n            }\n\n            int[] hull = new int[vertices.Count];\n            int m = 0;\n            int ih = i0;\n\n            for (;;)\n            {\n                hull[m] = ih;\n\n                int ie = 0;\n                for (int j = 1; j < vertices.Count; ++j)\n                {\n                    if (ie == ih)\n                    {\n                        ie = j;\n                        continue;\n                    }\n\n                    Vector2 r = vertices[ie] - vertices[hull[m]];\n                    Vector2 v = vertices[j] - vertices[hull[m]];\n                    float c = MathUtils.Cross(ref r, ref v);\n                    if (c < 0.0f)\n                    {\n                        ie = j;\n                    }\n\n                    // Collinearity check\n                    if (c == 0.0f && v.LengthSquared() > r.LengthSquared())\n                    {\n                        ie = j;\n                    }\n                }\n\n                ++m;\n                ih = ie;\n\n                if (ie == i0)\n                {\n                    break;\n                }\n            }\n\n            Vertices result = new Vertices(m);\n\n            // Copy vertices.\n            for (int i = 0; i < m; ++i)\n            {\n                result.Add(vertices[hull[i]]);\n            }\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/ConvexHull/Melkman/Melkman.cs",
    "content": "﻿using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.ConvexHull.Melkman\n{\n    /// <summary>\n    /// Creates a convex hull.\n    /// Note:\n    /// 1. Vertices must be of a simple polygon, i.e. edges do not overlap.\n    /// 2. Melkman does not work on point clouds\n    /// </summary>\n    /// <remarks>\n    /// Implemented using Melkman's Convex Hull Algorithm - O(n) time complexity.\n    /// Reference: http://www.ams.sunysb.edu/~jsbm/courses/345/melkman.pdf\n    /// </remarks>\n    public static class Melkman\n    {\n        //Melkman based convex hull algorithm contributed by Cowdozer\n\n        /// <summary>\n        /// Returns a convex hull from the given vertices.\n        /// </summary>\n        /// <returns>A convex hull in counter clockwise winding order.</returns>\n        public static Vertices GetConvexHull(Vertices vertices)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            //We'll never need a queue larger than the current number of Vertices +1\n            //Create double-ended queue\n            Vector2[] deque = new Vector2[vertices.Count + 1];\n            int qf = 3, qb = 0; //Queue front index, queue back index\n\n            //Start by placing first 3 vertices in convex CCW order\n            int startIndex = 3;\n            float k = MathUtils.Area(vertices[0], vertices[1], vertices[2]);\n            if (k == 0)\n            {\n                //Vertices are collinear.\n                deque[0] = vertices[0];\n                deque[1] = vertices[2]; //We can skip vertex 1 because it should be between 0 and 2\n                deque[2] = vertices[0];\n                qf = 2;\n\n                //Go until the end of the collinear sequence of vertices\n                for (startIndex = 3; startIndex < vertices.Count; startIndex++)\n                {\n                    Vector2 tmp = vertices[startIndex];\n                    if (MathUtils.Area(ref deque[0], ref deque[1], ref tmp) == 0) //This point is also collinear\n                        deque[1] = vertices[startIndex];\n                    else\n                        break;\n                }\n            }\n            else\n            {\n                deque[0] = deque[3] = vertices[2];\n                if (k > 0)\n                {\n                    //Is Left.  Set deque = {2, 0, 1, 2}\n                    deque[1] = vertices[0];\n                    deque[2] = vertices[1];\n                }\n                else\n                {\n                    //Is Right. Set deque = {2, 1, 0, 2}\n                    deque[1] = vertices[1];\n                    deque[2] = vertices[0];\n                }\n            }\n\n            int qfm1 = qf == 0 ? deque.Length - 1 : qf - 1;\n            int qbm1 = qb == deque.Length - 1 ? 0 : qb + 1;\n\n            //Add vertices one at a time and adjust convex hull as needed\n            for (int i = startIndex; i < vertices.Count; i++)\n            {\n                Vector2 nextPt = vertices[i];\n\n                //Ignore if it is already within the convex hull we have constructed\n                if (MathUtils.Area(ref deque[qfm1], ref deque[qf], ref nextPt) > 0 && MathUtils.Area(ref deque[qb], ref deque[qbm1], ref nextPt) > 0)\n                    continue;\n\n                //Pop front until convex\n                while (!(MathUtils.Area(ref deque[qfm1], ref deque[qf], ref nextPt) > 0))\n                {\n                    //Pop the front element from the queue\n                    qf = qfm1; //qf--;\n                    qfm1 = qf == 0 ? deque.Length - 1 : qf - 1; //qfm1 = qf - 1;\n                }\n\n                //Add vertex to the front of the queue\n                qf = qf == deque.Length - 1 ? 0 : qf + 1; //qf++;\n                qfm1 = qf == 0 ? deque.Length - 1 : qf - 1; //qfm1 = qf - 1;\n                deque[qf] = nextPt;\n\n                //Pop back until convex\n                while (!(MathUtils.Area(ref deque[qb], ref deque[qbm1], ref nextPt) > 0))\n                {\n                    //Pop the back element from the queue\n                    qb = qbm1; //qb++;\n                    qbm1 = qb == deque.Length - 1 ? 0 : qb + 1; //qbm1 = qb + 1;\n                }\n\n                //Add vertex to the back of the queue\n                qb = qb == 0 ? deque.Length - 1 : qb - 1; //qb--;\n                qbm1 = qb == deque.Length - 1 ? 0 : qb + 1; //qbm1 = qb + 1;\n                deque[qb] = nextPt;\n            }\n\n            //Create the convex hull from what is left in the deque\n            if (qb < qf)\n            {\n                Vertices convexHull = new Vertices(qf);\n\n                for (int i = qb; i < qf; i++)\n                    convexHull.Add(deque[i]);\n\n                return convexHull;\n            }\n            else\n            {\n                Vertices convexHull = new Vertices(qf + deque.Length);\n\n                for (int i = 0; i < qf; i++)\n                    convexHull.Add(deque[i]);\n\n                for (int i = qb; i < deque.Length; i++)\n                    convexHull.Add(deque[i]);\n\n                return convexHull;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Cutting/Simple/CuttingTools.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.Cutting.Simple\n{\n    public static class CuttingTools\n    {\n        //Cutting a shape into two is based on the work of Daid and his prototype BoxCutter: http://www.box2d.org/forum/viewtopic.php?f=3&t=1473\n\n        /// <summary>\n        /// Split a fixture into 2 vertices collections using the given entry and exit-point.\n        /// </summary>\n        /// <param name=\"fixture\">The Fixture to split</param>\n        /// <param name=\"entryPoint\">The entry point - The start point</param>\n        /// <param name=\"exitPoint\">The exit point - The end point</param>\n        /// <param name=\"first\">The first collection of vertexes</param>\n        /// <param name=\"second\">The second collection of vertexes</param>\n        public static void SplitShape(Fixture fixture, Vector2 entryPoint, Vector2 exitPoint, out Vertices first, out Vertices second)\n        {\n            Vector2 localEntryPoint = fixture.Body.GetLocalPoint(ref entryPoint);\n            Vector2 localExitPoint = fixture.Body.GetLocalPoint(ref exitPoint);\n\n            PolygonShape shape = fixture.Shape as PolygonShape;\n\n            //We can only cut polygons at the moment\n            if (shape == null)\n            {\n                first = new Vertices();\n                second = new Vertices();\n                return;\n            }\n\n            //Offset the entry and exit points if they are too close to the vertices\n            foreach (Vector2 vertex in shape.Vertices)\n            {\n                if (vertex.Equals(localEntryPoint))\n                    localEntryPoint -= new Vector2(0, Settings.Epsilon);\n\n                if (vertex.Equals(localExitPoint))\n                    localExitPoint += new Vector2(0, Settings.Epsilon);\n            }\n\n            Vertices vertices = new Vertices(shape.Vertices);\n            Vertices[] newPolygon = new Vertices[2];\n\n            for (int i = 0; i < newPolygon.Length; i++)\n            {\n                newPolygon[i] = new Vertices(vertices.Count);\n            }\n\n            int[] cutAdded = { -1, -1 };\n            int last = -1;\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                int n;\n\n                //Find out if this vertex is on the old or new shape.\n                if (Vector2.Dot(MathUtils.Cross(localExitPoint - localEntryPoint, 1), vertices[i] - localEntryPoint) > Settings.Epsilon)\n                    n = 0;\n                else\n                    n = 1;\n\n                if (last != n)\n                {\n                    //If we switch from one shape to the other add the cut vertices.\n                    if (last == 0)\n                    {\n                        Debug.Assert(cutAdded[0] == -1);\n                        cutAdded[0] = newPolygon[last].Count;\n                        newPolygon[last].Add(localExitPoint);\n                        newPolygon[last].Add(localEntryPoint);\n                    }\n                    if (last == 1)\n                    {\n                        Debug.Assert(cutAdded[last] == -1);\n                        cutAdded[last] = newPolygon[last].Count;\n                        newPolygon[last].Add(localEntryPoint);\n                        newPolygon[last].Add(localExitPoint);\n                    }\n                }\n\n                newPolygon[n].Add(vertices[i]);\n                last = n;\n            }\n\n            //Add the cut in case it has not been added yet.\n            if (cutAdded[0] == -1)\n            {\n                cutAdded[0] = newPolygon[0].Count;\n                newPolygon[0].Add(localExitPoint);\n                newPolygon[0].Add(localEntryPoint);\n            }\n            if (cutAdded[1] == -1)\n            {\n                cutAdded[1] = newPolygon[1].Count;\n                newPolygon[1].Add(localEntryPoint);\n                newPolygon[1].Add(localExitPoint);\n            }\n\n            for (int n = 0; n < 2; n++)\n            {\n                Vector2 offset;\n                if (cutAdded[n] > 0)\n                {\n                    offset = (newPolygon[n][cutAdded[n] - 1] - newPolygon[n][cutAdded[n]]);\n                }\n                else\n                {\n                    offset = (newPolygon[n][newPolygon[n].Count - 1] - newPolygon[n][0]);\n                }\n                offset.Normalize();\n\n                if (!offset.IsValid())\n                    offset = Vector2.One;\n\n                newPolygon[n][cutAdded[n]] += Settings.Epsilon * offset;\n\n                if (cutAdded[n] < newPolygon[n].Count - 2)\n                {\n                    offset = (newPolygon[n][cutAdded[n] + 2] - newPolygon[n][cutAdded[n] + 1]);\n                }\n                else\n                {\n                    offset = (newPolygon[n][0] - newPolygon[n][newPolygon[n].Count - 1]);\n                }\n                offset.Normalize();\n\n                if (!offset.IsValid())\n                    offset = Vector2.One;\n\n                newPolygon[n][cutAdded[n] + 1] += Settings.Epsilon * offset;\n            }\n\n            first = newPolygon[0];\n            second = newPolygon[1];\n        }\n\n        /// <summary>\n        /// This is a high-level function to cuts fixtures inside the given world, using the start and end points.\n        /// Note: We don't support cutting when the start or end is inside a shape.\n        /// </summary>\n        /// <param name=\"world\">The world.</param>\n        /// <param name=\"start\">The startpoint.</param>\n        /// <param name=\"end\">The endpoint.</param>\n        /// <returns>True if the cut was performed.</returns>\n        public static bool Cut(World world, Vector2 start, Vector2 end)\n        {\n            List<Fixture> fixtures = new List<Fixture>();\n            List<Vector2> entryPoints = new List<Vector2>();\n            List<Vector2> exitPoints = new List<Vector2>();\n\n            //We don't support cutting when the start or end is inside a shape.\n            if (world.TestPoint(start) != null || world.TestPoint(end) != null)\n                return false;\n\n            //Get the entry points\n            world.RayCast((f, p, n, fr) =>\n            {\n                fixtures.Add(f);\n                entryPoints.Add(p);\n                return 1;\n            }, start, end);\n\n            //Reverse the ray to get the exitpoints\n            world.RayCast((f, p, n, fr) =>\n            {\n                exitPoints.Add(p);\n                return 1;\n            }, end, start);\n\n            //We only have a single point. We need at least 2\n            if (entryPoints.Count + exitPoints.Count < 2)\n                return false;\n\n            for (int i = 0; i < fixtures.Count; i++)\n            {\n                // can't cut circles or edges yet !\n                if (fixtures[i].Shape.ShapeType != ShapeType.Polygon)\n                    continue;\n\n                if (fixtures[i].Body.BodyType != BodyType.Static)\n                {\n                    //Split the shape up into two shapes\n                    Vertices first;\n                    Vertices second;\n                    SplitShape(fixtures[i], entryPoints[i], exitPoints[i], out first, out second);\n\n                    //Delete the original shape and create two new. Retain the properties of the body.\n                    if (first.CheckPolygon() == PolygonError.NoError)\n                    {\n                        Body firstFixture = BodyFactory.CreatePolygon(world, first, fixtures[i].Shape.Density, fixtures[i].Body.Position);\n                        firstFixture.Rotation = fixtures[i].Body.Rotation;\n                        firstFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;\n                        firstFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;\n                        firstFixture.BodyType = BodyType.Dynamic;\n                    }\n\n                    if (second.CheckPolygon() == PolygonError.NoError)\n                    {\n                        Body secondFixture = BodyFactory.CreatePolygon(world, second, fixtures[i].Shape.Density, fixtures[i].Body.Position);\n                        secondFixture.Rotation = fixtures[i].Body.Rotation;\n                        secondFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;\n                        secondFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;\n                        secondFixture.BodyType = BodyType.Dynamic;\n                    }\n\n                    world.RemoveBody(fixtures[i].Body);\n                }\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Cutting/Simple/PolyClipError.cs",
    "content": "namespace VelcroPhysics.Tools.Cutting.Simple\n{\n    public enum PolyClipError\n    {\n        None,\n        DegeneratedOutput,\n        NonSimpleInput,\n        BrokenResult\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Cutting/Simple/PolyClipType.cs",
    "content": "namespace VelcroPhysics.Tools.Cutting.Simple\n{\n    internal enum PolyClipType\n    {\n        Intersect,\n        Union,\n        Difference\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Cutting/YuPengClipper.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.Cutting.Simple;\nusing VelcroPhysics.Tools.PolygonManipulation;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.Cutting\n{\n    //Clipper contributed by Helge Backhaus\n\n    public static class YuPengClipper\n    {\n        private const float ClipperEpsilonSquared = 1.192092896e-07f;\n\n        public static List<Vertices> Union(Vertices polygon1, Vertices polygon2, out PolyClipError error)\n        {\n            return Execute(polygon1, polygon2, PolyClipType.Union, out error);\n        }\n\n        public static List<Vertices> Difference(Vertices polygon1, Vertices polygon2, out PolyClipError error)\n        {\n            return Execute(polygon1, polygon2, PolyClipType.Difference, out error);\n        }\n\n        public static List<Vertices> Intersect(Vertices polygon1, Vertices polygon2, out PolyClipError error)\n        {\n            return Execute(polygon1, polygon2, PolyClipType.Intersect, out error);\n        }\n\n        /// <summary>\n        /// Implements \"A new algorithm for Boolean operations on general polygons\"\n        /// available here: http://liama.ia.ac.cn/wiki/_media/user:dong:dong_cg_05.pdf\n        /// Merges two polygons, a subject and a clip with the specified operation. Polygons may not be\n        /// self-intersecting.\n        /// Warning: May yield incorrect results or even crash if polygons contain collinear points.\n        /// </summary>\n        /// <param name=\"subject\">The subject polygon.</param>\n        /// <param name=\"clip\">\n        /// The clip polygon, which is added,\n        /// substracted or intersected with the subject\n        /// </param>\n        /// <param name=\"clipType\">\n        /// The operation to be performed. Either\n        /// Union, Difference or Intersection.\n        /// </param>\n        /// <param name=\"error\">The error generated (if any)</param>\n        /// <returns>\n        /// A list of closed polygons, which make up the result of the clipping operation.\n        /// Outer contours are ordered counter clockwise, holes are ordered clockwise.\n        /// </returns>\n        private static List<Vertices> Execute(Vertices subject, Vertices clip, PolyClipType clipType, out PolyClipError error)\n        {\n            Debug.Assert(subject.IsSimple() && clip.IsSimple(), \"Non simple input!\", \"Input polygons must be simple (cannot intersect themselves).\");\n\n            // Copy polygons\n            Vertices slicedSubject;\n            Vertices slicedClip;\n\n            // Calculate the intersection and touch points between\n            // subject and clip and add them to both\n            CalculateIntersections(subject, clip, out slicedSubject, out slicedClip);\n\n            // Translate polygons into upper right quadrant\n            // as the algorithm depends on it\n            Vector2 lbSubject = subject.GetAABB().LowerBound;\n            Vector2 lbClip = clip.GetAABB().LowerBound;\n            Vector2 translate;\n            Vector2.Min(ref lbSubject, ref lbClip, out translate);\n            translate = Vector2.One - translate;\n            if (translate != Vector2.Zero)\n            {\n                slicedSubject.Translate(ref translate);\n                slicedClip.Translate(ref translate);\n            }\n\n            // Enforce counterclockwise contours\n            slicedSubject.ForceCounterClockWise();\n            slicedClip.ForceCounterClockWise();\n\n            List<Edge> subjectSimplices;\n            List<float> subjectCoeff;\n            List<Edge> clipSimplices;\n            List<float> clipCoeff;\n\n            // Build simplical chains from the polygons and calculate the\n            // the corresponding coefficients\n            CalculateSimplicalChain(slicedSubject, out subjectCoeff, out subjectSimplices);\n            CalculateSimplicalChain(slicedClip, out clipCoeff, out clipSimplices);\n\n            List<Edge> resultSimplices;\n\n            // Determine the characteristics function for all non-original edges\n            // in subject and clip simplical chain and combine the edges contributing\n            // to the result, depending on the clipType\n            CalculateResultChain(subjectCoeff, subjectSimplices, clipCoeff, clipSimplices, clipType,\n                out resultSimplices);\n\n            List<Vertices> result;\n\n            // Convert result chain back to polygon(s)\n            error = BuildPolygonsFromChain(resultSimplices, out result);\n\n            // Reverse the polygon translation from the beginning\n            // and remove collinear points from output\n            translate *= -1f;\n            for (int i = 0; i < result.Count; ++i)\n            {\n                result[i].Translate(ref translate);\n                SimplifyTools.CollinearSimplify(result[i]);\n            }\n            return result;\n        }\n\n        /// <summary>\n        /// Calculates all intersections between two polygons.\n        /// </summary>\n        /// <param name=\"polygon1\">The first polygon.</param>\n        /// <param name=\"polygon2\">The second polygon.</param>\n        /// <param name=\"slicedPoly1\">Returns the first polygon with added intersection points.</param>\n        /// <param name=\"slicedPoly2\">Returns the second polygon with added intersection points.</param>\n        private static void CalculateIntersections(Vertices polygon1, Vertices polygon2,\n                                                   out Vertices slicedPoly1, out Vertices slicedPoly2)\n        {\n            slicedPoly1 = new Vertices(polygon1);\n            slicedPoly2 = new Vertices(polygon2);\n\n            // Iterate through polygon1's edges\n            for (int i = 0; i < polygon1.Count; i++)\n            {\n                // Get edge vertices\n                Vector2 a = polygon1[i];\n                Vector2 b = polygon1[polygon1.NextIndex(i)];\n\n                // Get intersections between this edge and polygon2\n                for (int j = 0; j < polygon2.Count; j++)\n                {\n                    Vector2 c = polygon2[j];\n                    Vector2 d = polygon2[polygon2.NextIndex(j)];\n\n                    Vector2 intersectionPoint;\n\n                    // Check if the edges intersect\n                    if (LineUtils.LineIntersect(a, b, c, d, out intersectionPoint))\n                    {\n                        // calculate alpha values for sorting multiple intersections points on a edge\n                        float alpha;\n\n                        // Insert intersection point into first polygon\n                        alpha = GetAlpha(a, b, intersectionPoint);\n                        if (alpha > 0f && alpha < 1f)\n                        {\n                            int index = slicedPoly1.IndexOf(a) + 1;\n                            while (index < slicedPoly1.Count &&\n                                   GetAlpha(a, b, slicedPoly1[index]) <= alpha)\n                            {\n                                ++index;\n                            }\n                            slicedPoly1.Insert(index, intersectionPoint);\n                        }\n\n                        // Insert intersection point into second polygon\n                        alpha = GetAlpha(c, d, intersectionPoint);\n                        if (alpha > 0f && alpha < 1f)\n                        {\n                            int index = slicedPoly2.IndexOf(c) + 1;\n                            while (index < slicedPoly2.Count &&\n                                   GetAlpha(c, d, slicedPoly2[index]) <= alpha)\n                            {\n                                ++index;\n                            }\n                            slicedPoly2.Insert(index, intersectionPoint);\n                        }\n                    }\n                }\n            }\n\n            // Check for very small edges\n            for (int i = 0; i < slicedPoly1.Count; ++i)\n            {\n                int iNext = slicedPoly1.NextIndex(i);\n\n                //If they are closer than the distance remove vertex\n                if ((slicedPoly1[iNext] - slicedPoly1[i]).LengthSquared() <= ClipperEpsilonSquared)\n                {\n                    slicedPoly1.RemoveAt(i);\n                    --i;\n                }\n            }\n            for (int i = 0; i < slicedPoly2.Count; ++i)\n            {\n                int iNext = slicedPoly2.NextIndex(i);\n\n                //If they are closer than the distance remove vertex\n                if ((slicedPoly2[iNext] - slicedPoly2[i]).LengthSquared() <= ClipperEpsilonSquared)\n                {\n                    slicedPoly2.RemoveAt(i);\n                    --i;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Calculates the simplical chain corresponding to the input polygon.\n        /// </summary>\n        /// <remarks>Used by method <c>Execute()</c>.</remarks>\n        private static void CalculateSimplicalChain(Vertices poly, out List<float> coeff,\n                                                    out List<Edge> simplicies)\n        {\n            simplicies = new List<Edge>();\n            coeff = new List<float>();\n            for (int i = 0; i < poly.Count; ++i)\n            {\n                simplicies.Add(new Edge(poly[i], poly[poly.NextIndex(i)]));\n                coeff.Add(CalculateSimplexCoefficient(Vector2.Zero, poly[i], poly[poly.NextIndex(i)]));\n            }\n        }\n\n        /// <summary>\n        /// Calculates the characteristics function for all edges of\n        /// the given simplical chains and builds the result chain.\n        /// </summary>\n        /// <remarks>Used by method <c>Execute()</c>.</remarks>\n        private static void CalculateResultChain(List<float> poly1Coeff, List<Edge> poly1Simplicies,\n                                                 List<float> poly2Coeff, List<Edge> poly2Simplicies,\n                                                 PolyClipType clipType, out List<Edge> resultSimplices)\n        {\n            resultSimplices = new List<Edge>();\n\n            for (int i = 0; i < poly1Simplicies.Count; ++i)\n            {\n                float edgeCharacter = 0;\n                if (poly2Simplicies.Contains(poly1Simplicies[i]))\n                {\n                    edgeCharacter = 1f;\n                }\n                else if (poly2Simplicies.Contains(-poly1Simplicies[i]) && clipType == PolyClipType.Union)\n                {\n                    edgeCharacter = 1f;\n                }\n                else\n                {\n                    for (int j = 0; j < poly2Simplicies.Count; ++j)\n                    {\n                        if (!poly2Simplicies.Contains(-poly1Simplicies[i]))\n                        {\n                            edgeCharacter += CalculateBeta(poly1Simplicies[i].GetCenter(),\n                                poly2Simplicies[j], poly2Coeff[j]);\n                        }\n                    }\n                }\n                if (clipType == PolyClipType.Intersect)\n                {\n                    if (edgeCharacter == 1f)\n                    {\n                        resultSimplices.Add(poly1Simplicies[i]);\n                    }\n                }\n                else\n                {\n                    if (edgeCharacter == 0f)\n                    {\n                        resultSimplices.Add(poly1Simplicies[i]);\n                    }\n                }\n            }\n            for (int i = 0; i < poly2Simplicies.Count; ++i)\n            {\n                float edgeCharacter = 0f;\n                if (!resultSimplices.Contains(poly2Simplicies[i]) &&\n                    !resultSimplices.Contains(-poly2Simplicies[i]))\n                {\n                    if (poly1Simplicies.Contains(-poly2Simplicies[i]) && clipType == PolyClipType.Union)\n                    {\n                        edgeCharacter = 1f;\n                    }\n                    else\n                    {\n                        edgeCharacter = 0f;\n                        for (int j = 0; j < poly1Simplicies.Count; ++j)\n                        {\n                            if (!poly1Simplicies.Contains(poly2Simplicies[i]) && !poly1Simplicies.Contains(-poly2Simplicies[i]))\n                            {\n                                edgeCharacter += CalculateBeta(poly2Simplicies[i].GetCenter(),\n                                    poly1Simplicies[j], poly1Coeff[j]);\n                            }\n                        }\n                        if (clipType == PolyClipType.Intersect || clipType == PolyClipType.Difference)\n                        {\n                            if (edgeCharacter == 1f)\n                            {\n                                resultSimplices.Add(-poly2Simplicies[i]);\n                            }\n                        }\n                        else\n                        {\n                            if (edgeCharacter == 0f)\n                            {\n                                resultSimplices.Add(poly2Simplicies[i]);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Calculates the polygon(s) from the result simplical chain.\n        /// </summary>\n        /// <remarks>Used by method <c>Execute()</c>.</remarks>\n        private static PolyClipError BuildPolygonsFromChain(List<Edge> simplicies, out List<Vertices> result)\n        {\n            result = new List<Vertices>();\n            PolyClipError errVal = PolyClipError.None;\n\n            while (simplicies.Count > 0)\n            {\n                Vertices output = new Vertices();\n                output.Add(simplicies[0].EdgeStart);\n                output.Add(simplicies[0].EdgeEnd);\n                simplicies.RemoveAt(0);\n                bool closed = false;\n                int index = 0;\n                int count = simplicies.Count; // Needed to catch infinite loops\n                while (!closed && simplicies.Count > 0)\n                {\n                    if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeStart))\n                    {\n                        if (VectorEqual(simplicies[index].EdgeEnd, output[0]))\n                        {\n                            closed = true;\n                        }\n                        else\n                        {\n                            output.Add(simplicies[index].EdgeEnd);\n                        }\n                        simplicies.RemoveAt(index);\n                        --index;\n                    }\n                    else if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeEnd))\n                    {\n                        if (VectorEqual(simplicies[index].EdgeStart, output[0]))\n                        {\n                            closed = true;\n                        }\n                        else\n                        {\n                            output.Add(simplicies[index].EdgeStart);\n                        }\n                        simplicies.RemoveAt(index);\n                        --index;\n                    }\n                    if (!closed)\n                    {\n                        if (++index == simplicies.Count)\n                        {\n                            if (count == simplicies.Count)\n                            {\n                                result = new List<Vertices>();\n                                Debug.WriteLine(\"Undefined error while building result polygon(s).\");\n                                return PolyClipError.BrokenResult;\n                            }\n                            index = 0;\n                            count = simplicies.Count;\n                        }\n                    }\n                }\n                if (output.Count < 3)\n                {\n                    errVal = PolyClipError.DegeneratedOutput;\n                    Debug.WriteLine(\"Degenerated output polygon produced (vertices < 3).\");\n                }\n                result.Add(output);\n            }\n            return errVal;\n        }\n\n        /// <summary>\n        /// Needed to calculate the characteristics function of a simplex.\n        /// </summary>\n        /// <remarks>Used by method <c>CalculateEdgeCharacter()</c>.</remarks>\n        private static float CalculateBeta(Vector2 point, Edge e, float coefficient)\n        {\n            float result = 0f;\n            if (PointInSimplex(point, e))\n            {\n                result = coefficient;\n            }\n            if (PointOnLineSegment(Vector2.Zero, e.EdgeStart, point) ||\n                PointOnLineSegment(Vector2.Zero, e.EdgeEnd, point))\n            {\n                result = .5f * coefficient;\n            }\n            return result;\n        }\n\n        /// <summary>\n        /// Needed for sorting multiple intersections points on the same edge.\n        /// </summary>\n        /// <remarks>Used by method <c>CalculateIntersections()</c>.</remarks>\n        private static float GetAlpha(Vector2 start, Vector2 end, Vector2 point)\n        {\n            return (point - start).LengthSquared() / (end - start).LengthSquared();\n        }\n\n        /// <summary>\n        /// Returns the coefficient of a simplex.\n        /// </summary>\n        /// <remarks>Used by method <c>CalculateSimplicalChain()</c>.</remarks>\n        private static float CalculateSimplexCoefficient(Vector2 a, Vector2 b, Vector2 c)\n        {\n            float isLeft = MathUtils.Area(ref a, ref b, ref c);\n            if (isLeft < 0f)\n            {\n                return -1f;\n            }\n\n            if (isLeft > 0f)\n            {\n                return 1f;\n            }\n\n            return 0f;\n        }\n\n        /// <summary>\n        /// Winding number test for a point in a simplex.\n        /// </summary>\n        /// <param name=\"point\">The point to be tested.</param>\n        /// <param name=\"edge\">The edge that the point is tested against.</param>\n        /// <returns>\n        /// False if the winding number is even and the point is outside\n        /// the simplex and True otherwise.\n        /// </returns>\n        private static bool PointInSimplex(Vector2 point, Edge edge)\n        {\n            Vertices polygon = new Vertices();\n            polygon.Add(Vector2.Zero);\n            polygon.Add(edge.EdgeStart);\n            polygon.Add(edge.EdgeEnd);\n            return (polygon.PointInPolygon(ref point) == 1);\n        }\n\n        /// <summary>\n        /// Tests if a point lies on a line segment.\n        /// </summary>\n        /// <remarks>Used by method <c>CalculateBeta()</c>.</remarks>\n        private static bool PointOnLineSegment(Vector2 start, Vector2 end, Vector2 point)\n        {\n            Vector2 segment = end - start;\n            return MathUtils.Area(ref start, ref end, ref point) == 0f &&\n                   Vector2.Dot(point - start, segment) >= 0f &&\n                   Vector2.Dot(point - end, segment) <= 0f;\n        }\n\n        private static bool VectorEqual(Vector2 vec1, Vector2 vec2)\n        {\n            return (vec2 - vec1).LengthSquared() <= ClipperEpsilonSquared;\n        }\n\n        #region Nested type: Edge\n\n        /// <summary>Specifies an Edge. Edges are used to represent simplicies in simplical chains</summary>\n        private sealed class Edge\n        {\n            public Edge(Vector2 edgeStart, Vector2 edgeEnd)\n            {\n                EdgeStart = edgeStart;\n                EdgeEnd = edgeEnd;\n            }\n\n            public Vector2 EdgeStart { get; private set; }\n            public Vector2 EdgeEnd { get; private set; }\n\n            public Vector2 GetCenter()\n            {\n                return (EdgeStart + EdgeEnd) / 2f;\n            }\n\n            public static Edge operator -(Edge e)\n            {\n                return new Edge(e.EdgeEnd, e.EdgeStart);\n            }\n\n            public override bool Equals(object obj)\n            {\n                // If parameter is null return false.\n                if (obj == null)\n                {\n                    return false;\n                }\n\n                // If parameter cannot be cast to Point return false.\n                return Equals(obj as Edge);\n            }\n\n            public bool Equals(Edge e)\n            {\n                // If parameter is null return false:\n                if (e == null)\n                {\n                    return false;\n                }\n\n                // Return true if the fields match\n                return VectorEqual(EdgeStart, e.EdgeStart) && VectorEqual(EdgeEnd, e.EdgeEnd);\n            }\n\n            public override int GetHashCode()\n            {\n                return EdgeStart.GetHashCode() ^ EdgeEnd.GetHashCode();\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/PathGenerator/LinkFactory.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.PathGenerator\n{\n    public static class LinkFactory\n    {\n        /// <summary>\n        /// Creates a chain.\n        /// </summary>\n        /// <param name=\"world\">The world.</param>\n        /// <param name=\"start\">The start.</param>\n        /// <param name=\"end\">The end.</param>\n        /// <param name=\"linkWidth\">The width.</param>\n        /// <param name=\"linkHeight\">The height.</param>\n        /// <param name=\"numberOfLinks\">The number of links.</param>\n        /// <param name=\"linkDensity\">The link density.</param>\n        /// <param name=\"attachRopeJoint\">\n        /// Creates a rope joint between start and end. This enforces the length of the rope. Said in\n        /// another way: it makes the rope less bouncy.\n        /// </param>\n        /// <returns></returns>\n        public static Path CreateChain(World world, Vector2 start, Vector2 end, float linkWidth, float linkHeight, int numberOfLinks, float linkDensity, bool attachRopeJoint)\n        {\n            Debug.Assert(numberOfLinks >= 2);\n\n            //Chain start / end\n            Path path = new Path();\n            path.Add(start);\n            path.Add(end);\n\n            //A single chainlink\n            PolygonShape shape = new PolygonShape(PolygonUtils.CreateRectangle(linkWidth, linkHeight), linkDensity);\n\n            //Use PathManager to create all the chainlinks based on the chainlink created before.\n            List<Body> chainLinks = PathManager.EvenlyDistributeShapesAlongPath(world, path, shape, BodyType.Dynamic, numberOfLinks);\n\n            //TODO\n            //if (fixStart)\n            //{\n            //    //Fix the first chainlink to the world\n            //    JointFactory.CreateFixedRevoluteJoint(world, chainLinks[0], new Vector2(0, -(linkHeight / 2)),\n            //                                          chainLinks[0].Position);\n            //}\n\n            //if (fixEnd)\n            //{\n            //    //Fix the last chainlink to the world\n            //    JointFactory.CreateFixedRevoluteJoint(world, chainLinks[chainLinks.Count - 1],\n            //                                          new Vector2(0, (linkHeight / 2)),\n            //                                          chainLinks[chainLinks.Count - 1].Position);\n            //}\n\n            //Attach all the chainlinks together with a revolute joint\n            PathManager.AttachBodiesWithRevoluteJoint(world, chainLinks, new Vector2(0, -linkHeight), new Vector2(0, linkHeight), false, false);\n\n            if (attachRopeJoint)\n                JointFactory.CreateRopeJoint(world, chainLinks[0], chainLinks[chainLinks.Count - 1], Vector2.Zero, Vector2.Zero);\n\n            return (path);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/PathGenerator/Path.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Tools.PathGenerator\n{\n    //Contributed by Matthew Bettcher\n\n    /// <summary>\n    /// Path:\n    /// Very similar to Vertices, but this\n    /// class contains vectors describing\n    /// control points on a Catmull-Rom\n    /// curve.\n    /// </summary>\n    public class Path\n    {\n        private float _deltaT;\n\n        /// <summary>\n        /// All the points that makes up the curve\n        /// </summary>\n        public List<Vector2> ControlPoints;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Path\" /> class.\n        /// </summary>\n        public Path()\n        {\n            ControlPoints = new List<Vector2>();\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Path\" /> class.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices to created the path from.</param>\n        public Path(Vector2[] vertices)\n        {\n            ControlPoints = new List<Vector2>(vertices.Length);\n\n            for (int i = 0; i < vertices.Length; i++)\n            {\n                Add(vertices[i]);\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Path\" /> class.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices to created the path from.</param>\n        public Path(IList<Vector2> vertices)\n        {\n            ControlPoints = new List<Vector2>(vertices.Count);\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                Add(vertices[i]);\n            }\n        }\n\n        /// <summary>\n        /// True if the curve is closed.\n        /// </summary>\n        /// <value><c>true</c> if closed; otherwise, <c>false</c>.</value>\n        public bool Closed { get; set; }\n\n        /// <summary>\n        /// Gets the next index of a controlpoint\n        /// </summary>\n        /// <param name=\"index\">The index.</param>\n        /// <returns></returns>\n        public int NextIndex(int index)\n        {\n            if (index == ControlPoints.Count - 1)\n            {\n                return 0;\n            }\n            return index + 1;\n        }\n\n        /// <summary>\n        /// Gets the previous index of a controlpoint\n        /// </summary>\n        /// <param name=\"index\">The index.</param>\n        /// <returns></returns>\n        public int PreviousIndex(int index)\n        {\n            if (index == 0)\n            {\n                return ControlPoints.Count - 1;\n            }\n            return index - 1;\n        }\n\n        /// <summary>\n        /// Translates the control points by the specified vector.\n        /// </summary>\n        /// <param name=\"vector\">The vector.</param>\n        public void Translate(ref Vector2 vector)\n        {\n            for (int i = 0; i < ControlPoints.Count; i++)\n                ControlPoints[i] = Vector2.Add(ControlPoints[i], vector);\n        }\n\n        /// <summary>\n        /// Scales the control points by the specified vector.\n        /// </summary>\n        /// <param name=\"value\">The Value.</param>\n        public void Scale(ref Vector2 value)\n        {\n            for (int i = 0; i < ControlPoints.Count; i++)\n                ControlPoints[i] = Vector2.Multiply(ControlPoints[i], value);\n        }\n\n        /// <summary>\n        /// Rotate the control points by the defined value in radians.\n        /// </summary>\n        /// <param name=\"value\">The amount to rotate by in radians.</param>\n        public void Rotate(float value)\n        {\n            Matrix rotationMatrix;\n            Matrix.CreateRotationZ(value, out rotationMatrix);\n\n            for (int i = 0; i < ControlPoints.Count; i++)\n                ControlPoints[i] = Vector2.Transform(ControlPoints[i], rotationMatrix);\n        }\n\n        public override string ToString()\n        {\n            StringBuilder builder = new StringBuilder();\n            for (int i = 0; i < ControlPoints.Count; i++)\n            {\n                builder.Append(ControlPoints[i]);\n                if (i < ControlPoints.Count - 1)\n                {\n                    builder.Append(\" \");\n                }\n            }\n            return builder.ToString();\n        }\n\n        /// <summary>\n        /// Returns a set of points defining the\n        /// curve with the specifed number of divisions\n        /// between each control point.\n        /// </summary>\n        /// <param name=\"divisions\">Number of divisions between each control point.</param>\n        /// <returns></returns>\n        public Vertices GetVertices(int divisions)\n        {\n            Vertices verts = new Vertices();\n\n            float timeStep = 1f / divisions;\n\n            for (float i = 0; i < 1f; i += timeStep)\n            {\n                verts.Add(GetPosition(i));\n            }\n\n            return verts;\n        }\n\n        public Vector2 GetPosition(float time)\n        {\n            Vector2 temp;\n\n            if (ControlPoints.Count < 2)\n                throw new Exception(\"You need at least 2 control points to calculate a position.\");\n\n            if (Closed)\n            {\n                Add(ControlPoints[0]);\n\n                _deltaT = 1f / (ControlPoints.Count - 1);\n\n                int p = (int)(time / _deltaT);\n\n                // use a circular indexing system\n                int p0 = p - 1;\n                if (p0 < 0) p0 = p0 + (ControlPoints.Count - 1);\n                else if (p0 >= ControlPoints.Count - 1) p0 = p0 - (ControlPoints.Count - 1);\n                int p1 = p;\n                if (p1 < 0) p1 = p1 + (ControlPoints.Count - 1);\n                else if (p1 >= ControlPoints.Count - 1) p1 = p1 - (ControlPoints.Count - 1);\n                int p2 = p + 1;\n                if (p2 < 0) p2 = p2 + (ControlPoints.Count - 1);\n                else if (p2 >= ControlPoints.Count - 1) p2 = p2 - (ControlPoints.Count - 1);\n                int p3 = p + 2;\n                if (p3 < 0) p3 = p3 + (ControlPoints.Count - 1);\n                else if (p3 >= ControlPoints.Count - 1) p3 = p3 - (ControlPoints.Count - 1);\n\n                // relative time\n                float lt = (time - _deltaT * p) / _deltaT;\n\n                temp = Vector2.CatmullRom(ControlPoints[p0], ControlPoints[p1], ControlPoints[p2], ControlPoints[p3], lt);\n\n                RemoveAt(ControlPoints.Count - 1);\n            }\n            else\n            {\n                int p = (int)(time / _deltaT);\n\n                // \n                int p0 = p - 1;\n                if (p0 < 0) p0 = 0;\n                else if (p0 >= ControlPoints.Count - 1) p0 = ControlPoints.Count - 1;\n                int p1 = p;\n                if (p1 < 0) p1 = 0;\n                else if (p1 >= ControlPoints.Count - 1) p1 = ControlPoints.Count - 1;\n                int p2 = p + 1;\n                if (p2 < 0) p2 = 0;\n                else if (p2 >= ControlPoints.Count - 1) p2 = ControlPoints.Count - 1;\n                int p3 = p + 2;\n                if (p3 < 0) p3 = 0;\n                else if (p3 >= ControlPoints.Count - 1) p3 = ControlPoints.Count - 1;\n\n                // relative time\n                float lt = (time - _deltaT * p) / _deltaT;\n\n                temp = Vector2.CatmullRom(ControlPoints[p0], ControlPoints[p1], ControlPoints[p2], ControlPoints[p3], lt);\n            }\n\n            return temp;\n        }\n\n        /// <summary>\n        /// Gets the normal for the given time.\n        /// </summary>\n        /// <param name=\"time\">The time</param>\n        /// <returns>The normal.</returns>\n        public Vector2 GetPositionNormal(float time)\n        {\n            float offsetTime = time + 0.0001f;\n\n            Vector2 a = GetPosition(time);\n            Vector2 b = GetPosition(offsetTime);\n\n            Vector2 output, temp;\n\n            Vector2.Subtract(ref a, ref b, out temp);\n\n#if (XBOX360 || WINDOWS_PHONE)\noutput = new Vector2();\n#endif\n            output.X = -temp.Y;\n            output.Y = temp.X;\n\n            Vector2.Normalize(ref output, out output);\n\n            return output;\n        }\n\n        public void Add(Vector2 point)\n        {\n            ControlPoints.Add(point);\n            _deltaT = 1f / (ControlPoints.Count - 1);\n        }\n\n        public void Remove(Vector2 point)\n        {\n            ControlPoints.Remove(point);\n            _deltaT = 1f / (ControlPoints.Count - 1);\n        }\n\n        public void RemoveAt(int index)\n        {\n            ControlPoints.RemoveAt(index);\n            _deltaT = 1f / (ControlPoints.Count - 1);\n        }\n\n        public float GetLength()\n        {\n            List<Vector2> verts = GetVertices(ControlPoints.Count * 25);\n            float length = 0;\n\n            for (int i = 1; i < verts.Count; i++)\n            {\n                length += Vector2.Distance(verts[i - 1], verts[i]);\n            }\n\n            if (Closed)\n                length += Vector2.Distance(verts[ControlPoints.Count - 1], verts[0]);\n\n            return length;\n        }\n\n        public List<Vector3> SubdivideEvenly(int divisions)\n        {\n            List<Vector3> verts = new List<Vector3>();\n\n            float length = GetLength();\n\n            float deltaLength = length / divisions + 0.001f;\n            float t = 0.000f;\n\n            // we always start at the first control point\n            Vector2 start = ControlPoints[0];\n            Vector2 end = GetPosition(t);\n\n            // increment t until we are at half the distance\n            while (deltaLength * 0.5f >= Vector2.Distance(start, end))\n            {\n                end = GetPosition(t);\n                t += 0.0001f;\n\n                if (t >= 1f)\n                    break;\n            }\n\n            start = end;\n\n            // for each box\n            for (int i = 1; i < divisions; i++)\n            {\n                Vector2 normal = GetPositionNormal(t);\n                float angle = (float)Math.Atan2(normal.Y, normal.X);\n\n                verts.Add(new Vector3(end, angle));\n\n                // until we reach the correct distance down the curve\n                while (deltaLength >= Vector2.Distance(start, end))\n                {\n                    end = GetPosition(t);\n                    t += 0.00001f;\n\n                    if (t >= 1f)\n                        break;\n                }\n                if (t >= 1f)\n                    break;\n\n                start = end;\n            }\n            return verts;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/PathGenerator/PathManager.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Collision.Shapes;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Dynamics.Joints;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.Triangulation.TriangulationBase;\n\nnamespace VelcroPhysics.Tools.PathGenerator\n{\n    /// <summary>\n    /// An easy to use manager for creating paths.\n    /// </summary>\n    public static class PathManager\n    {\n        #region LinkType enum\n\n        public enum LinkType\n        {\n            Revolute,\n            Slider\n        }\n\n        #endregion\n\n        //Contributed by Matthew Bettcher\n\n        /// <summary>\n        /// Convert a path into a set of edges and attaches them to the specified body.\n        /// Note: use only for static edges.\n        /// </summary>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"body\">The body.</param>\n        /// <param name=\"subdivisions\">The subdivisions.</param>\n        public static void ConvertPathToEdges(Path path, Body body, int subdivisions)\n        {\n            Vertices verts = path.GetVertices(subdivisions);\n\n            if (path.Closed)\n            {\n                ChainShape chain = new ChainShape(verts, true);\n                body.CreateFixture(chain);\n            }\n            else\n            {\n                for (int i = 1; i < verts.Count; i++)\n                {\n                    body.CreateFixture(new EdgeShape(verts[i], verts[i - 1]));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Convert a closed path into a polygon.\n        /// Convex decomposition is automatically performed.\n        /// </summary>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"body\">The body.</param>\n        /// <param name=\"density\">The density.</param>\n        /// <param name=\"subdivisions\">The subdivisions.</param>\n        public static void ConvertPathToPolygon(Path path, Body body, float density, int subdivisions)\n        {\n            if (!path.Closed)\n                throw new Exception(\"The path must be closed to convert to a polygon.\");\n\n            List<Vector2> verts = path.GetVertices(subdivisions);\n\n            List<Vertices> decomposedVerts = Triangulate.ConvexPartition(new Vertices(verts), TriangulationAlgorithm.Bayazit);\n\n            foreach (Vertices item in decomposedVerts)\n            {\n                body.CreateFixture(new PolygonShape(item, density));\n            }\n        }\n\n        /// <summary>\n        /// Duplicates the given Body along the given path for approximately the given copies.\n        /// </summary>\n        /// <param name=\"world\">The world.</param>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"shapes\">The shapes.</param>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"copies\">The copies.</param>\n        /// <param name=\"userData\"></param>\n        /// <returns></returns>\n        public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable<Shape> shapes, BodyType type, int copies, object userData = null)\n        {\n            List<Vector3> centers = path.SubdivideEvenly(copies);\n            List<Body> bodyList = new List<Body>();\n\n            for (int i = 0; i < centers.Count; i++)\n            {\n                // copy the type from original body\n                Body b = BodyFactory.CreateBody(world, new Vector2(centers[i].X, centers[i].Y), centers[i].Z, type, userData);\n\n                foreach (Shape shape in shapes)\n                {\n                    b.CreateFixture(shape);\n                }\n\n                bodyList.Add(b);\n            }\n\n            return bodyList;\n        }\n\n        /// <summary>\n        /// Duplicates the given Body along the given path for approximately the given copies.\n        /// </summary>\n        /// <param name=\"world\">The world.</param>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"shape\">The shape.</param>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"copies\">The copies.</param>\n        /// <param name=\"userData\">The user data.</param>\n        /// <returns></returns>\n        public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies, object userData)\n        {\n            List<Shape> shapes = new List<Shape>(1);\n            shapes.Add(shape);\n\n            return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, userData);\n        }\n\n        public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies)\n        {\n            return EvenlyDistributeShapesAlongPath(world, path, shape, type, copies, null);\n        }\n\n        /// <summary>\n        /// Moves the given body along the defined path.\n        /// </summary>\n        /// <param name=\"path\">The path.</param>\n        /// <param name=\"body\">The body.</param>\n        /// <param name=\"time\">The time.</param>\n        /// <param name=\"strength\">The strength.</param>\n        /// <param name=\"timeStep\">The time step.</param>\n        public static void MoveBodyOnPath(Path path, Body body, float time, float strength, float timeStep)\n        {\n            Vector2 destination = path.GetPosition(time);\n            Vector2 positionDelta = body.Position - destination;\n            Vector2 velocity = (positionDelta / timeStep) * strength;\n\n            body.LinearVelocity = -velocity;\n        }\n\n        /// <summary>\n        /// Attaches the bodies with revolute joints.\n        /// </summary>\n        /// <param name=\"world\">The world.</param>\n        /// <param name=\"bodies\">The bodies.</param>\n        /// <param name=\"localAnchorA\">The local anchor A.</param>\n        /// <param name=\"localAnchorB\">The local anchor B.</param>\n        /// <param name=\"connectFirstAndLast\">if set to <c>true</c> [connect first and last].</param>\n        /// <param name=\"collideConnected\">if set to <c>true</c> [collide connected].</param>\n        public static List<RevoluteJoint> AttachBodiesWithRevoluteJoint(World world, List<Body> bodies, Vector2 localAnchorA, Vector2 localAnchorB, bool connectFirstAndLast, bool collideConnected)\n        {\n            List<RevoluteJoint> joints = new List<RevoluteJoint>(bodies.Count + 1);\n\n            for (int i = 1; i < bodies.Count; i++)\n            {\n                RevoluteJoint joint = new RevoluteJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB);\n                joint.CollideConnected = collideConnected;\n                world.AddJoint(joint);\n                joints.Add(joint);\n            }\n\n            if (connectFirstAndLast)\n            {\n                RevoluteJoint lastjoint = new RevoluteJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB);\n                lastjoint.CollideConnected = collideConnected;\n                world.AddJoint(lastjoint);\n                joints.Add(lastjoint);\n            }\n\n            return joints;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/PolygonManipulation/SimpleCombiner.cs",
    "content": "﻿/*\n* C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010\n* \n* Original C++ Version Copyright (c) 2007 Eric Jordan\n*\n* This software is provided 'as-is', without any express or implied\n* warranty.  In no event will the authors be held liable for any damages\n* arising from the use of this software.\n* Permission is granted to anyone to use this software for any purpose,\n* including commercial applications, and to alter it and redistribute it\n* freely, subject to the following restrictions:\n* 1. The origin of this software must not be misrepresented; you must not\n* claim that you wrote the original software. If you use this software\n* in a product, an acknowledgment in the product documentation would be\n* appreciated but is not required.\n* 2. Altered source versions must be plainly marked as such, and must not be\n* misrepresented as being the original software.\n* 3. This notice may not be removed or altered from any source distribution.\n*/\n\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Tools.PolygonManipulation\n{\n    /// <summary>\n    /// Combines a list of triangles into a list of convex polygons.\n    /// Starts with a seed triangle, keep adding triangles to it until you can't add any more without making the polygon\n    /// non-convex.\n    /// </summary>\n    public static class SimpleCombiner\n    {\n        /// <summary>\n        /// Combine a list of triangles into a list of convex polygons.\n        /// Note: This only works on triangles.\n        /// </summary>\n        /// <param name=\"triangles\">The triangles.</param>\n        /// <param name=\"maxPolys\">The maximun number of polygons to return.</param>\n        /// <param name=\"tolerance\">The tolerance</param>\n        public static List<Vertices> PolygonizeTriangles(List<Vertices> triangles, int maxPolys = int.MaxValue, float tolerance = 0.001f)\n        {\n            if (triangles.Count <= 0)\n                return triangles;\n\n            List<Vertices> polys = new List<Vertices>();\n\n            bool[] covered = new bool[triangles.Count];\n            for (int i = 0; i < triangles.Count; ++i)\n            {\n                covered[i] = false;\n\n                //Check here for degenerate triangles\n                Vertices triangle = triangles[i];\n                Vector2 a = triangle[0];\n                Vector2 b = triangle[1];\n                Vector2 c = triangle[2];\n\n                if ((a.X == b.X && a.Y == b.Y) || (b.X == c.X && b.Y == c.Y) || (a.X == c.X && a.Y == c.Y))\n                    covered[i] = true;\n            }\n\n            int polyIndex = 0;\n\n            bool notDone = true;\n            while (notDone)\n            {\n                int currTri = -1;\n                for (int i = 0; i < triangles.Count; ++i)\n                {\n                    if (covered[i])\n                        continue;\n\n                    currTri = i;\n                    break;\n                }\n\n                if (currTri == -1)\n                {\n                    notDone = false;\n                }\n                else\n                {\n                    Vertices poly = new Vertices(3);\n\n                    for (int i = 0; i < 3; i++)\n                    {\n                        poly.Add(triangles[currTri][i]);\n                    }\n\n                    covered[currTri] = true;\n                    int index = 0;\n                    for (int i = 0; i < 2 * triangles.Count; ++i, ++index)\n                    {\n                        while (index >= triangles.Count)\n                            index -= triangles.Count;\n                        if (covered[index])\n                        {\n                            continue;\n                        }\n                        Vertices newP = AddTriangle(triangles[index], poly);\n                        if (newP == null)\n                            continue; // is this right\n\n                        if (newP.Count > Settings.MaxPolygonVertices)\n                            continue;\n\n                        if (newP.IsConvex())\n                        {\n                            //Or should it be IsUsable?  Maybe re-write IsConvex to apply the angle threshold from Box2d\n                            poly = new Vertices(newP);\n                            covered[index] = true;\n                        }\n                    }\n\n                    //We have a maximum of polygons that we need to keep under.\n                    if (polyIndex < maxPolys)\n                    {\n                        SimplifyTools.MergeParallelEdges(poly, tolerance);\n\n                        //If identical points are present, a triangle gets\n                        //borked by the MergeParallelEdges function, hence\n                        //the vertex number check\n                        if (poly.Count >= 3)\n                            polys.Add(new Vertices(poly));\n                        else\n                            Debug.WriteLine(\"Skipping corrupt poly.\");\n                    }\n\n                    if (poly.Count >= 3)\n                        polyIndex++; //Must be outside (polyIndex < polysLength) test\n                }\n            }\n\n            //TODO: Add sanity check\n            //Remove empty vertice collections\n            for (int i = polys.Count - 1; i >= 0; i--)\n            {\n                if (polys[i].Count == 0)\n                    polys.RemoveAt(i);\n            }\n\n            return polys;\n        }\n\n        private static Vertices AddTriangle(Vertices t, Vertices vertices)\n        {\n            // First, find vertices that connect\n            int firstP = -1;\n            int firstT = -1;\n            int secondP = -1;\n            int secondT = -1;\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (t[0].X == vertices[i].X && t[0].Y == vertices[i].Y)\n                {\n                    if (firstP == -1)\n                    {\n                        firstP = i;\n                        firstT = 0;\n                    }\n                    else\n                    {\n                        secondP = i;\n                        secondT = 0;\n                    }\n                }\n                else if (t[1].X == vertices[i].X && t[1].Y == vertices[i].Y)\n                {\n                    if (firstP == -1)\n                    {\n                        firstP = i;\n                        firstT = 1;\n                    }\n                    else\n                    {\n                        secondP = i;\n                        secondT = 1;\n                    }\n                }\n                else if (t[2].X == vertices[i].X && t[2].Y == vertices[i].Y)\n                {\n                    if (firstP == -1)\n                    {\n                        firstP = i;\n                        firstT = 2;\n                    }\n                    else\n                    {\n                        secondP = i;\n                        secondT = 2;\n                    }\n                }\n            }\n\n            // Fix ordering if first should be last vertex of poly\n            if (firstP == 0 && secondP == vertices.Count - 1)\n            {\n                firstP = vertices.Count - 1;\n                secondP = 0;\n            }\n\n            // Didn't find it\n            if (secondP == -1)\n            {\n                return null;\n            }\n\n            // Find tip index on triangle\n            int tipT = 0;\n            if (tipT == firstT || tipT == secondT)\n                tipT = 1;\n            if (tipT == firstT || tipT == secondT)\n                tipT = 2;\n\n            Vertices result = new Vertices(vertices.Count + 1);\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                result.Add(vertices[i]);\n\n                if (i == firstP)\n                    result.Add(t[tipT]);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/PolygonManipulation/SimplifyTools.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.PolygonManipulation\n{\n    /// <summary>\n    /// Provides a set of tools to simplify polygons in various ways.\n    /// </summary>\n    public static class SimplifyTools\n    {\n        /// <summary>\n        /// Removes all collinear points on the polygon.\n        /// </summary>\n        /// <param name=\"vertices\">The polygon that needs simplification.</param>\n        /// <param name=\"collinearityTolerance\">The collinearity tolerance.</param>\n        /// <returns>A simplified polygon.</returns>\n        public static Vertices CollinearSimplify(Vertices vertices, float collinearityTolerance = 0)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            Vertices simplified = new Vertices(vertices.Count);\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                Vector2 prev = vertices.PreviousVertex(i);\n                Vector2 current = vertices[i];\n                Vector2 next = vertices.NextVertex(i);\n\n                //If they collinear, continue\n                if (MathUtils.IsCollinear(ref prev, ref current, ref next, collinearityTolerance))\n                    continue;\n\n                simplified.Add(current);\n            }\n\n            return simplified;\n        }\n\n        /// <summary>\n        /// Ramer-Douglas-Peucker polygon simplification algorithm. This is the general recursive version that does not use the\n        /// speed-up technique by using the Melkman convex hull.\n        /// If you pass in 0, it will remove all collinear points.\n        /// </summary>\n        /// <returns>The simplified polygon</returns>\n        public static Vertices DouglasPeuckerSimplify(Vertices vertices, float distanceTolerance)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            bool[] usePoint = new bool[vertices.Count];\n\n            for (int i = 0; i < vertices.Count; i++)\n                usePoint[i] = true;\n\n            SimplifySection(vertices, 0, vertices.Count - 1, usePoint, distanceTolerance);\n\n            Vertices simplified = new Vertices(vertices.Count);\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (usePoint[i])\n                    simplified.Add(vertices[i]);\n            }\n\n            return simplified;\n        }\n\n        private static void SimplifySection(Vertices vertices, int i, int j, bool[] usePoint, float distanceTolerance)\n        {\n            if ((i + 1) == j)\n                return;\n\n            Vector2 a = vertices[i];\n            Vector2 b = vertices[j];\n\n            double maxDistance = -1.0;\n            int maxIndex = i;\n            for (int k = i + 1; k < j; k++)\n            {\n                Vector2 point = vertices[k];\n\n                double distance = LineUtils.DistanceBetweenPointAndLineSegment(ref point, ref a, ref b);\n\n                if (distance > maxDistance)\n                {\n                    maxDistance = distance;\n                    maxIndex = k;\n                }\n            }\n\n            if (maxDistance <= distanceTolerance)\n            {\n                for (int k = i + 1; k < j; k++)\n                {\n                    usePoint[k] = false;\n                }\n            }\n            else\n            {\n                SimplifySection(vertices, i, maxIndex, usePoint, distanceTolerance);\n                SimplifySection(vertices, maxIndex, j, usePoint, distanceTolerance);\n            }\n        }\n\n        /// <summary>\n        /// Merges all parallel edges in the list of vertices\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"tolerance\">The tolerance.</param>\n        public static Vertices MergeParallelEdges(Vertices vertices, float tolerance)\n        {\n            //From Eric Jordan's convex decomposition library\n\n            if (vertices.Count <= 3)\n                return vertices; //Can't do anything useful here to a triangle\n\n            bool[] mergeMe = new bool[vertices.Count];\n            int newNVertices = vertices.Count;\n\n            //Gather points to process\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                int lower = i == 0 ? vertices.Count - 1 : i - 1;\n                int middle = i;\n                int upper = i == vertices.Count - 1 ? 0 : i + 1;\n\n                float dx0 = vertices[middle].X - vertices[lower].X;\n                float dy0 = vertices[middle].Y - vertices[lower].Y;\n                float dx1 = vertices[upper].X - vertices[middle].X;\n                float dy1 = vertices[upper].Y - vertices[middle].Y;\n                float norm0 = (float)Math.Sqrt(dx0 * dx0 + dy0 * dy0);\n                float norm1 = (float)Math.Sqrt(dx1 * dx1 + dy1 * dy1);\n\n                if (!(norm0 > 0.0f && norm1 > 0.0f) && newNVertices > 3)\n                {\n                    //Merge identical points\n                    mergeMe[i] = true;\n                    --newNVertices;\n                }\n\n                dx0 /= norm0;\n                dy0 /= norm0;\n                dx1 /= norm1;\n                dy1 /= norm1;\n                float cross = dx0 * dy1 - dx1 * dy0;\n                float dot = dx0 * dx1 + dy0 * dy1;\n\n                if (Math.Abs(cross) < tolerance && dot > 0 && newNVertices > 3)\n                {\n                    mergeMe[i] = true;\n                    --newNVertices;\n                }\n                else\n                    mergeMe[i] = false;\n            }\n\n            if (newNVertices == vertices.Count || newNVertices == 0)\n                return vertices;\n\n            int currIndex = 0;\n\n            //Copy the vertices to a new list and clear the old\n            Vertices newVertices = new Vertices(newNVertices);\n\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                if (mergeMe[i] || currIndex == newNVertices)\n                    continue;\n\n                Debug.Assert(currIndex < newNVertices);\n\n                newVertices.Add(vertices[i]);\n                ++currIndex;\n            }\n\n            return newVertices;\n        }\n\n        /// <summary>\n        /// Merges the identical points in the polygon.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        public static Vertices MergeIdenticalPoints(Vertices vertices)\n        {\n            HashSet<Vector2> unique = new HashSet<Vector2>();\n\n            foreach (Vector2 vertex in vertices)\n            {\n                unique.Add(vertex);\n            }\n\n            return new Vertices(unique);\n        }\n\n        /// <summary>\n        /// Reduces the polygon by distance.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"distance\">The distance between points. Points closer than this will be removed.</param>\n        public static Vertices ReduceByDistance(Vertices vertices, float distance)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            float distance2 = distance * distance;\n\n            Vertices simplified = new Vertices(vertices.Count);\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                Vector2 current = vertices[i];\n                Vector2 next = vertices.NextVertex(i);\n\n                //If they are closer than the distance, continue\n                if ((next - current).LengthSquared() <= distance2)\n                    continue;\n\n                simplified.Add(current);\n            }\n\n            return simplified;\n        }\n\n        /// <summary>\n        /// Reduces the polygon by removing the Nth vertex in the vertices list.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"nth\">The Nth point to remove. Example: 5.</param>\n        /// <returns></returns>\n        public static Vertices ReduceByNth(Vertices vertices, int nth)\n        {\n            if (vertices.Count <= 3)\n                return vertices;\n\n            if (nth == 0)\n                return vertices;\n\n            Vertices simplified = new Vertices(vertices.Count);\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (i % nth == 0)\n                    continue;\n\n                simplified.Add(vertices[i]);\n            }\n\n            return simplified;\n        }\n\n        /// <summary>\n        /// Simplify the polygon by removing all points that in pairs of 3 have an area less than the tolerance.\n        /// Pass in 0 as tolerance, and it will only remove collinear points.\n        /// </summary>\n        /// <param name=\"vertices\"></param>\n        /// <param name=\"areaTolerance\"></param>\n        /// <returns></returns>\n        public static Vertices ReduceByArea(Vertices vertices, float areaTolerance)\n        {\n            //From physics2d.net\n\n            if (vertices.Count <= 3)\n                return vertices;\n\n            if (areaTolerance < 0)\n                throw new ArgumentOutOfRangeException(nameof(areaTolerance), \"must be equal to or greater than zero.\");\n\n            Vertices simplified = new Vertices(vertices.Count);\n            Vector2 v3;\n            Vector2 v1 = vertices[vertices.Count - 2];\n            Vector2 v2 = vertices[vertices.Count - 1];\n            areaTolerance *= 2;\n\n            for (int i = 0; i < vertices.Count; ++i, v2 = v3)\n            {\n                v3 = i == vertices.Count - 1 ? simplified[0] : vertices[i];\n\n                float old1;\n                MathUtils.Cross(ref v1, ref v2, out old1);\n\n                float old2;\n                MathUtils.Cross(ref v2, ref v3, out old2);\n\n                float new1;\n                MathUtils.Cross(ref v1, ref v3, out new1);\n\n                if (Math.Abs(new1 - (old1 + old2)) > areaTolerance)\n                {\n                    simplified.Add(v2);\n                    v1 = v2;\n                }\n            }\n\n            return simplified;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/TextureTools/MarchingSquares.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Tools.TextureTools\n{\n    // Ported by Matthew Bettcher - Feb 2011\n\n    /*\n    Copyright (c) 2010, Luca Deltodesco\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without modification, are permitted\n    provided that the following conditions are met:\n\n        * Redistributions of source code must retain the above copyright notice, this list of conditions\n\t      and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright notice, this list of\n\t      conditions and the following disclaimer in the documentation and/or other materials provided\n\t      with the distribution.\n        * Neither the name of the nape project nor the names of its contributors may be used to endorse\n\t     or promote products derived from this software without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n    */\n\n    public static class MarchingSquares\n    {\n        /// <summary>\n        /// Marching squares over the given domain using the mesh defined via the dimensions\n        /// (wid,hei) to build a set of polygons such that f(x,y) less than 0, using the given number\n        /// 'bin' for recursive linear inteprolation along cell boundaries.\n        /// if 'comb' is true, then the polygons will also be composited into larger possible concave\n        /// polygons.\n        /// </summary>\n        /// <param name=\"domain\"></param>\n        /// <param name=\"cellWidth\"></param>\n        /// <param name=\"cellHeight\"></param>\n        /// <param name=\"f\"></param>\n        /// <param name=\"lerpCount\"></param>\n        /// <param name=\"combine\"></param>\n        /// <returns></returns>\n        public static List<Vertices> DetectSquares(AABB domain, float cellWidth, float cellHeight, sbyte[,] f,\n                                                   int lerpCount, bool combine)\n        {\n            CxFastList<GeomPoly> ret = new CxFastList<GeomPoly>();\n\n            List<Vertices> verticesList = new List<Vertices>();\n\n            //NOTE: removed assignments as they were not used.\n            List<GeomPoly> polyList;\n            GeomPoly gp;\n\n            int xn = (int)(domain.Extents.X * 2 / cellWidth);\n            bool xp = xn == (domain.Extents.X * 2 / cellWidth);\n            int yn = (int)(domain.Extents.Y * 2 / cellHeight);\n            bool yp = yn == (domain.Extents.Y * 2 / cellHeight);\n            if (!xp)\n                xn++;\n            if (!yp)\n                yn++;\n\n            sbyte[,] fs = new sbyte[xn + 1, yn + 1];\n            GeomPolyVal[,] ps = new GeomPolyVal[xn + 1, yn + 1];\n\n            //populate shared function lookups.\n            for (int x = 0; x < xn + 1; x++)\n            {\n                int x0;\n                if (x == xn)\n                    x0 = (int)domain.UpperBound.X;\n                else\n                    x0 = (int)(x * cellWidth + domain.LowerBound.X);\n                for (int y = 0; y < yn + 1; y++)\n                {\n                    int y0;\n                    if (y == yn)\n                        y0 = (int)domain.UpperBound.Y;\n                    else\n                        y0 = (int)(y * cellHeight + domain.LowerBound.Y);\n                    fs[x, y] = f[x0, y0];\n                }\n            }\n\n            //generate sub-polys and combine to scan lines\n            for (int y = 0; y < yn; y++)\n            {\n                float y0 = y * cellHeight + domain.LowerBound.Y;\n                float y1;\n                if (y == yn - 1)\n                    y1 = domain.UpperBound.Y;\n                else\n                    y1 = y0 + cellHeight;\n                GeomPoly pre = null;\n                for (int x = 0; x < xn; x++)\n                {\n                    float x0 = x * cellWidth + domain.LowerBound.X;\n                    float x1;\n                    if (x == xn - 1)\n                        x1 = domain.UpperBound.X;\n                    else\n                        x1 = x0 + cellWidth;\n\n                    gp = new GeomPoly();\n\n                    int key = MarchSquare(f, fs, ref gp, x, y, x0, y0, x1, y1, lerpCount);\n                    if (gp.Length != 0)\n                    {\n                        if (combine && pre != null && (key & 9) != 0)\n                        {\n                            combLeft(ref pre, ref gp);\n                            gp = pre;\n                        }\n                        else\n                            ret.Add(gp);\n                        ps[x, y] = new GeomPolyVal(gp, key);\n                    }\n                    else\n                        gp = null;\n                    pre = gp;\n                }\n            }\n            if (!combine)\n            {\n                polyList = ret.GetListOfElements();\n\n                foreach (GeomPoly poly in polyList)\n                {\n                    verticesList.Add(new Vertices(poly.Points.GetListOfElements()));\n                }\n\n                return verticesList;\n            }\n\n            //combine scan lines together\n            for (int y = 1; y < yn; y++)\n            {\n                int x = 0;\n                while (x < xn)\n                {\n                    GeomPolyVal p = ps[x, y];\n\n                    //skip along scan line if no polygon exists at this point\n                    if (p == null)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    //skip along if current polygon cannot be combined above.\n                    if ((p.Key & 12) == 0)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    //skip along if no polygon exists above.\n                    GeomPolyVal u = ps[x, y - 1];\n                    if (u == null)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    //skip along if polygon above cannot be combined with.\n                    if ((u.Key & 3) == 0)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    float ax = x * cellWidth + domain.LowerBound.X;\n                    float ay = y * cellHeight + domain.LowerBound.Y;\n\n                    CxFastList<Vector2> bp = p.GeomP.Points;\n                    CxFastList<Vector2> ap = u.GeomP.Points;\n\n                    //skip if it's already been combined with above polygon\n                    if (u.GeomP == p.GeomP)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    //combine above (but disallow the hole thingies\n                    CxFastListNode<Vector2> bi = bp.Begin();\n                    while (Square(bi.Elem().Y - ay) > Settings.Epsilon || bi.Elem().X < ax)\n                        bi = bi.Next();\n\n                    //NOTE: Unused\n                    //Vector2 b0 = bi.elem();\n                    Vector2 b1 = bi.Next().Elem();\n                    if (Square(b1.Y - ay) > Settings.Epsilon)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    bool brk = true;\n                    CxFastListNode<Vector2> ai = ap.Begin();\n                    while (ai != ap.End())\n                    {\n                        if (VecDsq(ai.Elem(), b1) < Settings.Epsilon)\n                        {\n                            brk = false;\n                            break;\n                        }\n                        ai = ai.Next();\n                    }\n                    if (brk)\n                    {\n                        x++;\n                        continue;\n                    }\n\n                    CxFastListNode<Vector2> bj = bi.Next().Next();\n                    if (bj == bp.End())\n                        bj = bp.Begin();\n                    while (bj != bi)\n                    {\n                        ai = ap.Insert(ai, bj.Elem()); // .clone()\n                        bj = bj.Next();\n                        if (bj == bp.End())\n                            bj = bp.Begin();\n                        u.GeomP.Length++;\n                    }\n\n                    //u.p.simplify(float.Epsilon,float.Epsilon);\n                    //\n                    ax = x + 1;\n                    while (ax < xn)\n                    {\n                        GeomPolyVal p2 = ps[(int)ax, y];\n                        if (p2 == null || p2.GeomP != p.GeomP)\n                        {\n                            ax++;\n                            continue;\n                        }\n                        p2.GeomP = u.GeomP;\n                        ax++;\n                    }\n                    ax = x - 1;\n                    while (ax >= 0)\n                    {\n                        GeomPolyVal p2 = ps[(int)ax, y];\n                        if (p2 == null || p2.GeomP != p.GeomP)\n                        {\n                            ax--;\n                            continue;\n                        }\n                        p2.GeomP = u.GeomP;\n                        ax--;\n                    }\n                    ret.Remove(p.GeomP);\n                    p.GeomP = u.GeomP;\n\n                    x = (int)((bi.Next().Elem().X - domain.LowerBound.X) / cellWidth) + 1;\n\n                    //x++; this was already commented out!\n                }\n            }\n\n            polyList = ret.GetListOfElements();\n\n            foreach (GeomPoly poly in polyList)\n            {\n                verticesList.Add(new Vertices(poly.Points.GetListOfElements()));\n            }\n\n            return verticesList;\n        }\n\n        #region Private Methods\n\n        //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n        /** Linearly interpolate between (x0 to x1) given a value at these coordinates (v0 and v1)\n            such as to approximate value(return) = 0\n        **/\n\n        private static int[] _lookMarch =\n        {\n            0x00, 0xE0, 0x38, 0xD8, 0x0E, 0xEE, 0x36, 0xD6, 0x83, 0x63, 0xBB, 0x5B, 0x8D,\n            0x6D, 0xB5, 0x55\n        };\n\n        private static float Lerp(float x0, float x1, float v0, float v1)\n        {\n            float dv = v0 - v1;\n            float t;\n            if (dv * dv < Settings.Epsilon)\n                t = 0.5f;\n            else\n                t = v0 / dv;\n            return x0 + t * (x1 - x0);\n        }\n\n        //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n        /** Recursive linear interpolation for use in marching squares **/\n\n        private static float Xlerp(float x0, float x1, float y, float v0, float v1, sbyte[,] f, int c)\n        {\n            float xm = Lerp(x0, x1, v0, v1);\n            if (c == 0)\n                return xm;\n\n            sbyte vm = f[(int)xm, (int)y];\n\n            if (v0 * vm < 0)\n                return Xlerp(x0, xm, y, v0, vm, f, c - 1);\n\n            return Xlerp(xm, x1, y, vm, v1, f, c - 1);\n        }\n\n        /** Recursive linear interpolation for use in marching squares **/\n\n        private static float Ylerp(float y0, float y1, float x, float v0, float v1, sbyte[,] f, int c)\n        {\n            float ym = Lerp(y0, y1, v0, v1);\n            if (c == 0)\n                return ym;\n\n            sbyte vm = f[(int)x, (int)ym];\n\n            if (v0 * vm < 0)\n                return Ylerp(y0, ym, x, v0, vm, f, c - 1);\n\n            return Ylerp(ym, y1, x, vm, v1, f, c - 1);\n        }\n\n        /** Square value for use in marching squares **/\n\n        private static float Square(float x)\n        {\n            return x * x;\n        }\n\n        private static float VecDsq(Vector2 a, Vector2 b)\n        {\n            Vector2 d = a - b;\n            return d.X * d.X + d.Y * d.Y;\n        }\n\n        private static float VecCross(Vector2 a, Vector2 b)\n        {\n            return a.X * b.Y - a.Y * b.X;\n        }\n\n        /** Look-up table to relate polygon key with the vertices that should be used for\n            the sub polygon in marching squares\n        **/\n\n        /** Perform a single celled marching square for for the given cell defined by (x0,y0) (x1,y1)\n            using the function f for recursive interpolation, given the look-up table 'fs' of\n            the values of 'f' at cell vertices with the result to be stored in 'poly' given the actual\n            coordinates of 'ax' 'ay' in the marching squares mesh.\n        **/\n\n        private static int MarchSquare(sbyte[,] f, sbyte[,] fs, ref GeomPoly poly, int ax, int ay, float x0, float y0,\n                                       float x1, float y1, int bin)\n        {\n            //key lookup\n            int key = 0;\n            sbyte v0 = fs[ax, ay];\n            if (v0 < 0)\n                key |= 8;\n            sbyte v1 = fs[ax + 1, ay];\n            if (v1 < 0)\n                key |= 4;\n            sbyte v2 = fs[ax + 1, ay + 1];\n            if (v2 < 0)\n                key |= 2;\n            sbyte v3 = fs[ax, ay + 1];\n            if (v3 < 0)\n                key |= 1;\n\n            int val = _lookMarch[key];\n            if (val != 0)\n            {\n                CxFastListNode<Vector2> pi = null;\n                for (int i = 0; i < 8; i++)\n                {\n                    Vector2 p;\n                    if ((val & (1 << i)) != 0)\n                    {\n                        if (i == 7 && (val & 1) == 0)\n                            poly.Points.Add(p = new Vector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin)));\n                        else\n                        {\n                            if (i == 0)\n                                p = new Vector2(x0, y0);\n                            else if (i == 2)\n                                p = new Vector2(x1, y0);\n                            else if (i == 4)\n                                p = new Vector2(x1, y1);\n                            else if (i == 6)\n                                p = new Vector2(x0, y1);\n\n                            else if (i == 1)\n                                p = new Vector2(Xlerp(x0, x1, y0, v0, v1, f, bin), y0);\n                            else if (i == 5)\n                                p = new Vector2(Xlerp(x0, x1, y1, v3, v2, f, bin), y1);\n\n                            else if (i == 3)\n                                p = new Vector2(x1, Ylerp(y0, y1, x1, v1, v2, f, bin));\n                            else\n                                p = new Vector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin));\n\n                            pi = poly.Points.Insert(pi, p);\n                        }\n                        poly.Length++;\n                    }\n                }\n\n                //poly.simplify(float.Epsilon,float.Epsilon);\n            }\n            return key;\n        }\n\n        /** Used in polygon composition to composit polygons into scan lines\n            Combining polya and polyb into one super-polygon stored in polya.\n        **/\n\n        private static void combLeft(ref GeomPoly polya, ref GeomPoly polyb)\n        {\n            CxFastList<Vector2> ap = polya.Points;\n            CxFastList<Vector2> bp = polyb.Points;\n            CxFastListNode<Vector2> ai = ap.Begin();\n            CxFastListNode<Vector2> bi = bp.Begin();\n\n            Vector2 b = bi.Elem();\n            CxFastListNode<Vector2> prea = null;\n            while (ai != ap.End())\n            {\n                Vector2 a = ai.Elem();\n                if (VecDsq(a, b) < Settings.Epsilon)\n                {\n                    //ignore shared vertex if parallel\n                    if (prea != null)\n                    {\n                        Vector2 a0 = prea.Elem();\n                        b = bi.Next().Elem();\n\n                        Vector2 u = a - a0;\n\n                        //vec_new(u); vec_sub(a.p.p, a0.p.p, u);\n                        Vector2 v = b - a;\n\n                        //vec_new(v); vec_sub(b.p.p, a.p.p, v);\n                        float dot = VecCross(u, v);\n                        if (dot * dot < Settings.Epsilon)\n                        {\n                            ap.Erase(prea, ai);\n                            polya.Length--;\n                            ai = prea;\n                        }\n                    }\n\n                    //insert polyb into polya\n                    bool fst = true;\n                    CxFastListNode<Vector2> preb = null;\n                    while (!bp.Empty())\n                    {\n                        Vector2 bb = bp.Front();\n                        bp.Pop();\n                        if (!fst && !bp.Empty())\n                        {\n                            ai = ap.Insert(ai, bb);\n                            polya.Length++;\n                            preb = ai;\n                        }\n                        fst = false;\n                    }\n\n                    //ignore shared vertex if parallel\n                    ai = ai.Next();\n                    Vector2 a1 = ai.Elem();\n                    ai = ai.Next();\n                    if (ai == ap.End())\n                        ai = ap.Begin();\n                    Vector2 a2 = ai.Elem();\n                    Vector2 a00 = preb.Elem();\n                    Vector2 uu = a1 - a00;\n\n                    //vec_new(u); vec_sub(a1.p, a0.p, u);\n                    Vector2 vv = a2 - a1;\n\n                    //vec_new(v); vec_sub(a2.p, a1.p, v);\n                    float dot1 = VecCross(uu, vv);\n                    if (dot1 * dot1 < Settings.Epsilon)\n                    {\n                        ap.Erase(preb, preb.Next());\n                        polya.Length--;\n                    }\n\n                    return;\n                }\n                prea = ai;\n                ai = ai.Next();\n            }\n        }\n\n        #endregion\n\n        #region CxFastList from nape physics\n\n        #region Nested type: CxFastList\n\n        /// <summary>\n        /// Designed as a complete port of CxFastList from CxStd.\n        /// </summary>\n        internal class CxFastList<T>\n        {\n            private int _count;\n\n            // first node in the list\n            private CxFastListNode<T> _head;\n\n            /// <summary>\n            /// Iterator to start of list (O(1))\n            /// </summary>\n            public CxFastListNode<T> Begin()\n            {\n                return _head;\n            }\n\n            /// <summary>\n            /// Iterator to end of list (O(1))\n            /// </summary>\n            public CxFastListNode<T> End()\n            {\n                return null;\n            }\n\n            /// <summary>\n            /// Returns first element of list (O(1))\n            /// </summary>\n            public T Front()\n            {\n                return _head.Elem();\n            }\n\n            /// <summary>\n            /// add object to list (O(1))\n            /// </summary>\n            public CxFastListNode<T> Add(T value)\n            {\n                CxFastListNode<T> newNode = new CxFastListNode<T>(value);\n                if (_head == null)\n                {\n                    newNode._next = null;\n                    _head = newNode;\n                    _count++;\n                    return newNode;\n                }\n                newNode._next = _head;\n                _head = newNode;\n\n                _count++;\n\n                return newNode;\n            }\n\n            /// <summary>\n            /// remove object from list, returns true if an element was removed (O(n))\n            /// </summary>\n            public bool Remove(T value)\n            {\n                CxFastListNode<T> head = _head;\n                CxFastListNode<T> prev = _head;\n\n                EqualityComparer<T> comparer = EqualityComparer<T>.Default;\n\n                if (head != null)\n                {\n                    if (value != null)\n                    {\n                        do\n                        {\n                            // if we are on the value to be removed\n                            if (comparer.Equals(head._elt, value))\n                            {\n                                // then we need to patch the list\n                                // check to see if we are removing the _head\n                                if (head == _head)\n                                {\n                                    _head = head._next;\n                                    _count--;\n                                    return true;\n                                }\n                                else\n                                {\n                                    // were not at the head\n                                    prev._next = head._next;\n                                    _count--;\n                                    return true;\n                                }\n                            }\n\n                            // cache the current as the previous for the next go around\n                            prev = head;\n                            head = head._next;\n                        } while (head != null);\n                    }\n                }\n                return false;\n            }\n\n            /// <summary>\n            /// pop element from head of list (O(1)) Note: this does not return the object popped!\n            /// There is good reason to this, and it regards the Alloc list variants which guarantee\n            /// objects are released to the object pool. You do not want to retrieve an element\n            /// through pop or else that object may suddenly be used by another piece of code which\n            /// retrieves it from the object pool.\n            /// </summary>\n            public CxFastListNode<T> Pop()\n            {\n                return Erase(null, _head);\n            }\n\n            /// <summary>\n            /// insert object after 'node' returning an iterator to the inserted object.\n            /// </summary>\n            public CxFastListNode<T> Insert(CxFastListNode<T> node, T value)\n            {\n                if (node == null)\n                {\n                    return Add(value);\n                }\n                CxFastListNode<T> newNode = new CxFastListNode<T>(value);\n                CxFastListNode<T> nextNode = node._next;\n                newNode._next = nextNode;\n                node._next = newNode;\n\n                _count++;\n\n                return newNode;\n            }\n\n            /// <summary>\n            /// removes the element pointed to by 'node' with 'prev' being the previous iterator,\n            /// returning an iterator to the element following that of 'node' (O(1))\n            /// </summary>\n            public CxFastListNode<T> Erase(CxFastListNode<T> prev, CxFastListNode<T> node)\n            {\n                // cache the node after the node to be removed\n                CxFastListNode<T> nextNode = node._next;\n                if (prev != null)\n                    prev._next = nextNode;\n                else if (_head != null)\n                    _head = _head._next;\n                else\n                    return null;\n\n                _count--;\n                return nextNode;\n            }\n\n            /// <summary>\n            /// whether the list is empty (O(1))\n            /// </summary>\n            public bool Empty()\n            {\n                if (_head == null)\n                    return true;\n                return false;\n            }\n\n            /// <summary>\n            /// computes size of list (O(n))\n            /// </summary>\n            public int Size()\n            {\n                CxFastListNode<T> i = Begin();\n                int count = 0;\n\n                do\n                {\n                    count++;\n                } while (i.Next() != null);\n\n                return count;\n            }\n\n            /// <summary>\n            /// empty the list (O(1) if CxMixList, O(n) otherwise)\n            /// </summary>\n            public void Clear()\n            {\n                CxFastListNode<T> head = _head;\n                while (head != null)\n                {\n                    CxFastListNode<T> node2 = head;\n                    head = head._next;\n                    node2._next = null;\n                }\n                _head = null;\n                _count = 0;\n            }\n\n            /// <summary>\n            /// returns true if 'value' is an element of the list (O(n))\n            /// </summary>\n            public bool Has(T value)\n            {\n                return (Find(value) != null);\n            }\n\n            // Non CxFastList Methods \n            public CxFastListNode<T> Find(T value)\n            {\n                // start at head\n                CxFastListNode<T> head = _head;\n                EqualityComparer<T> comparer = EqualityComparer<T>.Default;\n                if (head != null)\n                {\n                    if (value != null)\n                    {\n                        do\n                        {\n                            if (comparer.Equals(head._elt, value))\n                            {\n                                return head;\n                            }\n                            head = head._next;\n                        } while (head != _head);\n                    }\n                    else\n                    {\n                        do\n                        {\n                            if (head._elt == null)\n                            {\n                                return head;\n                            }\n                            head = head._next;\n                        } while (head != _head);\n                    }\n                }\n                return null;\n            }\n\n            public List<T> GetListOfElements()\n            {\n                List<T> list = new List<T>();\n\n                CxFastListNode<T> iter = Begin();\n\n                if (iter != null)\n                {\n                    do\n                    {\n                        list.Add(iter._elt);\n                        iter = iter._next;\n                    } while (iter != null);\n                }\n                return list;\n            }\n        }\n\n        #endregion\n\n        #region Nested type: CxFastListNode\n\n        internal class CxFastListNode<T>\n        {\n            internal T _elt;\n            internal CxFastListNode<T> _next;\n\n            public CxFastListNode(T obj)\n            {\n                _elt = obj;\n            }\n\n            public T Elem()\n            {\n                return _elt;\n            }\n\n            public CxFastListNode<T> Next()\n            {\n                return _next;\n            }\n        }\n\n        #endregion\n\n        #endregion\n\n        #region Internal Stuff\n\n        #region Nested type: GeomPoly\n\n        internal class GeomPoly\n        {\n            public int Length;\n            public CxFastList<Vector2> Points;\n\n            public GeomPoly()\n            {\n                Points = new CxFastList<Vector2>();\n                Length = 0;\n            }\n        }\n\n        #endregion\n\n        #region Nested type: GeomPolyVal\n\n        private class GeomPolyVal\n        {\n            public GeomPoly GeomP;\n\n            /** Associated polygon at coordinate **/\n            /** Key of original sub-polygon **/\n            public int Key;\n\n            public GeomPolyVal(GeomPoly geomP, int K)\n            {\n                GeomP = geomP;\n                Key = K;\n            }\n        }\n\n        #endregion\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/TextureTools/Terrain.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Dynamics;\nusing VelcroPhysics.Factories;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.PolygonManipulation;\nusing VelcroPhysics.Tools.Triangulation.TriangulationBase;\n\nnamespace VelcroPhysics.Tools.TextureTools\n{\n    /// <summary>\n    /// Simple class to maintain a terrain. It can keep track\n    /// </summary>\n    public class Terrain\n    {\n        /// <summary>\n        /// Generated bodies.\n        /// </summary>\n        private List<Body>[,] _bodyMap;\n\n        private AABB _dirtyArea;\n        private float _localHeight;\n\n        private float _localWidth;\n\n        /// <summary>\n        /// Point cloud defining the terrain.\n        /// </summary>\n        private sbyte[,] _terrainMap;\n\n        private Vector2 _topLeft;\n        private int _xnum;\n        private int _ynum;\n\n        /// <summary>\n        /// Points per cell.\n        /// </summary>\n        public int CellSize;\n\n        /// <summary>\n        /// Center of terrain in world units.\n        /// </summary>\n        public Vector2 Center;\n\n        /// <summary>\n        /// Decomposer to use when regenerating terrain. Can be changed on the fly without consequence.\n        /// Note: Some decomposerers are unstable.\n        /// </summary>\n        public TriangulationAlgorithm Decomposer;\n\n        /// <summary>\n        /// Height of terrain in world units.\n        /// </summary>\n        public float Height;\n\n        /// <summary>\n        /// Number of iterations to perform in the Marching Squares algorithm.\n        /// Note: More then 3 has almost no effect on quality.\n        /// </summary>\n        public int Iterations = 2;\n\n        /// <summary>\n        /// Points per each world unit used to define the terrain in the point cloud.\n        /// </summary>\n        public int PointsPerUnit;\n\n        /// <summary>\n        /// Points per sub cell.\n        /// </summary>\n        public int SubCellSize;\n\n        /// <summary>\n        /// Width of terrain in world units.\n        /// </summary>\n        public float Width;\n\n        /// <summary>\n        /// World to manage terrain in.\n        /// </summary>\n        public World World;\n\n        /// <summary>\n        /// Creates a new terrain.\n        /// </summary>\n        /// <param name=\"world\">The World</param>\n        /// <param name=\"area\">The area of the terrain.</param>\n        public Terrain(World world, AABB area)\n        {\n            World = world;\n            Width = area.Width;\n            Height = area.Height;\n            Center = area.Center;\n        }\n\n        /// <summary>\n        /// Creates a new terrain\n        /// </summary>\n        /// <param name=\"world\">The World</param>\n        /// <param name=\"position\">The position (center) of the terrain.</param>\n        /// <param name=\"width\">The width of the terrain.</param>\n        /// <param name=\"height\">The height of the terrain.</param>\n        public Terrain(World world, Vector2 position, float width, float height)\n        {\n            World = world;\n            Width = width;\n            Height = height;\n            Center = position;\n        }\n\n        /// <summary>\n        /// Initialize the terrain for use.\n        /// </summary>\n        public void Initialize()\n        {\n            // find top left of terrain in world space\n            _topLeft = new Vector2(Center.X - (Width * 0.5f), Center.Y - (-Height * 0.5f));\n\n            // convert the terrains size to a point cloud size\n            _localWidth = Width * PointsPerUnit;\n            _localHeight = Height * PointsPerUnit;\n\n            _terrainMap = new sbyte[(int)_localWidth + 1, (int)_localHeight + 1];\n\n            for (int x = 0; x < _localWidth; x++)\n            {\n                for (int y = 0; y < _localHeight; y++)\n                {\n                    _terrainMap[x, y] = 1;\n                }\n            }\n\n            _xnum = (int)(_localWidth / CellSize);\n            _ynum = (int)(_localHeight / CellSize);\n            _bodyMap = new List<Body>[_xnum, _ynum];\n\n            // make sure to mark the dirty area to an infinitely small box\n            _dirtyArea = new AABB(new Vector2(float.MaxValue, float.MaxValue), new Vector2(float.MinValue, float.MinValue));\n        }\n\n        /// <summary>\n        /// Apply the specified texture data to the terrain.\n        /// </summary>\n        /// <param name=\"data\"></param>\n        /// <param name=\"offset\"></param>\n        public void ApplyData(sbyte[,] data, Vector2 offset = default(Vector2))\n        {\n            for (int x = 0; x < data.GetUpperBound(0); x++)\n            {\n                for (int y = 0; y < data.GetUpperBound(1); y++)\n                {\n                    if (x + offset.X >= 0 && x + offset.X < _localWidth && y + offset.Y >= 0 && y + offset.Y < _localHeight)\n                    {\n                        _terrainMap[(int)(x + offset.X), (int)(y + offset.Y)] = data[x, y];\n                    }\n                }\n            }\n\n            RemoveOldData(0, _xnum, 0, _ynum);\n        }\n\n        /// <summary>\n        /// Modify a single point in the terrain.\n        /// </summary>\n        /// <param name=\"location\">World location to modify. Automatically clipped.</param>\n        /// <param name=\"value\">-1 = inside terrain, 1 = outside terrain</param>\n        public void ModifyTerrain(Vector2 location, sbyte value)\n        {\n            // find local position\n            // make position local to map space\n            Vector2 p = location - _topLeft;\n\n            // find map position for each axis\n            p.X = p.X * _localWidth / Width;\n            p.Y = p.Y * -_localHeight / Height;\n\n            if (p.X >= 0 && p.X < _localWidth && p.Y >= 0 && p.Y < _localHeight)\n            {\n                _terrainMap[(int)p.X, (int)p.Y] = value;\n\n                // expand dirty area\n                if (p.X < _dirtyArea.LowerBound.X)\n                    _dirtyArea.LowerBound.X = p.X;\n                if (p.X > _dirtyArea.UpperBound.X)\n                    _dirtyArea.UpperBound.X = p.X;\n\n                if (p.Y < _dirtyArea.LowerBound.Y)\n                    _dirtyArea.LowerBound.Y = p.Y;\n                if (p.Y > _dirtyArea.UpperBound.Y)\n                    _dirtyArea.UpperBound.Y = p.Y;\n            }\n        }\n\n        /// <summary>\n        /// Regenerate the terrain.\n        /// </summary>\n        public void RegenerateTerrain()\n        {\n            //iterate effected cells\n            int xStart = (int)(_dirtyArea.LowerBound.X / CellSize);\n            if (xStart < 0)\n                xStart = 0;\n\n            int xEnd = (int)(_dirtyArea.UpperBound.X / CellSize) + 1;\n            if (xEnd > _xnum)\n                xEnd = _xnum;\n\n            int yStart = (int)(_dirtyArea.LowerBound.Y / CellSize);\n            if (yStart < 0)\n                yStart = 0;\n\n            int yEnd = (int)(_dirtyArea.UpperBound.Y / CellSize) + 1;\n            if (yEnd > _ynum)\n                yEnd = _ynum;\n\n            RemoveOldData(xStart, xEnd, yStart, yEnd);\n\n            _dirtyArea = new AABB(new Vector2(float.MaxValue, float.MaxValue), new Vector2(float.MinValue, float.MinValue));\n        }\n\n        private void RemoveOldData(int xStart, int xEnd, int yStart, int yEnd)\n        {\n            for (int x = xStart; x < xEnd; x++)\n            {\n                for (int y = yStart; y < yEnd; y++)\n                {\n                    //remove old terrain object at grid cell\n                    if (_bodyMap[x, y] != null)\n                    {\n                        for (int i = 0; i < _bodyMap[x, y].Count; i++)\n                        {\n                            World.RemoveBody(_bodyMap[x, y][i]);\n                        }\n                    }\n\n                    _bodyMap[x, y] = null;\n\n                    //generate new one\n                    GenerateTerrain(x, y);\n                }\n            }\n        }\n\n        private void GenerateTerrain(int gx, int gy)\n        {\n            float ax = gx * CellSize;\n            float ay = gy * CellSize;\n\n            List<Vertices> polys = MarchingSquares.DetectSquares(new AABB(new Vector2(ax, ay), new Vector2(ax + CellSize, ay + CellSize)), SubCellSize, SubCellSize, _terrainMap, Iterations, true);\n            if (polys.Count == 0)\n                return;\n\n            _bodyMap[gx, gy] = new List<Body>();\n\n            // create the scale vector\n            Vector2 scale = new Vector2(1f / PointsPerUnit, 1f / -PointsPerUnit);\n\n            // create physics object for this grid cell\n            foreach (Vertices item in polys)\n            {\n                // does this need to be negative?\n                item.Scale(ref scale);\n                item.Translate(ref _topLeft);\n                Vertices simplified = SimplifyTools.CollinearSimplify(item);\n\n                List<Vertices> decompPolys = Triangulate.ConvexPartition(simplified, Decomposer);\n\n                foreach (Vertices poly in decompPolys)\n                {\n                    if (poly.Count > 2)\n                        _bodyMap[gx, gy].Add(BodyFactory.CreatePolygon(World, poly, 1));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/TextureTools/TextureConverter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.TextureTools\n{\n    // User contribution from Sickbattery aka David Reschke.\n\n    public sealed class TextureConverter\n    {\n        private const int ClosepixelsLength = 8;\n\n        /// <summary>\n        /// This array is meant to be read-only.\n        /// It's not because it is accessed very frequently.\n        /// </summary>\n        private static int[,] _closePixels = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } };\n\n        private uint _alphaTolerance;\n\n        private uint[] _data;\n        private int _dataLength;\n        private int _height;\n\n        private bool _holeDetection;\n        private float _hullTolerance;\n        private bool _multipartDetection;\n        private bool _pixelOffsetOptimization;\n\n        private VerticesDetectionType _polygonDetectionType;\n\n        private Matrix _transform = Matrix.Identity;\n        private int _width;\n\n        #region Initialization\n\n        private void Initialize(uint[] data, int? width, byte? alphaTolerance,\n                                float? hullTolerance, bool? holeDetection, bool? multipartDetection,\n                                bool? pixelOffsetOptimization, Matrix? transform)\n        {\n            if (data != null && !width.HasValue)\n                throw new ArgumentNullException(nameof(width), \"'width' can't be null if 'data' is set.\");\n\n            if (data == null && width.HasValue)\n                throw new ArgumentNullException(nameof(data), \"'data' can't be null if 'width' is set.\");\n\n            if (data != null && width.HasValue)\n                SetTextureData(data, width.Value);\n\n            if (alphaTolerance.HasValue)\n                AlphaTolerance = alphaTolerance.Value;\n            else\n                AlphaTolerance = 20;\n\n            if (hullTolerance.HasValue)\n                HullTolerance = hullTolerance.Value;\n            else\n                HullTolerance = 1.5f;\n\n            if (holeDetection.HasValue)\n                HoleDetection = holeDetection.Value;\n            else\n                HoleDetection = false;\n\n            if (multipartDetection.HasValue)\n                MultipartDetection = multipartDetection.Value;\n            else\n                MultipartDetection = false;\n\n            if (pixelOffsetOptimization.HasValue)\n                PixelOffsetOptimization = pixelOffsetOptimization.Value;\n            else\n                PixelOffsetOptimization = false;\n\n            if (transform.HasValue)\n                Transform = transform.Value;\n            else\n                Transform = Matrix.Identity;\n        }\n\n        #endregion\n\n        private void SetTextureData(uint[] data, int width)\n        {\n            if (data == null)\n                throw new ArgumentNullException(nameof(data), \"'data' can't be null.\");\n\n            if (data.Length < 4)\n                throw new ArgumentOutOfRangeException(nameof(data), \"'data' length can't be less then 4. Your texture must be at least 2 x 2 pixels in size.\");\n\n            if (width < 2)\n                throw new ArgumentOutOfRangeException(nameof(width), \"'width' can't be less then 2. Your texture must be at least 2 x 2 pixels in size.\");\n\n            if (data.Length % width != 0)\n                throw new ArgumentException(\"'width' has an invalid value.\");\n\n            _data = data;\n            _dataLength = _data.Length;\n            _width = width;\n            _height = _dataLength / width;\n        }\n\n        /// <summary>\n        /// Detects the vertices of the supplied texture data. (PolygonDetectionType.Integrated)\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <returns></returns>\n        public static Vertices DetectVertices(uint[] data, int width)\n        {\n            TextureConverter tc = new TextureConverter(data, width);\n\n            List<Vertices> detectedVerticesList = tc.DetectVertices();\n\n            return detectedVerticesList[0];\n        }\n\n        /// <summary>\n        /// Detects the vertices of the supplied texture data.\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <param name=\"holeDetection\">if set to <c>true</c> it will perform hole detection.</param>\n        /// <returns></returns>\n        public static Vertices DetectVertices(uint[] data, int width, bool holeDetection)\n        {\n            TextureConverter tc = new TextureConverter(data, width)\n            {\n                HoleDetection = holeDetection\n            };\n\n            List<Vertices> detectedVerticesList = tc.DetectVertices();\n\n            return detectedVerticesList[0];\n        }\n\n        /// <summary>\n        /// Detects the vertices of the supplied texture data.\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <param name=\"holeDetection\">if set to <c>true</c> it will perform hole detection.</param>\n        /// <param name=\"hullTolerance\">The hull tolerance.</param>\n        /// <param name=\"alphaTolerance\">The alpha tolerance.</param>\n        /// <param name=\"multiPartDetection\">if set to <c>true</c> it will perform multi part detection.</param>\n        /// <returns></returns>\n        public static List<Vertices> DetectVertices(uint[] data, int width, float hullTolerance, byte alphaTolerance, bool multiPartDetection, bool holeDetection)\n        {\n            TextureConverter tc =\n                new TextureConverter(data, width)\n                {\n                    HullTolerance = hullTolerance,\n                    AlphaTolerance = alphaTolerance,\n                    MultipartDetection = multiPartDetection,\n                    HoleDetection = holeDetection\n                };\n\n            List<Vertices> detectedVerticesList = tc.DetectVertices();\n            List<Vertices> result = new List<Vertices>();\n\n            for (int i = 0; i < detectedVerticesList.Count; i++)\n            {\n                result.Add(detectedVerticesList[i]);\n            }\n\n            return result;\n        }\n\n        public List<Vertices> DetectVertices()\n        {\n            #region Check TextureConverter setup.\n\n            if (_data == null)\n                throw new Exception(\"'_data' can't be null. You have to use SetTextureData(uint[] data, int width) before calling this method.\");\n\n            if (_data.Length < 4)\n                throw new Exception(\"'_data' length can't be less then 4. Your texture must be at least 2 x 2 pixels in size. \" +\n                                    \"You have to use SetTextureData(uint[] data, int width) before calling this method.\");\n\n            if (_width < 2)\n                throw new Exception(\"'_width' can't be less then 2. Your texture must be at least 2 x 2 pixels in size. \" +\n                                    \"You have to use SetTextureData(uint[] data, int width) before calling this method.\");\n\n            if (_data.Length % _width != 0)\n                throw new Exception(\"'_width' has an invalid value. You have to use SetTextureData(uint[] data, int width) before calling this method.\");\n\n            #endregion\n\n            List<Vertices> detectedPolygons = new List<Vertices>();\n\n            Vector2? holeEntrance = null;\n            Vector2? polygonEntrance = null;\n\n            List<Vector2> blackList = new List<Vector2>();\n\n            bool searchOn;\n            do\n            {\n                Vertices polygon;\n                if (detectedPolygons.Count == 0)\n                {\n                    // First pass / single polygon\n                    polygon = new Vertices(CreateSimplePolygon(Vector2.Zero, Vector2.Zero));\n\n                    if (polygon.Count > 2)\n                        polygonEntrance = GetTopMostVertex(polygon);\n                }\n                else if (polygonEntrance.HasValue)\n                {\n                    // Multi pass / multiple polygons\n                    polygon = new Vertices(CreateSimplePolygon(polygonEntrance.Value, new Vector2(polygonEntrance.Value.X - 1f, polygonEntrance.Value.Y)));\n                }\n                else\n                    break;\n\n                searchOn = false;\n\n                if (polygon.Count > 2)\n                {\n                    if (_holeDetection)\n                    {\n                        do\n                        {\n                            holeEntrance = SearchHoleEntrance(polygon, holeEntrance);\n\n                            if (holeEntrance.HasValue)\n                            {\n                                if (!blackList.Contains(holeEntrance.Value))\n                                {\n                                    blackList.Add(holeEntrance.Value);\n                                    Vertices holePolygon = CreateSimplePolygon(holeEntrance.Value,\n                                        new Vector2(holeEntrance.Value.X + 1, holeEntrance.Value.Y));\n\n                                    if (holePolygon != null && holePolygon.Count > 2)\n                                    {\n                                        switch (_polygonDetectionType)\n                                        {\n                                            case VerticesDetectionType.Integrated:\n\n                                                // Add first hole polygon vertex to close the hole polygon.\n                                                holePolygon.Add(holePolygon[0]);\n\n                                                int vertex1Index, vertex2Index;\n                                                if (SplitPolygonEdge(polygon, holeEntrance.Value, out vertex1Index, out vertex2Index))\n                                                    polygon.InsertRange(vertex2Index, holePolygon);\n\n                                                break;\n\n                                            case VerticesDetectionType.Separated:\n                                                if (polygon.Holes == null)\n                                                    polygon.Holes = new List<Vertices>();\n\n                                                polygon.Holes.Add(holePolygon);\n                                                break;\n                                        }\n                                    }\n                                }\n                                else\n                                    break;\n                            }\n                            else\n                                break;\n                        } while (true);\n                    }\n\n                    detectedPolygons.Add(polygon);\n                }\n\n                if (_multipartDetection || polygon.Count <= 2)\n                {\n                    if (SearchNextHullEntrance(detectedPolygons, polygonEntrance.Value, out polygonEntrance))\n                        searchOn = true;\n                }\n            } while (searchOn);\n\n            if (detectedPolygons.Count == 0)\n                throw new Exception(\"Couldn't detect any vertices.\");\n\n            // Post processing.\n            if (PolygonDetectionType == VerticesDetectionType.Separated) // Only when VerticesDetectionType.Separated? -> Recheck.\n                ApplyTriangulationCompatibleWinding(ref detectedPolygons);\n\n            if (_transform != Matrix.Identity)\n                ApplyTransform(ref detectedPolygons);\n\n            return detectedPolygons;\n        }\n\n        private void ApplyTriangulationCompatibleWinding(ref List<Vertices> detectedPolygons)\n        {\n            for (int i = 0; i < detectedPolygons.Count; i++)\n            {\n                detectedPolygons[i].Reverse();\n\n                if (detectedPolygons[i].Holes != null && detectedPolygons[i].Holes.Count > 0)\n                {\n                    for (int j = 0; j < detectedPolygons[i].Holes.Count; j++)\n                        detectedPolygons[i].Holes[j].Reverse();\n                }\n            }\n        }\n\n        private void ApplyTransform(ref List<Vertices> detectedPolygons)\n        {\n            for (int i = 0; i < detectedPolygons.Count; i++)\n                detectedPolygons[i].Transform(ref _transform);\n        }\n\n        /// <summary>\n        /// Function to search for an entrance point of a hole in a polygon. It searches the polygon from top to bottom between the\n        /// polygon edges.\n        /// </summary>\n        /// <param name=\"polygon\">The polygon to search in.</param>\n        /// <param name=\"lastHoleEntrance\">The last entrance point.</param>\n        /// <returns>The next holes entrance point. Null if there are no holes.</returns>\n        private Vector2? SearchHoleEntrance(Vertices polygon, Vector2? lastHoleEntrance)\n        {\n            if (polygon == null)\n                throw new ArgumentNullException(\"'polygon' can't be null.\");\n\n            if (polygon.Count < 3)\n                throw new ArgumentException(\"'polygon.MainPolygon.Count' can't be less then 3.\");\n\n            List<float> xCoords;\n            Vector2? entrance;\n\n            int startY;\n            int endY;\n\n            int lastSolid = 0;\n            bool foundSolid;\n            bool foundTransparent;\n\n            // Set start y coordinate.\n            if (lastHoleEntrance.HasValue)\n            {\n                // We need the y coordinate only.\n                startY = (int)lastHoleEntrance.Value.Y;\n            }\n            else\n            {\n                // Start from the top of the polygon if last entrance == null.\n                startY = (int)GetTopMostCoord(polygon);\n            }\n\n            // Set the end y coordinate.\n            endY = (int)GetBottomMostCoord(polygon);\n\n            if (startY > 0 && startY < _height && endY > 0 && endY < _height)\n            {\n                // go from top to bottom of the polygon\n                for (int y = startY; y <= endY; y++)\n                {\n                    // get x-coord of every polygon edge which crosses y\n                    xCoords = SearchCrossingEdges(polygon, y);\n\n                    // We need an even number of crossing edges. \n                    // It's always a pair of start and end edge: nothing | polygon | hole | polygon | nothing ...\n                    // If it's not then don't bother, it's probably a peak ...\n                    // ...which should be filtered out by SearchCrossingEdges() anyway.\n                    if (xCoords.Count > 1 && xCoords.Count % 2 == 0)\n                    {\n                        // Ok, this is short, but probably a little bit confusing.\n                        // This part searches from left to right between the edges inside the polygon.\n                        // The problem: We are using the polygon data to search in the texture data.\n                        // That's simply not accurate, but necessary because of performance.\n                        for (int i = 0; i < xCoords.Count; i += 2)\n                        {\n                            foundSolid = false;\n                            foundTransparent = false;\n\n                            // We search between the edges inside the polygon.\n                            for (int x = (int)xCoords[i]; x <= (int)xCoords[i + 1]; x++)\n                            {\n                                // First pass: IsSolid might return false.\n                                // In that case the polygon edge doesn't lie on the texture's solid pixel, because of the hull tolerance.\n                                // If the edge lies before the first solid pixel then we need to skip our transparent pixel finds.\n\n                                // The algorithm starts to search for a relevant transparent pixel (which indicates a possible hole) \n                                // after it has found a solid pixel.\n\n                                // After we've found a solid and a transparent pixel (a hole's left edge) \n                                // we search for a solid pixel again (a hole's right edge).\n                                // When found the distance of that coordinate has to be greater then the hull tolerance.\n\n                                if (IsSolid(ref x, ref y))\n                                {\n                                    if (!foundTransparent)\n                                    {\n                                        foundSolid = true;\n                                        lastSolid = x;\n                                    }\n\n                                    if (foundSolid && foundTransparent)\n                                    {\n                                        entrance = new Vector2(lastSolid, y);\n\n                                        if (DistanceToHullAcceptable(polygon, entrance.Value, true))\n                                            return entrance;\n\n                                        entrance = null;\n                                        break;\n                                    }\n                                }\n                                else\n                                {\n                                    if (foundSolid)\n                                        foundTransparent = true;\n                                }\n                            }\n                        }\n                    }\n                    else\n                    {\n                        if (xCoords.Count % 2 == 0)\n                            Debug.WriteLine(\"SearchCrossingEdges() % 2 != 0\");\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        private bool DistanceToHullAcceptableHoles(Vertices polygon, Vector2 point, bool higherDetail)\n        {\n            if (polygon == null)\n                throw new ArgumentNullException(nameof(polygon), \"'polygon' can't be null.\");\n\n            if (polygon.Count < 3)\n                throw new ArgumentException(\"'polygon.MainPolygon.Count' can't be less then 3.\");\n\n            // Check the distance to main polygon.\n            if (DistanceToHullAcceptable(polygon, point, higherDetail))\n            {\n                if (polygon.Holes != null)\n                {\n                    for (int i = 0; i < polygon.Holes.Count; i++)\n                    {\n                        // If there is one distance not acceptable then return false.\n                        if (!DistanceToHullAcceptable(polygon.Holes[i], point, higherDetail))\n                            return false;\n                    }\n                }\n\n                // All distances are larger then _hullTolerance.\n                return true;\n            }\n\n            // Default to false.\n            return false;\n        }\n\n        private bool DistanceToHullAcceptable(Vertices polygon, Vector2 point, bool higherDetail)\n        {\n            if (polygon == null)\n                throw new ArgumentNullException(nameof(polygon), \"'polygon' can't be null.\");\n\n            if (polygon.Count < 3)\n                throw new ArgumentException(\"'polygon.Count' can't be less then 3.\");\n\n            Vector2 edgeVertex2 = polygon[polygon.Count - 1];\n            Vector2 edgeVertex1;\n\n            if (higherDetail)\n            {\n                for (int i = 0; i < polygon.Count; i++)\n                {\n                    edgeVertex1 = polygon[i];\n\n                    if (LineUtils.DistanceBetweenPointAndLineSegment(ref point, ref edgeVertex1, ref edgeVertex2) <= _hullTolerance || Vector2.Distance(point, edgeVertex1) <= _hullTolerance)\n                        return false;\n\n                    edgeVertex2 = polygon[i];\n                }\n\n                return true;\n            }\n            else\n            {\n                for (int i = 0; i < polygon.Count; i++)\n                {\n                    edgeVertex1 = polygon[i];\n\n                    if (LineUtils.DistanceBetweenPointAndLineSegment(ref point, ref edgeVertex1, ref edgeVertex2) <= _hullTolerance)\n                        return false;\n\n                    edgeVertex2 = polygon[i];\n                }\n\n                return true;\n            }\n        }\n\n        private bool InPolygon(Vertices polygon, Vector2 point)\n        {\n            bool inPolygon = !DistanceToHullAcceptableHoles(polygon, point, true);\n\n            if (!inPolygon)\n            {\n                List<float> xCoords = SearchCrossingEdgesHoles(polygon, (int)point.Y);\n\n                if (xCoords.Count > 0 && xCoords.Count % 2 == 0)\n                {\n                    for (int i = 0; i < xCoords.Count; i += 2)\n                    {\n                        if (xCoords[i] <= point.X && xCoords[i + 1] >= point.X)\n                            return true;\n                    }\n                }\n\n                return false;\n            }\n\n            return true;\n        }\n\n        private Vector2? GetTopMostVertex(Vertices vertices)\n        {\n            float topMostValue = float.MaxValue;\n            Vector2? topMost = null;\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (topMostValue > vertices[i].Y)\n                {\n                    topMostValue = vertices[i].Y;\n                    topMost = vertices[i];\n                }\n            }\n\n            return topMost;\n        }\n\n        private float GetTopMostCoord(Vertices vertices)\n        {\n            float returnValue = float.MaxValue;\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (returnValue > vertices[i].Y)\n                {\n                    returnValue = vertices[i].Y;\n                }\n            }\n\n            return returnValue;\n        }\n\n        private float GetBottomMostCoord(Vertices vertices)\n        {\n            float returnValue = float.MinValue;\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                if (returnValue < vertices[i].Y)\n                {\n                    returnValue = vertices[i].Y;\n                }\n            }\n\n            return returnValue;\n        }\n\n        private List<float> SearchCrossingEdgesHoles(Vertices polygon, int y)\n        {\n            if (polygon == null)\n                throw new ArgumentNullException(nameof(polygon), \"'polygon' can't be null.\");\n\n            if (polygon.Count < 3)\n                throw new ArgumentException(\"'polygon.MainPolygon.Count' can't be less then 3.\");\n\n            List<float> result = SearchCrossingEdges(polygon, y);\n\n            if (polygon.Holes != null)\n            {\n                for (int i = 0; i < polygon.Holes.Count; i++)\n                {\n                    result.AddRange(SearchCrossingEdges(polygon.Holes[i], y));\n                }\n            }\n\n            result.Sort();\n            return result;\n        }\n\n        /// <summary>\n        /// Searches the polygon for the x coordinates of the edges that cross the specified y coordinate.\n        /// </summary>\n        /// <param name=\"polygon\">Polygon to search in.</param>\n        /// <param name=\"y\">Y coordinate to check for edges.</param>\n        /// <returns>Descending sorted list of x coordinates of edges that cross the specified y coordinate.</returns>\n        private List<float> SearchCrossingEdges(Vertices polygon, int y)\n        {\n            // sick-o-note:\n            // Used to search the x coordinates of edges in the polygon for a specific y coordinate.\n            // (Usualy comming from the texture data, that's why it's an int and not a float.)\n\n            List<float> edges = new List<float>();\n\n            // current edge\n            Vector2 slope;\n            Vector2 vertex1; // i\n            Vector2 vertex2; // i - 1\n\n            // next edge\n            Vector2 nextSlope;\n            Vector2 nextVertex; // i + 1\n\n            bool addFind;\n\n            if (polygon.Count > 2)\n            {\n                // There is a gap between the last and the first vertex in the vertex list.\n                // We will bridge that by setting the last vertex (vertex2) to the last \n                // vertex in the list.\n                vertex2 = polygon[polygon.Count - 1];\n\n                // We are moving along the polygon edges.\n                for (int i = 0; i < polygon.Count; i++)\n                {\n                    vertex1 = polygon[i];\n\n                    // Approx. check if the edge crosses our y coord.\n                    if ((vertex1.Y >= y && vertex2.Y <= y) ||\n                        (vertex1.Y <= y && vertex2.Y >= y))\n                    {\n                        // Ignore edges that are parallel to y.\n                        if (vertex1.Y != vertex2.Y)\n                        {\n                            addFind = true;\n                            slope = vertex2 - vertex1;\n\n                            // Special treatment for edges that end at the y coord.\n                            if (vertex1.Y == y)\n                            {\n                                // Create preview of the next edge.\n                                nextVertex = polygon[(i + 1) % polygon.Count];\n                                nextSlope = vertex1 - nextVertex;\n\n                                // Ignore peaks. \n                                // If two edges are aligned like this: /\\ and the y coordinate lies on the top,\n                                // then we get the same x coord twice and we don't need that.\n                                if (slope.Y > 0)\n                                    addFind = (nextSlope.Y <= 0);\n                                else\n                                    addFind = (nextSlope.Y >= 0);\n                            }\n\n                            if (addFind)\n                                edges.Add((y - vertex1.Y) / slope.Y * slope.X + vertex1.X); // Calculate and add the x coord.\n                        }\n                    }\n\n                    // vertex1 becomes vertex2 :).\n                    vertex2 = vertex1;\n                }\n            }\n\n            edges.Sort();\n            return edges;\n        }\n\n        private bool SplitPolygonEdge(Vertices polygon, Vector2 coordInsideThePolygon, out int vertex1Index, out int vertex2Index)\n        {\n            Vector2 slope;\n            int nearestEdgeVertex1Index = 0;\n            int nearestEdgeVertex2Index = 0;\n            bool edgeFound = false;\n\n            float shortestDistance = float.MaxValue;\n\n            bool edgeCoordFound = false;\n            Vector2 foundEdgeCoord = Vector2.Zero;\n\n            List<float> xCoords = SearchCrossingEdges(polygon, (int)coordInsideThePolygon.Y);\n\n            vertex1Index = 0;\n            vertex2Index = 0;\n\n            foundEdgeCoord.Y = coordInsideThePolygon.Y;\n\n            if (xCoords != null && xCoords.Count > 1 && xCoords.Count % 2 == 0)\n            {\n                float distance;\n                for (int i = 0; i < xCoords.Count; i++)\n                {\n                    if (xCoords[i] < coordInsideThePolygon.X)\n                    {\n                        distance = coordInsideThePolygon.X - xCoords[i];\n\n                        if (distance < shortestDistance)\n                        {\n                            shortestDistance = distance;\n                            foundEdgeCoord.X = xCoords[i];\n\n                            edgeCoordFound = true;\n                        }\n                    }\n                }\n\n                if (edgeCoordFound)\n                {\n                    shortestDistance = float.MaxValue;\n\n                    int edgeVertex2Index = polygon.Count - 1;\n\n                    int edgeVertex1Index;\n                    for (edgeVertex1Index = 0; edgeVertex1Index < polygon.Count; edgeVertex1Index++)\n                    {\n                        Vector2 tempVector1 = polygon[edgeVertex1Index];\n                        Vector2 tempVector2 = polygon[edgeVertex2Index];\n                        distance = LineUtils.DistanceBetweenPointAndLineSegment(ref foundEdgeCoord,\n                            ref tempVector1, ref tempVector2);\n                        if (distance < shortestDistance)\n                        {\n                            shortestDistance = distance;\n\n                            nearestEdgeVertex1Index = edgeVertex1Index;\n                            nearestEdgeVertex2Index = edgeVertex2Index;\n\n                            edgeFound = true;\n                        }\n\n                        edgeVertex2Index = edgeVertex1Index;\n                    }\n\n                    if (edgeFound)\n                    {\n                        slope = polygon[nearestEdgeVertex2Index] - polygon[nearestEdgeVertex1Index];\n                        slope.Normalize();\n\n                        Vector2 tempVector = polygon[nearestEdgeVertex1Index];\n                        distance = Vector2.Distance(tempVector, foundEdgeCoord);\n\n                        vertex1Index = nearestEdgeVertex1Index;\n                        vertex2Index = nearestEdgeVertex1Index + 1;\n\n                        polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex1Index]);\n                        polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex2Index]);\n\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// </summary>\n        /// <param name=\"entrance\"></param>\n        /// <param name=\"last\"></param>\n        /// <returns></returns>\n        private Vertices CreateSimplePolygon(Vector2 entrance, Vector2 last)\n        {\n            bool entranceFound = false;\n            bool endOfHull = false;\n\n            Vertices polygon = new Vertices(32);\n            Vertices hullArea = new Vertices(32);\n            Vertices endOfHullArea = new Vertices(32);\n\n            Vector2 current = Vector2.Zero;\n\n            #region Entrance check\n\n            // Get the entrance point. //todo: alle möglichkeiten testen\n            if (entrance == Vector2.Zero || !InBounds(ref entrance))\n            {\n                entranceFound = SearchHullEntrance(out entrance);\n\n                if (entranceFound)\n                {\n                    current = new Vector2(entrance.X - 1f, entrance.Y);\n                }\n            }\n            else\n            {\n                if (IsSolid(ref entrance))\n                {\n                    if (IsNearPixel(ref entrance, ref last))\n                    {\n                        current = last;\n                        entranceFound = true;\n                    }\n                    else\n                    {\n                        Vector2 temp;\n                        if (SearchNearPixels(false, ref entrance, out temp))\n                        {\n                            current = temp;\n                            entranceFound = true;\n                        }\n                        else\n                        {\n                            entranceFound = false;\n                        }\n                    }\n                }\n            }\n\n            #endregion\n\n            if (entranceFound)\n            {\n                polygon.Add(entrance);\n                hullArea.Add(entrance);\n\n                Vector2 next = entrance;\n\n                do\n                {\n                    // Search in the pre vision list for an outstanding point.\n                    Vector2 outstanding;\n                    if (SearchForOutstandingVertex(hullArea, out outstanding))\n                    {\n                        if (endOfHull)\n                        {\n                            // We have found the next pixel, but is it on the last bit of the hull?\n                            if (endOfHullArea.Contains(outstanding))\n                            {\n                                // Indeed.\n                                polygon.Add(outstanding);\n                            }\n\n                            // That's enough, quit.\n                            break;\n                        }\n\n                        // Add it and remove all vertices that don't matter anymore\n                        // (all the vertices before the outstanding).\n                        polygon.Add(outstanding);\n                        hullArea.RemoveRange(0, hullArea.IndexOf(outstanding));\n                    }\n\n                    // Last point gets current and current gets next. Our little spider is moving forward on the hull ;).\n                    last = current;\n                    current = next;\n\n                    // Get the next point on hull.\n                    if (GetNextHullPoint(ref last, ref current, out next))\n                    {\n                        // Add the vertex to a hull pre-vision list.\n                        hullArea.Add(next);\n                    }\n                    else\n                    {\n                        // Quit\n                        break;\n                    }\n\n                    if (next == entrance && !endOfHull)\n                    {\n                        // It's the last bit of the hull, search on and exit at next found vertex.\n                        endOfHull = true;\n                        endOfHullArea.AddRange(hullArea);\n\n                        // We don't want the last vertex to be the same as the first one, because it causes the triangulation code to crash.\n                        if (endOfHullArea.Contains(entrance))\n                            endOfHullArea.Remove(entrance);\n                    }\n                } while (true);\n            }\n\n            return polygon;\n        }\n\n        private bool SearchNearPixels(bool searchingForSolidPixel, ref Vector2 current, out Vector2 foundPixel)\n        {\n            for (int i = 0; i < ClosepixelsLength; i++)\n            {\n                int x = (int)current.X + _closePixels[i, 0];\n                int y = (int)current.Y + _closePixels[i, 1];\n\n                if (!searchingForSolidPixel ^ IsSolid(ref x, ref y))\n                {\n                    foundPixel = new Vector2(x, y);\n                    return true;\n                }\n            }\n\n            // Nothing found.\n            foundPixel = Vector2.Zero;\n            return false;\n        }\n\n        private bool IsNearPixel(ref Vector2 current, ref Vector2 near)\n        {\n            for (int i = 0; i < ClosepixelsLength; i++)\n            {\n                int x = (int)current.X + _closePixels[i, 0];\n                int y = (int)current.Y + _closePixels[i, 1];\n\n                if (x >= 0 && x <= _width && y >= 0 && y <= _height)\n                {\n                    if (x == (int)near.X && y == (int)near.Y)\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        private bool SearchHullEntrance(out Vector2 entrance)\n        {\n            // Search for first solid pixel.\n            for (int y = 0; y <= _height; y++)\n            {\n                for (int x = 0; x <= _width; x++)\n                {\n                    if (IsSolid(ref x, ref y))\n                    {\n                        entrance = new Vector2(x, y);\n                        return true;\n                    }\n                }\n            }\n\n            // If there are no solid pixels.\n            entrance = Vector2.Zero;\n            return false;\n        }\n\n        /// <summary>\n        /// Searches for the next shape.\n        /// </summary>\n        /// <param name=\"detectedPolygons\">Already detected polygons.</param>\n        /// <param name=\"start\">Search start coordinate.</param>\n        /// <param name=\"entrance\">Returns the found entrance coordinate. Null if no other shapes found.</param>\n        /// <returns>True if a new shape was found.</returns>\n        private bool SearchNextHullEntrance(List<Vertices> detectedPolygons, Vector2 start, out Vector2? entrance)\n        {\n            int x;\n\n            bool foundTransparent = false;\n            bool inPolygon = false;\n\n            for (int i = (int)start.X + (int)start.Y * _width; i <= _dataLength; i++)\n            {\n                if (IsSolid(ref i))\n                {\n                    if (foundTransparent)\n                    {\n                        x = i % _width;\n                        entrance = new Vector2(x, (i - x) / (float)_width);\n\n                        inPolygon = false;\n                        for (int polygonIdx = 0; polygonIdx < detectedPolygons.Count; polygonIdx++)\n                        {\n                            if (InPolygon(detectedPolygons[polygonIdx], entrance.Value))\n                            {\n                                inPolygon = true;\n                                break;\n                            }\n                        }\n\n                        if (inPolygon)\n                            foundTransparent = false;\n                        else\n                            return true;\n                    }\n                }\n                else\n                    foundTransparent = true;\n            }\n\n            entrance = null;\n            return false;\n        }\n\n        private bool GetNextHullPoint(ref Vector2 last, ref Vector2 current, out Vector2 next)\n        {\n            int x;\n            int y;\n\n            int indexOfFirstPixelToCheck = GetIndexOfFirstPixelToCheck(ref last, ref current);\n            int indexOfPixelToCheck;\n\n            for (int i = 0; i < ClosepixelsLength; i++)\n            {\n                indexOfPixelToCheck = (indexOfFirstPixelToCheck + i) % ClosepixelsLength;\n\n                x = (int)current.X + _closePixels[indexOfPixelToCheck, 0];\n                y = (int)current.Y + _closePixels[indexOfPixelToCheck, 1];\n\n                if (x >= 0 && x < _width && y >= 0 && y <= _height)\n                {\n                    if (IsSolid(ref x, ref y))\n                    {\n                        next = new Vector2(x, y);\n                        return true;\n                    }\n                }\n            }\n\n            next = Vector2.Zero;\n            return false;\n        }\n\n        private bool SearchForOutstandingVertex(Vertices hullArea, out Vector2 outstanding)\n        {\n            Vector2 outstandingResult = Vector2.Zero;\n            bool found = false;\n\n            if (hullArea.Count > 2)\n            {\n                int hullAreaLastPoint = hullArea.Count - 1;\n\n                Vector2 tempVector1;\n                Vector2 tempVector2 = hullArea[0];\n                Vector2 tempVector3 = hullArea[hullAreaLastPoint];\n\n                // Search between the first and last hull point.\n                for (int i = 1; i < hullAreaLastPoint; i++)\n                {\n                    tempVector1 = hullArea[i];\n\n                    // Check if the distance is over the one that's tolerable.\n                    if (LineUtils.DistanceBetweenPointAndLineSegment(ref tempVector1, ref tempVector2, ref tempVector3) >= _hullTolerance)\n                    {\n                        outstandingResult = hullArea[i];\n                        found = true;\n                        break;\n                    }\n                }\n            }\n\n            outstanding = outstandingResult;\n            return found;\n        }\n\n        private int GetIndexOfFirstPixelToCheck(ref Vector2 last, ref Vector2 current)\n        {\n            // .: pixel\n            // l: last position\n            // c: current position\n            // f: first pixel for next search\n\n            // f . .\n            // l c .\n            // . . .\n\n            //Calculate in which direction the last move went and decide over the next pixel to check.\n            switch ((int)(current.X - last.X))\n            {\n                case 1:\n                    switch ((int)(current.Y - last.Y))\n                    {\n                        case 1:\n                            return 1;\n\n                        case 0:\n                            return 0;\n\n                        case -1:\n                            return 7;\n                    }\n                    break;\n\n                case 0:\n                    switch ((int)(current.Y - last.Y))\n                    {\n                        case 1:\n                            return 2;\n\n                        case -1:\n                            return 6;\n                    }\n                    break;\n\n                case -1:\n                    switch ((int)(current.Y - last.Y))\n                    {\n                        case 1:\n                            return 3;\n\n                        case 0:\n                            return 4;\n\n                        case -1:\n                            return 5;\n                    }\n                    break;\n            }\n\n            return 0;\n        }\n\n        #region Properties\n\n        /// <summary>\n        /// Get or set the polygon detection type.\n        /// </summary>\n        public VerticesDetectionType PolygonDetectionType\n        {\n            get { return _polygonDetectionType; }\n            set { _polygonDetectionType = value; }\n        }\n\n        /// <summary>\n        /// Will detect texture 'holes' if set to true. Slows down the detection. Default is false.\n        /// </summary>\n        public bool HoleDetection\n        {\n            get { return _holeDetection; }\n            set { _holeDetection = value; }\n        }\n\n        /// <summary>\n        /// Will detect texture multiple 'solid' isles if set to true. Slows down the detection. Default is false.\n        /// </summary>\n        public bool MultipartDetection\n        {\n            get { return _multipartDetection; }\n            set { _multipartDetection = value; }\n        }\n\n        /// <summary>\n        /// Will optimize the vertex positions along the interpolated normal between two edges about a half pixel (post\n        /// processing). Default is false.\n        /// </summary>\n        public bool PixelOffsetOptimization\n        {\n            get { return _pixelOffsetOptimization; }\n            set { _pixelOffsetOptimization = value; }\n        }\n\n        /// <summary>\n        /// Can be used for scaling.\n        /// </summary>\n        public Matrix Transform\n        {\n            get { return _transform; }\n            set { _transform = value; }\n        }\n\n        /// <summary>\n        /// Alpha (coverage) tolerance. Default is 20: Every pixel with a coverage value equal or greater to 20 will be counts as\n        /// solid.\n        /// </summary>\n        public byte AlphaTolerance\n        {\n            get { return (byte)(_alphaTolerance >> 24); }\n            set { _alphaTolerance = (uint)value << 24; }\n        }\n\n        /// <summary>\n        /// Default is 1.5f.\n        /// </summary>\n        public float HullTolerance\n        {\n            get { return _hullTolerance; }\n            set\n            {\n                if (value > 4f)\n                {\n                    _hullTolerance = 4f;\n                }\n                else if (value < 0.9f)\n                {\n                    _hullTolerance = 0.9f;\n                }\n                else\n                {\n                    _hullTolerance = value;\n                }\n            }\n        }\n\n        #endregion\n\n        #region Constructors\n\n        public TextureConverter()\n        {\n            Initialize(null, null, null, null, null, null, null, null);\n        }\n\n        public TextureConverter(byte? alphaTolerance, float? hullTolerance,\n                                bool? holeDetection, bool? multipartDetection, bool? pixelOffsetOptimization, Matrix? transform)\n        {\n            Initialize(null, null, alphaTolerance, hullTolerance, holeDetection,\n                multipartDetection, pixelOffsetOptimization, transform);\n        }\n\n        public TextureConverter(uint[] data, int width)\n        {\n            Initialize(data, width, null, null, null, null, null, null);\n        }\n\n        public TextureConverter(uint[] data, int width, byte? alphaTolerance,\n                                float? hullTolerance, bool? holeDetection, bool? multipartDetection,\n                                bool? pixelOffsetOptimization, Matrix? transform)\n        {\n            Initialize(data, width, alphaTolerance, hullTolerance, holeDetection,\n                multipartDetection, pixelOffsetOptimization, transform);\n        }\n\n        #endregion\n\n        #region Data[] functions\n\n        private int _tempIsSolidX;\n        private int _tempIsSolidY;\n\n        public bool IsSolid(ref Vector2 v)\n        {\n            _tempIsSolidX = (int)v.X;\n            _tempIsSolidY = (int)v.Y;\n\n            if (_tempIsSolidX >= 0 && _tempIsSolidX < _width && _tempIsSolidY >= 0 && _tempIsSolidY < _height)\n                return (_data[_tempIsSolidX + _tempIsSolidY * _width] >= _alphaTolerance);\n\n            //return ((_data[_tempIsSolidX + _tempIsSolidY * _width] & 0xFF000000) >= _alphaTolerance);\n\n            return false;\n        }\n\n        public bool IsSolid(ref int x, ref int y)\n        {\n            if (x >= 0 && x < _width && y >= 0 && y < _height)\n                return (_data[x + y * _width] >= _alphaTolerance);\n\n            //return ((_data[x + y * _width] & 0xFF000000) >= _alphaTolerance);\n\n            return false;\n        }\n\n        public bool IsSolid(ref int index)\n        {\n            if (index >= 0 && index < _dataLength)\n                return (_data[index] >= _alphaTolerance);\n\n            //return ((_data[index] & 0xFF000000) >= _alphaTolerance);\n\n            return false;\n        }\n\n        public bool InBounds(ref Vector2 coord)\n        {\n            return (coord.X >= 0f && coord.X < _width && coord.Y >= 0f && coord.Y < _height);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/TextureTools/VerticesDetectionType.cs",
    "content": "namespace VelcroPhysics.Tools.TextureTools\n{\n    /// <summary>\n    /// The detection type affects the resulting polygon data.\n    /// </summary>\n    public enum VerticesDetectionType\n    {\n        /// <summary>\n        /// Holes are integrated into the main polygon.\n        /// </summary>\n        Integrated = 0,\n\n        /// <summary>\n        /// The data of the main polygon and hole polygons is returned separately.\n        /// </summary>\n        Separated = 1\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Bayazit/BayazitDecomposer.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.Triangulation.Bayazit\n{\n    //From phed rev 36: http://code.google.com/p/phed/source/browse/trunk/Polygon.cpp\n\n    /// <summary>\n    /// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/)\n    /// \n    /// Properties:\n    /// - Tries to decompose using polygons instead of triangles.\n    /// - Tends to produce optimal results with low processing time.\n    /// - Running time is O(nr), n = number of vertices, r = reflex vertices.\n    /// - Does not support holes.\n    /// \n    /// For more information about this algorithm, see http://mnbayazit.com/406/bayazit\n    /// </summary>\n    internal static class BayazitDecomposer\n    {\n        /// <summary>\n        /// Decompose the polygon into several smaller non-concave polygon.\n        /// If the polygon is already convex, it will return the original polygon, unless it is over Settings.MaxPolygonVertices.\n        /// </summary>\n        public static List<Vertices> ConvexPartition(Vertices vertices)\n        {\n            Debug.Assert(vertices.Count > 3);\n            Debug.Assert(vertices.IsCounterClockWise());\n\n            return TriangulatePolygon(vertices);\n        }\n\n        private static List<Vertices> TriangulatePolygon(Vertices vertices)\n        {\n            List<Vertices> list = new List<Vertices>();\n            Vector2 lowerInt = new Vector2();\n            Vector2 upperInt = new Vector2(); // intersection points\n            int lowerIndex = 0, upperIndex = 0;\n            Vertices lowerPoly, upperPoly;\n\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                if (Reflex(i, vertices))\n                {\n                    float upperDist;\n                    float lowerDist = upperDist = float.MaxValue;\n                    for (int j = 0; j < vertices.Count; ++j)\n                    {\n                        // if line intersects with an edge\n                        float d;\n                        Vector2 p;\n                        if (Left(At(i - 1, vertices), At(i, vertices), At(j, vertices)) && RightOn(At(i - 1, vertices), At(i, vertices), At(j - 1, vertices)))\n                        {\n                            // find the point of intersection\n                            p = LineUtils.LineIntersect(At(i - 1, vertices), At(i, vertices), At(j, vertices), At(j - 1, vertices));\n\n                            if (Right(At(i + 1, vertices), At(i, vertices), p))\n                            {\n                                // make sure it's inside the poly\n                                d = SquareDist(At(i, vertices), p);\n                                if (d < lowerDist)\n                                {\n                                    // keep only the closest intersection\n                                    lowerDist = d;\n                                    lowerInt = p;\n                                    lowerIndex = j;\n                                }\n                            }\n                        }\n\n                        if (Left(At(i + 1, vertices), At(i, vertices), At(j + 1, vertices)) && RightOn(At(i + 1, vertices), At(i, vertices), At(j, vertices)))\n                        {\n                            p = LineUtils.LineIntersect(At(i + 1, vertices), At(i, vertices), At(j, vertices), At(j + 1, vertices));\n\n                            if (Left(At(i - 1, vertices), At(i, vertices), p))\n                            {\n                                d = SquareDist(At(i, vertices), p);\n                                if (d < upperDist)\n                                {\n                                    upperDist = d;\n                                    upperIndex = j;\n                                    upperInt = p;\n                                }\n                            }\n                        }\n                    }\n\n                    // if there are no vertices to connect to, choose a point in the middle\n                    if (lowerIndex == (upperIndex + 1) % vertices.Count)\n                    {\n                        Vector2 p = ((lowerInt + upperInt) / 2);\n\n                        lowerPoly = Copy(i, upperIndex, vertices);\n                        lowerPoly.Add(p);\n                        upperPoly = Copy(lowerIndex, i, vertices);\n                        upperPoly.Add(p);\n                    }\n                    else\n                    {\n                        double highestScore = 0, bestIndex = lowerIndex;\n                        while (upperIndex < lowerIndex)\n                            upperIndex += vertices.Count;\n\n                        for (int j = lowerIndex; j <= upperIndex; ++j)\n                        {\n                            if (CanSee(i, j, vertices))\n                            {\n                                double score = 1 / (SquareDist(At(i, vertices), At(j, vertices)) + 1);\n                                if (Reflex(j, vertices))\n                                {\n                                    if (RightOn(At(j - 1, vertices), At(j, vertices), At(i, vertices)) && LeftOn(At(j + 1, vertices), At(j, vertices), At(i, vertices)))\n                                        score += 3;\n                                    else\n                                        score += 2;\n                                }\n                                else\n                                {\n                                    score += 1;\n                                }\n                                if (score > highestScore)\n                                {\n                                    bestIndex = j;\n                                    highestScore = score;\n                                }\n                            }\n                        }\n                        lowerPoly = Copy(i, (int)bestIndex, vertices);\n                        upperPoly = Copy((int)bestIndex, i, vertices);\n                    }\n                    list.AddRange(TriangulatePolygon(lowerPoly));\n                    list.AddRange(TriangulatePolygon(upperPoly));\n                    return list;\n                }\n            }\n\n            // polygon is already convex\n            if (vertices.Count > Settings.MaxPolygonVertices)\n            {\n                lowerPoly = Copy(0, vertices.Count / 2, vertices);\n                upperPoly = Copy(vertices.Count / 2, 0, vertices);\n                list.AddRange(TriangulatePolygon(lowerPoly));\n                list.AddRange(TriangulatePolygon(upperPoly));\n            }\n            else\n                list.Add(vertices);\n\n            return list;\n        }\n\n        private static Vector2 At(int i, Vertices vertices)\n        {\n            int s = vertices.Count;\n            return vertices[i < 0 ? s - 1 - ((-i - 1) % s) : i % s];\n        }\n\n        private static Vertices Copy(int i, int j, Vertices vertices)\n        {\n            while (j < i)\n                j += vertices.Count;\n\n            Vertices p = new Vertices(j);\n\n            for (; i <= j; ++i)\n            {\n                p.Add(At(i, vertices));\n            }\n            return p;\n        }\n\n        private static bool CanSee(int i, int j, Vertices vertices)\n        {\n            if (Reflex(i, vertices))\n            {\n                if (LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)) && RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)))\n                    return false;\n            }\n            else\n            {\n                if (RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)) || LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)))\n                    return false;\n            }\n            if (Reflex(j, vertices))\n            {\n                if (LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)) && RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)))\n                    return false;\n            }\n            else\n            {\n                if (RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)) || LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)))\n                    return false;\n            }\n            for (int k = 0; k < vertices.Count; ++k)\n            {\n                if ((k + 1) % vertices.Count == i || k == i || (k + 1) % vertices.Count == j || k == j)\n                    continue; // ignore incident edges\n\n                Vector2 intersectionPoint;\n\n                if (LineUtils.LineIntersect(At(i, vertices), At(j, vertices), At(k, vertices), At(k + 1, vertices), out intersectionPoint))\n                    return false;\n            }\n            return true;\n        }\n\n        private static bool Reflex(int i, Vertices vertices)\n        {\n            return Right(i, vertices);\n        }\n\n        private static bool Right(int i, Vertices vertices)\n        {\n            return Right(At(i - 1, vertices), At(i, vertices), At(i + 1, vertices));\n        }\n\n        private static bool Left(Vector2 a, Vector2 b, Vector2 c)\n        {\n            return MathUtils.Area(ref a, ref b, ref c) > 0;\n        }\n\n        private static bool LeftOn(Vector2 a, Vector2 b, Vector2 c)\n        {\n            return MathUtils.Area(ref a, ref b, ref c) >= 0;\n        }\n\n        private static bool Right(Vector2 a, Vector2 b, Vector2 c)\n        {\n            return MathUtils.Area(ref a, ref b, ref c) < 0;\n        }\n\n        private static bool RightOn(Vector2 a, Vector2 b, Vector2 c)\n        {\n            return MathUtils.Area(ref a, ref b, ref c) <= 0;\n        }\n\n        private static float SquareDist(Vector2 a, Vector2 b)\n        {\n            float dx = b.X - a.X;\n            float dy = b.Y - a.Y;\n            return dx * dx + dy * dy;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/CDTDecomposer.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n*/\n\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    /// <summary>\n    /// 2D constrained Delaunay triangulation algorithm.\n    /// Based on the paper \"Sweep-line algorithm for constrained Delaunay triangulation\" by V. Domiter and and B. Zalik\n    /// \n    /// Properties:\n    /// - Creates triangles with a large interior angle.\n    /// - Supports holes\n    /// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.\n    /// - Running time is O(n^2), n = number of vertices.\n    /// - Does not care about winding order.\n    /// \n    /// Source: http://code.google.com/p/poly2tri/\n    /// </summary>\n    internal static class CDTDecomposer\n    {\n        /// <summary>\n        /// Decompose the polygon into several smaller non-concave polygon.\n        /// </summary>\n        public static List<Vertices> ConvexPartition(Vertices vertices)\n        {\n            Debug.Assert(vertices.Count > 3);\n\n            Polygon.Polygon poly = new Polygon.Polygon();\n\n            foreach (Vector2 vertex in vertices)\n                poly.Points.Add(new TriangulationPoint(vertex.X, vertex.Y));\n\n            if (vertices.Holes != null)\n            {\n                foreach (Vertices holeVertices in vertices.Holes)\n                {\n                    Polygon.Polygon hole = new Polygon.Polygon();\n\n                    foreach (Vector2 vertex in holeVertices)\n                        hole.Points.Add(new TriangulationPoint(vertex.X, vertex.Y));\n\n                    poly.AddHole(hole);\n                }\n            }\n\n            DTSweepContext tcx = new DTSweepContext();\n            tcx.PrepareTriangulation(poly);\n            DTSweep.Triangulate(tcx);\n\n            List<Vertices> results = new List<Vertices>();\n\n            foreach (DelaunayTriangle triangle in poly.Triangles)\n            {\n                Vertices v = new Vertices();\n                foreach (TriangulationPoint p in triangle.Points)\n                {\n                    v.Add(new Vector2((float)p.X, (float)p.Y));\n                }\n                results.Add(v);\n            }\n\n            return results;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/DelaunayTriangle.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing VelcroPhysics.Shared.Optimization;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay\n{\n    internal class DelaunayTriangle\n    {\n        /** Neighbor pointers */\n\n        /** Flags to determine if an edge is a Delauney edge */\n        public FixedArray3<bool> EdgeIsConstrained;\n\n        /** Flags to determine if an edge is a Constrained edge */\n        public FixedArray3<bool> EdgeIsDelaunay;\n\n        public FixedArray3<DelaunayTriangle> Neighbors;\n\n        /** Has this triangle been marked as an interior triangle? */\n\n        public FixedArray3<TriangulationPoint> Points;\n\n        public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3)\n        {\n            Points[0] = p1;\n            Points[1] = p2;\n            Points[2] = p3;\n        }\n\n        public bool IsInterior { get; set; }\n\n        public int IndexOf(TriangulationPoint p)\n        {\n            int i = Points.IndexOf(p);\n            if (i == -1)\n                throw new Exception(\"Calling index with a point that doesn't exist in triangle\");\n            return i;\n        }\n\n        //TODO: Port note - different implementation\n        public int IndexCW(TriangulationPoint p)\n        {\n            int index = IndexOf(p);\n            switch (index)\n            {\n                case 0:\n                    return 2;\n                case 1:\n                    return 0;\n                default:\n                    return 1;\n            }\n        }\n\n        //TODO: Port note - different implementation\n        public int IndexCCW(TriangulationPoint p)\n        {\n            int index = IndexOf(p);\n            switch (index)\n            {\n                case 0:\n                    return 1;\n                case 1:\n                    return 2;\n                default:\n                    return 0;\n            }\n        }\n\n        public bool Contains(TriangulationPoint p)\n        {\n            return (p == Points[0] || p == Points[1] || p == Points[2]);\n        }\n\n        public bool Contains(DTSweepConstraint e)\n        {\n            return (Contains(e.P) && Contains(e.Q));\n        }\n\n        public bool Contains(TriangulationPoint p, TriangulationPoint q)\n        {\n            return (Contains(p) && Contains(q));\n        }\n\n        /// <summary>\n        /// Update neighbor pointers\n        /// </summary>\n        /// <param name=\"p1\">Point 1 of the shared edge</param>\n        /// <param name=\"p2\">Point 2 of the shared edge</param>\n        /// <param name=\"t\">This triangle's new neighbor</param>\n        private void MarkNeighbor(TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t)\n        {\n            if ((p1 == Points[2] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[2]))\n            {\n                Neighbors[0] = t;\n            }\n            else if ((p1 == Points[0] && p2 == Points[2]) || (p1 == Points[2] && p2 == Points[0]))\n            {\n                Neighbors[1] = t;\n            }\n            else if ((p1 == Points[0] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[0]))\n            {\n                Neighbors[2] = t;\n            }\n            else\n            {\n                Debug.WriteLine(\"Neighbor error, please report!\");\n\n                // throw new Exception(\"Neighbor error, please report!\");\n            }\n        }\n\n        /// <summary>\n        /// Exhaustive search to update neighbor pointers\n        /// </summary>\n        public void MarkNeighbor(DelaunayTriangle t)\n        {\n            if (t.Contains(Points[1], Points[2]))\n            {\n                Neighbors[0] = t;\n                t.MarkNeighbor(Points[1], Points[2], this);\n            }\n            else if (t.Contains(Points[0], Points[2]))\n            {\n                Neighbors[1] = t;\n                t.MarkNeighbor(Points[0], Points[2], this);\n            }\n            else if (t.Contains(Points[0], Points[1]))\n            {\n                Neighbors[2] = t;\n                t.MarkNeighbor(Points[0], Points[1], this);\n            }\n            else\n            {\n                Debug.WriteLine(\"markNeighbor failed\");\n            }\n        }\n\n        public void ClearNeighbors()\n        {\n            Neighbors[0] = Neighbors[1] = Neighbors[2] = null;\n        }\n\n        public void ClearNeighbor(DelaunayTriangle triangle)\n        {\n            if (Neighbors[0] == triangle)\n            {\n                Neighbors[0] = null;\n            }\n            else if (Neighbors[1] == triangle)\n            {\n                Neighbors[1] = null;\n            }\n            else\n            {\n                Neighbors[2] = null;\n            }\n        }\n\n        /**\n         * Clears all references to all other triangles and points\n         */\n\n        public void Clear()\n        {\n            DelaunayTriangle t;\n            for (int i = 0; i < 3; i++)\n            {\n                t = Neighbors[i];\n                if (t != null)\n                {\n                    t.ClearNeighbor(this);\n                }\n            }\n            ClearNeighbors();\n            Points[0] = Points[1] = Points[2] = null;\n        }\n\n        /// <param name=\"t\">Opposite triangle</param>\n        /// <param name=\"p\">The point in t that isn't shared between the triangles</param>\n        public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p)\n        {\n            Debug.Assert(t != this, \"self-pointer error\");\n            return PointCW(t.PointCW(p));\n        }\n\n        public DelaunayTriangle NeighborCW(TriangulationPoint point)\n        {\n            return Neighbors[(Points.IndexOf(point) + 1) % 3];\n        }\n\n        public DelaunayTriangle NeighborCCW(TriangulationPoint point)\n        {\n            return Neighbors[(Points.IndexOf(point) + 2) % 3];\n        }\n\n        public DelaunayTriangle NeighborAcross(TriangulationPoint point)\n        {\n            return Neighbors[Points.IndexOf(point)];\n        }\n\n        public TriangulationPoint PointCCW(TriangulationPoint point)\n        {\n            return Points[(IndexOf(point) + 1) % 3];\n        }\n\n        public TriangulationPoint PointCW(TriangulationPoint point)\n        {\n            return Points[(IndexOf(point) + 2) % 3];\n        }\n\n        private void RotateCW()\n        {\n            TriangulationPoint t = Points[2];\n            Points[2] = Points[1];\n            Points[1] = Points[0];\n            Points[0] = t;\n        }\n\n        /// <summary>\n        /// Legalize triangle by rotating clockwise around oPoint\n        /// </summary>\n        /// <param name=\"oPoint\">The origin point to rotate around</param>\n        /// <param name=\"nPoint\">???</param>\n        public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint)\n        {\n            RotateCW();\n            Points[IndexCCW(oPoint)] = nPoint;\n        }\n\n        public override string ToString()\n        {\n            return Points[0] + \",\" + Points[1] + \",\" + Points[2];\n        }\n\n        /// <summary>\n        /// Finalize edge marking\n        /// </summary>\n        public void MarkNeighborEdges()\n        {\n            for (int i = 0; i < 3; i++)\n                if (EdgeIsConstrained[i] && Neighbors[i] != null)\n                {\n                    Neighbors[i].MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]);\n                }\n        }\n\n        public void MarkEdge(DelaunayTriangle triangle)\n        {\n            for (int i = 0; i < 3; i++)\n                if (EdgeIsConstrained[i])\n                {\n                    triangle.MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]);\n                }\n        }\n\n        public void MarkEdge(List<DelaunayTriangle> tList)\n        {\n            foreach (DelaunayTriangle t in tList)\n                for (int i = 0; i < 3; i++)\n                    if (t.EdgeIsConstrained[i])\n                    {\n                        MarkConstrainedEdge(t.Points[(i + 1) % 3], t.Points[(i + 2) % 3]);\n                    }\n        }\n\n        public void MarkConstrainedEdge(int index)\n        {\n            EdgeIsConstrained[index] = true;\n        }\n\n        public void MarkConstrainedEdge(DTSweepConstraint edge)\n        {\n            MarkConstrainedEdge(edge.P, edge.Q);\n        }\n\n        /// <summary>\n        /// Mark edge as constrained\n        /// </summary>\n        public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q)\n        {\n            int i = EdgeIndex(p, q);\n            if (i != -1)\n                EdgeIsConstrained[i] = true;\n        }\n\n        public double Area()\n        {\n            double b = Points[0].X - Points[1].X;\n            double h = Points[2].Y - Points[1].Y;\n\n            return Math.Abs((b * h * 0.5f));\n        }\n\n        public TriangulationPoint Centroid()\n        {\n            double cx = (Points[0].X + Points[1].X + Points[2].X) / 3f;\n            double cy = (Points[0].Y + Points[1].Y + Points[2].Y) / 3f;\n            return new TriangulationPoint(cx, cy);\n        }\n\n        /// <summary>\n        /// Get the index of the neighbor that shares this edge (or -1 if it isn't shared)\n        /// </summary>\n        /// <returns>index of the shared edge or -1 if edge isn't shared</returns>\n        public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2)\n        {\n            int i1 = Points.IndexOf(p1);\n            int i2 = Points.IndexOf(p2);\n\n            // Points of this triangle in the edge p1-p2\n            bool a = (i1 == 0 || i2 == 0);\n            bool b = (i1 == 1 || i2 == 1);\n            bool c = (i1 == 2 || i2 == 2);\n\n            if (b && c) return 0;\n            if (a && c) return 1;\n            if (a && b) return 2;\n            return -1;\n        }\n\n        public bool GetConstrainedEdgeCCW(TriangulationPoint p)\n        {\n            return EdgeIsConstrained[(IndexOf(p) + 2) % 3];\n        }\n\n        public bool GetConstrainedEdgeCW(TriangulationPoint p)\n        {\n            return EdgeIsConstrained[(IndexOf(p) + 1) % 3];\n        }\n\n        public bool GetConstrainedEdgeAcross(TriangulationPoint p)\n        {\n            return EdgeIsConstrained[IndexOf(p)];\n        }\n\n        public void SetConstrainedEdgeCCW(TriangulationPoint p, bool ce)\n        {\n            EdgeIsConstrained[(IndexOf(p) + 2) % 3] = ce;\n        }\n\n        public void SetConstrainedEdgeCW(TriangulationPoint p, bool ce)\n        {\n            EdgeIsConstrained[(IndexOf(p) + 1) % 3] = ce;\n        }\n\n        public void SetConstrainedEdgeAcross(TriangulationPoint p, bool ce)\n        {\n            EdgeIsConstrained[IndexOf(p)] = ce;\n        }\n\n        public bool GetDelaunayEdgeCCW(TriangulationPoint p)\n        {\n            return EdgeIsDelaunay[(IndexOf(p) + 2) % 3];\n        }\n\n        public bool GetDelaunayEdgeCW(TriangulationPoint p)\n        {\n            return EdgeIsDelaunay[(IndexOf(p) + 1) % 3];\n        }\n\n        public bool GetDelaunayEdgeAcross(TriangulationPoint p)\n        {\n            return EdgeIsDelaunay[IndexOf(p)];\n        }\n\n        public void SetDelaunayEdgeCCW(TriangulationPoint p, bool ce)\n        {\n            EdgeIsDelaunay[(IndexOf(p) + 2) % 3] = ce;\n        }\n\n        public void SetDelaunayEdgeCW(TriangulationPoint p, bool ce)\n        {\n            EdgeIsDelaunay[(IndexOf(p) + 1) % 3] = ce;\n        }\n\n        public void SetDelaunayEdgeAcross(TriangulationPoint p, bool ce)\n        {\n            EdgeIsDelaunay[IndexOf(p)] = ce;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/AdvancingFront.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Changes from the Java version\n//   Removed BST code, but not all artifacts of it\n// Future possibilities\n//   Eliminate Add/RemoveNode ?\n//   Comments comments and more comments!\n\nusing System;\nusing System.Text;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    /**\n     * @author Thomas Åhlen (thahlen@gmail.com)\n     */\n\n    internal class AdvancingFront\n    {\n        public AdvancingFrontNode Head;\n        protected AdvancingFrontNode Search;\n        public AdvancingFrontNode Tail;\n\n        public AdvancingFront(AdvancingFrontNode head, AdvancingFrontNode tail)\n        {\n            Head = head;\n            Tail = tail;\n            Search = head;\n            AddNode(head);\n            AddNode(tail);\n        }\n\n        public void AddNode(AdvancingFrontNode node)\n        {\n            //_searchTree.put(node.key, node);\n        }\n\n        public void RemoveNode(AdvancingFrontNode node)\n        {\n            //_searchTree.delete( node.key );\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder();\n            AdvancingFrontNode node = Head;\n            while (node != Tail)\n            {\n                sb.Append(node.Point.X).Append(\"->\");\n                node = node.Next;\n            }\n            sb.Append(Tail.Point.X);\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// MM:  This seems to be used by LocateNode to guess a position in the implicit linked list of AdvancingFrontNodes near x\n        /// Removed an overload that depended on this being exact\n        /// </summary>\n        private AdvancingFrontNode FindSearchNode(double x)\n        {\n            // TODO: implement BST index \n            return Search;\n        }\n\n        /// <summary>\n        /// We use a balancing tree to locate a node smaller or equal to given key value\n        /// </summary>\n        public AdvancingFrontNode LocateNode(TriangulationPoint point)\n        {\n            return LocateNode(point.X);\n        }\n\n        private AdvancingFrontNode LocateNode(double x)\n        {\n            AdvancingFrontNode node = FindSearchNode(x);\n            if (x < node.Value)\n            {\n                while ((node = node.Prev) != null)\n                    if (x >= node.Value)\n                    {\n                        Search = node;\n                        return node;\n                    }\n            }\n            else\n            {\n                while ((node = node.Next) != null)\n                    if (x < node.Value)\n                    {\n                        Search = node.Prev;\n                        return node.Prev;\n                    }\n            }\n            return null;\n        }\n\n        /// <summary>\n        /// This implementation will use simple node traversal algorithm to find a point on the front\n        /// </summary>\n        public AdvancingFrontNode LocatePoint(TriangulationPoint point)\n        {\n            double px = point.X;\n            AdvancingFrontNode node = FindSearchNode(px);\n            double nx = node.Point.X;\n\n            if (px == nx)\n            {\n                if (point != node.Point)\n                {\n                    // We might have two nodes with same x value for a short time\n                    if (point == node.Prev.Point)\n                    {\n                        node = node.Prev;\n                    }\n                    else if (point == node.Next.Point)\n                    {\n                        node = node.Next;\n                    }\n                    else\n                    {\n                        throw new Exception(\"Failed to find Node for given afront point\");\n\n                        //node = null;\n                    }\n                }\n            }\n            else if (px < nx)\n            {\n                while ((node = node.Prev) != null)\n                {\n                    if (point == node.Point)\n                    {\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                while ((node = node.Next) != null)\n                {\n                    if (point == node.Point)\n                    {\n                        break;\n                    }\n                }\n            }\n            Search = node;\n            return node;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/AdvancingFrontNode.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Changes from the Java version\n//   Removed getters\n//   Has* turned into attributes\n// Future possibilities\n//   Comments!\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    internal class AdvancingFrontNode\n    {\n        public AdvancingFrontNode Next;\n        public TriangulationPoint Point;\n        public AdvancingFrontNode Prev;\n        public DelaunayTriangle Triangle;\n        public double Value;\n\n        public AdvancingFrontNode(TriangulationPoint point)\n        {\n            Point = point;\n            Value = point.X;\n        }\n\n        public bool HasNext\n        {\n            get { return Next != null; }\n        }\n\n        public bool HasPrev\n        {\n            get { return Prev != null; }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/DTSweep.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and\n * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',\n * International Journal of Geographical Information Science\n * \n * \"FlipScan\" Constrained Edge Algorithm invented by author of this code.\n * \n * Author: Thomas Åhlén, thahlen@gmail.com \n */\n\n// Changes from the Java version\n//   Turned DTSweep into a static class\n//   Lots of deindentation via early bailout\n// Future possibilities\n//   Comments!\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    internal static class DTSweep\n    {\n        private const double PI_div2 = Math.PI / 2;\n        private const double PI_3div4 = 3 * Math.PI / 4;\n\n        /// <summary>\n        /// Triangulate simple polygon with holes\n        /// </summary>\n        public static void Triangulate(DTSweepContext tcx)\n        {\n            tcx.CreateAdvancingFront();\n\n            Sweep(tcx);\n\n            // Finalize triangulation\n            if (tcx.TriangulationMode == TriangulationMode.Polygon)\n            {\n                FinalizationPolygon(tcx);\n            }\n            else\n            {\n                FinalizationConvexHull(tcx);\n            }\n\n            tcx.Done();\n        }\n\n        /// <summary>\n        /// Start sweeping the Y-sorted point set from bottom to top\n        /// </summary>\n        private static void Sweep(DTSweepContext tcx)\n        {\n            List<TriangulationPoint> points = tcx.Points;\n\n            for (int i = 1; i < points.Count; i++)\n            {\n                TriangulationPoint point = points[i];\n\n                AdvancingFrontNode node = PointEvent(tcx, point);\n\n                if (point.HasEdges)\n                {\n                    foreach (DTSweepConstraint e in point.Edges)\n                    {\n                        EdgeEvent(tcx, e, node);\n                    }\n                }\n                tcx.Update(null);\n            }\n        }\n\n        /// <summary>\n        /// If this is a Delaunay Triangulation of a pointset we need to fill so the triangle mesh gets a ConvexHull\n        /// </summary>\n        private static void FinalizationConvexHull(DTSweepContext tcx)\n        {\n            DelaunayTriangle t1, t2;\n\n            AdvancingFrontNode n1 = tcx.aFront.Head.Next;\n            AdvancingFrontNode n2 = n1.Next;\n\n            TurnAdvancingFrontConvex(tcx, n1, n2);\n\n            // TODO: implement ConvexHull for lower right and left boundary\n\n            // Lets remove triangles connected to the two \"algorithm\" points\n\n            // XXX: When the first the nodes are points in a triangle we need to do a flip before \n            //      removing triangles or we will lose a valid triangle.\n            //      Same for last three nodes!\n            // !!! If I implement ConvexHull for lower right and left boundary this fix should not be \n            //     needed and the removed triangles will be added again by default\n            n1 = tcx.aFront.Tail.Prev;\n            if (n1.Triangle.Contains(n1.Next.Point) && n1.Triangle.Contains(n1.Prev.Point))\n            {\n                t1 = n1.Triangle.NeighborAcross(n1.Point);\n                RotateTrianglePair(n1.Triangle, n1.Point, t1, t1.OppositePoint(n1.Triangle, n1.Point));\n                tcx.MapTriangleToNodes(n1.Triangle);\n                tcx.MapTriangleToNodes(t1);\n            }\n            n1 = tcx.aFront.Head.Next;\n            if (n1.Triangle.Contains(n1.Prev.Point) && n1.Triangle.Contains(n1.Next.Point))\n            {\n                t1 = n1.Triangle.NeighborAcross(n1.Point);\n                RotateTrianglePair(n1.Triangle, n1.Point, t1, t1.OppositePoint(n1.Triangle, n1.Point));\n                tcx.MapTriangleToNodes(n1.Triangle);\n                tcx.MapTriangleToNodes(t1);\n            }\n\n            // Lower right boundary \n            TriangulationPoint first = tcx.aFront.Head.Point;\n            n2 = tcx.aFront.Tail.Prev;\n            t1 = n2.Triangle;\n            TriangulationPoint p1 = n2.Point;\n            n2.Triangle = null;\n            do\n            {\n                tcx.RemoveFromList(t1);\n                p1 = t1.PointCCW(p1);\n                if (p1 == first)\n                    break;\n                t2 = t1.NeighborCCW(p1);\n                t1.Clear();\n                t1 = t2;\n            } while (true);\n\n            // Lower left boundary\n            first = tcx.aFront.Head.Next.Point;\n            p1 = t1.PointCW(tcx.aFront.Head.Point);\n            t2 = t1.NeighborCW(tcx.aFront.Head.Point);\n            t1.Clear();\n            t1 = t2;\n            while (p1 != first) //TODO: Port note. This was do while before.\n            {\n                tcx.RemoveFromList(t1);\n                p1 = t1.PointCCW(p1);\n                t2 = t1.NeighborCCW(p1);\n                t1.Clear();\n                t1 = t2;\n            }\n\n            // Remove current head and tail node now that we have removed all triangles attached\n            // to them. Then set new head and tail node points\n            tcx.aFront.Head = tcx.aFront.Head.Next;\n            tcx.aFront.Head.Prev = null;\n            tcx.aFront.Tail = tcx.aFront.Tail.Prev;\n            tcx.aFront.Tail.Next = null;\n\n            tcx.FinalizeTriangulation();\n        }\n\n        /// <summary>\n        /// We will traverse the entire advancing front and fill it to form a convex hull.\n        /// </summary>\n        private static void TurnAdvancingFrontConvex(DTSweepContext tcx, AdvancingFrontNode b, AdvancingFrontNode c)\n        {\n            AdvancingFrontNode first = b;\n            while (c != tcx.aFront.Tail)\n            {\n                if (TriangulationUtil.Orient2d(b.Point, c.Point, c.Next.Point) == Orientation.CCW)\n                {\n                    // [b,c,d] Concave - fill around c\n                    Fill(tcx, c);\n                    c = c.Next;\n                }\n                else\n                {\n                    // [b,c,d] Convex\n                    if (b != first && TriangulationUtil.Orient2d(b.Prev.Point, b.Point, c.Point) == Orientation.CCW)\n                    {\n                        // [a,b,c] Concave - fill around b\n                        Fill(tcx, b);\n                        b = b.Prev;\n                    }\n                    else\n                    {\n                        // [a,b,c] Convex - nothing to fill\n                        b = c;\n                        c = c.Next;\n                    }\n                }\n            }\n        }\n\n        private static void FinalizationPolygon(DTSweepContext tcx)\n        {\n            // Get an Internal triangle to start with\n            DelaunayTriangle t = tcx.aFront.Head.Next.Triangle;\n            TriangulationPoint p = tcx.aFront.Head.Next.Point;\n            while (!t.GetConstrainedEdgeCW(p))\n            {\n                t = t.NeighborCCW(p);\n            }\n\n            // Collect interior triangles constrained by edges\n            tcx.MeshClean(t);\n        }\n\n        /// <summary>\n        /// Find closes node to the left of the new point and\n        /// create a new triangle. If needed new holes and basins\n        /// will be filled to.\n        /// </summary>\n        private static AdvancingFrontNode PointEvent(DTSweepContext tcx, TriangulationPoint point)\n        {\n            AdvancingFrontNode node = tcx.LocateNode(point);\n            AdvancingFrontNode newNode = NewFrontTriangle(tcx, point, node);\n\n            // Only need to check +epsilon since point never have smaller \n            // x value than node due to how we fetch nodes from the front\n            if (point.X <= node.Point.X + TriangulationUtil.EPSILON)\n            {\n                Fill(tcx, node);\n            }\n\n            tcx.AddNode(newNode);\n\n            FillAdvancingFront(tcx, newNode);\n            return newNode;\n        }\n\n        /// <summary>\n        /// Creates a new front triangle and legalize it\n        /// </summary>\n        private static AdvancingFrontNode NewFrontTriangle(DTSweepContext tcx, TriangulationPoint point, AdvancingFrontNode node)\n        {\n            DelaunayTriangle triangle = new DelaunayTriangle(point, node.Point, node.Next.Point);\n            triangle.MarkNeighbor(node.Triangle);\n            tcx.Triangles.Add(triangle);\n\n            AdvancingFrontNode newNode = new AdvancingFrontNode(point);\n            newNode.Next = node.Next;\n            newNode.Prev = node;\n            node.Next.Prev = newNode;\n            node.Next = newNode;\n\n            tcx.AddNode(newNode); // XXX: BST\n\n            if (!Legalize(tcx, triangle))\n            {\n                tcx.MapTriangleToNodes(triangle);\n            }\n\n            return newNode;\n        }\n\n        private static void EdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            try\n            {\n                tcx.EdgeEvent.ConstrainedEdge = edge;\n                tcx.EdgeEvent.Right = edge.P.X > edge.Q.X;\n\n                if (IsEdgeSideOfTriangle(node.Triangle, edge.P, edge.Q))\n                {\n                    return;\n                }\n\n                // For now we will do all needed filling\n                // TODO: integrate with flip process might give some better performance \n                //       but for now this avoid the issue with cases that needs both flips and fills\n                FillEdgeEvent(tcx, edge, node);\n\n                EdgeEvent(tcx, edge.P, edge.Q, node.Triangle, edge.Q);\n            }\n            catch (PointOnEdgeException e)\n            {\n                Debug.WriteLine(\"Skipping Edge: {0}\", e.Message);\n            }\n        }\n\n        private static void FillEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            if (tcx.EdgeEvent.Right)\n            {\n                FillRightAboveEdgeEvent(tcx, edge, node);\n            }\n            else\n            {\n                FillLeftAboveEdgeEvent(tcx, edge, node);\n            }\n        }\n\n        private static void FillRightConcaveEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge,\n                                                      AdvancingFrontNode node)\n        {\n            Fill(tcx, node.Next);\n            if (node.Next.Point != edge.P)\n            {\n                // Next above or below edge?\n                if (TriangulationUtil.Orient2d(edge.Q, node.Next.Point, edge.P) == Orientation.CCW)\n                {\n                    // Below\n                    if (TriangulationUtil.Orient2d(node.Point, node.Next.Point, node.Next.Next.Point) == Orientation.CCW)\n                    {\n                        // Next is concave\n                        FillRightConcaveEdgeEvent(tcx, edge, node);\n                    }\n                    else\n                    {\n                        // Next is convex\n                    }\n                }\n            }\n        }\n\n        private static void FillRightConvexEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            // Next concave or convex?\n            if (TriangulationUtil.Orient2d(node.Next.Point, node.Next.Next.Point, node.Next.Next.Next.Point) ==\n                Orientation.CCW)\n            {\n                // Concave\n                FillRightConcaveEdgeEvent(tcx, edge, node.Next);\n            }\n            else\n            {\n                // Convex\n                // Next above or below edge?\n                if (TriangulationUtil.Orient2d(edge.Q, node.Next.Next.Point, edge.P) == Orientation.CCW)\n                {\n                    // Below\n                    FillRightConvexEdgeEvent(tcx, edge, node.Next);\n                }\n                else\n                {\n                    // Above\n                }\n            }\n        }\n\n        private static void FillRightBelowEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            if (node.Point.X < edge.P.X) // needed?\n            {\n                if (TriangulationUtil.Orient2d(node.Point, node.Next.Point, node.Next.Next.Point) == Orientation.CCW)\n                {\n                    // Concave \n                    FillRightConcaveEdgeEvent(tcx, edge, node);\n                }\n                else\n                {\n                    // Convex\n                    FillRightConvexEdgeEvent(tcx, edge, node);\n\n                    // Retry this one\n                    FillRightBelowEdgeEvent(tcx, edge, node);\n                }\n            }\n        }\n\n        private static void FillRightAboveEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            while (node.Next.Point.X < edge.P.X)\n            {\n                // Check if next node is below the edge\n                Orientation o1 = TriangulationUtil.Orient2d(edge.Q, node.Next.Point, edge.P);\n                if (o1 == Orientation.CCW)\n                {\n                    FillRightBelowEdgeEvent(tcx, edge, node);\n                }\n                else\n                {\n                    node = node.Next;\n                }\n            }\n        }\n\n        private static void FillLeftConvexEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            // Next concave or convex?\n            if (TriangulationUtil.Orient2d(node.Prev.Point, node.Prev.Prev.Point, node.Prev.Prev.Prev.Point) ==\n                Orientation.CW)\n            {\n                // Concave\n                FillLeftConcaveEdgeEvent(tcx, edge, node.Prev);\n            }\n            else\n            {\n                // Convex\n                // Next above or below edge?\n                if (TriangulationUtil.Orient2d(edge.Q, node.Prev.Prev.Point, edge.P) == Orientation.CW)\n                {\n                    // Below\n                    FillLeftConvexEdgeEvent(tcx, edge, node.Prev);\n                }\n                else\n                {\n                    // Above\n                }\n            }\n        }\n\n        private static void FillLeftConcaveEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            Fill(tcx, node.Prev);\n            if (node.Prev.Point != edge.P)\n            {\n                // Next above or below edge?\n                if (TriangulationUtil.Orient2d(edge.Q, node.Prev.Point, edge.P) == Orientation.CW)\n                {\n                    // Below\n                    if (TriangulationUtil.Orient2d(node.Point, node.Prev.Point, node.Prev.Prev.Point) == Orientation.CW)\n                    {\n                        // Next is concave\n                        FillLeftConcaveEdgeEvent(tcx, edge, node);\n                    }\n                    else\n                    {\n                        // Next is convex\n                    }\n                }\n            }\n        }\n\n        private static void FillLeftBelowEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            if (node.Point.X > edge.P.X)\n            {\n                if (TriangulationUtil.Orient2d(node.Point, node.Prev.Point, node.Prev.Prev.Point) == Orientation.CW)\n                {\n                    // Concave \n                    FillLeftConcaveEdgeEvent(tcx, edge, node);\n                }\n                else\n                {\n                    // Convex\n                    FillLeftConvexEdgeEvent(tcx, edge, node);\n\n                    // Retry this one\n                    FillLeftBelowEdgeEvent(tcx, edge, node);\n                }\n            }\n        }\n\n        private static void FillLeftAboveEdgeEvent(DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node)\n        {\n            while (node.Prev.Point.X > edge.P.X)\n            {\n                // Check if next node is below the edge\n                Orientation o1 = TriangulationUtil.Orient2d(edge.Q, node.Prev.Point, edge.P);\n                if (o1 == Orientation.CW)\n                {\n                    FillLeftBelowEdgeEvent(tcx, edge, node);\n                }\n                else\n                {\n                    node = node.Prev;\n                }\n            }\n        }\n\n        private static bool IsEdgeSideOfTriangle(DelaunayTriangle triangle, TriangulationPoint ep, TriangulationPoint eq)\n        {\n            int index = triangle.EdgeIndex(ep, eq);\n            if (index != -1)\n            {\n                triangle.MarkConstrainedEdge(index);\n                triangle = triangle.Neighbors[index];\n                if (triangle != null)\n                {\n                    triangle.MarkConstrainedEdge(ep, eq);\n                }\n                return true;\n            }\n            return false;\n        }\n\n        private static void EdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle triangle, TriangulationPoint point)\n        {\n            if (IsEdgeSideOfTriangle(triangle, ep, eq))\n                return;\n\n            TriangulationPoint p1 = triangle.PointCCW(point);\n            Orientation o1 = TriangulationUtil.Orient2d(eq, p1, ep);\n            if (o1 == Orientation.Collinear)\n            {\n                if (triangle.Contains(eq, p1))\n                {\n                    triangle.MarkConstrainedEdge(eq, p1);\n\n                    // We are modifying the constraint maybe it would be better to \n                    // not change the given constraint and just keep a variable for the new constraint\n                    tcx.EdgeEvent.ConstrainedEdge.Q = p1;\n                    triangle = triangle.NeighborAcross(point);\n                    EdgeEvent(tcx, ep, p1, triangle, p1);\n                }\n                else\n                {\n                    throw new PointOnEdgeException(\"EdgeEvent - Point on constrained edge not supported yet\");\n                }\n                if (tcx.IsDebugEnabled)\n                {\n                    Debug.WriteLine(\"EdgeEvent - Point on constrained edge\");\n                }\n                return;\n            }\n\n            TriangulationPoint p2 = triangle.PointCW(point);\n            Orientation o2 = TriangulationUtil.Orient2d(eq, p2, ep);\n            if (o2 == Orientation.Collinear)\n            {\n                if (triangle.Contains(eq, p2))\n                {\n                    triangle.MarkConstrainedEdge(eq, p2);\n\n                    // We are modifying the constraint maybe it would be better to \n                    // not change the given constraint and just keep a variable for the new constraint\n                    tcx.EdgeEvent.ConstrainedEdge.Q = p2;\n                    triangle = triangle.NeighborAcross(point);\n                    EdgeEvent(tcx, ep, p2, triangle, p2);\n                }\n                else\n                {\n                    throw new PointOnEdgeException(\"EdgeEvent - Point on constrained edge not supported yet\");\n                }\n                if (tcx.IsDebugEnabled)\n                {\n                    Debug.WriteLine(\"EdgeEvent - Point on constrained edge\");\n                }\n                return;\n            }\n\n            if (o1 == o2)\n            {\n                // Need to decide if we are rotating CW or CCW to get to a triangle\n                // that will cross edge\n                if (o1 == Orientation.CW)\n                {\n                    triangle = triangle.NeighborCCW(point);\n                }\n                else\n                {\n                    triangle = triangle.NeighborCW(point);\n                }\n                EdgeEvent(tcx, ep, eq, triangle, point);\n            }\n            else\n            {\n                // This triangle crosses constraint so lets flippin start!\n                FlipEdgeEvent(tcx, ep, eq, triangle, point);\n            }\n        }\n\n        private static void FlipEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle t, TriangulationPoint p)\n        {\n            DelaunayTriangle ot = t.NeighborAcross(p);\n\n            // see https://github.com/greenm01/poly2tri/issues/102\n            //if (ot == null)\n            //{\n            //    // If we want to integrate the fillEdgeEvent do it here\n            //    // With current implementation we should never get here\n            //    throw new InvalidOperationException(\"[BUG:FIXME] FLIP failed due to missing triangle\");\n            //}\n\n            if (t.GetConstrainedEdgeAcross(p))\n            {\n                throw new Exception(\"Intersecting Constraints\");\n            }\n\n            TriangulationPoint op = ot.OppositePoint(t, p);\n\n            bool inScanArea = TriangulationUtil.InScanArea(p, t.PointCCW(p), t.PointCW(p), op);\n            if (inScanArea)\n            {\n                // Lets rotate shared edge one vertex CW\n                RotateTrianglePair(t, p, ot, op);\n                tcx.MapTriangleToNodes(t);\n                tcx.MapTriangleToNodes(ot);\n\n                if (p == eq && op == ep)\n                {\n                    if (eq == tcx.EdgeEvent.ConstrainedEdge.Q\n                        && ep == tcx.EdgeEvent.ConstrainedEdge.P)\n                    {\n                        if (tcx.IsDebugEnabled)\n                            Console.WriteLine(\"[FLIP] - constrained edge done\"); // TODO: remove\n                        t.MarkConstrainedEdge(ep, eq);\n                        ot.MarkConstrainedEdge(ep, eq);\n                        Legalize(tcx, t);\n                        Legalize(tcx, ot);\n                    }\n                    else\n                    {\n                        if (tcx.IsDebugEnabled)\n                            Console.WriteLine(\"[FLIP] - subedge done\"); // TODO: remove\n\n                        // XXX: I think one of the triangles should be legalized here?\n                    }\n                }\n                else\n                {\n                    if (tcx.IsDebugEnabled)\n                        Console.WriteLine(\"[FLIP] - flipping and continuing with triangle still crossing edge\");\n\n                    // TODO: remove\n                    Orientation o = TriangulationUtil.Orient2d(eq, op, ep);\n                    t = NextFlipTriangle(tcx, o, t, ot, p, op);\n                    FlipEdgeEvent(tcx, ep, eq, t, p);\n                }\n            }\n            else\n            {\n                TriangulationPoint newP = NextFlipPoint(ep, eq, ot, op);\n                FlipScanEdgeEvent(tcx, ep, eq, t, ot, newP);\n                EdgeEvent(tcx, ep, eq, t, p);\n            }\n        }\n\n        /// <summary>\n        /// When we need to traverse from one triangle to the next we need\n        /// the point in current triangle that is the opposite point to the next\n        /// triangle.\n        /// </summary>\n        private static TriangulationPoint NextFlipPoint(TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op)\n        {\n            Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep);\n            if (o2d == Orientation.CW)\n            {\n                // Right\n                return ot.PointCCW(op);\n            }\n            else if (o2d == Orientation.CCW)\n            {\n                // Left\n                return ot.PointCW(op);\n            }\n            else\n            {\n                // TODO: implement support for point on constraint edge\n                throw new PointOnEdgeException(\"Point on constrained edge not supported yet\");\n            }\n        }\n\n        /// <summary>\n        /// After a flip we have two triangles and know that only one will still be\n        /// intersecting the edge. So decide which to contiune with and legalize the other\n        /// </summary>\n        /// <param name=\"tcx\"></param>\n        /// <param name=\"o\">should be the result of an TriangulationUtil.orient2d( eq, op, ep )</param>\n        /// <param name=\"t\">triangle 1</param>\n        /// <param name=\"ot\">triangle 2</param>\n        /// <param name=\"p\">a point shared by both triangles</param>\n        /// <param name=\"op\">another point shared by both triangles</param>\n        /// <returns>returns the triangle still intersecting the edge</returns>\n        private static DelaunayTriangle NextFlipTriangle(DTSweepContext tcx, Orientation o, DelaunayTriangle t, DelaunayTriangle ot, TriangulationPoint p, TriangulationPoint op)\n        {\n            int edgeIndex;\n            if (o == Orientation.CCW)\n            {\n                // ot is not crossing edge after flip\n                edgeIndex = ot.EdgeIndex(p, op);\n                ot.EdgeIsDelaunay[edgeIndex] = true;\n                Legalize(tcx, ot);\n                ot.EdgeIsDelaunay.Clear();\n                return t;\n            }\n\n            // t is not crossing edge after flip\n            edgeIndex = t.EdgeIndex(p, op);\n            t.EdgeIsDelaunay[edgeIndex] = true;\n            Legalize(tcx, t);\n            t.EdgeIsDelaunay.Clear();\n            return ot;\n        }\n\n        /// <summary>\n        /// Scan part of the FlipScan algorithm\n        /// When a triangle pair isn't flippable we will scan for the next\n        /// point that is inside the flip triangle scan area. When found\n        /// we generate a new flipEdgeEvent\n        /// </summary>\n        /// <param name=\"tcx\"></param>\n        /// <param name=\"ep\">last point on the edge we are traversing</param>\n        /// <param name=\"eq\">first point on the edge we are traversing</param>\n        /// <param name=\"flipTriangle\">the current triangle sharing the point eq with edge</param>\n        /// <param name=\"t\"></param>\n        /// <param name=\"p\"></param>\n        private static void FlipScanEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle flipTriangle, DelaunayTriangle t, TriangulationPoint p)\n        {\n            DelaunayTriangle ot = t.NeighborAcross(p);\n\n            // see https://github.com/greenm01/poly2tri/issues/102\n            //if (ot == null)\n            //{\n            //    // If we want to integrate the fillEdgeEvent do it here\n            //    // With current implementation we should never get here\n            //    throw new Exception(\"[BUG:FIXME] FLIP failed due to missing triangle\");\n            //}\n\n            TriangulationPoint op = ot.OppositePoint(t, p);\n\n            bool inScanArea = TriangulationUtil.InScanArea(eq, flipTriangle.PointCCW(eq), flipTriangle.PointCW(eq), op);\n            if (inScanArea)\n            {\n                // flip with new edge op->eq\n                FlipEdgeEvent(tcx, eq, op, ot, op);\n\n                // TODO: Actually I just figured out that it should be possible to \n                //       improve this by getting the next ot and op before the the above \n                //       flip and continue the flipScanEdgeEvent here\n                // set new ot and op here and loop back to inScanArea test\n                // also need to set a new flipTriangle first\n                // Turns out at first glance that this is somewhat complicated\n                // so it will have to wait.\n            }\n            else\n            {\n                TriangulationPoint newP = NextFlipPoint(ep, eq, ot, op);\n                FlipScanEdgeEvent(tcx, ep, eq, flipTriangle, ot, newP);\n            }\n        }\n\n        /// <summary>\n        /// Fills holes in the Advancing Front\n        /// </summary>\n        private static void FillAdvancingFront(DTSweepContext tcx, AdvancingFrontNode n)\n        {\n            double angle;\n\n            // Fill right holes\n            AdvancingFrontNode node = n.Next;\n            while (node.HasNext)\n            {\n                // if HoleAngle exceeds 90 degrees then break.\n                if (LargeHole_DontFill(node))\n                    break;\n\n                Fill(tcx, node);\n                node = node.Next;\n            }\n\n            // Fill left holes\n            node = n.Prev;\n            while (node.HasPrev)\n            {\n                // if HoleAngle exceeds 90 degrees then break.\n                if (LargeHole_DontFill(node))\n                    break;\n\n                angle = HoleAngle(node);\n                if (angle > PI_div2 || angle < -PI_div2)\n                {\n                    break;\n                }\n                Fill(tcx, node);\n                node = node.Prev;\n            }\n\n            // Fill right basins\n            if (n.HasNext && n.Next.HasNext)\n            {\n                angle = BasinAngle(n);\n                if (angle < PI_3div4)\n                {\n                    FillBasin(tcx, n);\n                }\n            }\n        }\n\n        // True if HoleAngle exceeds 90 degrees.\n        private static bool LargeHole_DontFill(AdvancingFrontNode node)\n        {\n            AdvancingFrontNode nextNode = node.Next;\n            AdvancingFrontNode prevNode = node.Prev;\n            if (!AngleExceeds90Degrees(node.Point, nextNode.Point, prevNode.Point))\n                return false;\n\n            // Check additional points on front.\n            AdvancingFrontNode next2Node = nextNode.Next;\n\n            // \"..Plus..\" because only want angles on same side as point being added.\n            if ((next2Node != null) && !AngleExceedsPlus90DegreesOrIsNegative(node.Point, next2Node.Point, prevNode.Point))\n                return false;\n\n            AdvancingFrontNode prev2Node = prevNode.Prev;\n\n            // \"..Plus..\" because only want angles on same side as point being added.\n            if ((prev2Node != null) && !AngleExceedsPlus90DegreesOrIsNegative(node.Point, nextNode.Point, prev2Node.Point))\n                return false;\n\n            return true;\n        }\n\n        private static bool AngleExceeds90Degrees(TriangulationPoint origin, TriangulationPoint pa, TriangulationPoint pb)\n        {\n            double angle = Angle(origin, pa, pb);\n            bool exceeds90Degrees = ((angle > PI_div2) || (angle < -PI_div2));\n            return exceeds90Degrees;\n        }\n\n        private static bool AngleExceedsPlus90DegreesOrIsNegative(TriangulationPoint origin, TriangulationPoint pa, TriangulationPoint pb)\n        {\n            double angle = Angle(origin, pa, pb);\n            bool exceedsPlus90DegreesOrIsNegative = (angle > PI_div2) || (angle < 0);\n            return exceedsPlus90DegreesOrIsNegative;\n        }\n\n        private static double Angle(TriangulationPoint origin, TriangulationPoint pa, TriangulationPoint pb)\n        {\n            /* Complex plane\n            * ab = cosA +i*sinA\n            * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)\n            * atan2(y,x) computes the principal value of the argument function\n            * applied to the complex number x+iy\n            * Where x = ax*bx + ay*by\n            * y = ax*by - ay*bx\n            */\n            double px = origin.X;\n            double py = origin.Y;\n            double ax = pa.X - px;\n            double ay = pa.Y - py;\n            double bx = pb.X - px;\n            double by = pb.Y - py;\n            double x = ax * by - ay * bx;\n            double y = ax * bx + ay * by;\n            double angle = Math.Atan2(x, y);\n            return angle;\n        }\n\n        /// <summary>\n        /// Fills a basin that has formed on the Advancing Front to the right\n        /// of given node.\n        /// First we decide a left,bottom and right node that forms the\n        /// boundaries of the basin. Then we do a reqursive fill.\n        /// </summary>\n        /// <param name=\"tcx\"></param>\n        /// <param name=\"node\">starting node, this or next node will be left node</param>\n        private static void FillBasin(DTSweepContext tcx, AdvancingFrontNode node)\n        {\n            if (TriangulationUtil.Orient2d(node.Point, node.Next.Point, node.Next.Next.Point) == Orientation.CCW)\n            {\n                // tcx.basin.leftNode = node.next.next;\n                tcx.Basin.leftNode = node;\n            }\n            else\n            {\n                tcx.Basin.leftNode = node.Next;\n            }\n\n            // Find the bottom and right node\n            tcx.Basin.bottomNode = tcx.Basin.leftNode;\n            while (tcx.Basin.bottomNode.HasNext && tcx.Basin.bottomNode.Point.Y >= tcx.Basin.bottomNode.Next.Point.Y)\n            {\n                tcx.Basin.bottomNode = tcx.Basin.bottomNode.Next;\n            }\n\n            if (tcx.Basin.bottomNode == tcx.Basin.leftNode)\n            {\n                // No valid basins\n                return;\n            }\n\n            tcx.Basin.rightNode = tcx.Basin.bottomNode;\n            while (tcx.Basin.rightNode.HasNext && tcx.Basin.rightNode.Point.Y < tcx.Basin.rightNode.Next.Point.Y)\n            {\n                tcx.Basin.rightNode = tcx.Basin.rightNode.Next;\n            }\n\n            if (tcx.Basin.rightNode == tcx.Basin.bottomNode)\n            {\n                // No valid basins\n                return;\n            }\n\n            tcx.Basin.width = tcx.Basin.rightNode.Point.X - tcx.Basin.leftNode.Point.X;\n            tcx.Basin.leftHighest = tcx.Basin.leftNode.Point.Y > tcx.Basin.rightNode.Point.Y;\n\n            FillBasinReq(tcx, tcx.Basin.bottomNode);\n        }\n\n        /// <summary>\n        /// Recursive algorithm to fill a Basin with triangles\n        /// </summary>\n        private static void FillBasinReq(DTSweepContext tcx, AdvancingFrontNode node)\n        {\n            // if shallow stop filling\n            if (IsShallow(tcx, node))\n            {\n                return;\n            }\n\n            Fill(tcx, node);\n            if (node.Prev == tcx.Basin.leftNode && node.Next == tcx.Basin.rightNode)\n            {\n                return;\n            }\n            else if (node.Prev == tcx.Basin.leftNode)\n            {\n                Orientation o = TriangulationUtil.Orient2d(node.Point, node.Next.Point, node.Next.Next.Point);\n                if (o == Orientation.CW)\n                {\n                    return;\n                }\n                node = node.Next;\n            }\n            else if (node.Next == tcx.Basin.rightNode)\n            {\n                Orientation o = TriangulationUtil.Orient2d(node.Point, node.Prev.Point, node.Prev.Prev.Point);\n                if (o == Orientation.CCW)\n                {\n                    return;\n                }\n                node = node.Prev;\n            }\n            else\n            {\n                // Continue with the neighbor node with lowest Y value\n                if (node.Prev.Point.Y < node.Next.Point.Y)\n                {\n                    node = node.Prev;\n                }\n                else\n                {\n                    node = node.Next;\n                }\n            }\n            FillBasinReq(tcx, node);\n        }\n\n        private static bool IsShallow(DTSweepContext tcx, AdvancingFrontNode node)\n        {\n            double height;\n\n            if (tcx.Basin.leftHighest)\n            {\n                height = tcx.Basin.leftNode.Point.Y - node.Point.Y;\n            }\n            else\n            {\n                height = tcx.Basin.rightNode.Point.Y - node.Point.Y;\n            }\n            if (tcx.Basin.width > height)\n            {\n                return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// ???\n        /// </summary>\n        /// <param name=\"node\">middle node</param>\n        /// <returns>the angle between 3 front nodes</returns>\n        private static double HoleAngle(AdvancingFrontNode node)\n        {\n            // XXX: do we really need a signed angle for holeAngle?\n            //      could possible save some cycles here\n            /* Complex plane\n             * ab = cosA +i*sinA\n             * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)\n             * atan2(y,x) computes the principal value of the argument function\n             * applied to the complex number x+iy\n             * Where x = ax*bx + ay*by\n             *       y = ax*by - ay*bx\n             */\n            double px = node.Point.X;\n            double py = node.Point.Y;\n            double ax = node.Next.Point.X - px;\n            double ay = node.Next.Point.Y - py;\n            double bx = node.Prev.Point.X - px;\n            double by = node.Prev.Point.Y - py;\n            return Math.Atan2(ax * by - ay * bx, ax * bx + ay * by);\n        }\n\n        /// <summary>\n        /// The basin angle is decided against the horizontal line [1,0]\n        /// </summary>\n        private static double BasinAngle(AdvancingFrontNode node)\n        {\n            double ax = node.Point.X - node.Next.Next.Point.X;\n            double ay = node.Point.Y - node.Next.Next.Point.Y;\n            return Math.Atan2(ay, ax);\n        }\n\n        /// <summary>\n        /// Adds a triangle to the advancing front to fill a hole.\n        /// </summary>\n        /// <param name=\"tcx\"></param>\n        /// <param name=\"node\">middle node, that is the bottom of the hole</param>\n        private static void Fill(DTSweepContext tcx, AdvancingFrontNode node)\n        {\n            DelaunayTriangle triangle = new DelaunayTriangle(node.Prev.Point, node.Point, node.Next.Point);\n\n            // TODO: should copy the cEdge value from neighbor triangles\n            //       for now cEdge values are copied during the legalize \n            triangle.MarkNeighbor(node.Prev.Triangle);\n            triangle.MarkNeighbor(node.Triangle);\n            tcx.Triangles.Add(triangle);\n\n            // Update the advancing front\n            node.Prev.Next = node.Next;\n            node.Next.Prev = node.Prev;\n            tcx.RemoveNode(node);\n\n            // If it was legalized the triangle has already been mapped\n            if (!Legalize(tcx, triangle))\n            {\n                tcx.MapTriangleToNodes(triangle);\n            }\n        }\n\n        /// <summary>\n        /// Returns true if triangle was legalized\n        /// </summary>\n        private static bool Legalize(DTSweepContext tcx, DelaunayTriangle t)\n        {\n            // To legalize a triangle we start by finding if any of the three edges\n            // violate the Delaunay condition\n            for (int i = 0; i < 3; i++)\n            {\n                // TODO: fix so that cEdge is always valid when creating new triangles then we can check it here\n                //       instead of below with ot\n                if (t.EdgeIsDelaunay[i])\n                {\n                    continue;\n                }\n\n                DelaunayTriangle ot = t.Neighbors[i];\n                if (ot != null)\n                {\n                    TriangulationPoint p = t.Points[i];\n                    TriangulationPoint op = ot.OppositePoint(t, p);\n                    int oi = ot.IndexOf(op);\n\n                    // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization)\n                    // then we should not try to legalize\n                    if (ot.EdgeIsConstrained[oi] || ot.EdgeIsDelaunay[oi])\n                    {\n                        t.EdgeIsConstrained[i] = ot.EdgeIsConstrained[oi];\n\n                        // XXX: have no good way of setting this property when creating new triangles so lets set it here\n                        continue;\n                    }\n\n                    bool inside = TriangulationUtil.SmartIncircle(p, t.PointCCW(p), t.PointCW(p), op);\n\n                    if (inside)\n                    {\n                        // Lets mark this shared edge as Delaunay \n                        t.EdgeIsDelaunay[i] = true;\n                        ot.EdgeIsDelaunay[oi] = true;\n\n                        // Lets rotate shared edge one vertex CW to legalize it\n                        RotateTrianglePair(t, p, ot, op);\n\n                        // We now got one valid Delaunay Edge shared by two triangles\n                        // This gives us 4 new edges to check for Delaunay\n\n                        // Make sure that triangle to node mapping is done only one time for a specific triangle\n                        bool notLegalized = !Legalize(tcx, t);\n\n                        if (notLegalized)\n                        {\n                            tcx.MapTriangleToNodes(t);\n                        }\n                        notLegalized = !Legalize(tcx, ot);\n                        if (notLegalized)\n                        {\n                            tcx.MapTriangleToNodes(ot);\n                        }\n\n                        // Reset the Delaunay edges, since they only are valid Delaunay edges\n                        // until we add a new triangle or point.\n                        // XXX: need to think about this. Can these edges be tried after we \n                        //      return to previous recursive level?\n                        t.EdgeIsDelaunay[i] = false;\n                        ot.EdgeIsDelaunay[oi] = false;\n\n                        // If triangle have been legalized no need to check the other edges since\n                        // the recursive legalization will handles those so we can end here.\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Rotates a triangle pair one vertex CW\n        /// n2                    n2\n        /// P +-----+             P +-----+\n        /// | t  /|               |\\  t |\n        /// |   / |               | \\   |\n        /// n1|  /  |n3           n1|  \\  |n3\n        /// | /   |    after CW   |   \\ |\n        /// |/ oT |               | oT \\|\n        /// +-----+ oP            +-----+\n        /// n4                    n4\n        /// </summary>\n        private static void RotateTrianglePair(DelaunayTriangle t, TriangulationPoint p, DelaunayTriangle ot, TriangulationPoint op)\n        {\n            DelaunayTriangle n1 = t.NeighborCCW(p);\n            DelaunayTriangle n2 = t.NeighborCW(p);\n            DelaunayTriangle n3 = ot.NeighborCCW(op);\n            DelaunayTriangle n4 = ot.NeighborCW(op);\n\n            bool ce1 = t.GetConstrainedEdgeCCW(p);\n            bool ce2 = t.GetConstrainedEdgeCW(p);\n            bool ce3 = ot.GetConstrainedEdgeCCW(op);\n            bool ce4 = ot.GetConstrainedEdgeCW(op);\n\n            bool de1 = t.GetDelaunayEdgeCCW(p);\n            bool de2 = t.GetDelaunayEdgeCW(p);\n            bool de3 = ot.GetDelaunayEdgeCCW(op);\n            bool de4 = ot.GetDelaunayEdgeCW(op);\n\n            t.Legalize(p, op);\n            ot.Legalize(op, p);\n\n            // Remap dEdge\n            ot.SetDelaunayEdgeCCW(p, de1);\n            t.SetDelaunayEdgeCW(p, de2);\n            t.SetDelaunayEdgeCCW(op, de3);\n            ot.SetDelaunayEdgeCW(op, de4);\n\n            // Remap cEdge\n            ot.SetConstrainedEdgeCCW(p, ce1);\n            t.SetConstrainedEdgeCW(p, ce2);\n            t.SetConstrainedEdgeCCW(op, ce3);\n            ot.SetConstrainedEdgeCW(op, ce4);\n\n            // Remap neighbors\n            // XXX: might optimize the markNeighbor by keeping track of\n            //      what side should be assigned to what neighbor after the \n            //      rotation. Now mark neighbor does lots of testing to find \n            //      the right side.\n            t.Neighbors.Clear();\n            ot.Neighbors.Clear();\n            if (n1 != null) ot.MarkNeighbor(n1);\n            if (n2 != null) t.MarkNeighbor(n2);\n            if (n3 != null) t.MarkNeighbor(n3);\n            if (n4 != null) ot.MarkNeighbor(n4);\n            t.MarkNeighbor(ot);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/DTSweepConstraint.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    internal class DTSweepConstraint : TriangulationConstraint\n    {\n        /// <summary>\n        /// Give two points in any order. Will always be ordered so\n        /// that q.y > p.y and q.x > p.x if same y value\n        /// </summary>\n        public DTSweepConstraint(TriangulationPoint p1, TriangulationPoint p2)\n        {\n            P = p1;\n            Q = p2;\n            if (p1.Y > p2.Y)\n            {\n                Q = p1;\n                P = p2;\n            }\n            else if (p1.Y == p2.Y)\n            {\n                if (p1.X > p2.X)\n                {\n                    Q = p1;\n                    P = p2;\n                }\n                else if (p1.X == p2.X)\n                {\n                    //                logger.info( \"Failed to create constraint {}={}\", p1, p2 );\n                    //                throw new DuplicatePointException( p1 + \"=\" + p2 );\n                    //                return;\n                }\n            }\n            Q.AddEdge(this);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/DTSweepContext.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    /**\n     * \n     * @author Thomas Åhlén, thahlen@gmail.com\n     *\n     */\n\n    internal class DTSweepContext : TriangulationContext\n    {\n        // Inital triangle factor, seed triangle will extend 30% of \n        // PointSet width to both left and right.\n        private const float ALPHA = 0.3f;\n\n        private DTSweepPointComparator _comparator = new DTSweepPointComparator();\n        public AdvancingFront aFront;\n\n        public DTSweepBasin Basin = new DTSweepBasin();\n        public DTSweepEdgeEvent EdgeEvent = new DTSweepEdgeEvent();\n\n        public DTSweepContext()\n        {\n            Clear();\n        }\n\n        public TriangulationPoint Head { get; set; }\n        public TriangulationPoint Tail { get; set; }\n\n        public void RemoveFromList(DelaunayTriangle triangle)\n        {\n            Triangles.Remove(triangle);\n\n            // TODO: remove all neighbor pointers to this triangle\n            //        for( int i=0; i<3; i++ )\n            //        {\n            //            if( triangle.neighbors[i] != null )\n            //            {\n            //                triangle.neighbors[i].clearNeighbor( triangle );\n            //            }\n            //        }\n            //        triangle.clearNeighbors();\n        }\n\n        public void MeshClean(DelaunayTriangle triangle)\n        {\n            MeshCleanReq(triangle);\n        }\n\n        private void MeshCleanReq(DelaunayTriangle triangle)\n        {\n            if (triangle != null && !triangle.IsInterior)\n            {\n                triangle.IsInterior = true;\n                Triangulatable.AddTriangle(triangle);\n                for (int i = 0; i < 3; i++)\n                {\n                    if (!triangle.EdgeIsConstrained[i])\n                    {\n                        MeshCleanReq(triangle.Neighbors[i]);\n                    }\n                }\n            }\n        }\n\n        public override void Clear()\n        {\n            base.Clear();\n            Triangles.Clear();\n        }\n\n        public void AddNode(AdvancingFrontNode node)\n        {\n            //        Console.WriteLine( \"add:\" + node.key + \":\" + System.identityHashCode(node.key));\n            //        m_nodeTree.put( node.getKey(), node );\n            aFront.AddNode(node);\n        }\n\n        public void RemoveNode(AdvancingFrontNode node)\n        {\n            //        Console.WriteLine( \"remove:\" + node.key + \":\" + System.identityHashCode(node.key));\n            //        m_nodeTree.delete( node.getKey() );\n            aFront.RemoveNode(node);\n        }\n\n        public AdvancingFrontNode LocateNode(TriangulationPoint point)\n        {\n            return aFront.LocateNode(point);\n        }\n\n        public void CreateAdvancingFront()\n        {\n            AdvancingFrontNode head, tail, middle;\n\n            // Initial triangle\n            DelaunayTriangle iTriangle = new DelaunayTriangle(Points[0], Tail, Head);\n            Triangles.Add(iTriangle);\n\n            head = new AdvancingFrontNode(iTriangle.Points[1]);\n            head.Triangle = iTriangle;\n            middle = new AdvancingFrontNode(iTriangle.Points[0]);\n            middle.Triangle = iTriangle;\n            tail = new AdvancingFrontNode(iTriangle.Points[2]);\n\n            aFront = new AdvancingFront(head, tail);\n            aFront.AddNode(middle);\n\n            // TODO: I think it would be more intuitive if head is middles next and not previous\n            //       so swap head and tail\n            aFront.Head.Next = middle;\n            middle.Next = aFront.Tail;\n            middle.Prev = aFront.Head;\n            aFront.Tail.Prev = middle;\n        }\n\n        /// <summary>\n        /// Try to map a node to all sides of this triangle that don't have\n        /// a neighbor.\n        /// </summary>\n        public void MapTriangleToNodes(DelaunayTriangle t)\n        {\n            AdvancingFrontNode n;\n            for (int i = 0; i < 3; i++)\n            {\n                if (t.Neighbors[i] == null)\n                {\n                    n = aFront.LocatePoint(t.PointCW(t.Points[i]));\n                    if (n != null)\n                    {\n                        n.Triangle = t;\n                    }\n                }\n            }\n        }\n\n        public override void PrepareTriangulation(Triangulatable t)\n        {\n            base.PrepareTriangulation(t);\n\n            double xmax, xmin;\n            double ymax, ymin;\n\n            xmax = xmin = Points[0].X;\n            ymax = ymin = Points[0].Y;\n\n            // Calculate bounds. Should be combined with the sorting\n            foreach (TriangulationPoint p in Points)\n            {\n                if (p.X > xmax)\n                    xmax = p.X;\n                if (p.X < xmin)\n                    xmin = p.X;\n                if (p.Y > ymax)\n                    ymax = p.Y;\n                if (p.Y < ymin)\n                    ymin = p.Y;\n            }\n\n            double deltaX = ALPHA * (xmax - xmin);\n            double deltaY = ALPHA * (ymax - ymin);\n            TriangulationPoint p1 = new TriangulationPoint(xmax + deltaX, ymin - deltaY);\n            TriangulationPoint p2 = new TriangulationPoint(xmin - deltaX, ymin - deltaY);\n\n            Head = p1;\n            Tail = p2;\n\n            //        long time = System.nanoTime();\n            // Sort the points along y-axis\n            Points.Sort(_comparator);\n\n            //        logger.info( \"Triangulation setup [{}ms]\", ( System.nanoTime() - time ) / 1e6 );\n        }\n\n        public void FinalizeTriangulation()\n        {\n            Triangulatable.AddTriangles(Triangles);\n            Triangles.Clear();\n        }\n\n        public override TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b)\n        {\n            return new DTSweepConstraint(a, b);\n        }\n\n        #region Nested type: DTSweepBasin\n\n        public class DTSweepBasin\n        {\n            public AdvancingFrontNode bottomNode;\n            public bool leftHighest;\n            public AdvancingFrontNode leftNode;\n            public AdvancingFrontNode rightNode;\n            public double width;\n        }\n\n        #endregion\n\n        #region Nested type: DTSweepEdgeEvent\n\n        public class DTSweepEdgeEvent\n        {\n            public DTSweepConstraint ConstrainedEdge;\n            public bool Right;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/DTSweepPointComparator.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    internal class DTSweepPointComparator : IComparer<TriangulationPoint>\n    {\n        #region IComparer<TriangulationPoint> Members\n\n        public int Compare(TriangulationPoint p1, TriangulationPoint p2)\n        {\n            if (p1.Y < p2.Y)\n            {\n                return -1;\n            }\n            else if (p1.Y > p2.Y)\n            {\n                return 1;\n            }\n            else\n            {\n                if (p1.X < p2.X)\n                {\n                    return -1;\n                }\n                else if (p1.X > p2.X)\n                {\n                    return 1;\n                }\n                else\n                {\n                    return 0;\n                }\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Delaunay/Sweep/PointOnEdgeException.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep\n{\n    internal class PointOnEdgeException : NotImplementedException\n    {\n        public PointOnEdgeException(string message)\n            : base(message) { }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Orientation.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal enum Orientation\n    {\n        CW,\n        CCW,\n        Collinear\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Polygon/Polygon.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Changes from the Java version\n//   Polygon constructors sprused up, checks for 3+ polys\n//   Naming of everything\n//   getTriangulationMode() -> TriangulationMode { get; }\n//   Exceptions replaced\n// Future possibilities\n//   We have a lot of Add/Clear methods -- we may prefer to just expose the container\n//   Some self-explanitory methods may deserve commenting anyways\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Polygon\n{\n    internal class Polygon : Triangulatable\n    {\n        protected List<Polygon> _holes;\n        protected PolygonPoint _last;\n        protected List<TriangulationPoint> _points = new List<TriangulationPoint>();\n        protected List<TriangulationPoint> _steinerPoints;\n        protected List<DelaunayTriangle> _triangles;\n\n        /// <summary>\n        /// Create a polygon from a list of at least 3 points with no duplicates.\n        /// </summary>\n        /// <param name=\"points\">A list of unique points</param>\n        public Polygon(IList<PolygonPoint> points)\n        {\n            if (points.Count < 3)\n                throw new ArgumentException(\"List has fewer than 3 points\", nameof(points));\n\n            // Lets do one sanity check that first and last point hasn't got same position\n            // Its something that often happen when importing polygon data from other formats\n            if (points[0].Equals(points[points.Count - 1]))\n                points.RemoveAt(points.Count - 1);\n\n            _points.AddRange(points.Cast<TriangulationPoint>());\n        }\n\n        /// <summary>\n        /// Create a polygon from a list of at least 3 points with no duplicates.\n        /// </summary>\n        /// <param name=\"points\">A list of unique points.</param>\n        public Polygon(IEnumerable<PolygonPoint> points) : this((points as IList<PolygonPoint>) ?? points.ToArray()) { }\n\n        public Polygon() { }\n\n        public IList<Polygon> Holes\n        {\n            get { return _holes; }\n        }\n\n        public void AddSteinerPoint(TriangulationPoint point)\n        {\n            if (_steinerPoints == null)\n            {\n                _steinerPoints = new List<TriangulationPoint>();\n            }\n            _steinerPoints.Add(point);\n        }\n\n        public void AddSteinerPoints(List<TriangulationPoint> points)\n        {\n            if (_steinerPoints == null)\n            {\n                _steinerPoints = new List<TriangulationPoint>();\n            }\n            _steinerPoints.AddRange(points);\n        }\n\n        public void ClearSteinerPoints()\n        {\n            if (_steinerPoints != null)\n            {\n                _steinerPoints.Clear();\n            }\n        }\n\n        /// <summary>\n        /// Add a hole to the polygon.\n        /// </summary>\n        /// <param name=\"poly\">A subtraction polygon fully contained inside this polygon.</param>\n        public void AddHole(Polygon poly)\n        {\n            if (_holes == null)\n                _holes = new List<Polygon>();\n            _holes.Add(poly);\n\n            // XXX: tests could be made here to be sure it is fully inside\n            //        addSubtraction( poly.getPoints() );\n        }\n\n        /// <summary>\n        /// Inserts newPoint after point.\n        /// </summary>\n        /// <param name=\"point\">The point to insert after in the polygon</param>\n        /// <param name=\"newPoint\">The point to insert into the polygon</param>\n        public void InsertPointAfter(PolygonPoint point, PolygonPoint newPoint)\n        {\n            // Validate that \n            int index = _points.IndexOf(point);\n            if (index == -1)\n                throw new ArgumentException(\n                    \"Tried to insert a point into a Polygon after a point not belonging to the Polygon\", nameof(point));\n            newPoint.Next = point.Next;\n            newPoint.Previous = point;\n            point.Next.Previous = newPoint;\n            point.Next = newPoint;\n            _points.Insert(index + 1, newPoint);\n        }\n\n        /// <summary>\n        /// Inserts list (after last point in polygon?)\n        /// </summary>\n        /// <param name=\"list\"></param>\n        public void AddPoints(IEnumerable<PolygonPoint> list)\n        {\n            PolygonPoint first;\n            foreach (PolygonPoint p in list)\n            {\n                p.Previous = _last;\n                if (_last != null)\n                {\n                    p.Next = _last.Next;\n                    _last.Next = p;\n                }\n                _last = p;\n                _points.Add(p);\n            }\n            first = (PolygonPoint)_points[0];\n            _last.Next = first;\n            first.Previous = _last;\n        }\n\n        /// <summary>\n        /// Adds a point after the last in the polygon.\n        /// </summary>\n        /// <param name=\"p\">The point to add</param>\n        public void AddPoint(PolygonPoint p)\n        {\n            p.Previous = _last;\n            p.Next = _last.Next;\n            _last.Next = p;\n            _points.Add(p);\n        }\n\n        /// <summary>\n        /// Removes a point from the polygon.\n        /// </summary>\n        /// <param name=\"p\"></param>\n        public void RemovePoint(PolygonPoint p)\n        {\n            PolygonPoint next, prev;\n\n            next = p.Next;\n            prev = p.Previous;\n            prev.Next = next;\n            next.Previous = prev;\n            _points.Remove(p);\n        }\n\n        #region Triangulatable Members\n\n        public TriangulationMode TriangulationMode\n        {\n            get { return TriangulationMode.Polygon; }\n        }\n\n        public IList<TriangulationPoint> Points\n        {\n            get { return _points; }\n        }\n\n        public IList<DelaunayTriangle> Triangles\n        {\n            get { return _triangles; }\n        }\n\n        public void AddTriangle(DelaunayTriangle t)\n        {\n            _triangles.Add(t);\n        }\n\n        public void AddTriangles(IEnumerable<DelaunayTriangle> list)\n        {\n            _triangles.AddRange(list);\n        }\n\n        public void ClearTriangles()\n        {\n            if (_triangles != null)\n                _triangles.Clear();\n        }\n\n        /// <summary>\n        /// Creates constraints and populates the context with points\n        /// </summary>\n        /// <param name=\"tcx\">The context</param>\n        public void PrepareTriangulation(TriangulationContext tcx)\n        {\n            if (_triangles == null)\n            {\n                _triangles = new List<DelaunayTriangle>(_points.Count);\n            }\n            else\n            {\n                _triangles.Clear();\n            }\n\n            // Outer constraints\n            for (int i = 0; i < _points.Count - 1; i++)\n            {\n                tcx.NewConstraint(_points[i], _points[i + 1]);\n            }\n            tcx.NewConstraint(_points[0], _points[_points.Count - 1]);\n            tcx.Points.AddRange(_points);\n\n            // Hole constraints\n            if (_holes != null)\n            {\n                foreach (Polygon p in _holes)\n                {\n                    for (int i = 0; i < p._points.Count - 1; i++)\n                    {\n                        tcx.NewConstraint(p._points[i], p._points[i + 1]);\n                    }\n                    tcx.NewConstraint(p._points[0], p._points[p._points.Count - 1]);\n                    tcx.Points.AddRange(p._points);\n                }\n            }\n\n            if (_steinerPoints != null)\n            {\n                tcx.Points.AddRange(_steinerPoints);\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Polygon/PolygonPoint.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Changes from the Java version\n//   Replaced get/set Next/Previous with attributes\n// Future possibilities\n//   Documentation!\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Polygon\n{\n    internal class PolygonPoint : TriangulationPoint\n    {\n        public PolygonPoint(double x, double y) : base(x, y) { }\n\n        public PolygonPoint Next { get; set; }\n        public PolygonPoint Previous { get; set; }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Polygon/PolygonSet.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// Changes from the Java version\n//   Replaced getPolygons with attribute\n// Future possibilities\n//   Replace Add(Polygon) with exposed container?\n//   Replace entire class with HashSet<Polygon> ?\n\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Polygon\n{\n    internal class PolygonSet\n    {\n        protected List<Polygon> _polygons = new List<Polygon>();\n\n        public PolygonSet() { }\n\n        public PolygonSet(Polygon poly)\n        {\n            _polygons.Add(poly);\n        }\n\n        public IEnumerable<Polygon> Polygons\n        {\n            get { return _polygons; }\n        }\n\n        public void Add(Polygon p)\n        {\n            _polygons.Add(p);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Sets/ConstrainedPointSet.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Sets\n{\n    /*\n     * Extends the PointSet by adding some Constraints on how it will be triangulated<br>\n     * A constraint defines an edge between two points in the set, these edges can not\n     * be crossed. They will be enforced triangle edges after a triangulation.\n     * <p>\n     * \n     * \n     * @author Thomas Åhlén, thahlen@gmail.com\n     */\n\n    internal class ConstrainedPointSet : PointSet\n    {\n        private List<TriangulationPoint> _constrainedPointList;\n\n        public ConstrainedPointSet(List<TriangulationPoint> points, int[] index)\n            : base(points)\n        {\n            EdgeIndex = index;\n        }\n\n        /**\n         * \n         * @param points - A list of all points in PointSet\n         * @param constraints - Pairs of two points defining a constraint, all points <b>must</b> be part of given PointSet!\n         */\n\n        public ConstrainedPointSet(List<TriangulationPoint> points, IEnumerable<TriangulationPoint> constraints)\n            : base(points)\n        {\n            _constrainedPointList = new List<TriangulationPoint>();\n            _constrainedPointList.AddRange(constraints);\n        }\n\n        public int[] EdgeIndex { get; private set; }\n\n        public override TriangulationMode TriangulationMode\n        {\n            get { return TriangulationMode.Constrained; }\n        }\n\n        public override void PrepareTriangulation(TriangulationContext tcx)\n        {\n            base.PrepareTriangulation(tcx);\n            if (_constrainedPointList != null)\n            {\n                TriangulationPoint p1, p2;\n                List<TriangulationPoint>.Enumerator iterator = _constrainedPointList.GetEnumerator();\n                while (iterator.MoveNext())\n                {\n                    p1 = iterator.Current;\n                    iterator.MoveNext();\n                    p2 = iterator.Current;\n                    tcx.NewConstraint(p1, p2);\n                }\n            }\n            else\n            {\n                for (int i = 0; i < EdgeIndex.Length; i += 2)\n                {\n                    // XXX: must change!!\n                    tcx.NewConstraint(Points[EdgeIndex[i]], Points[EdgeIndex[i + 1]]);\n                }\n            }\n        }\n\n        /**\n         * TODO: TO BE IMPLEMENTED!\n         * Peforms a validation on given input<br>\n         * 1. Check's if there any constraint edges are crossing or collinear<br>\n         * 2. \n         * @return\n         */\n\n        public bool isValid()\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Sets/PointSet.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Sets\n{\n    internal class PointSet : Triangulatable\n    {\n        public PointSet(List<TriangulationPoint> points)\n        {\n            Points = new List<TriangulationPoint>(points);\n        }\n\n        #region Triangulatable Members\n\n        public IList<TriangulationPoint> Points { get; private set; }\n        public IList<DelaunayTriangle> Triangles { get; private set; }\n\n        public virtual TriangulationMode TriangulationMode\n        {\n            get { return TriangulationMode.Unconstrained; }\n        }\n\n        public void AddTriangle(DelaunayTriangle t)\n        {\n            Triangles.Add(t);\n        }\n\n        public void AddTriangles(IEnumerable<DelaunayTriangle> list)\n        {\n            foreach (DelaunayTriangle tri in list)\n                Triangles.Add(tri);\n        }\n\n        public void ClearTriangles()\n        {\n            Triangles.Clear();\n        }\n\n        public virtual void PrepareTriangulation(TriangulationContext tcx)\n        {\n            if (Triangles == null)\n            {\n                Triangles = new List<DelaunayTriangle>(Points.Count);\n            }\n            else\n            {\n                Triangles.Clear();\n            }\n            tcx.Points.AddRange(Points);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Triangulatable.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal interface Triangulatable\n    {\n        IList<TriangulationPoint> Points { get; } // MM: Neither of these are used via interface (yet?)\n        IList<DelaunayTriangle> Triangles { get; }\n        TriangulationMode TriangulationMode { get; }\n        void PrepareTriangulation(TriangulationContext tcx);\n\n        void AddTriangle(DelaunayTriangle t);\n        void AddTriangles(IEnumerable<DelaunayTriangle> list);\n        void ClearTriangles();\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/TriangulationConstraint.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Forces a triangle edge between two points p and q\n * when triangulating. For example used to enforce\n * Polygon Edges during a polygon triangulation.\n * \n * @author Thomas Åhlén, thahlen@gmail.com\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal class TriangulationConstraint\n    {\n        public TriangulationPoint P;\n        public TriangulationPoint Q;\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/TriangulationContext.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal abstract class TriangulationContext\n    {\n        public readonly List<TriangulationPoint> Points = new List<TriangulationPoint>(200);\n        public readonly List<DelaunayTriangle> Triangles = new List<DelaunayTriangle>();\n        private int _stepTime = -1;\n\n        public TriangulationContext()\n        {\n            Terminated = false;\n        }\n\n        public TriangulationMode TriangulationMode { get; protected set; }\n        public Triangulatable Triangulatable { get; private set; }\n\n        public bool WaitUntilNotified { get; private set; }\n        public bool Terminated { get; set; }\n\n        public int StepCount { get; private set; }\n        public virtual bool IsDebugEnabled { get; protected set; }\n\n        public void Done()\n        {\n            StepCount++;\n        }\n\n        public virtual void PrepareTriangulation(Triangulatable t)\n        {\n            Triangulatable = t;\n            TriangulationMode = t.TriangulationMode;\n            t.PrepareTriangulation(this);\n        }\n\n        public abstract TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b);\n\n        public void Update(string message) { }\n\n        public virtual void Clear()\n        {\n            Points.Clear();\n            Terminated = false;\n            StepCount = 0;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/TriangulationMode.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal enum TriangulationMode\n    {\n        Unconstrained,\n        Constrained,\n        Polygon\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/TriangulationPoint.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System.Collections.Generic;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Delaunay.Sweep;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    internal class TriangulationPoint\n    {\n        // List of edges this point constitutes an upper ending point (CDT)\n\n        public double X, Y;\n\n        public TriangulationPoint(double x, double y)\n        {\n            X = x;\n            Y = y;\n        }\n\n        public List<DTSweepConstraint> Edges { get; private set; }\n\n        public float Xf\n        {\n            get { return (float)X; }\n            set { X = value; }\n        }\n\n        public float Yf\n        {\n            get { return (float)Y; }\n            set { Y = value; }\n        }\n\n        public bool HasEdges\n        {\n            get { return Edges != null; }\n        }\n\n        public override string ToString()\n        {\n            return \"[\" + X + \",\" + Y + \"]\";\n        }\n\n        public void AddEdge(DTSweepConstraint e)\n        {\n            if (Edges == null)\n            {\n                Edges = new List<DTSweepConstraint>();\n            }\n            Edges.Add(e);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/TriangulationUtil.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay\n{\n    /**\n     * @author Thomas Åhlén, thahlen@gmail.com\n     */\n\n    internal class TriangulationUtil\n    {\n        public static double EPSILON = 1e-12;\n\n        /// <summary>\n        /// Requirements:\n        /// 1. a,b and c form a triangle.\n        /// 2. a and d is know to be on opposite side of bc\n        /// <code>\n        ///                a\n        ///                +\n        ///               / \\\n        ///              /   \\\n        ///            b/     \\c\n        ///            +-------+ \n        ///           /    B    \\  \n        ///          /           \\ \n        /// </code>\n        /// Facts:\n        /// d has to be in area B to have a chance to be inside the circle formed by a,b and c\n        /// d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW\n        /// This preknowledge gives us a way to optimize the incircle test\n        /// </summary>\n        /// <param name=\"pa\">triangle point, opposite d</param>\n        /// <param name=\"pb\">triangle point</param>\n        /// <param name=\"pc\">triangle point</param>\n        /// <param name=\"pd\">point opposite a</param>\n        /// <returns>true if d is inside circle, false if on circle edge</returns>\n        public static bool SmartIncircle(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc,\n                                         TriangulationPoint pd)\n        {\n            double pdx = pd.X;\n            double pdy = pd.Y;\n            double adx = pa.X - pdx;\n            double ady = pa.Y - pdy;\n            double bdx = pb.X - pdx;\n            double bdy = pb.Y - pdy;\n\n            double adxbdy = adx * bdy;\n            double bdxady = bdx * ady;\n            double oabd = adxbdy - bdxady;\n\n            //        oabd = orient2d(pa,pb,pd);\n            if (oabd <= 0)\n                return false;\n\n            double cdx = pc.X - pdx;\n            double cdy = pc.Y - pdy;\n\n            double cdxady = cdx * ady;\n            double adxcdy = adx * cdy;\n            double ocad = cdxady - adxcdy;\n\n            //      ocad = orient2d(pc,pa,pd);\n            if (ocad <= 0)\n                return false;\n\n            double bdxcdy = bdx * cdy;\n            double cdxbdy = cdx * bdy;\n\n            double alift = adx * adx + ady * ady;\n            double blift = bdx * bdx + bdy * bdy;\n            double clift = cdx * cdx + cdy * cdy;\n\n            double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;\n\n            return det > 0;\n        }\n        /*\n        public static bool InScanArea(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc,\n                                      TriangulationPoint pd)\n        {\n            double pdx = pd.X;\n            double pdy = pd.Y;\n            double adx = pa.X - pdx;\n            double ady = pa.Y - pdy;\n            double bdx = pb.X - pdx;\n            double bdy = pb.Y - pdy;\n\n            double adxbdy = adx*bdy;\n            double bdxady = bdx*ady;\n            double oabd = adxbdy - bdxady;\n            //        oabd = orient2d(pa,pb,pd);\n            if (oabd <= 0)\n            {\n                return false;\n            }\n\n            double cdx = pc.X - pdx;\n            double cdy = pc.Y - pdy;\n\n            double cdxady = cdx*ady;\n            double adxcdy = adx*cdy;\n            double ocad = cdxady - adxcdy;\n            //      ocad = orient2d(pc,pa,pd);\n            if (ocad <= 0)\n            {\n                return false;\n            }\n            return true;\n        }\n        */\n\n        public static bool InScanArea(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc, TriangulationPoint pd)\n        {\n            double oadb = (pa.X - pb.X) * (pd.Y - pb.Y) - (pd.X - pb.X) * (pa.Y - pb.Y);\n            if (oadb >= -EPSILON)\n            {\n                return false;\n            }\n\n            double oadc = (pa.X - pc.X) * (pd.Y - pc.Y) - (pd.X - pc.X) * (pa.Y - pc.Y);\n            if (oadc <= EPSILON)\n            {\n                return false;\n            }\n            return true;\n        }\n\n        /// Forumla to calculate signed area\n        /// Positive if CCW\n        /// Negative if CW\n        /// 0 if collinear\n        /// A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)\n        /// =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)\n        public static Orientation Orient2d(TriangulationPoint pa, TriangulationPoint pb, TriangulationPoint pc)\n        {\n            double detleft = (pa.X - pc.X) * (pb.Y - pc.Y);\n            double detright = (pa.Y - pc.Y) * (pb.X - pc.X);\n            double val = detleft - detright;\n            if (val > -EPSILON && val < EPSILON)\n            {\n                return Orientation.Collinear;\n            }\n            if (val > 0)\n            {\n                return Orientation.CCW;\n            }\n            return Orientation.CW;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Util/PointGenerator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Util\n{\n    internal class PointGenerator\n    {\n        private static readonly Random RNG = new Random();\n\n        public static List<TriangulationPoint> UniformDistribution(int n, double scale)\n        {\n            List<TriangulationPoint> points = new List<TriangulationPoint>();\n            for (int i = 0; i < n; i++)\n            {\n                points.Add(new TriangulationPoint(scale * (0.5 - RNG.NextDouble()), scale * (0.5 - RNG.NextDouble())));\n            }\n            return points;\n        }\n\n        public static List<TriangulationPoint> UniformGrid(int n, double scale)\n        {\n            double x = 0;\n            double size = scale / n;\n            double halfScale = 0.5 * scale;\n\n            List<TriangulationPoint> points = new List<TriangulationPoint>();\n            for (int i = 0; i < n + 1; i++)\n            {\n                x = halfScale - i * size;\n                for (int j = 0; j < n + 1; j++)\n                {\n                    points.Add(new TriangulationPoint(x, halfScale - j * size));\n                }\n            }\n            return points;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Delaunay/Util/PolygonGenerator.cs",
    "content": "﻿/* Poly2Tri\n * Copyright (c) 2009-2010, Poly2Tri Contributors\n * http://code.google.com/p/poly2tri/\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n * * Neither the name of Poly2Tri nor the names of its contributors may be\n *   used to endorse or promote products derived from this software without specific\n *   prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nusing System;\nusing VelcroPhysics.Tools.Triangulation.Delaunay.Polygon;\n\nnamespace VelcroPhysics.Tools.Triangulation.Delaunay.Util\n{\n    internal class PolygonGenerator\n    {\n        private static readonly Random RNG = new Random();\n\n        private static double PI_2 = 2.0 * Math.PI;\n\n        public static Polygon.Polygon RandomCircleSweep(double scale, int vertexCount)\n        {\n            PolygonPoint point;\n            PolygonPoint[] points;\n            double radius = scale / 4;\n\n            points = new PolygonPoint[vertexCount];\n            for (int i = 0; i < vertexCount; i++)\n            {\n                do\n                {\n                    if (i % 250 == 0)\n                    {\n                        radius += scale / 2 * (0.5 - RNG.NextDouble());\n                    }\n                    else if (i % 50 == 0)\n                    {\n                        radius += scale / 5 * (0.5 - RNG.NextDouble());\n                    }\n                    else\n                    {\n                        radius += 25 * scale / vertexCount * (0.5 - RNG.NextDouble());\n                    }\n                    radius = radius > scale / 2 ? scale / 2 : radius;\n                    radius = radius < scale / 10 ? scale / 10 : radius;\n                } while (radius < scale / 10 || radius > scale / 2);\n                point = new PolygonPoint(radius * Math.Cos((PI_2 * i) / vertexCount),\n                    radius * Math.Sin((PI_2 * i) / vertexCount));\n                points[i] = point;\n            }\n            return new Polygon.Polygon(points);\n        }\n\n        public static Polygon.Polygon RandomCircleSweep2(double scale, int vertexCount)\n        {\n            PolygonPoint point;\n            PolygonPoint[] points;\n            double radius = scale / 4;\n\n            points = new PolygonPoint[vertexCount];\n            for (int i = 0; i < vertexCount; i++)\n            {\n                do\n                {\n                    radius += scale / 5 * (0.5 - RNG.NextDouble());\n                    radius = radius > scale / 2 ? scale / 2 : radius;\n                    radius = radius < scale / 10 ? scale / 10 : radius;\n                } while (radius < scale / 10 || radius > scale / 2);\n                point = new PolygonPoint(radius * Math.Cos((PI_2 * i) / vertexCount),\n                    radius * Math.Sin((PI_2 * i) / vertexCount));\n                points[i] = point;\n            }\n            return new Polygon.Polygon(points);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Earclip/EarclipDecomposer.cs",
    "content": "﻿/*\n* C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010\n* \n* Original C++ Version Copyright (c) 2007 Eric Jordan\n*\n* This software is provided 'as-is', without any express or implied\n* warranty.  In no event will the authors be held liable for any damages\n* arising from the use of this software.\n* Permission is granted to anyone to use this software for any purpose,\n* including commercial applications, and to alter it and redistribute it\n* freely, subject to the following restrictions:\n* 1. The origin of this software must not be misrepresented; you must not\n* claim that you wrote the original software. If you use this software\n* in a product, an acknowledgment in the product documentation would be\n* appreciated but is not required.\n* 2. Altered source versions must be plainly marked as such, and must not be\n* misrepresented as being the original software.\n* 3. This notice may not be removed or altered from any source distribution.\n*/\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.Triangulation.Earclip\n{\n    /// <summary>\n    /// Convex decomposition algorithm using ear clipping\n    /// Properties:\n    /// - Only works on simple polygons.\n    /// - Does not support holes.\n    /// - Running time is O(n^2), n = number of vertices.\n    /// Source: http://www.ewjordan.com/earClip/\n    /// </summary>\n    internal static class EarclipDecomposer\n    {\n        //box2D rev 32 - for details, see http://www.box2d.org/forum/viewtopic.php?f=4&t=83&start=50 \n\n        /// <summary>\n        /// Decompose the polygon into several smaller non-concave polygon.\n        /// Each resulting polygon will have no more than Settings.MaxPolygonVertices vertices.\n        /// </summary>\n        /// <param name=\"vertices\">The vertices.</param>\n        /// <param name=\"tolerance\">The tolerance.</param>\n        public static List<Vertices> ConvexPartition(Vertices vertices, float tolerance = 0.001f)\n        {\n            Debug.Assert(vertices.Count > 3);\n            Debug.Assert(!vertices.IsCounterClockWise());\n\n            return TriangulatePolygon(vertices, tolerance);\n        }\n\n        /// <summary>\n        /// Triangulates a polygon using simple ear-clipping algorithm. Returns\n        /// size of Triangle array unless the polygon can't be triangulated.\n        /// This should only happen if the polygon self-intersects,\n        /// though it will not _always_ return null for a bad polygon - it is the\n        /// caller's responsibility to check for self-intersection, and if it\n        /// doesn't, it should at least check that the return value is non-null\n        /// before using. You're warned!\n        /// Triangles may be degenerate, especially if you have identical points\n        /// in the input to the algorithm.  Check this before you use them.\n        /// This is totally unoptimized, so for large polygons it should not be part\n        /// of the simulation loop.\n        /// </summary>\n        /// <remarks>\n        /// Only works on simple polygons.\n        /// </remarks>\n        private static List<Vertices> TriangulatePolygon(Vertices vertices, float tolerance)\n        {\n            //Velcro note: Check is needed as invalid triangles can be returned in recursive calls.\n            if (vertices.Count < 3)\n                return new List<Vertices>();\n\n            List<Vertices> results = new List<Vertices>();\n\n            //Recurse and split on pinch points\n            Vertices pA, pB;\n            Vertices pin = new Vertices(vertices);\n            if (ResolvePinchPoint(pin, out pA, out pB, tolerance))\n            {\n                List<Vertices> mergeA = TriangulatePolygon(pA, tolerance);\n                List<Vertices> mergeB = TriangulatePolygon(pB, tolerance);\n\n                if (mergeA.Count == -1 || mergeB.Count == -1)\n                    throw new Exception(\"Can't triangulate your polygon.\");\n\n                for (int i = 0; i < mergeA.Count; ++i)\n                {\n                    results.Add(new Vertices(mergeA[i]));\n                }\n                for (int i = 0; i < mergeB.Count; ++i)\n                {\n                    results.Add(new Vertices(mergeB[i]));\n                }\n\n                return results;\n            }\n\n            Vertices[] buffer = new Vertices[vertices.Count - 2];\n            int bufferSize = 0;\n            float[] xrem = new float[vertices.Count];\n            float[] yrem = new float[vertices.Count];\n            for (int i = 0; i < vertices.Count; ++i)\n            {\n                xrem[i] = vertices[i].X;\n                yrem[i] = vertices[i].Y;\n            }\n\n            int vNum = vertices.Count;\n\n            while (vNum > 3)\n            {\n                // Find an ear\n                int earIndex = -1;\n                float earMaxMinCross = -10.0f;\n                for (int i = 0; i < vNum; ++i)\n                {\n                    if (IsEar(i, xrem, yrem, vNum))\n                    {\n                        int lower = Remainder(i - 1, vNum);\n                        int upper = Remainder(i + 1, vNum);\n                        Vector2 d1 = new Vector2(xrem[upper] - xrem[i], yrem[upper] - yrem[i]);\n                        Vector2 d2 = new Vector2(xrem[i] - xrem[lower], yrem[i] - yrem[lower]);\n                        Vector2 d3 = new Vector2(xrem[lower] - xrem[upper], yrem[lower] - yrem[upper]);\n\n                        d1.Normalize();\n                        d2.Normalize();\n                        d3.Normalize();\n                        float cross12;\n                        MathUtils.Cross(ref d1, ref d2, out cross12);\n                        cross12 = Math.Abs(cross12);\n\n                        float cross23;\n                        MathUtils.Cross(ref d2, ref d3, out cross23);\n                        cross23 = Math.Abs(cross23);\n\n                        float cross31;\n                        MathUtils.Cross(ref d3, ref d1, out cross31);\n                        cross31 = Math.Abs(cross31);\n\n                        //Find the maximum minimum angle\n                        float minCross = Math.Min(cross12, Math.Min(cross23, cross31));\n                        if (minCross > earMaxMinCross)\n                        {\n                            earIndex = i;\n                            earMaxMinCross = minCross;\n                        }\n                    }\n                }\n\n                // If we still haven't found an ear, we're screwed.\n                // Note: sometimes this is happening because the\n                // remaining points are collinear.  Really these\n                // should just be thrown out without halting triangulation.\n                if (earIndex == -1)\n                {\n                    for (int i = 0; i < bufferSize; i++)\n                    {\n                        results.Add(buffer[i]);\n                    }\n\n                    return results;\n                }\n\n                // Clip off the ear:\n                // - remove the ear tip from the list\n\n                --vNum;\n                float[] newx = new float[vNum];\n                float[] newy = new float[vNum];\n                int currDest = 0;\n                for (int i = 0; i < vNum; ++i)\n                {\n                    if (currDest == earIndex)\n                        ++currDest;\n                    newx[i] = xrem[currDest];\n                    newy[i] = yrem[currDest];\n                    ++currDest;\n                }\n\n                // - add the clipped triangle to the triangle list\n                int under = (earIndex == 0) ? (vNum) : (earIndex - 1);\n                int over = (earIndex == vNum) ? 0 : (earIndex + 1);\n                Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under],\n                    yrem[under]);\n                buffer[bufferSize] = toAdd;\n                ++bufferSize;\n\n                // - replace the old list with the new one\n                xrem = newx;\n                yrem = newy;\n            }\n\n            Triangle tooAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);\n            buffer[bufferSize] = tooAdd;\n            ++bufferSize;\n\n            for (int i = 0; i < bufferSize; i++)\n            {\n                results.Add(new Vertices(buffer[i]));\n            }\n\n            return results;\n        }\n\n        /// <summary>\n        /// Finds and fixes \"pinch points,\" points where two polygon\n        /// vertices are at the same point.\n        /// If a pinch point is found, pin is broken up into poutA and poutB\n        /// and true is returned; otherwise, returns false.\n        /// Mostly for internal use.\n        /// O(N^2) time, which sucks...\n        /// </summary>\n        /// <param name=\"pin\">The pin.</param>\n        /// <param name=\"poutA\">The pout A.</param>\n        /// <param name=\"poutB\">The pout B.</param>\n        /// <param name=\"tolerance\"></param>\n        private static bool ResolvePinchPoint(Vertices pin, out Vertices poutA, out Vertices poutB, float tolerance)\n        {\n            poutA = new Vertices();\n            poutB = new Vertices();\n\n            if (pin.Count < 3)\n                return false;\n\n            bool hasPinchPoint = false;\n            int pinchIndexA = -1;\n            int pinchIndexB = -1;\n            for (int i = 0; i < pin.Count; ++i)\n            {\n                for (int j = i + 1; j < pin.Count; ++j)\n                {\n                    //Don't worry about pinch points where the points\n                    //are actually just dupe neighbors\n                    if (Math.Abs(pin[i].X - pin[j].X) < tolerance && Math.Abs(pin[i].Y - pin[j].Y) < tolerance && j != i + 1)\n                    {\n                        pinchIndexA = i;\n                        pinchIndexB = j;\n                        hasPinchPoint = true;\n                        break;\n                    }\n                }\n                if (hasPinchPoint)\n                    break;\n            }\n            if (hasPinchPoint)\n            {\n                int sizeA = pinchIndexB - pinchIndexA;\n                if (sizeA == pin.Count)\n                    return false; //has dupe points at wraparound, not a problem here\n                for (int i = 0; i < sizeA; ++i)\n                {\n                    int ind = Remainder(pinchIndexA + i, pin.Count); // is this right\n                    poutA.Add(pin[ind]);\n                }\n\n                int sizeB = pin.Count - sizeA;\n                for (int i = 0; i < sizeB; ++i)\n                {\n                    int ind = Remainder(pinchIndexB + i, pin.Count); // is this right    \n                    poutB.Add(pin[ind]);\n                }\n            }\n            return hasPinchPoint;\n        }\n\n        /// <summary>\n        /// Fix for obnoxious behavior for the % operator for negative numbers...\n        /// </summary>\n        /// <param name=\"x\">The x.</param>\n        /// <param name=\"modulus\">The modulus.</param>\n        /// <returns></returns>\n        private static int Remainder(int x, int modulus)\n        {\n            int rem = x % modulus;\n            while (rem < 0)\n            {\n                rem += modulus;\n            }\n            return rem;\n        }\n\n        /// <summary>\n        /// Checks if vertex i is the tip of an ear in polygon defined by xv[] and  yv[].\n        /// </summary>\n        /// <param name=\"i\">The i.</param>\n        /// <param name=\"xv\">The xv.</param>\n        /// <param name=\"yv\">The yv.</param>\n        /// <param name=\"xvLength\">Length of the xv.</param>\n        /// <remarks>\n        /// Assumes clockwise orientation of polygon.\n        /// </remarks>\n        /// <returns>\n        /// <c>true</c> if the specified i is ear; otherwise, <c>false</c>.\n        /// </returns>\n        private static bool IsEar(int i, float[] xv, float[] yv, int xvLength)\n        {\n            float dx0, dy0, dx1, dy1;\n            if (i >= xvLength || i < 0 || xvLength < 3)\n            {\n                return false;\n            }\n            int upper = i + 1;\n            int lower = i - 1;\n            if (i == 0)\n            {\n                dx0 = xv[0] - xv[xvLength - 1];\n                dy0 = yv[0] - yv[xvLength - 1];\n                dx1 = xv[1] - xv[0];\n                dy1 = yv[1] - yv[0];\n                lower = xvLength - 1;\n            }\n            else if (i == xvLength - 1)\n            {\n                dx0 = xv[i] - xv[i - 1];\n                dy0 = yv[i] - yv[i - 1];\n                dx1 = xv[0] - xv[i];\n                dy1 = yv[0] - yv[i];\n                upper = 0;\n            }\n            else\n            {\n                dx0 = xv[i] - xv[i - 1];\n                dy0 = yv[i] - yv[i - 1];\n                dx1 = xv[i + 1] - xv[i];\n                dy1 = yv[i + 1] - yv[i];\n            }\n\n            float cross = dx0 * dy1 - dx1 * dy0;\n\n            if (cross > 0)\n                return false;\n\n            Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]);\n\n            for (int j = 0; j < xvLength; ++j)\n            {\n                if (j == i || j == lower || j == upper)\n                    continue;\n                if (myTri.IsInside(xv[j], yv[j]))\n                    return false;\n            }\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Earclip/Triangle.cs",
    "content": "using Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Tools.Triangulation.Earclip {\n    public class Triangle : Vertices\n    {\n        //Constructor automatically fixes orientation to ccw\n        public Triangle(float x1, float y1, float x2, float y2, float x3, float y3)\n        {\n            float cross = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);\n            if (cross > 0)\n            {\n                Add(new Vector2(x1, y1));\n                Add(new Vector2(x2, y2));\n                Add(new Vector2(x3, y3));\n            }\n            else\n            {\n                Add(new Vector2(x1, y1));\n                Add(new Vector2(x3, y3));\n                Add(new Vector2(x2, y2));\n            }\n        }\n\n        public bool IsInside(float x, float y)\n        {\n            Vector2 a = this[0];\n            Vector2 b = this[1];\n            Vector2 c = this[2];\n\n            if (x < a.X && x < b.X && x < c.X) return false;\n            if (x > a.X && x > b.X && x > c.X) return false;\n            if (y < a.Y && y < b.Y && y < c.Y) return false;\n            if (y > a.Y && y > b.Y && y > c.Y) return false;\n\n            float vx2 = x - a.X;\n            float vy2 = y - a.Y;\n            float vx1 = b.X - a.X;\n            float vy1 = b.Y - a.Y;\n            float vx0 = c.X - a.X;\n            float vy0 = c.Y - a.Y;\n\n            float dot00 = vx0 * vx0 + vy0 * vy0;\n            float dot01 = vx0 * vx1 + vy0 * vy1;\n            float dot02 = vx0 * vx2 + vy0 * vy2;\n            float dot11 = vx1 * vx1 + vy1 * vy1;\n            float dot12 = vx1 * vx2 + vy1 * vy2;\n            float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);\n            float u = (dot11 * dot02 - dot01 * dot12) * invDenom;\n            float v = (dot00 * dot12 - dot01 * dot02) * invDenom;\n\n            return ((u > 0) && (v > 0) && (u + v < 1));\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/FlipCode/FlipcodeDecomposer.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Utilities;\n\nnamespace VelcroPhysics.Tools.Triangulation.FlipCode\n{\n    /// <summary>\n    /// Convex decomposition algorithm created by unknown\n    /// Properties:\n    /// - No support for holes\n    /// - Very fast\n    /// - Only works on simple polygons\n    /// - Only works on counter clockwise polygons\n    /// More information: http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml\n    /// </summary>\n    internal static class FlipcodeDecomposer\n    {\n        private static Vector2 _tmpA;\n        private static Vector2 _tmpB;\n        private static Vector2 _tmpC;\n\n        /// <summary>\n        /// Decompose the polygon into triangles.\n        /// Properties:\n        /// - Only works on counter clockwise polygons\n        /// </summary>\n        /// <param name=\"vertices\">The list of points describing the polygon</param>\n        public static List<Vertices> ConvexPartition(Vertices vertices)\n        {\n            Debug.Assert(vertices.Count > 3);\n            Debug.Assert(vertices.IsCounterClockWise());\n\n            int[] polygon = new int[vertices.Count];\n\n            for (int v = 0; v < vertices.Count; v++)\n                polygon[v] = v;\n\n            int nv = vertices.Count;\n\n            // Remove nv-2 Vertices, creating 1 triangle every time\n            int count = 2 * nv; /* error detection */\n\n            List<Vertices> result = new List<Vertices>();\n\n            for (int v = nv - 1; nv > 2;)\n            {\n                // If we loop, it is probably a non-simple polygon \n                if (0 >= (count--))\n                {\n                    // Triangulate: ERROR - probable bad polygon!\n                    return new List<Vertices>();\n                }\n\n                // Three consecutive vertices in current polygon, <u,v,w>\n                int u = v;\n                if (nv <= u)\n                    u = 0; // Previous \n                v = u + 1;\n                if (nv <= v)\n                    v = 0; // New v   \n                int w = v + 1;\n                if (nv <= w)\n                    w = 0; // Next \n\n                _tmpA = vertices[polygon[u]];\n                _tmpB = vertices[polygon[v]];\n                _tmpC = vertices[polygon[w]];\n\n                if (Snip(vertices, u, v, w, nv, polygon))\n                {\n                    int s, t;\n\n                    // Output Triangle\n                    Vertices triangle = new Vertices(3);\n                    triangle.Add(_tmpA);\n                    triangle.Add(_tmpB);\n                    triangle.Add(_tmpC);\n                    result.Add(triangle);\n\n                    // Remove v from remaining polygon \n                    for (s = v, t = v + 1; t < nv; s++, t++)\n                    {\n                        polygon[s] = polygon[t];\n                    }\n                    nv--;\n\n                    // Reset error detection counter\n                    count = 2 * nv;\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Check if the point P is inside the triangle defined by\n        /// the points A, B, C\n        /// </summary>\n        /// <param name=\"a\">The A point.</param>\n        /// <param name=\"b\">The B point.</param>\n        /// <param name=\"c\">The C point.</param>\n        /// <param name=\"p\">The point to be tested.</param>\n        /// <returns>True if the point is inside the triangle</returns>\n        private static bool InsideTriangle(ref Vector2 a, ref Vector2 b, ref Vector2 c, ref Vector2 p)\n        {\n            //A cross bp\n            float abp = (c.X - b.X) * (p.Y - b.Y) - (c.Y - b.Y) * (p.X - b.X);\n\n            //A cross ap\n            float aap = (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X);\n\n            //b cross cp\n            float bcp = (a.X - c.X) * (p.Y - c.Y) - (a.Y - c.Y) * (p.X - c.X);\n\n            return ((abp >= 0.0f) && (bcp >= 0.0f) && (aap >= 0.0f));\n        }\n\n        /// <summary>\n        /// Cut a the contour and add a triangle into V to describe the\n        /// location of the cut\n        /// </summary>\n        /// <param name=\"contour\">The list of points defining the polygon</param>\n        /// <param name=\"u\">The index of the first point</param>\n        /// <param name=\"v\">The index of the second point</param>\n        /// <param name=\"w\">The index of the third point</param>\n        /// <param name=\"n\">The number of elements in the array.</param>\n        /// <param name=\"V\">The array to populate with indicies of triangles.</param>\n        /// <returns>True if a triangle was found</returns>\n        private static bool Snip(Vertices contour, int u, int v, int w, int n, int[] V)\n        {\n            if (Settings.Epsilon > MathUtils.Area(ref _tmpA, ref _tmpB, ref _tmpC))\n                return false;\n\n            for (int p = 0; p < n; p++)\n            {\n                if ((p == u) || (p == v) || (p == w))\n                    continue;\n\n                Vector2 point = contour[V[p]];\n\n                if (InsideTriangle(ref _tmpA, ref _tmpB, ref _tmpC, ref point))\n                    return false;\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Edge.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class Edge\n    {\n        // Pointers used for building trapezoidal map\n        public Trapezoid Above;\n\n        public float B;\n        public Trapezoid Below;\n\n        // Montone mountain points\n        public HashSet<Point> MPoints;\n\n        public Point P;\n        public Point Q;\n\n        // Slope of the line (m)\n        public float Slope;\n\n        public Edge(Point p, Point q)\n        {\n            P = p;\n            Q = q;\n\n            if (q.X - p.X != 0)\n                Slope = (q.Y - p.Y) / (q.X - p.X);\n            else\n                Slope = 0;\n\n            B = p.Y - (p.X * Slope);\n            Above = null;\n            Below = null;\n            MPoints = new HashSet<Point>();\n            MPoints.Add(p);\n            MPoints.Add(q);\n        }\n\n        public bool IsAbove(Point point)\n        {\n            return P.Orient2D(Q, point) < 0;\n        }\n\n        public bool IsBelow(Point point)\n        {\n            return P.Orient2D(Q, point) > 0;\n        }\n\n        public void AddMpoint(Point point)\n        {\n            foreach (Point mp in MPoints)\n            {\n                if (!mp.Neq(point))\n                    return;\n            }\n\n            MPoints.Add(point);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/MonotoneMountain.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class MonotoneMountain\n    {\n        // Almost Pi!\n        private const float PiSlop = 3.1f;\n\n        private HashSet<Point> _convexPoints;\n        private Point _head;\n\n        // Monotone mountain points\n        private List<Point> _monoPoly;\n\n        // Used to track which side of the line we are on\n        private bool _positive;\n\n        private int _size;\n        private Point _tail;\n\n        // Triangles that constitute the mountain\n        public List<List<Point>> Triangles;\n\n        public MonotoneMountain()\n        {\n            _size = 0;\n            _tail = null;\n            _head = null;\n            _positive = false;\n            _convexPoints = new HashSet<Point>();\n            _monoPoly = new List<Point>();\n            Triangles = new List<List<Point>>();\n        }\n\n        // Append a point to the list\n        public void Add(Point point)\n        {\n            if (_size == 0)\n            {\n                _head = point;\n                _size = 1;\n            }\n            else if (_size == 1)\n            {\n                // Keep repeat points out of the list\n                _tail = point;\n                _tail.Prev = _head;\n                _head.Next = _tail;\n                _size = 2;\n            }\n            else\n            {\n                // Keep repeat points out of the list\n                _tail.Next = point;\n                point.Prev = _tail;\n                _tail = point;\n                _size += 1;\n            }\n        }\n\n        // Remove a point from the list\n        public void Remove(Point point)\n        {\n            Point next = point.Next;\n            Point prev = point.Prev;\n            point.Prev.Next = next;\n            point.Next.Prev = prev;\n            _size -= 1;\n        }\n\n        // Partition a x-monotone mountain into triangles O(n)\n        // See \"Computational Geometry in C\", 2nd edition, by Joseph O'Rourke, page 52\n        public void Process()\n        {\n            // Establish the proper sign\n            _positive = AngleSign();\n\n            // create monotone polygon - for dubug purposes\n            GenMonoPoly();\n\n            // Initialize internal angles at each nonbase vertex\n            // Link strictly convex vertices into a list, ignore reflex vertices\n            Point p = _head.Next;\n            while (p.Neq(_tail))\n            {\n                float a = Angle(p);\n\n                // If the point is almost colinear with it's neighbor, remove it!\n                if (a >= PiSlop || a <= -PiSlop || a == 0.0f)\n                    Remove(p);\n                else if (IsConvex(p))\n                    _convexPoints.Add(p);\n                p = p.Next;\n            }\n\n            Triangulate();\n        }\n\n        private void Triangulate()\n        {\n            while (_convexPoints.Count != 0)\n            {\n                IEnumerator<Point> e = _convexPoints.GetEnumerator();\n                e.MoveNext();\n                Point ear = e.Current;\n\n                _convexPoints.Remove(ear);\n                Point a = ear.Prev;\n                Point b = ear;\n                Point c = ear.Next;\n                List<Point> triangle = new List<Point>(3);\n                triangle.Add(a);\n                triangle.Add(b);\n                triangle.Add(c);\n\n                Triangles.Add(triangle);\n\n                // Remove ear, update angles and convex list\n                Remove(ear);\n                if (Valid(a))\n                    _convexPoints.Add(a);\n                if (Valid(c))\n                    _convexPoints.Add(c);\n            }\n\n            Debug.Assert(_size <= 3, \"Triangulation bug, please report\");\n        }\n\n        private bool Valid(Point p)\n        {\n            return p.Neq(_head) && p.Neq(_tail) && IsConvex(p);\n        }\n\n        // Create the monotone polygon\n        private void GenMonoPoly()\n        {\n            Point p = _head;\n            while (p != null)\n            {\n                _monoPoly.Add(p);\n                p = p.Next;\n            }\n        }\n\n        private float Angle(Point p)\n        {\n            Point a = (p.Next - p);\n            Point b = (p.Prev - p);\n            return (float)Math.Atan2(a.Cross(b), a.Dot(b));\n        }\n\n        private bool AngleSign()\n        {\n            Point a = (_head.Next - _head);\n            Point b = (_tail - _head);\n            return Math.Atan2(a.Cross(b), a.Dot(b)) >= 0;\n        }\n\n        // Determines if the inslide angle is convex or reflex\n        private bool IsConvex(Point p)\n        {\n            if (_positive != (Angle(p) >= 0))\n                return false;\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Node.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    // Node for a Directed Acyclic graph (DAG)\n    internal abstract class Node\n    {\n        protected Node LeftChild;\n        public List<Node> ParentList;\n        protected Node RightChild;\n\n        protected Node(Node left, Node right)\n        {\n            ParentList = new List<Node>();\n            LeftChild = left;\n            RightChild = right;\n\n            if (left != null)\n                left.ParentList.Add(this);\n            if (right != null)\n                right.ParentList.Add(this);\n        }\n\n        public abstract Sink Locate(Edge s);\n\n        // Replace a node in the graph with this node\n        // Make sure parent pointers are updated\n        public void Replace(Node node)\n        {\n            foreach (Node parent in node.ParentList)\n            {\n                // Select the correct node to replace (left or right child)\n                if (parent.LeftChild == node)\n                    parent.LeftChild = this;\n                else\n                    parent.RightChild = this;\n            }\n            ParentList.AddRange(node.ParentList);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Point.cs",
    "content": "﻿namespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class Point\n    {\n        // Pointers to next and previous points in Monontone Mountain\n        public Point Next, Prev;\n\n        public float X, Y;\n\n        public Point(float x, float y)\n        {\n            X = x;\n            Y = y;\n            Next = null;\n            Prev = null;\n        }\n\n        public static Point operator -(Point p1, Point p2)\n        {\n            return new Point(p1.X - p2.X, p1.Y - p2.Y);\n        }\n\n        public static Point operator +(Point p1, Point p2)\n        {\n            return new Point(p1.X + p2.X, p1.Y + p2.Y);\n        }\n\n        public static Point operator -(Point p1, float f)\n        {\n            return new Point(p1.X - f, p1.Y - f);\n        }\n\n        public static Point operator +(Point p1, float f)\n        {\n            return new Point(p1.X + f, p1.Y + f);\n        }\n\n        public float Cross(Point p)\n        {\n            return X * p.Y - Y * p.X;\n        }\n\n        public float Dot(Point p)\n        {\n            return X * p.X + Y * p.Y;\n        }\n\n        public bool Neq(Point p)\n        {\n            return p.X != X || p.Y != Y;\n        }\n\n        public float Orient2D(Point pb, Point pc)\n        {\n            float acx = X - pc.X;\n            float bcx = pb.X - pc.X;\n            float acy = Y - pc.Y;\n            float bcy = pb.Y - pc.Y;\n            return acx * bcy - acy * bcx;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/QueryGraph.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    // Directed Acyclic graph (DAG)\n    // See \"Computational Geometry\", 3rd edition, by Mark de Berg et al, Chapter 6.2\n    internal class QueryGraph\n    {\n        private Node _head;\n\n        public QueryGraph(Node head)\n        {\n            _head = head;\n        }\n\n        private Trapezoid Locate(Edge edge)\n        {\n            return _head.Locate(edge).Trapezoid;\n        }\n\n        public List<Trapezoid> FollowEdge(Edge edge)\n        {\n            List<Trapezoid> trapezoids = new List<Trapezoid>();\n            trapezoids.Add(Locate(edge));\n            int j = 0;\n\n            while (edge.Q.X > trapezoids[j].RightPoint.X)\n            {\n                if (edge.IsAbove(trapezoids[j].RightPoint))\n                {\n                    trapezoids.Add(trapezoids[j].UpperRight);\n                }\n                else\n                {\n                    trapezoids.Add(trapezoids[j].LowerRight);\n                }\n                j += 1;\n            }\n            return trapezoids;\n        }\n\n        private void Replace(Sink sink, Node node)\n        {\n            if (sink.ParentList.Count == 0)\n                _head = node;\n            else\n                node.Replace(sink);\n        }\n\n        public void Case1(Sink sink, Edge edge, Trapezoid[] tList)\n        {\n            YNode yNode = new YNode(edge, Sink.Isink(tList[1]), Sink.Isink(tList[2]));\n            XNode qNode = new XNode(edge.Q, yNode, Sink.Isink(tList[3]));\n            XNode pNode = new XNode(edge.P, Sink.Isink(tList[0]), qNode);\n            Replace(sink, pNode);\n        }\n\n        public void Case2(Sink sink, Edge edge, Trapezoid[] tList)\n        {\n            YNode yNode = new YNode(edge, Sink.Isink(tList[1]), Sink.Isink(tList[2]));\n            XNode pNode = new XNode(edge.P, Sink.Isink(tList[0]), yNode);\n            Replace(sink, pNode);\n        }\n\n        public void Case3(Sink sink, Edge edge, Trapezoid[] tList)\n        {\n            YNode yNode = new YNode(edge, Sink.Isink(tList[0]), Sink.Isink(tList[1]));\n            Replace(sink, yNode);\n        }\n\n        public void Case4(Sink sink, Edge edge, Trapezoid[] tList)\n        {\n            YNode yNode = new YNode(edge, Sink.Isink(tList[0]), Sink.Isink(tList[1]));\n            XNode qNode = new XNode(edge.Q, yNode, Sink.Isink(tList[2]));\n            Replace(sink, qNode);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/SeidelDecomposer.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n*/\n\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    /// <summary>\n    /// Convex decomposition algorithm created by Raimund Seidel\n    /// Properties:\n    /// - Decompose the polygon into trapezoids, then triangulate.\n    /// - To use the trapezoid data, use ConvexPartitionTrapezoid()\n    /// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.\n    /// - Running time is O(n log n), n = number of vertices.\n    /// - Running time is almost linear for most simple polygons.\n    /// - Does not care about winding order.\n    /// For more information, see Raimund Seidel's paper \"A simple and fast incremental randomized\n    /// algorithm for computing trapezoidal decompositions and for triangulating polygons\"\n    /// See also: \"Computational Geometry\", 3rd edition, by Mark de Berg et al, Chapter 6.2\n    /// \"Computational Geometry in C\", 2nd edition, by Joseph O'Rourke\n    /// Original code from the Poly2Tri project by Mason Green.\n    /// http://code.google.com/p/poly2tri/source/browse?repo=archive#hg/scala/src/org/poly2tri/seidel\n    /// This implementation is from Dec 14, 2010\n    /// </summary>\n    internal static class SeidelDecomposer\n    {\n        /// <summary>\n        /// Decompose the polygon into several smaller non-concave polygons.\n        /// </summary>\n        /// <param name=\"vertices\">The polygon to decompose.</param>\n        /// <param name=\"sheer\">The sheer to use if you get bad results, try using a higher value.</param>\n        /// <returns>A list of triangles</returns>\n        public static List<Vertices> ConvexPartition(Vertices vertices, float sheer = 0.001f)\n        {\n            Debug.Assert(vertices.Count > 3);\n\n            List<Point> compatList = new List<Point>(vertices.Count);\n\n            foreach (Vector2 vertex in vertices)\n            {\n                compatList.Add(new Point(vertex.X, vertex.Y));\n            }\n\n            Triangulator t = new Triangulator(compatList, sheer);\n\n            List<Vertices> list = new List<Vertices>();\n\n            foreach (List<Point> triangle in t.Triangles)\n            {\n                Vertices outTriangles = new Vertices(triangle.Count);\n\n                foreach (Point outTriangle in triangle)\n                {\n                    outTriangles.Add(new Vector2(outTriangle.X, outTriangle.Y));\n                }\n\n                list.Add(outTriangles);\n            }\n\n            return list;\n        }\n\n        /// <summary>\n        /// Decompose the polygon into several smaller non-concave polygons.\n        /// </summary>\n        /// <param name=\"vertices\">The polygon to decompose.</param>\n        /// <param name=\"sheer\">The sheer to use if you get bad results, try using a higher value.</param>\n        /// <returns>A list of trapezoids</returns>\n        public static List<Vertices> ConvexPartitionTrapezoid(Vertices vertices, float sheer = 0.001f)\n        {\n            List<Point> compatList = new List<Point>(vertices.Count);\n\n            foreach (Vector2 vertex in vertices)\n            {\n                compatList.Add(new Point(vertex.X, vertex.Y));\n            }\n\n            Triangulator t = new Triangulator(compatList, sheer);\n\n            List<Vertices> list = new List<Vertices>();\n\n            foreach (Trapezoid trapezoid in t.Trapezoids)\n            {\n                Vertices verts = new Vertices();\n\n                List<Point> points = trapezoid.GetVertices();\n                foreach (Point point in points)\n                {\n                    verts.Add(new Vector2(point.X, point.Y));\n                }\n\n                list.Add(verts);\n            }\n\n            return list;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Sink.cs",
    "content": "﻿namespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class Sink : Node\n    {\n        public Trapezoid Trapezoid;\n\n        private Sink(Trapezoid trapezoid)\n            : base(null, null)\n        {\n            Trapezoid = trapezoid;\n            trapezoid.Sink = this;\n        }\n\n        public static Sink Isink(Trapezoid trapezoid)\n        {\n            if (trapezoid.Sink == null)\n                return new Sink(trapezoid);\n\n            return trapezoid.Sink;\n        }\n\n        public override Sink Locate(Edge edge)\n        {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Trapezoid.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class Trapezoid\n    {\n        public Edge Bottom;\n        public bool Inside;\n        public Point LeftPoint;\n\n        // Neighbor pointers\n        public Trapezoid LowerLeft;\n\n        public Trapezoid LowerRight;\n\n        public Point RightPoint;\n        public Sink Sink;\n\n        public Edge Top;\n        public Trapezoid UpperLeft;\n        public Trapezoid UpperRight;\n\n        public Trapezoid(Point leftPoint, Point rightPoint, Edge top, Edge bottom)\n        {\n            LeftPoint = leftPoint;\n            RightPoint = rightPoint;\n            Top = top;\n            Bottom = bottom;\n            UpperLeft = null;\n            UpperRight = null;\n            LowerLeft = null;\n            LowerRight = null;\n            Inside = true;\n            Sink = null;\n        }\n\n        // Update neighbors to the left\n        public void UpdateLeft(Trapezoid ul, Trapezoid ll)\n        {\n            UpperLeft = ul;\n            if (ul != null) ul.UpperRight = this;\n            LowerLeft = ll;\n            if (ll != null) ll.LowerRight = this;\n        }\n\n        // Update neighbors to the right\n        public void UpdateRight(Trapezoid ur, Trapezoid lr)\n        {\n            UpperRight = ur;\n            if (ur != null) ur.UpperLeft = this;\n            LowerRight = lr;\n            if (lr != null) lr.LowerLeft = this;\n        }\n\n        // Update neighbors on both sides\n        public void UpdateLeftRight(Trapezoid ul, Trapezoid ll, Trapezoid ur, Trapezoid lr)\n        {\n            UpperLeft = ul;\n            if (ul != null) ul.UpperRight = this;\n            LowerLeft = ll;\n            if (ll != null) ll.LowerRight = this;\n            UpperRight = ur;\n            if (ur != null) ur.UpperLeft = this;\n            LowerRight = lr;\n            if (lr != null) lr.LowerLeft = this;\n        }\n\n        // Recursively trim outside neighbors\n        public void TrimNeighbors()\n        {\n            if (Inside)\n            {\n                Inside = false;\n                if (UpperLeft != null) UpperLeft.TrimNeighbors();\n                if (LowerLeft != null) LowerLeft.TrimNeighbors();\n                if (UpperRight != null) UpperRight.TrimNeighbors();\n                if (LowerRight != null) LowerRight.TrimNeighbors();\n            }\n        }\n\n        // Determines if this point lies inside the trapezoid\n        public bool Contains(Point point)\n        {\n            return (point.X > LeftPoint.X && point.X < RightPoint.X && Top.IsAbove(point) && Bottom.IsBelow(point));\n        }\n\n        public List<Point> GetVertices()\n        {\n            List<Point> verts = new List<Point>(4);\n            verts.Add(LineIntersect(Top, LeftPoint.X));\n            verts.Add(LineIntersect(Bottom, LeftPoint.X));\n            verts.Add(LineIntersect(Bottom, RightPoint.X));\n            verts.Add(LineIntersect(Top, RightPoint.X));\n            return verts;\n        }\n\n        private Point LineIntersect(Edge edge, float x)\n        {\n            float y = edge.Slope * x + edge.B;\n            return new Point(x, y);\n        }\n\n        // Add points to monotone mountain\n        public void AddPoints()\n        {\n            if (LeftPoint != Bottom.P)\n            {\n                Bottom.AddMpoint(LeftPoint);\n            }\n            if (RightPoint != Bottom.Q)\n            {\n                Bottom.AddMpoint(RightPoint);\n            }\n            if (LeftPoint != Top.P)\n            {\n                Top.AddMpoint(LeftPoint);\n            }\n            if (RightPoint != Top.Q)\n            {\n                Top.AddMpoint(RightPoint);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/TrapezoidalMap.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class TrapezoidalMap\n    {\n        // Bottom segment that spans multiple trapezoids\n        private Edge _bCross;\n\n        // Top segment that spans multiple trapezoids\n        private Edge _cross;\n\n        // AABB margin\n        private float _margin;\n\n        // Trapezoid container\n        public HashSet<Trapezoid> Map;\n\n        public TrapezoidalMap()\n        {\n            Map = new HashSet<Trapezoid>();\n            _margin = 50.0f;\n            _bCross = null;\n            _cross = null;\n        }\n\n        public void Clear()\n        {\n            _bCross = null;\n            _cross = null;\n        }\n\n        // Case 1: segment completely enclosed by trapezoid\n        //         break trapezoid into 4 smaller trapezoids\n        public Trapezoid[] Case1(Trapezoid t, Edge e)\n        {\n            Trapezoid[] trapezoids = new Trapezoid[4];\n            trapezoids[0] = new Trapezoid(t.LeftPoint, e.P, t.Top, t.Bottom);\n            trapezoids[1] = new Trapezoid(e.P, e.Q, t.Top, e);\n            trapezoids[2] = new Trapezoid(e.P, e.Q, e, t.Bottom);\n            trapezoids[3] = new Trapezoid(e.Q, t.RightPoint, t.Top, t.Bottom);\n\n            trapezoids[0].UpdateLeft(t.UpperLeft, t.LowerLeft);\n            trapezoids[1].UpdateLeftRight(trapezoids[0], null, trapezoids[3], null);\n            trapezoids[2].UpdateLeftRight(null, trapezoids[0], null, trapezoids[3]);\n            trapezoids[3].UpdateRight(t.UpperRight, t.LowerRight);\n\n            return trapezoids;\n        }\n\n        // Case 2: Trapezoid contains point p, q lies outside\n        //         break trapezoid into 3 smaller trapezoids\n        public Trapezoid[] Case2(Trapezoid t, Edge e)\n        {\n            Point rp;\n            if (e.Q.X == t.RightPoint.X)\n                rp = e.Q;\n            else\n                rp = t.RightPoint;\n\n            Trapezoid[] trapezoids = new Trapezoid[3];\n            trapezoids[0] = new Trapezoid(t.LeftPoint, e.P, t.Top, t.Bottom);\n            trapezoids[1] = new Trapezoid(e.P, rp, t.Top, e);\n            trapezoids[2] = new Trapezoid(e.P, rp, e, t.Bottom);\n\n            trapezoids[0].UpdateLeft(t.UpperLeft, t.LowerLeft);\n            trapezoids[1].UpdateLeftRight(trapezoids[0], null, t.UpperRight, null);\n            trapezoids[2].UpdateLeftRight(null, trapezoids[0], null, t.LowerRight);\n\n            _bCross = t.Bottom;\n            _cross = t.Top;\n\n            e.Above = trapezoids[1];\n            e.Below = trapezoids[2];\n\n            return trapezoids;\n        }\n\n        // Case 3: Trapezoid is bisected\n        public Trapezoid[] Case3(Trapezoid t, Edge e)\n        {\n            Point lp;\n            if (e.P.X == t.LeftPoint.X)\n                lp = e.P;\n            else\n                lp = t.LeftPoint;\n\n            Point rp;\n            if (e.Q.X == t.RightPoint.X)\n                rp = e.Q;\n            else\n                rp = t.RightPoint;\n\n            Trapezoid[] trapezoids = new Trapezoid[2];\n\n            if (_cross == t.Top)\n            {\n                trapezoids[0] = t.UpperLeft;\n                trapezoids[0].UpdateRight(t.UpperRight, null);\n                trapezoids[0].RightPoint = rp;\n            }\n            else\n            {\n                trapezoids[0] = new Trapezoid(lp, rp, t.Top, e);\n                trapezoids[0].UpdateLeftRight(t.UpperLeft, e.Above, t.UpperRight, null);\n            }\n\n            if (_bCross == t.Bottom)\n            {\n                trapezoids[1] = t.LowerLeft;\n                trapezoids[1].UpdateRight(null, t.LowerRight);\n                trapezoids[1].RightPoint = rp;\n            }\n            else\n            {\n                trapezoids[1] = new Trapezoid(lp, rp, e, t.Bottom);\n                trapezoids[1].UpdateLeftRight(e.Below, t.LowerLeft, null, t.LowerRight);\n            }\n\n            _bCross = t.Bottom;\n            _cross = t.Top;\n\n            e.Above = trapezoids[0];\n            e.Below = trapezoids[1];\n\n            return trapezoids;\n        }\n\n        // Case 4: Trapezoid contains point q, p lies outside\n        //         break trapezoid into 3 smaller trapezoids\n        public Trapezoid[] Case4(Trapezoid t, Edge e)\n        {\n            Point lp;\n            if (e.P.X == t.LeftPoint.X)\n                lp = e.P;\n            else\n                lp = t.LeftPoint;\n\n            Trapezoid[] trapezoids = new Trapezoid[3];\n\n            if (_cross == t.Top)\n            {\n                trapezoids[0] = t.UpperLeft;\n                trapezoids[0].RightPoint = e.Q;\n            }\n            else\n            {\n                trapezoids[0] = new Trapezoid(lp, e.Q, t.Top, e);\n                trapezoids[0].UpdateLeft(t.UpperLeft, e.Above);\n            }\n\n            if (_bCross == t.Bottom)\n            {\n                trapezoids[1] = t.LowerLeft;\n                trapezoids[1].RightPoint = e.Q;\n            }\n            else\n            {\n                trapezoids[1] = new Trapezoid(lp, e.Q, e, t.Bottom);\n                trapezoids[1].UpdateLeft(e.Below, t.LowerLeft);\n            }\n\n            trapezoids[2] = new Trapezoid(e.Q, t.RightPoint, t.Top, t.Bottom);\n            trapezoids[2].UpdateLeftRight(trapezoids[0], trapezoids[1], t.UpperRight, t.LowerRight);\n\n            return trapezoids;\n        }\n\n        // Create an AABB around segments\n        public Trapezoid BoundingBox(List<Edge> edges)\n        {\n            Point max = edges[0].P + _margin;\n            Point min = edges[0].Q - _margin;\n\n            foreach (Edge e in edges)\n            {\n                if (e.P.X > max.X) max = new Point(e.P.X + _margin, max.Y);\n                if (e.P.Y > max.Y) max = new Point(max.X, e.P.Y + _margin);\n                if (e.Q.X > max.X) max = new Point(e.Q.X + _margin, max.Y);\n                if (e.Q.Y > max.Y) max = new Point(max.X, e.Q.Y + _margin);\n                if (e.P.X < min.X) min = new Point(e.P.X - _margin, min.Y);\n                if (e.P.Y < min.Y) min = new Point(min.X, e.P.Y - _margin);\n                if (e.Q.X < min.X) min = new Point(e.Q.X - _margin, min.Y);\n                if (e.Q.Y < min.Y) min = new Point(min.X, e.Q.Y - _margin);\n            }\n\n            Edge top = new Edge(new Point(min.X, max.Y), new Point(max.X, max.Y));\n            Edge bottom = new Edge(new Point(min.X, min.Y), new Point(max.X, min.Y));\n            Point left = bottom.P;\n            Point right = top.Q;\n\n            return new Trapezoid(left, right, top, bottom);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/Triangulator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class Triangulator\n    {\n        // Initialize trapezoidal map and query structure\n        private Trapezoid _boundingBox;\n\n        private List<Edge> _edgeList;\n        private QueryGraph _queryGraph;\n        private float _sheer = 0.001f;\n        private TrapezoidalMap _trapezoidalMap;\n\n        private List<MonotoneMountain> _xMonoPoly;\n\n        // Trapezoid decomposition list\n        public List<Trapezoid> Trapezoids;\n\n        public List<List<Point>> Triangles;\n\n        public Triangulator(List<Point> polyLine, float sheer)\n        {\n            _sheer = sheer;\n            Triangles = new List<List<Point>>();\n            Trapezoids = new List<Trapezoid>();\n            _xMonoPoly = new List<MonotoneMountain>();\n            _edgeList = InitEdges(polyLine);\n            _trapezoidalMap = new TrapezoidalMap();\n            _boundingBox = _trapezoidalMap.BoundingBox(_edgeList);\n            _queryGraph = new QueryGraph(Sink.Isink(_boundingBox));\n\n            Process();\n        }\n\n        // Build the trapezoidal map and query graph\n        private void Process()\n        {\n            foreach (Edge edge in _edgeList)\n            {\n                List<Trapezoid> traps = _queryGraph.FollowEdge(edge);\n\n                // Remove trapezoids from trapezoidal Map\n                foreach (Trapezoid t in traps)\n                {\n                    _trapezoidalMap.Map.Remove(t);\n\n                    bool cp = t.Contains(edge.P);\n                    bool cq = t.Contains(edge.Q);\n                    Trapezoid[] tList;\n\n                    if (cp && cq)\n                    {\n                        tList = _trapezoidalMap.Case1(t, edge);\n                        _queryGraph.Case1(t.Sink, edge, tList);\n                    }\n                    else if (cp && !cq)\n                    {\n                        tList = _trapezoidalMap.Case2(t, edge);\n                        _queryGraph.Case2(t.Sink, edge, tList);\n                    }\n                    else if (!cp && !cq)\n                    {\n                        tList = _trapezoidalMap.Case3(t, edge);\n                        _queryGraph.Case3(t.Sink, edge, tList);\n                    }\n                    else\n                    {\n                        tList = _trapezoidalMap.Case4(t, edge);\n                        _queryGraph.Case4(t.Sink, edge, tList);\n                    }\n\n                    // Add new trapezoids to map\n                    foreach (Trapezoid y in tList)\n                    {\n                        _trapezoidalMap.Map.Add(y);\n                    }\n                }\n                _trapezoidalMap.Clear();\n            }\n\n            // Mark outside trapezoids\n            foreach (Trapezoid t in _trapezoidalMap.Map)\n            {\n                MarkOutside(t);\n            }\n\n            // Collect interior trapezoids\n            foreach (Trapezoid t in _trapezoidalMap.Map)\n            {\n                if (t.Inside)\n                {\n                    Trapezoids.Add(t);\n                    t.AddPoints();\n                }\n            }\n\n            // Generate the triangles\n            CreateMountains();\n        }\n\n        // Build a list of x-monotone mountains\n        private void CreateMountains()\n        {\n            foreach (Edge edge in _edgeList)\n            {\n                if (edge.MPoints.Count > 2)\n                {\n                    MonotoneMountain mountain = new MonotoneMountain();\n\n                    // Sorting is a perfromance hit. Literature says this can be accomplised in\n                    // linear time, although I don't see a way around using traditional methods\n                    // when using a randomized incremental algorithm\n\n                    // Insertion sort is one of the fastest algorithms for sorting arrays containing \n                    // fewer than ten elements, or for lists that are already mostly sorted.\n\n                    List<Point> points = new List<Point>(edge.MPoints);\n                    points.Sort((p1, p2) => p1.X.CompareTo(p2.X));\n\n                    foreach (Point p in points)\n                        mountain.Add(p);\n\n                    // Triangulate monotone mountain\n                    mountain.Process();\n\n                    // Extract the triangles into a single list\n                    foreach (List<Point> t in mountain.Triangles)\n                    {\n                        Triangles.Add(t);\n                    }\n\n                    _xMonoPoly.Add(mountain);\n                }\n            }\n        }\n\n        // Mark the outside trapezoids surrounding the polygon\n        private void MarkOutside(Trapezoid t)\n        {\n            if (t.Top == _boundingBox.Top || t.Bottom == _boundingBox.Bottom)\n                t.TrimNeighbors();\n        }\n\n        // Create segments and connect end points; update edge event pointer\n        private List<Edge> InitEdges(List<Point> points)\n        {\n            List<Edge> edges = new List<Edge>();\n\n            for (int i = 0; i < points.Count - 1; i++)\n            {\n                edges.Add(new Edge(points[i], points[i + 1]));\n            }\n            edges.Add(new Edge(points[0], points[points.Count - 1]));\n            return OrderSegments(edges);\n        }\n\n        private List<Edge> OrderSegments(List<Edge> edgeInput)\n        {\n            // Ignore vertical segments!\n            List<Edge> edges = new List<Edge>();\n\n            foreach (Edge e in edgeInput)\n            {\n                Point p = ShearTransform(e.P);\n                Point q = ShearTransform(e.Q);\n\n                // Point p must be to the left of point q\n                if (p.X > q.X)\n                {\n                    edges.Add(new Edge(q, p));\n                }\n                else if (p.X < q.X)\n                {\n                    edges.Add(new Edge(p, q));\n                }\n            }\n\n            // Randomized triangulation improves performance\n            // See Seidel's paper, or O'Rourke's book, p. 57 \n            Shuffle(edges);\n            return edges;\n        }\n\n        private static void Shuffle<T>(IList<T> list)\n        {\n            Random rng = new Random();\n            int n = list.Count;\n            while (n > 1)\n            {\n                n--;\n                int k = rng.Next(n + 1);\n                T value = list[k];\n                list[k] = list[n];\n                list[n] = value;\n            }\n        }\n\n        // Prevents any two distinct endpoints from lying on a common vertical line, and avoiding\n        // the degenerate case. See Mark de Berg et al, Chapter 6.3\n        private Point ShearTransform(Point point)\n        {\n            return new Point(point.X + _sheer * point.Y, point.Y);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/XNode.cs",
    "content": "﻿namespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class XNode : Node\n    {\n        private Point _point;\n\n        public XNode(Point point, Node lChild, Node rChild)\n            : base(lChild, rChild)\n        {\n            _point = point;\n        }\n\n        public override Sink Locate(Edge edge)\n        {\n            if (edge.P.X >= _point.X)\n                return RightChild.Locate(edge); // Move to the right in the graph\n\n            return LeftChild.Locate(edge); // Move to the left in the graph\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/Seidel/YNode.cs",
    "content": "﻿namespace VelcroPhysics.Tools.Triangulation.Seidel\n{\n    internal class YNode : Node\n    {\n        private Edge _edge;\n\n        public YNode(Edge edge, Node lChild, Node rChild)\n            : base(lChild, rChild)\n        {\n            _edge = edge;\n        }\n\n        public override Sink Locate(Edge edge)\n        {\n            if (_edge.IsAbove(edge.P))\n                return RightChild.Locate(edge); // Move down the graph\n\n            if (_edge.IsBelow(edge.P))\n                return LeftChild.Locate(edge); // Move up the graph\n\n            // s and segment share the same endpoint, p\n            if (edge.Slope < _edge.Slope)\n                return RightChild.Locate(edge); // Move down the graph\n\n            // Move up the graph\n            return LeftChild.Locate(edge);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/TriangulationBase/Triangulate.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.ConvexHull.GiftWrap;\nusing VelcroPhysics.Tools.Triangulation.Bayazit;\nusing VelcroPhysics.Tools.Triangulation.Delaunay;\nusing VelcroPhysics.Tools.Triangulation.Earclip;\nusing VelcroPhysics.Tools.Triangulation.FlipCode;\nusing VelcroPhysics.Tools.Triangulation.Seidel;\n\nnamespace VelcroPhysics.Tools.Triangulation.TriangulationBase\n{\n    public static class Triangulate\n    {\n        public static List<Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)\n        {\n            if (vertices.Count <= 3)\n                return new List<Vertices> { vertices };\n\n            List<Vertices> results;\n\n            switch (algorithm)\n            {\n                case TriangulationAlgorithm.Earclip:\n                    if (Settings.SkipSanityChecks)\n                        Debug.Assert(!vertices.IsCounterClockWise(), \"The Ear-clip algorithm expects the polygon to be clockwise.\");\n                    else\n                    {\n                        if (vertices.IsCounterClockWise())\n                        {\n                            Vertices temp = new Vertices(vertices);\n                            temp.Reverse();\n                            results = EarclipDecomposer.ConvexPartition(temp, tolerance);\n                        }\n                        else\n                            results = EarclipDecomposer.ConvexPartition(vertices, tolerance);\n                    }\n                    break;\n                case TriangulationAlgorithm.Bayazit:\n                    if (Settings.SkipSanityChecks)\n                        Debug.Assert(vertices.IsCounterClockWise(), \"The polygon is not counter clockwise. This is needed for Bayazit to work correctly.\");\n                    else\n                    {\n                        if (!vertices.IsCounterClockWise())\n                        {\n                            Vertices temp = new Vertices(vertices);\n                            temp.Reverse();\n                            results = BayazitDecomposer.ConvexPartition(temp);\n                        }\n                        else\n                            results = BayazitDecomposer.ConvexPartition(vertices);\n                    }\n                    break;\n                case TriangulationAlgorithm.Flipcode:\n                    if (Settings.SkipSanityChecks)\n                        Debug.Assert(vertices.IsCounterClockWise(), \"The polygon is not counter clockwise. This is needed for Bayazit to work correctly.\");\n                    else\n                    {\n                        if (!vertices.IsCounterClockWise())\n                        {\n                            Vertices temp = new Vertices(vertices);\n                            temp.Reverse();\n                            results = FlipcodeDecomposer.ConvexPartition(temp);\n                        }\n                        else\n                            results = FlipcodeDecomposer.ConvexPartition(vertices);\n                    }\n                    break;\n                case TriangulationAlgorithm.Seidel:\n                    results = SeidelDecomposer.ConvexPartition(vertices, tolerance);\n                    break;\n                case TriangulationAlgorithm.SeidelTrapezoids:\n                    results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance);\n                    break;\n                case TriangulationAlgorithm.Delauny:\n                    results = CDTDecomposer.ConvexPartition(vertices);\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(algorithm));\n            }\n\n            if (discardAndFixInvalid)\n            {\n                for (int i = results.Count - 1; i >= 0; i--)\n                {\n                    Vertices polygon = results[i];\n\n                    if (!ValidatePolygon(polygon))\n                        results.RemoveAt(i);\n                }\n            }\n\n            return results;\n        }\n\n        private static bool ValidatePolygon(Vertices polygon)\n        {\n            PolygonError errorCode = polygon.CheckPolygon();\n\n            if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall || errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)\n                return false;\n\n            if (errorCode == PolygonError.NotCounterClockWise) //NotCounterCloseWise is the last check in CheckPolygon(), thus we don't need to call ValidatePolygon again.\n                polygon.Reverse();\n\n            if (errorCode == PolygonError.NotConvex)\n            {\n                polygon = GiftWrap.GetConvexHull(polygon);\n                return ValidatePolygon(polygon);\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Tools/Triangulation/TriangulationBase/TriangulationAlgorithm.cs",
    "content": "namespace VelcroPhysics.Tools.Triangulation.TriangulationBase\n{\n    public enum TriangulationAlgorithm\n    {\n        /// <summary>\n        /// Convex decomposition algorithm using ear clipping\n        /// Properties:\n        /// - Only works on simple polygons.\n        /// - Does not support holes.\n        /// - Running time is O(n^2), n = number of vertices.\n        /// </summary>\n        Earclip,\n\n        /// <summary>\n        /// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/)\n        /// Properties:\n        /// - Tries to decompose using polygons instead of triangles.\n        /// - Tends to produce optimal results with low processing time.\n        /// - Running time is O(nr), n = number of vertices, r = reflex vertices.\n        /// - Does not support holes.\n        /// </summary>\n        Bayazit,\n\n        /// <summary>\n        /// Convex decomposition algorithm created by unknown\n        /// Properties:\n        /// - No support for holes\n        /// - Very fast\n        /// - Only works on simple polygons\n        /// - Only works on counter clockwise polygons\n        /// </summary>\n        Flipcode,\n\n        /// <summary>\n        /// Convex decomposition algorithm created by Raimund Seidel\n        /// Properties:\n        /// - Decompose the polygon into trapezoids, then triangulate.\n        /// - To use the trapezoid data, use ConvexPartitionTrapezoid()\n        /// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.\n        /// - Running time is O(n log n), n = number of vertices.\n        /// - Running time is almost linear for most simple polygons.\n        /// - Does not care about winding order.\n        /// </summary>\n        Seidel,\n        SeidelTrapezoids,\n\n        /// <summary>\n        /// 2D constrained Delaunay triangulation algorithm.\n        /// Based on the paper \"Sweep-line algorithm for constrained Delaunay triangulation\" by V. Domiter and and B. Zalik\n        /// Properties:\n        /// - Creates triangles with a large interior angle.\n        /// - Supports holes\n        /// - Generate a lot of garbage due to incapsulation of the Poly2Tri library.\n        /// - Running time is O(n^2), n = number of vertices.\n        /// - Does not care about winding order.\n        /// </summary>\n        Delauny\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Utilities/ConvertUnits.cs",
    "content": "/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n*/\n\nusing Microsoft.Xna.Framework;\n\nnamespace VelcroPhysics.Utilities\n{\n    /// <summary>\n    /// Convert units between display and simulation units.\n    /// </summary>\n    public static class ConvertUnits\n    {\n        private static float _displayUnitsToSimUnitsRatio = 100f;\n        private static float _simUnitsToDisplayUnitsRatio = 1 / _displayUnitsToSimUnitsRatio;\n\n        public static void SetDisplayUnitToSimUnitRatio(float displayUnitsPerSimUnit)\n        {\n            _displayUnitsToSimUnitsRatio = displayUnitsPerSimUnit;\n            _simUnitsToDisplayUnitsRatio = 1 / displayUnitsPerSimUnit;\n        }\n\n        public static float ToDisplayUnits(float simUnits)\n        {\n            return simUnits * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static float ToDisplayUnits(int simUnits)\n        {\n            return simUnits * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static Vector2 ToDisplayUnits(Vector2 simUnits)\n        {\n            return simUnits * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static void ToDisplayUnits(ref Vector2 simUnits, out Vector2 displayUnits)\n        {\n            Vector2.Multiply(ref simUnits, _displayUnitsToSimUnitsRatio, out displayUnits);\n        }\n\n        public static Vector3 ToDisplayUnits(Vector3 simUnits)\n        {\n            return simUnits * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static Vector2 ToDisplayUnits(float x, float y)\n        {\n            return new Vector2(x, y) * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static void ToDisplayUnits(float x, float y, out Vector2 displayUnits)\n        {\n            displayUnits = Vector2.Zero;\n            displayUnits.X = x * _displayUnitsToSimUnitsRatio;\n            displayUnits.Y = y * _displayUnitsToSimUnitsRatio;\n        }\n\n        public static float ToSimUnits(float displayUnits)\n        {\n            return displayUnits * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static float ToSimUnits(double displayUnits)\n        {\n            return (float)displayUnits * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static float ToSimUnits(int displayUnits)\n        {\n            return displayUnits * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static Vector2 ToSimUnits(Vector2 displayUnits)\n        {\n            return displayUnits * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static Vector3 ToSimUnits(Vector3 displayUnits)\n        {\n            return displayUnits * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static void ToSimUnits(ref Vector2 displayUnits, out Vector2 simUnits)\n        {\n            Vector2.Multiply(ref displayUnits, _simUnitsToDisplayUnitsRatio, out simUnits);\n        }\n\n        public static Vector2 ToSimUnits(float x, float y)\n        {\n            return new Vector2(x, y) * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static Vector2 ToSimUnits(double x, double y)\n        {\n            return new Vector2((float)x, (float)y) * _simUnitsToDisplayUnitsRatio;\n        }\n\n        public static void ToSimUnits(float x, float y, out Vector2 simUnits)\n        {\n            simUnits = Vector2.Zero;\n            simUnits.X = x * _simUnitsToDisplayUnitsRatio;\n            simUnits.Y = y * _simUnitsToDisplayUnitsRatio;\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Utilities/LineUtils.cs",
    "content": "﻿using System;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Utilities\n{\n    /// <summary>\n    /// Collection of helper methods for misc collisions.\n    /// Does float tolerance and line collisions with lines and AABBs.\n    /// </summary>\n    public static class LineUtils\n    {\n        public static float DistanceBetweenPointAndLineSegment(ref Vector2 point, ref Vector2 start, ref Vector2 end)\n        {\n            if (start == end)\n                return Vector2.Distance(point, start);\n\n            Vector2 v = Vector2.Subtract(end, start);\n            Vector2 w = Vector2.Subtract(point, start);\n\n            float c1 = Vector2.Dot(w, v);\n            if (c1 <= 0)\n                return Vector2.Distance(point, start);\n\n            float c2 = Vector2.Dot(v, v);\n            if (c2 <= c1)\n                return Vector2.Distance(point, end);\n\n            float b = c1 / c2;\n            Vector2 pointOnLine = Vector2.Add(start, Vector2.Multiply(v, b));\n            return Vector2.Distance(point, pointOnLine);\n        }\n\n        // From Eric Jordan's convex decomposition library\n        /// <summary>\n        /// Check if the lines a0->a1 and b0->b1 cross.\n        /// If they do, intersectionPoint will be filled\n        /// with the point of crossing.\n        /// Grazing lines should not return true.\n        /// </summary>\n        public static bool LineIntersect2(ref Vector2 a0, ref Vector2 a1, ref Vector2 b0, ref Vector2 b1, out Vector2 intersectionPoint)\n        {\n            intersectionPoint = Vector2.Zero;\n\n            if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1)\n                return false;\n\n            float x1 = a0.X;\n            float y1 = a0.Y;\n            float x2 = a1.X;\n            float y2 = a1.Y;\n            float x3 = b0.X;\n            float y3 = b0.Y;\n            float x4 = b1.X;\n            float y4 = b1.Y;\n\n            //AABB early exit\n            if (Math.Max(x1, x2) < Math.Min(x3, x4) || Math.Max(x3, x4) < Math.Min(x1, x2))\n                return false;\n\n            if (Math.Max(y1, y2) < Math.Min(y3, y4) || Math.Max(y3, y4) < Math.Min(y1, y2))\n                return false;\n\n            float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));\n            float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));\n            float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);\n            if (Math.Abs(denom) < Settings.Epsilon)\n            {\n                //Lines are too close to parallel to call\n                return false;\n            }\n            ua /= denom;\n            ub /= denom;\n\n            if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1))\n            {\n                intersectionPoint.X = (x1 + ua * (x2 - x1));\n                intersectionPoint.Y = (y1 + ua * (y2 - y1));\n                return true;\n            }\n\n            return false;\n        }\n\n        //From Mark Bayazit's convex decomposition algorithm\n        public static Vector2 LineIntersect(Vector2 p1, Vector2 p2, Vector2 q1, Vector2 q2)\n        {\n            Vector2 i = Vector2.Zero;\n            float a1 = p2.Y - p1.Y;\n            float b1 = p1.X - p2.X;\n            float c1 = a1 * p1.X + b1 * p1.Y;\n            float a2 = q2.Y - q1.Y;\n            float b2 = q1.X - q2.X;\n            float c2 = a2 * q1.X + b2 * q1.Y;\n            float det = a1 * b2 - a2 * b1;\n\n            if (!MathUtils.FloatEquals(det, 0))\n            {\n                // lines are not parallel\n                i.X = (b2 * c1 - b1 * c2) / det;\n                i.Y = (a1 * c2 - a2 * c1) / det;\n            }\n            return i;\n        }\n\n        /// <summary>\n        /// This method detects if two line segments (or lines) intersect,\n        /// and, if so, the point of intersection. Use the <paramref name=\"firstIsSegment\" /> and\n        /// <paramref name=\"secondIsSegment\" /> parameters to set whether the intersection point\n        /// must be on the first and second line segments. Setting these\n        /// both to true means you are doing a line-segment to line-segment\n        /// intersection. Setting one of them to true means you are doing a\n        /// line to line-segment intersection test, and so on.\n        /// Note: If two line segments are coincident, then\n        /// no intersection is detected (there are actually\n        /// infinite intersection points).\n        /// Author: Jeremy Bell\n        /// </summary>\n        /// <param name=\"point1\">The first point of the first line segment.</param>\n        /// <param name=\"point2\">The second point of the first line segment.</param>\n        /// <param name=\"point3\">The first point of the second line segment.</param>\n        /// <param name=\"point4\">The second point of the second line segment.</param>\n        /// <param name=\"point\">\n        /// This is set to the intersection\n        /// point if an intersection is detected.\n        /// </param>\n        /// <param name=\"firstIsSegment\">\n        /// Set this to true to require that the\n        /// intersection point be on the first line segment.\n        /// </param>\n        /// <param name=\"secondIsSegment\">\n        /// Set this to true to require that the\n        /// intersection point be on the second line segment.\n        /// </param>\n        /// <returns>True if an intersection is detected, false otherwise.</returns>\n        public static bool LineIntersect(ref Vector2 point1, ref Vector2 point2, ref Vector2 point3, ref Vector2 point4, bool firstIsSegment, bool secondIsSegment, out Vector2 point)\n        {\n            point = new Vector2();\n\n            // these are reused later.\n            // each lettered sub-calculation is used twice, except\n            // for b and d, which are used 3 times\n            float a = point4.Y - point3.Y;\n            float b = point2.X - point1.X;\n            float c = point4.X - point3.X;\n            float d = point2.Y - point1.Y;\n\n            // denominator to solution of linear system\n            float denom = (a * b) - (c * d);\n\n            // if denominator is 0, then lines are parallel\n            if (!(denom >= -Settings.Epsilon && denom <= Settings.Epsilon))\n            {\n                float e = point1.Y - point3.Y;\n                float f = point1.X - point3.X;\n                float oneOverDenom = 1.0f / denom;\n\n                // numerator of first equation\n                float ua = (c * e) - (a * f);\n                ua *= oneOverDenom;\n\n                // check if intersection point of the two lines is on line segment 1\n                if (!firstIsSegment || ua >= 0.0f && ua <= 1.0f)\n                {\n                    // numerator of second equation\n                    float ub = (b * e) - (d * f);\n                    ub *= oneOverDenom;\n\n                    // check if intersection point of the two lines is on line segment 2\n                    // means the line segments intersect, since we know it is on\n                    // segment 1 as well.\n                    if (!secondIsSegment || ub >= 0.0f && ub <= 1.0f)\n                    {\n                        // check if they are coincident (no collision in this case)\n                        if (ua != 0f || ub != 0f)\n                        {\n                            //There is an intersection\n                            point.X = point1.X + ua * b;\n                            point.Y = point1.Y + ua * d;\n                            return true;\n                        }\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// This method detects if two line segments (or lines) intersect,\n        /// and, if so, the point of intersection. Use the <paramref name=\"firstIsSegment\" /> and\n        /// <paramref name=\"secondIsSegment\" /> parameters to set whether the intersection point\n        /// must be on the first and second line segments. Setting these\n        /// both to true means you are doing a line-segment to line-segment\n        /// intersection. Setting one of them to true means you are doing a\n        /// line to line-segment intersection test, and so on.\n        /// Note: If two line segments are coincident, then\n        /// no intersection is detected (there are actually\n        /// infinite intersection points).\n        /// Author: Jeremy Bell\n        /// </summary>\n        /// <param name=\"point1\">The first point of the first line segment.</param>\n        /// <param name=\"point2\">The second point of the first line segment.</param>\n        /// <param name=\"point3\">The first point of the second line segment.</param>\n        /// <param name=\"point4\">The second point of the second line segment.</param>\n        /// <param name=\"intersectionPoint\">\n        /// This is set to the intersection\n        /// point if an intersection is detected.\n        /// </param>\n        /// <param name=\"firstIsSegment\">\n        /// Set this to true to require that the\n        /// intersection point be on the first line segment.\n        /// </param>\n        /// <param name=\"secondIsSegment\">\n        /// Set this to true to require that the\n        /// intersection point be on the second line segment.\n        /// </param>\n        /// <returns>True if an intersection is detected, false otherwise.</returns>\n        public static bool LineIntersect(Vector2 point1, Vector2 point2, Vector2 point3, Vector2 point4, bool firstIsSegment, bool secondIsSegment, out Vector2 intersectionPoint)\n        {\n            return LineIntersect(ref point1, ref point2, ref point3, ref point4, firstIsSegment, secondIsSegment, out intersectionPoint);\n        }\n\n        /// <summary>\n        /// This method detects if two line segments intersect,\n        /// and, if so, the point of intersection.\n        /// Note: If two line segments are coincident, then\n        /// no intersection is detected (there are actually\n        /// infinite intersection points).\n        /// </summary>\n        /// <param name=\"point1\">The first point of the first line segment.</param>\n        /// <param name=\"point2\">The second point of the first line segment.</param>\n        /// <param name=\"point3\">The first point of the second line segment.</param>\n        /// <param name=\"point4\">The second point of the second line segment.</param>\n        /// <param name=\"intersectionPoint\">\n        /// This is set to the intersection\n        /// point if an intersection is detected.\n        /// </param>\n        /// <returns>True if an intersection is detected, false otherwise.</returns>\n        public static bool LineIntersect(ref Vector2 point1, ref Vector2 point2, ref Vector2 point3, ref Vector2 point4, out Vector2 intersectionPoint)\n        {\n            return LineIntersect(ref point1, ref point2, ref point3, ref point4, true, true, out intersectionPoint);\n        }\n\n        /// <summary>\n        /// This method detects if two line segments intersect,\n        /// and, if so, the point of intersection.\n        /// Note: If two line segments are coincident, then\n        /// no intersection is detected (there are actually\n        /// infinite intersection points).\n        /// </summary>\n        /// <param name=\"point1\">The first point of the first line segment.</param>\n        /// <param name=\"point2\">The second point of the first line segment.</param>\n        /// <param name=\"point3\">The first point of the second line segment.</param>\n        /// <param name=\"point4\">The second point of the second line segment.</param>\n        /// <param name=\"intersectionPoint\">\n        /// This is set to the intersection\n        /// point if an intersection is detected.\n        /// </param>\n        /// <returns>True if an intersection is detected, false otherwise.</returns>\n        public static bool LineIntersect(Vector2 point1, Vector2 point2, Vector2 point3, Vector2 point4, out Vector2 intersectionPoint)\n        {\n            return LineIntersect(ref point1, ref point2, ref point3, ref point4, true, true, out intersectionPoint);\n        }\n\n        /// <summary>\n        /// Get all intersections between a line segment and a list of vertices\n        /// representing a polygon. The vertices reuse adjacent points, so for example\n        /// edges one and two are between the first and second vertices and between the\n        /// second and third vertices. The last edge is between vertex vertices.Count - 1\n        /// and verts0. (ie, vertices from a Geometry or AABB)\n        /// </summary>\n        /// <param name=\"point1\">The first point of the line segment to test</param>\n        /// <param name=\"point2\">The second point of the line segment to test.</param>\n        /// <param name=\"vertices\">The vertices, as described above</param>\n        public static Vertices LineSegmentVerticesIntersect(ref Vector2 point1, ref Vector2 point2, Vertices vertices)\n        {\n            Vertices intersectionPoints = new Vertices();\n\n            for (int i = 0; i < vertices.Count; i++)\n            {\n                Vector2 point;\n                if (LineIntersect(vertices[i], vertices[vertices.NextIndex(i)], point1, point2, true, true, out point))\n                {\n                    intersectionPoints.Add(point);\n                }\n            }\n\n            return intersectionPoints;\n        }\n\n        /// <summary>\n        /// Get all intersections between a line segment and an AABB.\n        /// </summary>\n        /// <param name=\"point1\">The first point of the line segment to test</param>\n        /// <param name=\"point2\">The second point of the line segment to test.</param>\n        /// <param name=\"aabb\">The AABB that is used for testing intersection.</param>\n        public static Vertices LineSegmentAABBIntersect(ref Vector2 point1, ref Vector2 point2, AABB aabb)\n        {\n            return LineSegmentVerticesIntersect(ref point1, ref point2, aabb.Vertices);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Utilities/MathUtils.cs",
    "content": "﻿/*\n* Velcro Physics:\n* Copyright (c) 2017 Ian Qvist\n* \n* Original source Box2D:\n* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org \n* \n* This software is provided 'as-is', without any express or implied \n* warranty.  In no event will the authors be held liable for any damages \n* arising from the use of this software. \n* Permission is granted to anyone to use this software for any purpose, \n* including commercial applications, and to alter it and redistribute it \n* freely, subject to the following restrictions: \n* 1. The origin of this software must not be misrepresented; you must not \n* claim that you wrote the original software. If you use this software \n* in a product, an acknowledgment in the product documentation would be \n* appreciated but is not required. \n* 2. Altered source versions must be plainly marked as such, and must not be \n* misrepresented as being the original software. \n* 3. This notice may not be removed or altered from any source distribution. \n*/\n\nusing System;\nusing System.Runtime.InteropServices;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\n\nnamespace VelcroPhysics.Utilities\n{\n    public static class MathUtils\n    {\n        public static float Cross(ref Vector2 a, ref Vector2 b)\n        {\n            return a.X * b.Y - a.Y * b.X;\n        }\n\n        public static float Cross(Vector2 a, Vector2 b)\n        {\n            return Cross(ref a, ref b);\n        }\n\n        /// Perform the cross product on two vectors.\n        public static Vector3 Cross(Vector3 a, Vector3 b)\n        {\n            return new Vector3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);\n        }\n\n        public static Vector2 Cross(Vector2 a, float s)\n        {\n            return new Vector2(s * a.Y, -s * a.X);\n        }\n\n        public static Vector2 Cross(float s, Vector2 a)\n        {\n            return new Vector2(-s * a.Y, s * a.X);\n        }\n\n        public static Vector2 Abs(Vector2 v)\n        {\n            return new Vector2(Math.Abs(v.X), Math.Abs(v.Y));\n        }\n\n        public static Vector2 Mul(ref Mat22 A, Vector2 v)\n        {\n            return Mul(ref A, ref v);\n        }\n\n        public static Vector2 Mul(ref Mat22 A, ref Vector2 v)\n        {\n            return new Vector2(A.ex.X * v.X + A.ey.X * v.Y, A.ex.Y * v.X + A.ey.Y * v.Y);\n        }\n\n        public static Vector2 Mul(ref Transform T, Vector2 v)\n        {\n            return Mul(ref T, ref v);\n        }\n\n        public static Vector2 Mul(ref Transform T, ref Vector2 v)\n        {\n            float x = (T.q.c * v.X - T.q.s * v.Y) + T.p.X;\n            float y = (T.q.s * v.X + T.q.c * v.Y) + T.p.Y;\n\n            return new Vector2(x, y);\n        }\n\n        public static Vector2 MulT(ref Mat22 A, Vector2 v)\n        {\n            return MulT(ref A, ref v);\n        }\n\n        public static Vector2 MulT(ref Mat22 A, ref Vector2 v)\n        {\n            return new Vector2(v.X * A.ex.X + v.Y * A.ex.Y, v.X * A.ey.X + v.Y * A.ey.Y);\n        }\n\n        public static Vector2 MulT(ref Transform T, Vector2 v)\n        {\n            return MulT(ref T, ref v);\n        }\n\n        public static Vector2 MulT(ref Transform T, ref Vector2 v)\n        {\n            float px = v.X - T.p.X;\n            float py = v.Y - T.p.Y;\n            float x = (T.q.c * px + T.q.s * py);\n            float y = (-T.q.s * px + T.q.c * py);\n\n            return new Vector2(x, y);\n        }\n\n        // A^T * B\n        public static void MulT(ref Mat22 A, ref Mat22 B, out Mat22 C)\n        {\n            C = new Mat22();\n            C.ex.X = A.ex.X * B.ex.X + A.ex.Y * B.ex.Y;\n            C.ex.Y = A.ey.X * B.ex.X + A.ey.Y * B.ex.Y;\n            C.ey.X = A.ex.X * B.ey.X + A.ex.Y * B.ey.Y;\n            C.ey.Y = A.ey.X * B.ey.X + A.ey.Y * B.ey.Y;\n        }\n\n        /// Multiply a matrix times a vector.\n        public static Vector3 Mul(Mat33 A, Vector3 v)\n        {\n            return v.X * A.ex + v.Y * A.ey + v.Z * A.ez;\n        }\n\n        // v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p\n        //    = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p\n        public static Transform Mul(Transform A, Transform B)\n        {\n            Transform C = new Transform();\n            C.q = Mul(A.q, B.q);\n            C.p = Mul(A.q, B.p) + A.p;\n            return C;\n        }\n\n        // v2 = A.q' * (B.q * v1 + B.p - A.p)\n        //    = A.q' * B.q * v1 + A.q' * (B.p - A.p)\n        public static void MulT(ref Transform A, ref Transform B, out Transform C)\n        {\n            C = new Transform();\n            C.q = MulT(A.q, B.q);\n            C.p = MulT(A.q, B.p - A.p);\n        }\n\n        public static void Swap<T>(ref T a, ref T b)\n        {\n            T tmp = a;\n            a = b;\n            b = tmp;\n        }\n\n        /// Multiply a matrix times a vector.\n        public static Vector2 Mul22(Mat33 A, Vector2 v)\n        {\n            return new Vector2(A.ex.X * v.X + A.ey.X * v.Y, A.ex.Y * v.X + A.ey.Y * v.Y);\n        }\n\n        /// Multiply two rotations: q * r\n        public static Rot Mul(Rot q, Rot r)\n        {\n            // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]\n            // [qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]\n            // s = qs * rc + qc * rs\n            // c = qc * rc - qs * rs\n            Rot qr;\n            qr.s = q.s * r.c + q.c * r.s;\n            qr.c = q.c * r.c - q.s * r.s;\n            return qr;\n        }\n\n        public static Vector2 MulT(Transform T, Vector2 v)\n        {\n            float px = v.X - T.p.X;\n            float py = v.Y - T.p.Y;\n            float x = (T.q.c * px + T.q.s * py);\n            float y = (-T.q.s * px + T.q.c * py);\n\n            return new Vector2(x, y);\n        }\n\n        /// Transpose multiply two rotations: qT * r\n        public static Rot MulT(Rot q, Rot r)\n        {\n            // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]\n            // [-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]\n            // s = qc * rs - qs * rc\n            // c = qc * rc + qs * rs\n            Rot qr;\n            qr.s = q.c * r.s - q.s * r.c;\n            qr.c = q.c * r.c + q.s * r.s;\n            return qr;\n        }\n\n        // v2 = A.q' * (B.q * v1 + B.p - A.p)\n        //    = A.q' * B.q * v1 + A.q' * (B.p - A.p)\n        public static Transform MulT(Transform A, Transform B)\n        {\n            Transform C = new Transform();\n            C.q = MulT(A.q, B.q);\n            C.p = MulT(A.q, B.p - A.p);\n            return C;\n        }\n\n        /// Rotate a vector\n        public static Vector2 Mul(Rot q, Vector2 v)\n        {\n            return new Vector2(q.c * v.X - q.s * v.Y, q.s * v.X + q.c * v.Y);\n        }\n\n        /// Inverse rotate a vector\n        public static Vector2 MulT(Rot q, Vector2 v)\n        {\n            return new Vector2(q.c * v.X + q.s * v.Y, -q.s * v.X + q.c * v.Y);\n        }\n\n        /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)\n        public static Vector2 Skew(Vector2 input)\n        {\n            return new Vector2(-input.Y, input.X);\n        }\n\n        /// <summary>\n        /// This function is used to ensure that a floating point number is\n        /// not a NaN or infinity.\n        /// </summary>\n        /// <param name=\"x\">The x.</param>\n        /// <returns>\n        /// <c>true</c> if the specified x is valid; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsValid(float x)\n        {\n            if (float.IsNaN(x))\n            {\n                // NaN.\n                return false;\n            }\n\n            return !float.IsInfinity(x);\n        }\n\n        public static bool IsValid(this Vector2 x)\n        {\n            return IsValid(x.X) && IsValid(x.Y);\n        }\n\n        /// <summary>\n        /// This is a approximate yet fast inverse square-root.\n        /// </summary>\n        /// <param name=\"x\">The x.</param>\n        /// <returns></returns>\n        public static float InvSqrt(float x)\n        {\n            FloatConverter convert = new FloatConverter();\n            convert.x = x;\n            float xhalf = 0.5f * x;\n            convert.i = 0x5f3759df - (convert.i >> 1);\n            x = convert.x;\n            x = x * (1.5f - xhalf * x * x);\n            return x;\n        }\n\n        public static int Clamp(int a, int low, int high)\n        {\n            return Math.Max(low, Math.Min(a, high));\n        }\n\n        public static float Clamp(float a, float low, float high)\n        {\n            return Math.Max(low, Math.Min(a, high));\n        }\n\n        public static Vector2 Clamp(Vector2 a, Vector2 low, Vector2 high)\n        {\n            return Vector2.Max(low, Vector2.Min(a, high));\n        }\n\n        public static void Cross(ref Vector2 a, ref Vector2 b, out float c)\n        {\n            c = a.X * b.Y - a.Y * b.X;\n        }\n\n        /// <summary>\n        /// Return the angle between two vectors on a plane\n        /// The angle is from vector 1 to vector 2, positive anticlockwise\n        /// The result is between -pi -> pi\n        /// </summary>\n        public static double VectorAngle(ref Vector2 p1, ref Vector2 p2)\n        {\n            double theta1 = Math.Atan2(p1.Y, p1.X);\n            double theta2 = Math.Atan2(p2.Y, p2.X);\n            double dtheta = theta2 - theta1;\n            while (dtheta > Math.PI)\n                dtheta -= (2 * Math.PI);\n            while (dtheta < -Math.PI)\n                dtheta += (2 * Math.PI);\n\n            return (dtheta);\n        }\n\n        /// Perform the dot product on two vectors.\n        public static float Dot(Vector3 a, Vector3 b)\n        {\n            return a.X * b.X + a.Y * b.Y + a.Z * b.Z;\n        }\n\n        public static double VectorAngle(Vector2 p1, Vector2 p2)\n        {\n            return VectorAngle(ref p1, ref p2);\n        }\n\n        /// <summary>\n        /// Returns a positive number if c is to the left of the line going from a to b.\n        /// </summary>\n        /// <returns>\n        /// Positive number if point is left, negative if point is right,\n        /// and 0 if points are collinear.\n        /// </returns>\n        public static float Area(Vector2 a, Vector2 b, Vector2 c)\n        {\n            return Area(ref a, ref b, ref c);\n        }\n\n        /// <summary>\n        /// Returns a positive number if c is to the left of the line going from a to b.\n        /// </summary>\n        /// <returns>\n        /// Positive number if point is left, negative if point is right,\n        /// and 0 if points are collinear.\n        /// </returns>\n        public static float Area(ref Vector2 a, ref Vector2 b, ref Vector2 c)\n        {\n            return a.X * (b.Y - c.Y) + b.X * (c.Y - a.Y) + c.X * (a.Y - b.Y);\n        }\n\n        /// <summary>\n        /// Determines if three vertices are collinear (ie. on a straight line)\n        /// </summary>\n        /// <param name=\"a\">First vertex</param>\n        /// <param name=\"b\">Second vertex</param>\n        /// <param name=\"c\">Third vertex</param>\n        /// <param name=\"tolerance\">The tolerance</param>\n        /// <returns></returns>\n        public static bool IsCollinear(ref Vector2 a, ref Vector2 b, ref Vector2 c, float tolerance = 0)\n        {\n            return FloatInRange(Area(ref a, ref b, ref c), -tolerance, tolerance);\n        }\n\n        public static void Cross(float s, ref Vector2 a, out Vector2 b)\n        {\n            b = new Vector2(-s * a.Y, s * a.X);\n        }\n\n        public static bool FloatEquals(float value1, float value2)\n        {\n            return Math.Abs(value1 - value2) <= Settings.Epsilon;\n        }\n\n        /// <summary>\n        /// Checks if a floating point Value is equal to another,\n        /// within a certain tolerance.\n        /// </summary>\n        /// <param name=\"value1\">The first floating point Value.</param>\n        /// <param name=\"value2\">The second floating point Value.</param>\n        /// <param name=\"delta\">The floating point tolerance.</param>\n        /// <returns>True if the values are \"equal\", false otherwise.</returns>\n        public static bool FloatEquals(float value1, float value2, float delta)\n        {\n            return FloatInRange(value1, value2 - delta, value2 + delta);\n        }\n\n        /// <summary>\n        /// Checks if a floating point Value is within a specified\n        /// range of values (inclusive).\n        /// </summary>\n        /// <param name=\"value\">The Value to check.</param>\n        /// <param name=\"min\">The minimum Value.</param>\n        /// <param name=\"max\">The maximum Value.</param>\n        /// <returns>\n        /// True if the Value is within the range specified,\n        /// false otherwise.\n        /// </returns>\n        public static bool FloatInRange(float value, float min, float max)\n        {\n            return (value >= min && value <= max);\n        }\n\n        public static Vector2 Mul(ref Rot rot, Vector2 axis)\n        {\n            return Mul(rot, axis);\n        }\n\n        public static Vector2 MulT(ref Rot rot, Vector2 axis)\n        {\n            return MulT(rot, axis);\n        }\n\n        #region Nested type: FloatConverter\n\n        [StructLayout(LayoutKind.Explicit)]\n        private struct FloatConverter\n        {\n            [FieldOffset(0)]\n            public float x;\n\n            [FieldOffset(0)]\n            public int i;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VelcroPhysics/Utilities/PolygonUtils.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Microsoft.Xna.Framework;\nusing VelcroPhysics.Shared;\nusing VelcroPhysics.Tools.TextureTools;\n\nnamespace VelcroPhysics.Utilities\n{\n    public static class PolygonUtils\n    {\n        /// <summary>\n        /// Build vertices to represent an axis-aligned box.\n        /// </summary>\n        /// <param name=\"hx\">the half-width.</param>\n        /// <param name=\"hy\">the half-height.</param>\n        public static Vertices CreateRectangle(float hx, float hy)\n        {\n            Vertices vertices = new Vertices(4);\n            vertices.Add(new Vector2(-hx, -hy));\n            vertices.Add(new Vector2(hx, -hy));\n            vertices.Add(new Vector2(hx, hy));\n            vertices.Add(new Vector2(-hx, hy));\n\n            return vertices;\n        }\n\n        /// <summary>\n        /// Build vertices to represent an oriented box.\n        /// </summary>\n        /// <param name=\"hx\">the half-width.</param>\n        /// <param name=\"hy\">the half-height.</param>\n        /// <param name=\"center\">the center of the box in local coordinates.</param>\n        /// <param name=\"angle\">the rotation of the box in local coordinates.</param>\n        public static Vertices CreateRectangle(float hx, float hy, Vector2 center, float angle)\n        {\n            Vertices vertices = CreateRectangle(hx, hy);\n\n            Transform xf = new Transform();\n            xf.p = center;\n            xf.q.Set(angle);\n\n            // Transform vertices\n            for (int i = 0; i < 4; ++i)\n            {\n                vertices[i] = MathUtils.Mul(ref xf, vertices[i]);\n            }\n\n            return vertices;\n        }\n\n        //Rounded rectangle contributed by Jonathan Smars - jsmars@gmail.com\n\n        /// <summary>\n        /// Creates a rounded rectangle with the specified width and height.\n        /// </summary>\n        /// <param name=\"width\">The width.</param>\n        /// <param name=\"height\">The height.</param>\n        /// <param name=\"xRadius\">The rounding X radius.</param>\n        /// <param name=\"yRadius\">The rounding Y radius.</param>\n        /// <param name=\"segments\">The number of segments to subdivide the edges.</param>\n        /// <returns></returns>\n        public static Vertices CreateRoundedRectangle(float width, float height, float xRadius, float yRadius,\n                                                      int segments)\n        {\n            if (yRadius > height / 2 || xRadius > width / 2)\n                throw new Exception(\"Rounding amount can't be more than half the height and width respectively.\");\n            if (segments < 0)\n                throw new Exception(\"Segments must be zero or more.\");\n\n            //TODO: TBM\n            //We need at least 8 vertices to create a rounded rectangle\n            //Debug.Assert(Settings.MaxPolygonVertices >= 8);\n\n            Vertices vertices = new Vertices();\n            if (segments == 0)\n            {\n                vertices.Add(new Vector2(width * .5f - xRadius, -height * .5f));\n                vertices.Add(new Vector2(width * .5f, -height * .5f + yRadius));\n\n                vertices.Add(new Vector2(width * .5f, height * .5f - yRadius));\n                vertices.Add(new Vector2(width * .5f - xRadius, height * .5f));\n\n                vertices.Add(new Vector2(-width * .5f + xRadius, height * .5f));\n                vertices.Add(new Vector2(-width * .5f, height * .5f - yRadius));\n\n                vertices.Add(new Vector2(-width * .5f, -height * .5f + yRadius));\n                vertices.Add(new Vector2(-width * .5f + xRadius, -height * .5f));\n            }\n            else\n            {\n                int numberOfEdges = (segments * 4 + 8);\n\n                float stepSize = MathHelper.TwoPi / (numberOfEdges - 4);\n                int perPhase = numberOfEdges / 4;\n\n                Vector2 posOffset = new Vector2(width / 2 - xRadius, height / 2 - yRadius);\n                vertices.Add(posOffset + new Vector2(xRadius, -yRadius + yRadius));\n                short phase = 0;\n                for (int i = 1; i < numberOfEdges; i++)\n                {\n                    if (i - perPhase == 0 || i - perPhase * 3 == 0)\n                    {\n                        posOffset.X *= -1;\n                        phase--;\n                    }\n                    else if (i - perPhase * 2 == 0)\n                    {\n                        posOffset.Y *= -1;\n                        phase--;\n                    }\n\n                    vertices.Add(posOffset + new Vector2(xRadius * (float)Math.Cos(stepSize * -(i + phase)),\n                                     -yRadius * (float)Math.Sin(stepSize * -(i + phase))));\n                }\n            }\n\n            return vertices;\n        }\n\n        /// <summary>\n        /// Set this as a single edge.\n        /// </summary>\n        /// <param name=\"start\">The first point.</param>\n        /// <param name=\"end\">The second point.</param>\n        public static Vertices CreateLine(Vector2 start, Vector2 end)\n        {\n            Vertices vertices = new Vertices(2);\n            vertices.Add(start);\n            vertices.Add(end);\n\n            return vertices;\n        }\n\n        /// <summary>\n        /// Creates a circle with the specified radius and number of edges.\n        /// </summary>\n        /// <param name=\"radius\">The radius.</param>\n        /// <param name=\"numberOfEdges\">The number of edges. The more edges, the more it resembles a circle</param>\n        /// <returns></returns>\n        public static Vertices CreateCircle(float radius, int numberOfEdges)\n        {\n            return CreateEllipse(radius, radius, numberOfEdges);\n        }\n\n        /// <summary>\n        /// Creates a ellipse with the specified width, height and number of edges.\n        /// </summary>\n        /// <param name=\"xRadius\">Width of the ellipse.</param>\n        /// <param name=\"yRadius\">Height of the ellipse.</param>\n        /// <param name=\"numberOfEdges\">The number of edges. The more edges, the more it resembles an ellipse</param>\n        /// <returns></returns>\n        public static Vertices CreateEllipse(float xRadius, float yRadius, int numberOfEdges)\n        {\n            Vertices vertices = new Vertices();\n\n            float stepSize = MathHelper.TwoPi / numberOfEdges;\n\n            vertices.Add(new Vector2(xRadius, 0));\n            for (int i = numberOfEdges - 1; i > 0; --i)\n                vertices.Add(new Vector2(xRadius * (float)Math.Cos(stepSize * i),\n                    -yRadius * (float)Math.Sin(stepSize * i)));\n\n            return vertices;\n        }\n\n        public static Vertices CreateArc(float radians, int sides, float radius)\n        {\n            Debug.Assert(radians > 0, \"The arc needs to be larger than 0\");\n            Debug.Assert(sides > 1, \"The arc needs to have more than 1 sides\");\n            Debug.Assert(radius > 0, \"The arc needs to have a radius larger than 0\");\n\n            Vertices vertices = new Vertices();\n\n            float stepSize = radians / sides;\n            for (int i = sides - 1; i > 0; i--)\n            {\n                vertices.Add(new Vector2(radius * (float)Math.Cos(stepSize * i),\n                    radius * (float)Math.Sin(stepSize * i)));\n            }\n\n            return vertices;\n        }\n\n        //Capsule contributed by Yobiv\n\n        /// <summary>\n        /// Creates an capsule with the specified height, radius and number of edges.\n        /// A capsule has the same form as a pill capsule.\n        /// </summary>\n        /// <param name=\"height\">Height (inner height + 2 * radius) of the capsule.</param>\n        /// <param name=\"endRadius\">Radius of the capsule ends.</param>\n        /// <param name=\"edges\">The number of edges of the capsule ends. The more edges, the more it resembles an capsule</param>\n        /// <returns></returns>\n        public static Vertices CreateCapsule(float height, float endRadius, int edges)\n        {\n            if (endRadius >= height / 2)\n                throw new ArgumentException(\n                    \"The radius must be lower than height / 2. Higher values of radius would create a circle, and not a half circle.\",\n                    nameof(endRadius));\n\n            return CreateCapsule(height, endRadius, edges, endRadius, edges);\n        }\n\n        /// <summary>\n        /// Creates an capsule with the specified  height, radius and number of edges.\n        /// A capsule has the same form as a pill capsule.\n        /// </summary>\n        /// <param name=\"height\">Height (inner height + radii) of the capsule.</param>\n        /// <param name=\"topRadius\">Radius of the top.</param>\n        /// <param name=\"topEdges\">The number of edges of the top. The more edges, the more it resembles an capsule</param>\n        /// <param name=\"bottomRadius\">Radius of bottom.</param>\n        /// <param name=\"bottomEdges\">The number of edges of the bottom. The more edges, the more it resembles an capsule</param>\n        /// <returns></returns>\n        public static Vertices CreateCapsule(float height, float topRadius, int topEdges, float bottomRadius,\n                                             int bottomEdges)\n        {\n            if (height <= 0)\n                throw new ArgumentException(\"Height must be longer than 0\", nameof(height));\n\n            if (topRadius <= 0)\n                throw new ArgumentException(\"The top radius must be more than 0\", nameof(topRadius));\n\n            if (topEdges <= 0)\n                throw new ArgumentException(\"Top edges must be more than 0\", nameof(topEdges));\n\n            if (bottomRadius <= 0)\n                throw new ArgumentException(\"The bottom radius must be more than 0\", nameof(bottomRadius));\n\n            if (bottomEdges <= 0)\n                throw new ArgumentException(\"Bottom edges must be more than 0\", nameof(bottomEdges));\n\n            if (topRadius >= height / 2)\n                throw new ArgumentException(\n                    \"The top radius must be lower than height / 2. Higher values of top radius would create a circle, and not a half circle.\",\n                    nameof(topRadius));\n\n            if (bottomRadius >= height / 2)\n                throw new ArgumentException(\n                    \"The bottom radius must be lower than height / 2. Higher values of bottom radius would create a circle, and not a half circle.\",\n                    nameof(bottomRadius));\n\n            Vertices vertices = new Vertices();\n\n            float newHeight = (height - topRadius - bottomRadius) * 0.5f;\n\n            // top\n            vertices.Add(new Vector2(topRadius, newHeight));\n\n            float stepSize = MathHelper.Pi / topEdges;\n            for (int i = 1; i < topEdges; i++)\n            {\n                vertices.Add(new Vector2(topRadius * (float)Math.Cos(stepSize * i),\n                    topRadius * (float)Math.Sin(stepSize * i) + newHeight));\n            }\n\n            vertices.Add(new Vector2(-topRadius, newHeight));\n\n            // bottom\n            vertices.Add(new Vector2(-bottomRadius, -newHeight));\n\n            stepSize = MathHelper.Pi / bottomEdges;\n            for (int i = 1; i < bottomEdges; i++)\n            {\n                vertices.Add(new Vector2(-bottomRadius * (float)Math.Cos(stepSize * i),\n                    -bottomRadius * (float)Math.Sin(stepSize * i) - newHeight));\n            }\n\n            vertices.Add(new Vector2(bottomRadius, -newHeight));\n\n            return vertices;\n        }\n\n        /// <summary>\n        /// Creates a gear shape with the specified radius and number of teeth.\n        /// </summary>\n        /// <param name=\"radius\">The radius.</param>\n        /// <param name=\"numberOfTeeth\">The number of teeth.</param>\n        /// <param name=\"tipPercentage\">The tip percentage.</param>\n        /// <param name=\"toothHeight\">Height of the tooth.</param>\n        /// <returns></returns>\n        public static Vertices CreateGear(float radius, int numberOfTeeth, float tipPercentage, float toothHeight)\n        {\n            Vertices vertices = new Vertices();\n\n            float stepSize = MathHelper.TwoPi / numberOfTeeth;\n            tipPercentage /= 100f;\n            MathHelper.Clamp(tipPercentage, 0f, 1f);\n            float toothTipStepSize = (stepSize / 2f) * tipPercentage;\n\n            float toothAngleStepSize = (stepSize - (toothTipStepSize * 2f)) / 2f;\n\n            for (int i = numberOfTeeth - 1; i >= 0; --i)\n            {\n                if (toothTipStepSize > 0f)\n                {\n                    vertices.Add(\n                        new Vector2(radius *\n                                    (float)Math.Cos(stepSize * i + toothAngleStepSize * 2f + toothTipStepSize),\n                            -radius *\n                            (float)Math.Sin(stepSize * i + toothAngleStepSize * 2f + toothTipStepSize)));\n\n                    vertices.Add(\n                        new Vector2((radius + toothHeight) *\n                                    (float)Math.Cos(stepSize * i + toothAngleStepSize + toothTipStepSize),\n                            -(radius + toothHeight) *\n                            (float)Math.Sin(stepSize * i + toothAngleStepSize + toothTipStepSize)));\n                }\n\n                vertices.Add(new Vector2((radius + toothHeight) *\n                                         (float)Math.Cos(stepSize * i + toothAngleStepSize),\n                    -(radius + toothHeight) *\n                    (float)Math.Sin(stepSize * i + toothAngleStepSize)));\n\n                vertices.Add(new Vector2(radius * (float)Math.Cos(stepSize * i),\n                    -radius * (float)Math.Sin(stepSize * i)));\n            }\n\n            return vertices;\n        }\n\n        /// <summary>\n        /// Detects the vertices by analyzing the texture data.\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <returns></returns>\n        public static Vertices CreatePolygon(uint[] data, int width)\n        {\n            return TextureConverter.DetectVertices(data, width);\n        }\n\n        /// <summary>\n        /// Detects the vertices by analyzing the texture data.\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <param name=\"holeDetection\">if set to <c>true</c> it will perform hole detection.</param>\n        /// <returns></returns>\n        public static Vertices CreatePolygon(uint[] data, int width, bool holeDetection)\n        {\n            return TextureConverter.DetectVertices(data, width, holeDetection);\n        }\n\n        /// <summary>\n        /// Detects the vertices by analyzing the texture data.\n        /// </summary>\n        /// <param name=\"data\">The texture data.</param>\n        /// <param name=\"width\">The texture width.</param>\n        /// <param name=\"hullTolerance\">The hull tolerance.</param>\n        /// <param name=\"alphaTolerance\">The alpha tolerance.</param>\n        /// <param name=\"multiPartDetection\">if set to <c>true</c> it will perform multi part detection.</param>\n        /// <param name=\"holeDetection\">if set to <c>true</c> it will perform hole detection.</param>\n        /// <returns></returns>\n        public static List<Vertices> CreatePolygon(uint[] data, int width, float hullTolerance,\n                                                   byte alphaTolerance, bool multiPartDetection, bool holeDetection)\n        {\n            return TextureConverter.DetectVertices(data, width, hullTolerance, alphaTolerance,\n                multiPartDetection, holeDetection);\n        }\n    }\n}"
  },
  {
    "path": "VelcroPhysics/VelcroPhysics.MonoGame.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <RootNamespace>VelcroPhysics</RootNamespace>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DefineConstants>TRACE;DEBUG;MONOGAME</DefineConstants>\n    <PlatformTarget>x64</PlatformTarget>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <DefineConstants>TRACE;RELEASE;MONOGAME</DefineConstants>\n    <PlatformTarget>x64</PlatformTarget>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"Tools\\Curve.cs\" />\n    <Compile Remove=\"Tools\\CurveKey.cs\" />\n    <Compile Remove=\"Tools\\CurveKeyCollection.cs\" />\n    <Compile Remove=\"Tools\\HashSet.cs\" />\n    <Compile Remove=\"Tools\\MathHelper.cs\" />\n    <Compile Remove=\"Tools\\Matrix.cs\" />\n    <Compile Remove=\"Tools\\Stopwatch.cs\" />\n    <Compile Remove=\"Tools\\Vector2.cs\" />\n    <Compile Remove=\"Tools\\Vector3.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MonoGame.Framework.Content.Pipeline.Portable\" Version=\"3.7.1.189\" />\n    <PackageReference Include=\"MonoGame.Framework.Portable\" Version=\"3.7.1.189\" />\n    <PackageReference Include=\"System.Collections\" Version=\"4.3.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Reference Include=\"netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51\">\n      <HintPath>..\\..\\..\\..\\usr\\lib\\mono\\4.5\\Facades\\netstandard.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "VelcroPhysics/VelcroPhysics.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netstandard1.4</TargetFrameworks>\n    <Authors>Ian Qvist</Authors>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <DefineConstants>TRACE;DEBUG;NETSTANDARD1_3</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Xml.XmlSerializer\" Version=\"4.3.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "VelcroPhysics/packages.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n    <package id=\"System.Xml.XmlSerializer\" version=\"4.3.0\" targetFramework=\"net471\" />\n    <package id=\"MonoGame.Framework.Content.Pipeline.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n    <package id=\"MonoGame.Framework.Portable\" version=\"3.7.1.189\" targetFramework=\"net471\" />\n</packages>"
  },
  {
    "path": "changes.md",
    "content": "* Reworked the whole projectile system\n* Blue bullet slime doesn't shoot after death anymore\n* Dino is a bit more angry now\n* Halo buffed\n* Projectile light/poof effects wont work after there are 99 projectiles in game\n* Mob projectiles are capped at 199\n* Removed Tags.Torch => Tags.MobProjectile\n* Removed Tags.Gramaphone => Tags.PlayerProjectile \n* Projectiles wont be able to hit mobs/paintings/tnt in rooms that there are no players in\n* All projectiles will die after some time now\n* The game will give up trying to process past time if it is more than 0.25 of a second\n* If player has more than 69 projectiles old projectiles will start to break\n* Improved missile\n* Added bounce cap of 8\n* Killing shopkeeper gives you 3 scoure points now\n* Boss bullets will become scourged on 1st loop\n* Enemy bullets will become scourged on 2nd loop\n* Shopkeeper mood wont change if you are not in his room\n* Added \"always cook second\" to the loading screen jokes\n* Death/win screen will now have a note if the run was seeded\n* The player now actually drops all the items he collected on the run when dying (it was meant to work like that forever but was broken)\n* Some movement speed tweaks\n* Player sprite is now tilted slightly while moving\n* Ctrl+V works on beetroot now\n* Click to place bombs with bomb lamp\n* Removed aura from not reflectable projectiles\n* Added battery sfx\n* Fixed black bars not resizing (aka ui target not updating its size)\n* Mobs killed with explosive lamp will drop bombs on death\n* Unhitatble creatures wont get buffs from projectiles\n* Hopefully fixed ice level bug (rude but still)\n* Improved minimap\n* Bumped steamworks version\n* Upgraded monogame\n* Fixed weird rendering issues by flooring all rendering positions\n* Menu won't react to all keys/mouse buttons now\n* Old man will now greet you upon entering the game\n* Camera in menu wont follow the cursor anymore\n* level command now accepts second number for the loop\n* Changed how seeds work (internally), sadly probably breaks all old seeds\n* Changed how level saving works: loop levels are now stored separately instead of overwriting old files\n* Changed how scourged projectiles look\n* Flies wont deal contact damage anymore\n* Decreased room reward chance\n* Enemies in snow castle and ice ruins will now be cold immune\n* Exploding bees wont explode from melee/explosion kills\n* Ice queen hp buffed from 500 to 550\n* Queen bees projectiles wont be reflectable in 3rd phase anymore (same for the ice queen)\n* Buffed cupguy by a lot\n* Buffed post-first area wall crawler\n* Buffed maggot\n* Player hitbox is now smaller\n* New gang painting\n* Dialog options are now instant-printed, improved ui dialog in general\n* Nerfed pharaoh 300 => 250\n* Shells and some other particles will disappear in 5 instead of 10 seconds\n* Changed statues voice\n* Ice crawler projectile size buffed\n* Reverted to old map\n* Rave Cave level variant added\n* Nerfed red key attack speed, added 1 damage\n* Fixed permanent item stands missing their pickup sounds\n* Fixed a bunch of brain based softlocks\n* Made gunners/bullet slimes a bit more rare / fat in the desert biome\n* Shops & treasure rooms will now appear in emerald caves\n* Melee arcs will not be affected by range downs that go below 1\n* Nerfed ghost chase a tiny bit\n* Nerfed amurs arrow\n* Lowered default screenshake\n* Added an extra treasure room to the emerald caves"
  }
]