Repository: egordorichev/BurningKnight Branch: release Commit: 03df92abed1f Files: 1814 Total size: 4.4 MB Directory structure: gitextract_875549rw/ ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── deploy-steam.yml ├── .gitignore ├── Aseprite/ │ ├── Aseprite.csproj │ ├── AsepriteAnimation.cs │ ├── AsepriteFile.cs │ ├── AsepriteImporter.cs │ ├── AsepriteProcessor.cs │ ├── AsepriteReader.cs │ ├── AsepriteWriter.cs │ ├── AudioFile.cs │ ├── AudioImporter.cs │ ├── AudioProcessor.cs │ ├── AudioReader.cs │ ├── AudioWriter.cs │ ├── Calc.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── README.md │ └── packages.config ├── BurningKnight/ │ ├── BK.cs │ ├── BurningKnight.csproj │ ├── Content/ │ │ ├── Animations/ │ │ │ ├── accessory_trader.ase │ │ │ ├── achievements.ase │ │ │ ├── active_trader.ase │ │ │ ├── baby_gobbo.ase │ │ │ ├── baby_slime.ase │ │ │ ├── backpack.ase │ │ │ ├── badosz.ase │ │ │ ├── bandit.ase │ │ │ ├── bee.ase │ │ │ ├── beehive.ase │ │ │ ├── beet.ase │ │ │ ├── belt.ase │ │ │ ├── belt_down.ase │ │ │ ├── belt_up.ase │ │ │ ├── big_slime.ase │ │ │ ├── big_snowball.ase │ │ │ ├── bigbee.ase │ │ │ ├── biome_assets.ase │ │ │ ├── bird.ase │ │ │ ├── bk_orbital.ase │ │ │ ├── blue_bullet_slime.ase │ │ │ ├── book.ase │ │ │ ├── boss_door.ase │ │ │ ├── boxy.ase │ │ │ ├── brastin.ase │ │ │ ├── broco.ase │ │ │ ├── buffed_flower.ase │ │ │ ├── buffer.ase │ │ │ ├── builder.ase │ │ │ ├── bullet_slime.ase │ │ │ ├── button.ase │ │ │ ├── cactus.ase │ │ │ ├── campfire.ase │ │ │ ├── castle_biome.ase │ │ │ ├── cave_biome.ase │ │ │ ├── challenge_door.ase │ │ │ ├── clown.ase │ │ │ ├── copper_coin.ase │ │ │ ├── crab.ase │ │ │ ├── crawler.ase │ │ │ ├── crystal.ase │ │ │ ├── cup_guy.ase │ │ │ ├── dark_mage.ase │ │ │ ├── death_fx.ase │ │ │ ├── demon.ase │ │ │ ├── desert_biome.ase │ │ │ ├── desert_bullet_slime.ase │ │ │ ├── desert_slime.ase │ │ │ ├── dino.ase │ │ │ ├── discord.ase │ │ │ ├── duck.ase │ │ │ ├── dude.ase │ │ │ ├── dummy.ase │ │ │ ├── elon.ase │ │ │ ├── emerald_golem.ase │ │ │ ├── emerald_gunner.ase │ │ │ ├── explobee.ase │ │ │ ├── explosion.ase │ │ │ ├── eye.ase │ │ │ ├── flower.ase │ │ │ ├── fly.ase │ │ │ ├── ghost.ase │ │ │ ├── globbo.ase │ │ │ ├── gobbo.ase │ │ │ ├── gobetta.ase │ │ │ ├── gold_coin.ase │ │ │ ├── grandma.ase │ │ │ ├── gunner.ase │ │ │ ├── half_mana.ase │ │ │ ├── hat_trader.ase │ │ │ ├── head_door.ase │ │ │ ├── heinur.ase │ │ │ ├── hub_biome.ase │ │ │ ├── ice_biome.ase │ │ │ ├── ice_crawler.ase │ │ │ ├── ice_queen.ase │ │ │ ├── iron_coin.ase │ │ │ ├── isaac.ase │ │ │ ├── item_half_heart.ase │ │ │ ├── item_heart.ase │ │ │ ├── items.ase │ │ │ ├── jungle_biome.ase │ │ │ ├── key.ase │ │ │ ├── knight.ase │ │ │ ├── level_lock.ase │ │ │ ├── lever.ase │ │ │ ├── library_biome.ase │ │ │ ├── loading.ase │ │ │ ├── lock.ase │ │ │ ├── logo.ase │ │ │ ├── logobg.ase │ │ │ ├── maanex.ase │ │ │ ├── mage.ase │ │ │ ├── maggot.ase │ │ │ ├── mana.ase │ │ │ ├── mapuzzle.ase │ │ │ ├── marshmallow.ase │ │ │ ├── meat_guy.ase │ │ │ ├── mega_slime.ase │ │ │ ├── mike.ase │ │ │ ├── milt.ase │ │ │ ├── mother_slime.ase │ │ │ ├── moving_platform.ase │ │ │ ├── mummy.ase │ │ │ ├── new_gobbo.ase │ │ │ ├── nullptr.ase │ │ │ ├── nurse.ase │ │ │ ├── old_burning_knight.ase │ │ │ ├── old_gobbo.ase │ │ │ ├── old_king.ase │ │ │ ├── old_man.ase │ │ │ ├── ord.ase │ │ │ ├── paintings.ase │ │ │ ├── particles.ase │ │ │ ├── payed_door.ase │ │ │ ├── pharaoh.ase │ │ │ ├── planks_particle.ase │ │ │ ├── platinum_coin.ase │ │ │ ├── preasure_plate.ase │ │ │ ├── prism.ase │ │ │ ├── projectiles.ase │ │ │ ├── props.ase │ │ │ ├── proto_chest.ase │ │ │ ├── rat.ase │ │ │ ├── regular_door.ase │ │ │ ├── roger.ase │ │ │ ├── rolling_spike.ase │ │ │ ├── scourged_door.ase │ │ │ ├── shield_buddy.ase │ │ │ ├── shooty.ase │ │ │ ├── shop_door.ase │ │ │ ├── shopkeeper.ase │ │ │ ├── side_door.ase │ │ │ ├── skele_buddy.ase │ │ │ ├── skeleton.ase │ │ │ ├── slime.ase │ │ │ ├── small_king.ase │ │ │ ├── snek.ase │ │ │ ├── sniper.ase │ │ │ ├── snowball.ase │ │ │ ├── snowflake.ase │ │ │ ├── snowman.ase │ │ │ ├── snowman_body.ase │ │ │ ├── spelunker.ase │ │ │ ├── spider.ase │ │ │ ├── spiked_cookie.ase │ │ │ ├── spiked_door.ase │ │ │ ├── spikes.ase │ │ │ ├── splash_fx.ase │ │ │ ├── splash_particle.ase │ │ │ ├── sponge.ase │ │ │ ├── spooky_big_slime.ase │ │ │ ├── spooky_biome.ase │ │ │ ├── spooky_slime.ase │ │ │ ├── stepping_platform.ase │ │ │ ├── sword_trail.ase │ │ │ ├── tech_biome.ase │ │ │ ├── thief.ase │ │ │ ├── trash_goblin.ase │ │ │ ├── treasure_door.ase │ │ │ ├── turret.ase │ │ │ ├── twitch.ase │ │ │ ├── twitch_pet.ase │ │ │ ├── ui.ase │ │ │ ├── vampire.ase │ │ │ ├── vertical_shop_door.ase │ │ │ ├── vertical_treasure_door.ase │ │ │ ├── wallet.ase │ │ │ ├── weapon_trader.ase │ │ │ ├── wombat.ase │ │ │ ├── worm.ase │ │ │ └── xmas_biome.ase │ │ ├── Content.mgcb │ │ ├── Dialogs/ │ │ │ ├── accessorytrader.json │ │ │ ├── activetrader.json │ │ │ ├── beet.json │ │ │ ├── bk.json │ │ │ ├── bk_sign.json │ │ │ ├── boxy.json │ │ │ ├── brastin.json │ │ │ ├── builder.json │ │ │ ├── charger.json │ │ │ ├── control.json │ │ │ ├── dialogs.json │ │ │ ├── discord.json │ │ │ ├── dm.json │ │ │ ├── duck.json │ │ │ ├── eg.json │ │ │ ├── elon.json │ │ │ ├── fountain.json │ │ │ ├── gobetta.json │ │ │ ├── granny.json │ │ │ ├── hattrader.json │ │ │ ├── isaac.json │ │ │ ├── maanex.json │ │ │ ├── maanex2.json │ │ │ ├── machine.json │ │ │ ├── mapuzzle.json │ │ │ ├── milt.json │ │ │ ├── mob.json │ │ │ ├── npc.json │ │ │ ├── npc_hurt.json │ │ │ ├── nullptr.json │ │ │ ├── nurse.json │ │ │ ├── old_man.json │ │ │ ├── player.json │ │ │ ├── roger.json │ │ │ ├── shopkeeper.json │ │ │ ├── snek.json │ │ │ ├── tomb.json │ │ │ ├── trash_goblin.json │ │ │ ├── twitch.json │ │ │ ├── vampire.json │ │ │ └── weapontrader.json │ │ ├── Fonts/ │ │ │ ├── fnt.spritefont │ │ │ ├── large.xnb │ │ │ ├── large_font.fnt │ │ │ ├── large_font.xnb │ │ │ ├── small.xnb │ │ │ ├── small_font.fnt │ │ │ └── small_font.xnb │ │ ├── Locales/ │ │ │ ├── by.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── fr.json │ │ │ ├── it.json │ │ │ ├── pl.json │ │ │ ├── pt.json │ │ │ ├── qu.json │ │ │ └── ru.json │ │ ├── Music/ │ │ │ ├── BK.ogg │ │ │ ├── Believer.ogg │ │ │ ├── Born to do rogueries.ogg │ │ │ ├── Botanical Expedition.ogg │ │ │ ├── Cursed legend.ogg │ │ │ ├── Fatiga.ogg │ │ │ ├── Frozen to the bones.ogg │ │ │ ├── Gobbeon.ogg │ │ │ ├── Hidden knowledge.ogg │ │ │ ├── Hub.ogg │ │ │ ├── Last chance.ogg │ │ │ ├── Ma Precious.ogg │ │ │ ├── Menu.ogg │ │ │ ├── My precious.ogg │ │ │ ├── Nostalgia.ogg │ │ │ ├── Outsider.ogg │ │ │ ├── Pirate Bay.ogg │ │ │ ├── Reckless.ogg │ │ │ ├── Serendipity.ogg │ │ │ ├── Shopkeeper.ogg │ │ │ ├── Void.ogg │ │ │ ├── chip.ogg │ │ │ └── piano.ogg │ │ ├── Prefabs/ │ │ │ ├── cutscene_0.lvl │ │ │ ├── granny.lvl │ │ │ ├── hub.lvl │ │ │ ├── mclaw.lvl │ │ │ ├── new_hub.lvl │ │ │ ├── nhub.lvl │ │ │ └── tutorial.lvl │ │ ├── README.txt │ │ ├── Shaders/ │ │ │ ├── bk.fx │ │ │ ├── chasm.fx │ │ │ ├── entity.fx │ │ │ ├── fog.fx │ │ │ ├── item.fx │ │ │ ├── screen.fx │ │ │ ├── terrain.fx │ │ │ └── ui.fx │ │ ├── achievements.json │ │ ├── bin/ │ │ │ ├── Fonts/ │ │ │ │ ├── fnt.xnb │ │ │ │ ├── large.xnb │ │ │ │ └── small.xnb │ │ │ ├── Shaders/ │ │ │ │ ├── bk.xnb │ │ │ │ ├── chasm.xnb │ │ │ │ ├── entity.xnb │ │ │ │ ├── fog.xnb │ │ │ │ ├── item.xnb │ │ │ │ ├── screen.xnb │ │ │ │ ├── terrain.xnb │ │ │ │ ├── test │ │ │ │ └── ui.xnb │ │ │ └── Textures/ │ │ │ ├── light.xnb │ │ │ ├── noise.xnb │ │ │ └── rexcellent_logo_pixel.xnb │ │ ├── items.json │ │ ├── keys.json │ │ └── logo_helper.ase │ ├── Events.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── Settings.cs │ ├── Tags.cs │ ├── assets/ │ │ ├── CommonAse.cs │ │ ├── Dialogs.cs │ │ ├── Font.cs │ │ ├── ImGuiHelper.cs │ │ ├── Palette.cs │ │ ├── Shaders.cs │ │ ├── achievements/ │ │ │ ├── Achievement.cs │ │ │ └── Achievements.cs │ │ ├── input/ │ │ │ ├── Control.cs │ │ │ └── Controls.cs │ │ ├── items/ │ │ │ ├── ItemData.cs │ │ │ └── Items.cs │ │ ├── lighting/ │ │ │ ├── EntityLight.cs │ │ │ ├── Light.cs │ │ │ ├── LightComponent.cs │ │ │ ├── Lights.cs │ │ │ └── PositionedLight.cs │ │ ├── loot/ │ │ │ ├── Drops.cs │ │ │ └── LootTables.cs │ │ ├── mod/ │ │ │ ├── Mod.cs │ │ │ └── Mods.cs │ │ ├── particle/ │ │ │ ├── AnimatedParticle.cs │ │ │ ├── Particle.cs │ │ │ ├── ParticleEmitter.cs │ │ │ ├── ParticleEntity.cs │ │ │ ├── ParticleSystem.cs │ │ │ ├── Particles.cs │ │ │ ├── controller/ │ │ │ │ ├── AnimatedParticleController.cs │ │ │ │ ├── AshController.cs │ │ │ │ ├── BkDeathParticleController.cs │ │ │ │ ├── BloodParticleController.cs │ │ │ │ ├── Controllers.cs │ │ │ │ ├── DestroyParticleController.cs │ │ │ │ ├── FloatParticleController.cs │ │ │ │ ├── HealthParticleController.cs │ │ │ │ ├── LavaController.cs │ │ │ │ ├── ParticleController.cs │ │ │ │ ├── RainParticleController.cs │ │ │ │ ├── ScourgeController.cs │ │ │ │ ├── SimpleParticleController.cs │ │ │ │ └── SparkParticleController.cs │ │ │ ├── custom/ │ │ │ │ ├── BuffParticle.cs │ │ │ │ ├── ConfettiParticle.cs │ │ │ │ ├── ConsumableParticle.cs │ │ │ │ ├── EpicSpawn.cs │ │ │ │ ├── FadingParticle.cs │ │ │ │ ├── FireEmitter.cs │ │ │ │ ├── FireParticle.cs │ │ │ │ ├── ProjectileParticle.cs │ │ │ │ ├── RainParticle.cs │ │ │ │ ├── SnowParticle.cs │ │ │ │ ├── TextParticle.cs │ │ │ │ └── TileParticle.cs │ │ │ └── renderer/ │ │ │ ├── AnimatedParticleRenderer.cs │ │ │ ├── HealthParticleRenderer.cs │ │ │ ├── ParticleRenderer.cs │ │ │ ├── RandomFrameRenderer.cs │ │ │ └── TexturedParticleRenderer.cs │ │ └── prefabs/ │ │ ├── Prefab.cs │ │ └── Prefabs.cs │ ├── capsule.ase │ ├── debug/ │ │ ├── BiomeCommand.cs │ │ ├── BuffCommand.cs │ │ ├── CheatWindow.cs │ │ ├── Console.cs │ │ ├── ConsoleCommand.cs │ │ ├── DebugCommand.cs │ │ ├── DieCommand.cs │ │ ├── EntityCommand.cs │ │ ├── ExploreCommand.cs │ │ ├── GiveCommand.cs │ │ ├── GodModeCommand.cs │ │ ├── HappeningCommand.cs │ │ ├── HealCommand.cs │ │ ├── HurtCommand.cs │ │ ├── LevelCommand.cs │ │ ├── LevelLayerDebug.cs │ │ ├── LootTableEditor.cs │ │ ├── PassableCommand.cs │ │ ├── PoolEditor.cs │ │ ├── SaveCommand.cs │ │ ├── SpawnCommand.cs │ │ ├── TileCommand.cs │ │ └── ZoomCommand.cs │ ├── entity/ │ │ ├── BlankMaker.cs │ │ ├── Cursor.cs │ │ ├── DamageType.cs │ │ ├── ExplosionMaker.cs │ │ ├── HealthType.cs │ │ ├── Layers.cs │ │ ├── Lego.cs │ │ ├── RenderTrigger.cs │ │ ├── RenderTriggerManager.cs │ │ ├── SpawnPoint.cs │ │ ├── bomb/ │ │ │ ├── Bomb.cs │ │ │ └── controller/ │ │ │ └── TargetBombController.cs │ │ ├── buff/ │ │ │ ├── ArmoredBuff.cs │ │ │ ├── BleedingBuff.cs │ │ │ ├── BrokenArmorBuff.cs │ │ │ ├── Buff.cs │ │ │ ├── BuffCheckEvent.cs │ │ │ ├── BuffInfo.cs │ │ │ ├── BuffRegistry.cs │ │ │ ├── BuffedBuff.cs │ │ │ ├── BurningBuff.cs │ │ │ ├── CharmedBuff.cs │ │ │ ├── ConfusedBuff.cs │ │ │ ├── FrozenBuff.cs │ │ │ ├── InvincibleBuff.cs │ │ │ ├── InvisibleBuff.cs │ │ │ ├── PoisonBuff.cs │ │ │ ├── ProjectileShaderHelper.cs │ │ │ ├── RageBuff.cs │ │ │ └── SlowBuff.cs │ │ ├── component/ │ │ │ ├── AimComponent.cs │ │ │ ├── AnimationComponent.cs │ │ │ ├── AudioEmitterComponent.cs │ │ │ ├── BodyComponent.cs │ │ │ ├── BombGraphicsComponent.cs │ │ │ ├── BuffsComponent.cs │ │ │ ├── CircleBodyComponent.cs │ │ │ ├── CloseDialogComponent.cs │ │ │ ├── CollisionFilterComponent.cs │ │ │ ├── CursorComponent.cs │ │ │ ├── DoorBodyComponent.cs │ │ │ ├── DropModifier.cs │ │ │ ├── DropsComponent.cs │ │ │ ├── ExplodableComponent.cs │ │ │ ├── ExplodeComponent.cs │ │ │ ├── ExtraAnimationComponent.cs │ │ │ ├── FollowerComponent.cs │ │ │ ├── GamepadComponent.cs │ │ │ ├── HatComponent.cs │ │ │ ├── HealthComponent.cs │ │ │ ├── InteractDialogComponent.cs │ │ │ ├── InteractableComponent.cs │ │ │ ├── InteractableSliceComponent.cs │ │ │ ├── InventoryComponent.cs │ │ │ ├── ItemComponent.cs │ │ │ ├── LockComponent.cs │ │ │ ├── ManaComponent.cs │ │ │ ├── MobAnimationComponent.cs │ │ │ ├── NoCornerBodyComponent.cs │ │ │ ├── OrbitGiverComponent.cs │ │ │ ├── OrbitalComponent.cs │ │ │ ├── OwnerComponent.cs │ │ │ ├── PoolDropsComponent.cs │ │ │ ├── QuackInteractionComponent.cs │ │ │ ├── RandomFrameComponent.cs │ │ │ ├── RectBodyComponent.cs │ │ │ ├── RoomComponent.cs │ │ │ ├── ScalableSliceComponent.cs │ │ │ ├── SensorBodyComponent.cs │ │ │ ├── ShadowComponent.cs │ │ │ ├── SimpleZAnimationComponent.cs │ │ │ ├── SliceComponent.cs │ │ │ ├── SparkEmitterComponent.cs │ │ │ ├── StatsComponent.cs │ │ │ ├── SupportableComponent.cs │ │ │ ├── TextGraphicsComponent.cs │ │ │ ├── TileInteractionComponent.cs │ │ │ ├── WallAnimationComponent.cs │ │ │ ├── ZAnimationComponent.cs │ │ │ ├── ZComponent.cs │ │ │ └── ZSliceComponent.cs │ │ ├── creature/ │ │ │ ├── Creature.cs │ │ │ ├── Decoy.cs │ │ │ ├── Gore.cs │ │ │ ├── SmartState.cs │ │ │ ├── bk/ │ │ │ │ ├── BkGraphicsComponent.cs │ │ │ │ ├── BkOrbital.cs │ │ │ │ ├── BurningKnight.cs │ │ │ │ └── SpawnTrigger.cs │ │ │ ├── drop/ │ │ │ │ ├── AnyDrop.cs │ │ │ │ ├── Drop.cs │ │ │ │ ├── DropInfo.cs │ │ │ │ ├── DropRegistry.cs │ │ │ │ ├── EmptyDrop.cs │ │ │ │ ├── OneOfDrop.cs │ │ │ │ ├── PoolDrop.cs │ │ │ │ ├── SimpleDrop.cs │ │ │ │ └── SingleDrop.cs │ │ │ ├── mob/ │ │ │ │ ├── Dummy.cs │ │ │ │ ├── LoopChance.cs │ │ │ │ ├── Mimic.cs │ │ │ │ ├── Mob.cs │ │ │ │ ├── MobInfo.cs │ │ │ │ ├── MobPair.cs │ │ │ │ ├── MobRegistry.cs │ │ │ │ ├── MobSpawnInfo.cs │ │ │ │ ├── SpawnChance.cs │ │ │ │ ├── boss/ │ │ │ │ │ ├── BkHead.cs │ │ │ │ │ ├── Boss.cs │ │ │ │ │ ├── BossAttack.cs │ │ │ │ │ ├── BossInfo.cs │ │ │ │ │ ├── BossRegistry.cs │ │ │ │ │ ├── DM.cs │ │ │ │ │ ├── IceQueen.cs │ │ │ │ │ ├── OldKing.cs │ │ │ │ │ ├── Pharaoh.cs │ │ │ │ │ ├── QueenBee.cs │ │ │ │ │ └── rooms/ │ │ │ │ │ ├── DmBulletDodgeRoom.cs │ │ │ │ │ ├── DmEndRoom.cs │ │ │ │ │ ├── DmEnemyRoom.cs │ │ │ │ │ ├── DmMazeRoom.cs │ │ │ │ │ ├── DmPadsRoom.cs │ │ │ │ │ ├── DmPlatformRoom.cs │ │ │ │ │ ├── DmRoom.cs │ │ │ │ │ ├── DmRoomRegistry.cs │ │ │ │ │ └── DmSpikeRoom.cs │ │ │ │ ├── castle/ │ │ │ │ │ ├── BabySlime.cs │ │ │ │ │ ├── Bandit.cs │ │ │ │ │ ├── BigSlime.cs │ │ │ │ │ ├── BlueBulletSlime.cs │ │ │ │ │ ├── BulletSlime.cs │ │ │ │ │ ├── Caster.cs │ │ │ │ │ ├── Clown.cs │ │ │ │ │ ├── Crab.cs │ │ │ │ │ ├── Ghost.cs │ │ │ │ │ ├── Gunner.cs │ │ │ │ │ ├── King.cs │ │ │ │ │ ├── Knight.cs │ │ │ │ │ ├── MotherSlime.cs │ │ │ │ │ ├── Rat.cs │ │ │ │ │ ├── SimpleSlime.cs │ │ │ │ │ └── WallCrawler.cs │ │ │ │ ├── cave/ │ │ │ │ │ ├── Broco.cs │ │ │ │ │ ├── EmeraldGunner.cs │ │ │ │ │ └── Thief.cs │ │ │ │ ├── desert/ │ │ │ │ │ ├── Cactus.cs │ │ │ │ │ ├── DesertBulletSlime.cs │ │ │ │ │ ├── DesertSlime.cs │ │ │ │ │ ├── Fly.cs │ │ │ │ │ ├── Maggot.cs │ │ │ │ │ ├── MegaSlime.cs │ │ │ │ │ ├── Mummy.cs │ │ │ │ │ ├── Spelunker.cs │ │ │ │ │ └── Worm.cs │ │ │ │ ├── ice/ │ │ │ │ │ ├── BigSnowball.cs │ │ │ │ │ ├── CupGuy.cs │ │ │ │ │ ├── Dino.cs │ │ │ │ │ ├── IceCrawler.cs │ │ │ │ │ ├── Snowball.cs │ │ │ │ │ ├── Snowflake.cs │ │ │ │ │ ├── Snowman.cs │ │ │ │ │ ├── SnowmanBody.cs │ │ │ │ │ └── Sponge.cs │ │ │ │ ├── jungle/ │ │ │ │ │ ├── Bee.cs │ │ │ │ │ ├── BeeHive.cs │ │ │ │ │ ├── BigBee.cs │ │ │ │ │ ├── BuffedFlower.cs │ │ │ │ │ ├── Explobee.cs │ │ │ │ │ ├── Flower.cs │ │ │ │ │ ├── Sniper.cs │ │ │ │ │ └── Wombat.cs │ │ │ │ ├── library/ │ │ │ │ │ ├── Book.cs │ │ │ │ │ ├── Buffer.cs │ │ │ │ │ ├── Skeleton.cs │ │ │ │ │ └── TeleportingMage.cs │ │ │ │ ├── prefabs/ │ │ │ │ │ ├── Slime.cs │ │ │ │ │ └── WallWalker.cs │ │ │ │ └── prefix/ │ │ │ │ ├── DeathShotPrefix.cs │ │ │ │ ├── EmeraldPrefix.cs │ │ │ │ ├── ExplosivePrefix.cs │ │ │ │ ├── FragilePrefix.cs │ │ │ │ ├── GoldPrefix.cs │ │ │ │ ├── HealthyPrefix.cs │ │ │ │ ├── Prefix.cs │ │ │ │ ├── PrefixRegistry.cs │ │ │ │ └── RegenerativePrefix.cs │ │ │ ├── npc/ │ │ │ │ ├── AccessoryTrader.cs │ │ │ │ ├── ActiveTrader.cs │ │ │ │ ├── Beet.cs │ │ │ │ ├── Bird.cs │ │ │ │ ├── Brastin.cs │ │ │ │ ├── Builder.cs │ │ │ │ ├── DarkMage.cs │ │ │ │ ├── Discord.cs │ │ │ │ ├── Duck.cs │ │ │ │ ├── Elon.cs │ │ │ │ ├── EmeraldGolem.cs │ │ │ │ ├── Granny.cs │ │ │ │ ├── HatTrader.cs │ │ │ │ ├── Isaac.cs │ │ │ │ ├── MaPuzzle.cs │ │ │ │ ├── Maanex.cs │ │ │ │ ├── Maanex2.cs │ │ │ │ ├── Mike.cs │ │ │ │ ├── Milt.cs │ │ │ │ ├── Npc.cs │ │ │ │ ├── NullPtr.cs │ │ │ │ ├── OldMan.cs │ │ │ │ ├── Ord.cs │ │ │ │ ├── ShopKeeper.cs │ │ │ │ ├── ShopNpc.cs │ │ │ │ ├── WeaponTrader.cs │ │ │ │ └── dungeon/ │ │ │ │ ├── Boxy.cs │ │ │ │ ├── DungeonDuck.cs │ │ │ │ ├── DungeonElon.cs │ │ │ │ ├── DungeonShopNpc.cs │ │ │ │ ├── Gobetta.cs │ │ │ │ ├── Nurse.cs │ │ │ │ ├── Roger.cs │ │ │ │ ├── Snek.cs │ │ │ │ ├── TrashGoblin.cs │ │ │ │ └── Vampire.cs │ │ │ ├── pet/ │ │ │ │ ├── AnimatedFollowerPet.cs │ │ │ │ ├── Backpack.cs │ │ │ │ ├── BooGraphicsComponent.cs │ │ │ │ ├── Bubblo.cs │ │ │ │ ├── Crystal.cs │ │ │ │ ├── DiagonalPet.cs │ │ │ │ ├── FollowerPet.cs │ │ │ │ ├── GeneratorPet.cs │ │ │ │ ├── LampPet.cs │ │ │ │ ├── LilBoo.cs │ │ │ │ ├── Pet.cs │ │ │ │ ├── PetRegistry.cs │ │ │ │ ├── RoomBasedPet.cs │ │ │ │ ├── ShieldBuddy.cs │ │ │ │ ├── Shooty.cs │ │ │ │ ├── SnekPet.cs │ │ │ │ ├── SpikedCookie.cs │ │ │ │ ├── Strawberry.cs │ │ │ │ ├── TheEye.cs │ │ │ │ └── Wallet.cs │ │ │ └── player/ │ │ │ ├── ActiveItemComponent.cs │ │ │ ├── ActiveWeaponComponent.cs │ │ │ ├── ConsumablesComponent.cs │ │ │ ├── HeartsComponent.cs │ │ │ ├── InteractorComponent.cs │ │ │ ├── LampComponent.cs │ │ │ ├── LocalPlayer.cs │ │ │ ├── Player.cs │ │ │ ├── PlayerClass.cs │ │ │ ├── PlayerGraphicsComponent.cs │ │ │ ├── PlayerInputComponent.cs │ │ │ └── WeaponComponent.cs │ │ ├── cutscene/ │ │ │ ├── controller/ │ │ │ │ ├── CutsceneController.cs │ │ │ │ └── GobboCutsceneController.cs │ │ │ └── entity/ │ │ │ ├── BabyGobbo.cs │ │ │ ├── CutsceneEntity.cs │ │ │ ├── Gobbo.cs │ │ │ ├── Heinur.cs │ │ │ └── OldGobbo.cs │ │ ├── door/ │ │ │ ├── BossDoor.cs │ │ │ ├── BossLock.cs │ │ │ ├── CageDoor.cs │ │ │ ├── CageLock.cs │ │ │ ├── ChallengeDoor.cs │ │ │ ├── ConditionDoor.cs │ │ │ ├── ConditionLock.cs │ │ │ ├── CustomDoor.cs │ │ │ ├── Door.cs │ │ │ ├── GoldLock.cs │ │ │ ├── HallDoor.cs │ │ │ ├── HallLock.cs │ │ │ ├── HeadDoor.cs │ │ │ ├── IronLock.cs │ │ │ ├── ItemDoor.cs │ │ │ ├── ItemLock.cs │ │ │ ├── LevelDoor.cs │ │ │ ├── LevelLock.cs │ │ │ ├── Lock.cs │ │ │ ├── LockableDoor.cs │ │ │ ├── LockedDoor.cs │ │ │ ├── PayedDoor.cs │ │ │ ├── RedDoor.cs │ │ │ ├── RedLock.cs │ │ │ ├── ScourgedDoor.cs │ │ │ ├── ShopDoor.cs │ │ │ ├── SpecialDoor.cs │ │ │ ├── SpikedDoor.cs │ │ │ ├── TeleportTrigger.cs │ │ │ ├── TreasureDoor.cs │ │ │ ├── VerticalConditionDoor.cs │ │ │ ├── VerticalDoor.cs │ │ │ ├── VerticalHallDoor.cs │ │ │ └── VerticalShopDoor.cs │ │ ├── events/ │ │ │ ├── BombPlacedEvent.cs │ │ │ ├── BuffAddedEvent.cs │ │ │ ├── BuffRemovedEvent.cs │ │ │ ├── BurningKnightDefeatedEvent.cs │ │ │ ├── CollisionEndedEvent.cs │ │ │ ├── CollisionStartedEvent.cs │ │ │ ├── ConsumableAddedEvent.cs │ │ │ ├── ConsumableRemovedEvent.cs │ │ │ ├── DealChanceCalculateEvent.cs │ │ │ ├── DiedEvent.cs │ │ │ ├── DoorClosedEvent.cs │ │ │ ├── DoorOpenedEvent.cs │ │ │ ├── ExplodedEvent.cs │ │ │ ├── FlagCollisionEndEvent.cs │ │ │ ├── FlagCollisionStartEvent.cs │ │ │ ├── GramophoneBrokenEvent.cs │ │ │ ├── HealthModifiedEvent.cs │ │ │ ├── InteractedEvent.cs │ │ │ ├── ItemAddedEvent.cs │ │ │ ├── ItemBoughtEvent.cs │ │ │ ├── ItemCheckEvent.cs │ │ │ ├── ItemPlacedEvent.cs │ │ │ ├── ItemPriceCalculationEvent.cs │ │ │ ├── ItemRemovedEvent.cs │ │ │ ├── ItemTakenEvent.cs │ │ │ ├── ItemUsedEvent.cs │ │ │ ├── KilledEvent.cs │ │ │ ├── LockClosedEvent.cs │ │ │ ├── LockOpenedEvent.cs │ │ │ ├── LostSupportEvent.cs │ │ │ ├── MaxHealthModifiedEvent.cs │ │ │ ├── MobTargetChange.cs │ │ │ ├── NewFloorEvent.cs │ │ │ ├── NewLevelStartedEvent.cs │ │ │ ├── PlayerHurtEvent.cs │ │ │ ├── PlayerRolledEvent.cs │ │ │ ├── PlayerShootEvent.cs │ │ │ ├── PostHealthModifiedEvent.cs │ │ │ ├── ProjectileCreatedEvent.cs │ │ │ ├── QuackEvent.cs │ │ │ ├── RemoveFromPoolUse.cs │ │ │ ├── RevivedEvent.cs │ │ │ ├── RoomChangedEvent.cs │ │ │ ├── RoomClearedEvent.cs │ │ │ ├── SaveEndedEvent.cs │ │ │ ├── SaveStartedEvent.cs │ │ │ ├── SecretRoomFoundEvent.cs │ │ │ ├── TileCollisionEndEvent.cs │ │ │ ├── TileCollisionStartEvent.cs │ │ │ └── WeaponSwappedEvent.cs │ │ ├── fx/ │ │ │ ├── ChasmFx.cs │ │ │ ├── ExplosionLeftOver.cs │ │ │ ├── Firefly.cs │ │ │ ├── InteractFx.cs │ │ │ ├── SplashFx.cs │ │ │ ├── SplashParticle.cs │ │ │ ├── TileFx.cs │ │ │ ├── WaterfallFx.cs │ │ │ └── WindFx.cs │ │ ├── item/ │ │ │ ├── AnimatedItemGraphicsComponent.cs │ │ │ ├── BossStand.cs │ │ │ ├── Chance.cs │ │ │ ├── EmeraldStand.cs │ │ │ ├── Item.cs │ │ │ ├── ItemGraphicsComponent.cs │ │ │ ├── ItemInfo.cs │ │ │ ├── ItemPair.cs │ │ │ ├── ItemPickupFx.cs │ │ │ ├── ItemPool.cs │ │ │ ├── ItemQuality.cs │ │ │ ├── ItemType.cs │ │ │ ├── PriceCalculator.cs │ │ │ ├── RandomItem.cs │ │ │ ├── Reroller.cs │ │ │ ├── RoundItem.cs │ │ │ ├── Scourge.cs │ │ │ ├── SingleChoiceStand.cs │ │ │ ├── SpawnMobsUse.cs │ │ │ ├── Weapon.cs │ │ │ ├── WeaponType.cs │ │ │ ├── WeaponTypeHelper.cs │ │ │ ├── renderer/ │ │ │ │ ├── AngledRenderer.cs │ │ │ │ ├── ItemRenderer.cs │ │ │ │ ├── MovingAngledRenderer.cs │ │ │ │ ├── RendererRegistry.cs │ │ │ │ └── StickRenderer.cs │ │ │ ├── stand/ │ │ │ │ ├── ActiveStand.cs │ │ │ │ ├── ArtifactStand.cs │ │ │ │ ├── BkStand.cs │ │ │ │ ├── BoxyStand.cs │ │ │ │ ├── CustomStand.cs │ │ │ │ ├── DarkMageStand.cs │ │ │ │ ├── GarderobeStand.cs │ │ │ │ ├── GobettaStand.cs │ │ │ │ ├── GrannyStand.cs │ │ │ │ ├── HatStand.cs │ │ │ │ ├── HealChoiceStand.cs │ │ │ │ ├── HealthStand.cs │ │ │ │ ├── ItemStand.cs │ │ │ │ ├── LampStand.cs │ │ │ │ ├── LampUnlockStand.cs │ │ │ │ ├── PermanentStand.cs │ │ │ │ ├── RogerStand.cs │ │ │ │ ├── ScourgedStand.cs │ │ │ │ ├── ShieldChoiceStand.cs │ │ │ │ ├── ShopStand.cs │ │ │ │ ├── SnekStand.cs │ │ │ │ ├── TrashGoblinStand.cs │ │ │ │ ├── VampireStand.cs │ │ │ │ └── WeaponStand.cs │ │ │ ├── use/ │ │ │ │ ├── AddHitboxUse.cs │ │ │ │ ├── AddTorchUse.cs │ │ │ │ ├── AffectDealChanceUse.cs │ │ │ │ ├── BlankUse.cs │ │ │ │ ├── BlindFoldUse.cs │ │ │ │ ├── BlockDamageUse.cs │ │ │ │ ├── BreakPiggyBankUse.cs │ │ │ │ ├── BucketUse.cs │ │ │ │ ├── ChanceToUseWeaponUse.cs │ │ │ │ ├── ConsumeUse.cs │ │ │ │ ├── DetonateBombsUse.cs │ │ │ │ ├── DigUse.cs │ │ │ │ ├── DiscoverSecretRoomsUse.cs │ │ │ │ ├── DiscoverSideRoomsUse.cs │ │ │ │ ├── DoOnEnemyCollisionUse.cs │ │ │ │ ├── DoOnHurtUse.cs │ │ │ │ ├── DoOnNewFloorUse.cs │ │ │ │ ├── DoOnTimerUse.cs │ │ │ │ ├── DoUsesIfUse.cs │ │ │ │ ├── DoWithUse.cs │ │ │ │ ├── DuplicateItemsUse.cs │ │ │ │ ├── DuplicateMobsAndHealUse.cs │ │ │ │ ├── DuplicateMobsUse.cs │ │ │ │ ├── EnableScourgeUse.cs │ │ │ │ ├── ExplodeUse.cs │ │ │ │ ├── FireInAllDirsUse.cs │ │ │ │ ├── GiveBombUse.cs │ │ │ │ ├── GiveBuffImmunityUse.cs │ │ │ │ ├── GiveBuffUse.cs │ │ │ │ ├── GiveEmeraldsUse.cs │ │ │ │ ├── GiveFlightUse.cs │ │ │ │ ├── GiveGoldUse.cs │ │ │ │ ├── GiveHeartContainersUse.cs │ │ │ │ ├── GiveItemUse.cs │ │ │ │ ├── GiveKeyUse.cs │ │ │ │ ├── GiveLaserAimUse.cs │ │ │ │ ├── GivePhaseUse.cs │ │ │ │ ├── GiveRandomPickupUse.cs │ │ │ │ ├── GiveScourgeImmunityUse.cs │ │ │ │ ├── GiveWeaponUse.cs │ │ │ │ ├── GoThonkUse.cs │ │ │ │ ├── InvokeItemsUse.cs │ │ │ │ ├── ItemUse.cs │ │ │ │ ├── KillMobUse.cs │ │ │ │ ├── LeaveLegoUse.cs │ │ │ │ ├── MakeBombsBlankUse.cs │ │ │ │ ├── MakeBombsExplodeOnTouchUse.cs │ │ │ │ ├── MakeBombsHomeUse.cs │ │ │ │ ├── MakeItemsAttactUse.cs │ │ │ │ ├── MakeLayerPassableUse.cs │ │ │ │ ├── MakeProjectileExpandUse.cs │ │ │ │ ├── MakeProjectileReshootUse.cs │ │ │ │ ├── MakeProjectileShrinkUse.cs │ │ │ │ ├── MakeProjectilesBlankOnDeathUse.cs │ │ │ │ ├── MakeProjectilesBoomerangUse.cs │ │ │ │ ├── MakeProjectilesBounceUse.cs │ │ │ │ ├── MakeProjectilesHomeInUse.cs │ │ │ │ ├── MakeProjectilesHurtOnMissUse.cs │ │ │ │ ├── MakeProjectilesKillWithBuffUse.cs │ │ │ │ ├── MakeProjectilesShatternOnDeathUse.cs │ │ │ │ ├── MakeProjectilesSlowDown.cs │ │ │ │ ├── MakeProjectilesSplitOnDeathUse.cs │ │ │ │ ├── MakeProjectilesSplitUse.cs │ │ │ │ ├── MakeRollKickProjectilesUse.cs │ │ │ │ ├── MakeShopRestockUse.cs │ │ │ │ ├── MeleeArcUse.cs │ │ │ │ ├── ModEachAttackUse.cs │ │ │ │ ├── ModifyActiveChargeUse.cs │ │ │ │ ├── ModifyArcUse.cs │ │ │ │ ├── ModifyBombsUse.cs │ │ │ │ ├── ModifyConsumableWeightsUse.cs │ │ │ │ ├── ModifyGameSaveValueUse.cs │ │ │ │ ├── ModifyGenUse.cs │ │ │ │ ├── ModifyHpUse.cs │ │ │ │ ├── ModifyLuckUse.cs │ │ │ │ ├── ModifyManaMaxUse.cs │ │ │ │ ├── ModifyManaUse.cs │ │ │ │ ├── ModifyMaxHpUse.cs │ │ │ │ ├── ModifyProjectileTextureUse.cs │ │ │ │ ├── ModifyProjectilesUse.cs │ │ │ │ ├── ModifyShieldHeartsUse.cs │ │ │ │ ├── ModifyShootUse.cs │ │ │ │ ├── ModifyStatUse.cs │ │ │ │ ├── ModifyStatsUse.cs │ │ │ │ ├── PlaceDecoyUse.cs │ │ │ │ ├── PokemonUse.cs │ │ │ │ ├── PoofUse.cs │ │ │ │ ├── PreventDamageUse.cs │ │ │ │ ├── RandomActiveUse.cs │ │ │ │ ├── RandomUse.cs │ │ │ │ ├── RegenUse.cs │ │ │ │ ├── ReplaceHeartsWithShieldsUse.cs │ │ │ │ ├── RerollAndHideUse.cs │ │ │ │ ├── RerollItemsOnPlayerUse.cs │ │ │ │ ├── RerollItemsUse.cs │ │ │ │ ├── RevealMapUse.cs │ │ │ │ ├── SaleItemsUse.cs │ │ │ │ ├── ScourgeUse.cs │ │ │ │ ├── SetKnockbackModifierUse.cs │ │ │ │ ├── SetMaxHpUse.cs │ │ │ │ ├── SetMusicSpeed.cs │ │ │ │ ├── ShootLaserUse.cs │ │ │ │ ├── ShootQueueUse.cs │ │ │ │ ├── ShootUse.cs │ │ │ │ ├── SimpleShootUse.cs │ │ │ │ ├── SpawnBombUse.cs │ │ │ │ ├── SpawnDropUse.cs │ │ │ │ ├── SpawnItemsUse.cs │ │ │ │ ├── SpawnOrbitalUse.cs │ │ │ │ ├── SpawnPetUse.cs │ │ │ │ ├── SpawnProjectilesUse.cs │ │ │ │ ├── SpeedUpOrbitalsUse.cs │ │ │ │ ├── SuperHotUse.cs │ │ │ │ ├── TeleportToCursorUse.cs │ │ │ │ ├── TeleportToPrevRoomUse.cs │ │ │ │ ├── TeleportToShopUse.cs │ │ │ │ ├── TeleportUse.cs │ │ │ │ ├── TriggerHurtEventUse.cs │ │ │ │ ├── UseOnEventUse.cs │ │ │ │ ├── UseRegistry.cs │ │ │ │ └── parent/ │ │ │ │ ├── DoUsesUse.cs │ │ │ │ └── DoWithTagUse.cs │ │ │ ├── useCheck/ │ │ │ │ ├── ItemUseCheck.cs │ │ │ │ └── ItemUseChecks.cs │ │ │ └── util/ │ │ │ └── MeleeArc.cs │ │ ├── orbital/ │ │ │ ├── AnimatedOrbital.cs │ │ │ ├── Marshmallow.cs │ │ │ ├── Orbital.cs │ │ │ ├── OrbitalRegistry.cs │ │ │ └── Prism.cs │ │ ├── pc/ │ │ │ ├── Controller.cs │ │ │ └── Pico.cs │ │ ├── pool/ │ │ │ └── Pool.cs │ │ ├── projectile/ │ │ │ ├── BasicProjectileGraphicsComponent.cs │ │ │ ├── Laser.cs │ │ │ ├── LaserGraphicsComponent.cs │ │ │ ├── LetterTemplateData.cs │ │ │ ├── Missile.cs │ │ │ ├── OldProjectile.cs │ │ │ ├── Projectile.cs │ │ │ ├── ProjectileBuilder.cs │ │ │ ├── ProjectileCallbacks.cs │ │ │ ├── ProjectileColor.cs │ │ │ ├── ProjectileFlags.cs │ │ │ ├── ProjectileGraphicsComponent.cs │ │ │ ├── ProjectileGraphicsEffect.cs │ │ │ ├── ProjectilePattern.cs │ │ │ ├── ProjectileRegistry.cs │ │ │ ├── ProjectileTemplate.cs │ │ │ ├── controller/ │ │ │ │ ├── BoomerangProjectileController.cs │ │ │ │ ├── ExpandProjectileController.cs │ │ │ │ ├── HsvProjectileController.cs │ │ │ │ ├── ReturnProjectileController.cs │ │ │ │ ├── ShrinkProjectileController.cs │ │ │ │ ├── SlowdownProjectileController.cs │ │ │ │ ├── SmokeProjectileController.cs │ │ │ │ ├── TargetProjectileController.cs │ │ │ │ ├── TimedProjectileController.cs │ │ │ │ └── WhatController.cs │ │ │ └── pattern/ │ │ │ ├── CircleProjectilePattern.cs │ │ │ ├── CircleWithCenterProjectilePattern.cs │ │ │ ├── ExpandingCirclePattern.cs │ │ │ └── KeepShapePattern.cs │ │ ├── room/ │ │ │ ├── Room.cs │ │ │ ├── controllable/ │ │ │ │ ├── AlwaysOnSpikes.cs │ │ │ │ ├── FireTrap.cs │ │ │ │ ├── Piston.cs │ │ │ │ ├── RollingSpike.cs │ │ │ │ ├── RoomControllable.cs │ │ │ │ ├── Support.cs │ │ │ │ ├── platform/ │ │ │ │ │ ├── MovingPlatform.cs │ │ │ │ │ ├── Platform.cs │ │ │ │ │ ├── PlatformBorder.cs │ │ │ │ │ ├── PlatformController.cs │ │ │ │ │ └── SteppingPlatform.cs │ │ │ │ ├── spikes/ │ │ │ │ │ ├── SensingSpikes.cs │ │ │ │ │ └── Spikes.cs │ │ │ │ └── turret/ │ │ │ │ ├── QuadRotatingTurret.cs │ │ │ │ ├── QuadTurret.cs │ │ │ │ ├── RotatingTurret.cs │ │ │ │ └── Turret.cs │ │ │ ├── controller/ │ │ │ │ ├── BossRoomController.cs │ │ │ │ ├── ChallengeRoomController.cs │ │ │ │ ├── FollowingSpikeBallController.cs │ │ │ │ ├── PistonActivatorController.cs │ │ │ │ ├── RoomController.cs │ │ │ │ ├── RoomControllerRegistery.cs │ │ │ │ ├── SpikeFieldController.cs │ │ │ │ ├── TimedPistonSwitchController.cs │ │ │ │ └── TrapRoomController.cs │ │ │ └── input/ │ │ │ ├── Button.cs │ │ │ ├── Lever.cs │ │ │ ├── PreasurePlate.cs │ │ │ └── RoomInput.cs │ │ └── twitch/ │ │ ├── LoginSign.cs │ │ ├── TwitchBridge.cs │ │ ├── TwitchExit.cs │ │ ├── TwitchNpc.cs │ │ ├── TwitchPet.cs │ │ └── happening/ │ │ ├── BkRageHappening.cs │ │ ├── BombHappening.cs │ │ ├── BombingHappening.cs │ │ ├── BuffHappening.cs │ │ ├── ChestHappening.cs │ │ ├── DarknessHappening.cs │ │ ├── FloorResetHappening.cs │ │ ├── GiveShieldHappening.cs │ │ ├── Happening.cs │ │ ├── HappeningRegistry.cs │ │ ├── HealHappening.cs │ │ ├── HurtHappening.cs │ │ ├── ItemGiveHappening.cs │ │ ├── MakeItemsDamageUse.cs │ │ ├── ModifyCoinsHappening.cs │ │ ├── ModifyMaxHpHappening.cs │ │ ├── RandomItemHappening.cs │ │ ├── RandomTypedItemHappening.cs │ │ ├── RerollHappening.cs │ │ ├── ScourgeHappening.cs │ │ ├── SlideHappening.cs │ │ ├── StealWeaponHappening.cs │ │ └── TeleportHappening.cs │ ├── export_achievements.sh │ ├── item_sprites.ase │ ├── level/ │ │ ├── Chasm.cs │ │ ├── ChasmBodyComponent.cs │ │ ├── DoorPlaceholder.cs │ │ ├── Flag.cs │ │ ├── HalfProjectileBodyComponent.cs │ │ ├── HalfProjectileLevel.cs │ │ ├── HalfWall.cs │ │ ├── HalfWallBodyComponent.cs │ │ ├── Level.cs │ │ ├── LevelBodyComponent.cs │ │ ├── LevelTiler.cs │ │ ├── Painter.cs │ │ ├── Patch.cs │ │ ├── ProjectileBodyComponent.cs │ │ ├── ProjectileLevelBody.cs │ │ ├── RegularLevel.cs │ │ ├── Weather.cs │ │ ├── biome/ │ │ │ ├── Biome.cs │ │ │ ├── BiomeAssets.cs │ │ │ ├── BiomeInfo.cs │ │ │ ├── BiomeRegistry.cs │ │ │ ├── CastleBiome.cs │ │ │ ├── CaveBiome.cs │ │ │ ├── DesertBiome.cs │ │ │ ├── HubBiome.cs │ │ │ ├── IceBiome.cs │ │ │ ├── JungleBiome.cs │ │ │ ├── LibraryBiome.cs │ │ │ └── TechBiome.cs │ │ ├── builders/ │ │ │ ├── Builder.cs │ │ │ ├── CastleBuilder.cs │ │ │ ├── InfinityBuilder.cs │ │ │ ├── LineBuilder.cs │ │ │ ├── LoopBuilder.cs │ │ │ ├── RegularBuilder.cs │ │ │ └── SingleRoomBuilder.cs │ │ ├── challenge/ │ │ │ ├── BombOnlyChallenge.cs │ │ │ ├── Challenge.cs │ │ │ └── ChallengeRegistry.cs │ │ ├── cutscene/ │ │ │ ├── CutsceneLevel.cs │ │ │ └── CutsceneRoom.cs │ │ ├── entities/ │ │ │ ├── AchievementStatue.cs │ │ │ ├── Belt.cs │ │ │ ├── BreakableProp.cs │ │ │ ├── Campfire.cs │ │ │ ├── Claw.cs │ │ │ ├── ClawControll.cs │ │ │ ├── ContinueRun.cs │ │ │ ├── Crystal.cs │ │ │ ├── DailySign.cs │ │ │ ├── DownBelt.cs │ │ │ ├── Entrance.cs │ │ │ ├── Exit.cs │ │ │ ├── ExplodingBarrel.cs │ │ │ ├── Gramophone.cs │ │ │ ├── HiddenEntrance.cs │ │ │ ├── HiddenExit.cs │ │ │ ├── Portal.cs │ │ │ ├── Prop.cs │ │ │ ├── RightBelt.cs │ │ │ ├── Safe.cs │ │ │ ├── ShadowedProp.cs │ │ │ ├── Sign.cs │ │ │ ├── SlicedProp.cs │ │ │ ├── SolidProp.cs │ │ │ ├── Stand.cs │ │ │ ├── StatDisplay.cs │ │ │ ├── Teleporter.cs │ │ │ ├── Tombstone.cs │ │ │ ├── UpBelt.cs │ │ │ ├── building/ │ │ │ │ ├── House.cs │ │ │ │ └── Thing.cs │ │ │ ├── chest/ │ │ │ │ ├── AnimatedChest.cs │ │ │ │ ├── Chest.cs │ │ │ │ ├── ChestRegistry.cs │ │ │ │ ├── DoubleChest.cs │ │ │ │ ├── DuckChest.cs │ │ │ │ ├── GlassChest.cs │ │ │ │ ├── GoldChest.cs │ │ │ │ ├── ProtoChest.cs │ │ │ │ ├── RedChest.cs │ │ │ │ ├── ScourgedChest.cs │ │ │ │ ├── StoneChest.cs │ │ │ │ ├── TreasureChest.cs │ │ │ │ ├── TripleChest.cs │ │ │ │ └── WoodenChest.cs │ │ │ ├── decor/ │ │ │ │ ├── BurningStatue.cs │ │ │ │ ├── GrannyDecor.cs │ │ │ │ ├── Lamp.cs │ │ │ │ ├── Torch.cs │ │ │ │ ├── Tree.cs │ │ │ │ └── WallTorch.cs │ │ │ ├── exit/ │ │ │ │ ├── BossRushExit.cs │ │ │ │ ├── ChallengeExit.cs │ │ │ │ ├── DailyRunExit.cs │ │ │ │ ├── ShortcutExit.cs │ │ │ │ └── TutorialExit.cs │ │ │ ├── machine/ │ │ │ │ ├── Charger.cs │ │ │ │ ├── RerollMachine.cs │ │ │ │ └── VendingMachine.cs │ │ │ ├── plant/ │ │ │ │ ├── Plant.cs │ │ │ │ └── PlantGraphicsComponent.cs │ │ │ └── statue/ │ │ │ ├── ChestStatue.cs │ │ │ ├── DiceStatue.cs │ │ │ ├── Fountain.cs │ │ │ ├── GamepadStatue.cs │ │ │ ├── ScourgeStatue.cs │ │ │ ├── Statue.cs │ │ │ ├── StoneStatue.cs │ │ │ ├── SwordStatue.cs │ │ │ ├── WarriorStatue.cs │ │ │ └── Well.cs │ │ ├── floors/ │ │ │ ├── BathFloor.cs │ │ │ ├── ChessFloor.cs │ │ │ ├── DiagonalFloor.cs │ │ │ ├── FancyFloor.cs │ │ │ ├── FloorPainter.cs │ │ │ ├── FloorRegistry.cs │ │ │ ├── GeometryFloor.cs │ │ │ ├── HoneycombFloor.cs │ │ │ ├── LineFloor.cs │ │ │ ├── MazeFloor.cs │ │ │ ├── PatchFloor.cs │ │ │ └── TrippleFloor.cs │ │ ├── hall/ │ │ │ ├── HallBuilder.cs │ │ │ ├── HallLevel.cs │ │ │ └── HallRoom.cs │ │ ├── paintings/ │ │ │ ├── AnimatedPainting.cs │ │ │ ├── Painting.cs │ │ │ └── PaintingRegistry.cs │ │ ├── rooms/ │ │ │ ├── RoomDef.cs │ │ │ ├── RoomInfo.cs │ │ │ ├── RoomRegistry.cs │ │ │ ├── RoomType.cs │ │ │ ├── RoomTypeHelper.cs │ │ │ ├── boss/ │ │ │ │ ├── BossRoom.cs │ │ │ │ ├── ChasmBossRoom.cs │ │ │ │ ├── CollumnsBossRoom.cs │ │ │ │ └── FireTrapBossRoom.cs │ │ │ ├── challenge/ │ │ │ │ └── ChallengeRoom.cs │ │ │ ├── connection/ │ │ │ │ ├── CabbadgeConnectionRoom.cs │ │ │ │ ├── ComplexTunnelRoom.cs │ │ │ │ ├── ConnectionRoom.cs │ │ │ │ ├── HoleConnectionRoom.cs │ │ │ │ ├── IceConnectionRoom.cs │ │ │ │ ├── IntersectionConnectionRoom.cs │ │ │ │ ├── LibraryConnectionRoom.cs │ │ │ │ ├── MazeConnectionRoom.cs │ │ │ │ ├── RingConnectionRoom.cs │ │ │ │ └── TunnelRoom.cs │ │ │ ├── darkmarket/ │ │ │ │ └── DarkMarketRoom.cs │ │ │ ├── entrance/ │ │ │ │ ├── EntranceRoom.cs │ │ │ │ ├── EntranceWallPool.cs │ │ │ │ ├── ExitRoom.cs │ │ │ │ └── PortalEntranceRoom.cs │ │ │ ├── granny/ │ │ │ │ └── GrannyRoom.cs │ │ │ ├── oldman/ │ │ │ │ └── OldManRoom.cs │ │ │ ├── payed/ │ │ │ │ └── PayedRoom.cs │ │ │ ├── preboss/ │ │ │ │ └── PrebossRoom.cs │ │ │ ├── regular/ │ │ │ │ ├── EmptyRoom.cs │ │ │ │ ├── HiveRoom.cs │ │ │ │ ├── ItemTrollRoom.cs │ │ │ │ ├── JungleRoom.cs │ │ │ │ ├── PlatformChaosRoom.cs │ │ │ │ ├── PlatformLineRoom.cs │ │ │ │ ├── PlatformRingRoom.cs │ │ │ │ ├── RegularRoom.cs │ │ │ │ ├── TwoSidesRoom.cs │ │ │ │ └── VerticalRegularRoom.cs │ │ │ ├── scourged/ │ │ │ │ └── ScourgedRoom.cs │ │ │ ├── secret/ │ │ │ │ ├── BirdSecretRoom.cs │ │ │ │ ├── GrannySecretRoom.cs │ │ │ │ ├── SecretChasmRoom.cs │ │ │ │ ├── SecretChestRoom.cs │ │ │ │ ├── SecretDarkMarketEntranceRoom.cs │ │ │ │ ├── SecretEmeraldGolemRoom.cs │ │ │ │ ├── SecretItemRoom.cs │ │ │ │ ├── SecretKeyRoom.cs │ │ │ │ ├── SecretMachineRoom.cs │ │ │ │ ├── SecretRoom.cs │ │ │ │ └── SecretScourgeRoom.cs │ │ │ ├── shop/ │ │ │ │ ├── ShopRoom.cs │ │ │ │ └── sub/ │ │ │ │ ├── ProtoShopRoom.cs │ │ │ │ ├── SnekShopRoom.cs │ │ │ │ ├── StorageRoom.cs │ │ │ │ ├── SubShopRoom.cs │ │ │ │ └── VampireShopRoom.cs │ │ │ ├── special/ │ │ │ │ ├── ChargerRoom.cs │ │ │ │ ├── DarkMarketEntranceRoom.cs │ │ │ │ ├── DesertWellRoom.cs │ │ │ │ ├── HeartRoom.cs │ │ │ │ ├── IdolTrapRoom.cs │ │ │ │ ├── LockedRoom.cs │ │ │ │ ├── NpcKeyRoom.cs │ │ │ │ ├── NpcSaveRoom.cs │ │ │ │ ├── ProtoChestRoom.cs │ │ │ │ ├── SafeRoom.cs │ │ │ │ ├── SpecialRoom.cs │ │ │ │ ├── TombRoom.cs │ │ │ │ ├── VendingRoom.cs │ │ │ │ ├── minigame/ │ │ │ │ │ ├── ChestMinigameRoom.cs │ │ │ │ │ └── ClawMinigameRoom.cs │ │ │ │ ├── npc/ │ │ │ │ │ ├── DuckRoom.cs │ │ │ │ │ ├── ElonRoom.cs │ │ │ │ │ ├── NurseRoom.cs │ │ │ │ │ └── VampireRoom.cs │ │ │ │ ├── shop/ │ │ │ │ │ ├── BoxyShopRoom.cs │ │ │ │ │ ├── GobettaShopRoom.cs │ │ │ │ │ ├── NpcShopRoom.cs │ │ │ │ │ ├── RogerShopRoom.cs │ │ │ │ │ ├── SnekRoom.cs │ │ │ │ │ └── TrashGoblinRoom.cs │ │ │ │ └── statue/ │ │ │ │ ├── ChestStatueRoom.cs │ │ │ │ ├── DiceStatueRoom.cs │ │ │ │ ├── FountainRoom.cs │ │ │ │ ├── ScourgeStatueRoom.cs │ │ │ │ ├── StatueRoom.cs │ │ │ │ ├── StoneStatueRoom.cs │ │ │ │ ├── SwordStatueRoom.cs │ │ │ │ ├── WarriorStatueRoom.cs │ │ │ │ └── WellRoom.cs │ │ │ ├── spiked/ │ │ │ │ └── SpikedRoom.cs │ │ │ ├── trap/ │ │ │ │ ├── CrossTurretPassageRoom.cs │ │ │ │ ├── DangerousPadsRoom.cs │ │ │ │ ├── FollowingSpikeBallRoom.cs │ │ │ │ ├── RollingSpikesRoom.cs │ │ │ │ ├── SpikeMazeRoom.cs │ │ │ │ ├── SpikePassageRoom.cs │ │ │ │ ├── TrapRoom.cs │ │ │ │ ├── TurretPassageRoom.cs │ │ │ │ ├── TurretTrapRoom.cs │ │ │ │ └── VerticalTurretPassageRoom.cs │ │ │ └── treasure/ │ │ │ ├── AcrossTreasureRoom.cs │ │ │ ├── HoleTreasureRoom.cs │ │ │ ├── PadTreasureRoom.cs │ │ │ ├── PlatformTreasureRoom.cs │ │ │ ├── TreasureRoom.cs │ │ │ └── TwoDiagonalTreasureRoom.cs │ │ ├── tile/ │ │ │ ├── Tile.cs │ │ │ ├── TileFlags.cs │ │ │ ├── Tiles.cs │ │ │ ├── Tileset.cs │ │ │ └── Tilesets.cs │ │ ├── tutorial/ │ │ │ ├── TutorialLevel.cs │ │ │ ├── TutorialRoom.cs │ │ │ └── TutorialStand.cs │ │ ├── variant/ │ │ │ ├── ChasmLevelVariant.cs │ │ │ ├── FloodedLevelVariant.cs │ │ │ ├── ForestLevelVariant.cs │ │ │ ├── GoldLevelVariant.cs │ │ │ ├── LevelVariant.cs │ │ │ ├── RaveCaveVariant.cs │ │ │ ├── RegularLevelVariant.cs │ │ │ ├── SandLevelVariant.cs │ │ │ ├── SnowLevelVariant.cs │ │ │ ├── VariantInfo.cs │ │ │ ├── VariantRegistry.cs │ │ │ └── WebbedLevelVariant.cs │ │ └── walls/ │ │ ├── CollumnWall.cs │ │ ├── CollumsWall.cs │ │ ├── CornerWall.cs │ │ ├── CorneredTurretWall.cs │ │ ├── EllipseWalls.cs │ │ ├── MazeWall.cs │ │ ├── PatchWall.cs │ │ ├── PlatformWall.cs │ │ ├── RuinsWall.cs │ │ ├── SegmentedWall.cs │ │ ├── SplitWall.cs │ │ ├── TempleWalls.cs │ │ ├── TurretWall.cs │ │ ├── WallPainter.cs │ │ ├── WallRegistry.cs │ │ └── library/ │ │ ├── LibraryWallPainter.cs │ │ └── TeleportSplitWall.cs │ ├── mockups.ase │ ├── monitor.ase │ ├── packages.config │ ├── physics/ │ │ ├── CollisionFilterEntity.cs │ │ ├── CollisionResult.cs │ │ ├── Physics.cs │ │ └── PhysicsDebugRenderer.cs │ ├── pico.ase │ ├── save/ │ │ ├── EntitySaver.cs │ │ ├── GameSave.cs │ │ ├── GlobalSave.cs │ │ ├── LevelSave.cs │ │ ├── PlayerSave.cs │ │ ├── PrefabData.cs │ │ ├── PrefabSaver.cs │ │ ├── SaveDebug.cs │ │ ├── SaveLock.cs │ │ ├── SaveManager.cs │ │ ├── SaveType.cs │ │ ├── SaveableEntity.cs │ │ ├── Saver.cs │ │ ├── SecretSave.cs │ │ ├── StatisticsSaver.cs │ │ ├── cloud/ │ │ │ ├── CloudFileReader.cs │ │ │ └── CloudFileWriter.cs │ │ └── statistics/ │ │ └── RunStatistics.cs │ ├── state/ │ │ ├── AreaDebug.cs │ │ ├── AssetLoadState.cs │ │ ├── Credits.cs │ │ ├── CutsceneState.cs │ │ ├── DevAssetLoadState.cs │ │ ├── DialogEditorState.cs │ │ ├── Editor.cs │ │ ├── EditorState.cs │ │ ├── InGameAudio.cs │ │ ├── InGameState.cs │ │ ├── ItemEditor.cs │ │ ├── LoadState.cs │ │ ├── LogoRenderer.cs │ │ ├── PhotoCard.cs │ │ ├── PicoState.cs │ │ ├── RoomEditorState.cs │ │ ├── Run.cs │ │ ├── RunType.cs │ │ └── save/ │ │ ├── EntityData.cs │ │ ├── EntityInspector.cs │ │ ├── GameInspector.cs │ │ ├── GlobalInspector.cs │ │ ├── SaveData.cs │ │ ├── SaveExplorerState.cs │ │ ├── SaveGroup.cs │ │ ├── SaveInspector.cs │ │ └── SaveNode.cs │ ├── ui/ │ │ ├── AchievementBanner.cs │ │ ├── ButtonType.cs │ │ ├── FrameRenderer.cs │ │ ├── HealthBar.cs │ │ ├── SaveIndicator.cs │ │ ├── UiAchievement.cs │ │ ├── UiAnimation.cs │ │ ├── UiBanner.cs │ │ ├── UiButton.cs │ │ ├── UiChat.cs │ │ ├── UiCheckbox.cs │ │ ├── UiChoice.cs │ │ ├── UiControl.cs │ │ ├── UiDescriptionBanner.cs │ │ ├── UiEntity.cs │ │ ├── UiError.cs │ │ ├── UiImageButton.cs │ │ ├── UiLabel.cs │ │ ├── UiMap.cs │ │ ├── UiPane.cs │ │ ├── UiSlider.cs │ │ ├── UiTable.cs │ │ ├── UiTableEntry.cs │ │ ├── dialog/ │ │ │ ├── AnswerDialog.cs │ │ │ ├── AnswerType.cs │ │ │ ├── ChoiceDialog.cs │ │ │ ├── CombineDialog.cs │ │ │ ├── Dialog.cs │ │ │ ├── DialogComponent.cs │ │ │ ├── DialogNode.cs │ │ │ ├── EventDialog.cs │ │ │ └── UiDialog.cs │ │ ├── editor/ │ │ │ ├── CursorMode.cs │ │ │ ├── EditorWindow.cs │ │ │ ├── EntityEditor.cs │ │ │ ├── PlaceableEntity.cs │ │ │ ├── TileEditor.cs │ │ │ ├── TileInfo.cs │ │ │ ├── TypeInfo.cs │ │ │ └── command/ │ │ │ ├── Command.cs │ │ │ ├── CommandQueue.cs │ │ │ ├── FillCommand.cs │ │ │ └── SetCommand.cs │ │ ├── imgui/ │ │ │ ├── DebugWindow.cs │ │ │ ├── DialogEditor.cs │ │ │ ├── DrawVertDeclaration.cs │ │ │ ├── ImConnection.cs │ │ │ ├── ImGuiRenderer.cs │ │ │ ├── ImNodes.cs │ │ │ ├── LocaleEditor.cs │ │ │ ├── WindowManager.cs │ │ │ └── node/ │ │ │ ├── ImAnswerNode.cs │ │ │ ├── ImChoiceNode.cs │ │ │ ├── ImDialogNode.cs │ │ │ ├── ImNode.cs │ │ │ ├── ImNodeRegistry.cs │ │ │ ├── ImOrdNode.cs │ │ │ ├── ImTextInputNode.cs │ │ │ ├── ImTextNode.cs │ │ │ └── ImTextOutputNode.cs │ │ ├── inventory/ │ │ │ ├── UiActiveItemSlot.cs │ │ │ ├── UiInventory.cs │ │ │ ├── UiItem.cs │ │ │ └── UiWeaponSlot.cs │ │ └── str/ │ │ ├── Glyph.cs │ │ ├── IconRenderer.cs │ │ ├── StrRenderer.cs │ │ ├── UiString.cs │ │ ├── effect/ │ │ │ ├── BlinkEffect.cs │ │ │ ├── BoldEffect.cs │ │ │ ├── ColorEffect.cs │ │ │ ├── FlipEffect.cs │ │ │ ├── GlyphEffect.cs │ │ │ ├── ItalicEffect.cs │ │ │ ├── RainbowEffect.cs │ │ │ ├── RandomEffect.cs │ │ │ ├── ShakeEffect.cs │ │ │ └── WaveEffect.cs │ │ └── event/ │ │ ├── DelayEvent.cs │ │ ├── GlyphEvent.cs │ │ ├── SkipEvent.cs │ │ ├── SpeedEvent.cs │ │ └── UserEvent.cs │ └── util/ │ ├── AnimationUtil.cs │ ├── ArrayUtils.cs │ ├── BArray.cs │ ├── BiomeTitles.cs │ ├── Birthday.cs │ ├── BitHelper.cs │ ├── CollisionHelper.cs │ ├── Direction.cs │ ├── Directions.cs │ ├── FollowingDriver.cs │ ├── ImJson.cs │ ├── JsonCounter.cs │ ├── Line.cs │ ├── LoadScreenJokes.cs │ ├── LoadScreenTips.cs │ ├── Maze.cs │ ├── PathFinder.cs │ ├── Titles.cs │ ├── Vec2.cs │ └── geometry/ │ ├── Dot.cs │ └── Rect.cs ├── CompileNetFrameworkOnLinux.md ├── Desktop/ │ ├── Desktop.csproj │ ├── DesktopApp.cs │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── integration/ │ │ ├── Integration.cs │ │ ├── crash/ │ │ │ └── CrashReporter.cs │ │ ├── discord/ │ │ │ ├── DiscordIntegration.cs │ │ │ └── DiscordRpc.cs │ │ ├── rgb/ │ │ │ └── RgbIntegration.cs │ │ ├── steam/ │ │ │ └── SteamIntegration.cs │ │ ├── twitch/ │ │ │ ├── HappeningOption.cs │ │ │ ├── TwitchContoller.cs │ │ │ └── TwitchIntegration.cs │ │ └── twitch_todo.md │ └── packages.config ├── LICENSE ├── Lens/ │ ├── Cloner.cs │ ├── Display.cs │ ├── Engine.cs │ ├── Lens.csproj │ ├── MonoGame.Framework.dll.config │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── Version.cs │ ├── assets/ │ │ ├── Animations.cs │ │ ├── Assets.cs │ │ ├── Audio.cs │ │ ├── Effects.cs │ │ ├── Locale.cs │ │ └── Textures.cs │ ├── core/ │ │ ├── ConsoleCore.cs │ │ ├── Core.cs │ │ ├── DesktopCore.cs │ │ ├── PS4Core.cs │ │ ├── SwitchCore.cs │ │ └── XBoxCore.cs │ ├── entity/ │ │ ├── Area.cs │ │ ├── BitTag.cs │ │ ├── Entity.cs │ │ ├── EntityList.cs │ │ ├── Event.cs │ │ ├── EventListener.cs │ │ ├── Subscriber.cs │ │ ├── TagLists.cs │ │ └── component/ │ │ ├── Component.cs │ │ ├── SaveableComponent.cs │ │ ├── graphics/ │ │ │ ├── GraphicsComponent.cs │ │ │ └── ImageComponent.cs │ │ └── logic/ │ │ ├── EntityState.cs │ │ ├── InterestingComponent.cs │ │ ├── ShakeComponent.cs │ │ ├── StateChangedEvent.cs │ │ └── StateComponent.cs │ ├── game/ │ │ └── GameState.cs │ ├── graphics/ │ │ ├── ColorUtils.cs │ │ ├── Graphics.cs │ │ ├── TextureRegion.cs │ │ ├── animation/ │ │ │ ├── Animation.cs │ │ │ ├── AnimationData.cs │ │ │ ├── AnimationDirection.cs │ │ │ ├── AnimationFrame.cs │ │ │ ├── AnimationTag.cs │ │ │ ├── ColorSet.cs │ │ │ └── ColorSets.cs │ │ └── gamerenderer/ │ │ ├── DefaultGameRenderer.cs │ │ ├── GameRenderer.cs │ │ ├── NativeGameRenderer.cs │ │ └── PixelPerfectGameRenderer.cs │ ├── input/ │ │ ├── GamepadData.cs │ │ ├── Input.cs │ │ ├── InputButton.cs │ │ ├── InputComponent.cs │ │ ├── KeyboardData.cs │ │ ├── MouseButtons.cs │ │ └── MouseData.cs │ ├── lightJson/ │ │ ├── JsonArray.cs │ │ ├── JsonObject.cs │ │ ├── JsonValue.cs │ │ ├── JsonValueType.cs │ │ ├── README.md │ │ └── Serialization/ │ │ ├── JsonParseException.cs │ │ ├── JsonReader.cs │ │ ├── JsonSerializationException.cs │ │ ├── JsonWriter.cs │ │ ├── TextPosition.cs │ │ └── TextScanner.cs │ ├── packages.config │ └── util/ │ ├── FrameCounter.cs │ ├── Log.cs │ ├── MathUtils.cs │ ├── Noise.cs │ ├── NumberExtensions.cs │ ├── VectorExtension.cs │ ├── Web.cs │ ├── camera/ │ │ ├── Camera.cs │ │ ├── CameraDriver.cs │ │ └── CustomCameraJumper.cs │ ├── file/ │ │ ├── FileHandle.cs │ │ ├── FileReader.cs │ │ └── FileWriter.cs │ ├── math/ │ │ ├── Calc.cs │ │ └── Rnd.cs │ ├── pool/ │ │ ├── DisposablePool.cs │ │ └── Pool.cs │ ├── timer/ │ │ ├── Timer.cs │ │ └── TimerTask.cs │ └── tween/ │ ├── Ease.cs │ ├── Tween.cs │ ├── TweenTask.cs │ └── TweenValue.cs ├── Lens.sln ├── README.md ├── VelcroPhysics/ │ ├── BreakableBody.cs │ ├── Collision/ │ │ ├── AABBHelper.cs │ │ ├── Broadphase/ │ │ │ ├── DynamicTree.cs │ │ │ ├── DynamicTreeBroadPhase.cs │ │ │ ├── IBroadPhase.cs │ │ │ ├── Pair.cs │ │ │ └── TreeNode.cs │ │ ├── ContactSystem/ │ │ │ ├── Contact.cs │ │ │ ├── ContactEdge.cs │ │ │ ├── ContactFeature.cs │ │ │ ├── ContactFeatureType.cs │ │ │ ├── ContactFlags.cs │ │ │ ├── ContactID.cs │ │ │ ├── ContactManager.cs │ │ │ └── ContactType.cs │ │ ├── Distance/ │ │ │ ├── DistanceGJK.cs │ │ │ ├── DistanceInput.cs │ │ │ ├── DistanceOutput.cs │ │ │ └── DistanceProxy.cs │ │ ├── Filtering/ │ │ │ ├── Category.cs │ │ │ └── Filter.cs │ │ ├── Handlers/ │ │ │ ├── AfterCollisionHandler.cs │ │ │ ├── BeforeCollisionHandler.cs │ │ │ ├── BeginContactHandler.cs │ │ │ ├── BroadphaseHandler.cs │ │ │ ├── CollisionFilterHandler.cs │ │ │ ├── EndContactHandler.cs │ │ │ ├── OnCollisionHandler.cs │ │ │ └── OnSeparationHandler.cs │ │ ├── Narrowphase/ │ │ │ ├── ClipVertex.cs │ │ │ ├── CollideCircle.cs │ │ │ ├── CollideEdge.cs │ │ │ ├── CollidePolygon.cs │ │ │ ├── Collision.cs │ │ │ ├── EPAxis.cs │ │ │ ├── EPAxisType.cs │ │ │ ├── EPCollider.cs │ │ │ ├── Manifold.cs │ │ │ ├── ManifoldPoint.cs │ │ │ ├── ManifoldType.cs │ │ │ ├── PointState.cs │ │ │ ├── ReferenceFace.cs │ │ │ ├── Simplex.cs │ │ │ ├── SimplexCache.cs │ │ │ ├── SimplexVertex.cs │ │ │ └── WorldManifold.cs │ │ ├── RayCast/ │ │ │ ├── RayCastInput.cs │ │ │ └── RayCastOutput.cs │ │ ├── RayCastHelper.cs │ │ ├── Shapes/ │ │ │ ├── ChainShape.cs │ │ │ ├── CircleShape.cs │ │ │ ├── EdgeShape.cs │ │ │ ├── MassData.cs │ │ │ ├── PolygonShape.cs │ │ │ ├── Shape.cs │ │ │ └── ShapeType.cs │ │ ├── TOI/ │ │ │ ├── SeparationFunction.cs │ │ │ ├── SeparationFunctionType.cs │ │ │ ├── Sweep.cs │ │ │ ├── TOIInput.cs │ │ │ ├── TOIOutput.cs │ │ │ ├── TOIOutputState.cs │ │ │ └── TimeOfImpact.cs │ │ └── TestPointHelper.cs │ ├── Dynamics/ │ │ ├── Body.cs │ │ ├── BodyFlags.cs │ │ ├── BodyType.cs │ │ ├── Fixture.cs │ │ ├── FixtureProxy.cs │ │ ├── Handlers/ │ │ │ ├── BodyHandler.cs │ │ │ ├── ControllerHandler.cs │ │ │ ├── FixtureHandler.cs │ │ │ ├── JointHandler.cs │ │ │ ├── PostSolveHandler.cs │ │ │ └── PreSolveHandler.cs │ │ ├── Joints/ │ │ │ ├── AngleJoint.cs │ │ │ ├── DistanceJoint.cs │ │ │ ├── FixedMouseJoint.cs │ │ │ ├── FrictionJoint.cs │ │ │ ├── GearJoint.cs │ │ │ ├── Joint.cs │ │ │ ├── JointEdge.cs │ │ │ ├── JointType.cs │ │ │ ├── LimitState.cs │ │ │ ├── MotorJoint.cs │ │ │ ├── PrismaticJoint.cs │ │ │ ├── PulleyJoint.cs │ │ │ ├── RevoluteJoint.cs │ │ │ ├── RopeJoint.cs │ │ │ ├── WeldJoint.cs │ │ │ └── WheelJoint.cs │ │ ├── Solver/ │ │ │ ├── ContactPositionConstraint.cs │ │ │ ├── ContactSolver.cs │ │ │ ├── ContactVelocityConstraint.cs │ │ │ ├── Island.cs │ │ │ ├── Position.cs │ │ │ ├── PositionSolverManifold.cs │ │ │ ├── SolverData.cs │ │ │ ├── Velocity.cs │ │ │ └── VelocityConstraintPoint.cs │ │ ├── TimeStep.cs │ │ └── World.cs │ ├── Extensions/ │ │ ├── Controllers/ │ │ │ ├── Buoyancy/ │ │ │ │ └── BuoyancyController.cs │ │ │ ├── ControllerBase/ │ │ │ │ ├── Controller.cs │ │ │ │ ├── ControllerFilter.cs │ │ │ │ └── ControllerType.cs │ │ │ ├── Gravity/ │ │ │ │ ├── GravityController.cs │ │ │ │ └── GravityType.cs │ │ │ ├── Velocity/ │ │ │ │ └── VelocityLimitController.cs │ │ │ └── Wind/ │ │ │ ├── AbstractForceController.cs │ │ │ └── SimpleWindForce.cs │ │ ├── DebugView/ │ │ │ ├── DebugViewBase.cs │ │ │ └── DebugViewFlags.cs │ │ └── PhysicsLogics/ │ │ ├── Explosion/ │ │ │ ├── RayDataComparer.cs │ │ │ ├── RealExplosion.cs │ │ │ └── SimpleExplosion.cs │ │ └── PhysicsLogicBase/ │ │ ├── FilterData.cs │ │ ├── PhysicsLogic.cs │ │ ├── PhysicsLogicFilter.cs │ │ ├── PhysicsLogicType.cs │ │ └── ShapeData.cs │ ├── Factories/ │ │ ├── BodyFactory.cs │ │ ├── FixtureFactory.cs │ │ └── JointFactory.cs │ ├── Primitives/ │ │ ├── Curve.cs │ │ ├── CurveContinuity.cs │ │ ├── CurveKey.cs │ │ ├── CurveKeyCollection.cs │ │ ├── CurveLoopType.cs │ │ ├── CurveTangent.cs │ │ ├── MathHelper.cs │ │ ├── Matrix.cs │ │ ├── Vector2.cs │ │ └── Vector3.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── Settings.cs │ ├── Shared/ │ │ ├── AABB.cs │ │ ├── Benchmark.cs │ │ ├── BenchmarkRun.cs │ │ ├── Contracts/ │ │ │ ├── Contract.cs │ │ │ ├── EnsuresException.cs │ │ │ └── RequiredException.cs │ │ ├── Graph.cs │ │ ├── GraphNode.cs │ │ ├── Mat22.cs │ │ ├── Mat33.cs │ │ ├── Optimization/ │ │ │ ├── FixedArray2.cs │ │ │ ├── FixedArray3.cs │ │ │ └── IPoolable.cs │ │ ├── PolygonError.cs │ │ ├── Pool.cs │ │ ├── Rot.cs │ │ ├── Transform.cs │ │ └── Vertices.cs │ ├── Templates/ │ │ ├── BodyTemplate.cs │ │ ├── FixtureTemplate.cs │ │ ├── IDefaults.cs │ │ ├── Joints/ │ │ │ ├── DistanceJointTemplate.cs │ │ │ ├── FrictionJointTemplate.cs │ │ │ ├── GearJointTemplate.cs │ │ │ ├── JointTemplate.cs │ │ │ ├── MotorJointTemplate.cs │ │ │ ├── MouseJointTemplate.cs │ │ │ ├── PrismaticJointTemplate.cs │ │ │ ├── PulleyJointTemplate.cs │ │ │ ├── RevoluteJointTemplate.cs │ │ │ ├── RopeJointTemplate.cs │ │ │ ├── WeldJointTemplate.cs │ │ │ └── WheelJointTemplate.cs │ │ └── Shapes/ │ │ ├── ChainShapeTemplate.cs │ │ ├── CircleShapeTemplate.cs │ │ ├── EdgeShapeTemplate.cs │ │ ├── PolygonShapeTemplate.cs │ │ └── ShapeTemplate.cs │ ├── Tools/ │ │ ├── ConvexHull/ │ │ │ ├── ChainHull/ │ │ │ │ └── ChainHull.cs │ │ │ ├── GiftWrap/ │ │ │ │ └── GiftWrap.cs │ │ │ └── Melkman/ │ │ │ └── Melkman.cs │ │ ├── Cutting/ │ │ │ ├── Simple/ │ │ │ │ ├── CuttingTools.cs │ │ │ │ ├── PolyClipError.cs │ │ │ │ └── PolyClipType.cs │ │ │ └── YuPengClipper.cs │ │ ├── PathGenerator/ │ │ │ ├── LinkFactory.cs │ │ │ ├── Path.cs │ │ │ └── PathManager.cs │ │ ├── PolygonManipulation/ │ │ │ ├── SimpleCombiner.cs │ │ │ └── SimplifyTools.cs │ │ ├── TextureTools/ │ │ │ ├── MarchingSquares.cs │ │ │ ├── Terrain.cs │ │ │ ├── TextureConverter.cs │ │ │ └── VerticesDetectionType.cs │ │ └── Triangulation/ │ │ ├── Bayazit/ │ │ │ └── BayazitDecomposer.cs │ │ ├── Delaunay/ │ │ │ ├── CDTDecomposer.cs │ │ │ ├── Delaunay/ │ │ │ │ ├── DelaunayTriangle.cs │ │ │ │ └── Sweep/ │ │ │ │ ├── AdvancingFront.cs │ │ │ │ ├── AdvancingFrontNode.cs │ │ │ │ ├── DTSweep.cs │ │ │ │ ├── DTSweepConstraint.cs │ │ │ │ ├── DTSweepContext.cs │ │ │ │ ├── DTSweepPointComparator.cs │ │ │ │ └── PointOnEdgeException.cs │ │ │ ├── Orientation.cs │ │ │ ├── Polygon/ │ │ │ │ ├── Polygon.cs │ │ │ │ ├── PolygonPoint.cs │ │ │ │ └── PolygonSet.cs │ │ │ ├── Sets/ │ │ │ │ ├── ConstrainedPointSet.cs │ │ │ │ └── PointSet.cs │ │ │ ├── Triangulatable.cs │ │ │ ├── TriangulationConstraint.cs │ │ │ ├── TriangulationContext.cs │ │ │ ├── TriangulationMode.cs │ │ │ ├── TriangulationPoint.cs │ │ │ ├── TriangulationUtil.cs │ │ │ └── Util/ │ │ │ ├── PointGenerator.cs │ │ │ └── PolygonGenerator.cs │ │ ├── Earclip/ │ │ │ ├── EarclipDecomposer.cs │ │ │ └── Triangle.cs │ │ ├── FlipCode/ │ │ │ └── FlipcodeDecomposer.cs │ │ ├── Seidel/ │ │ │ ├── Edge.cs │ │ │ ├── MonotoneMountain.cs │ │ │ ├── Node.cs │ │ │ ├── Point.cs │ │ │ ├── QueryGraph.cs │ │ │ ├── SeidelDecomposer.cs │ │ │ ├── Sink.cs │ │ │ ├── Trapezoid.cs │ │ │ ├── TrapezoidalMap.cs │ │ │ ├── Triangulator.cs │ │ │ ├── XNode.cs │ │ │ └── YNode.cs │ │ └── TriangulationBase/ │ │ ├── Triangulate.cs │ │ └── TriangulationAlgorithm.cs │ ├── Utilities/ │ │ ├── ConvertUnits.cs │ │ ├── LineUtils.cs │ │ ├── MathUtils.cs │ │ └── PolygonUtils.cs │ ├── VelcroPhysics.MonoGame.csproj │ ├── VelcroPhysics.csproj │ └── packages.config └── changes.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: egordorichev custom: https://paypal.me/egordorichev ================================================ FILE: .github/workflows/deploy-steam.yml ================================================ name: Build BurningKnight on: push: branches: - release - dev jobs: build: name: Build BurningKnight runs-on: windows-2019 steps: - name: Download MonoGame shell: powershell run: | dotnet --info dotnet tool install -g dotnet-mgcb # wget -O MonoGameSetup.exe https://github.com/MonoGame/MonoGame/releases/download/v3.7/MonoGameSetup.exe #- name: Install MonoGame # shell: cmd # run: | # MonoGameSetup.exe /S - name: Checkout uses: actions/checkout@v1 - name: Install NuGet shell: powershell run: | wget -O nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - name: Install NuGet packages shell: bash run: | ls -l mkdir packages cd packages ../nuget.exe install ../Lens/packages.config ../nuget.exe install ../Aseprite/packages.config ../nuget.exe install ../BurningKnight/packages.config ../nuget.exe install ../Desktop/packages.config ../nuget.exe install ../MonoGamePico8/packages.config ../nuget.exe install ../Pico8Emulator/packages.config ls -l cd .. echo $GITHUB_WORKSPACE ./nuget.exe restore ./VelcroPhysics/packages.config -SolutionDirectory $GITHUB_WORKSPACE dotnet restore - name: Building Aseprite Extention shell: bash run: | cd $GITHUB_WORKSPACE ls -l "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/MSBuild.exe" ./Aseprite/Aseprite.csproj ls -l - name: Building Resources shell: bash run: | cd $GITHUB_WORKSPACE/BurningKnight/Content/ mgcb "Content.mgcb" /platform:DesktopGL ls -l - name: Building Solution shell: bash run: | cd $GITHUB_WORKSPACE "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/MSBuild.exe" ./Lens.sln /property:Configuration=Release cd $GITHUB_WORKSPACE/Desktop/bin/Release git init git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add * git commit -m "Added changes" cd $GITHUB_WORKSPACE - name: Push Build to egordorichev/bk_builds uses: ad-m/github-push-action@master with: github_token: ${{ secrets.GITHUB_KEY }} force: true repository: "egordorichev/bk_builds" directory: "./Desktop/bin/Release/" branch: "master" # - name: Upload Windows Version to Itch # shell: powershell # env: # BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }} # run: | # ./butler.exe push ./Windows/ egordorichev/bkt:windows # - name: Prepare Linux Version # shell: bash # run: | # mkdir ./Linux # cp -rf ./Windows/* ./Linux/ # git clone https://github.com/egordorichev/bk_linux_kick # cp -rf ./bk_linux_kick/* ./Linux/ # cd ./Linux # ls # cd .. # # - name: Upload Linux Version to Itch # shell: powershell # env: # BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }} # run: | # ./butler.exe push ./Linux/ egordorichev/bkt:linux # # - name: Upload windows build to linux # uses: actions/upload-artifact@v1 # with: # name: Windows # path: Windows # # - name: Upload linux build to linux # uses: actions/upload-artifact@v1 # with: # name: Linux # path: Linux # # upload: # needs: build # name: Push BurningKnight to Steam # runs-on: ubuntu-18.04 # steps: # - name: Download windows # uses: actions/download-artifact@v1 # with: # name: Windows # - name: Download linux # uses: actions/download-artifact@v1 # with: # name: Linux # - name: Upload depots to steam # shell: bash # run: | # git clone "https://${{ secrets.GITHUB_KEY }}@github.com/egordorichev/steam_builder.git" # mkdir ~/.steam/steam/ -p # cp ./steam_builder/ssfn2631791037380626867 ~/.steam/steam/ # ls -l ~/.steam/steam # mkdir -p ./steam_builder/tools/ContentBuilder/builder/public/ # cp ./steam_builder/steambootstrapper_english.txt ./steam_builder/tools/ContentBuilder/builder/public/ # ls -l ./steam_builder/tools/ContentBuilder/builder/public/ # cd steam_builder/tools/ContentBuilder # mkdir ./content/Windows # cp ../../../Windows/* ./content/Windows/ -r # ls -l ./content/Windows/ # mkdir ./content/Linux # cp ../../../Linux/* ./content/Linux/ -r # ls -l ./content/Linux/ # chmod a+x builder_linux/steamcmd.sh # chmod a+x builder_linux/linux32/steamcmd # builder_linux/steamcmd.sh +login "${{ secrets.STEAM_USERNAME }}" "${{ secrets.STEAM_PASSWORD }}" +run_app_build ../scripts/app_build_851150.vdf +quit ================================================ FILE: .gitignore ================================================ *.idea/* .git */bin/* */obj/* BurningKnight/Content/bin/Sfx BurningKnight/Content/bin/Music BurningKnight/Content/obj* BurningKnight/Content/obj/** packages/* BurningKnight/achievement_sprites* *.exe *.pdb *.dll *SharpDx.* *mgfxc.* SharpDX.xml SharpDX.D3DCompiler.xml ================================================ FILE: Aseprite/Aseprite.csproj ================================================  Debug x64 {13C6F252-0B3C-4A22-A9DB-270C76657FAB} Library Properties Aseprite Aseprite v4.7.2 win-x64 512 x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 ..\packages\MonoGame.Framework.Portable.3.7.1.189\lib\portable-net45+win8+wpa81\MonoGame.Framework.dll True ..\packages\MonoGame.Framework.Content.Pipeline.Portable.3.7.1.189\lib\portable-net45+win8+wpa81\MonoGame.Framework.Content.Pipeline.dll True ..\packages\NVorbis.0.8.6\lib\net35\NVorbis.dll True ..\packages\NVorbis.OpenTKSupport.1.2.0\lib\net35\NVorbis.OpenTKSupport.dll True ..\packages\OpenTK.3.0.1\lib\net20\OpenTK.dll True ================================================ FILE: Aseprite/AsepriteAnimation.cs ================================================ namespace Aseprite { public class AsepriteAnimation { public int FirstFrame; public int LastFrame; public string Name; public AsepriteTag.LoopDirections Directions; } } ================================================ FILE: Aseprite/AsepriteFile.cs ================================================ using System.Collections.Generic; using System; using System.IO; using System.IO.Compression; using System.Text; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Graphics; namespace Aseprite { public enum Modes { Indexed = 1, Grayscale = 2, RGBA = 4 } public class AsepriteFile { public Modes Mode; public int Width; public int Height; public List Frames = new List(); public List Layers = new List(); public List Tags = new List(); public List Slices = new List(); public Dictionary Animations = new Dictionary(); public Texture2D Texture; private enum Chunks { OldPaletteA = 0x0004, OldPaletteB = 0x0011, Layer = 0x2004, Cel = 0x2005, CelExtra = 0x2006, Mask = 0x2016, Path = 0x2017, FrameTags = 0x2018, Palette = 0x2019, UserData = 0x2020, Slice = 0x2022 } private enum CelTypes { RawCel = 0, LinkedCel = 1, CompressedImage = 2 } public AsepriteFile() { } public AsepriteFile(string filename) : this(filename, null) { int framesCount = Frames.Count; int layersCount = Layers.Count; int textureWidth = framesCount * Width; int textureHeight = layersCount * Height; int width = Width; int height = Height; int size = textureWidth * (textureHeight + 1); var pixelData = new Color[size]; for (int f = 0; f < framesCount; f++) { var frame = Frames[f]; for (int i = 0; i < frame.Cels.Count; i++) { var cel = frame.Cels[i]; var celWidth = cel.Width; var celHeight = cel.Height; var addX = cel.X; var addY = cel.Y; for (int celY = 0; celY < celHeight; celY++) { for (int celX = 0; celX < celWidth; celX++) { int ind = celX + celY * cel.Width; var pixel = cel.Pixels[ind]; pixelData[(f * width) + celX + addX + ((i * height) + celY + addY) * textureWidth] = pixel; } } } } Texture = new Texture2D(AsepriteReader.GraphicsDevice, textureWidth, textureHeight + 1); Texture.SetData(pixelData); } public AsepriteFile(string filename, ContentBuildLogger logger) { using (var stream = File.OpenRead(filename)) { var reader = new BinaryReader(stream); #region File helpers // Helpers for translating the Aseprite file format reference // See: https://github.com/aseprite/aseprite/blob/master/docs/ase-file-specs.md byte BYTE() { return reader.ReadByte(); } ushort WORD() { return reader.ReadUInt16(); } short SHORT() { return reader.ReadInt16(); } uint DWORD() { return reader.ReadUInt32(); } long LONG() { return reader.ReadInt32(); } string STRING() { return Encoding.UTF8.GetString(BYTES(WORD())); } byte[] BYTES(int number) { return reader.ReadBytes(number); } void SEEK(int number) { reader.BaseStream.Position += number; } #endregion #region Consume header int frameCount; { DWORD(); // Magic number var magic = WORD(); if (magic != 0xA5e0) { throw new Exception("File doesn't appear to be from Aseprite."); } // Basic info frameCount = WORD(); Width = WORD(); Height = WORD(); Mode = (Modes) (WORD() / 8); logger?.LogMessage($"Cels are {Width}x{Height}, mode is {Mode}"); // Ignore a bunch of stuff DWORD(); // Flags WORD(); // Speed (deprecated) DWORD(); // 0 DWORD(); // 0 BYTE(); // Palette entry SEEK(3); // Ignore these bytes WORD(); // Number of colors (0 means 256 for old sprites) BYTE(); // Pixel width BYTE(); // Pixel height SEEK(92); // For Future } #endregion #region Actual data // Some temporary holders var colorBuffer = new byte[Width * Height * (int) Mode]; var palette = new Color[256]; IUserData lastUserData = null; for (int i = 0; i < frameCount; i++) { var frame = new AsepriteFrame(); Frames.Add(frame); long frameStart; long frameEnd; int chunkCount; // Frame header { frameStart = reader.BaseStream.Position; frameEnd = frameStart + DWORD(); WORD(); // Magic number (always 0xF1FA) chunkCount = WORD(); frame.Duration = WORD() / 1000f; SEEK(6); // For future (set to zero) } for (int j = 0; j < chunkCount; j++) { long chunkStart; long chunkEnd; Chunks chunkType; // Chunk header { chunkStart = reader.BaseStream.Position; chunkEnd = chunkStart + DWORD(); chunkType = (Chunks) WORD(); } // Layer if (chunkType == Chunks.Layer) { var layer = new AsepriteLayer(); layer.Flag = (AsepriteLayer.Flags) WORD(); layer.Type = (AsepriteLayer.Types) WORD(); layer.ChildLevel = WORD(); WORD(); // width WORD(); // height layer.BlendMode = (AsepriteLayer.BlendModes) WORD(); layer.Opacity = BYTE() / 255f; SEEK(3); layer.Name = STRING(); lastUserData = layer; Layers.Add(layer); } else if (chunkType == Chunks.Cel) { // Cell var cel = new AsepriteCel(); var layerIndex = WORD(); cel.Layer = Layers[layerIndex]; // Layer is row (Frame is column) cel.X = SHORT(); cel.Y = SHORT(); cel.Opacity = BYTE() / 255f; var celType = (CelTypes) WORD(); SEEK(7); if (celType == CelTypes.RawCel || celType == CelTypes.CompressedImage) { cel.Width = WORD(); cel.Height = WORD(); var byteCount = cel.Width * cel.Height * (int) Mode; if (celType == CelTypes.RawCel) { reader.Read(colorBuffer, 0, byteCount); } else { SEEK(2); var deflate = new DeflateStream(reader.BaseStream, CompressionMode.Decompress); deflate.Read(colorBuffer, 0, byteCount); } cel.Pixels = new Color[cel.Width * cel.Height]; ConvertBytesToPixels(colorBuffer, cel.Pixels, palette); } else if (celType == CelTypes.LinkedCel) { var targetFrame = WORD(); // Frame position to link with // Grab the cel from a previous frame var targetCel = Frames[targetFrame].Cels.Where(c => c.Layer == Layers[layerIndex]).First(); cel.Width = targetCel.Width; cel.Height = targetCel.Height; cel.Pixels = targetCel.Pixels; } lastUserData = cel; frame.Cels.Add(cel); } else if (chunkType == Chunks.Palette) { // Palette var size = DWORD(); var start = DWORD(); var end = DWORD(); SEEK(8); for (int c = 0; c < (end - start) + 1; c++) { var hasName = Calc.IsBitSet(WORD(), 0); palette[start + c] = new Color(BYTE(), BYTE(), BYTE(), BYTE()); if (hasName) { STRING(); // Color name } } } else if (chunkType == Chunks.UserData) { // User data if (lastUserData != null) { var flags = DWORD(); if (Calc.IsBitSet(flags, 0)) { lastUserData.UserDataText = STRING(); } else if (Calc.IsBitSet(flags, 1)) { lastUserData.UserDataColor = new Color(BYTE(), BYTE(), BYTE(), BYTE()); } } } else if (chunkType == Chunks.FrameTags) { // Tag (animation reference) var tagsCount = WORD(); SEEK(8); for (int t = 0; t < tagsCount; t++) { var tag = new AsepriteTag(); tag.From = WORD(); tag.To = WORD(); tag.LoopDirection = (AsepriteTag.LoopDirections) BYTE(); SEEK(8); tag.Color = new Color(BYTE(), BYTE(), BYTE(), (byte) 255); SEEK(1); tag.Name = STRING(); Tags.Add(tag); } } else if (chunkType == Chunks.Slice) { // Slice var slicesCount = DWORD(); var flags = DWORD(); DWORD(); var name = STRING(); for (int s = 0; s < slicesCount; s++) { var slice = new AsepriteSlice(); slice.Name = name; slice.Frame = (int) DWORD(); slice.OriginX = (int) LONG(); slice.OriginY = (int) LONG(); slice.Width = (int) DWORD(); slice.Height = (int) DWORD(); // 9 slice if (Calc.IsBitSet(flags, 0)) { LONG(); // Center X position (relative to slice bounds) LONG(); // Center Y position DWORD(); // Center width DWORD(); // Center height } else if (Calc.IsBitSet(flags, 1)) { // Pivot slice.Pivot = new Point((int) DWORD(), (int) DWORD()); } lastUserData = slice; Slices.Add(slice); } } reader.BaseStream.Position = chunkEnd; } reader.BaseStream.Position = frameEnd; } #endregion } if (logger == null) { return; } // Log out what we found logger.LogMessage("Layers:"); foreach (var layer in Layers) { logger.LogMessage($"\t{layer.Name}"); } logger.LogMessage("Animations:"); foreach (var animation in Tags) { if (animation.To == animation.From) { logger.LogMessage($"\t{animation.Name} => {animation.From + 1}"); } else { logger.LogMessage($"\t{animation.Name} => {animation.From + 1} - {animation.To + 1}"); } } } private void ConvertBytesToPixels(byte[] bytes, Color[] pixels, Color[] palette) { int length = pixels.Length; if (Mode == Modes.RGBA) { for (int pixel = 0, b = 0; pixel < length; pixel++, b += 4) { pixels[pixel].R = (byte) (bytes[b + 0] * bytes[b + 3] / 255); pixels[pixel].G = (byte) (bytes[b + 1] * bytes[b + 3] / 255); pixels[pixel].B = (byte) (bytes[b + 2] * bytes[b + 3] / 255); pixels[pixel].A = bytes[b + 3]; } } else if (Mode == Modes.Grayscale) { for (int pixel = 0, b = 0; pixel < length; pixel++, b += 2) { pixels[pixel].R = pixels[pixel].G = pixels[pixel].B = (byte) (bytes[b + 0] * bytes[b + 1] / 255); pixels[pixel].A = bytes[b + 1]; } } else if (Mode == Modes.Indexed) { for (int pixel = 0; pixel < length; pixel++) { int index = bytes[pixel]; if (index > 0) { pixels[pixel] = palette[index]; } } } } } // UserData are extended chunks that get attached // to other chunks public interface IUserData { string UserDataText { get; set; } Color UserDataColor { get; set; } } // A layer stores just the meta info for a row of cels public class AsepriteLayer : IUserData { [Flags] public enum Flags { Visible = 1, Editable = 2, LockMovement = 4, Background = 8, PreferLinkedCels = 16, Collapsed = 32, Reference = 64 } public enum Types { Normal = 0, Group = 1 } public enum BlendModes { Normal = 0, Multiply = 1, Screen = 2, Overlay = 3, Darken = 4, Lighten = 5, ColorDodge = 6, ColorBurn = 7, HardLight = 8, SoftLight = 9, Difference = 10, Exclusion = 11, Hue = 12, Saturation = 13, Color = 14, Luminosity = 15, Addition = 16, Subtract = 17, Divide = 18 } public Flags Flag; public Types Type; public bool Visible; public string Name; public float Opacity; public BlendModes BlendMode; public int ChildLevel; string IUserData.UserDataText { get; set; } Color IUserData.UserDataColor { get; set; } } // A frame is a column of cels public class AsepriteFrame { public float Duration; public List Cels; public AsepriteFrame() { Cels = new List(); } } // Tags are animation references public class AsepriteTag { public enum LoopDirections { Forward = 0, Reverse = 1, PingPong = 2 } public string Name; public LoopDirections LoopDirection; public int From; public int To; public Color Color; } public struct AsepriteSlice : IUserData { public int Frame; public string Name; public int OriginX; public int OriginY; public int Width; public int Height; public Point? Pivot; string IUserData.UserDataText { get; set; } Color IUserData.UserDataColor { get; set; } } // Cels are just pixel grids public class AsepriteCel : IUserData { public AsepriteLayer Layer; public Color[] Pixels; public int X; public int Y; public int Width; public int Height; public float Opacity; public string UserDataText { get; set; } public Color UserDataColor { get; set; } } } ================================================ FILE: Aseprite/AsepriteImporter.cs ================================================ using Microsoft.Xna.Framework.Content.Pipeline; namespace Aseprite { [ContentImporter(".aseprite", ".ase", DefaultProcessor = "AsepriteProcessor", DisplayName = "Aseprite Importer")] public class AsepriteImporter : ContentImporter { public override AsepriteFile Import(string filename, ContentImporterContext context) { return new AsepriteFile(filename, context.Logger); } } } ================================================ FILE: Aseprite/AsepriteProcessor.cs ================================================ using Microsoft.Xna.Framework.Content.Pipeline; namespace Aseprite { [ContentProcessor(DisplayName = "Aseprite Processor")] public class AsepriteProcessor : ContentProcessor { public override ProcessedAseprite Process(AsepriteFile input, ContentProcessorContext context) { return new ProcessedAseprite { Aseprite = input, Log = context.Logger }; } } public class ProcessedAseprite { public AsepriteFile Aseprite; public ContentBuildLogger Log; } } ================================================ FILE: Aseprite/AsepriteReader.cs ================================================ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; namespace Aseprite { public class AsepriteReader : ContentTypeReader { public static GraphicsDevice GraphicsDevice; protected override AsepriteFile Read(ContentReader input, AsepriteFile existingInstance) { if (existingInstance != null) { return existingInstance; } int width = input.ReadInt32(); int height = input.ReadInt32(); AsepriteFile aseprite = new AsepriteFile { Width = width, Height = height }; // Layers int layersCount = input.ReadInt32(); AsepriteLayer layer; List layersByIndex = new List(); for (int i = 0; i < layersCount; i++) { layer = new AsepriteLayer { Name = input.ReadString(), Opacity = input.ReadSingle(), BlendMode = (AsepriteLayer.BlendModes) input.ReadInt32(), Visible = input.ReadBoolean() }; aseprite.Layers.Add(layer); // Use this for referencing cels down further layersByIndex.Add(layer); } // Frames AsepriteFrame frame; AsepriteCel cel; int framesCount = input.ReadInt32(); int celsCount; int celOriginX; int celOriginY; int celWidth; int celHeight; int textureWidth = framesCount * width; int textureHeight = layersCount * height; Color[] pixelData = new Color[textureWidth * textureHeight]; for (int f = 0; f < framesCount; f++) { frame = new AsepriteFrame { Duration = input.ReadSingle() }; // Cels celsCount = input.ReadInt32(); for (int i = 0; i < celsCount; i++) { int layerIndex = input.ReadInt32(); cel = new AsepriteCel { Layer = layersByIndex[layerIndex] // ClipRect = new Rectangle(f * width, layerIndex * height, width, height) }; frame.Cels.Add(cel); // Get info for the texture celOriginX = input.ReadInt32(); celOriginY = input.ReadInt32(); celWidth = input.ReadInt32(); celHeight = input.ReadInt32(); var addX = cel.X; var addY = cel.Y; for (int celY = celOriginY; celY < celOriginY + celHeight; celY++) { for (int celX = celOriginX; celX < celOriginX + celWidth; celX++) { var pixel = input.ReadColor(); var ind = (f * width) + celX + addX + ((i * height) + celY + addY) * textureWidth; // fixme: debug if check, figure out why texture loads wrong if (ind > -1 && ind < pixelData.Length) { pixelData[ind] = pixel; } } } } aseprite.Frames.Add(frame); } // Dump our pixels into the texture aseprite.Texture = new Texture2D(GraphicsDevice, textureWidth, textureHeight); aseprite.Texture.SetData(pixelData); // Animations int animationsCount = input.ReadInt32(); AsepriteAnimation animation; for (int i = 0; i < animationsCount; i++) { animation = new AsepriteAnimation { Name = input.ReadString(), FirstFrame = input.ReadInt32(), LastFrame = input.ReadInt32(), Directions = (AsepriteTag.LoopDirections) input.ReadByte() }; aseprite.Animations.Add(animation.Name, animation); } // If no animations were added then just add one // that covers all frames if (aseprite.Animations.Count == 0) { animation = new AsepriteAnimation { Name = "Idle", FirstFrame = 0, LastFrame = aseprite.Frames.Count - 1 }; aseprite.Animations.Add(animation.Name, animation); } return aseprite; } } } ================================================ FILE: Aseprite/AsepriteWriter.cs ================================================ using System; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; namespace Aseprite { [ContentTypeWriter] class AsepriteWriter : ContentTypeWriter { protected override void Write(ContentWriter output, ProcessedAseprite value) { AsepriteFile aseprite = value.Aseprite; output.Write(aseprite.Width); output.Write(aseprite.Height); // Layers output.Write(aseprite.Layers.Count); foreach (var layer in aseprite.Layers) { output.Write(layer.Name); output.Write(layer.Opacity); output.Write((int) layer.BlendMode); output.Write(layer.Flag.HasFlag(AsepriteLayer.Flags.Visible)); } // Frames output.Write(aseprite.Frames.Count); var f = 0; foreach (var frame in aseprite.Frames) { output.Write(frame.Duration); output.Write(frame.Cels.Count); for (int i = 0; i < frame.Cels.Count; i++) { var cel = frame.Cels[i]; output.Write(aseprite.Layers.IndexOf(cel.Layer)); output.Write(cel.X); output.Write(cel.Y); output.Write(cel.Width); output.Write(cel.Height); for (int celY = 0; celY < cel.Height; celY++) { for (int celX = 0; celX < cel.Width; celX++) { int ind = celX + celY * cel.Width; output.Write(cel.Pixels[ind]); } } } f++; } // Animations output.Write(aseprite.Tags.Count); foreach (var animation in aseprite.Tags) { output.Write(animation.Name); output.Write(animation.From); output.Write(animation.To); output.Write((byte) animation.LoopDirection); } } public override string GetRuntimeType(TargetPlatform targetPlatform) { Type type = typeof(AsepriteReader); return type.Namespace + ".AsepriteReader, " + type.AssemblyQualifiedName; } public override string GetRuntimeReader(TargetPlatform targetPlatform) { Type type = typeof(AsepriteReader); return type.Namespace + ".AsepriteReader, " + type.Assembly.FullName; } } } ================================================ FILE: Aseprite/AudioFile.cs ================================================ namespace Aseprite { public class AudioFile { public int SampleRate; public bool Stereo; public float[] Buffer; } } ================================================ FILE: Aseprite/AudioImporter.cs ================================================ using System; using Microsoft.Xna.Framework.Content.Pipeline; namespace Aseprite { [ContentImporter(".ogg", DefaultProcessor = "AudioProcessor", DisplayName = "Audio Importer")] public class AudioImporter : ContentImporter { public static AudioFile Load(string filename) { using (var vorbis = new NVorbis.VorbisReader(filename)) { var channels = vorbis.Channels; var sampleRate = vorbis.SampleRate; var channelSize = sampleRate * vorbis.TotalTime.TotalSeconds; var bufferSize = (int) Math.Ceiling(channels * channelSize); var readBuffer = new float[bufferSize]; vorbis.ReadSamples(readBuffer, 0, bufferSize); return new AudioFile { SampleRate = sampleRate, Stereo = channels == 2, Buffer = readBuffer }; } } public override AudioFile Import(string filename, ContentImporterContext context) { return Load(filename); } } } ================================================ FILE: Aseprite/AudioProcessor.cs ================================================ using Microsoft.Xna.Framework.Content.Pipeline; namespace Aseprite { [ContentProcessor(DisplayName = "Audio Processor")] public class AudioProcessor : ContentProcessor { public override AudioFile Process(AudioFile input, ContentProcessorContext context) { return input; } } } ================================================ FILE: Aseprite/AudioReader.cs ================================================ using Microsoft.Xna.Framework.Content; namespace Aseprite { public class AudioReader : ContentTypeReader { protected override AudioFile Read(ContentReader input, AudioFile existingInstance) { if (existingInstance != null) { return existingInstance; } var stereo = input.ReadBoolean(); var sampleRate = input.ReadInt32(); var length = input.ReadInt32(); var buffer = new float[length]; for (var i = 0; i < buffer.Length; i++) { buffer[i] = input.ReadSingle(); } return new AudioFile { Stereo = stereo, SampleRate = sampleRate, Buffer = buffer }; } } } ================================================ FILE: Aseprite/AudioWriter.cs ================================================ using System; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; namespace Aseprite { [ContentTypeWriter] public class AudioWriter : ContentTypeWriter { public override string GetRuntimeType(TargetPlatform targetPlatform) { Type type = typeof(AsepriteReader); return type.Namespace + ".AudioReader, " + type.AssemblyQualifiedName; } public override string GetRuntimeReader(TargetPlatform targetPlatform) { Type type = typeof(AsepriteReader); return type.Namespace + ".AudioReader, " + type.Assembly.FullName; } protected override void Write(ContentWriter output, AudioFile value) { output.Write(value.Stereo); output.Write(value.SampleRate); output.Write(value.Buffer.Length); for (var i = 0; i < value.Buffer.Length; i++) { output.Write(value.Buffer[i]); } } } } ================================================ FILE: Aseprite/Calc.cs ================================================ namespace Aseprite { public static class Calc { public static bool IsBitSet(uint b, int pos) { return (b & (1 << pos)) != 0; } } } ================================================ FILE: Aseprite/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Aseprite")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Aseprite")] [assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("13C6F252-0B3C-4A22-A9DB-270C76657FAB")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: Aseprite/README.md ================================================ # Aseprite loading helper **This is mostly not my code (not written by @egordorichev)** Full credit goes to the author [of this gist](https://gist.github.com/nathanhoad/bf9ddac2e13a5aaa922182005f3da6e5). The task of this package is to allow me to use `.ase` files (Aseprite files) without having to export them. ================================================ FILE: Aseprite/packages.config ================================================  ================================================ FILE: BurningKnight/BK.cs ================================================ using System; using System.Diagnostics; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.assets.mod; using BurningKnight.assets.prefabs; using BurningKnight.level; using BurningKnight.save; using BurningKnight.state; using BurningKnight.util; using Lens; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; using Version = Lens.Version; namespace BurningKnight { public class BK : Engine { public const bool StandMode = false; public const bool Demo = false; public static Version Version = new Version("Bad rock update", 50, 1, 3, 1, 4, Debug); public BK(int width, int height, bool fullscreen) : base(Version, #if DEBUG new DevAssetLoadState(), #else new AssetLoadState(), #endif Rnd.Chance(60) ? "Burning Knight" : $"Burning Knight{(Demo ? " Demo" : "")}: {Titles.Generate()}", width, height, fullscreen) { } protected override void Initialize() { base.Initialize(); SaveManager.Init(); Controls.Load(); Font.Load(); try { ImGuiHelper.Init(); } catch (Exception e) { Log.Error(e); } Weather.Init(); } private static void RunBash(string args) { var process = new Process { StartInfo = new ProcessStartInfo { FileName = "/bin/bash", Arguments = $"-c \"{args}\"", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, } }; process.Start(); var result = process.StandardOutput.ReadToEnd(); process.WaitForExit(); Console.WriteLine(result); } protected override void UnloadContent() { Mods.Destroy(); Items.Destroy(); Prefabs.Destroy(); Lights.DestroySurface(); base.UnloadContent(); } protected override void Update(GameTime gameTime) { base.Update(gameTime); Mods.Update((float) gameTime.ElapsedGameTime.TotalSeconds); } public override void RenderUi() { base.RenderUi(); Mods.Render(); } } } ================================================ FILE: BurningKnight/BurningKnight.csproj ================================================  Debug x64 {D31D0D40-105E-47D5-A5D0-F6E30328BF86} Library Properties BurningKnight BurningKnight v4.7.2 512 7.2 x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 true x64 pdbonly true bin\Release\ TRACE prompt 4 true ..\packages\Facepunch.Steamworks.2.3.3\lib\net46\Facepunch.Steamworks.Win64.dll True ..\packages\ImGui.NET.1.70.0\lib\netstandard2.0\ImGui.NET.dll True ..\packages\Microsoft.Extensions.DependencyInjection.1.1.1\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll True ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.1.1\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll True ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll True ..\packages\MonoGame.Extended.3.8.0\lib\netstandard2.0\MonoGame.Extended.dll True ..\packages\MonoGame.Extended.Graphics.3.8.0\lib\netstandard2.0\MonoGame.Extended.Graphics.dll True ..\packages\MonoGame.Extended.Tiled.3.8.0\lib\netstandard2.0\MonoGame.Extended.Tiled.dll True ..\packages\MonoGame.Framework.DesktopGL.Core.3.8.0.13\lib\net452\MonoGame.Framework.dll True ..\packages\MonoGame.Framework.Content.Pipeline.Portable.3.7.0.1708\lib\portable-net45+win8+wpa81\MonoGame.Framework.Content.Pipeline.dll True ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll True ..\packages\SharpDX.4.0.1\lib\net45\SharpDX.dll True ..\packages\SharpDX.Direct2D1.4.0.1\lib\net45\SharpDX.Direct2D1.dll True ..\packages\SharpDX.Direct3D11.4.0.1\lib\net45\SharpDX.Direct3D11.dll True ..\packages\SharpDX.Direct3D9.4.0.1\lib\net45\SharpDX.Direct3D9.dll True ..\packages\SharpDX.DXGI.4.0.1\lib\net45\SharpDX.DXGI.dll True ..\packages\SharpDX.Mathematics.4.0.1\lib\net45\SharpDX.Mathematics.dll True ..\packages\SharpDX.MediaFoundation.4.0.1\lib\net45\SharpDX.MediaFoundation.dll True ..\packages\SharpDX.XAudio2.4.0.1\lib\net45\SharpDX.XAudio2.dll True ..\packages\SharpDX.XInput.4.0.1\lib\net45\SharpDX.XInput.dll True ..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll True ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll True ..\..\..\..\usr\lib\mono\4.5\Facades\System.Collections.dll ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll True ..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll True ..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll True ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll True ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll True ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll True ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll True ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll True ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll True ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll True ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll True ..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll True ..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll True ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll True ..\..\..\..\usr\lib\mono\4.5\System.Numerics.dll ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll True ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll True ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll True ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0-preview2-26406-04\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll True ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll True ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll True ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll True ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll True ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll True ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll True ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll True ..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll True ..\..\..\..\usr\lib\mono\4.5\Facades\System.Threading.dll ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll True ..\packages\TextCopy.1.7.1\lib\net461\TextCopy.dll True {13c6f252-0b3c-4a22-a9db-270c76657fab} Aseprite {3b26aa2e-0ba2-42dc-ad62-e6c8617f9e4d} Lens {ba524303-7074-4c9e-8650-59e2c1293a56} MonoGamePico8 {ec0602b1-5a17-4cdc-bbb7-f2c5401ff899} Pico8Emulator {4650bd15-4b03-4a7e-98d4-9f8697ed2eb4} VelcroPhysics.MonoGame PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest 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}. ================================================ FILE: BurningKnight/Content/Content.mgcb ================================================ #----------------------------- Global Properties ----------------------------# /outputDir:bin /intermediateDir:obj /platform:DesktopGL /config: /profile:Reach /compress:False #-------------------------------- References --------------------------------# /reference:..\..\Aseprite\bin\Debug\Aseprite.dll /reference:..\..\packages\MonoGame.Framework.Content.Pipeline.Portable.3.7.0.1708\lib\portable-net45+win8+wpa81\MonoGame.Framework.Content.Pipeline.dll /reference:..\..\packages\MonoGame.Extended.Content.Pipeline.1.1.0\tools\MonoGame.Extended.Content.Pipeline.dll #---------------------------------- Content ---------------------------------# #begin Fonts/fnt.spritefont /importer:FontDescriptionImporter /processor:FontDescriptionProcessor /processorParam:PremultiplyAlpha=False /processorParam:TextureFormat=Compressed /build:Fonts/fnt.spritefont #begin Fonts/large.png /importer:TextureImporter /processor:TextureProcessor /processorParam:ColorKeyColor=255,0,255,255 /processorParam:ColorKeyEnabled=True /processorParam:GenerateMipmaps=False /processorParam:PremultiplyAlpha=True /processorParam:ResizeToPowerOfTwo=False /processorParam:MakeSquare=False /processorParam:TextureFormat=Color /build:Fonts/large.png #begin Fonts/small.png /importer:TextureImporter /processor:TextureProcessor /processorParam:ColorKeyColor=255,0,255,255 /processorParam:ColorKeyEnabled=True /processorParam:GenerateMipmaps=False /processorParam:PremultiplyAlpha=True /processorParam:ResizeToPowerOfTwo=False /processorParam:MakeSquare=False /processorParam:TextureFormat=Color /build:Fonts/small.png #begin Music/Believer.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Believer.ogg #begin Music/BK.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/BK.ogg #begin Music/Born to do rogueries.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Born to do rogueries.ogg #begin Music/Botanical Expedition.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Botanical Expedition.ogg #begin Music/chip.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/chip.ogg #begin Music/Cursed legend.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Cursed legend.ogg #begin Music/Fatiga.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Fatiga.ogg #begin Music/Frozen to the bones.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Frozen to the bones.ogg #begin Music/Gobbeon.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Gobbeon.ogg #begin Music/Hidden knowledge.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Hidden knowledge.ogg #begin Music/Hub.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Hub.ogg #begin Music/Last chance.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Last chance.ogg #begin Music/Ma Precious.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Ma Precious.ogg #begin Music/Menu.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Menu.ogg #begin Music/My precious.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/My precious.ogg #begin Music/Nostalgia.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Nostalgia.ogg #begin Music/Outsider.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Outsider.ogg #begin Music/piano.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/piano.ogg #begin Music/Pirate Bay.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Pirate Bay.ogg #begin Music/Reckless.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Reckless.ogg #begin Music/Serendipity.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Serendipity.ogg #begin Music/Shopkeeper.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Shopkeeper.ogg #begin Music/Void.ogg /importer:OggImporter /processor:SongProcessor /processorParam:Quality=Best /build:Music/Void.ogg #begin Sfx/airhorn.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/airhorn.wav #begin Sfx/bomb_placed.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/bomb_placed.wav #begin Sfx/clap.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/clap.wav #begin Sfx/dead1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/dead1.wav #begin Sfx/dead2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/dead2.wav #begin Sfx/dead3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/dead3.wav #begin Sfx/enemy_alert.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/enemy_alert.wav #begin Sfx/explosion.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/explosion.wav #begin Sfx/fireball_cast.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/fireball_cast.wav #begin Sfx/fireball_death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/fireball_death.wav #begin Sfx/gunner_charge.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/gunner_charge.wav #begin Sfx/health_up.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/health_up.wav #begin Sfx/hi.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/hi.wav #begin Sfx/hurt1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/hurt1.wav #begin Sfx/hurt2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/hurt2.wav #begin Sfx/item/active.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/active.wav #begin Sfx/item/active_charged.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/active_charged.wav #begin Sfx/item/axe/catch.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/axe/catch.wav #begin Sfx/item/axe/throw.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/axe/throw.wav #begin Sfx/item/bag.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/bag.wav #begin Sfx/item/bomb.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/bomb.wav #begin Sfx/item/bow/attack.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/bow/attack.wav #begin Sfx/item/cage_key_used.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/cage_key_used.wav #begin Sfx/item/charge.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/charge.wav #begin Sfx/item/coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/coin.wav #begin Sfx/item/dice/bad.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/dice/bad.wav #begin Sfx/item/dice/break.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/dice/break.wav #begin Sfx/item/dice/good.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/dice/good.wav #begin Sfx/item/discord.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/discord.wav #begin Sfx/item/emerald.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/emerald.wav #begin Sfx/item/gold_coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gold_coin.wav #begin Sfx/item/gun/burst.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/burst.wav #begin Sfx/item/gun/fire/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/fire/1.wav #begin Sfx/item/gun/fire/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/fire/2.wav #begin Sfx/item/gun/machine.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/machine.wav #begin Sfx/item/gun/pickup.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/pickup.wav #begin Sfx/item/gun/switch.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/gun/switch.wav #begin Sfx/item/heart.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/heart.wav #begin Sfx/item/key.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/key.wav #begin Sfx/item/key_pickup.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/key_pickup.wav #begin Sfx/item/laser/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/laser/1.wav #begin Sfx/item/laser/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/laser/2.wav #begin Sfx/item/laser/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/laser/3.wav #begin Sfx/item/laser/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/laser/4.wav #begin Sfx/item/laser/player.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/laser/player.wav #begin Sfx/item/magic/lava/lava_appear.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/lava/lava_appear.wav #begin Sfx/item/magic/lava/lava_cast.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/lava/lava_cast.wav #begin Sfx/item/magic/pickup.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/pickup.wav #begin Sfx/item/magic/switch.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/switch.wav #begin Sfx/item/magic/web/appear.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/web/appear.wav #begin Sfx/item/magic/web/cast.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/magic/web/cast.wav #begin Sfx/item/mana.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/mana.wav #begin Sfx/item/map.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/map.wav #begin Sfx/item/meatguy/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/meatguy/1.wav #begin Sfx/item/meatguy/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/meatguy/2.wav #begin Sfx/item/meatguy/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/meatguy/3.wav #begin Sfx/item/meatguy/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/meatguy/4.wav #begin Sfx/item/nocash.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/nocash.wav #begin Sfx/item/orbitals.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/orbitals.wav #begin Sfx/item/pickup.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/pickup.wav #begin Sfx/item/platinum_coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/platinum_coin.wav #begin Sfx/item/purchase.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/purchase.wav #begin Sfx/item/reroll.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/reroll.wav #begin Sfx/item/shield.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/shield.wav #begin Sfx/item/shotgun/fire/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/shotgun/fire/1.wav #begin Sfx/item/shotgun/fire/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/shotgun/fire/2.wav #begin Sfx/item/shotgun/reload/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/shotgun/reload/1.wav #begin Sfx/item/shotgun/reload/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/shotgun/reload/2.wav #begin Sfx/item/silver_coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/silver_coin.wav #begin Sfx/item/sword/attack/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/attack/1.wav #begin Sfx/item/sword/attack/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/attack/2.wav #begin Sfx/item/sword/attack/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/attack/3.wav #begin Sfx/item/sword/attack/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/attack/4.wav #begin Sfx/item/sword/cooldown.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/cooldown.wav #begin Sfx/item/sword/hit/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/hit/1.wav #begin Sfx/item/sword/hit/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/hit/2.wav #begin Sfx/item/sword/hit/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/hit/3.wav #begin Sfx/item/sword/hit/wall.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/hit/wall.wav #begin Sfx/item/sword/pickup.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/pickup.wav #begin Sfx/item/sword/switch.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/sword/switch.wav #begin Sfx/item/ukulele/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/ukulele/1.wav #begin Sfx/item/ukulele/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/ukulele/2.wav #begin Sfx/item/ukulele/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/ukulele/3.wav #begin Sfx/item/ukulele/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/ukulele/4.wav #begin Sfx/item/ukulele/5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/ukulele/5.wav #begin Sfx/item/wand/fire.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/wand/fire.wav #begin Sfx/item/wand/general.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/item/wand/general.wav #begin Sfx/level/chair/break/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/chair/break/1.wav #begin Sfx/level/chair/break/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/chair/break/2.wav #begin Sfx/level/chest_open.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/chest_open.wav #begin Sfx/level/claw/close.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/close.wav #begin Sfx/level/claw/move.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/move.wav #begin Sfx/level/claw/open.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/open.wav #begin Sfx/level/claw/pc.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/pc.wav #begin Sfx/level/claw/start.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/start.wav #begin Sfx/level/claw/stop.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/claw/stop.wav #begin Sfx/level/cleared.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/cleared.wav #begin Sfx/level/cup/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/cup/1.wav #begin Sfx/level/cup/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/cup/2.wav #begin Sfx/level/door/bell.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/bell.wav #begin Sfx/level/door/close/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/close/1.wav #begin Sfx/level/door/close/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/close/2.wav #begin Sfx/level/door/head/fail.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/head/fail.wav #begin Sfx/level/door/head/success.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/head/success.wav #begin Sfx/level/door/open/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/open/1.wav #begin Sfx/level/door/open/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/open/2.wav #begin Sfx/level/door/open/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/open/3.wav #begin Sfx/level/door/open/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/open/4.wav #begin Sfx/level/door/open/5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/open/5.wav #begin Sfx/level/door/shut.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/door/shut.wav #begin Sfx/level/explosion/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/explosion/1.wav #begin Sfx/level/explosion/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/explosion/2.wav #begin Sfx/level/explosion/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/explosion/3.wav #begin Sfx/level/lever.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/lever.wav #begin Sfx/level/rain/jungle.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/rain/jungle.wav #begin Sfx/level/rain/regular.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/rain/regular.wav #begin Sfx/level/rain/snow.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/rain/snow.wav #begin Sfx/level/rock/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/rock/1.wav #begin Sfx/level/rock/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/rock/2.wav #begin Sfx/level/room_cleared.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/room_cleared.wav #begin Sfx/level/scourge_statue.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/scourge_statue.wav #begin Sfx/level/snow_break/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/snow_break/1.wav #begin Sfx/level/snow_break/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/snow_break/2.wav #begin Sfx/level/snow_break/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/snow_break/3.wav #begin Sfx/level/spike.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/spike.wav #begin Sfx/level/spike_peaking.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/spike_peaking.wav #begin Sfx/level/statue_break.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/statue_break.wav #begin Sfx/level/stone_statue_break.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/stone_statue_break.wav #begin Sfx/level/summon_chest.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/summon_chest.wav #begin Sfx/level/teleport/arrive.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/teleport/arrive.wav #begin Sfx/level/teleport/send.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/teleport/send.wav #begin Sfx/level/tnt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/tnt.wav #begin Sfx/level/turret/fire.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/turret/fire.wav #begin Sfx/level/turret/rotating.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/turret/rotating.wav #begin Sfx/level/vending_machine.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/vending_machine.wav #begin Sfx/level/vending_machine_coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/vending_machine_coin.wav #begin Sfx/level/well.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/well.wav #begin Sfx/level/well_coin.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/level/well_coin.wav #begin Sfx/mob/archeolog/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/archeolog/death.wav #begin Sfx/mob/archeolog/explosion.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/archeolog/explosion.wav #begin Sfx/mob/archeolog/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/archeolog/hurt.wav #begin Sfx/mob/bandit/damage.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bandit/damage.wav #begin Sfx/mob/bandit/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bandit/death.wav #begin Sfx/mob/bee/damage.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bee/damage.wav #begin Sfx/mob/bee/shot.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bee/shot.wav #begin Sfx/mob/bee/swirly_shot.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bee/swirly_shot.wav #begin Sfx/mob/bk/capture.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/capture.wav #begin Sfx/mob/bk/fight_loop.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/fight_loop.wav #begin Sfx/mob/bk/fire.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/fire.wav #begin Sfx/mob/bk/flame_loop.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/flame_loop.wav #begin Sfx/mob/bk/hovering_loop.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hovering_loop.wav #begin Sfx/mob/bk/hurt/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hurt/1.wav #begin Sfx/mob/bk/hurt/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hurt/2.wav #begin Sfx/mob/bk/hurt/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hurt/3.wav #begin Sfx/mob/bk/hurt/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hurt/4.wav #begin Sfx/mob/bk/hurt/5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/hurt/5.wav #begin Sfx/mob/bk/roar/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/roar/1.wav #begin Sfx/mob/bk/roar/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/roar/2.wav #begin Sfx/mob/bk/roar/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/roar/3.wav #begin Sfx/mob/bk/roar/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/roar/4.wav #begin Sfx/mob/bk/syllable/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/syllable/1.wav #begin Sfx/mob/bk/syllable/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/syllable/2.wav #begin Sfx/mob/bk/syllable/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/syllable/3.wav #begin Sfx/mob/bk/syllable/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/syllable/4.wav #begin Sfx/mob/bk/syllable/5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/syllable/5.wav #begin Sfx/mob/bk/voice.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/voice.wav #begin Sfx/mob/bk/wave.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/wave.wav #begin Sfx/mob/bk/word/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/word/1.wav #begin Sfx/mob/bk/word/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/word/2.wav #begin Sfx/mob/bk/word/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/bk/word/3.wav #begin Sfx/mob/clown/bomb/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/clown/bomb/1.wav #begin Sfx/mob/clown/bomb/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/clown/bomb/2.wav #begin Sfx/mob/clown/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/clown/death.wav #begin Sfx/mob/clown/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/clown/hurt.wav #begin Sfx/mob/dino/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/dino/death.wav #begin Sfx/mob/dino/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/dino/hurt.wav #begin Sfx/mob/dummy.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/dummy.wav #begin Sfx/mob/fire.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/fire.wav #begin Sfx/mob/fire_static.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/fire_static.wav #begin Sfx/mob/fire_wall.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/fire_wall.wav #begin Sfx/mob/flower/charging.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/flower/charging.wav #begin Sfx/mob/flower/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/flower/death.wav #begin Sfx/mob/flower/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/flower/hurt.wav #begin Sfx/mob/fly_death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/fly_death.wav #begin Sfx/mob/ghost/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/ghost/death.wav #begin Sfx/mob/ghost/hurt_1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/ghost/hurt_1.wav #begin Sfx/mob/ghost/hurt_2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/ghost/hurt_2.wav #begin Sfx/mob/gunner/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/gunner/death.wav #begin Sfx/mob/gunner/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/gunner/hurt.wav #begin Sfx/mob/hive/breaking.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hive/breaking.wav #begin Sfx/mob/hive/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hive/hurt.wav #begin Sfx/mob/hive/pop.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hive/pop.wav #begin Sfx/mob/hive/release.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hive/release.wav #begin Sfx/mob/hive/static.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hive/static.wav #begin Sfx/mob/hugger_death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/hugger_death.wav #begin Sfx/mob/mummy/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/mummy/death.wav #begin Sfx/mob/mummy/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/mummy/hurt.wav #begin Sfx/mob/oldking/explode.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/oldking/explode.wav #begin Sfx/mob/oldking/jump.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/oldking/jump.wav #begin Sfx/mob/oldking/land.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/oldking/land.wav #begin Sfx/mob/oldking/shoot.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/oldking/shoot.wav #begin Sfx/mob/pharaoh/adidos.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/pharaoh/adidos.wav #begin Sfx/mob/pharaoh/appear.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/pharaoh/appear.wav #begin Sfx/mob/pharaoh/shot.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/pharaoh/shot.wav #begin Sfx/mob/pharaoh/shot_wave.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/pharaoh/shot_wave.wav #begin Sfx/mob/pharaoh/summon.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/pharaoh/summon.wav #begin Sfx/mob/skeleton/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/skeleton/death.wav #begin Sfx/mob/skeleton/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/skeleton/hurt.wav #begin Sfx/mob/slime/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/slime/death.wav #begin Sfx/mob/slime/jump_1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/slime/jump_1.wav #begin Sfx/mob/slime/jump_2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/slime/jump_2.wav #begin Sfx/mob/slime/land_1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/slime/land_1.wav #begin Sfx/mob/slime/land_2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/slime/land_2.wav #begin Sfx/mob/sniper/focus.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/sniper/focus.wav #begin Sfx/mob/snowball/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/snowball/death.wav #begin Sfx/mob/snowball/hut.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/snowball/hut.wav #begin Sfx/mob/snowman/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/snowman/death.wav #begin Sfx/mob/snowman/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/snowman/hurt.wav #begin Sfx/mob/spelunker/beep.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/spelunker/beep.wav #begin Sfx/mob/wizard/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/wizard/death.wav #begin Sfx/mob/wizard/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/wizard/hurt.wav #begin Sfx/mob/wombat/fly.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/wombat/fly.wav #begin Sfx/mob/worm_death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/mob/worm_death.wav #begin Sfx/npc/beet/hide.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/beet/hide.wav #begin Sfx/npc/beet/show.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/beet/show.wav #begin Sfx/npc/voice/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/1.wav #begin Sfx/npc/voice/10.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/10.wav #begin Sfx/npc/voice/11.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/11.wav #begin Sfx/npc/voice/12.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/12.wav #begin Sfx/npc/voice/13.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/13.wav #begin Sfx/npc/voice/14.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/14.wav #begin Sfx/npc/voice/15.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/15.wav #begin Sfx/npc/voice/16.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/16.wav #begin Sfx/npc/voice/17.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/17.wav #begin Sfx/npc/voice/18.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/18.wav #begin Sfx/npc/voice/19.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/19.wav #begin Sfx/npc/voice/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/2.wav #begin Sfx/npc/voice/20.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/20.wav #begin Sfx/npc/voice/21.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/21.wav #begin Sfx/npc/voice/22.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/22.wav #begin Sfx/npc/voice/23.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/23.wav #begin Sfx/npc/voice/24.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/24.wav #begin Sfx/npc/voice/25.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/25.wav #begin Sfx/npc/voice/26.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/26.wav #begin Sfx/npc/voice/27.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/27.wav #begin Sfx/npc/voice/28.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/28.wav #begin Sfx/npc/voice/29.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/29.wav #begin Sfx/npc/voice/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/3.wav #begin Sfx/npc/voice/30.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/30.wav #begin Sfx/npc/voice/4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/4.wav #begin Sfx/npc/voice/5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/5.wav #begin Sfx/npc/voice/6.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/6.wav #begin Sfx/npc/voice/7.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/7.wav #begin Sfx/npc/voice/8.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/8.wav #begin Sfx/npc/voice/9.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/npc/voice/9.wav #begin Sfx/player/cursed.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/cursed.wav #begin Sfx/player/death.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/death.wav #begin Sfx/player/descending.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/descending.wav #begin Sfx/player/hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/hurt.wav #begin Sfx/player/low_hp_hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/low_hp_hurt.wav #begin Sfx/player/roll.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/roll.wav #begin Sfx/player/shield_hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/shield_hurt.wav #begin Sfx/player/step/default/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/default/1.wav #begin Sfx/player/step/gold/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/gold/1.wav #begin Sfx/player/step/gold/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/gold/2.wav #begin Sfx/player/step/gold/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/gold/3.wav #begin Sfx/player/step/grass/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/grass/1.wav #begin Sfx/player/step/grass/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/grass/2.wav #begin Sfx/player/step/grass/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/grass/3.wav #begin Sfx/player/step/ice/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/ice/1.wav #begin Sfx/player/step/ice/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/ice/2.wav #begin Sfx/player/step/ice/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/ice/3.wav #begin Sfx/player/step/sand/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/sand/1.wav #begin Sfx/player/step/sand/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/sand/2.wav #begin Sfx/player/step/sand/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/sand/3.wav #begin Sfx/player/step/snow/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/snow/1.wav #begin Sfx/player/step/snow/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/snow/2.wav #begin Sfx/player/step/snow/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/snow/3.wav #begin Sfx/player/step/stone/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/stone/1.wav #begin Sfx/player/step/stone/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/stone/2.wav #begin Sfx/player/step/stone/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/stone/3.wav #begin Sfx/player/step/water/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/water/1.wav #begin Sfx/player/step/water/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/water/2.wav #begin Sfx/player/step/water/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/water/3.wav #begin Sfx/player/step/wood/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/wood/1.wav #begin Sfx/player/step/wood/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/wood/2.wav #begin Sfx/player/step/wood/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/player/step/wood/3.wav #begin Sfx/projectile/reflected/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/reflected/1.wav #begin Sfx/projectile/reflected/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/reflected/2.wav #begin Sfx/projectile/shell/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/shell/1.wav #begin Sfx/projectile/shell/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/shell/2.wav #begin Sfx/projectile/shell/3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/shell/3.wav #begin Sfx/projectile/wall/1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/wall/1.wav #begin Sfx/projectile/wall/2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/wall/2.wav #begin Sfx/projectile/wall/enemy.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/projectile/wall/enemy.wav #begin Sfx/quck.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/quck.wav #begin Sfx/sand.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/sand.wav #begin Sfx/scroll.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/scroll.wav #begin Sfx/secret.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/secret.wav #begin Sfx/slime_hurt.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/slime_hurt.wav #begin Sfx/swap.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/swap.wav #begin Sfx/take.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/take.wav #begin Sfx/ui/achievement.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/achievement.wav #begin Sfx/ui/change_parameter.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/change_parameter.wav #begin Sfx/ui/exit.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/exit.wav #begin Sfx/ui/goback.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/goback.wav #begin Sfx/ui/moving.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/moving.wav #begin Sfx/ui/select.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/select.wav #begin Sfx/ui/start.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/ui/start.wav #begin Sfx/unlock.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/unlock.wav #begin Sfx/villager1.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager1.wav #begin Sfx/villager2.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager2.wav #begin Sfx/villager3.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager3.wav #begin Sfx/villager4.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager4.wav #begin Sfx/villager5.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager5.wav #begin Sfx/villager6.wav /importer:WavImporter /processor:SoundEffectProcessor /processorParam:Quality=Best /build:Sfx/villager6.wav #begin Shaders/bk.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/bk.fx #begin Shaders/chasm.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/chasm.fx #begin Shaders/entity.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/entity.fx #begin Shaders/fog.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/fog.fx #begin Shaders/item.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/item.fx #begin Shaders/screen.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/screen.fx #begin Shaders/terrain.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/terrain.fx #begin Shaders/ui.fx /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:Shaders/ui.fx #begin Textures/light.png /importer:TextureImporter /processor:TextureProcessor /processorParam:ColorKeyColor=255,0,255,255 /processorParam:ColorKeyEnabled=True /processorParam:GenerateMipmaps=False /processorParam:PremultiplyAlpha=True /processorParam:ResizeToPowerOfTwo=False /processorParam:MakeSquare=False /processorParam:TextureFormat=Color /build:Textures/light.png #begin Textures/noise.png /importer:TextureImporter /processor:TextureProcessor /processorParam:ColorKeyColor=255,0,255,255 /processorParam:ColorKeyEnabled=True /processorParam:GenerateMipmaps=False /processorParam:PremultiplyAlpha=True /processorParam:ResizeToPowerOfTwo=False /processorParam:MakeSquare=False /processorParam:TextureFormat=Color /build:Textures/noise.png #begin Textures/rexcellent_logo_pixel.png /importer:TextureImporter /processor:TextureProcessor /processorParam:ColorKeyColor=255,0,255,255 /processorParam:ColorKeyEnabled=True /processorParam:GenerateMipmaps=False /processorParam:PremultiplyAlpha=True /processorParam:ResizeToPowerOfTwo=False /processorParam:MakeSquare=False /processorParam:TextureFormat=Color /build:Textures/rexcellent_logo_pixel.png ================================================ FILE: BurningKnight/Content/Dialogs/accessorytrader.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/activetrader.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/beet.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/bk.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/bk_sign.json ================================================ [{"id":0,"outputs":[[[]]],"type":"Text output","x":327,"y":126},{"id":1,"outputs":[[[]]],"type":"Text output","x":412,"y":249}] ================================================ FILE: BurningKnight/Content/Dialogs/boxy.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/brastin.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":443,"y":95}] ================================================ FILE: BurningKnight/Content/Dialogs/builder.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/charger.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/control.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/dialogs.json ================================================ [] ================================================ FILE: BurningKnight/Content/Dialogs/discord.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":733,"y":220}] ================================================ FILE: BurningKnight/Content/Dialogs/dm.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/duck.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/eg.json ================================================ [{"id":0,"outputs":[[[]],[[]]],"type":"Choice","x":336,"y":234,"cc":2}] ================================================ FILE: BurningKnight/Content/Dialogs/elon.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/fountain.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/gobetta.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/granny.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/hattrader.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/isaac.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/maanex.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/maanex2.json ================================================ [{"id":0,"outputs":[[[]],[[]]],"type":"Choice","x":445,"y":250,"cc":2}] ================================================ FILE: BurningKnight/Content/Dialogs/machine.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":607,"y":218}] ================================================ FILE: BurningKnight/Content/Dialogs/mapuzzle.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":409,"y":238}] ================================================ FILE: BurningKnight/Content/Dialogs/milt.json ================================================ [{"id":1,"outputs":[],"type":"Text","x":303,"y":162}] ================================================ FILE: BurningKnight/Content/Dialogs/mob.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":344,"y":244}] ================================================ FILE: BurningKnight/Content/Dialogs/npc.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/npc_hurt.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/nullptr.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":487,"y":312}] ================================================ FILE: BurningKnight/Content/Dialogs/nurse.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/old_man.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/player.json ================================================ [{"id":0,"outputs":[],"type":"Text","x":441,"y":164}] ================================================ FILE: BurningKnight/Content/Dialogs/roger.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/shopkeeper.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/snek.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/tomb.json ================================================ [{"id":0,"outputs":[[[]]],"type":"Text output","x":536,"y":249}] ================================================ FILE: BurningKnight/Content/Dialogs/trash_goblin.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/twitch.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/vampire.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Dialogs/weapontrader.json ================================================ [{"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}] ================================================ FILE: BurningKnight/Content/Fonts/fnt.spritefont ================================================  fnt.ttf 9 0 true ~ ================================================ FILE: BurningKnight/Content/Fonts/large_font.fnt ================================================  ================================================ FILE: BurningKnight/Content/Fonts/small_font.fnt ================================================  ================================================ FILE: BurningKnight/Content/Locales/by.json ================================================ { "bk:halo": "Нiмб", "bk:halo_desc": "Павелiчэнне HP", "bk:revolver": "Рэвальвер", "bk:sword": "Драýляны Меч", "bk:sword_desc": "Ня проста палка", "bk:heart": "Сэрца", "resume": "Працягнуць", "settings": "Наладкi", "restart": "Пачаць Нанова", "death_message": "Ты Памёр", "descend": "Спусцiцца", "ascend": "Падняцца", "exit": "Выхад", "painting_rexcellent": "Экселлент", "painting_grannylisa": "Граннiлiза", "painting_maanex": "Думацель", "painting_bk": "Падгарэлы Рыцар", "painting_failpositive": "Дыджэй", "painting_old_man": "Ну вееельмi стары стары", "painting_arthouse": "Арт Хаус", "painting_black": "Сусвет", "painting_milt": "Чувак ý снезе", "painting_skyscraper": "Адынокi хмарачос", "painting_egor": "Падпалены дыназавр", "painting_null": "НУЛЬ", "painting_badosz": "Згубiýшiся пацан", "painting_banana": "Бананчык", "painting_tv": "Скрыня на нябёсах", "painting_company": "Балдёжная кампанiя", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Сабака ля Трасевол", "painting_lamp": "Да вазьмi ты яе", "painting_scream": "Марозiва", "painting_stars": "Стремная ноч", "painting_fog": "На морах", "painting_nufflee": "Вуф", "by": "Аýтар", "old_man_0": "Там небяспечна!", "continue_run": "Працягнуть Забег", "new_run": "Новы Забег", "was_unlocked": "Быý Адкрыты!", "bk:revolver_desc": "Рукi ýгору, @everyone!", "bk:shovel": "Сiняя Лапата", "bk:shovel_desc": "А че яна сiняя-то?", "beet_0": "Прiвкi!", "beet_2": "Як назваць?", "npc_hurt_0": "Ой.", "npc_hurt_1": "Блiн, балюча.", "npc_hurt_2": "О нет.", "beet_3": "Пасiбкi <3", "beet_1": "А ты не хочаш пасадзiць ^^насенне^^?", "beet_1_0": "Да!", "beet_1_1": "Не.", "beet_4": "Насенне зараз [vr seed]. Хочаш яе памяняць?", "beet_4_0": "Да!", "beet_4_1": "Не.", "beet_5": "Ну добра.", "beet_4_2": "Хай будзе выпадковым.", "beet_6": "Ок. Насенне зараз [vr seed]!", "bk:idol": "Iдал", "bk:idol_desc": "Схаваная пастка шчоýкнула!", "bk:key": "Залаты Ключык", "bk:infinite_bomb": "Бясконцая Бомба", "bk:infinite_bomb_desc": "Ну амаль", "throw_coin": "Кiнуць Манетку", "bk:potatoo": "Буульба", "bk:potatoo_desc": "Дзелiць Кулi", "bk:spectacles": "Акуляры", "bk:spectacles_desc": "Паказвае Сакрэткi", "bk:cross": "Крыж", "bk:cross_desc": "Павялiчвае час непаражальнасцi", "bk:slime": "Слiзь", "bk:slime_desc": "Прыгучыя кулi", "bk:missile": "Ракета", "bk:missile_desc": "Саманаводка", "bk:rod_of_discord": "Посах Дiскорда", "bk:rod_of_discord_desc": "Тэлепортатор для @everyone", "bk:goo": "Гу", "bk:goo_desc": "Круцельны Сябар", "bk:jelly": "Жэлешка", "bk:jelly_desc": "^^Прыгучая^^", "bk:broken_stone": "Зламаны Камень", "bk:broken_stone_desc": "Моцны Арбiталь", "bk:nano_orb": "Нана Шар", "bk:nano_orb_desc": "Мiкра Сябар", "bk:saturn": "Планета", "bk:saturn_desc": "Зразумела мы яе яшчэ кахаем", "bk:soap": "Мыла", "bk:soap_desc": "Замаруджвае кулi", "bk:d6": "Д6", "bk:d6_desc": "^^Рэролл^^ прадметаý!", "bk:my_heart": "Маё Сэрца", "bk:my_heart_desc": "Павелiчвае HP", "bk:broken_heart": "Разбiтае Сэрца", "bk:broken_heart_desc": "Павелiчвае HP", "bk:parcel": "Пасылка", "bk:parcel_desc": "Аднаýляе здароýе", "bk:glass": "Шкляшка", "bk:glass_desc": "##Крохкiя## кулi", "bk:glass_bullet": "Шкляныя Кулi", "bk:glass_bullet_desc": "Страляй над камянямi", "bk:broken_guitar": "Зламаная Гiтара", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Аýтамат", "bk:machine_gun_desc": "Аýтаматычны", "bk:grenade_launcher": "Базука", "bk:grenade_launcher_desc": "Бум!", "bk:shotgun": "Драбаш", "bk:shotgun_desc": "Соль у твар!", "bk:missile_launcher": "Ракетнiца", "bk:missile_launcher_desc": "Мэта выяýлена", "bk:burst_gun": "Пушка-Фiгулька", "bk:burst_gun_desc": "Фiгня найпоýная", "bk:flak_cannon": "Пушка-Ватрушка", "bk:flak_cannon_desc": "Вечарынка", "bk:disk_gun": "Дыскастрэл", "bk:disk_gun_desc": "Вельмi востры", "bk:duck_gun": "Крякалка", "bk:duck_gun_desc": "Кряк!", "bk:follower": "Паслядоýнiк", "bk:follower_desc": "За мной!", "bk:portal_gun": "Портал Ган", "bk:portal_gun_desc": "Торцiк гэта хлусня", "bk:snowflake": "Сняжынка", "bk:snowflake_desc": "Марозiць усiх", "bk:restock": "Пастаýка", "bk:restock_desc": "Тавар у краме не сканчаецца", "bk:charisma_ring_desc": "Царскiя знiжкi", "bk:charisma_ring": "Харызматычнае Кальцо", "bk:battery": "Батарэйка", "tomb_0": "Тут пахаваны Вялiкi [cl green]Гоблiн[cl]", "bk:homemade_dice": "Самадзельны Кубiк Dice", "bk:homemade_dice_desc": "^^Рэролл^^ прадметаý! (DIY)", "shopkeeper_0": "##Я КАЗАÝ ПЕРАСТАНЬ!##", "shopkeeper_1": "Спынiся!", "shopkeeper_2": "Ня трэба.", "shopkeeper_3": "[cl red]##РЫХТУЙСЯ ДА СМЕРЦI!##", "shopkeeper_4": "[cl red]ВОР!", "shopkeeper_5": "[cl red]ЛАВI ЯГО!", "desert": "Пустынны Замак", "jungle": "Старажытныя Джунглi", "ice": "Ледзяныя Развалiны", "bk:iron_boots": "Стальныя Чаравiкi", "bk:iron_boots_desc": "Шыпы - не перашкода", "bk:mimic_totem": "Татэм мiмiкаý", "bk:mimic_totem_desc": "##Смерць мiмiкам!##", "back_to_town": "Вяртацца ý Горад", "bk:glass_gun": "Шкляная Пукалка", "bk:glass_gun_desc": "##Крохкая##", "bk:glass_shard": "Асколак Шкла", "bk:glass_shard_desc": "Астаткi цэлага", "bk:disk_10": "Дыск №10", "bk:disk_10_desc": "Торгаш", "bk:disk_1": "Дыск 1", "bk:disk_1_desc": "Хата", "bk:disk_2": "Дыск 2", "bk:disk_2_desc": "Лес", "bk:disk_3": "Дыск 3", "bk:disk_3_desc": "Джунглi", "bk:disk_4": "Дыск 4", "bk:disk_4_desc": "Лед", "bk:disk_5": "Дыск 5", "bk:disk_5_desc": "Замак", "bk:disk_6": "Дыск 6", "bk:disk_6_desc": "Пекла", "bk:disk_7": "Дыск 7", "bk:disk_7_desc": "???", "bk:disk_8": "Дыск 8", "bk:disk_8_desc": "Пустата", "bk:disk_9": "Дыск 9", "bk:disk_9_desc": "Cut", "bk:dagger": "Кiнжал", "bk:dagger_desc": "Настальгiя...", "bk:spear": "Кап'ё", "bk:spear_desc": "Доýгiя лапкi", "shopkeeper_6": "Дратуце :)", "shopkeeper_7": "[cl yellow]Чаю[cl] не хочаш?", "shopkeeper_8": "Як жыцце?", "back": "Назад", "master_volume": "Агульная Гучнасць", "music": "Музыка", "sfx": "Гукi", "graphics": "Графон", "audio": "Аýдыё", "ui_sfx": "Гукi Кнопачак", "on": "УКЛ", "off": "ВЫКЛ", "fullscreen": "Поýны Экран", "vsync": "V-Sync", "fps": "Лiчыльнiк FPS", "speedrun_timer": "Таймер", "screenshake": "Трасянiна Экрана", "freeze_frames": "Кадры Замарозкi", "flash_frames": "Кадры Ýспышкi", "reset_progress": "Скiнуць Прагрэс", "blood_n_gore": "Кроý i Астанкi", "vegan_mode": "Агароднiнны Рэжым", "reset_settings": "Скiнуць Наладкi", "are_you_sure": "Ты ýпэýнены?", "yes": "Угу", "reset_progress_dis": "Гэта сатрэ ýвесь твой прагрэс!", "reset_settings_dis": "Гэта верне ýсе наладкi да iх дэфолту!", "autosave": "Аýта Захаванне", "autopause": "Аýта Паýза", "input": "Кiраванне", "use": "Выкарыстоýваць", "active": "Актыýка", "bomb": "Бомба", "interact": "Узаемадзеянне", "swap": "Змена Зброi", "roll": "Перакат", "duck": "Крак", "pause": "Паýза", "none": "Ничего", "keyboard_controls": "Клавя", "gamepad_controls": "Джойсцiк", "keyboard": "Клавя", "gamepad": "Джойсцiк", "game": "Геймплэй", "select": "Выбраць", "cursor": "Курсок", "ach_bk:rip_desc": "Памры", "ach_bk:overshake": "Перетрасянiна", "ach_bk:overshake_desc": "1000% трасянiна экрану", "ach_bk:rip": "Самая Папулярная Ачiýка", "bk:emerald": "Смарагд", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Дзякуй!^^", "shopkeeper_11": "Якая %%прапанова%%!", "shopkeeper_12": "Не хочаш купiць [cl red]buy[cl] ^^што небудзь^^?", "shopkeeper_13": "Толькi сёння, толькi для [cl green]вас[cl]!", "shopkeeper_14": "Якая [cl yellow]прапанова[cl]!", "bk:magnifier": "Павелiчальная Шкляшка", "bk:magnifier_desc": "Вялiкiя кулi", "bk:mushroom_hat": "Грыбная Шапка", "bk:mushroom_hat_desc": "Смачная?", "bk:stone_hat": "Закамянелая Шапка", "bk:stone_hat_desc": "Цяжкая", "bk:knight_hat": "Шлем Рыцара", "bk:knight_hat_desc": "Старыя добрыя ворагi...", "bk:cowboy_hat": "Капялюш Каýбоя", "bk:cowboy_hat_desc": "Дзiкi Захад!", "bk:soup_hat": "Супны Капялюш", "bk:soup_hat_desc": "^^Смачны.^^", "bk:gold_hat": "Залаты Капялюш", "bk:gold_hat_desc": "[cl yellow]Багач!", "bk:viking_hat": "Шлем Вiкiнга", "bk:viking_hat_desc": "Амерыка!", "bk:dunce_hat": "Капялюш Балбеса", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Кацялок", "bk:top_hat_desc": "Мода гэта я!", "bk:ushanka": "Ушанка", "bk:ushanka_desc": "Дзе мая ##балалайка##?", "bk:valkyrie_hat": "Шапка Валькiрыi", "bk:valkyrie_hat_desc": "Я веру што ^^я магу лётаць^^!", "bk:skull_hat": "Чэрапушка", "bk:skull_hat_desc": "Кашалёк або жыццё!", "bk:grandma_head": "Галава Бабули", "bk:grandma_head_desc": "Чаёк?", "bk:diamond_helmet": "Алмазны Шлем", "bk:diamond_helmet_desc": "Иди копай!", "bk:villager_head": "Галава Жыхара", "bk:villager_head_desc": "Хмм?", "bk:fez": "Феска", "bk:fez_desc": "Кубит", "bk:no_hat": "Зняць Капялюш", "bk:no_hat_desc": "Няма капялюша - няма праблем!", "bk:null_hat": "НУЛЬ", "bk:null_hat_desc": "Спроба выклiкаць значэнне null", "accessorytrader_0": "##ЗМАТВАЙСЯ АДСЮЛЬ!## [dl]Або купi гэтыя ^^цудоýныя^^ прадметы за ^^%%99 крышталяý кожны%%^^!", "accessorytrader_1": "Здароý!", "accessorytrader_2": "Прывiтанне!", "weapontrader_0": "Заходзь!", "weapontrader_1": "Як надворье?", "weapontrader_2": "Купи што-небудзь, я хачу паабедаць!", "activetrader_0": "Лепшыя прапановы на рынку!", "activetrader_1": "Заплацi за два i атрымай два!", "activetrader_2": "Купi мне пончыкаý, [dl]калi ласка!!", "hattrader_0": "Хочаш быць такiм жа ^^страшэнным^^ як я? [dl]Купi капялюш", "hattrader_1": "Хочаш быць такiм жа стромкiм, як я? [dl]Я таксама.", "hattrader_2": "^^Ха ха hats!^^", "granny_0": "Ня хочаш чайку?", "granny_1": "Зрабi паýзу, выпей чайку!", "granny_2": "Чайку?", "bk:xmas_hat": "Шапка Санты", "bk:xmas_hat_desc": "З Калядамi!", "bk:pumpkin_hat": "Гарбузища", "bk:pumpkin_hat_desc": "^^Стремный стремный шкiлетос^^", "bk:cage_key": "Ключ ад Турмы", "bk:cage_key_desc": "Выратуй ^^чувака^^!", "npc_0": "Дапамажы мне! Знайдзi ключ!", "npc_1": "Дзякуй за выратаванне!", "npc_2": "Хутчэй, адкрывай дзверы!", "npc_3": "Калi ласка, выратуй мяне!", "control_0": "Жмякнi [ic 0][ic 1] каб паставiць бомбу", "control_1": "Перакочвацца ты можаш! Тыкнi [ic 0][ic 1] каб здабыць сiлу!", "control_2": "Нацiснi [ic 0][ic 1] каб стаць небяспечным", "control_3": "Дацягнiся да [ic 0][ic 1] каб ýзаемадзейнiчаць", "control_4": "Крак? [ic 0][ic 1]!", "control_5": "Выкарыстоýвай [ic 0][ic 1] каб змяняць зброю", "shopkeeper_15": "Я не даваý табе знiжак!", "shopkeeper_16": "Прынясi пабольш грошай!", "shopkeeper_17": "Ты забыýся заплацiць!", "bk:frog": "Тэлегушка", "bk:frog_desc": "Хуткае перасоýванне?", "bk:sword_orbital": "Меч Правасуддзя", "bk:sword_orbital_desc": "Ён круцiцца", "robbed": "Абрабаваны", "bk:gift_desc": "Што ж там унутры?", "bk:spike_ring": "калючае Кальцо", "bk:spike_ring_desc": "Страты з дотыку", "bk:fire_ring": "Падпаленае Кальцо", "bk:fire_ring_desc" : "падпальваючы з дотыку", "bk:ice_ring" : "Ледзяное Кальцо", "bk:ice_ring_desc" : "Замарозка з дотыку", "bk:duck_ring" : " Крякцо", "bk:duck_ring_desc" : "тэлепартацыя з страт", "bk:dull_blade" : "затупiць Брытва", "bk:dull_blade_desc" : "Трiгеррыт прадметы на атрыманне страт", "bk:sharp_blade" : "Брытва", "bk:sharp_blade_desc" : "Балюча ", "bk:obsidian_shield": "Обсидиановый Шчыт", "bk:obsidian_shield_desc": "Iмунiтэт да отбасыванию", "bk:bill": "Валюта", "bk:bill_desc": "99 Баксiка", "control_6": "Выкарыстоýвай активку з дапамогай [ic 0] [ic 1]", "bk:clover" : "Чатырехлiстнiк", "bk:clover_desc" : "Шчаслiвы!", "bk:d4" : "д4", "bk:d4_desc" : "^^ Рэролл %% тваiх артыфактаý %%! ^^", "brastin_0" : "знайдзi карцiну [cl purple] з катом [cl]!", "elon_1" : "Трымай!", "bk:maanex_head" : "Галава Маанекса", "bk:maanex_head_desc" : "хмммммм", "bk:maanex" : "Маанекс", "bk:maanex_desc": "Прымушае ворагаý задумацца", "mob_0": "Хмммм", "bk:map_greenprints": "Чарцяжы Замка", "bk:map_greenprints_desc": "Адкрывае Карту", "bk:map" : "Карта", "bk:map_desc" : "Адкрывае Карту назаýсёды", "milt_1" : "Я хачу падаруначак", "mapuzzle_0" : "Гравiтацыя.", "nullptr_0" : "ПАМЫЛКА сегментацыi.", "copied_to_clipboard" : "скапiяваць!", "isaac_0": "У жыццi няма сэнсу ...", "isaac_1": "Чаму", "isaac_2":" : sob:", "discord_0": "Скажы прывiтанне discord.gg\/rexcellent", "old_man_5" : "Кацiся, дурань!", "tutorial" : "Туторыал", "bk:crying_bomb" : "Бомба-Плакса", "bk:crying_bomb_desc" : "Бомбы страляюць", "bk:matches" : "Запалкi", "bk:matches_desc": "Памяншае затрымку перад выбухам у бомбаý", "bk:bomb_pack": "Пачак бомба", "bk:bomb_pack_desc": "Мы кладзем бомбы ý вашыя бомбы!", "bk:tnt" : "Дынамiт", "bk:tnt_desc" : "99 узрывалак", "bk:weird_mushroom_desc" : "падвойвае ýсё", "bk:weird_mushroom" : "стремно Грыб", "bk:bomb_shower" : "Бомбический Душ " , "bk:bomb_shower_desc": "Хай пойдзе дождж з бомбаý!", "bk:black_belt": "Чорны Пояс", "bk:black_belt_desc": "Больш не падрываць", "bk:ninjia_bomb": "Бомба Нiндзя", "bk:ninjia_bomb_desc": "Заклiкае падмогу пры атрыманнi страт", "start_new_run": "Твой заб яг будзе сцёрты!", "bk:laser_pointer" : "Лазерная ýказка", "bk:laser_pointer_desc" : "Паказаць", "ach_bk:marauder" : "Марадер", "ach_bk:marauder_desc" : "Убей гандляра", "ach_bk : treasure_hunter" : "Паляýнiчы за скарбамi", "ach_bk:treasure_hunter_desc" : "Знайдзi сакрэткi", "ach_bk:dodge_master" : "Майстар Додж", "ach_bk:dodge_master_desc" : "завал босяру без атрымання страху", "ach_bk:dodge_overlord" : "Уладар Додж", "ach_bk:dodge_overlord_desc" : "Прайдзi паверх без атрымання страт", "ach_bk:quackers" : "Квакерz", "ach_bk:quackers_desc" : "Пераквакай", "ach_bk:tea_party" : "Паýдзённы Чай", "ach_bk:tea_party_desc" : "Выпi кубачак гарбаты з бабусi", "ach_bk:not_a_thief" : "Больш не Злодзей", "ach_bk:not_a_thief_desc" : "завяршыýся забег не ýзяýшы ня еди ого прадмета", "ach_bk:npc_party2" : "туса", "ach_bk:npc_party2_desc" : "Выратуй усiх NPC", "bk:gold_coin" : "Залатая Манета", "bk:iron_coin" : "Жалезная Манета", "bk : copper_coin" : "Медная Манета", "bk:platinum_coin" : "Плацiнавая Манета", "bk:voodoo_doll" : "Лялька Вуду", "bk:voodoo_doll_desc" : "Забiвае ýсiх ворагаý у пакоi", "hub" : "Горад Доджа", "castle" : "Графскi Развалiны", "charger_0" : "АКТИВКА НЕ вЫЯУЛЕНА", "charger_1" : "АКТИВКА УЖО ЗАРАДЖАНА", "charger_2" : "ДЗЕ МАЕ ГРОШЫ, мяшок з мясам?", "charger_3" : "## Я КАЗА ДАЙ МНЕ ГРОШЫ! ##", "charger_4" : "## Я захоплены УВЕСЬ СВЕТ! ##", "charger_5" : "## МУХАХАХАХАХАХА ##", "maanex_6_0" : "Вядома, давай!", "maanex_6_1" : "Найн.", "maanex_6" : "Окей, дай мне [cl yellow] [vr cost] манет [cl] i я дам табе адкрыць адзiн куфар, iдзе?", "maanex_5" : "Гэй ты, не хочаш ^^ выпрабаваць поспех ^^?", "maanex_7" : "Гэта было весела!", "maanex_8" : "Удачы!", "maanex_9": "Ну, пашанцуе ý наступны раз :(", "maanex_10": "%%^^ВАУ^^%%", "maanex_11": "Але ý цябе няма столькi грошай!", "maanex_12": "##СЫН?!##", "bk:amurs_arrow": "Страла Амура", "bk:amurs_arrow_desc": "ýлюбляюцца кулi", "bk:amurs_bow": "Цыбуля Амура", "bk:amurs_bow_desc" : "Я бачу каханне", "bk:poison_flask" : "склянкi з атрутай", "bk:poison_flask_desc" : "Атручаныя Кулi", "bk:snowball" : "Сняжок", "bk:snowball_desc" : "Страшэнна непрыемныя кулi", "bk:peper" : "Востры Перчык", "bk:peper_desc" : "Гарачыя кулi", "bk:sale_coupon" : "Купон на Знiжкон", "bk:sale_coupon_desc" : "-50%! ", "bk:pet_box": "Кот у Скрынцы", "bk:pet_box_desc" : "А хто ж ýнутры?", "bk:crate" : "Скрынка з арбiталей", "bk:crate_desc" : "А хто ж ýнутры?", "bk:strawberry" : "Клубнiчка", "bk:strawberry_desc" : "Салодкiя ýспамiны", "bk:wings" : "Крылы", "bk:wings_desc" : "я не веру, што я магу лятаць", "bk:coin_pouch" : "Мешочек з манетамi", "bk:coin_pouch_desc" : "Цi дае манеты", "bk:key_pouch" : "Мешочек з Ключамi", "bk:key_pouch_desc" : "Цi дае ключы", "bk:bomb_pouch" : "Бомбический Мешочек", "bk : bomb_pouch_desc" : "Цi дае бомбы", "bk:pouch_pouch" : "Мешочек з мяшочка", "bk:pouch_pouch_desc" : "Ён дакладна не дае мяшэчкi", "bk:lightsaber" : "Светсейбер", "bk:lightsaber_desc" : "Ты быý абраным!", "bk:snail": "Слiмак", "bk:snail_desc": "Запавольвае ворагаý", "bk:spike": "Калючка", "bk:spike_desc" : "+1 да страт", "bk:mushroom" : "Грыб", "bk:mushroom_desc" : "буст хуткасць", "bk:candy" : "Цукерка", "bk:candy_desc" : "^^ павышае бадзёрасць ^^, павялiчвае хуткасць стрэльбы", "bk:glasses" : "Ачкi", "bk:glasses_desc" : "Падвышаная дакладнасць", "bk:ruler" : "Лiнейка", "bk:ruler_desc" : "+1 да далёкасцi атакi", "bk:stopwatch" : "Секундамер", "bk:stopwatch_desc" : "Атрыманне страт запавольвае час", "bk_0" : "## НЯ СМЕЙ ЧАПАЦЬ ГЭТА! ## ", "bk_1": "## Я СКАЗАЛ НЕ ЧАПАЦЬ !! ##", "bk_2": "## ТЫ НЕ МОЖАШ ПЕРАМАГЧЫ МЯНЕ, [cl red] ПАДПАЛЕНАГА РЫЦАРА [cl], ДУРАНЬ! ##", "bk_3": "## ПРЫГАТАВАЦЬ СУСТРЭЧУ! ##", "bk_4": "^^ КАКАЯ ШУТКА ^^", "shopkeeper_18": "[cl red] ^^ Гарачая распродажа! [cl]", "dm_0": "@ @ Да нас запрашаем @@", "ach_bk:deal" : "Выбiтны Ход", "ach_bk:deal_desc" : "Зрабi здзелку з Цёмным Чараýнiком", "ach_bk:grannys_gift" : "Падарунак Бабулi", "ach_bk:grannys_gift_desc" : "Атрымай падарунак ад бабусi", "ach_bk:shopper" : "Пакупкi да упаду", "ach_bk:shopper_desc" : "Купi прадмет у магазе", "bk_5" : "Я Б НЕ ЗВЯРТАÝ УВАГУ НА ГЭТУ ПСКЛЮ", "bk_6" : "## ЗАБI ЯГО, [cl lime] ЭДВАРД [cl]! ##", "bk_7" : "[cl lime] ЭДВАРД [cl], ## НЕЕЕЕЕЕТ !!!! ##", "bk_8" : "ПЕРАСТАНЬ ПАДРЫВАЦЬ МОЙ ЗАМАК!", "bk_9" : "[cl pink] БАБУЛЬКА [cl], [dl] ТЫ МОЖАШ УЖЕ ЗГIНУЦЬ, КАЛI ЛАСКА ##?!? ##", "bk_10" : "МАЙСТАР, [dl] Я ПРЫВЁÝ [cl green] ГОБЛIНА [cl]", "dm_1" : "Вельмi добра [dl], дзякуй [dl], [cl red] Лимпор [cl]", "dm_2" : "## Так, так, мне трэба больш [cl orange] моцы [cl]! ##", "dm_3" : "## БОЛЬШ [cl orange] моцы [cl]!", "dm_4" : "Я чуствую [cl orange] моц [cl] пульсавалую ýва мне !", "granny_3" : "Ты будзеш першым, [cl red] Лимпор [cl]!", "granny_4" : "Сардэчна запрашаем, [cl green] Гоббо [vr id][cl]!", "granny_5" : "Удачы ý тваiм сумным квэсце!", "bk:meat_guy" : "Мясны Таварыш", "bk:meat_guy_desc" : "Магутны!", "bk:bullet_stone" : "Каменны Стралок", "bk:bullet_stone_desc" : "Ён аттакует i абараняе!", "bk:batman" : "Батарейкман", "bk:batman_desc" : "Не дапамагае, але затое дае батарэйкi", "vibration" : "Вiбрацыя", "bk:sharp_arrow" : "Вострая Страла", "bk:sharp_arrow_desc" : "Скразныя кулi", "machine_0" : "Устаýце [cl yellow] манету", "bk:boomerang" : "Бумеранг", "bk:boomerang_desc" : "кулi вернуцца", "bk:backpack" : "Заплечнiк", "bk:backpack_desc" : "Больш месца", "place_an_item" : "Пакласцi Зброя", "bk:crystal" : "Крышталь", "bk:crystal_desc" : "Сiла Вясёлкi ", "bk:prism": "Прызма", "bk:prism_desc": "Кулi -> Вясёлка", "scourged": "Пракляты", "bk:bomb": "Бомба", "bk:scourge_of_egg": "Праклён Яйкi", "bk:scourge_of_egg_desc" : "пераблыталi назвы", "bk:scourge_of_unknown" : "Праклён невядома", "bk:scourge_of_unknown_desc" : "Схаваныя прадметы", "bk:scourge_of_blood" : "Праклён Крывi", "bk:scourge_of_blood_desc" : "Больш ворагаý", "bk:scourge_of_risk" : "Праклён Рызыкi", "bk:scourge_of_risk_desc" : "Схаванае здароýе", "bk:scourge_of_keys" : "Праклён Ключоý", "bk:scourge_of_keys_desc" : "Схаваныя пiкапы " , "bk:scourge_of_lost": "Праклён Страчанага", "bk:scourge_of_lost_desc" : "Амнезiя", "bk:scourge_of_scourged" : "Праклён праклён", "bk:scourge_of_scourged_desc" : "Праклёны Усюды", "bk:scourge_of_illness" : "Праклён Хворага", "bk:scourge_of_illness_desc" : "Сэрца лечаць менш", "bk:scourge_of_death" : "Праклён Смерцi", "bk:scourge_of_death_desc" : "Хардмод", "bk:ancient_revolver" : "Старажытны Рэвальвер", "bk:ancient_revolver_desc" : "Выглядае Классно " , "bk:assault_rifle": "Штурмавая Вiнтоýка", "bk:assault_rifle_desc": "Пiу Пiу", "fountain_0": "Прынясi пяць манет i я благославлю цябе", "fountain_1": "Ты быý часткова ачышчаны", "fountain_2" : "Ты быý цалкам ачышчаны", "fountain_3" : "Ты ýжо ачышчаны", "buffed" : "Бафнут", "nerfed" : "Панерфлен", "restored" : "узражден", "damaged" : "калецтваý", "cleansed" : "ачышчаны", "gifted" : "адарыý", "lucky" : "Шчаслiýчык", "unlucky" : "Няýдачнiк", "max_hp" : "Максiмальнае HP", "touch" : "пакратаць", "break" : "Зламаць", "no_coins" : "Няма Манет", "old_man_6" : "Небяспечна iсцi аднаму, вазьмi гэта!", "roger_0" : "Бум! ", "roger_1": "## * бУМ * ##", "roger_2": "бум бум шакалака!", "bk:shield": "Шчыт", "bk:gift": "Падарунак", "bk:shield_pouch" : "Мешочек з Шчытамi", "bk:shield_pouch_desc": "Цi дае шчыты", "bk:shield_buddy": "Щитовик", "bk:shield_buddy_desc": "Абаронца", "bk:skeleton_key": "Ключ Шкiлета", "bk:skeleton_key_desc" : "99 ключыкаý", "bk:jar" : "склянкамi са Здароýем", "bk:jar_desc" : "Джэм", "bk:star" : "Зорка", "bk:star_desc" : "Абарона", "bk:car_bomb" : "Бомбы на колах", "bk:car_bomb_desc" : "сiстэму ма дастаýкi бомбаý да ворагаý", "bk:grenade" : "Граната", "bk:grenade_desc" : "Бомбы выбухаюць пры дотыку", "trash_goblin_0" : "Выратуй мяне ад майго [cl purple] праклёны [cl]! Калi ласка!", "Trash_goblin_1" : "Я свабодны! [Dl] Дзякуй табе велiзарнае!", "Boxy_0" : "Балдеж", "boxy_1" : "Якая ýпакоýка!", "Boxy_2" : "Табе патрэбна абгортачная папера? " , "trash_goblin_2": "^^ Туман над ракой ^^", "bk:vampire_bat": "Мыш Вампiр", "bk:vampire_bat_desc": "Реген", "shields": "Шчыты", "bk:mustache": "Вусы", "bk:mustache_desc": "ВIП", "bk:bloody_chest": "Крывавы Сундук", "bk:bloody_chest_desc": "Куфры лечят", "bk:bloody_shield": "Крывавы Шчыт", "bk:bloody_shield_desc" : "Шчыты назаýсёды", "bk:cutsaw" : "Пiла", "bk:cutsaw_desc" : "Ворагi заплацяць", "vampire_0" : "Нам!", "vampire_1" : "Балдеж", "vampire_2" : "Мммм", "vampire_3": "Мы ведаем правiлы, [cl red] ^^ цi не так [cl]?", "vampire_4": "^^ Мммммм ^^", "vampire_5": "Якi ý цябе тып крывi ?", "vampire_6" : "Смаката", "duck_2": "Адкажаш на пару пытанняý?", "Duck_7_0": "Давай", "duck_7_1": "Не", "duck_7": "Ты атрымаеш гэты куфар?", "Duck_4": " прыгажунчык, трымай куфар!", "duck_5" : "Я не магу з табой пагадзiцца ...", "duck_6_0" : "Сусвет", "duck_6_1" : "^^ кваркаý ^^", "duck_6" : "Пра што я думаю?", "duck_8_0" : "[cl red] Чырвоны [cl]", "duck_8_1" : "[cl blue] Сiнi [cl]", "duck_8" : "Якi мой любiмы ^^ %% колер %% ^^?", "duck_9_0" : "Кошка", "duck_9_1" : "Ты", "duck_9" : "Хто сказаý \"мяу\"?", "duck_10_0" : "0", "duck_10_1" : "1", "duck_10" : "Што лепш?", "duck_11_0" : "Што, ты яйка?", "duck_11_1" : "\\[_ Ён ударыý его._]", "duck_11" : "ты соус", "duck_12_0" : "Курыца", "duck_12_1" : "Яйка", "duck_12" : "Што было першым?", "duck_13_0" : "Нiчога.", "duck_13_1" : "Снэк.", "duck_13_2" : "Яйка.", "duck_13_3" : "Смажаная курыца.", "duck_13" : "Што я еý сёння?", "duck_14" : "Ой.", "duck_17_0" : "Вядома", "duck_17_1" : "## Нанi ##", "duck_17": "Як наконт ананасаý на тваёй пiцы?", "duck_18_0": "Белага!", "duck_18_1": "[cl yellow] Жоýтага [cl]!", "duck_18" : "Якога колеру сыр?", "nurse_0" : "Ты выглядаеш выдатна, дарагi!", "nurse_1" : "Я магу цябе падлячыць, але мне трэба [cl yellow] [vr price] манет [cl]", "nurse_2" : "Я спадзяюся гэта было не балiць", "elon_4" : "Трымай, поспеху", "elon_2_0" : "Паехалi", "elon_2_1" : "надвор'е", "elon_2" : "Хочаш выпрабаваць маю магiю? ", "elon_3": "Я магу трансмутировать тваё зброю", "elon_5": "Ну добра", "elon_7": "Бро, дзе тваё зброю ???", "gobetta_0": "<3", "gobetta_1":" : 3", "gobetta_2": "=)", "gobetta_3": "* blush *", "gobetta_4": "Гэта ... ты?", "Gobetta_5": "Столькi гадоý мiнула ...", "ach_bk:desert": "Суха ды Жарко", "ach_bk:desert_desc": "дойдзем да пустыннага Замка", "ach_bk:jungle": "Жужала Пчолкi", "ach_bk:jungle_desc": "Дабярыся да Старажытных Джунглей", "rooms_explored" : "Пакояý даследавана", "bk:shadow_cloak_desc" : "No U", "bk:shadow_cloak" : "Мантыя Неведимка", "bk:dynamite_stick" : "Палка дынамiту", "bk:dynamite_stick_desc" : "Хочаш бомбануть?", "bk:chalice_of_blood" : "Кубак з Крывёю", "bk:chalice_of_blood_desc" : "Боль выклiкае злосць, злосць выклiкае страты", "bk:detonator" : "Дэтанатар", "bk:detonator_desc" : "выклiкае выбухi", "invincibility_time" : "Час непаражальным", "accuracy" : "Дакладнасць", "range" : "Так льность", "fire_rate" : "Хуткасць Аттаки", "speed" : "Хуткасць", "bk:talisman_of_foresight" : "Талiсман прадбачання", "bk:talisman_of_foresight_desc" : "Адкрый вочы i ýбачыýшы суседнiя пакоi!", "bk:scourge_ring" : "Праклятае Кальцо", "bk:scourge_ring_desc" : "Iмунiтэт да праклёнам", "snek_0" : "Найс.", "snek_1" : "Дддддзякуй", "snek_2" : "Класшшш", "snek_3" : "прывiтанне", "snek_4" : "Добрага часу шшуток", "snek_5" : "Купi шшшто-небудзь?", "snek_6" : "Мне трэба удоволетворить пакупнiка ...", "snek_7" : "я ссссделаю то, шшшто я павiнен!", "bk:snek" : "смей", "bk:snek_desc" : "Снэк?", "boxy_3" : "^^: wave: ^^", "boxy_4" : "Цi знойдзецца лiшнi ключ? ", "boxy_5": "Дай пару ключоý?", "bk:blank": "Пустышка", "bk:blank_desc": "_Пусты Тэкст_", "bk:blank_bombs" : "Пустыя Бомбы", "bk:blank_bombs_desc" : "_Пустота_", "bk:explosive_bullets" : "Бомбические Кулi", "bk:explosive_bullets_desc" : "Выбухаюць", "bk:random_bullets" : "Выпадковыя Кулi", "bk:random_bullets_desc": "RNG", "bk:cup": "Чашка", "bk:cup_desc": "Бабуля не зможа не прыйсцi", "bk:cartridge": "Катрыджа", "bk:cartridge_desc": "Цёмны Чараýнiк абяцаý зайсцi пагуляць", "bk:marriage_ring": "Заручальнае Кальцо", "bk:marriage_ring_desc": "Цёмны Чараýнiк & Бабуля назаýсёды!", "boxy_7": "Я хачу ключоý", "boxy_8": "у цябе не дастаткова ключоý :(", "boxy_9": "Цяпер у мяне хапае ключоý каб ^^ адкрыцца ^^!", "roger_3": "Я не супраць калi ты заплацiш", "roger_4": "Сёння няма знiжак", "roger_5": "Бомбы ýтаропiý адз", "vampire_7" : "Ты не здаровы", "vampire_8" : "Я не даю скiдак", "vampire_9" : "Ты памрэш", "ach_bk:scourged" : "Пракляты", "ach_bk:scourged_desc" : "атрымай токен праклёны", "ach_bk:scourged_weapon" : "праклятае зброя", "ach_bk:scourged_weapon_desc" : "атрымай праклятае зброю", "rerolled" : "Зарэролена", "ach_bk:open_up" : "Адкрывашка", "ach_bk:open_up_desc" : "Купi усё ý краме бокс", "ach_bk:snek" : "змяя ý ботах", "ach_bk:snek_desc" : "займець гандляра змея ý якасцi гадаванца", "bk:scourge_of_greed" : "Праклён прагнасць", "bk : scourge_of_greed_desc" : "Высокiя цэны", "killed_by" : "Забойца", "kills" : "Забiта iстот", "time" : "Час", "depth" : "Узровень", "bk:blank_bullets" : "Пустыя кулi", "bk:blank_bullets_desc" : "Пуста", "bk:lego" : "Канструктар", "bk:lego_desc": "На яго так балюча наступаць ...", "bk:iron_armor": "Стальная Броня", "bk:iron_armor_desc": "Цi дае Шчыты", "bk:round_shield": "Круглы Шчыт", "bk:round_shield_desc": "Iмунiтэт да кантактнага страт", "bk:arkhalis": "Аркалис", "bk:arkhalis_desc": "Легендарны меч", "bk:inverted_arkhalis": "Антычны Аркалис", "bk:inverted_arkhalis_desc": "Падмога пры 1 hp", "bk:gun_sword": "Пушкамеч", "bk:gun_sword_desc": "Мутант", "ach_bk:scourge_king_desc": "Атрымай 10 праклёнаý", "ach_bk:scourge_king" : "Пракляты Кароль", "ach_bk:sting_operation": "Жальная Аперацыя", "ach_bk:sting_operation_desc": "Перамажы Каралеву Пчалу", "ach_bk:mummified": "забальзамаваную", "ach_bk:mummified_desc": "Перамажы фараона", "ach_bk:democracy": "Дэмакратыя", "ach_bk:democracy_desc": "Перамажы Караля", "pharaoh_scream": "## Прыгатаваць СТАЦЬ мумiяй! ##", "queen_bee_scream": "## ЗА [cl yellow] HONEY LORD [cl]! ##", "bk : half_heart" : "Пол Сэрца", "right" : "Направа", "down" : "Унiз", "left" : "Налева", "up" : "Уверх", "painting_cat" : "Кот", "bk:axe" : "Сякера", "bk:axe_desc" : "Ён паляцеý, але абяцаý вярнуцца", "bk:guitar" : "Гiтара", "bk:guitar_desc" : "Яна вельмi растроена", "bk:glass_sword" : "Шкляны Меч", "bk:glass_sword_desc" : "Зброя майстроý", "bk:chicken" : "Крыльца", "bk:chicken_desc" : "Ай, пальчыкi апёк", "bk:pickaxe" : "Кiрха " , "bk:pickaxe_desc": "Капай давай", "bk:mana": "Мана", "bk:half_mana": "Пол маны", "bk:lava_wand": "Посах Лавы", "bk:lava_wand_desc": "Гарачы", "bk:web_wand": "Павуковы Посах", "bk:web_wand_desc": "правайдер web сэрвiсаý", "bk:slap_stick" : "Палка Надавалка", "bk:slap_stick_desc" : "шлёп", "sensivity" : "Адчувальнасць", "no" : "Не", "scale" : "Наблiжэнне ", "ach_bk:ice": "Леднiковы Перыяд", "ach_bk:ice_desc": "Дабярыся да Ледзяных развалiны", "ach_bk:library": "Знiклыя Тэксты", "ach_bk:library_desc": "Дабярыся да Сакрэтнай Бибилотеки", "bk : ice_skates" : "Канькi", "bk:ice_skates_desc" : "Iмунiтэт да лёду", "bk:campfire_in_bottle" : "Вогнiшча ý бутэльку", "bk:campfire_in_bottle_desc" : "Iмунiтэт да замарозцы", "library" : "Сакрэтная бiблiятэка", "ach_bk:cat_without_a_hat" : "Кот без шапкi", "ach_bk:cat_without_a_hat_desc" : "Знайдзi карцiну з Катом", "ach_bk:rich" : "Туалетная Папера", "ach_bk:rich_desc" : "Збяры 99 манет " , "ach_bk:rescue_operation" : "Выратавальная Аперацыя", "ach_bk:rescue_operation_desc" : "Выратуй NPC", "ach_bk:tutorial" : "Былы", "ach_bk:tutorial_desc" : "Закончы туторыал", "ach_bk:fancy_hat" : "Клевы Капялюш" , "ach_bk:fancy_hat_desc": "Купi Капялюш", "ach_bk:unlock": "Адкрывальнiк", "ach_bk:unlock_desc": "разблакуюцца прадмет", "floor_brightness": "Якрость Пола", "ach_bk:shielded": "Падняць шчыты", "ach_bk:shielded_desc" : "займець сэрца-шчыт", "run_type" : "Тып забегу", "run_regular" : "Звычайны", "run_challenge" : "Выпрабаванне", "damage_taken" : "Страты атрыманы ", "km": "км", "distance_traveled": "Дыстанцыя", "seed": "Сiд", "score": "Рахунак", "new_high_score": "Новы рэкорд!", "items_collected": "Рэчаý сабрана" , "boss_rush": "Бос Раш", "run_bossrush": "Бос Раш", "bk:blindfold": "Павязка", "Daily_run" : "Дэйлик", "builder_0_0" : "Так", "builder_0_1" : "Мне самому патрэбныя грошы", "builder_0" : "Я планую пабудаваць тунэль сюды, але мне трэба яшчэ [vr need] [ic 0]. Можаш дапамагчы?", "Builder_1" : "Але ý цябе наогул няма грошай!", "Builder_2" : "Дзякуй за iнвестыцыю!", "Builder_3" : "У мяне нарэшце дастаткова грошай для заканчэння гэтага праекта! Дзякуй велiзарнае!", "Builder_4" : "Ок, прабач!", "Shortcut_is_broken" : "Тунэль Зламаны", "ach_bk:boss_rush" : "заваёýнiк босаý", "ach_bk:boss_rush_desc" : "Перамажы ýсiх босаý ý Бос Раше " , "ach_bk:daily": "Дзённая Слава", "ach_bk:daily_desc": "выйграла Дейлик", "ach_bk:desert_shortcut": "Пустынны Тунэль", "ach_bk:desert_shortcut_desc": "пачын тунель, якi вядзе ý Пустынны Палац", "ach_bk:jungle_shortcut": "Старажытны Тунэль", "ach_bk:jungle_shortcut_desc": "пачын тунель, якi вядзе ý Старажытныя Джунглi", "ach_bk:ice_shortcut": "Ледзяны Тунэль", "ach_bk:ice_shortcut_desc": "пачын тунель, якi вядзе ý ледзяныя Развалiны", "ach_bk:library_shortcut" : "Сакрэтны Тунэль", "ach_bk:library_shortcut_desc" : "пачын тунель, якi вядзе ý Сакрэтную Бiблiятэку", "ach_bk:fashion_matters2" : "Мода Важная", "ach_bk:fashion_matters2_desc" : "Купi усё капялюшы", "ach_bk:10_challenges" : "Challenger", "ach_bk:10_challenges_desc" : "Скончы 10 выпрабавання" , "ach_bk:20_challenges": "Challenger 2.0", "ach_bk:20_challenges_desc": "Скончы 20 выпрабаваннi", "ach_bk:30_challenges": "Challenger 3.0", "ach_bk:30_challenges_desc": "Скончы 30 выпрабаваннi", "ach_bk:bk_no_more" : "BK no more", "ach_bk:bk_no_more_desc" : "Пераможыць Падпаленага Рыцара", "ach_bk:dm_no_more" : "DM no more", "ach_bk:dm_no_more_desc" : "Пераможыць Цемнага Калдуна", "ach_bk : egor_no_more" : "Egor no more", "ach_bk:egor_no_more_desc" : "???", "ach_bk:loop" : "Ah, here we go again", "ach_bk:loop_desc" : "Enter the loop", "coins_collected" : "Манет собранно", "bk:cup_head" : "Галавачашка", "bk:cup_head_desc" : "Выпi чайку", "bk:mustache_hat" : "Вусы", "bk:mustache_hat_desc" : "AFK", "bk:propeller_hat" : "Шапка з маторчыкам", "bk:propeller_hat_desc": "Ён круцiцца", "bk:sunglasses": "Сонечныя Ачкi", "bk:sunglasses_desc": "Гэтак жа працуюць з Месяцам!", "bk:cap": " кепка", "bk:cap_desc" : "Круты @ - @", "bk:eyes" : "Вочы", "bk:eyes_desc" : "@ @", "bk:eye" : "Вока", "bk:eye_desc" : "@", "bk:hair" : "Валасы", "bk:hair_desc" : "Ну нарэшце", "won" : "Перамог", "won_message" : "Ты перамог!", "garderobe_sign" : "Гардэроб", "darkmarket_tip": "~~ [cl purple] Праклён [cl] або [cl yellow] 30 манет [cl] @@", "mike_0": "Заплацi мне [cl green] 3 смарагду", "mike_1" : "Паспрабуй Бос Раш ýсяго за [cl green] 3 смарагду [cl]!", "bk:weird_potion" : "стремно Зелле", "bk:weird_potion_desc" : "Дзiýныя Кулi", "bk:megaphone" : "Мегафон", "bk:megaphone_desc" : "павялiчэнню Куль", "scourge" : "Праклёны" , "Scourge_stats": "Праклёны", "run_daily": "Дэйлик", "completed_on": "Дасягнута", "complete": "дасягнута", "next_daily_in": "[cl gray]Наступны пачынаецца праз[cl]", "hours": "гадзiн", "minutes": "хвiлiн", "seconds": "секунд", "ach_bk:star": "Зорка Шоу", "ach_bk:star_desc": "Збяры 3 арбiталь", "ach_bk:family" : "Шчаслiвая Сям'я", "ach_bk:family_desc" : "Збяры 3 гадаванца", "ach_bk:return_to_sender" : "No U", "ach_bk:return_to_sender_desc" : "Убей ворага яго ж куляй", "ach_bk:van_no_gogh" : "Ван Але Гог", "ach_bk:van_no_gogh_desc": "Зламай 100 карцiн", "ach_bk:boom": "Ланцуговая Рэакцыя", "ach_bk:boom_desc": "Падарву ланцуг з 3 дынамiтаý", "ach_bk:dark_market": "Крымiнальная нычку", "ach_bk:dark_market_desc": "Спусцiся ý Цёмны Маркет", "ach_bk:spikes": "Шыпамi Замак не сапсавалi", "ach_bk:spikes_desc" : "Актывiруйце 100 шыпоý за 1 забег", "ach_bk:white_flag" : "Бяззбройны", "ach_bk:white_flag_desc" : "зачысцiць пакой не выкарыстоýваючы зброi", "quack" : "[cl yellow] Крак! [cl]", "pixel_perfect" : "Pixel Perfect", "bk_11" : "Я дарую табе жыццу. АЛЕ ## НЕ РАБI ## ГЭТА IЗНОÝ!", "Leaderboard" : "Дошка Лiдэраý", "display" : "Фiльтр", "around_you" : "Вакол Цябе", "friends" : "Сябры", "global" : "Усе", "loading": "Загружаем", "generating": "Генерим", "cursor_radius": "Радыус Курсора", "no_scores_yet": "Яшчэ няма рахункаý", "no_score_yet": "Яшчэ няма рахунку", "run" : "Забег", "top" : "Топ", "quick_restart" : "Хуткi Рэстарт", "painting_dungeon" : "Замак", "painting_goose" : "Мiнi Гусь", "painting_chess" : "Лятучы Слон ", "painting_peach": "Персiкавае Дрэва", "bk:no_lamp": "Не", "bk:explosive_lamp": "Выбухная Лямпа", "bk:explosive_lamp_desc": "Калi ты занадта любiш ýсе падрываць", "bk:shielded_lamp" : "Шчытавая Лямпа", "bk:shielded_lamp_desc": "Падняць Шчыты!", "lamp": "Лямпа", "bk:brain": "Мега Мозг", "bk:brain_desc" : "Памер мозгу: Мега", "bk:heart_amulet" : "Сардэчны Амулет", "bk:heart_amulet_desc" : "+1 да памеру сэрца", "bk:star_amulet_desc" : "+1 да маны ", "bk:star_amulet": "Зорны Амулет", "bk:coin_amulet": "Амулет на Грошы", "bk:coin_amulet_desc": "Грошы даюць больш", "bk:key_amulet": "Амулет на Ключы", "bk:key_amulet_desc": "Ключы даюць больш", "bk:bomb_amulet": "Бомбический Амулет", "bk:bomb_amulet_desc": "Бомбы даюць больш", "bk:eye_amulet": "Вочны Амулет", "bk:eye_amulet_desc" : "Як жа балюча быць недакладным", "bk:eye_patch" : "Оклюдер", "bk:eye_patch_desc" : "Вы гатовыя, дзецi?", "bk:toilet_paper" : "Туалетная Папера", "bk:toilet_paper_desc" : "Заýсёды заканчиватся", "bk:decoy": "Прынада", "bk:decoy_desc": "Яна взрываетс я", "bk:wallet": "Кашэлечак", "bk:wallet_desc": "Захоýвае грошы", "bk:skele_buddy" : "Дэманюга","bk:skele_buddy_desc" : "стремно", "bk:mega_bomb" : "Мега Бомба", "bk:mega_bomb_desc" : "Памер бомбы: Мега", "bk:condensed_milk" : "Згушчонка", "bk:condensed_milk_desc" : "Шустрыя пiкселi - Павольныя Працiýнiкi", "bk:marshma llow" : "Маршмеллоу", "bk:marshmallow_desc" : "Лiпкая штука", "bk:orbital_multiplier" : "Множнiк арбiталей", "bk:orbital_multiplier_desc" : "Больш арбiталей ýладару арбiталей!", "bk:pet_multiplier" : "множнiк гадаванца", "bk:pet_multiplier_desc" : "Больш гадаванцаý!", "bk:ghost_bullets" : "Кулi Прывiды", "bk:ghost_bullets_desc" : "Сцены не перашкода", "bk:weight" : "Гiра", "bk:weight_desc" : "Узмацняе гравiтацыю", "bk:d2" : "Д2", "bk:d2_desc" : "Вазьмi або пакiнь", "bk:ethernal_d6" : "Нябесны Д6", "bk:ethernal_d6_desc" : "Рэролiт i \/ або знiшчае", "bk:billiard" : "Бiльярд", "bk:billiard_desc" : "Кулi адскокваюць ад куль", "bk:enraged_bullets" : "раззлаваны Кулi", "bk:enraged_bullets_desc" : "Кулi ламаюць кулi", "bk:rewind_button" : "Кноп ка перамоткi", "bk:rewind_button_desc" : "Пастой", "bk:piggy_bank" : "Свiнка Скарбонка", "bk:piggy_bank_desc" : "Мае зберажэннi", "coins" : "Манеты", "bk:death_star" : "Зорка Смерцi", "bk:death_star_desc": "RIP Альдэран", "bk:soldering_iron": "Паяльнiк", "bk:soldering_iron_desc": "Гарачы", "bk:can": "Банка", "bk:can_desc" : "Падваенне Куль", "bk:swimming_mask" : "Плавальны Маска", "bk:swimming_mask_desc" : "Сакрэтная Зброя", "bk:bullet_chair" : "Рэактывны Стул", "bk:bullet_chair_desc" : "4 ногi 4 пухи", "bk:cell" : "Клетка", "bk:cell_desc" : "Кулi нараджаюцца", "bk:brick" : "iКiрпыч", "bk:brick_desc" : "Вялiкiя ýзроýнi", "bk:ring_of_pain" : "Кола Болi", "bk:ring_of_pain_desc" : "Атрыманне страт б'е ýсiх", "bk:schrodingers_cat" : "Кот Schrödingerа", "bk:schrodingers_cat_ desc" : "Быць цi не быць (50% шанец)", "bk:smoke_bomb" : "Дымавуха", "bk:smoke_bomb_desc" : "Уцёкi ý стылi нiндзя", "bk:chest_ring" : "Кола куфар", "bk:chest_ring_desc" : "Вялiкi куфар!", "bk:empty_shell" : "Пустая Гiльза", "bk:empty_shell_desc" : "Шанец знiшчыць кулi працiýнiкаý", "bk:parachute" : "Парашут", "bk:parachute_desc" : "Iмунiтэт да дзiркi", "bk:spiked_cookie": "шыпастым Печенька", "bk:spiked_cookie_desc": "Хворы аб б'е", "bk:shooty": "Стреляка", "bk:shooty_desc": "Ён страляе" , "bk:rabbit_bullets": "Зайчёна Кулi", "bk:rabbit_bullets_desc": "Яны размножваюцца", "bk:pandoras_box": "Скрынка Пандоры", "bk:pandoras_box_desc": "Захавай зло", "bk:bubbles" : "Мыльныя Бурбалкi", "bk:bubbles_desc": "Сябар", "bk:match": "Запалка", "bk:match_desc" : "Агонь для ýсiх", "bk:hammer": "Молат", "bk:hammer_desc": "Я тваю бронь ламаць", "bk:helmet": "Сталёвы Шлем", "bk:helmet_desc": "Шанец ня атрымаць страты", "bk:beer" : "Пiýка", "bk:beer_desc" : "страты выклiкае злосць", "bk:the_eye" : "Глазик", "bk:the_eye_desc" : "Ён глядзiць", "bk:mimics_tooth" : "Зуб мiмiка", "bk:mimics_tooth_desc" : "Прыцягвае мiмiка", "ach_bk:mimic" : "Скрымер", "ach_bk:mimic_desc" : "Знайдзi мiмiка", "bk:paper_airplane" : "Папяровы Самалёцiк " , "bk:paper_airplane_desc": "Саманавадяшиеся кулi", "ach_bk:ice_boss": "Дай ёй Сысцi", "ach_bk:ice_boss_desc": "Убей Ледзяную Каралеву", "ice_queen_scream": "^^ [cl cyan] Ахем", "painting_agency": "Сардэчна запрашаем у агенства", "language": "Мова", "bk:pouch": "Мешочек", "bk:alien_glasses": "Iнапланетныя Акуляры", "bk:alien_glasses_desc" : "Я бачу больш", "inventory": "Iнвентар", "bk:led": "Святлодыёд", "bk:led_desc": "Дакладная Лямпачка", "bk:fragile_lamp": "Крохкая Лямпачка", "bk:fragile_lamp_desc": "Адын удар K.O.", "painting_guitar" : "Больш гучнасцi!" } ================================================ FILE: BurningKnight/Content/Locales/de.json ================================================ { "bk:halo": "Heiligenschein", "bk:halo_desc": "Mehr Leben", "bk:revolver": "Revolver", "bk:sword": "Holzschwert", "bk:sword_desc": "Ein Stock mit scharfen Kanten", "bk:heart": "Herz", "resume": "Fortfahren", "settings": "Einstellungen", "restart": "Neustarten", "death_message": "Du bist gestorben!", "descend": "Hinabsteigen", "ascend": "Hochklettern", "exit": "Verlassen", "painting_rexcellent": "Excellent", "painting_grannylisa": "Grannylisa", "painting_maanex": "Der Denker", "painting_bk": "Der geröstete Ritter", "painting_failpositive": "Party Macher", "painting_old_man": "Sehr alter Mann", "painting_arthouse": "Kunst Haus", "painting_black": "Universum", "painting_milt": "Junge im Schnee", "painting_skyscraper": "Einsamer Wolkenkratzer", "painting_egor": "Brennender Rex", "painting_null": "NULL", "painting_badosz": "Verwirrter Junge im Wald", "painting_banana": "BANANE", "painting_tv": "Fernseher im Himmel", "painting_company": "In guter Gesellschaft", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Dog du Trasevol", "painting_lamp": "Schnapp sie dir!", "painting_scream": "Eis!", "painting_stars": "Gruselige Nacht", "painting_fog": "In den Gewässern...", "painting_nufflee": "WUFF", "by": "von", "old_man_0": "Es ist gefährlich!", "continue_run": "Run fortsetzen", "new_run": "Neuer Run", "was_unlocked": "wurde freigeschaltet!", "bk:revolver_desc": "HÄNDE HOCH @everyone!", "bk:shovel": "Blaue Schaufel", "bk:shovel_desc": "Aber warum ist sie blau???", "beet_0": "Hi!", "beet_2": "Wie soll er heißen?", "npc_hurt_0": "Aua.", "npc_hurt_1": "Das tut weh.", "npc_hurt_2": "Oh nein.", "beet_3": "Danke <3", "beet_1": "Möchtest du einen ^^Seed^^ einsetzen?", "beet_1_0": "Klar!", "beet_1_1": "Nein", "beet_4": "Der momentane Seed ist [vr seed]. Willst du ihn verändern?", "beet_4_0": "Ja bitte!", "beet_4_1": "Ne, passt so.", "beet_5": "Wie auch immer...", "beet_4_2": "Zufalls-Seed bitte!", "beet_6": "Alles klar. Der Seed lautet nun: [vr seed]", "bk:idol": "Idol", "bk:idol_desc": "Eine geheime Falle aktiviert sich!", "bk:key": "Goldener Schlüssel", "bk:infinite_bomb": "Unendlichkeits-Bombe", "bk:infinite_bomb_desc": "Eine wiederverwendbare Bombe", "throw_coin": "Wirf eine Münze", "bk:potatoo": "Kartoffel", "bk:potatoo_desc": "Spaltet projektile", "bk:spectacles": "Sehhilfe", "bk:spectacles_desc": "Deckt Geheimnisse auf", "bk:cross": "Kreuz", "bk:cross_desc": "Erhöht die Dauer der Unsterblichkeit", "bk:slime": "Slime", "bk:slime_desc": "Lässt deine Schüsse abprallen!", "bk:missile": "Rakete", "bk:missile_desc": "Zielsuchende Schüsse", "bk:rod_of_discord": "Discord Zauberstab", "bk:rod_of_discord_desc": "Teleportation für Jedermann", "bk:goo": "Glibber", "bk:goo_desc": "Begleiter-Freund", "bk:jelly": "Gelee!", "bk:jelly_desc": "^^Wackelig^^", "bk:broken_stone": "Gebrochener Stein", "bk:broken_stone_desc": "Gut gebautes Orbital", "bk:nano_orb": "Mini Orb", "bk:nano_orb_desc": "Micro freund", "bk:saturn": "Planet", "bk:saturn_desc": "Natürlich haben wir ihn auch lieb", "bk:soap": "Seife", "bk:soap_desc": "Nicht fallen lassen! (Langamere Projektile)", "bk:d6": "D6", "bk:d6_desc": "Gegenstände ^^durchmischen^^!", "bk:my_heart": "Mein Herz", "bk:my_heart_desc": "Mehr Leben", "bk:broken_heart": "Gebrochenes Herz", "bk:broken_heart_desc": "Mehr Leben", "bk:parcel": "Paketchen", "bk:parcel_desc": "Wiederverwendbare Heilung", "bk:glass": "Glas", "bk:glass_desc": "##Zerbrechliche## Projektile", "bk:glass_bullet": "Glass Patrone", "bk:glass_bullet_desc": "Schieße über Steine", "bk:broken_guitar": "Demolierte Gitarre", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Maschinengewehr", "bk:machine_gun_desc": "Vollautomatisch", "bk:grenade_launcher": "Granatenwerfer", "bk:grenade_launcher_desc": "Kaboom!", "bk:shotgun": "Shotgun", "bk:shotgun_desc": "Bitte Sicherheitsabstand einhalten!", "bk:missile_launcher": "Portable Raketenabschussrampe", "bk:missile_launcher_desc": "Verrückte Technologie...", "bk:burst_gun": "Feuerstoßgewähr", "bk:burst_gun_desc": "Mit Lichtgeschwindigkeit!", "bk:flak_cannon": "Flakkanone", "bk:flak_cannon_desc": "Zeit für Party!", "bk:disk_gun": "Scheiben-Pistole", "bk:disk_gun_desc": "Scharfe Angelegenheit", "bk:duck_gun": "Enten-Pistole", "bk:duck_gun_desc": "Jetzt ist Ente im Gelände", "bk:follower": "Follower", "bk:follower_desc": "\"Und lasst nen like da!\"", "bk:portal_gun": "Portal Gun", "bk:portal_gun_desc": "Der Kuchen war eine Lüge!", "bk:snowflake": "Schneeflocke", "bk:snowflake_desc": "Frier sie alle ein!", "bk:restock": "Auffüllen", "bk:restock_desc": "Unbegrenzte Angebote in Shops", "bk:charisma_ring_desc": "Königliche Angebote", "bk:charisma_ring": "Charisma Ring", "bk:battery": "Batterie", "tomb_0": "Hier liegt [cl green]Gobbo[cl] der Große", "bk:homemade_dice": "Hausgemachter Würfel", "bk:homemade_dice_desc": "Gegenstände ^^durchmischen^^! (DIY)", "shopkeeper_0": "##ICH SAGTE DU SOLLST DAS LASSEN!##", "shopkeeper_1": "Bitte, aufhören!", "shopkeeper_2": "Mach das nicht.", "shopkeeper_3": "[cl red]##MACH DICH BEREIT ZUM STERBEN!##", "shopkeeper_4": "[cl red]DIEB!", "shopkeeper_5": "[cl red]SCHNAPP IHN DIR!", "desert": "Wüstentempel", "jungle": "Uralter Dschungel", "ice": "Eis-Ruinen", "bk:iron_boots": "Eisenstiefel", "bk:iron_boots_desc": "Stacheln tun nicht mehr weh", "bk:mimic_totem": "Nachahm-Totem", "bk:mimic_totem_desc": "##KEINE NACHAHMUNGEN MEHR##", "back_to_town": "Zurück ins Dorf", "bk:glass_gun": "Glas-Pistole", "bk:glass_gun_desc": "##Zerbrechlich##", "bk:glass_shard": "Glassplitter", "bk:glass_shard_desc": "Nur ein kleiner Teil des Ganzen", "bk:disk_10": "Platte №10", "bk:disk_10_desc": "Ladenbesitzer", "bk:disk_1": "Platte 1", "bk:disk_1_desc": "Zuhause", "bk:disk_2": "Platte 2", "bk:disk_2_desc": "Wald", "bk:disk_3": "Platte 3", "bk:disk_3_desc": "Dschungel", "bk:disk_4": "Platte 4", "bk:disk_4_desc": "Eis", "bk:disk_5": "Platte 5", "bk:disk_5_desc": "Kerker", "bk:disk_6": "Platte 6", "bk:disk_6_desc": "Hölle", "bk:disk_7": "Platte 7", "bk:disk_7_desc": "???", "bk:disk_8": "Platte 8", "bk:disk_8_desc": "Leere", "bk:disk_9": "Platte 9", "bk:disk_9_desc": "Schnitt", "bk:dagger": "Messer", "bk:dagger_desc": "Nostalgie...", "bk:spear": "Speer", "bk:spear_desc": "Längere arme?", "shopkeeper_6": "Willkommen :)", "shopkeeper_7": "Wie gehts,[dl] darf ich dir etwas [cl yellow]Tee[cl] anbieten?", "shopkeeper_8": "Wie gehts wie stehts?", "back": "Zurück", "master_volume": "Allgemeine Lautstärke", "music": "Musik", "sfx": "Soundeffekte", "graphics": "Grafik", "audio": "Audio", "ui_sfx": "Menü-Soundeffekte", "on": "An", "off": "Aus", "fullscreen": "Vollbild", "vsync": "V-Sync", "fps": "FPS Anzeige", "speedrun_timer": "Speedrun Modus", "screenshake": "Bilschirmwackeln", "freeze_frames": "Freeze Frames", "flash_frames": "Flash Frames", "reset_progress": "Fortschritt zurücksetzen", "blood_n_gore": "Blut und Innereien", "vegan_mode": "Vegan-Modus", "reset_settings": "Einstellungen zurücksetzen", "are_you_sure": "Bist du dir sicher?", "yes": "Yes", "reset_progress_dis": "Das wird deinen GESAMTEN FORTSCHRITT löschen!", "reset_settings_dis": "Das wird ALLE Einstellungen zurücksetzen!", "autosave": "Automatisch Speichern", "autopause": "Automatisch Pausieren", "input": "Eingabe", "use": "Benutzen", "active": "Aktiv", "bomb": "Bombe", "interact": "Interagieren", "swap": "Waffen tauschen", "roll": "Rollen", "duck": "Ducken", "pause": "Pause", "none": "Nichts", "keyboard_controls": "Tastatursteuerung", "gamepad_controls": "Gamepadsteuerung", "keyboard": "Tastatur", "gamepad": "Gamepad", "game": "Spiel", "select": "Auswählen", "cursor": "Zeiger", "bk:rip": "RIP", "ach_bk:rip_desc": "Stirb", "ach_bk:overshake": "Überschüttelung", "ach_bk:overshake_desc": "1000% screen shake", "ach_bk:rip": "Beliebteste Errungenschaft", "bk:emerald": "Smaragd", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Danke!^^", "shopkeeper_11": "Was für ein %%Deal%%!", "shopkeeper_12": "Willst du ^^Etwas^^ [cl red]kaufen[cl]?", "shopkeeper_13": "Exclusiv nur für [cl green]dich[cl] und nur heute!", "shopkeeper_14": "So viele [cl yellow]unglaublich gute[cl] Angebote!", "bk:magnifier": "Lupe", "bk:magnifier_desc": "Größere Projektile", "bk:mushroom_hat": "Pilzhut", "bk:mushroom_hat_desc": "Schmeckts?", "bk:stone_hat": "Steinhut", "bk:stone_hat_desc": "Leider recht schwer", "bk:knight_hat": "Ritterhelm", "bk:knight_hat_desc": "Hile, ich seh nichts mehr!", "bk:cowboy_hat": "Cowboyhut", "bk:cowboy_hat_desc": "YEEHAW", "bk:soup_hat": "Suppenhut", "bk:soup_hat_desc": "^^Lecker!^^", "bk:gold_hat": "Goldener Hut", "bk:gold_hat_desc": "[cl yellow]Reichtum!", "bk:viking_hat": "Wikingerhelm", "bk:viking_hat_desc": "Nur für die starken Männer!", "bk:dunce_hat": "Dummkopf Hut", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Zylinder", "bk:top_hat_desc": "Modisch!", "bk:ushanka": "Ushanka", "bk:ushanka_desc": "Wo ist meine ##balalaika?##", "bk:valkyrie_hat": "Walküren Hut", "bk:valkyrie_hat_desc": "^^I belive I can fly!^^", "bk:skull_hat": "Schädelhut", "bk:skull_hat_desc": "Moralisch gesehen eher fragwürdig.", "bk:grandma_head": "Omi's Kopf", "bk:grandma_head_desc": "\"Und du bist auch wirklich satt?\"", "bk:diamond_helmet": "Diamanthelm", "bk:diamond_helmet_desc": "Grab niemals gerade nach unten!", "bk:villager_head": "Dorfbewohnerkopf", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fes", "bk:fez_desc": "Schick!", "bk:no_hat": "Hut entfernen", "bk:no_hat_desc": "Kein Hut - kein Stress!", "bk:null_hat": "NULL", "bk:null_hat_desc": "ERROR! NullPointerException at NullItem:43", "accessorytrader_0": "##RAUS HIER!## [dl]Oder natürlich du kaufst ein paar dieser ^^wunderbaren^^ Gegenstände für nur ^^%%99 Diamanten pro Stück%%^^!", "accessorytrader_1": "Hi", "accessorytrader_2": "Na?", "weapontrader_0": "Kommen'se rein!", "weapontrader_1": "Nen' guten Tag, der Herr!", "weapontrader_2": "Willst was kaufen? Scho' oder?", "activetrader_0": "Die besten Angebote auf dem Markt!", "activetrader_1": "Zahl für Zwei und bekomme auch Zwei!", "activetrader_2": "Gebt mir Donuts, [dl]bitte!!", "hattrader_0": "Möchten Sie so cool sein wie ich? [dl]Legen Sie sich einen neuen Hut zu!", "hattrader_1": "Wollen Sie auch so unglaublich gut ausschauen wie ich? [dl]Treten Sie näher!", "hattrader_2": "^^Wunderbare neue Hüte, exklusiv für Sie ausgesucht!^^", "granny_0": "Willst du etwas Tee?", "granny_1": "Setz dich![dl]Mach kurz 'ne Pause!", "granny_2": "Du bist so Groß geworden!", "bk:xmas_hat": "Weihnachtsmütze", "bk:xmas_hat_desc": "Frohe Weihnachten!", "bk:pumpkin_hat": "Ausgeschnitzter Kürbis", "bk:pumpkin_hat_desc": "^^spooky scary skeletons^^", "bk:cage_key": "Gefängnisschlüssel", "bk:cage_key_desc": "Rette ^^den Kerl^^!", "npc_0": "Hilf mir! Such den Schlüssel!", "npc_1": "Vielen Dank, dass du mich gerettet hast!", "npc_2": "Schneller! Sperr die Tür auf!", "npc_3": "Bitte! Hilf mir!", "control_0": "Drücke [ic 0][ic 1] um eine Bombe zu werfen!", "control_1": "Rollen, du kannst! [ic 0][ic 1] drücken, du musst!", "control_2": "Drücke [ic 0][ic 1] um anzugreifen", "control_3": "Drücke [ic 0][ic 1] um zu interagieren", "control_4": "Quak? [ic 0][ic 1]!", "control_5": "Drücke [ic 0][ic 1] um Waffen zu wechseln", "shopkeeper_15": "Kein Angebot für dich!", "shopkeeper_16": "Schnapp dir ein bisschen mehr Geld und dann komm wieder!", "shopkeeper_17": "Du musst schon erst bezahlen!", "bk:frog": "Tele-Frosch", "bk:frog_desc": "Wuschhh", "bk:sword_orbital": "Schwert-Orbital", "bk:sword_orbital_desc": "Gerechtigkeit!", "robbed": "Beklaut", "bk:gift_desc": "Was da wohl drinnen ist?", "bk:spike_ring": "Stachelring", "bk:spike_ring_desc": "Deine Feinde müssen ##bestraft## werden!", "bk:fire_ring": "Freuerring", "bk:fire_ring_desc": "Lass sie BRENNEN", "bk:ice_ring": "Eisring", "bk:ice_ring_desc": "Stoppe deine Gegner", "bk:duck_ring": "Entenring", "bk:duck_ring_desc": "Teleportiert dich beim Schaden nehmen", "bk:dull_blade": "Stumpfe Klinge", "bk:dull_blade_desc": "Löst Schadenseffekt aus", "bk:sharp_blade": "Scharfe Klinge", "bk:sharp_blade_desc": "Echt scharf, lieber aufpassen!", "bk:obsidian_shield": "Obsidianschild", "bk:obsidian_shield_desc": "Rückstoß = 0", "bk:bill": "Rechnung", "bk:bill_desc": "99 Euro", "control_6": "Setzte dein aktives Item mit [ic 0][ic 1] ein!", "bk:clover": "Vierblättriges Kleeblatt", "bk:clover_desc": "Glückspilz!", "bk:d4": "D4", "bk:d4_desc": "^^%%Neue Artifakte!%%^^", "brastin_0": "Finde das [cl purple]Katzen-Gemälde[cl]!", "elon_0": "Ich kann deine Waffe in eine Andere verwandeln", "elon_1": "Hier, bitteschön. Viel Spaß damit!", "bk:maanex_head": "Maanex Kopf", "bk:maanex_head_desc": "Hmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Lässt alle Gegner für einen Moment nachdenken", "mob_0": "Hmmmm", "bk:map_greenprints": "Karten Grünpause", "bk:map_greenprints_desc": "Deckt alle Räume auf", "bk:map": "Karte", "bk:map_desc": "Deckt die gesamte Ebene permanent auf", "milt_1": "Ich will Geschenk.", "mapuzzle_0": "Schweeerkraaaft.", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Kopiert!", "isaac_0": "Leben hat keinen Sinn...", "isaac_1": "Waruuuuuummmmm????", "isaac_2": ":sob:", "discord_0": "Sag Hi! discord.gg\/rexcellent", "old_man_5": "Rollen, Dummkopf!", "tutorial": "Tutorial", "bk:the_key": "Der Schlüssel", "bk:the_key_desc": "Öffnet den Ausgang", "bk:crying_bomb": "Heulende Bombe", "bk:crying_bomb_desc": "Bomben weinen jetzt!", "bk:matches": "Streichhölzer", "bk:matches_desc": "Explosionen explodieren schneller", "bk:bomb_pack": "Bombenpack", "bk:bomb_pack_desc": "Wir packen Bomben in deine Bomben!", "bk:tnt": "TNT", "bk:tnt_desc": "99 Bomben", "bk:weird_mushroom_desc": "Verdoppelt alles!", "bk:weird_mushroom": "Komischer Pilz", "bk:bomb_shower": "Bomben-Dusche", "bk:bomb_shower_desc": "Lass es Bomben regnen!", "bk:black_belt": "Schwarzer Gürtel", "bk:black_belt_desc": "\"Explosionen machen mir nichts mehr aus!\"", "bk:ninjia_bomb": "Ninjia-Bombe", "bk:ninjia_bomb_desc": "Erschafft Bomben, wenn du verletzt wirst!", "start_new_run": "Dein momentaner Run wird verloren gehen!", "bk:laser_pointer": "Laser Pointer", "bk:laser_pointer_desc": "Ziel ist im Visier!", "ach_bk:marauder": "Plünderer", "ach_bk:marauder_desc": "Töte den Ladenbesitzer", "ach_bk:treasure_hunter": "Schatzjäger", "ach_bk:treasure_hunter_desc": "Finde einen geheimen Raum", "ach_bk:dodge_master": "Meister des Ausweichens", "ach_bk:dodge_master_desc": "Töte einen Boss-Gegner ohne Schaden zu nehmen", "ach_bk:dodge_overlord": "Jetzt übertreib mal nicht!", "ach_bk:dodge_overlord_desc": "Schaff es durch eine Ebene, ohne Schaden zu nehmen", "ach_bk:quackers": "Quak Quak Quak", "ach_bk:quackers_desc": "Quak Quak Quak Quak Quak Quak", "ach_bk:tea_party": "Zeit für einen Tee", "ach_bk:tea_party_desc": "Lass dir von der Großmutter einen Tee servieren", "ach_bk:not_a_thief": "Alles andere als ein Dieb", "ach_bk:not_a_thief_desc": "Beende einen Run ohne auch nur einen einzigen Gegenstand mitgehen zu lassen", "ach_bk:npc_party2": "NPC Party", "ach_bk:npc_party2_desc": "Rette alle NPCs", "bk:gold_coin": "Goldmünze", "bk:iron_coin": "Silbermünze", "bk:copper_coin": "Kupfermünze", "bk:platinum_coin": "Platinmünze", "bk:voodoo_doll": "Voodoo Puppe", "bk:voodoo_doll_desc": "Tötet alle Gegner im Raum", "hub": "Rollingen", "castle": "Burgruinen", "charger_0": "KEIN AKTIVER GEGENSTAND GEFUNDEN", "charger_1": "AKTIVER GEGENSTAND IST BEREITS VOLLKOMMEND AUFGELADEN", "charger_2": "WO IST MEIN GELD, DU FLEISCHSACK?", "charger_3": "##ICH SAGTE GIB MIR MEIN GELD!##", "charger_4": "##ICH WERDE DIE WELTHERRSCHAFT AN MICH REIßEN!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Na klar, gerne!", "maanex_6_1": "Ne, lass mal lieber.", "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?", "maanex_5": "Hallöchen, lust auf ein kleines ^^Glücksspiel^^?", "maanex_7": "Das war super!", "maanex_8": "Viel Glück!", "maanex_9": "Ahhh, das tut mir leid. Vielleicht nächstes Mal!", "maanex_10": "%%^^WOAH^^%%", "maanex_11": "Aber... [dl]ähh... [dl] du hast nicht genug Geld!", "maanex_12": "##SOHN?![dl] BIST DUS?!##", "bk:amurs_arrow": "Amors Pfeil", "bk:amurs_arrow_desc": "Bezaubernde Projektile", "bk:amurs_bow": "Amors Bogen", "bk:amurs_bow_desc": "Herzschmerz vorprogrammiert", "bk:poison_flask": "Gift-Flasche", "bk:poison_flask_desc": "Vergiftete Projektile", "bk:snowball": "Schneeball", "bk:snowball_desc": "Eiskalte Projektile", "bk:peper_desc": "Richtig Heiße Projektile", "bk:peper": "Chilischote", "bk:sale_coupon": "Rabatt Gutschein", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Haustier in einer Box", "bk:pet_box_desc": "Was da wohl drinnen ist?", "bk:crate": "Orbital-Box", "bk:crate_desc": "Hallo? Ist da jemand drinnen?", "bk:strawberry": "Erdbeere", "bk:strawberry_desc": "Süße Erinnerungen", "bk:wings": "Flügel", "bk:wings_desc": "\"I belive I can fly\"", "bk:coin_pouch": "Münzbeutel", "bk:coin_pouch_desc": "Gibt dir ein paar Münzen", "bk:key_pouch": "Schlüssel-Säckchen", "bk:key_pouch_desc": "Gibt dir eine handvoll Schlüssel", "bk:bomb_pouch": "Bombenbeutel", "bk:bomb_pouch_desc": "Gibt dir Bomben", "bk:pouch_pouch": "Beutel-Beutel", "bk:pouch_pouch_desc": "Gibt dir noch mehr Beutel", "bk:lightsaber": "Lichtschwert", "bk:lightsaber_desc": "Ich hab da ein ganz mieses Gefühl...", "bk:snail": "Schnecke", "bk:snail_desc": "Liiichtgeeschwwindigkeeiit. *gähn*", "bk:spike": "Stachel", "bk:spike_desc": "MEHR SCHADEN!", "bk:mushroom": "Pilz", "bk:mushroom_desc": "Schneller, SCHNELLER!", "bk:candy": "Bonbon", "bk:candy_desc": "^^Zuckerrausch^^, schieß jetzt noch schneller!", "bk:glasses": "Brille", "bk:glasses_desc": "Bessere Zielgenauigkeit", "bk:ruler": "Lineal", "bk:ruler_desc": "Erhöhte Reichweite", "bk:stopwatch": "Stoppuhr", "bk:stopwatch_desc": "Um kurz anzuhalten, wenn du getroffen wirst", "bk_0": "##WAG ES JA NICHT DAS ANZUFASSEN!##", "bk_1": "##HÖRST DU SCHLECHT? [dl]ICH SAGTE NICHT ANFASSEN!##", "bk_2": "##DU KANNST DEN [cl red]BURNING KNIGHT[cl] NICHT BESIEGEN!##[dl] Dummkopf...", "bk_3": "##DU HAST ES SCHEINBAR SO GEWOLLT!##", "bk_4": "^^SO EINE WITZFIGUR^^", "shopkeeper_18": "[cl red]^^Heiße Angebote![cl]", "dm_0": "@@Willkommen@@", "ach_bk:deal": "Überragender Schachzug", "ach_bk:deal_desc": "Lass dich auf einen Deal mit dem dunklen Magier ein", "ach_bk:grannys_gift": "Geschenk von Oma", "ach_bk:grannys_gift_desc": "Wenn da mal keine Socken drinnen sind...", "ach_bk:shopper": "Wirtschaft ankurbeln", "ach_bk:shopper_desc": "Kauf dir Etwas in einem Laden", "bk_5": "AN DEINER STELLE WÜRDE ICH MIR NICHT EINMAL DIE MÜHE MACHEN, MIT IHM ZU REDEN", "bk_6": "##TÖTE IHN, [cl lime]BERND[cl]!##", "bk_7": "[cl lime]BERND[cl], ##NEEEEEEEEIN!!!!##", "bk_8": "ACH KOMM SCHON, HÖR AUF HIER ALLES IN DIE LUFT ZU JAGEN!", "bk_9": "Oh, [cl pink]guten Tag[cl], die Dame. [dl]Ich hoffe mein ^^Gast^^ hier stört Sie nicht.", "bk_10": "MEIN MEISTER,[dl] ICH HABE DEN [cl green]GOBLIN[cl] MITGEBRACHT, WIE VEREINBART.", "dm_1": "Sehr gut[dl], vielen dank[dl], [cl red]Limpor[cl]", "dm_2": "Ja,[dl] oh ja,[dl] ICH BRAUCHE MEHR [cl orange]##ENERGIE##[cl]!", "dm_3": "##MEHR [cl orange]ENERGIEEEEE[cl]!##", "dm_4": "Ich kann [cl orange]die Energie[cl] schon förmlich Spüren!", "granny_3": "Er macht nen netteren Eindruck als du, [cl red]Limpor[cl]!", "granny_4": "Willkommen, [cl green]Gobbo [vr id][cl]!", "granny_5": "Viel Glück und Erfolg! [dl]Pass auf dich auf!", "bk:meat_guy": "Fleisch Typ", "bk:meat_guy_desc": "Joa...", "bk:bullet_stone": "Patronen Patron", "bk:bullet_stone_desc": "Ein kleiner Schutzengel", "bk:batman": "Batman", "bk:batman_desc": "Hilft nicht, aber gibt dir Batterien", "vibration": "Vibration", "bk:sharp_arrow": "Spitzer Pfeil", "bk:sharp_arrow_desc": "Erhöhte Projektil Penetration", "machine_0": "[cl yellow]Münze [cl]einwerfen", "player_0": "Papa?? ##Was haben die mit dir gemacht?!?##", "bk:boomerang": "Boomerang", "bk:boomerang_desc": "Boomerang Projektile", "bk:backpack": "Rucksack", "bk:backpack_desc": "Das wandern ist des Müllers lust", "place_an_item": "Gegenstand hineinlegen", "bk:crystal": "Kristall", "bk:crystal_desc": "Mit der Kraft des %%Regenbogen%%", "bk:prism": "Prisma", "bk:prism_desc": "Projektile -> %%Regenbogen%%", "scourged": "Verflucht", "bk:bomb": "Bombe", "bk:scourge_of_egg": "Fluch des Eies", "bk:scourge_of_egg_desc": "Vertauschte Gegenstandsnamen", "bk:scourge_of_unknown": "Fluch des Unbekannten", "bk:scourge_of_unknown_desc": "Gegenstände versteckt", "bk:scourge_of_blood": "Fluch des Blutes", "bk:scourge_of_blood_desc": "Gegner verdoppelt", "bk:scourge_of_risk": "Fluch des Risikos", "bk:scourge_of_risk_desc": "Versteckte Lebensanzeige", "bk:scourge_of_keys": "Fluch der Schlüssel", "bk:scourge_of_keys_desc": "Münzen, Bomben und Schlüssel versteckt", "bk:scourge_of_lost": "Fluch der Orientierungslosigkeit", "bk:scourge_of_lost_desc": "Amnesie", "bk:scourge_of_scourged": "Fluch der Flüche", "bk:scourge_of_scourged_desc": "Flüche überall!", "bk:scourge_of_illness": "Fluch der Krankheit", "bk:scourge_of_illness_desc": "Heilung weniger effektiv", "bk:scourge_of_death": "Fluch des Todes", "bk:scourge_of_death_desc": "Leben am Limit", "bk:ancient_revolver": "Uralter Revolver", "bk:ancient_revolver_desc": "Schaut cool aus", "bk:assault_rifle": "Sturmgewehr", "bk:assault_rifle_desc": "Ratatatatatata", "fountain_0": "Bringe 5 Münzen und du seist gesegnet", "fountain_1": "Du wurdest teilweise gereinigt", "fountain_2": "Du wurdest vollkommend gereinigt", "fountain_3": "Du bist bereits gereinigt", "buffed": "Verbessert", "nerfed": "Verschlechtert", "restored": "Wiederhergestellt", "damaged": "Verletzt", "cleansed": "Gereinigt", "gifted": "Beschenkt", "lucky": "Glück gehabt!", "unlucky": "Pech gehabt!", "max_hp": "Maximale HP", "touch": "Anfassen", "break": "Zerstören", "no_coins": "Keine Münzen", "old_man_6": "Es ist gefährlich alleine zu gehen, nimm das!", "roger_0": "Kaboom!", "roger_1": "##*BOOM*##", "roger_2": "Boom boom shakalaka!", "bk:shield": "Schild", "bk:gift": "Geschenk", "bk:shield_pouch": "Schildsäckchen", "bk:shield_pouch_desc": "Gibt dir Schilde", "bk:shield_buddy": "Schild Kumpel", "bk:shield_buddy_desc": "Beschützt dich!", "bk:skeleton_key": "Skelettschlüssel", "bk:skeleton_key_desc": "99 Schlüssel", "bk:jar": "Lebenstrank", "bk:jar_desc": "Aber nicht alles aufeinmal!", "bk:star": "Stern", "bk:star_desc": "%%^^Weeeeeee^^%%", "bk:car_bomb": "Autobombe", "bk:car_bomb_desc": "Bomben-Lieferservice", "bk:grenade": "Granate", "bk:grenade_desc": "Explodiert bei Berührung", "trash_goblin_0": "Befrei mich von meinem [cl purple]Fluch[cl]![dl] Bitte!", "trash_goblin_1": "ICH BIN FREI![dl] Vielen, vielen Dank!", "boxy_0": "Schlüsselhaft...", "boxy_1": "Was für eine schöne Box!", "boxy_2": "Brauchst du noch Geschenkpapier?", "trash_goblin_2": "[ic 0] ^^Atemlos... [dl]durch die Naaaacht...^^ [ic 1][dl] ##BIS EIN NEUER TAG ERWAAAACHT[ic 0]##", "bk:vampire_bat": "Vampir Fledermaus", "bk:vampire_bat_desc": "Regeneration", "shields": "Schilder", "bk:mustache": "Schnurrbart", "bk:mustache_desc": "Premium", "bk:bloody_chest": "Blutige Kiste", "bk:bloody_chest_desc": "Kisten heilen dich", "bk:bloody_shield": "Blutiges Schild", "bk:bloody_shield_desc": "Schilder bis zum Lebensende", "bk:cutsaw": "Kreissäge", "bk:cutsaw_desc": "Sie werden bezahlen, MUHAHAHAHA", "vampire_0": "Mhhh!", "vampire_1": "Einfach nur Herzerwärmend!", "vampire_2": "So süß!", "vampire_3": "We know the rules, [cl red]^^right[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "Welche Blutgruppe hast du?", "vampire_6": "So lecker!", "duck_2": "Entschuldigung,[dl] hätten Sie kurz Zeit für eine kleine Umfrage?", "duck_7_0": "Klar", "duck_7_1": "Nö", "duck_7": "Willst du die Kiste?", "duck_4": "Sehr gut! Dann darfst du die Kiste haben!", "duck_5": "Dem kann ich leider nicht zustimmen!", "duck_6_0": "Pizza", "duck_6_1": "Steuern", "duck_6": "Über was denke ich gerade nach?", "duck_8_0": "[cl red]Rot[cl]", "duck_8_1": "[cl blue]Blau[cl]", "duck_8": "Welche ist meine ^^%%Lieblingsfarbe%%^^?", "duck_9_0": "Eine Katze", "duck_9_1": "Du, gerade im Moment", "duck_9": "Wer sagt \"Miau\"?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "Was ist besser?", "duck_11_0": "What, you egg?", "duck_11_1": "\\[_He stabs him._]", "duck_11": "\"You are a saucy boy\"", "duck_12_0": "Henne", "duck_12_1": "Ei", "duck_12": "Was kam zuerst?", "duck_13_0": "Müsli, Milch, Löffel", "duck_13_1": "Milch, Müsli, Löffel", "duck_13_2": "Löffel, Milch, Müsli", "duck_13_3": "Müsli, Käse, Salat, Gabel", "duck_13": "Welche ist die richtige Reihenfolge?", "duck_14": "Autsch.", "duck_17_0": "Na klar!", "duck_17_1": "##EKELHAFT##", "duck_17": "Ananas auf Pizza?", "duck_18_0": "Weiss!", "duck_18_1": "[cl yellow]Gelb![cl]", "duck_18": "Welche Farbe hat Käse?", "nurse_0": "Du schaust super aus, Liebling!", "nurse_1": "Ich könnte dich etwas Ärztlich versorgen.[dl] Nicht versichert? Dann macht das [cl yellow][vr price] Münzen[cl]!", "nurse_2": "Ich hoffe das hat jetzt nicht wehgetan!", "elon_4": "Hier, Bitteschön, viel Spaß!", "elon_2_0": "Losgehts", "elon_2_1": "HALT STOP", "elon_2": "Willst du ein bisschen Magie ausprobieren?", "elon_3": "Ich kann deine Waffe in eine Andere verwandeln!", "elon_5": "Okay...", "elon_7": "Junge, wo ist dein Waffe?", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*peinlich berührter Gesichtsausdruck*", "gobetta_4": "Bist du's?", "gobetta_5": "Es ist so lange her..", "ach_bk:desert": "Trocken und Heiß", "ach_bk:desert_desc": "Erreiche den Wüstenpalast", "ach_bk:jungle": "Sum sum sum", "ach_bk:jungle_desc": "Erreiche den verlorenen Tempel", "rooms_explored": "Räume erkundet", "bk:shadow_cloak_desc": "Nein, du!", "bk:shadow_cloak": "Schattenumhang", "bk:dynamite_stick": "Dynamitstange", "bk:dynamite_stick_desc": "Willst du explodieren?", "bk:chalice_of_blood": "Kelch des Blutes", "bk:chalice_of_blood_desc": "Furcht führt zu Wut, Wut führt zu Hass, Hass führt zu unsäglichem Leid", "bk:detonator": "Zündvorrichtung", "bk:detonator_desc": "Jagt Sprengkörper in die Luft", "invincibility_time": "Unbesiegbarkeitszeit", "accuracy": "Zielgenauigkeit", "range": "Reichweite", "fire_rate": "Feuerrate", "speed": "Geschwindigkeit", "bk:talisman_of_foresight": "Talisman der Voraussicht", "bk:talisman_of_foresight_desc": "Öffne deine Augen und sieh in angrenzende Räume!", "bk:scourge_ring": "Fluchring", "bk:scourge_ring_desc": "Schnipp Schnapp, Fluch hau ab.", "snek_0": "Cool.", "snek_1": "Sssehr nett, man", "snek_2": "Vvvverrückt!", "snek_3": "Wie gehtssss?", "snek_4": "Guten Tag, Ssssir", "snek_5": "Wollen Ssssie was kaufen?", "snek_6": "Kunde isssst König", "snek_7": "Ich werde tun, wassss ich musssss", "bk:snek": "Snek", "bk:snek_desc": "Snack?", "boxy_3": "^^:wave:^^", "boxy_4": "Hey, hast nen Schlüssel übrig?", "boxy_5": "Was dagegen ein paar Schlüssel zu spenden?", "bk:blank": "Leer", "bk:blank_desc": "_Leerer Text_", "bk:blank_bombs": "Leere Bomben", "bk:blank_bombs_desc": "Schusssicheres Schild", "bk:explosive_bullets": "Explosive Schüsse", "bk:explosive_bullets_desc": "bumm bumm", "bk:random_bullets": "Zufällige Projektile", "bk:random_bullets_desc": "Alle Angaben ohne Gewehr", "bk:cup": "Tasse", "bk:cup_desc": "*Schlürf*", "bk:cartridge": "Druckerpatrone", "bk:cartridge_desc": "Da kann selbst der dunkle Magier nicht wiederstehen!", "bk:marriage_ring": "Hochzeitsring", "bk:marriage_ring_desc": "DM & Omi <3", "boxy_7": "Ich will Schlüssel", "boxy_8": "Du scheinst nicht genug Schlüssel zu haben :(", "boxy_9": "Ayyy, super![dl] Jetzt hab ich genug Schlüssel, danke!", "roger_3": "Lust zu spielen?", "roger_4": "Keine Rabatte heute, sorry", "roger_5": "Bombastisch!", "vampire_7": "Du hast nicht genug Blut!", "vampire_8": "Ich geb hier keine Preisnachlässe...", "vampire_9": "Deine HP scheinen zu niedrig zu sein...", "ach_bk:scourged": "Verflucht", "ach_bk:scourged_desc": "Hebe eine Fluch-Rune auf", "ach_bk:scourged_weapon": "Verfluchte Waffe", "ach_bk:scourged_weapon_desc": "Hebe eine verfluchte Waffe auf", "rerolled": "Gegenstände durchgemischt!", "ach_bk:open_up": "Open Up", "ach_bk:open_up_desc": "Kaufe alles was Boxy anbietet.", "ach_bk:snek": "Snek", "ach_bk:snek_desc": "Bekomme Snek dazu dein Haustier zu sein.", "bk:scourge_of_greed": "Fluch der Gier", "bk:scourge_of_greed_desc": "Hohe Preise", "killed_by": "Getötet durch", "kills": "Tötungen", "time": "Zeit", "depth": "Ebene", "bk:blank_bullets": "Leere Kugeln", "bk:blank_bullets_desc": "Leer", "bk:lego": "Baustein", "bk:lego_desc": "Aus rechtlichen Gründen können wir hier leider nicht den allseits bekannten Namen verwenden.", "bk:iron_armor": "Eisenrüstung", "bk:iron_armor_desc": "Gibt Schilde", "bk:round_shield": "Rundes Schild", "bk:round_shield_desc": "Verhindert Schaden durch direkten Kontakt", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "Wie in der Legende", "bk:inverted_arkhalis": "Invertiertes Arkhalis", "bk:inverted_arkhalis_desc": "Hilfe kommt kurz vorm Tod", "bk:gun_sword": "Pistolen-Schwert", "bk:gun_sword_desc": "Jetzt gibt es Ärger!", "ach_bk:scourge_king_desc": "Bekomme 10 Fluch-Punkte", "ach_bk:scourge_king": "König der Flüche", "ach_bk:sting_operation": "Stachlige Angelegenheit", "ach_bk:sting_operation_desc": "Besiege die Bienenkönigin", "ach_bk:mummified": "Mumifiziert", "ach_bk:mummified_desc": "Besiege den Pharao", "ach_bk:democracy": "Demokratie", "ach_bk:democracy_desc": "Besiege den alten König", "pharaoh_scream": "##MACH DICH BEREIT FÜR DEN SARG!##", "queen_bee_scream": "##FÜR DEN [cl yellow]HONIG LORD[cl]!##", "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...", "duck_20": "quack. ", "bk:half_heart": "Halbes Herz", "right": "Rechts", "down": "Runter", "left": "Links", "up": "Hoch", "painting_cat": "Katzen-Gemälde", "bk:axe": "Axt", "bk:axe_desc": "Hat versprochen wiederzukommen", "bk:guitar": "Gitarre", "bk:guitar_desc": "Ist leider verstimmt", "bk:glass_sword": "Glas-Schwert", "bk:glass_sword_desc": "Man sieht die Klinge nicht kommen...", "bk:chicken": "Hähnchenflügel", "bk:chicken_desc": "Scharf wie sonst noch was...", "bk:pickaxe": "Spitzhacke", "bk:pickaxe_desc": "Grab schneller, du fauler Sack!", "bk:mana": "Mana", "bk:half_mana": "Halbe Mana", "bk:lava_wand": "Lava-Zauberstab", "bk:lava_wand_desc": "Hitzige Sache", "bk:web_wand": "Spinnen-Zauberstab", "bk:web_wand_desc": "World-Wide-Web Anbieter", "bk:slap_stick": "Fernklatscher", "bk:slap_stick_desc": "Klatsch!", "sensivity": "Empfindlichkeit", "no": "Nein", "scale": "Zoom-Faktor", "ach_bk:ice": "Eiszeit", "ach_bk:ice_desc": "Erreiche die Eis-Ruinen", "ach_bk:library": "Die heiligen Texte!", "ach_bk:library_desc": "Erreiche die geheime Bibliothek", "bk:ice_skates": "Schlittschuhe", "bk:ice_skates_desc": "Für mehr Körperkontrolle auf dem Eis", "bk:campfire_in_bottle": "Lagerfeuer in der Flasche", "bk:campfire_in_bottle_desc": "Immunität gegen Einfrieren", "library": "Geheime Bibliothek", "ach_bk:cat_without_a_hat": "Katze ohne Hut", "ach_bk:cat_without_a_hat_desc": "Finde das Katzen-Gemälde", "ach_bk:rich": "Toilettenpapier", "ach_bk:rich_desc": "Besitze 99 Münzen", "ach_bk:rescue_operation": "Rettungsaktion", "ach_bk:rescue_operation_desc": "Rette einen NPC", "ach_bk:tutorial": "Guru", "ach_bk:tutorial_desc": "Beende das Tutorial", "ach_bk:fancy_hat": "Schicker Hut!", "ach_bk:fancy_hat_desc": "Kauf dir einen Hut", "ach_bk:unlock": "Sammler", "ach_bk:unlock_desc": "Schalte einen Gegenstand frei", "floor_brightness": "Boden-Helligkeit", "ach_bk:shielded": "Schilde Hoch!", "ach_bk:shielded_desc": "Sammle ein Schild-Herz", "run_type": "Run Typ", "run_regular": "Normal", "run_challenge": "Herausforderung", "damage_taken": "Schaden erlitten", "km": "km", "distance_traveled": "Distanz gelaufen", "seed": "Seed", "score": "Punktzahl", "new_high_score": "Neuer Rekord!", "items_collected": "Gegenstände gesammelt", "boss_rush": "Boss Rush", "run_bossrush": "Boss Rush", "bk:blindfold_desc": "RIP meine Waffen", "bk:blindfold": "Augenbinde", "daily_run": "Täglicher Run", "builder_0_0": "Ja klar!", "builder_0_1": "Ich brauch das Geld selber!", "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?", "builder_1": "Aber du hast garkein Geld! :(", "builder_2": "Danke für deine Investition!", "builder_3": "Ich hab endlich genug Geld um das Projekt hier abzuschließen. Vielen Dank!", "builder_4": "Okay, 'tschuldigung!", "shortcut_is_broken": "Abkürzung ist kaputt", "ach_bk:boss_rush": "Boss Herausforderer", "ach_bk:boss_rush_desc": "Besiege alle Bosse in \"Boss Rush\"", "ach_bk:daily": "Täglicher Ruhm", "ach_bk:daily_desc": "Beende eine der täglichen Herausforderungen", "ach_bk:desert_shortcut": "Wüstenpalast Abkürzung", "ach_bk:desert_shortcut_desc": "Repariere die Abkürzung zum Wüstenpalast", "ach_bk:jungle_shortcut": "Uralter Dschungel Abkürzung", "ach_bk:jungle_shortcut_desc": "Repariere die Abkürzung zum Uralten Dschungel", "ach_bk:ice_shortcut": "Eis-Ruinen Abkürzung", "ach_bk:ice_shortcut_desc": "Repariere die Abkürzung zu den Eis-Ruinen", "ach_bk:library_shortcut": "Geheime Bibliothek Abkürzung", "ach_bk:library_shortcut_desc": "Repariere die Abkürzung zur Geheime Bibliothek", "ach_bk:fashion_matters2": "Mode ist wichtig", "ach_bk:fashion_matters2_desc": "Kaufe jeden einzelnen Hut", "ach_bk:10_challenges": "Herausforderer", "ach_bk:10_challenges_desc": "Schließe 10 Herausforderungen ab", "ach_bk:20_challenges": "Herausforderer 2.0", "ach_bk:20_challenges_desc": "Schließe 20 Herausforderungen ab", "ach_bk:30_challenges": "Herausforderer 3.0", "ach_bk:30_challenges_desc": "Schließe 30 Herausforderungen ab", "ach_bk:bk_no_more": "Tschüss, Burning Knight!", "ach_bk:bk_no_more_desc": "Besiege den Burning Knight", "ach_bk:dm_no_more": "Ende im Gelände", "ach_bk:dm_no_more_desc": "Besiege den dunklen Magier", "ach_bk:egor_no_more": "Egor's Untergang", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Auf ein Neues!", "ach_bk:loop_desc": "Betrete die Schleife", "coins_collected": "Münzen gesammelt", "bk:cup_head": "Tassenhut", "bk:cup_head_desc": "Hoffentlich ohne Inhalt", "bk:mustache_hat": "Schnurrbart", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Propeller Hut", "bk:propeller_hat_desc": "Er dreht sich", "bk:sunglasses": "Sonnenbrille", "bk:sunglasses_desc": "Der coolere Daniel", "bk:cap": "Cap", "bk:cap_desc": "Cool @-@", "bk:eyes": "Augen", "bk:eyes_desc": "@ @", "bk:eye": "Auge", "bk:eye_desc": "@", "bk:hair": "Haare", "bk:hair_desc": "Schick!", "won": "Gewonnen", "won_message": "Du haben Gewonnen! Großer Glückwunsch!", "you_won_demo": "Das ist das Ende der Demo-Version :)", "garderobe_sign": "Ankleideraum", "darkmarket_tip": "~~[cl purple]Fluch[cl] oder [cl yellow]30 Münzen[cl]@@", "mike_0": "Du musst mir [cl green]3 Smaragde[cl] zahlen!", "mike_1": "Probiere Boss Rush für nur [cl green]3 Smaragde[cl]!", "bk:weird_potion": "Seltsamer Trank", "bk:weird_potion_desc": "Seltsame Projektile", "bk:megaphone": "Megaphon", "bk:megaphone_desc": "SEHR LAUTE UND VORALLEM GROßE PROJEKTILE", "scourge": "Fluch", "scourge_stats": "Flüche", "run_daily": "Täglicher Run", "full_version": "Diese Tür kannst du nur in der Vollversion öffnen!", "completed_on": "Abgeschlossen am", "complete": "Abgeschlossen", "wishlist_pls": "Macht dir die Demo spaß? Füge die Vollversion zu deiner Wunschlite hinzu! [cl red]burningknight.net\/steam", "next_daily_in": "[cl gray]Nächster Run startet in[cl]", "hours": "Stunden", "minutes": "Minuten", "seconds": "Sekunden", "ach_bk:star": "Der Star der Show", "ach_bk:star_desc": "Habe drei Orbitale gleichzeitig", "ach_bk:family": "Familienvater", "ach_bk:family_desc": "Besitze drei Haustiere gleichzeitig", "ach_bk:return_to_sender": "no u", "ach_bk:return_to_sender_desc": "Töte einen Gegner mit seinem eigenen Projektil", "ach_bk:van_no_gogh": "Van-Ganzundgarnicht-Gogh", "ach_bk:van_no_gogh_desc": "Zerstöre 100 Gemälde", "ach_bk:boom": "Kettenreaktion", "ach_bk:boom_desc": "Lasse eine Kette von drei TNT explodieren", "ach_bk:dark_market": "Verbrecherversteck", "ach_bk:dark_market_desc": "Begieb dich zum Schwarzmarkt", "ach_bk:spikes": "Brensliche Angelegenheit", "ach_bk:spikes_desc": "Aktiviere 100 Fallen in einem Run", "ach_bk:white_flag": "Ich komme in Frieden", "ach_bk:white_flag_desc": "Leere einen Raum ohne Waffen zu verwenden", "quack": "[cl yellow]Quak![cl]", "pixel_perfect": "Pixel-Perfect", "bk_11": "ICH VERGEBE DIR DIESES EINE MAL... ##ABER MACH DAS BLOß NICHT NOCHMAL!##", "leaderboard": "Bestenliste", "display": "Zeige an", "around_you": "Dein Umfeld", "friends": "Freunde", "global": "Global", "loading": "Läd...", "generating": "Generiert...", "cursor_radius": "Cursor Radius", "no_scores_yet": "Keine Punkzahlen bisher", "no_score_yet": "Keine Punkzahl bisher", "run": "Run", "top": "Top", "quick_restart": "Schnellstart", "painting_dungeon": "Kerker", "painting_goose": "Mini Gans", "painting_chess": "Fliegender Elefant", "painting_peach": "Ein Pfirsichbaum", "bk:no_lamp": "Keine Lampe", "bk:explosive_lamp": "Explosive Lampe", "bk:explosive_lamp_desc": "Wenn ein Bumm nicht einfach nur ein Bumm ist...", "bk:shielded_lamp": "Gepanzerte Lampe", "bk:shielded_lamp_desc": "KAMERADSCHAFT, SCHILE HOCH!", "lamp": "Lampe", "bk:brain": "Mega Gehirn", "bk:brain_desc": "Gehin Größe: Mega", "bk:heart_amulet": "Herzamulett", "bk:heart_amulet_desc": "+1 Herzgröße", "bk:star_amulet_desc": "Mehr Mana", "bk:star_amulet": "Sternenamulett", "bk:coin_amulet": "Münzamulett", "bk:coin_amulet_desc": "Münzen sind mehr Wert", "bk:key_amulet": "Schlüsselamulett", "bk:key_amulet_desc": "Schlüssel sind mehr Wert", "bk:bomb_amulet": "Bombenamulett", "bk:bomb_amulet_desc": "Bomben sind mehr Wert", "bk:eye_amulet": "Augamulett", "bk:eye_amulet_desc": "Es schmerzt so Unpräzise zu sein", "bk:eye_patch": "Augenklappe", "bk:eye_patch_desc": "Arr arr!", "bk:toilet_paper": "Klopapier", "bk:toilet_paper_desc": "Kann man nie genug davon haben!", "bk:decoy": "Lockvogel", "bk:decoy_desc": "...mit Sprengstatz", "bk:wallet": "Geldbeutel-Kumpel", "bk:wallet_desc": "Passt auf deine Münzen auf", "bk:skele_buddy": "Skelett-Kumpel", "bk:skele_buddy_desc": "Gruselig", "bk:mega_bomb": "Mega Bombe", "bk:mega_bomb_desc": "Bomben Größe: Mega", "bk:condensed_milk": "Kondensmilch", "bk:condensed_milk_desc": "Jetzt mit 0.5% weniger Fett!", "bk:marshmallow": "Marshmallow", "bk:marshmallow_desc": "Klebrig", "bk:orbital_multiplier": "Orbitalmultiplikator", "bk:orbital_multiplier_desc": "Mehr Orbitale!", "bk:pet_multiplier": "Haustiermultiplikator", "bk:pet_multiplier_desc": "Mehr Haustiere!", "bk:ghost_bullets": "Geisterkugeln", "bk:ghost_bullets_desc": "Wände halten dich nicht mehr auf!", "bk:weight": "Schweres Gewicht", "bk:weight_desc": "e = m * v^2", "bk:d2": "D2", "bk:d2_desc": "\"Take it or leave it\"", "bk:ethernal_d6": "Zeitloser D6", "bk:ethernal_d6_desc": "Würfelt und\/oder Zerstört", "bk:billiard": "Billard", "bk:billiard_desc": "Kugeln prallen ab", "bk:enraged_bullets": "Wütende Kugeln", "bk:enraged_bullets_desc": "Kugeln zerstören Kugeln", "bk:rewind_button": "Rewind Knopf", "bk:rewind_button_desc": "Das kann ja nur schief gehen!", "bk:piggy_bank": "Sparschwein", "bk:piggy_bank_desc": "Für schlechte Zeiten", "coins": "Münzen", "bk:death_star": "Todesstern", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Lötkolben", "bk:soldering_iron_desc": "heiß heiß heiß", "bk:can": "Dose", "bk:can_desc": "Doppelte Projektile", "bk:swimming_mask": "Taucherbrille", "bk:swimming_mask_desc": "(Ist eine geheime Waffe)", "bk:bullet_chair": "Offensivstuhl", "bk:bullet_chair_desc": "4 Beine, 4 Kanonen", "bk:cell": "Zelle", "bk:cell_desc": "Zelltelilung für Projektile", "bk:brick": "iZiegel", "bk:brick_desc": "Größere Level", "bk:ring_of_pain": "Ring des Schmerzes", "bk:ring_of_pain_desc": "Verlezt werden tut allen Weh", "bk:schrodingers_cat": "Schrödingers Katze", "bk:schrodingers_cat_desc": "Sein oder nicht sein, das hat eine 50% Wahrscheinlichkeit. Oder so.", "bk:smoke_bomb": "Rauchbombe", "bk:smoke_bomb_desc": "Bitte nicht im Gebäude rauchen!", "bk:chest_ring": "Kistenring", "bk:chest_ring_desc": "Wer auch immer sich das ausgedacht hat, sollte gefeuert werden. (Mehr Kisten)", "bk:empty_shell": "Leerer Panzer", "bk:empty_shell_desc": "Eine Chance gegnerische Kugeln zu zerstören", "bk:parachute": "Fallschirm", "bk:parachute_desc": "Runterfallen nicht mehr mögich", "bk:spiked_cookie": "Stachelkeks", "bk:spiked_cookie_desc": "Joa, was soll man dazu noch sagen...", "bk:shooty": "Shooty", "bk:shooty_desc": "Schießt schneller als sein Schatten", "bk:rabbit_bullets": "Kaninchenkugeln", "bk:rabbit_bullets_desc": "Sie vermehren sich wie die Karnickel", "bk:pandoras_box": "Pandora's Büchse", "bk:pandoras_box_desc": "Öffne sie lieber nicht", "bk:bubbles": "Blasen", "bk:bubbles_desc": "Blubberfreund", "bk:match": "Streichholz", "bk:match_desc": "Mit feuer spielt man nicht!", "bk:hammer": "Hammer", "bk:hammer_desc": "Rüstungsbrecher", "bk:helmet": "Eisenhelm", "bk:helmet_desc": "Mit etwas Glück hält er Schaden ab", "bk:beer": "Bier", "bk:beer_desc": "Betrunken + Aggressiv = Schlechte Kombination", "bk:the_eye": "Das Auge", "bk:the_eye_desc": "Es beobachtet dich!", "bk:mimics_tooth": "Mimic's Zähne", "bk:mimics_tooth_desc": "Zieht Mimics an", "ach_bk:mimic": "Jump Scare", "ach_bk:mimic_desc": "Finde einen Mimic", "bk:paper_airplane": "Papierflugzeug", "bk:paper_airplane_desc": "Kugeln mit Autopilot", "ach_bk:ice_boss": "Let It Go", "ach_bk:ice_boss_desc": "Töte die Eiskönigin", "ice_queen_scream": "^^[cl cyan]Ahem", "painting_agency": "Willkommen in der Agentur", "inventory" : "Inventar", "bk:pouch": "Beutel", "bk:alien_glasses": "Alien Brille", "bk:alien_glasses_desc": "Ich sehe mehr!", "bk:led": "LED", "bk:led_desc": "Es werde Licht!", "bk:fragile_lamp": "Zerbrechliche Lampe", "bk:fragile_lamp_desc": "Schachmatt in einem Zug", "painting_guitar": "LAUTER!", "ach_bk:maanex": "Et tu, Brut?", "ach_bk:maanex_desc": "Töte Maanex während du seinen Kopf aufhast.", "dad_0": "Hey Sohn![dl] Ich muss gehen um [cl red]die Lampe[cl] zu finden. Du hast jetzt hier das Komando!", "dad_1": "Ach, fast vergessen...[dl]Wenn ich nicht zurück komme, such auch nicht nach mir. Tschüssi!", "son_0": "##NEEEEEEEIN##", "gobbo_0": "Sohn, [cl green]mein Vater[cl] hat mich vor 20 Jahren verlassen. Ich muss ihn finden.", "gobbo_1": "Du, äh... du hast jetzt hier das Sagen! Man sieht sich!", "dm_5": "Eine neue und vorallem ^^bessere^^ [cl red]Puppe[cl]![dl] ##MUHAHAHA##", "dm_6": "Hast du mich gehört, [cl red]Limpor?", "heinur_0": "##OCH NEEE[dl], NICH SCHON WIEDER!##", "nbk_0": "##JA, MEIN MEISTER##", "bk_12": "##ICH HAB KEINE KÖNIGE MEHR ÜBRIG! ALSO KÄMPF GEGEN MICH, DU SCHWÄCHLING!##", "bk:headshot_gun": "Gebogene Shotgun", "bk:headshot_gun_desc": "Sehr fragwürdiges Patent", "bk:laser_cannon": "Laserpistole", "bk:laser_cannon_desc": "Haha, laser macht pew pew", "credits": "Mitwirkende", "head_0": "Trottel", "tech": "Techno", "ach_bk:collector": "Sammler", "ach_bk:collector_desc": "Sammel alle Gegenstände", "bk:treasure_key": "Roter Schlüssel", "bk:treasure_key_desc": "Öffnet die %%Schleife%%", "bk:pass": "Pass", "bk:pass_desc": "Führerschein und Fahrzeugpapiere bitte!", "bk:bucket": "Eimer", "bk:bucket_desc": "So leer macht der wenig Sinn.", "bk:water_bucket": "Wassereimer", "bk:water_bucket_desc": "Beruhigt [cl red]das Feuer[cl]", "bk:snow_bucket": "Schneeeimer", "bk:snow_bucket_desc": "Vielleicht... könnte es... schmelzen?", "m2_0": "Ich glaub ich muss Insolvenz anmelden...", "m2_1": "Nicht schlecht!", "m2_2": "Hey du, willst du mal die Maschine hier ausprobieren?", "m2_3": "Kassenzettel?[dl] Wie auch immer, benutze ^^%%den Computer%%^^ hier um den Greifarm zu steuern!", "maanex2_0_0": "Nimm mein Geld!", "maanex2_0_1": "Das ist doch eh nur Abzocke.", "maanex2_0": "Okay, das macht dann [cl yellow][vr cost] Münzen[cl], bitte!", "dm_7": "Lasst uns ein kleines Spiel spielen!", "bkw_0": "EIN WEITERER [cl red]EINDRINGLING[cl]!", "bkw_1": "##RAUS HIER, SOFORT!##[dl] Oder ich äh, muss dich zwingen...", "bkw_2": "Ich suche nach [cl green]meinem Vater", "bkw_3": "ICH HABE DICH GEWARNT", "spanish_inquisition": "[cl red]Spanische Inquisition", "lp_0": "Nicht schlecht, [cl purple]Ritta[cl][dl], ich starte [cl green]die Simulation[cl] dann mal neu, ja?", "bk:broken_bucket": "Eimer mit Loch", "bk:broken_bucket_desc": "Also quasi Müll...", "bk:ankh": "Ankh", "bk:ankh_desc": "Leben nach dem Tod!", "bk:broken_ankh": "Kaputtes Ankh", "bk:broken_ankh_desc": "Leben nach dem Tod?", "bk:what": "Was?", "bk:what_desc": "Nein ernsthaft, WAS?", "bk:gold_minigun": "Goldene Minigun", "bk:gold_minigun_desc": "Teurer Spaß...", "bk:gold_dagger": "Goldenes Messer", "bk:gold_dagger_desc": "Factory New", "bk:gold_revolver": "Goldener Revolver", "bk:gold_revolver_desc": "Überschütte mich mit Gold!", "bk:gold_axe": "Goldene Axt", "bk:gold_axe_desc": "Ja halt ne Axt, nix besonderes...", "painting_code": "Code", "bk:katana": "Katana", "bk:katana_desc": "Wem gehört das eigentlich?", "bk:smart_gun": "Schlaue Pistole", "bk:smart_gun_desc": "Sie weiß bescheid!", "bk:pop_gun": "Pop Gun", "bk:pop_gun_desc": "Sehr populär!", "bk:the_button": "Der Knopf", "bk:the_button_desc": "Schaut gefährlich aus...", "bk:gold_sword": "Goldenes Schwert", "bk:gold_sword_desc": "Wenn du sonst nichts mehr findest wofür du Geld ausgeben kannst...", "bk:donut": "Donut", "bk:donut_desc": "Lieber nicht auf die Kalorienwerte schauen!", "bk:sudoku": "Sudoku", "bk:sudoku_desc": "Die Hälfte des Raumes ist weg, reduziert auf Atome", "bk:gps_ring": "GPS Ring", "bk:gps_ring_desc": "Kleine Wahrscheinlichkeit die Karte aufzudecken", "bk:shield_potion": "Schildtrank", "bk:shield_potion_desc": "Einen großen Schluck nehmen!", "bk:trash_generator": "Müll Generator", "bk:trash_generator_desc": "Ja.", "bk:crabs_claw": "Krabbenklaue", "bk:crabs_claw_desc": "Zerstört jegliche Rüstung", "eg_3": "Guten Zeitpunkt, der Herr", "eg_0_0": "Nimm ^^[cl lime]die Smaragde[cl]^^", "eg_0_1": "Lass sie liegen", "eg_0": "Nimm [cl lime]meine Smaragde[cl], ich bitteschön!", "eg_1": "Ich bin raus hier", "bk:reverse_card": "Richtungswechsel", "bk:reverse_card_desc": "Durch Projektile rollen, reflektiert diese", "bk:magnet": "Magnet", "bk:magnet_desc": "Anziehung und Zuneigung", "bk:glowing_mushroom": "Leuchtender Pilz", "bk:glowing_mushroom_desc": "Er ist am viben", "bk:tinfoil_hat": "Aluhut", "bk:tinfoil_hat_desc": "Sicher vor außerirdischen Strahlungen", "bk:rear_window": "Heckscheibe", "bk:rear_window_desc": "Hält dir den Rücken frei!", "bk:refractor": "Refraktor", "bk:refractor_desc": "Mit ein bisschen Glück greifst du in alle Richtungen gleichzeitig an!", "bk:fork": "Gabel", "bk:fork_desc": "Es tut weh", "bk:rock": "Felsen", "bk:rock_desc": "Schaden zu einem Preis", "bk:coffee_grinder": "Kaffeemühle", "bk:coffee_grinder_desc": "Kleine aber schnelle Projektile", "integrations": "Integrationen", "twitch": "Twitch", "streamer_username": "Twitch Benutzername", "bk:shawarma": "Schawarma", "bk:shawarma_desc": "Manchmal sind deine Projektile größer, aber nicht immer!", "bk:cats_ear": "Katzenohr", "bk:cats_ear_desc": "Kranke Ausweichmanöver!", "luck": "Glück", "bk:gamepad": "Gamepad", "bk:gamepad_desc": "Stabile FPS", "bk:hotdog": "Hotdog", "bk:hotdog_desc": "Du wurdest gesegnet. Mehr Glück und mehr Leben auf all deinen Wegen!", "bk:bomb_shell": "Bombenpanzer", "bk:bomb_shell_desc": "Interessantes Konzept", "painting_no_idea": "Kein Plan", "painting_tinkerer": "Bastler", "painting_in_loving_memory_of_ali": "In liebevoller Erinnerung an Ali", "painting_happy_accident": "Glück im Unglück", "painting_observing_cheese": "Käseinspektion", "painting_chicken_enemy_unknown": "Huhn Gegner Unbekannt", "painting_know_stuff": "Er weiß bescheid", "painting_whoops": "Upsi", "painting_too_lake": "Schweinerei", "painting_step_through": "Zu viel des Guten", "painting_thats_a_moon": "Der Mond ist echt!", "painting_totem": "Magischer Kreis", "painting_too_late": "Zu spät!", "painting_whipped_cream": "Schlagsahne", "painting_beet_boys": "Rübenkumpel", "painting_moonshine": "Mondschein", "painting_void": "Die Leere", "painting_peasants": "Der einfache Mann", "bk:gold_lamp": "Gold Lampe", "bk:gold_lamp_desc": "GELD GELD GELD", "bk:sharp_lamp": "Scharfe Lampe", "bk:sharp_lamp_desc": "Für Nahkampf-Enthusiasten", "bk:ancient_sword": "Uraltes Schwert", "bk:ancient_sword_desc": "Das war schon zu Zeiten meines Opas alt!", "ach_bk:unstoppable": "Unaufhaltbar", "ach_bk:unstoppable_desc": "Spiele das Spiel mit einer Lampe durch!", "no_emeralds": "Keine Smaragde", "bk:emerald_gun": "Smaragdpistole", "bk:emerald_gun_desc": "Die teuerste Pistole auf dem Mark!" } ================================================ FILE: BurningKnight/Content/Locales/en.json ================================================ { "bk:halo": "Halo", "bk:halo_desc": "Health up", "bk:revolver": "Revolver", "bk:sword": "Wooden Sword", "bk:sword_desc": "Not just a stick", "bk:heart": "Heart", "resume": "Resume", "settings": "Settings", "restart": "Restart", "death_message": "You Died", "descend": "Descend", "ascend": "Ascend", "exit": "Exit", "painting_rexcellent": "Excellent", "painting_grannylisa": "Grannylisa", "painting_maanex": "Thinker", "painting_bk": "Roasted Knight", "painting_bgang": "The Gang", "painting_failpositive": "Party Maker", "painting_old_man": "Really Old Man", "painting_arthouse": "Art House", "painting_black": "Universe", "painting_milt": "Boy in the snow", "painting_skyscraper": "Lonely skyscraper", "painting_egor": "Burning Rex", "painting_null": "NULL", "painting_badosz": "Lost Boy in the Woods", "painting_banana": "BANANA", "painting_tv": "TV in the sky", "painting_company": "Good Company", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Dog du Trasevol", "painting_lamp": "Take it", "painting_scream": "Icecream", "painting_stars": "Scarry night", "painting_fog": "In the Seas", "painting_nufflee": "Bark", "by": "by", "old_man_0": "It's dangerous!", "continue_run": "Continue Run", "new_run": "New Run", "was_unlocked": "Was unlocked!", "bk:revolver_desc": "Hands up, @everyone!", "bk:shovel": "Blue Shovel", "bk:shovel_desc": "But why is it blue???", "beet_0": "Hi!", "beet_2": "Tell me its name!", "npc_hurt_0": "Ouch.", "npc_hurt_1": "That hurts.", "npc_hurt_2": "Oh no.", "beet_3": "Thanks <3", "beet_1": "Do you want to plant a ^^seed^^?", "beet_1_0": "Yes", "beet_1_1": "No", "beet_4": "The seed is [vr seed]. Do you want to change it?", "beet_4_0": "Yes", "beet_4_1": "No", "beet_5": "Whatever.", "beet_4_2": "Let it be random!", "beet_6": "Ok. Seed is now [vr seed]!", "bk:idol": "Idol", "bk:idol_desc": "A hidden trap activates!", "bk:key": "Golden Key", "bk:infinite_bomb": "Infinite Bomb", "bk:infinite_bomb_desc": "Reusable bomb", "throw_coin": "Throw a Coin", "bk:potatoo": "Potatoo", "bk:potatoo_desc": "Splits projectiles", "bk:spectacles": "Spectacles", "bk:spectacles_desc": "Reveals secrets", "bk:cross": "Cross", "bk:cross_desc": "Increases invincibility time", "bk:slime": "Slime", "bk:slime_desc": "Bouncy shots", "bk:missile": "Missile", "bk:missile_desc": "Homing shots", "bk:rod_of_discord": "Rod of Discord", "bk:rod_of_discord_desc": "Teleporter for @everyone", "bk:goo": "Goo", "bk:goo_desc": "Orbiting friend", "bk:jelly": "Jelly!", "bk:jelly_desc": "^^Bouncy^^", "bk:broken_stone": "Broken Stone", "bk:broken_stone_desc": "Well-built orbital", "bk:nano_orb": "Nano Orb", "bk:nano_orb_desc": "Micro friend", "bk:saturn": "Planet", "bk:saturn_desc": "Of course we still love it", "bk:soap": "Soap", "bk:soap_desc": "Slows down your projectiles", "bk:d6": "D6", "bk:d6_desc": "^^Reroll^^ items!", "bk:my_heart": "My Heart", "bk:my_heart_desc": "Health up", "bk:broken_heart": "Broken Heart", "bk:broken_heart_desc": "Health up", "bk:parcel": "Parcel", "bk:parcel_desc": "Reusable healer", "bk:glass": "Glass", "bk:glass_desc": "##Fragile## projectiles", "bk:glass_bullet": "Glass Bullet", "bk:glass_bullet_desc": "Shoot over stones", "bk:broken_guitar": "Broken Guitar", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Machine Gun", "bk:machine_gun_desc": "Automatic", "bk:grenade_launcher": "Grenade Launcher", "bk:grenade_launcher_desc": "Kaboom!", "bk:shotgun": "Shotgun", "bk:shotgun_desc": "Salt into the face!", "bk:missile_launcher": "Missile Launcher", "bk:missile_launcher_desc": "Target detected!", "bk:burst_gun": "Burst Gun", "bk:burst_gun_desc": "Speed of light", "bk:flak_cannon": "Flak Cannon", "bk:flak_cannon_desc": "It's party time!", "bk:disk_gun": "Disk Gun", "bk:disk_gun_desc": "Sharp matter", "bk:duck_gun": "Duck Gun", "bk:duck_gun_desc": "Quakers!", "bk:follower": "Follower", "bk:follower_desc": "Follow me!", "bk:portal_gun": "Portal Gun", "bk:portal_gun_desc": "Cake is a lie", "bk:snowflake": "Snowflake", "bk:snowflake_desc": "Freeze everyone!", "bk:restock": "Restock", "bk:restock_desc": "Infinite shop supply", "bk:charisma_ring_desc": "Royal Sales", "bk:charisma_ring": "Charisma Ring", "bk:battery": "Battery", "tomb_0": "Here lies [cl green]Gobbo[cl] the Great", "bk:homemade_dice": "Homemade Dice", "bk:homemade_dice_desc": "^^Reroll^^ items! (DIY)", "shopkeeper_0": "##I SAID DON'T DO IT!##", "shopkeeper_1": "Please, stop!", "shopkeeper_2": "Don't do that.", "shopkeeper_3": "[cl red]##PREPARE TO DIE!##", "shopkeeper_4": "[cl red]BURGLAR!", "shopkeeper_5": "[cl red]GET HIM!", "desert": "Desert Palace", "jungle": "Ancient Jungle", "ice": "Ice Ruins", "bk:iron_boots": "Iron Boots", "bk:iron_boots_desc": "Spikes hurt no more", "bk:mimic_totem": "Mimic Totem", "bk:mimic_totem_desc": "##NO MORE MIMICS##", "back_to_town": "Back to Town", "bk:glass_gun": "Glass Gun", "bk:glass_gun_desc": "##Fragile##", "bk:glass_shard": "Glass Shard", "bk:glass_shard_desc": "Just a piece of the whole", "bk:dagger": "Dagger", "bk:dagger_desc": "Nostalgia...", "bk:spear": "Spear", "bk:spear_desc": "Longer arms?", "shopkeeper_6": "Welcome :)", "shopkeeper_7": "Sup, wanna some [cl yellow]tea[cl]?", "shopkeeper_8": "How's going?", "back": "Back", "master_volume": "Master Volume", "music": "Music", "sfx": "Sound Effects", "graphics": "Graphics", "audio": "Audio", "ui_sfx": "Ui Sound Effects", "on": "On", "off": "Off", "fullscreen": "Fullscreen", "vsync": "V-Sync", "fps": "FPS Counter", "flashes": "Flashes", "speedrun_timer": "Speedrun Timer", "screenshake": "Screen Shake", "reset_progress": "Reset Progress", "blood_n_gore": "Blood'n'Gore", "vegan_mode": "Vegan Mode", "reset_settings": "Reset Settings", "are_you_sure": "Are you sure?", "yes": "Yes", "reset_progress_dis": "This will delete ALL your progress!", "reset_settings_dis": "This will reset ALL settings to their default values!", "autosave": "Auto Save", "autopause": "Auto Pause", "input": "Input", "use": "Use", "active": "Active", "bomb": "Bomb", "interact": "Interact", "swap": "Swap Weapons", "roll": "Roll", "duck": "Duck", "pause": "Pause", "none": "None", "keyboard_controls": "Keyboard Controls", "gamepad_controls": "Gamepad Controls", "keyboard": "Keyboard", "gamepad": "Gamepad", "game": "Game", "select": "Select", "cursor": "Cursor", "bk:rip": "RIP", "ach_bk:rip_desc": "Die", "ach_bk:overshake": "Overshake", "ach_bk:overshake_desc": "1000% screen shake", "ach_bk:rip": "Most Popular Achievement", "bk:emerald": "Emerald", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Thanks!^^", "shopkeeper_11": "What a %%deal%%!", "shopkeeper_12": "Wanna [cl red]buy[cl] ^^smth^^?", "shopkeeper_13": "Only for [cl green]you[cl], only today!", "shopkeeper_14": "What an [cl yellow]offer[cl]!", "bk:magnifier": "Magnifier", "bk:magnifier_desc": "Bigger Projectiles", "bk:mushroom_hat": "Mushroom Hat", "bk:mushroom_hat_desc": "Tasty?", "bk:stone_hat": "Stone Hat", "bk:stone_hat_desc": "Heavy", "bk:knight_hat": "Knight Hat", "bk:knight_hat_desc": "Good old enemies...", "bk:cowboy_hat": "Cowboy Hat", "bk:cowboy_hat_desc": "Wild west!", "bk:soup_hat": "Soup Hat", "bk:soup_hat_desc": "^^Yummy^^", "bk:gold_hat": "Gold Hat", "bk:gold_hat_desc": "[cl yellow]Rich!", "bk:viking_hat": "Viking Hat", "bk:viking_hat_desc": "America!", "bk:dunce_hat": "Dunce Hat", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Top Hat", "bk:top_hat_desc": "Fashion!", "bk:ushanka": "Ushanka", "bk:ushanka_desc": "Where is my ##balalaika?##", "bk:valkyrie_hat": "Valkyrie Hat", "bk:valkyrie_hat_desc": "I believe ^^I can fly!^^", "bk:skull_hat": "Skull Hat", "bk:skull_hat_desc": "Money or life!", "bk:grandma_head": "Grandma Head", "bk:grandma_head_desc": "Tea?", "bk:diamond_helmet": "Diamond Helmet", "bk:diamond_helmet_desc": "Shut up and dig!", "bk:villager_head": "Villager Head", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fez", "bk:fez_desc": "Cubit", "bk:no_hat": "Remove Hat", "bk:no_hat_desc": "Not hat - no trouble!", "bk:null_hat": "NULL", "bk:null_hat_desc": "Attempt to call a null value", "accessorytrader_0": "##GET OUT OF HERE!## [dl]Or buy these ^^delicious^^ items at only ^^%%99 diamonds each%%^^!", "accessorytrader_1": "Hi", "accessorytrader_2": "Sup!", "weapontrader_0": "Come in!", "weapontrader_1": "Good day, sir!", "weapontrader_2": "Buy somethin', will ya?", "activetrader_0": "Best offers on the market!", "activetrader_1": "Pay for two and get two!", "activetrader_2": "Give me donuts, [dl]please!!", "hattrader_0": "Wanna be as cool as I am? [dl]Buy some hats!", "hattrader_1": "Wanna be as cool as I am? [dl]Me too, boy.", "hattrader_2": "^^Ha ha hats!^^", "granny_0": "Wanna some tea?", "granny_1": "Have a tea pause!", "granny_2": "Tea?", "bk:xmas_hat": "Santa Hat", "bk:xmas_hat_desc": "Merry Christmas!", "bk:pumpkin_hat": "Carved Pumpkin", "bk:pumpkin_hat_desc": "^^Spooky spooky skeleton^^", "bk:cage_key": "Cage Key", "bk:cage_key_desc": "Save ^^the dude^^!", "npc_0": "Help me! Find the key!", "npc_1": "Thanks for saving me!", "npc_2": "Faster! Unlock the door!", "npc_3": "Please! Help me!", "control_0": "Press [ic 0][ic 1] to place a bomb", "control_1": "Roll you can! Press [ic 0][ic 1] to obtain the power!", "control_2": "Press [ic 0][ic 1] to attack", "control_3": "Press [ic 0][ic 1] to interact", "control_4": "Quack? [ic 0][ic 1]!", "control_5": "Press [ic 0][ic 1] to swap weapons", "shopkeeper_15": "No discount for you!", "shopkeeper_16": "Grab more money and come back!", "shopkeeper_17": "Gotta pay first!", "bk:frog": "Tele Frog", "bk:frog_desc": "Fast travel?", "bk:sword_orbital": "Sword Orbital", "bk:sword_orbital_desc": "Justice", "robbed": "Robbed", "bk:gift_desc": "What's inside?", "bk:spike_ring": "Spike Ring", "bk:spike_ring_desc": "Your enemies must be ##punished##!", "bk:fire_ring": "Fire Ring", "bk:fire_ring_desc": "Let your enemies burn", "bk:ice_ring": "Ice Ring", "bk:ice_ring_desc": "Stop your enemies", "bk:duck_ring": "Duck Ring", "bk:duck_ring_desc": "Teleport after getting hit", "bk:dull_blade": "Dull Blade", "bk:dull_blade_desc": "Triggers hurt effect", "bk:sharp_blade": "Sharp Blade", "bk:sharp_blade_desc": "Self damage", "bk:obsidian_shield": "Obsidian Shield", "bk:obsidian_shield_desc": "Knockback = 0", "bk:bill": "Bill", "bk:bill_desc": "99 dollars", "control_6": "Use active item with [ic 0][ic 1]", "bk:clover": "4 Leaf Clover", "bk:clover_desc": "Lucky!", "bk:d4": "D4", "bk:d4_desc": "^^Reroll %%your artifacts%%!^^", "brastin_0": "Find the [cl purple]cat[cl] painting!", "elon_1": "Here you go, have fun", "bk:maanex_head": "Maanex Head", "bk:maanex_head_desc": "Hmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Makes enemies think for a bit", "mob_0": "Hmmmm", "bk:map_greenprints": "Map Greenprints", "bk:map_greenprints_desc": "Reveals the map", "bk:map": "Map", "bk:map_desc": "Reveals the map permanently", "milt_1": "I want gift", "mapuzzle_0": "Gravity.", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Copied!", "isaac_0": "Life has no meaning...", "isaac_1": "Whyyyyyyyy", "isaac_2": ":sob:", "discord_0": "Say hi! discord.gg\/rexcellent", "old_man_5": "Roll, fool!", "tutorial": "Tutorial", "bk:crying_bomb": "Crying Bomb", "bk:crying_bomb_desc": "Bombs now cry!", "bk:matches": "Matches", "bk:matches_desc": "Shorter explosion timer", "bk:bomb_pack": "Bomb Pack", "bk:bomb_pack_desc": "We put bombs in your bombs!", "bk:tnt": "TNT", "bk:tnt_desc": "99 bombs", "bk:weird_mushroom_desc": "Doubles Everything", "bk:weird_mushroom": "Weird Mushroom", "bk:bomb_shower": "Bomb Shower", "bk:bomb_shower_desc": "Let it rain bombs", "bk:black_belt": "Black Belt", "bk:black_belt_desc": "Explode no more", "bk:ninjia_bomb": "Ninja Bomb", "bk:ninjia_bomb_desc": "Getting hurt spawns bombs", "start_new_run": "Your current run will be lost!", "bk:laser_pointer": "Laser Pointer", "bk:laser_pointer_desc": "Aim is clear!", "ach_bk:marauder": "Marauder", "ach_bk:marauder_desc": "Kill the shopkeeper", "ach_bk:treasure_hunter": "Treasure Hunter", "ach_bk:treasure_hunter_desc": "Find a secret room", "ach_bk:dodge_master": "Dodge Master", "ach_bk:dodge_master_desc": "Kill a boss without getting hit", "ach_bk:dodge_overlord": "Dodge Overlord", "ach_bk:dodge_overlord_desc": "Finish a floor without getting hit once", "ach_bk:quackers": "Quackers", "ach_bk:quackers_desc": "Overquack", "ach_bk:tea_party": "Tea Party", "ach_bk:tea_party_desc": "Join Granny in her tea party", "ach_bk:not_a_thief": "Not a thief", "ach_bk:not_a_thief_desc": "Finish a run without stealing any items", "ach_bk:npc_party2": "NPC Party", "ach_bk:npc_party2_desc": "Save all NPCs", "bk:gold_coin": "Gold Coin", "bk:iron_coin": "Iron Coin", "bk:copper_coin": "Copper Coin", "bk:platinum_coin": "Platinum Coin", "bk:voodoo_doll": "Voodoo Doll", "bk:voodoo_doll_desc": "Kills all enemies in the room", "hub": "Dodge Town", "castle": "Castle Ruins", "cave": "Emerald Caves", "charger_0": "NO ACTIVE ITEM DETECTED", "charger_1": "ACTIVE ITEM IS ALREADY CHARGED", "charger_2": "WHERE IS MY MONEY, YOU, MEAT BAG!", "charger_3": "##I SAID GIVE ME MY MONEY!##", "charger_4": "##I WILL TAKE OVER THE WORLD!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Sure, let's do this!", "maanex_6_1": "Nah.", "maanex_6": "Okay, give me [cl yellow][vr cost] coins[cl] and I will let you open one of these chests. Ok?", "maanex_5": "Hey man, wanna ^^try out^^ your luck?", "maanex_7": "That was fun!", "maanex_8": "Good luck!", "maanex_9": "Well, not this time :(", "maanex_10": "%%^^WOAH^^%%", "maanex_11": "But you don't have enough money!", "maanex_12": "##SON?!##", "bk:amurs_arrow": "Amur's Arrow", "bk:amurs_arrow_desc": "Charming Projectiles", "bk:amurs_bow": "Amur's Bow", "bk:amurs_bow_desc": "I see love", "bk:poison_flask": "Poison Flask", "bk:poison_flask_desc": "Poisoned Projectiles", "bk:snowball": "Snowball", "bk:snowball_desc": "Ice Cold Projectiles", "bk:peper_desc": "Hot Projectiles", "bk:peper": "Hot Pepper", "bk:sale_coupon": "Sale Coupon", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Pet in a Box", "bk:pet_box_desc": "Who's inside?", "bk:crate": "Orbital Crate", "bk:crate_desc": "Who's inside?", "bk:strawberry": "Strawberry", "bk:strawberry_desc": "Sweet Memories", "bk:wings": "Wings", "bk:wings_desc": "I belive I can fly", "bk:coin_pouch": "Coin Pouch", "bk:coin_pouch_desc": "Gives Coins", "bk:key_pouch": "Key Pouch", "bk:key_pouch_desc": "Gives Keys", "bk:bomb_pouch": "Bomb Pouch", "bk:bomb_pouch_desc": "Gives Bombs", "bk:pouch_pouch": "Pouch Pouch", "bk:pouch_pouch_desc": "Gives Pouches", "bk:lightsaber": "Svetsaber", "bk:lightsaber_desc": "You were the chosen one!", "bk:snail": "Snail", "bk:snail_desc": "Mass Slower", "bk:spike": "Spike", "bk:spike_desc": "Damage Up", "bk:mushroom": "Mushroom", "bk:mushroom_desc": "Speed up", "bk:candy": "Candy", "bk:candy_desc": "^^Sugar rush^^, fire rate up", "bk:glasses": "Glasses", "bk:glasses_desc": "Better Accuracy", "bk:ruler": "Ruler", "bk:ruler_desc": "Longer Range", "bk:stopwatch": "Stopwatch", "bk:stopwatch_desc": "Getting Hurt Controls the Time", "bk_0": "##DON'T YOU DARE TOUCH THAT!##", "bk_1": "##I SAID DON'T TOUCH THAT!##", "bk_2": "##YOU CAN'T DEFEAT [cl red]THE BURNING KNIGHT[cl], FOOL!##", "bk_3": "##PREPARE TO DIE!##", "bk_4": "^^WHAT A JOKE^^", "shopkeeper_18": "[cl red]^^Hot sale![cl]", "dm_0": "@@Welcome@@", "ach_bk:deal": "Outstanding Move", "ach_bk:deal_desc": "Make a deal with the Dark Mage", "ach_bk:grannys_gift": "Granny's Gift", "ach_bk:grannys_gift_desc": "Take a gift from Granny", "ach_bk:shopper": "Shop till ya Drop", "ach_bk:shopper_desc": "Buy an item in any shop", "bk_5": "I WOUDLN'T EVEN BOTHER TALKING TO HIM", "bk_6": "##KILL HIM, [cl lime]EDWARD[cl]!##", "bk_7": "[cl lime]EDWARD[cl], ##NOOOOOO!!!!##", "bk_8": "OH COMON, STOP EXPLODING MY CASTLE!", "bk_9": "[cl pink]GRANNY[cl],[dl] CAN YOU JUST DIE, PLEASE##?!?##", "bk_10": "MY MASTER,[dl] I BROUGHT [cl green]GOBLIN[cl]", "dm_1": "Very well[dl], thank you[dl], [cl red]Limpor[cl]", "dm_2": "##Yes, yes, I need more [cl orange]power[cl]!##", "dm_3": "##MORE [cl orange]POWER[cl]!", "dm_4": "I can feel [cl orange]the power[cl] pulsing inside of me!", "granny_3": "You will be first, [cl red]Limpor[cl]!", "granny_4": "Welcome, [cl green]Gobbo [vr id][cl]!", "granny_5": "Good luck on your sad quest!", "bk:meat_guy": "Meat Guy", "bk:meat_guy_desc": "Nuts!", "bk:bullet_stone": "Bullet Stone", "bk:bullet_stone_desc": "He attac, he protec, but most importantly, he cute as hecc", "bk:batman": "Batman", "bk:batman_desc": "Doesn't help, but gives batteries", "vibration": "Vibration", "bk:sharp_arrow": "Sharp Arrow", "bk:sharp_arrow_desc": "Projectile Penetration", "machine_0": "Insert a [cl yellow]coin", "player_0": "Daddy?? ##What did they do with you?!?##", "bk:boomerang": "Boomerang", "bk:boomerang_desc": "Boomerang Projectiles", "bk:backpack": "Backpack", "bk:backpack_desc": "Ma Bear Friend", "place_an_item": "Place an Item", "bk:crystal": "Crystal", "bk:crystal_desc": "The Power of the Rainbow", "bk:prism": "Prism", "bk:prism_desc": "Projectiles -> Rainbow", "scourged": "Scourged", "bk:bomb": "Bomb", "bk:scourge_of_egg": "Scourge of Egg", "bk:scourge_of_egg_desc": "Shuffeled Item Names", "bk:scourge_of_unknown": "Scourge of Unknown", "bk:scourge_of_unknown_desc": "Hidden Items", "bk:scourge_of_blood": "Scourge of Blood", "bk:scourge_of_blood_desc": "Double Trouble (and Enemies)", "bk:scourge_of_risk": "Scourge of Risk", "bk:scourge_of_risk_desc": "Hidden Health", "bk:scourge_of_keys": "Scourge of Keys", "bk:scourge_of_keys_desc": "Hidden Consumables", "bk:scourge_of_lost": "Scourge of Lost", "bk:scourge_of_lost_desc": "Amnesia", "bk:scourge_of_scourged": "Scourge of Scourged", "bk:scourge_of_scourged_desc": "Scourge Everywhere", "bk:scourge_of_illness": "Scourge of Illness", "bk:scourge_of_illness_desc": "Healing is Nerfed", "bk:scourge_of_death": "Scourge of Death", "bk:scourge_of_death_desc": "Hardmode", "bk:ancient_revolver": "Ancient Revolver", "bk:ancient_revolver_desc": "Looks Cool", "bk:assault_rifle": "Assault Rifle", "bk:assault_rifle_desc": "Bursts", "fountain_0": "Bring 5 coins and you will be blessed", "fountain_1": "You've been partly cleansed", "fountain_2": "You've been fully cleansed", "fountain_3": "You are already cleansed", "buffed": "Buffed", "nerfed": "Nerfed", "restored": "Restored", "damaged": "Damaged", "cleansed": "Cleansed", "gifted": "Gifted", "lucky": "Lucky", "unlucky": "Unlucky", "max_hp": "Max HP", "touch": "Touch", "break": "Break", "no_coins": "No Coins", "old_man_6": "It's dangerous to go alone, take this!", "roger_0": "Kaboom!", "roger_1": "##*BOOM*##", "roger_2": "Boom boom shakataka!", "bk:shield": "Shield", "bk:gift": "Gift", "bk:shield_pouch": "Shield Pouch", "bk:shield_pouch_desc": "Gives Shields", "bk:shield_buddy": "Shield Buddy", "bk:shield_buddy_desc": "He protec", "bk:skeleton_key": "Skeleton Key", "bk:skeleton_key_desc": "99 keys", "bk:jar": "Health Jar", "bk:jar_desc": "Jar Jar Clinks", "bk:star": "Star", "bk:star_desc": "It protec", "bk:car_bomb": "Car Bomb", "bk:car_bomb_desc": "Bomb Delivery Service", "bk:grenade": "Grenade", "bk:grenade_desc": "Detonates Bomb on Touch", "trash_goblin_0": "Free me from my [cl purple]scourge[cl]! Please!", "trash_goblin_1": "I'm free![dl] Thank you so much!", "boxy_0": "Keysellent!", "boxy_1": "What a neat box!", "boxy_2": "You need wrapping paper?", "trash_goblin_2": "^^Smoke on the water [ic 0] [ic 1]^^", "bk:vampire_bat": "Vampire Bat", "bk:vampire_bat_desc": "Regen", "shields": "Shields", "bk:mustache": "Mustache", "bk:mustache_desc": "VIP", "bk:bloody_chest": "Bloody Chest", "bk:bloody_chest_desc": "Chests Heal", "bk:bloody_shield": "Bloody Shield", "bk:bloody_shield_desc": "Shields Forever", "bk:cutsaw": "Cutsaw", "bk:cutsaw_desc": "Enemies Will Pay", "vampire_0": "Yum!", "vampire_1": "Bloody awesome!", "vampire_2": "So sweet!", "vampire_3": "We know the rules, [cl red]^^right[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "What's your blood type?", "vampire_6": "So tasty", "duck_2": "Mind particapating in a survey?", "duck_7_0": "Yes", "duck_7_1": "No", "duck_7": "Will you get this chest?", "duck_4": "Good job, have this chest!", "duck_5": "I can't agree with you...", "duck_6_0": "The universe", "duck_6_1": "^^Quarks^^", "duck_6": "What I'm thinking about?", "duck_8_0": "[cl red]Red[cl]", "duck_8_1": "[cl blue]Blue[cl]", "duck_8": "What's my favorite ^^%%color%%^^?", "duck_9_0": "A cat", "duck_9_1": "You just said it", "duck_9": "Who said meow?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "What's better?", "duck_11_0": "What, you egg?", "duck_11_1": "\\[_He stabs him._]", "duck_11": "You are a saucy boy", "duck_12_0": "Chicken", "duck_12_1": "Egg", "duck_12": "Who came first?", "duck_13_0": "Nothing.", "duck_13_1": "A snack.", "duck_13_2": "An egg.", "duck_13_3": "Fried chicken.", "duck_13": "What did you eat today?", "duck_14": "Ouch.", "duck_17_0": "Sure lad", "duck_17_1": "##NAAAAAH##", "duck_17": "Ya like some pineapple on your pizza?", "duck_18_0": "White!", "duck_18_1": "[cl yellow]Yellow[cl]!", "duck_18": "What color is cheese?", "nurse_0": "You are looking really good, honey!", "nurse_1": "I could heal you a bit, but I need [cl yellow][vr price] coins[cl]", "nurse_2": "I hope that didn't hurt", "elon_4": "Here you go, have fun", "elon_2_0": "Letsego", "elon_2_1": "Hold up", "elon_2": "Wanna try out my magic?", "elon_3": "I can transform your weapon into another one", "elon_5": "Whatever", "elon_7": "Bro, where is your weapon???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*blush*", "gobetta_4": "Is it... you?", "gobetta_5": "It's been so long...", "ach_bk:desert": "Dry'n'Hot", "ach_bk:desert_desc": "Reach the Desert Palace", "ach_bk:jungle": "Buzzing Bees", "ach_bk:jungle_desc": "Reach the Ancient Jungle", "rooms_explored": "Rooms explored", "bk:shadow_cloak_desc": "No U", "bk:shadow_cloak": "Shadow Cloak", "bk:dynamite_stick": "Dynamite Stick", "bk:dynamite_stick_desc": "Do you want to explode?", "bk:chalice_of_blood": "Chalice of Blood", "bk:chalice_of_blood_desc": "Pain invokes rage, rage invokes damage", "bk:detonator": "Detonator", "bk:detonator_desc": "Detonates Explosives", "invincibility_time": "Invincibility Time", "accuracy": "Accuracy", "range": "Range", "fire_rate": "Fire Rate", "speed": "Speed", "bk:talisman_of_foresight": "Talisman of Foresight", "bk:talisman_of_foresight_desc": "Open your eyes and see the rooms nearby!", "bk:scourge_ring": "Scourge Ring", "bk:scourge_ring_desc": "Scourge No More", "snek_0": "Nice.", "snek_1": "Thhankss man", "snek_2": "Awesssome", "snek_3": "Ssssup", "snek_4": "Good day, ssssir", "snek_5": "Thou sssshal buy smth?", "snek_6": "I need to sssatisfy the customer...", "snek_7": "I will do, what I mussst!", "bk:snek": "Snek", "bk:snek_desc": "Snack?", "boxy_3": "^^:wave:^^", "boxy_4": "Got a spare key?", "boxy_5": "Mind donating a few keys?", "bk:blank": "Blank", "bk:blank_desc": "_Blank Text_", "bk:blank_bombs": "Blank Bombs", "bk:blank_bombs_desc": "Bullet Shield", "bk:explosive_bullets": "Explosive Bullets", "bk:explosive_bullets_desc": "Explosive", "bk:random_bullets": "Random Bullets", "bk:random_bullets_desc": "RNG", "bk:cup": "Cup", "bk:cup_desc": "Granny can't resist showing up", "bk:cartridge": "Cartridge", "bk:cartridge_desc": "Dark Mage can't resist showing up", "bk:marriage_ring": "Marriage Ring", "bk:marriage_ring_desc": "DM & Granny Forever!", "boxy_7": "I want keys", "boxy_8": "You don't seem to have enough keys :(", "boxy_9": "Now I finally have enough keys to ^^open up^^!", "roger_3": "Mind paying?", "roger_4": "No discounts today", "roger_5": "Bombs first", "vampire_7": "You are not healthy enough", "vampire_8": "I don't give discounts", "vampire_9": "Your health seems to be low", "ach_bk:scourged": "Scourged", "ach_bk:scourged_desc": "Pickup a Scourge Token", "ach_bk:scourged_weapon": "Scourged Weapon", "ach_bk:scourged_weapon_desc": "Pickup a Scourged Weapon", "rerolled": "Rerolled", "ach_bk:open_up": "Open Up", "ach_bk:open_up_desc": "Buy everything from Boxy", "ach_bk:snek": "Snek Pet", "ach_bk:snek_desc": "Get the Snek to be your pet", "bk:scourge_of_greed": "Scourge of Greed", "bk:scourge_of_greed_desc": "High Prices", "killed_by": "Killed by", "kills": "Kills", "time": "Time", "depth": "Depth", "bk:blank_bullets": "Blank Bullets", "bk:blank_bullets_desc": "Blank", "bk:lego": "Constructor", "bk:lego_desc": "It hurts so much stepping on these...", "bk:iron_armor": "Iron Armor", "bk:iron_armor_desc": "Gives Shields", "bk:round_shield": "Round Shield", "bk:round_shield_desc": "Prevents Contact Damage", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "The Legend Himself", "bk:inverted_arkhalis": "Inverted Arkhalis", "bk:inverted_arkhalis_desc": "Help will come when low on health", "bk:gun_sword": "Gun Sword", "bk:gun_sword_desc": "Prepare for trouble and make it double!", "ach_bk:scourge_king_desc": "Get 10 Scourge points", "ach_bk:scourge_king": "Scourge King", "ach_bk:sting_operation": "Sting Operation", "ach_bk:sting_operation_desc": "Defeat the Queen Bee", "ach_bk:mummified": "Mummified", "ach_bk:mummified_desc": "Defeat the Pharaoh", "ach_bk:democracy": "Democracy", "ach_bk:democracy_desc": "Defeat the Old King", "pharaoh_scream": "##PREPARE TO GET MUMMIFIED!##", "queen_bee_scream": "##FOR THE [cl yellow]HONEY LORD[cl]!##", "bk:half_heart": "Half Heart", "right": "Right", "down": "Down", "left": "Left", "up": "Up", "painting_cat": "Cat Painting", "bk:axe": "Axe", "bk:axe_desc": "He promised to return", "bk:guitar": "Guitar", "bk:guitar_desc": "It's detuned", "bk:glass_sword": "Glass Sword", "bk:glass_sword_desc": "The weapon of masters", "bk:chicken": "Chicken Wing", "bk:chicken_desc": "It's Hot", "bk:pickaxe": "Pickaxe", "bk:pickaxe_desc": "Dig, peasant!", "bk:mana": "Mana", "bk:half_mana": "Half Mana", "bk:lava_wand": "Lava Wand", "bk:lava_wand_desc": "Hot Matter", "bk:web_wand": "Spider Wand", "bk:web_wand_desc": "World-wide web provider", "bk:slap_stick": "Slap Stick", "bk:slap_stick_desc": "Slap", "sensivity": "Sensivity", "no": "No", "scale": "Scale", "ach_bk:ice": "Ice Age", "ach_bk:ice_desc": "Reach the Frozen Ruins", "ach_bk:library": "Sacred Texts", "ach_bk:library_desc": "Reach the Secret Library", "bk:ice_skates": "Ice Skates", "bk:ice_skates_desc": "Ice Immunity", "bk:campfire_in_bottle": "Campfire in a Bottle", "bk:campfire_in_bottle_desc": "Frost Immunity", "library": "Secret Library", "ach_bk:cat_without_a_hat": "Cat without a hat", "ach_bk:cat_without_a_hat_desc": "Find the cat painting", "ach_bk:rich": "Toilet Paper", "ach_bk:rich_desc": "Obtain 99 coins", "ach_bk:rescue_operation": "Rescue Operation", "ach_bk:rescue_operation_desc": "Save a NPC", "ach_bk:tutorial": "Guru", "ach_bk:tutorial_desc": "Finish the tutorial", "ach_bk:fancy_hat": "Fancy Hat", "ach_bk:fancy_hat_desc": "Buy a hat", "ach_bk:unlock": "Unlocker", "ach_bk:unlock_desc": "Unlock an item", "floor_brightness": "Floor Brightness", "ach_bk:shielded": "Shields Up", "ach_bk:shielded_desc": "Obtain a shield heart", "run_type": "Run type", "run_regular": "Regular", "run_challenge": "Challenge", "damage_taken": "Damage taken", "km": "km", "distance_traveled": "Distance traveled", "seed": "Seed", "score": "Score", "new_high_score": "New high!", "items_collected": "Items collected", "boss_rush": "Boss Rush", "run_bossrush": "Boss rush", "bk:blindfold_desc": "RIP my weapons", "bk:blindfold": "Blindfold", "daily_run": "Daily Run", "builder_0_0": "Yeah", "builder_0_1": "I need my money for myself", "builder_0": "I'm planning on building a shortcut here, but I need [vr need] [ic 0] more coins. Can you help me?", "builder_1": "But you have no money! :(", "builder_2": "Thanks for your investment!", "builder_3": "I finally have enough money to finish the project! Thanks so much!", "builder_4": "Okay, sorry!", "shortcut_is_broken": "Shortcut is broken", "ach_bk:boss_rush": "Boss Challenger", "ach_bk:boss_rush_desc": "Defeat all bosses in the Boss Rush", "ach_bk:daily": "Daily Glory", "ach_bk:daily_desc": "Complete the Daily Challenge", "ach_bk:desert_shortcut": "Desert Palace Shortcut", "ach_bk:desert_shortcut_desc": "Fix the shortcut to the Desert Palace", "ach_bk:jungle_shortcut": "Ancient Jungle Shortcut", "ach_bk:jungle_shortcut_desc": "Fix the shortcut to the Ancient Jungle", "ach_bk:ice_shortcut": "Frozen Ruins Shortcut", "ach_bk:ice_shortcut_desc": "Fix the shortcut to the Frozen Ruins", "ach_bk:library_shortcut": "Secret Library Shortcut", "ach_bk:library_shortcut_desc": "Fix the shortcut to the Secret Library", "ach_bk:fashion_matters2": "Fashion Matters", "ach_bk:fashion_matters2_desc": "Buy every single hat", "ach_bk:10_challenges": "Challenger", "ach_bk:10_challenges_desc": "Complete 10 challenges", "ach_bk:20_challenges": "Challenger 2.0", "ach_bk:20_challenges_desc": "Complete 20 challenges", "ach_bk:30_challenges": "Challenger 3.0", "ach_bk:30_challenges_desc": "Complete 30 challenges", "ach_bk:bk_no_more": "Burning no more", "ach_bk:bk_no_more_desc": "Defeat the Burning Knight himself", "ach_bk:dm_no_more": "DM no more", "ach_bk:dm_no_more_desc": "Defeat the Dark Mage", "ach_bk:egor_no_more": "Egor no more", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Ah, here we go again", "ach_bk:loop_desc": "Enter the loop", "coins_collected": "Coins collected", "bk:cup_head": "Cup Head", "bk:cup_head_desc": "Have a cup of tea", "bk:mustache_hat": "Mustache", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Propeller Hat", "bk:propeller_hat_desc": "It spins", "bk:sunglasses": "Sunglasses", "bk:sunglasses_desc": "Work with moon too!", "bk:cap": "Cap", "bk:cap_desc": "Cool @-@", "bk:eyes": "Eyes", "bk:eyes_desc": "@ @", "bk:eye": "Eye", "bk:eye_desc": "@", "bk:hair": "Hair", "bk:hair_desc": "Fancy", "won": "Won", "won_message": "You Won!", "garderobe_sign": "Dressing Room", "darkmarket_tip": "~~[cl purple]Scourge[cl] or [cl yellow]30 coins[cl]@@", "mike_0": "Gotta pay me [cl green]3 emeralds", "mike_1": "Try boss rush just for [cl green]3 emeralds[cl]!", "bk:weird_potion": "Weird Potion", "bk:weird_potion_desc": "Weird Projectiles", "bk:megaphone": "Megaphone", "bk:megaphone_desc": "Expanding Projectiles", "scourge": "Scourge", "scourge_stats": "Scourge", "run_daily": "Daily", "completed_on": "Completed on", "complete": "complete", "next_daily_in": "[cl gray]Next starts in[cl]", "hours": "hours", "minutes": "minutes", "seconds": "seconds", "ach_bk:star": "The Star of the Show", "ach_bk:star_desc": "Obtain 3 orbitals", "ach_bk:family": "Happy Lil Family", "ach_bk:family_desc": "Obtain 3 pets", "ach_bk:return_to_sender": "No U", "ach_bk:return_to_sender_desc": "Kill an enemy with its own projectile", "ach_bk:van_no_gogh": "Van No Gogh", "ach_bk:van_no_gogh_desc": "Destroy 100 paintings", "ach_bk:dark_market": "Crime Hideout", "ach_bk:dark_market_desc": "Descend into the Dark Market", "ach_bk:spikes": "Sharp Matter", "ach_bk:spikes_desc": "Active 100 spikes in a single run", "ach_bk:white_flag": "Weapon Free", "ach_bk:white_flag_desc": "Defeat a room without using a weapon once", "quack": "[cl yellow]Quack![cl]", "pixel_perfect": "Pixel Perfect", "bk_11": "I FORGIVE YOU THIS TIME... BUT ##DO NOT## DO IT AGAIN!", "leaderboard": "Leaderboard", "display": "Display", "around_you": "Around You", "friends": "Friends", "global": "Global", "loading": "Loading", "generating": "Generating", "cursor_radius": "Cursor Radius", "no_scores_yet": "No scores yet", "no_score_yet": "No score yet", "run": "Run", "top": "Top", "quick_restart": "Quack Restart", "painting_dungeon": "Dungeon", "painting_goose": "Mini Goose", "painting_chess": "Flying Elephant", "painting_peach": "A peach tree", "bk:no_lamp": "No Lamp", "bk:explosive_lamp": "Explosive Lamp", "bk:explosive_lamp_desc": "When boom means more", "bk:shielded_lamp": "Shielded Lamp", "bk:shielded_lamp_desc": "Shields Up!", "lamp": "Lamp", "bk:brain": "Mega Brain", "bk:brain_desc": "What if we use 0% of our brain", "bk:heart_amulet": "Heart Amulet", "bk:heart_amulet_desc": "+1 to Heart Size", "bk:star_amulet_desc": "Mana Up", "bk:star_amulet": "Star Amulet", "bk:coin_amulet": "Coin Amulet", "bk:coin_amulet_desc": "Coins Are Worth More", "bk:key_amulet": "Key Amulet", "bk:key_amulet_desc": "Keys Are Worth More", "bk:bomb_amulet": "Bomb Amulet", "bk:bomb_amulet_desc": "Bombs Are Worth More", "bk:eye_amulet": "Eye Amulet", "bk:eye_amulet_desc": "It Hurts To Be Inaccurate", "bk:eye_patch": "Eye Patch", "bk:eye_patch_desc": "Are You Ready, Kids?", "bk:toilet_paper": "Toilet Paper", "bk:toilet_paper_desc": "Its Always Ending", "bk:decoy": "Decoy", "bk:decoy_desc": "It Explodes", "bk:wallet": "Wallet Buddy", "bk:wallet_desc": "Stores Your Coins", "bk:skele_buddy": "Skele Buddy", "bk:skele_buddy_desc": "Spooky", "bk:mega_bomb": "Mega Bomb", "bk:mega_bomb_desc": "Bomb Size: Mega", "bk:condensed_milk": "Condensed Milk", "bk:condensed_milk_desc": "Fast Pixels - Slow Enemies", "bk:marshmallow": "Marshmallow X_X", "bk:marshmallow_desc": "Sticky", "bk:orbital_multiplier": "Orbital Multiplier", "bk:orbital_multiplier_desc": "More Orbitals!", "bk:pet_multiplier": "Pet Multiplier", "bk:pet_multiplier_desc": "More Pets!", "bk:ghost_bullets": "Ghost Bullets", "bk:ghost_bullets_desc": "Walls Wont Stop", "bk:weight": "Heavy Weight", "bk:weight_desc": "Gravity Booster", "bk:d2": "D2", "bk:d2_desc": "Take it or leave it", "bk:ethernal_d6": "Ethernal D6", "bk:ethernal_d6_desc": "Rerolls And\/Or Destroys", "bk:billiard": "Billiard", "bk:billiard_desc": "Bullets Bounce", "bk:enraged_bullets": "Enraged Bullets", "bk:enraged_bullets_desc": "Bullets Break Bullets", "bk:rewind_button": "Rewind Button", "bk:rewind_button_desc": "Hold Up", "bk:piggy_bank": "Piggy Bank", "bk:piggy_bank_desc": "My Life Savings", "coins": "Coins", "bk:death_star": "Death Star", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Soldering Iron", "bk:soldering_iron_desc": "It's Hot", "bk:can": "Can", "bk:can_desc": "Double Projectiles", "bk:swimming_mask": "Swimming Mask", "bk:swimming_mask_desc": "It's a Secret Weapon", "bk:bullet_chair": "Bullet Chair", "bk:bullet_chair_desc": "4 Legs 4 Guns", "bk:cell": "Cell", "bk:cell_desc": "Projectiles Multiply", "bk:brick": "iBrick", "bk:brick_desc": "Bigger Levels", "bk:ring_of_pain": "Ring Of Pain", "bk:ring_of_pain_desc": "Getting Hurt Hurts Everyone", "bk:schrodingers_cat": "Schrödingers Cat", "bk:schrodingers_cat_desc": "To Be Or Not To Be (50% chance)", "bk:smoke_bomb": "Smoke Bomb", "bk:smoke_bomb_desc": "Ninjia-inspired Escape", "bk:chest_ring": "Chest Ring", "bk:chest_ring_desc": "More Chests!", "bk:empty_shell": "Empty Shell", "bk:empty_shell_desc": "A Chance To Destroy Enemy Bullets", "bk:parachute": "Parachute", "bk:parachute_desc": "Pit Immunity", "bk:spiked_cookie": "Spiked Cookie", "bk:spiked_cookie_desc": "Spiky Boi", "bk:shooty": "Shooty", "bk:shooty_desc": "He Be Shooting", "bk:rabbit_bullets": "Rabbit Bullets", "bk:rabbit_bullets_desc": "They Multiply", "bk:pandoras_box": "Pandora's Box", "bk:pandoras_box_desc": "You had to fight evel!", "bk:bubbles": "Bubbles", "bk:bubbles_desc": "Bubble Frend", "bk:match": "Match", "bk:match_desc": "Fire For Everyone", "bk:hammer": "Hammer", "bk:hammer_desc": "Armor Breaker", "bk:helmet": "Iron Helmet", "bk:helmet_desc": "A Chance To Ignore Damage", "bk:beer": "Beer", "bk:beer_desc": "Damage Enrages", "bk:the_eye": "The Eye", "bk:the_eye_desc": "He Be Watching", "bk:mimics_tooth": "Mimic's Tooth", "bk:mimics_tooth_desc": "Attracks Mimics", "ach_bk:mimic": "Jump Scare", "ach_bk:mimic_desc": "Find A Mimic", "bk:paper_airplane": "Paper Airplane", "bk:paper_airplane_desc": "Homing Projectiles", "ach_bk:ice_boss": "Let It Go", "ach_bk:ice_boss_desc": "Kill The Ice Queen", "ice_queen_scream": "^^[cl cyan]Ahem", "painting_agency": "Welcome to the agency", "painting_nat": "Nat", "painting_totemori": "Totemori", "painting_horatio": "Horatio", "painting_coce": "Coce", "painting_totemori_redux": "Totemori Redux", "painting_raj": "Raj", "painting_plank": "Plank", "painting_qrilin": "Qrilin", "painting_kobra_throne": "Kobra Can", "painting_mori": "Mori", "painting_balbo": "Balbo", "painting_olpi": "Olpi", "painting_one_knight_stand": "One Knight Stand", "painting_ne_furdje_le": "Ne furdje le!", "painting_sushi_sushi": "Sushi! Sushi!", "painting_hoop_gang": "Hoop Gang", "painting_riveting_view": "Riveting View", "painting_gang": "Goop Gang", "painting_zweihandler": "Zweihandler", "painting_cauliflower": "Cauliflower", "painting_raise_volcano": "Raise Volcano", "painting_mahula": "Mahula", "painting_tofulama": "Tofulama", "painting_esty": "Misfit", "language": "Language", "bk:pouch": "Pouch", "bk:alien_glasses": "Alien Glasses", "bk:alien_glasses_desc": "I see more", "inventory": "Inventory", "bk:led": "LED", "bk:led_desc": "Accurate Lamp", "bk:fragile_lamp": "Fragile Lamp", "bk:fragile_lamp_desc": "1 hit K.O.", "painting_guitar": "More volume!", "ach_bk:maanex": "Et tu, Brute?", "ach_bk:maanex_desc": "Kill Maanex while wearing his head", "dad_0": "Hey son![dl] I need to go and find [cl red]the Lamp[cl]. I leave you to rule.", "dad_1": "If I don't return, don't search for me. Bye!", "son_0": "##NOOOOOOO##", "gobbo_0": "Son, [cl green]my father[cl] left me 20 years ago. I need to find him.", "gobbo_1": "I leave you as the ruler. Bye!", "dm_5": "A new and ^^better^^ [cl red]puppet[cl]![dl] ##MUHAHAHA##", "dm_6": "Do you hear me, [cl red]Limpor?", "heinur_0": "##NO[dl], NOT AGAIN!##", "nbk_0": "##YES, MY MASTER##", "bk_12": "##I'M OUT OF KINGS, SO FIGHT ME, FOOL!##", "bk:headshot_gun": "Bent Gun", "bk:headshot_gun_desc": "Headshot", "bk:laser_cannon": "Laser Cannon", "bk:laser_cannon_desc": "Haha, laser go pew pew", "credits": "Credits", "head_0": "Fool", "tech": "Techno", "ach_bk:collector": "Collector", "ach_bk:collector_desc": "Unlock all items", "bk:treasure_key": "Red Key", "bk:treasure_key_desc": "Opens loopholes", "bk:pass": "Pass", "bk:pass_desc": "Identify yourself!", "bk:bucket": "Bucket", "bk:bucket_desc": "Useless without the contents", "bk:water_bucket": "Water Bucket", "bk:water_bucket_desc": "Calms [cl red]the Fire[cl]", "bk:snow_bucket": "Snow Bucket", "bk:snow_bucket_desc": "Prehaps, it could melt", "m2_0": "I'm never going to financially recover from this", "m2_1": "Good job!", "m2_2": "Hey man, wanna ^^try out^^ your %%skill%%?", "m2_3": "Use ^^%%the Computer%%^^ to control the claw!", "maanex2_0_0": "Take my money!", "maanex2_0_1": "Not this time, tnx.", "maanex2_0": "Okay, gimme [cl yellow][vr cost] coins[cl] and you can give the claw a try!", "dm_7": "Let's play a game", "bkw_0": "ANOTHER [cl red]INTRUDER[cl]!", "bkw_1": "##GET OUT OF HERE##[dl], OR I WILL FORCE YOU!", "bkw_2": "I'm looking for [cl green]my father", "bkw_3": "I GAVE YOU _A WARNING_", "spanish_inquisition": "[cl red]Spanish Inquisition", "lp_0": "Good job, [cl purple]Ritta[cl][dl], restarting [cl green]the simulation[cl][dl].[dl].[dl].", "bk:broken_bucket": "Broken Bucket", "bk:broken_bucket_desc": "Protecc", "bk:ankh": "Ankh", "bk:ankh_desc": "Eternal Life", "bk:broken_ankh": "Broken Ankh", "bk:broken_ankh_desc": "Eternal Life?", "bk:what": "What", "bk:what_desc": "Seriusly, WHAT?", "bk:gold_minigun": "Golden Minigun", "bk:gold_minigun_desc": "Haha budget go brrr", "bk:gold_dagger": "Golden Dagger", "bk:gold_dagger_desc": "Old but gold", "bk:gold_revolver": "Golden Revolver", "bk:gold_revolver_desc": "Cover me in gold", "bk:gold_axe": "Golden Axe", "bk:gold_axe_desc": "Just an axe", "painting_code": "Code", "bk:katana": "Katana", "bk:katana_desc": "Who's [cl orange]the owner[cl]?", "bk:smart_gun": "Smart Gun", "bk:smart_gun_desc": "He knows", "bk:pop_gun": "Pop Gun", "bk:pop_gun_desc": "Really popular", "bk:the_button": "The Button", "bk:the_button_desc": "8-dir attack", "bk:gold_sword": "Golden Sword", "bk:gold_sword_desc": "When you don't have anything to spend money on", "bk:donut": "Donut", "bk:donut_desc": "Do not hesitate", "bk:sudoku": "Sudoku", "bk:sudoku_desc": "Half of the room just gone, reduced to atoms", "bk:gps_ring": "GPS Ring", "bk:gps_ring_desc": "A chance to reveal the map", "bk:shield_potion": "Shield Potion", "bk:shield_potion_desc": "Shield juice big sip", "bk:trash_generator": "Trash Generator", "bk:trash_generator_desc": "Yes.", "bk:crabs_claw": "Crab's Claw", "bk:crabs_claw_desc": "Breaks any armor", "eg_3": "Good time of day, sir", "eg_0_0": "Take ^^[cl lime]the emeralds[cl]^^", "eg_0_1": "Leave them", "eg_0": "Take [cl lime]my emeralds[cl], I beg you!", "eg_1": "Ima head out", "bk:reverse_card": "Reverse Card", "bk:reverse_card_desc": "Rolling through projectiles reflects them", "bk:magnet": "Magnet", "bk:magnet_desc": "Attraction & Affection", "bk:glowing_mushroom": "Glowing Mushroom", "bk:glowing_mushroom_desc": "He be vibing", "bk:tinfoil_hat": "Tinfoil Hat", "bk:tinfoil_hat_desc": "Feels safe", "bk:rear_window": "Rear Window", "bk:rear_window_desc": "Watches your back", "bk:refractor": "Refractor", "bk:refractor_desc": "A chance to attack in all directions", "bk:fork": "Fork", "bk:fork_desc": "It hurts", "bk:rock": "Rock", "bk:rock_desc": "Damage at a cost", "bk:coffee_grinder": "Coffee Grinder", "bk:coffee_grinder_desc": "Small & fast projectiles", "integrations": "Integrations", "twitch": "Twitch", "twitch_mode": "Twitch Mode", "streamer_username": "Streamer Username", "bk:shawarma": "Shawarma", "bk:shawarma_desc": "Sometimes projectiles are bigger", "bk:cats_ear": "Cat's Ear", "bk:cats_ear_desc": "Sick dodge", "luck": "Luck", "bk:gamepad": "Gamepad", "bk:gamepad_desc": "Stable FPS", "bk:hotdog": "Hotdog", "bk:bomb_shell": "Bomb Shell", "bk:bomb_shell_desc": "Weird Health", "painting_no_idea": "No Idea", "painting_tinkerer": "Tinkerer", "painting_in_loving_memory_of_ali": "In loving memory of Ali", "painting_happy_accident": "Happy Accident", "painting_observing_cheese": "Observing Cheese", "painting_chicken_enemy_unknown": "Chicken Enemy Unknown", "painting_know_stuff": "Know Stuff", "painting_whoops": "Whoops", "painting_too_lake": "Too Lake", "painting_step_through": "Threshold", "painting_thats_a_moon": "That's a moon", "painting_totem": "Magic Circle", "painting_too_late": "Too Late", "painting_whipped_cream": "Whipped Cream", "painting_beet_boys": "Beet Bois", "painting_moonshine": "Moonshine", "painting_void": "The Void", "painting_peasants": "Peasants", "bk:hotdog_desc": "Luck & Health Up", "logged_in_as": "Logged in as", "not_logged_in": "Not logged in", "failed_to_login": "Failed to log in as", "logging_in": "Logging in[dl].[dl].[dl].", "twitch_0": "Pog!", "twitch_1_0": "Yes", "twitch_1_1": "No", "twitch_1": "Do you want to play with Twitch mode on?", "twitch_2": "Tell me your Twitch username!", "twitch_3": "Welcome to the chat, [cl purple]@[vr username][cl]!", "twitch_4": "Mkay.", "twitch_5_0": "Yes", "twitch_5_1": "No", "twitch_5": "Your Twitch username is [cl purple]@[vr username][cl]. Wanna change it?", "run_twitch": "Twitch", "happening_bk:hurt": "Hurt", "happening_bk:big_hurt": "Big Hurt", "happening_bk:omega_hurt": "Omega Hurt", "happening_bk:confused": "Confusion", "happening_bk:snail": "Snail", "happening_bk:broken": "Broken Armor", "happening_bk:darkness": "Lights Out", "happening_bk:scourge_token": "Bad Token", "happening_bk:risk": "Hidden Health", "happening_bk:double_trouble": "Double Trouble", "happening_bk:rage": "Rage", "happening_bk:regular_tp": "Teleport", "happening_bk:reset": "Level Reset", "happening_bk:sudoku": "Sudoku", "happening_bk:items_hurt": "Items Hurt", "happening_bk:scourged": "Scourged", "happening_bk:reroll_items": "Rerolled", "happening_bk:reroll_weapon": "New Weapons", "happening_bk:nerf": "Nerfed", "happening_bk:rob": "Robbed", "happening_bk:steal": "Weapon Stolen", "happening_bk:give_artifact": "Random Artifact", "happening_bk:give_weapon": "Random Weapon", "happening_bk:give_random_item": "Random Item", "happening_bk:give_random_consumable": "Random Consumable", "happening_bk:invincible": "Invincibility", "happening_bk:treasure_tp": "Treasure Locator", "happening_bk:small_heal": "Tiny Heal", "happening_bk:heal": "Heal", "happening_bk:omega_heal": "OEMGA HEAL", "happening_bk:shielded": "Shielded", "happening_bk:cleanse": "Cleansed", "happening_bk:chest": "Chest Attack", "happening_bk:buffed": "Buffed", "happening_bk:gift": "Gifted", "happening_bk:entrance_tp": "Here we start again", "happening_bk:exit_tp": "Get out", "twitch_next": "What shall happen next?", "total_votes": "votes", "bk:gold_lamp": "Gold Lamp", "bk:gold_lamp_desc": "Money money money", "bk:sharp_lamp": "Sharp Lamp", "bk:sharp_lamp_desc": "For melee lowers", "bk:ancient_sword": "Ancient Sword", "bk:ancient_sword_desc": "Really old stick", "ach_bk:unstoppable": "Unstoppable", "ach_bk:unstoppable_desc": "Beat the game with any lamp", "no_emeralds": "No Emeralds", "bk:emerald_gun": "Emerald Gun", "bk:emerald_gun_desc": "Most expensive gun on the market", "minimap": "Minimap", "quality": "Quality", "normal": "Normal", "potato": "Potato", "happening_bk:bomb": "Bomb Attack", "happening_bk:slide": "Slide to the left", "20_years_later": "20 years later", "painting_ducktective": "Ducktective", "painting_eye": "Space Eye", "boss_oldking": "Old King", "boss_pharaoh": "Pharaoh", "boss_queenbee": "Queen Bee", "boss_icequeen": "Ice Queen", "boss_burningknight": "Burning Knight", "boss_dm": "Dark Mage", "painting_bug": "This isn't a bug, that's a feature!", "damage": "Damage", "painting_new": "Gnobfather", "revive": "Revive", "coop_sign": "Press any button on a gamepad to add another player", "bk:party_hat": "Party Hat", "bk:party_hat_desc": "Why do I feel so sad", "bk:police_hat": "Police Hat", "bk:police_hat_desc": "Better stay away from portals", "bk:spike_hat": "Spike Hat", "bk:spike_hat_desc": "Poke", "bk:hood": "Hood", "bk:hood_desc": "Find the ring", "bk:bullet_hat": "Bullet Hat", "bk:bullet_hat_desc": "Bang", "remove_player": "Hold [ic 0] to remove player", "bk:spook": "Spook", "bk:spook_desc": "Boo", "bk:mask": "Mask", "bk:mask_desc": "Stay at 127.0.0.1", "bk:sword_polish": "Sword Polish", "bk:sword_polish_desc": "Bigger Melee Attacks", "bk:pumpkin_juice": "Pumpkin Juice", "bk:pumpkin_juice_desc": "Exciting", "bk:bouncy_glove": "Bouncy Glove", "bk:bouncy_glove_desc": "Bonk", "seeded": "(seeded)" } ================================================ FILE: BurningKnight/Content/Locales/fr.json ================================================ { "bk:halo": "Halo", "bk:halo_desc": "Vie augmentée", "bk:revolver": "Revolver", "bk:sword": "Épée en bois", "bk:sword_desc": "Pas juste un bâton", "bk:heart": "Coeur", "resume": "Reprendre", "settings": "Options", "restart": "Recommencer", "death_message": "Vous êtes mort", "descend": "Descendre", "ascend": "Monter", "exit": "Sortir", "painting_rexcellent": "Excellent", "painting_grannylisa": "Mamielisa", "painting_maanex": "Le Penseur", "painting_bk": "Burning Knight", "painting_failpositive": "Le fêtard", "painting_old_man": "Un homme vraiment vieux", "painting_arthouse": "Maison Artistique", "painting_black": "L'Univers", "painting_milt": "Une boite dans la neige", "painting_skyscraper": "Un gratte-ciel solitaire", "painting_egor": "Burning Rex", "painting_null": "NULL", "painting_badosz": "Garçon perdu dans les bois", "painting_banana": "BANANE", "painting_tv": "Télé dans le ciel", "painting_company": "Une bonne entreprise", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Chien du Trasevol", "painting_lamp": "Prend le", "painting_scream": "Une glace", "painting_stars": "Nuit blanche", "painting_fog": "Dans les mers", "painting_nufflee": "Écorce", "by": "par", "old_man_0": "C'est dangeureux!", "continue_run": "Continuer la partie", "new_run": "Nouvelle partie", "was_unlocked": "A été déverrouillé!", "bk:revolver_desc": "Mains en l'air, @everyone!", "bk:shovel": "Une pelle bleue", "bk:shovel_desc": "Mais pourquoi est-elle bleue???", "beet_0": "Salut!", "beet_2": "Dites-moi son nom!", "npc_hurt_0": "Ouch.", "npc_hurt_1": "Ça fait mal.", "npc_hurt_2": "Oh non.", "beet_3": "Merci <3", "beet_1": "Veux tu planter une ^^graine^^?", "beet_1_0": "Oui!", "beet_1_1": "Non.", "beet_4": "La graine est [vr seed]. Voulez-vous la changer?", "beet_4_0": "Oui!", "beet_4_1": "Non.", "beet_5": "Peu importe.", "beet_4_2": "Faites que ce soit aléatoire!", "beet_6": "Ok. La graine est désormais [vr seed]!", "bk:idol": "Idole", "bk:idol_desc": "Un piège caché s'active!", "bk:key": "Clé en Or", "bk:infinite_bomb": "Bombe infinie", "bk:infinite_bomb_desc": "Bombe réutilisable", "throw_coin": "Jeter une pièce", "bk:potatoo": "Potatoo", "bk:potatoo_desc": "Projectiles à fragmentation", "bk:spectacles": "Lunettes", "bk:spectacles_desc": "Révèle les secrets", "bk:cross": "Croix", "bk:cross_desc": "Augmente le temps d'invincibilité", "bk:slime": "Slime", "bk:slime_desc": "Renvoi les tirs", "bk:missile": "Missile", "bk:missile_desc": "Tirs à tête chercheuse", "bk:rod_of_discord": "Baguette de Discord", "bk:rod_of_discord_desc": "Téléporte @everyone", "bk:goo": "Goo", "bk:goo_desc": "Un ami en orbite", "bk:jelly": "Jelly!", "bk:jelly_desc": "^^Rebondis^^", "bk:broken_stone": "Pierre brisée", "bk:broken_stone_desc": "Une orbite bien construite", "bk:nano_orb": "Nano Orbe", "bk:nano_orb_desc": "Un ami microscopique", "bk:saturn": "Planète", "bk:saturn_desc": "Bien sûr, nous l'aimons toujours", "bk:soap": "Savon", "bk:soap_desc": "Ralenti vos projectiles", "bk:d6": "D6", "bk:d6_desc": "^^Reroll^^ les objets!", "bk:my_heart": "Mon Coeur", "bk:my_heart_desc": "Augmente la vie", "bk:broken_heart": "Coeur Brisé", "bk:broken_heart_desc": "Augmente la vie", "bk:parcel": "Colis", "bk:parcel_desc": "Médecin réutilisable", "bk:glass": "Verre", "bk:glass_desc": "Projectiles ##Fragile##", "bk:glass_bullet": "Balle de Verre", "bk:glass_bullet_desc": "Tire à travers la pierre", "bk:broken_guitar": "Guitare Cassée", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Mitrailleuse", "bk:machine_gun_desc": "Automatique", "bk:grenade_launcher": "Lance-Grenades", "bk:grenade_launcher_desc": "Kaboom!", "bk:shotgun": "Fusil à Pompe", "bk:shotgun_desc": "Du gros sel dans la face!", "bk:missile_launcher": "Lance-Missiles", "bk:missile_launcher_desc": "Cible détectée!", "bk:burst_gun": "Pistolet Automatique", "bk:burst_gun_desc": "Tir à la vitesse de la lumière", "bk:flak_cannon": "Cannon Anti-Aérien", "bk:flak_cannon_desc": "C'est la fête !", "bk:disk_gun": "Pistolet à Disque", "bk:disk_gun_desc": "Il faut que ça coupe", "bk:duck_gun": "Pistolet Canard", "bk:duck_gun_desc": "Coin-Coin!", "bk:follower": "Follower", "bk:follower_desc": "Follow me!", "bk:portal_gun": "Pistolet à portail", "bk:portal_gun_desc": "The cake is a lie", "bk:snowflake": "Flocon", "bk:snowflake_desc": "Gèle tout le monde!", "bk:restock": "Réapprovisionnement", "bk:restock_desc": "Offre de magasin infinie", "bk:charisma_ring_desc": "Ventes royales", "bk:charisma_ring": "Anneau de Charisme", "bk:battery": "Batterie", "tomb_0": "Ci-gît [cl green]Gobbo[cl] le Grand", "bk:homemade_dice": "Dé fait maison", "bk:homemade_dice_desc": "^^Reroll^^ les objets! (DIY)", "shopkeeper_0": "##JE VOUS AI DIT DE NE PAS LE FAIRE !##", "shopkeeper_1": "S'il te plaît, arrête!", "shopkeeper_2": "Ne fais pas ça.", "shopkeeper_3": "[cl red]##PREPARE TOI À MOURIR!##", "shopkeeper_4": "[cl red]VOLEUR!", "shopkeeper_5": "[cl red]ATTRAPEZ LE!", "desert": "Palais du Désert", "jungle": "Jungle Ancienne", "ice": "Ruines de Glace", "bk:iron_boots": "Bottes de Métal", "bk:iron_boots_desc": "Les piques ne font plus mal", "bk:mimic_totem": "Totem Imitateur", "bk:mimic_totem_desc": "##PAS D'AUTRES IMITATIONS##", "back_to_town": "Retour à la ville", "bk:glass_gun": "Pistolet de Verre", "bk:glass_gun_desc": "##Fragile##", "bk:glass_shard": "Éclats de verre", "bk:glass_shard_desc": "Juste une partie de l'ensemble", "bk:dagger": "Dague", "bk:dagger_desc": "Nostalgie...", "bk:spear": "Lance", "bk:spear_desc": "Des bras plus longs?", "shopkeeper_6": "Bienvenue :)", "shopkeeper_7": "Yo, tu veux du [cl yellow]thé[cl]?", "shopkeeper_8": "Comment ca se passe?", "back": "Retour", "master_volume": "Volume Général", "music": "Musique", "sfx": "Effets sonores", "graphics": "Graphismes", "audio": "Audio", "ui_sfx": "Ui Effets sonores", "on": "On", "off": "Off", "fullscreen": "Plein Écran", "vsync": "V-Sync", "fps": "Compteur de FPS", "speedrun_timer": "Chronomètre Speedrun", "screenshake": "Tremblement de l'écran", "reset_progress": "Réinitialiser la progression", "blood_n_gore": "Sang et Effets gores", "vegan_mode": "Mode Végan", "reset_settings": "Réinitialiser les Options", "are_you_sure": "Êtes vous sûrs?", "yes": "Oui", "reset_progress_dis": "Cela supprimera TOUTE votre progression!", "reset_settings_dis": "Ceci réinitialisera TOUS les paramètres à leurs valeurs par défaut!", "autosave": "Sauvegarde Automatique", "autopause": "Pause Automatique", "input": "Saisie", "use": "Utiliser", "active": "Actif", "bomb": "Bombe", "interact": "Interagir", "swap": "Changer d'Armes", "roll": "Esquiver", "duck": "S'accroupir", "pause": "Pause", "none": "None", "keyboard_controls": "Contrôles du clavier", "gamepad_controls": "Contrôles de la manette de jeu", "keyboard": "Clavier", "gamepad": "Manette", "game": "Jeu", "select": "Selectionner", "cursor": "Curseur", "bk:rip": "RIP", "ach_bk:rip_desc": "Meurt", "ach_bk:overshake": "Mode Tremblement Infernal", "ach_bk:overshake_desc": "1000% de tremblement d'écran", "ach_bk:rip": "Succès le plus populaire", "bk:emerald": "Emeraude", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Merci!^^", "shopkeeper_11": "Quelle %%affaire%%!", "shopkeeper_12": "Tu veux [cl red]acheter[cl] ^^quelque chose^^?", "shopkeeper_13": "Seulement pour [cl green]toi[cl], seulement aujourd'hui!", "shopkeeper_14": "Quelle [cl yellow]offre[cl]!", "bk:magnifier": "Loupe", "bk:magnifier_desc": "Projectiles plus gros", "bk:mushroom_hat": "Chapeau champignons", "bk:mushroom_hat_desc": "C'est bon ?", "bk:stone_hat": "Chapeau de pierre", "bk:stone_hat_desc": "C'est lourd", "bk:knight_hat": "Casque de chevalier", "bk:knight_hat_desc": "De bons vieux ennemis...", "bk:cowboy_hat": "Chapeau de Cowboy", "bk:cowboy_hat_desc": "L'Ouest Sauvage!", "bk:soup_hat": "Chapeau de soupe", "bk:soup_hat_desc": "^^Délicieux^^", "bk:gold_hat": "Chapeau doré", "bk:gold_hat_desc": "[cl yellow]Riche!", "bk:viking_hat": "Casque Viking", "bk:viking_hat_desc": "Amerique!", "bk:dunce_hat": "Chapeau d'âne", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Haut-de-Forme", "bk:top_hat_desc": "À la mode!", "bk:ushanka": "Chapka", "bk:ushanka_desc": "Où est ma ##balalaïka?##", "bk:valkyrie_hat": "Casque de Valkyrie", "bk:valkyrie_hat_desc": "I believe ^^I can fly!^^", "bk:skull_hat": "Masque de squelette", "bk:skull_hat_desc": "L'argent ou la vie!", "bk:grandma_head": "Tête de Grand-mère", "bk:grandma_head_desc": "Du thé?", "bk:diamond_helmet": "Casque de Diamant", "bk:diamond_helmet_desc": "Tais toi et creuse!", "bk:villager_head": "Tête de villageois", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fez", "bk:fez_desc": "Cubit", "bk:no_hat": "Enlever son chapeau", "bk:no_hat_desc": "Pas de chapeau - pas de problèmes!", "bk:null_hat": "NULL", "bk:null_hat_desc": "Tentative d'appeler une valeur null", "accessorytrader_0": "##SORS DE LÀ!## [dl]Ou achète ces ^^delicieux^^ objets à seulement ^^%%99 diamants chacun%%^^!", "accessorytrader_1": "Salut", "accessorytrader_2": "Ca va!", "weapontrader_0": "Entre!", "weapontrader_1": "Bonne journée, monsieur!", "weapontrader_2": "Achète quelque chose, non?", "activetrader_0": "Les meilleures offres sur le marché!", "activetrader_1": "Payez pour deux et obtenez-en deux!", "activetrader_2": "Donne moi des donuts, [dl]s'il te plait!!", "hattrader_0": "Tu veux être aussi cool que moi? [dl]Achète des chapeaux!", "hattrader_1": "Tu veux être aussi cool que moi? [dl]Moi aussi, gamin.", "hattrader_2": "^^Ha ha des chapeaux!^^", "granny_0": "Tu veux du thé?", "granny_1": "Fais une pause thé!", "granny_2": "Thé?", "bk:xmas_hat": "Chapeau de Noël", "bk:xmas_hat_desc": "Joyeux Noël!", "bk:pumpkin_hat": "Citrouille sculptée", "bk:pumpkin_hat_desc": "^^Squelette effrayant^^", "bk:cage_key": "Clé de la cage", "bk:cage_key_desc": "Sauve ^^le mec^^!", "npc_0": "Aide moi! Touve la clé!", "npc_1": "Merci de m'avoir sauvé!", "npc_2": "Plus vite! Déverrouille la porte!", "npc_3": "S'il te plait! Aide moi!", "control_0": "Appuie sur [ic 0][ic 1] pour poser une bombe", "control_1": "Esquive! Appuie sur [ic 0][ic 1] pour obtenir le pouvoir!", "control_2": "Appuie sur [ic 0][ic 1] pour attaquer", "control_3": "Appuie sur [ic 0][ic 1] pour interagir", "control_4": "Coin? [ic 0][ic 1]!", "control_5": "Appuie sur [ic 0][ic 1] pour changer d'arme", "shopkeeper_15": "Pas de réduction pour toi!", "shopkeeper_16": "Obtenez plus d'argent et revenez!", "shopkeeper_17": "Il faut d'abord payer!", "bk:frog": "Télé-grenouille", "bk:frog_desc": "Voyage rapide?", "bk:sword_orbital": "Épée Orbitale", "bk:sword_orbital_desc": "Justice", "robbed": "Volé", "bk:gift_desc": "Qu'est ce qu'il y a à l'intérieur?", "bk:spike_ring": "Bague à pointes", "bk:spike_ring_desc": "Vos ennemies doivent être ##punis##!", "bk:fire_ring": "Anneau de Feu", "bk:fire_ring_desc": "Laissez vos ennemis brûler", "bk:ice_ring": "Anneau de Glace", "bk:ice_ring_desc": "Arrêtez vos ennemis", "bk:duck_ring": "Anneau du Canard", "bk:duck_ring_desc": "Vous téléporte après avoir été touché", "bk:dull_blade": "Lame émoussée", "bk:dull_blade_desc": "Déclenche un effet négatif", "bk:sharp_blade": "Lame aiguisée", "bk:sharp_blade_desc": "Vous blesse", "bk:obsidian_shield": "Bouclier d'Obsidienne", "bk:obsidian_shield_desc": "Recul = 0", "bk:bill": "Facture", "bk:bill_desc": "99 dollars", "control_6": "Utilisez les objets actifs avec [ic 0][ic 1]", "bk:clover": "Trèfle à 4 feuilles", "bk:clover_desc": "Chanceux!", "bk:d4": "D4", "bk:d4_desc": "^^Reroll %%vos artéfacts%%!^^", "brastin_0": "Trouvez le tableau du [cl purple]chat[cl]!", "elon_1": "Voilà, amusez-vous bien", "bk:maanex_head": "Tête de Maanex", "bk:maanex_head_desc": "Hmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Fait réfléchir un peu les ennemis", "mob_0": "Hmmmm", "bk:map_greenprints": "Carte des empreintes vertes", "bk:map_greenprints_desc": "Révèle la carte", "bk:map": "Carte", "bk:map_desc": "Révèle la carte définitivement ", "milt_1": "Je veux un cadeau", "mapuzzle_0": "Gravité.", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Copié!", "isaac_0": "La vie n'a pas de sens...", "isaac_1": "Pourquoiiiiiii", "isaac_2": ":sob:", "discord_0": "Dites bonjour! discord.gg\/rexcellent", "old_man_5": "Esquive, idiot!", "tutorial": "Tutoriel", "bk:crying_bomb": "Bombe pleureuse", "bk:crying_bomb_desc": "Les bombes pleurent maintenant!", "bk:matches": "Allumettes", "bk:matches_desc": "Réduis le délai de l'explosion", "bk:bomb_pack": "Pack de bombes", "bk:bomb_pack_desc": "On met des bombes dans vos bombes!", "bk:tnt": "TNT", "bk:tnt_desc": "99 bombes", "bk:weird_mushroom_desc": "Double tout", "bk:weird_mushroom": "Champignon bizarre", "bk:bomb_shower": "Pluie de bombe", "bk:bomb_shower_desc": "Faites pleuvoir les bombes", "bk:black_belt": "Ceinture noire", "bk:black_belt_desc": "N'explosez plus", "bk:ninjia_bomb": "Bombe Ninjia", "bk:ninjia_bomb_desc": "Les blessures font apparaitre des bombes", "start_new_run": "Votre partie actuelle sera perdue!", "bk:laser_pointer": "Pointeur laser", "bk:laser_pointer_desc": "L'objectif est clair!", "ach_bk:marauder": "Maraudeur", "ach_bk:marauder_desc": "Tuez le marchand", "ach_bk:treasure_hunter": "Chasseur de trésor", "ach_bk:treasure_hunter_desc": "Trouver une pièce secrète", "ach_bk:dodge_master": "Maître de l'esquive", "ach_bk:dodge_master_desc": "Tuer un boss sans se faire toucher", "ach_bk:dodge_overlord": "Maître de l'Esquive Suprême", "ach_bk:dodge_overlord_desc": "Terminer un étage sans se faire toucher une seule fois", "ach_bk:quackers": "Coin-Coin", "ach_bk:quackers_desc": "Super Coin-Coin", "ach_bk:tea_party": "Après-midi thé", "ach_bk:tea_party_desc": "Rejoignez Mamie dans son après-midi thé", "ach_bk:not_a_thief": "Pas un voleur", "ach_bk:not_a_thief_desc": "Terminer une partie sans prendre d'objets", "ach_bk:npc_party2": "Fête de PNJ", "ach_bk:npc_party2_desc": "Sauvez tous les PNJ", "bk:gold_coin": "Pièce d'Or", "bk:iron_coin": "Pièce d'Argent", "bk:copper_coin": "Pièce de Cuivre", "bk:platinum_coin": "Pièce de Platine", "bk:voodoo_doll": "Poupée Vaudou", "bk:voodoo_doll_desc": "Tuez tous les ennemis présents dans la pièce", "hub": "Ville de l'esquive", "castle": "Ruines du château", "charger_0": "AUCUN OBJET ACTIF DÉTECTÉ", "charger_1": "L'OBJET ACTIF EST DÉJÀ CHARGÉ", "charger_2": "OÙ EST MON ARGENT, TOI, SAC À VIANDE!", "charger_3": "##J'AI DIT DONNE-MOI MON ARGENT!##", "charger_4": "##JE VAIS CONQUÉRIR LE MONDE!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Bien sûr, allons-y!", "maanex_6_1": "Non.", "maanex_6": "Okay, donne moi [cl yellow][vr cost] pièces[cl] et je te laisserai ouvrir un de ces coffres. D'accord?", "maanex_5": "Hey toi, tu veux ^^tenter^^ ta chance?", "maanex_7": "C'était amusant!", "maanex_8": "Bonne Chance!", "maanex_9": "Eh bien, pas cette fois :(", "maanex_10": "%%^^WOAH^^%%", "maanex_11": "Mais tu n'as pas assez d'argent!", "maanex_12": "##FILS?!##", "bk:amurs_arrow": "Flèche d'Amour", "bk:amurs_arrow_desc": "Projectiles de charme", "bk:amurs_bow": "Arc d'Amour'", "bk:amurs_bow_desc": "Je vois l'amour", "bk:poison_flask": "Flacon de Poison", "bk:poison_flask_desc": "Projectiles empoisonnés", "bk:snowball": "Boule de neige", "bk:snowball_desc": "Projectiles glacés", "bk:peper_desc": "Projectiles brûlants", "bk:peper": "Piment Fort", "bk:sale_coupon": "Coupon de vente", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Animal en boîte", "bk:pet_box_desc": "Qui est là?", "bk:crate": "Caisse Orbitale", "bk:crate_desc": "Qui est à l'intérieur?", "bk:strawberry": "Fraise", "bk:strawberry_desc": "Doux souvenirs", "bk:wings": "Ailes", "bk:wings_desc": "I belive I can fly", "bk:coin_pouch": "Sac de pièces", "bk:coin_pouch_desc": "Donne des pièces", "bk:key_pouch": "Sac de Clés", "bk:key_pouch_desc": "Donne des Clés", "bk:bomb_pouch": "Sac de Bombes", "bk:bomb_pouch_desc": "Donne des Bombes", "bk:pouch_pouch": "Sac de Sacs", "bk:pouch_pouch_desc": "Donne des Sacs", "bk:lightsaber": "Svetsaber", "bk:lightsaber_desc": "Vous étiez l'élu!", "bk:snail": "Escargot", "bk:snail_desc": "Ralentissement de la masse", "bk:spike": "Piques", "bk:spike_desc": "Augmente les Dégâts", "bk:mushroom": "Champignon", "bk:mushroom_desc": "Augmente la Vitesse", "bk:candy": "Bonbon", "bk:candy_desc": "^^Sugar rush^^, Cadence de Tir augmentée", "bk:glasses": "Lunettes", "bk:glasses_desc": "Augmente la Précision", "bk:ruler": "Règle", "bk:ruler_desc": "Augmente la Portée", "bk:stopwatch": "Chronomètre", "bk:stopwatch_desc": "Se faire toucher permet de contrôler le temps", "bk_0": "##N'OSE PAS TOUCHER À ÇA!##", "bk_1": "##J'AI DIT NE TOUCHE À ÇA!##", "bk_2": "##TU NE PEUX PAS VAINCRE [cl red]BURNING KNIGHT[cl], IDIOT!##", "bk_3": "##PREPARE TOI A MOURIR!##", "bk_4": "^^QUELLE BLAGUE^^", "shopkeeper_18": "[cl red]^^Grosses Soldes![cl]", "dm_0": "@@Bienvenue@@", "ach_bk:deal": "Événement Exceptionnel", "ach_bk:deal_desc": "Conclure un accord avec le Mage Noir", "ach_bk:grannys_gift": "Cadeau de mamie", "ach_bk:grannys_gift_desc": "Prenez un cadeau de Mamie", "ach_bk:shopper": "Acheter jusqu'à ne plus pouvoir", "ach_bk:shopper_desc": "Acheter un article dans n'importe quel magasin", "bk_5": "JE N'AURAIS MÊME PAS BESOIN DE LUI PARLER", "bk_6": "##TUE-LE, [cl lime]EDWARD[cl]!##", "bk_7": "[cl lime]EDWARD[cl], ##NOOOOOON!!!!##", "bk_8": "OH ÇA VA, ARRÊTE DE FAIRE EXPLOSER MON CHÂTEAU!", "bk_9": "[cl pink]?Q?IE[cl],[dl] TU PEUX MOURIR, S'IL TE PLAÎT##?!?##", "bk_10": "MON MAÎTRE,[dl] J'AI APPORTÉ LE [cl green]GOBLIN[cl]", "dm_1": "Très bien[dl], merci[dl], [cl red]Limpor[cl]", "dm_2": "##Oui, oui, j'ai besoin de plus de [cl orange]puissance[cl]!##", "dm_3": "##PLUS DE [cl orange]PUISSANCE[cl]!", "dm_4": "Je peux sentir [cl orange]cette force[cl] palpiter en moi!", "granny_3": "Tu sera le premier, [cl red]Limpor[cl]!", "granny_4": "Bienvenue, [cl green]Gobbo [vr id][cl]!", "granny_5": "Bonne chance dans votre triste quête!", "bk:meat_guy": "Homme Viande", "bk:meat_guy_desc": "Les boules!", "bk:bullet_stone": "Balles de pierre", "bk:bullet_stone_desc": "Il attaque, il protège, mais surtout, il est mignon comme tout", "bk:batman": "Batman", "bk:batman_desc": "N'aide pas, mais donne des piles", "vibration": "Vibration", "bk:sharp_arrow": "Flèche acérée", "bk:sharp_arrow_desc": "Augmente la pénétration des projectiles", "machine_0": "Insérer une [cl yellow]pièce", "player_0": "Papa?? ##Qu'est-ce qu'ils t'ont fait?!?##", "bk:boomerang": "Boomerang", "bk:boomerang_desc": "Projectiles Boomerang", "bk:backpack": "Sac à Dos", "bk:backpack_desc": "Mon meilleur ami", "place_an_item": "Placer un objet", "bk:crystal": "Crystal", "bk:crystal_desc": "La puissance de l'arc-en-ciel", "bk:prism": "Prisme", "bk:prism_desc": "Projectiles -> Arc-en-ciel", "scourged": "Malédiction", "bk:bomb": "Bombe", "bk:scourge_of_egg": "La Malédiction de l'Oeuf", "bk:scourge_of_egg_desc": "Mélange les noms d'objets", "bk:scourge_of_unknown": "La Malédiction de l'inconnu", "bk:scourge_of_unknown_desc": "Objets cachés", "bk:scourge_of_blood": "La Malédiction du sang", "bk:scourge_of_blood_desc": "Double problème (et ennemis)", "bk:scourge_of_risk": "La Malédiction du risque", "bk:scourge_of_risk_desc": "Santé cachée", "bk:scourge_of_keys": "La Malédiction des Clés", "bk:scourge_of_keys_desc": "Consommables cachés", "bk:scourge_of_lost": "La Malédiction du Vide", "bk:scourge_of_lost_desc": "Amnésie", "bk:scourge_of_scourged": "La Malédiction des Malédictions", "bk:scourge_of_scourged_desc": "Des Malédictions partout", "bk:scourge_of_illness": "La Malédiction de Vie", "bk:scourge_of_illness_desc": "Les soins sont amoindries", "bk:scourge_of_death": "La Malédiction Mortelle", "bk:scourge_of_death_desc": "Mode Difficile", "bk:ancient_revolver": "Revolver Ancient", "bk:ancient_revolver_desc": "L'aspect est cool", "bk:assault_rifle": "Fusil d'Assaut", "bk:assault_rifle_desc": "Mitraille", "fountain_0": "Apporte 5 pièces et tu sera bénis", "fountain_1": "Vous avez été partiellement purifié", "fountain_2": "Vous avez été entièrement purifié", "fountain_3": "Vous êtes déjà purifié", "buffed": "Amélioré", "nerfed": "Nerfé", "restored": "Restoré", "damaged": "Endommagé", "cleansed": "Purifié", "gifted": "Doué", "lucky": "Chanceux", "unlucky": "Malchanceux", "max_hp": "PV Max", "touch": "Contact", "break": "Pause", "no_coins": "Pas de pièces", "old_man_6": "C'est dangereux d'y aller seul, prends ça!", "roger_0": "Kaboom!", "roger_1": "##*BOOM*##", "roger_2": "Boom boom shakataka!", "bk:shield": "Bouclier", "bk:gift": "Cadeau", "bk:shield_pouch": "Sac de Boucliers", "bk:shield_pouch_desc": "Donne des Boucliers", "bk:shield_buddy": "Compagnon bouclier", "bk:shield_buddy_desc": "Il protège", "bk:skeleton_key": "Passe-partout", "bk:skeleton_key_desc": "99 clés", "bk:jar": "Jar de Vie", "bk:jar_desc": "Jar Jar Clinks", "bk:star": "Étoile", "bk:star_desc": "Elle protège", "bk:car_bomb": "Voiture piégée", "bk:car_bomb_desc": "Service de livraison de bombes", "bk:grenade": "Grenade", "bk:grenade_desc": "Explose au touché", "trash_goblin_0": "Libérez-moi de ma [cl purple]malédiction[cl]! S'il vous plait!", "trash_goblin_1": "Je suis libre![dl] Merci beaucoup!", "boxy_0": "Cléxellent!", "boxy_1": "Quelle belle boîte!", "boxy_2": "Tu veux du papier cadeau?", "trash_goblin_2": "^^Fumée sur l'eau [ic 0] [ic 1]^^", "bk:vampire_bat": "Chauve-souris vampire", "bk:vampire_bat_desc": "Régen", "shields": "Boucliers", "bk:mustache": "Moustache", "bk:mustache_desc": "VIP", "bk:bloody_chest": "Coffre sanglant", "bk:bloody_chest_desc": "Les coffres vous soignent", "bk:bloody_shield": "Bouclier sanglant", "bk:bloody_shield_desc": "Boucliers pour toujour", "bk:cutsaw": "Scie", "bk:cutsaw_desc": "Les ennemis paieront", "vampire_0": "Yum!", "vampire_1": "Exsanglant!", "vampire_2": "Si doux!", "vampire_3": "Nous connaissons les règles, [cl red]^^pas vrai[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "Quel est ton groupe sanguin?", "vampire_6": "Si savoureux", "duck_2": "Ça te dirais de participer a une enquête?", "duck_7_0": "Oui", "duck_7_1": "Non", "duck_7": "Voulez-vous obtenir ce coffre?", "duck_4": "Bien joué, prenez ce coffre!", "duck_5": "Je ne suis pas d'accord avec toi...", "duck_6_0": "L'Univers", "duck_6_1": "^^Coin^^", "duck_6": "A quoi est ce que je pense?", "duck_8_0": "[cl red]Rouge[cl]", "duck_8_1": "[cl blue]Bleu[cl]", "duck_8": "Quel est ma ^^%%couleur%%^^ préférée?", "duck_9_0": "Un chat", "duck_9_1": "Tu viens de le dire", "duck_9": "Qui a dit meow?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "Qu'est-ce qui est mieux?", "duck_11_0": "Quoi, ton oeuf?", "duck_11_1": "\\[_Il le poignarde._]", "duck_11": "Tu es un insolent", "duck_12_0": "Poulet", "duck_12_1": "Oeuf", "duck_12": "Qui est arrivé en premier?", "duck_13_0": "Rien.", "duck_13_1": "Une collation.", "duck_13_2": "un oeuf.", "duck_13_3": "Poulet frit.", "duck_13": "Tu as mangé quoi aujourd'hui?", "duck_14": "Ouch.", "duck_17_0": "Bien sûr, mon gars", "duck_17_1": "##NAAAAAH##", "duck_17": "Tu aimes l'ananas sur ta pizza?", "duck_18_0": "Blanc!", "duck_18_1": "[cl yellow]Jaune[cl]!", "duck_18": "Quelle est la couleur du fromage ??", "nurse_0": "Tu es magnifique, chérie!", "nurse_1": "Je pourrais te guérir un peu, mais j'ai besoin [cl yellow][vr price] pièces[cl]", "nurse_2": "J'espère que çq n'a pas fait mal", "elon_4": "Voilà, amusez-vous bien", "elon_2_0": "Allons-y", "elon_2_1": "Attends", "elon_2": "Tu veux essayer ma magie?", "elon_3": "Je peux transformer ton arme en une autre", "elon_5": "Peu importe", "elon_7": "Bro, où est ton arme???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*blush*", "gobetta_4": "C'est... toi?", "gobetta_5": "Ça fait si longtemps...", "ach_bk:desert": "Sec et Chaud", "ach_bk:desert_desc": "Atteindre le Palais du Désert", "ach_bk:jungle": "Abeilles bourdonnantes", "ach_bk:jungle_desc": "Atteindre l'ancienne jungle", "rooms_explored": "Salles explorées", "bk:shadow_cloak_desc": "Non Toi", "bk:shadow_cloak": "Cape de l'ombre", "bk:dynamite_stick": "Bâton de Dynamite", "bk:dynamite_stick_desc": "Tu veux exploser?", "bk:chalice_of_blood": "Calice de sang", "bk:chalice_of_blood_desc": "La douleur invoque la rage, la rage invoque les dégâts", "bk:detonator": "Detonateur", "bk:detonator_desc": "Déclenche les explosifs", "invincibility_time": "Temps d'invincibilité", "accuracy": "Précision", "range": "Portée", "fire_rate": "Cadence de Tir", "speed": "Vitesse", "bk:talisman_of_foresight": "Talisman de prévoyance", "bk:talisman_of_foresight_desc": "Ouvrez les yeux et voyez les salles à proximité!", "bk:scourge_ring": "Anneau de Malédiction", "bk:scourge_ring_desc": "Vous ne pouvez plus être maudis", "snek_0": "Nice.", "snek_1": "Mersssi mec", "snek_2": "Impressionnant", "snek_3": "Ssssa va", "snek_4": "Bonne journée, monssssieur", "snek_5": "Tu dois assseter quelque chossse?", "snek_6": "Je dois sssatissssfaire le client...", "snek_7": "Je vais faire ssse que je dois faire !", "bk:snek": "Snek", "bk:snek_desc": "Snack?", "boxy_3": "^^:wave:^^", "boxy_4": "Tu as un double de la clé?", "boxy_5": "Faites don de quelques clés?", "bk:blank": "Vide", "bk:blank_desc": "_Texte Vide_", "bk:blank_bombs": "Bombes à blanc", "bk:blank_bombs_desc": "Bouclier de balles", "bk:explosive_bullets": "Balles explosives", "bk:explosive_bullets_desc": "Explosif", "bk:random_bullets": "Balles aléatoires", "bk:random_bullets_desc": "RNG", "bk:cup": "Coupe", "bk:cup_desc": "Mamie ne peut pas résister à l'envie de se montrer", "bk:cartridge": "Cartouche", "bk:cartridge_desc": "Le Mage Noir ne résiste pas à l'envie de se montrer", "bk:marriage_ring": "Alliance de mariage", "bk:marriage_ring_desc": "MN & Mamie pour toujours!", "boxy_7": "Je veux des clés", "boxy_8": "Tu n'as pas assez de clés :(", "boxy_9": "Maintenant, j'ai enfin assez de clés ^^m'ouvrir^^!", "roger_3": "Vous voulez bien payer ?", "roger_4": "Pas de réductions aujourd'hui", "roger_5": "Les bombes d'abord", "vampire_7": "Vous n'êtes pas en assez bonne santé", "vampire_8": "Je n'accorde pas de remises", "vampire_9": "Votre santé semble faible", "ach_bk:scourged": "Maudis", "ach_bk:scourged_desc": "Prenez un jeton maudis", "ach_bk:scourged_weapon": "Arme Maudite", "ach_bk:scourged_weapon_desc": "Ramassez une arme maudite", "rerolled": "Rerolled", "ach_bk:open_up": "Ouvrir", "ach_bk:open_up_desc": "Tout acheter à Boxy", "ach_bk:snek": "Animal de compagnie Snek", "ach_bk:snek_desc": "Faites du Snek votre animal de compagnie", "bk:scourge_of_greed": "La Malédiction de l'Avidité", "bk:scourge_of_greed_desc": "Prix élevés", "killed_by": "Tué par", "kills": "Kills", "time": "Temps", "depth": "Profondeur", "bk:blank_bullets": "Balles à Blanc", "bk:blank_bullets_desc": "Vide", "bk:lego": "Constructeur", "bk:lego_desc": "Cela fait tellement mal de marcher sur ces...", "bk:iron_armor": "Armure de Fer", "bk:iron_armor_desc": "Donne des boucliers", "bk:round_shield": "Bouclier Rond", "bk:round_shield_desc": "Empêche les dégâts de mêlée", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "La légende elle-même", "bk:inverted_arkhalis": "Arkhalis Inversé", "bk:inverted_arkhalis_desc": "L'aide viendra quand la santé sera au plus bas", "bk:gun_sword": "Épée fusil", "bk:gun_sword_desc": "Préparez-vous aux ennuis et faites en deux fois plus!", "ach_bk:scourge_king_desc": "Obtenew 10 points de Malédiction", "ach_bk:scourge_king": "Roi Maudis", "ach_bk:sting_operation": "Opération Pointilleuse", "ach_bk:sting_operation_desc": "Vaincre la Reine des Abeilles", "ach_bk:mummified": "Momifié", "ach_bk:mummified_desc": "Vaincre le Pharaon", "ach_bk:democracy": "Démocratie", "ach_bk:democracy_desc": "Vaincre le Vieux Roi", "pharaoh_scream": "##PRÉPARE TOI À ÊTRE MOMIFIÉ!##", "queen_bee_scream": "##POUR LE [cl yellow]SEIGNEUR DU MIEL[cl]!##", "bk:half_heart": "Demi-Coeur", "right": "Droite", "down": "Bas", "left": "Gauche", "up": "Haut", "painting_cat": "Peinture de Chat", "bk:axe": "Hache", "bk:axe_desc": "Il a promis de revenir", "bk:guitar": "Guitare", "bk:guitar_desc": "Elle est désaccordée", "bk:glass_sword": "Épée de verre", "bk:glass_sword_desc": "L'arme des maîtres", "bk:chicken": "Aile de Poulet", "bk:chicken_desc": "C'est chaud", "bk:pickaxe": "Pioche", "bk:pickaxe_desc": "Creuse, paysan!", "bk:mana": "Mana", "bk:half_mana": "Demi Mana", "bk:lava_wand": "Baguette de lave", "bk:lava_wand_desc": "Matière chaude", "bk:web_wand": "Baguette de l'Araignée", "bk:web_wand_desc": "Fournisseur d'accès au web", "bk:slap_stick": "Bâton à claques", "bk:slap_stick_desc": "Slap", "sensivity": "Sensibilité", "no": "Non", "scale": "Taille", "ach_bk:ice": "L'ère glaciaire", "ach_bk:ice_desc": "Atteindre les Ruines Gelées", "ach_bk:library": "Les Textes Sacrés", "ach_bk:library_desc": "Accéder à la bibliothèque secrète", "bk:ice_skates": "Patins à glace", "bk:ice_skates_desc": "L'immunité à la glace", "bk:campfire_in_bottle": "Feu de camp en bouteille", "bk:campfire_in_bottle_desc": "Immunité au gel", "library": "Bibliothèque secrète", "ach_bk:cat_without_a_hat": "Un chat sans chapeau", "ach_bk:cat_without_a_hat_desc": "Trouver le tableau du chat", "ach_bk:rich": "Papier Toilette", "ach_bk:rich_desc": "Obtiens 99 pièces", "ach_bk:rescue_operation": "Opération de sauvetage", "ach_bk:rescue_operation_desc": "Sauver un PNJ", "ach_bk:tutorial": "Gourou", "ach_bk:tutorial_desc": "Terminer le tutoriel", "ach_bk:fancy_hat": "Chapeau fantaisie", "ach_bk:fancy_hat_desc": "Acheter un chapeau", "ach_bk:unlock": "Débloqueur", "ach_bk:unlock_desc": "Débloquer un objet", "floor_brightness": "Luminosité de la salle", "ach_bk:shielded": "Boucliers levés", "ach_bk:shielded_desc": "Obtenir un coeur-bouclier", "run_type": "Type de partie", "run_regular": "Normal", "run_challenge": "Challenge", "damage_taken": "Dégats subis", "km": "km", "distance_traveled": "Distance parcourue", "seed": "Seed", "score": "Score", "new_high_score": "Nouveau record!", "items_collected": "Objets collectés", "boss_rush": "Boss Rush", "run_bossrush": "Boss rush", "bk:blindfold_desc": "RIP mes armes", "bk:blindfold": "Les yeux bandés", "daily_run": "Le prochain commence dans", "builder_0_0": "Yeah", "builder_0_1": "J'ai besoin de mon argent pour moi", "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?", "builder_1": "Mais tu n'as pas d'argent! :(", "builder_2": "Merci de votre investissement!", "builder_3": "J'ai enfin assez d'argent pour terminer le projet ! Merci beaucoup.!", "builder_4": "Okay, pardon!", "shortcut_is_broken": "Le raccourci est cassé", "ach_bk:boss_rush": "Boss Challenger", "ach_bk:boss_rush_desc": "Vaincre tous les bosses dans le mode Boss Rush", "ach_bk:daily": "Gloire Quotidienne", "ach_bk:daily_desc": "Relevez le défi quotidien", "ach_bk:desert_shortcut": "Raccourci vers le Palais du Désert", "ach_bk:desert_shortcut_desc": "Réparer le raccourci vers le Palais du Désert", "ach_bk:jungle_shortcut": "Raccourci vers la Jungle Ancienne", "ach_bk:jungle_shortcut_desc": "Réparer le raccourci vers la Jungle Ancienne", "ach_bk:ice_shortcut": "Raccourci vers les Ruines Gelées", "ach_bk:ice_shortcut_desc": "Réparer le raccourci vers les Ruines Gelées", "ach_bk:library_shortcut": "Raccourci vers la Bibliothèque Secrète", "ach_bk:library_shortcut_desc": "Réparer le raccourci vers la Bibliothèque Secrète", "ach_bk:fashion_matters2": "La mode a son importance", "ach_bk:fashion_matters2_desc": "Acheter tous les chapeaux", "ach_bk:10_challenges": "Challenger", "ach_bk:10_challenges_desc": "Compléter 10 challenges", "ach_bk:20_challenges": "Challenger 2.0", "ach_bk:20_challenges_desc": "Compléter 20 challenges", "ach_bk:30_challenges": "Challenger 3.0", "ach_bk:30_challenges_desc": "Compléter 30 challenges", "ach_bk:bk_no_more": "Plus de BK", "ach_bk:bk_no_more_desc": "Vaincre le Burning Knight en personne", "ach_bk:dm_no_more": "Plus de MN", "ach_bk:dm_no_more_desc": "Vaincre le Mage Noir", "ach_bk:egor_no_more": "Plus de Egor", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Ah, et c'est reparti", "ach_bk:loop_desc": "Entrez dans la boucle", "coins_collected": "Pièces collectées", "bk:cup_head": "Cup Head", "bk:cup_head_desc": "Prendre une tasse de thé", "bk:mustache_hat": "Moustache", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Chapeau à hélices", "bk:propeller_hat_desc": "Ça tourne", "bk:sunglasses": "Lunettes de soleil", "bk:sunglasses_desc": "Marche avec la lune aussi!", "bk:cap": "Casquette", "bk:cap_desc": "Cool @-@", "bk:eyes": "Yeux", "bk:eyes_desc": "@ @", "bk:eye": "Oeil", "bk:eye_desc": "@", "bk:hair": "Cheveux", "bk:hair_desc": "Fantaisie", "won": "Gagné", "won_message": "Tu as gagné!", "garderobe_sign": "Vestiaire", "darkmarket_tip": "~~[cl purple]Une Malédiction[cl] ou [cl yellow]30 pièces[cl]@@", "mike_0": "Il faut me payer [cl green]3 émeraudes", "mike_1": "Essaye boss rush contre [cl green]3 émeraudes[cl]!", "bk:weird_potion": "Potion Bizarre", "bk:weird_potion_desc": "Projectiles bizarres", "bk:megaphone": "Megaphone", "bk:megaphone_desc": "Projectiles à expansion", "scourge": "Malédiction", "scourge_stats": "Malédiction", "run_daily": "Quotidien", "completed_on": "Complété le", "complete": "Terminé", "next_daily_in": "[cl gray]La prochaine commence dans[cl]", "hours": "heures", "minutes": "minutes", "seconds": "secondes", "ach_bk:star": "La Vedette du Spectacle", "ach_bk:star_desc": "Obtiens 3 orbites", "ach_bk:family": "Petite famille heureuse", "ach_bk:family_desc": "Obtenir 3 animaux de compagnie", "ach_bk:return_to_sender": "Non Toi", "ach_bk:return_to_sender_desc": "Tuer un ennemi avec son propre projectile", "ach_bk:van_no_gogh": "Van No Gogh", "ach_bk:van_no_gogh_desc": "Détruire 100 peintures", "ach_bk:dark_market": "Cachette pour les criminels", "ach_bk:dark_market_desc": "Descendre dans le marché noir", "ach_bk:spikes": "Une question épineuse", "ach_bk:spikes_desc": "Active 100 piques en une seule partie", "ach_bk:white_flag": "Sans arme", "ach_bk:white_flag_desc": "Vaincre une salle sans utiliser une arme une seule fois", "quack": "[cl yellow]Coin![cl]", "pixel_perfect": "Pixel Perfect", "bk_11": "JE TE PARDONNE POUR CETTE FOIS... MAIS ##N'ESSAYEZ PAS## DE RECOMMENCER!", "leaderboard": "Leaderboard", "display": "Affichage", "around_you": "Autour de vous", "friends": "Amis", "global": "Global", "loading": "Chargement", "generating": "Génération", "cursor_radius": "Rayon du curseur", "no_scores_yet": "Aucun résultat pour l'instant", "no_score_yet": "Aucun résultat pour l'instant", "run": "Partie", "top": "Top", "quick_restart": "Redémarrage Rapide", "painting_dungeon": "Donjon", "painting_goose": "Mini-Oie", "painting_chess": "Eléphant volant", "painting_peach": "Un arbre à pêche", "bk:no_lamp": "Pas de lampe", "bk:explosive_lamp": "Lampe explosive", "bk:explosive_lamp_desc": "Quand boom veut dire plus", "bk:shielded_lamp": "Lampe blindée", "bk:shielded_lamp_desc": "Boucliers levés!", "lamp": "Lampe", "bk:brain": "Méga Cerveau", "bk:brain_desc": "Taille de l'Esprit: Méga", "bk:heart_amulet": "Amulet en Coeur", "bk:heart_amulet_desc": "+1 à vos Coeurs", "bk:star_amulet_desc": "Mana Augmenté", "bk:star_amulet": "Amulette Étoilée", "bk:coin_amulet": "Amulette Pièces de monnaie", "bk:coin_amulet_desc": "Les pièces ont plus de valeur", "bk:key_amulet": "Amulette Clé", "bk:key_amulet_desc": "Les clés ont plus de valeur", "bk:bomb_amulet": "Amulet Explosive", "bk:bomb_amulet_desc": "Les bombes ont plus de valeur", "bk:eye_amulet": "Amulette Oculaire", "bk:eye_amulet_desc": "Ça fait mal de ne pas être précis", "bk:eye_patch": "Cache-Oeil", "bk:eye_patch_desc": "Vous-êtes prêts, les enfants ??", "bk:toilet_paper": "Papier Toilette", "bk:toilet_paper_desc": "Ça se termine toujours", "bk:decoy": "Leurre", "bk:decoy_desc": "Ça explose", "bk:wallet": "Banque de Compagnie", "bk:wallet_desc": "Stock vos pièces", "bk:skele_buddy": "Copain Squelette", "bk:skele_buddy_desc": "Effrayant ", "bk:mega_bomb": "Mega Bombe", "bk:mega_bomb_desc": "Taille de la Bombe : Mega", "bk:condensed_milk": "Lait Condensé", "bk:condensed_milk_desc": "Pixels rapides - Ennemis lents", "bk:marshmallow": "Marshmallow", "bk:marshmallow_desc": "Collant", "bk:orbital_multiplier": "Multiplicateur Orbital", "bk:orbital_multiplier_desc": "Plus d'Orbites!", "bk:pet_multiplier": "Multiplicateur d'animaux de compagnie", "bk:pet_multiplier_desc": "Plus d'animaux!", "bk:ghost_bullets": "Balles Fantômes", "bk:ghost_bullets_desc": "Les murs ne les arrêteront pas", "bk:weight": "Poids Lourd", "bk:weight_desc": "Booster de gravité", "bk:d2": "D2", "bk:d2_desc": "À prendre ou à laisser", "bk:ethernal_d6": "Ethernel D6", "bk:ethernal_d6_desc": "Rerolls et\/Ou Détruit", "bk:billiard": "Billard", "bk:billiard_desc": "Les balles rebondissent", "bk:enraged_bullets": "Balles Enragées", "bk:enraged_bullets_desc": "Les balles cassent les balles", "bk:rewind_button": "Bouton de Rembobinage", "bk:rewind_button_desc": "Attends", "bk:piggy_bank": "Tirelire", "bk:piggy_bank_desc": "Mes économies", "coins": "Pièces", "bk:death_star": "L'étoile de la mort", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Fer à souder", "bk:soldering_iron_desc": "C'est chaud", "bk:can": "Conserve", "bk:can_desc": "Projectiles doubles", "bk:swimming_mask": "Masque de Plongé", "bk:swimming_mask_desc": "C'est une arme secrète", "bk:bullet_chair": "Balle Chaise", "bk:bullet_chair_desc": "4 Pieds 4 Armes", "bk:cell": "Cellule", "bk:cell_desc": "Les projectiles se multiplient", "bk:brick": "iBrick", "bk:brick_desc": "Des niveaux plus grands", "bk:ring_of_pain": "Anneau de Douleur", "bk:ring_of_pain_desc": "Les dégâts sont infligés à tout le monde", "bk:schrodingers_cat": "Le Chat de Schrödingers", "bk:schrodingers_cat_desc": "Être ou ne pas être (50% de chance)", "bk:smoke_bomb": "Bombe Ninja", "bk:smoke_bomb_desc": "Une évasion inspirée par les Ninjia", "bk:chest_ring": "Bague du Coffre", "bk:chest_ring_desc": "Plus de Coffres!", "bk:empty_shell": "Coquille vide", "bk:empty_shell_desc": "Une chance de détruire les balles ennemies", "bk:parachute": "Parachute", "bk:parachute_desc": "Empêche les dégâts de chute", "bk:spiked_cookie": "Cookie Épiqués", "bk:spiked_cookie_desc": "Ca pique", "bk:shooty": "Shooty", "bk:shooty_desc": "Il tire", "bk:rabbit_bullets": "Balles Lapin", "bk:rabbit_bullets_desc": "Elles se multiplient", "bk:pandoras_box": "La Boîte de Pandore", "bk:pandoras_box_desc": "Conserve le Mal", "bk:bubbles": "Bulles", "bk:bubbles_desc": "L'ami des bulles", "bk:match": "Match", "bk:match_desc": "Tire pour tous les monde", "bk:hammer": "Marteau", "bk:hammer_desc": "Briseur d'armure", "bk:helmet": "Casque de fer", "bk:helmet_desc": "Une chance d'ignorer les dommages", "bk:beer": "Bière", "bk:beer_desc": "Enragés par les dégâts", "bk:the_eye": "L'Oeil", "bk:the_eye_desc": "Il regarde", "bk:mimics_tooth": "Dent de l'Imitateur", "bk:mimics_tooth_desc": "Attire les mimiques", "ach_bk:mimic": "Jump Scare", "ach_bk:mimic_desc": "Révèle une mimique", "bk:paper_airplane": "Avion en papier", "bk:paper_airplane_desc": "Missile à Tête Chercheuse", "ach_bk:ice_boss": "Laissez-le aller", "ach_bk:ice_boss_desc": "Tuez la Reine de Glace", "ice_queen_scream": "^^[cl cyan]Ahem", "painting_agency": "Bienvenue à l'Qgence", "language": "Langue", "bk:pouch": "Poche", "bk:alien_glasses": "Lunettes Alien", "bk:alien_glasses_desc": "Je vois mieux", "inventory": "Inventaire", "bk:led": "LED", "bk:led_desc": "Lampe précise", "bk:fragile_lamp": "Lampe fragile", "bk:fragile_lamp_desc": "K.O.en un coup", "painting_guitar": "Plus de volume!", "ach_bk:maanex": "Et tu, Brut ?", "ach_bk:maanex_desc": "Tue Maanex tout en portant son chapeau", "dad_0": "Hey fiston![dl] Je dois aller trouver [cl red]la Lampe [cl]. Je te laisse régner.", "dad_1": "Si je ne reviens pas, ne viens pas me chercher. Salut!", "son_0": "##NOOOOOOON##", "gobbo_0": "Fiston, [cl green]mon père[cl] est parti il y a 20 ans. Je dois le retrouver.", "gobbo_1": "Je te laisse régner. Salut!", "dm_5": "Une nouvelle et ^^meilleure^^ [cl red]marionette[cl]![dl] ##MUHAHAHA##", "dm_6": "M'entends-tu, [cl red]Limpor?", "heinur_0": "##NON[dl], PAS ENCORE!##", "nbk_0": "##OUI, MON MAÎTRE##", "bk_12": "##JE N'AI PLUS DE ROI EN STOCK, AFFRONTE-MOI DONC, IDIOT!##", "bk:headshot_gun": "Pistolet courbé", "bk:headshot_gun_desc": "Headshot", "bk:laser_cannon": "Canon laser", "bk:laser_cannon_desc": "Haha, laser go pew pew", "credits": "Crédits", "head_0": "Idiot", "tech": "Techno", "ach_bk:collector": "Collectionneur", "ach_bk:collector_desc": "Débloque tous les items", "bk:treasure_key": "Clé rouge", "bk:treasure_key_desc": "Ouvre des échappatoires", "bk:pass": "Laisser-Passer", "bk:pass_desc": "Identifiez-vous!", "bk:bucket": "Seau", "bk:bucket_desc": "Inutile sans le contenu", "bk:water_bucket": "Seau d'eau", "bk:water_bucket_desc": "Calme [cl red]le Feu[cl]", "bk:snow_bucket": "Seau de neige", "bk:snow_bucket_desc": "Peut-être, que ça peut fondre", "m2_0": "Je ne vais jamais pouvoir récupérer financièrement de cette perte", "m2_1": "Bien joué!", "m2_2": "Hey mec, ça te dirait de mettre tes %%skills%% ^^à l'epreuve^^?", "m2_3": "Utilise ^^%%l'Ordinateur%%^^ pour controler le grappin!", "maanex2_0_0": "Prends mon argent!", "maanex2_0_1": "Pas cette fois, merci.", "maanex2_0": "Okay, Donne-moi [cl yellow][vr cost] pièces [cl] et tu peux essayer le grappin!", "dm_7": "Jouons un jeu", "bkw_0": "UN AUTRE [cl red]INTRUS[cl]!", "bkw_1": "##VAS-T'EN##[dl], OU JE M'EN CHARGE!", "bkw_2": "Je suis à la recherche de [cl green]mon père", "bkw_3": "JE T'AURAIS _PRÉVENU_", "spanish_inquisition": "[cl red]L'Inquisition Espagnole", "lp_0": "Bien joué, [cl purple]Ritta[cl][dl], réinitialisation de [cl green]la simulation[cl][dl].[dl].[dl].", "bk:broken_bucket": "Seau cassé", "bk:broken_bucket_desc": "Protecc", "bk:ankh": "Ankh", "bk:ankh_desc": "Vie éternelle", "bk:broken_ankh": "Ankh cassé", "bk:broken_ankh_desc": "Vie éternelle?", "bk:what": "Quoi", "bk:what_desc": "sérieusement, QUOI?", "bk:gold_minigun": "Minigun doré", "bk:gold_minigun_desc": "Haha budget go brrr", "bk:gold_dagger": "Dague dorée", "bk:gold_dagger_desc": "Vieille mais dorée", "bk:gold_revolver": "Revolver doré", "bk:gold_revolver_desc": "Couvrez-moi d'or", "bk:gold_axe": "Hache dorée", "bk:gold_axe_desc": "Juste une hache", "painting_code": "Code", "bk:katana": "Katana", "bk:katana_desc": "Qui est [cl orange]le propriétaire[cl]?", "bk:smart_gun": "Pistolet intelligent", "bk:smart_gun_desc": "Il sait", "bk:pop_gun": "Pop Gun", "bk:pop_gun_desc": "Très populaire", "bk:the_button": "Le Bouton", "bk:the_button_desc": "Attaque dans 8 directions", "bk:gold_sword": "Epée dorée", "bk:gold_sword_desc": "Quand tu ne sais plus comment dépenser ton argent", "bk:donut": "Donut", "bk:donut_desc": "N'hésite-pas", "bk:sudoku": "Sudoku", "bk:sudoku_desc": "La moitié de la salle a disparu, réduite en atomes", "bk:gps_ring": "Anneau GPS", "bk:gps_ring_desc": "Une chance de révéler l'étage", "bk:shield_potion": "Potion Bouclier", "bk:shield_potion_desc": "Grosse gorgée de Jus de bouclier ", "bk:trash_generator": "Générateur d'ordures", "bk:trash_generator_desc": "Oui.", "bk:crabs_claw": "Pince de crabe", "bk:crabs_claw_desc": "Détruit toutes les armures", "eg_3": "Belle journée, Monsieur", "eg_0_0": "Prendre ^^[cl lime]ces émeraudes[cl]^^", "eg_0_1": "Les laisser", "eg_0": "Prends [cl lime]mes émeraudes[cl], je t'en supplie!", "eg_1": "Je m'en vais", "bk:reverse_card": "Carte Inversion", "bk:reverse_card_desc": "Rouler à travers les projectiles les dévie", "bk:magnet": "Aimant", "bk:magnet_desc": "Attraction & Affection", "bk:glowing_mushroom": "Champignon brillant", "bk:glowing_mushroom_desc": "Il est vibrant", "bk:tinfoil_hat": "Chapeau en papier d'aluminium", "bk:tinfoil_hat_desc": "Tu te sens en sécurité", "bk:rear_window": "Vitre arrière", "bk:rear_window_desc": "Regarde derrière toi", "bk:refractor": "Réfracteur", "bk:refractor_desc": "Une chance d'attaquer dans toutes les directions", "bk:fork": "Fourchette", "bk:fork_desc": "Ça fait mal", "bk:rock": "Rocher", "bk:rock_desc": "Les dégâts ont un coût", "bk:coffee_grinder": "Moulin à café", "bk:coffee_grinder_desc": "Projectiles petits & rapides ", "integrations": "Integrations", "twitch": "Twitch", "streamer_username": "Pseudo du Twitcher", "bk:shawarma": "Shwarma", "bk:shawarma_desc": "Parfois les projectiles sont plus gros", "bk:cats_ear": "Oreille de chat", "bk:cats_ear_desc": "Esquive de malade", "luck": "Chance", "bk:gamepad": "Gamepad", "bk:gamepad_desc": "FPS stable", "bk:hotdog": "Hotdog", "bk:bomb_shell": "Obus", "bk:bomb_shell_desc": "Santé étrange", "painting_no_idea": "No Idea", "painting_tinkerer": "Tinkerer", "painting_in_loving_memory_of_ali": "In loving memory of Ali", "painting_happy_accident": "Happy Accident", "painting_observing_cheese": "Observing Cheese", "painting_chicken_enemy_unknown": "Chicken Enemy Unknown", "painting_know_stuff": "Know Stuff", "painting_whoops": "Whoops", "painting_too_lake": "Too Lake", "painting_step_through": "Threshold", "painting_thats_a_moon": "That's a moon", "painting_totem": "Magic Circle", "painting_too_late": "Too Late", "painting_whipped_cream": "Whipped Cream", "painting_beet_boys": "Beet Bois", "painting_moonshine": "Moonshine", "painting_void": "The Void", "painting_peasants": "Peasants", "quality" : "Qualité", "20_years_later" : "20 ans plus tard" } ================================================ FILE: BurningKnight/Content/Locales/it.json ================================================ { "bk:halo": "aureola", "bk:halo_desc": "Vita su", "bk:revolver": "Revolver", "bk:sword": "Spada di legno", "bk:sword_desc": "Non solamente un bastone", "bk:heart": "Cuore", "resume": "Continua", "settings": "Opzioni", "restart": "Ricomincia", "death_message": "Sei morto", "descend": "Scendi", "ascend": "Sali", "exit": "esci", "painting_rexcellent": "rexcellent", "painting_grannylisa": "Nonnalisa", "painting_maanex": "maanex il Pensatore", "painting_bk": "Cavaliere arrostito", "painting_failpositive": "Festeggiatore Seriale", "painting_old_man": "Un Uomo Molto Vecchio", "painting_arthouse": "Casa dell'Arte", "painting_black": "Universo", "painting_milt": "Ragazzo nella neve", "painting_skyscraper": "Grattacielo solitario", "painting_egor": "Rex infuocato", "painting_null": "NULL", "painting_badosz": "Ragazzo perso nel bosco", "painting_banana": "BANANA", "painting_tv": "TV nel cielo", "painting_company": "Buona compagnia", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "cane du Trasevol", "painting_lamp": "Prendila", "painting_scream": "Gelato", "painting_stars": "Notte stellata", "painting_fog": "Nei mari", "painting_nufflee": "Bau", "by": "da", "old_man_0": "E' pericoloso!", "continue_run": "Continua la Partita", "new_run": "Nuova Partita", "was_unlocked": "E' stata sbloccata!", "bk:revolver_desc": "Mani in alto, @everyone!", "bk:shovel": "Pala blu", "bk:shovel_desc": "Ma perche' e blu???", "beet_0": "Ciao!", "beet_2": "seed:", "npc_hurt_0": "Ouch.", "npc_hurt_1": "Hei fa male.", "npc_hurt_2": "Oh no.", "beet_3": "Grazie <3", "beet_1": "Vuoi piantare un seme ^^seme^^?", "beet_1_0": "Si!", "beet_1_1": "No.", "beet_4": "il seme e' [vr seed]. Lo vuoi cambiare?", "beet_4_0": "Si!", "beet_4_1": "No.", "beet_5": "Vabbe.", "beet_4_2": "Mettilo a caso!", "beet_6": "Ok. il seme e' [vr seed]!", "bk:idol": "Idol", "bk:idol_desc": "Una trappola nascosta si e' attivata!", "bk:key": "Chiave d'oro", "bk:infinite_bomb": "Bombe infinite", "bk:infinite_bomb_desc": "Bombe riusabili", "throw_coin": "Lancia una moneta", "bk:potatoo": "Patata", "bk:potatoo_desc": "Proiettili che si dividonooo", "bk:spectacles": "occhiali magici", "bk:spectacles_desc": "Rivela segreti", "bk:cross": "Croce", "bk:cross_desc": "aumenta periodo di invincibilita", "bk:slime": "Slime", "bk:slime_desc": "Proiettili rimbalzanti", "bk:missile": "Missile", "bk:missile_desc": "teleguidati", "bk:rod_of_discord": "bacchetta della Discordia", "bk:rod_of_discord_desc": "Teletrasportatore per @everyone", "bk:goo": "Goo", "bk:goo_desc": "Amico orbitante", "bk:jelly": "Gelatina!", "bk:jelly_desc": "^^Rimbalzoso^^", "bk:broken_stone": "Pietra rotta", "bk:broken_stone_desc": "Orbitale ben fatto", "bk:nano_orb": "Orb nano", "bk:nano_orb_desc": "Micro amici", "bk:saturn": "Pianeta", "bk:saturn_desc": "Of course we still love it", "bk:soap": "Sapone", "bk:soap_desc": "Rallenta i tuoi proiettili", "bk:d6": "D6", "bk:d6_desc": "^^Ripesca^^ oggetti!", "bk:my_heart": "Il mio cuore", "bk:my_heart_desc": "Salute su", "bk:broken_heart": "Cuore spezzato", "bk:broken_heart_desc": "salute su", "bk:parcel": "Pacco", "bk:parcel_desc": "Cura riusabile", "bk:glass": "Vetro", "bk:glass_desc": "Proiettili ##Fragili##", "bk:glass_bullet": "Proiettili di vetro", "bk:glass_bullet_desc": "Spaccavetri", "bk:broken_guitar": "Chitarra rotta", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Mitragloatrice", "bk:machine_gun_desc": "Automatica", "bk:grenade_launcher": "Lanciagranate", "bk:grenade_launcher_desc": "Kaboom!", "bk:shotgun": "fucile", "bk:shotgun_desc": "Sale in faccia!", "bk:missile_launcher": "Lancia missili", "bk:missile_launcher_desc": "Obbiettivo agganciato!", "bk:burst_gun": "Burst Gun", "bk:burst_gun_desc": "Velocita' della luce", "bk:flak_cannon": "Cannone antiaereo", "bk:flak_cannon_desc": "e' tempo di festa!", "bk:disk_gun": "Pistola lanciadisco", "bk:disk_gun_desc": "Roba affilata", "bk:duck_gun": "Pistola papera", "bk:duck_gun_desc": "quack!", "bk:follower": "Seguace", "bk:follower_desc": "Seguimi!", "bk:portal_gun": "Portal Gun", "bk:portal_gun_desc": "Cake is a lie", "bk:snowflake": "Fiocco di neve", "bk:snowflake_desc": "Fermi tutti!", "bk:restock": "Rifornimenti", "bk:restock_desc": "scorte infinite al negozio", "bk:charisma_ring_desc": "Sconti regali", "bk:charisma_ring": "Anello del carisma", "bk:battery": "Batteria", "tomb_0": "Qui giace [cl green]Gobbo[cl] il grande", "bk:homemade_dice": "Dado fatto in casa", "bk:homemade_dice_desc": "^^R^^ items! (DIY)", "shopkeeper_0": "##TI AVEVO DETTO DI NON FARLO!##", "shopkeeper_1": "Per favore fermati!", "shopkeeper_2": "Non lo fare.", "shopkeeper_3": "[cl red]##PREPARATI A MORIRE!##", "shopkeeper_4": "[cl red]LADRO!", "shopkeeper_5": "[cl red]PRENDETELO!", "desert": "Palazzo del deserto", "jungle": "Giungla antica", "ice": "Rovine Ghiacciate", "bk:iron_boots": "Stivali di ferro", "bk:iron_boots_desc": "Le trappole non mi faranno piu paura", "bk:mimic_totem": "Totem dei mimic", "bk:mimic_totem_desc": "##NIENTE PIU' MIMIC##", "back_to_town": "Torna al villaggio'", "bk:glass_gun": "pistola di vetro", "bk:glass_gun_desc": "##Fragile##", "bk:glass_shard": "frammenti do vetro", "bk:glass_shard_desc": "solo un pezzo dell totale", "bk:dagger": "Pugnale", "bk:dagger_desc": "Nostalgia...", "bk:spear": "Lancia", "bk:spear_desc": "Braccia piu lunghe?", "shopkeeper_6": "Benvenuto :)", "shopkeeper_7": "Hei, vuoi un po di [cl yellow]te'[cl]?", "shopkeeper_8": "come va?", "back": "indietro", "master_volume": "Principale", "music": "Musica", "sfx": "Effetti audio", "graphics": "Grafica", "audio": "Audio", "ui_sfx": "Suoni interfaccia", "on": "On", "off": "Off", "fullscreen": "Schermo intero", "vsync": "V-Sync", "fps": "Contatore FPS", "speedrun_timer": "Speedrun Timer", "screenshake": "Screen Shake", "reset_progress": "Reset dei Progressi", "blood_n_gore": "Sangue", "vegan_mode": "Modalita' vegana", "reset_settings": "Reset delle opzioni", "are_you_sure": "Sicuro?", "yes": "Si", "reset_progress_dis": "Cancellerai tutti i tuoi progressi!", "reset_settings_dis": "Fara' il reset di TUTTE le impostazioni!", "autosave": "Salvataggio automatico", "autopause": "Pausa automatica", "input": "Input", "use": "Usa", "active": "Attiva", "bomb": "Bomba", "interact": "Interagisci", "swap": "Cambia arma", "roll": "Rotola", "duck": "Accucciati", "pause": "Pausa", "none": "Nessuno", "keyboard_controls": "Controlli tastiera", "gamepad_controls": "Controlli gamepad", "keyboard": "Tastieta", "gamepad": "Gamepad", "game": "Gioco", "select": "Seleziona", "cursor": "Cursore", "bk:rip": "RIP", "ach_bk:rip_desc": "muori", "ach_bk:overshake": "Overshake", "ach_bk:overshake_desc": "1000% screen shake", "ach_bk:rip": "Obbiettivo piu' poplare", "bk:emerald": "Smeraldo", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Grazie!^^", "shopkeeper_11": "che %%affare%%!", "shopkeeper_12": "Vuoi [cl red]comprare[cl] ^^qualcosa^^?", "shopkeeper_13": "solo per [cl green]te[cl], solo oggi!", "shopkeeper_14": "Che [cl yellow]offerte[cl]!", "bk:magnifier": "Lente d'ingrandimento", "bk:magnifier_desc": "Proietti piu' grandi", "bk:mushroom_hat": "Cappello fungo", "bk:mushroom_hat_desc": "Gustoso?", "bk:stone_hat": "cappello di pietra", "bk:stone_hat_desc": "Pesante", "bk:knight_hat": "elmo del cavaliere", "bk:knight_hat_desc": "Buoni vecchi nemici ...", "bk:cowboy_hat": "Cappello del cowboy", "bk:cowboy_hat_desc": "Wild west!", "bk:soup_hat": "Cappello zuppa", "bk:soup_hat_desc": "^^Yummy^^", "bk:gold_hat": "Cappello d'oro", "bk:gold_hat_desc": "[cl yellow]Ricco!", "bk:viking_hat": "Cappello del vichingo", "bk:viking_hat_desc": "America!", "bk:dunce_hat": "Cappello dell'asino", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Cilindro", "bk:top_hat_desc": "Fashion!", "bk:ushanka": "Ushanka", "bk:ushanka_desc": "Dov' e' la mia ##balalaika?##", "bk:valkyrie_hat": "Cappello della valchiria", "bk:valkyrie_hat_desc": "I belive ^^I can fly!^^", "bk:skull_hat": "Cappello teschio", "bk:skull_hat_desc": "I soldi o la vita!", "bk:grandma_head": "Cappello della nonna", "bk:grandma_head_desc": "Te'?", "bk:diamond_helmet": "Elmo di Diamante", "bk:diamond_helmet_desc": "Zitto e scava!", "bk:villager_head": "Testa del villico", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fez", "bk:fez_desc": "Cubit", "bk:no_hat": "Togli il cappello", "bk:no_hat_desc": "Nessun cappello - nessun problema!", "bk:null_hat": "NULL", "bk:null_hat_desc": "Attempt to call a null value", "accessorytrader_0": "##VIA DI QUI!## [dl]O compra questi ^^deliziosi^^ oggetti a soli ^^%%99 diamanti l'uno%%^^!", "accessorytrader_1": "Ciao", "accessorytrader_2": "Hei!", "weapontrader_0": "Vieni dentro!", "weapontrader_1": "Buona giornata, signore!", "weapontrader_2": "Hai voglia di comprare qualcosa?", "activetrader_0": "Migliori offerte sul mercato!", "activetrader_1": "Paghi due e prendi due!", "activetrader_2": "voglio ciambelle, [dl]perpiacere perfavore!!", "hattrader_0": "vuoi essere figo quanto me? [dl]Compra dei cappelli!", "hattrader_1": "vuoi essere figo quanto me? [dl]anch'io bimbo.", "hattrader_2": "^^Ha ha cappelli!^^", "granny_0": "Wuoi del te'?", "granny_1": "Fai una pausa te'!", "granny_2": "Te'?", "bk:xmas_hat": "Cappello di Babbo natale", "bk:xmas_hat_desc": "Buon natale!", "bk:pumpkin_hat": "Zucca intagliata", "bk:pumpkin_hat_desc": "^^Spooky spooky skeleton^^", "bk:cage_key": "Chiave della prigione", "bk:cage_key_desc": "Salva ^^il tipo^^!", "npc_0": "Aiuto! Trova la chiave!", "npc_1": "Grazie per avermi salvato!", "npc_2": "Veloce! Apri la porta!", "npc_3": "Ti prego! aiuto!", "control_0": "Premi [ic 0][ic 1] per posizionare una bomba", "control_1": "Rotola! Premi [ic 0][ic 1] per rotolare!", "control_2": "Premi [ic 0][ic 1] per attaccare", "control_3": "Premi [ic 0][ic 1] per interagire", "control_4": "Qua? [ic 0][ic 1]!", "control_5": "Premi [ic 0][ic 1] per cambiare arma", "shopkeeper_15": "Niente sconto per te!", "shopkeeper_16": "Trova altri soldi e torna qui!", "shopkeeper_17": "Prima devi pagare!", "bk:frog": "Tele Rana", "bk:frog_desc": "Viaggio rapido?", "bk:sword_orbital": "Spada Orbitante", "bk:sword_orbital_desc": "Giustizia", "robbed": "Derubato", "bk:gift_desc": "Cosa c'e' dentro?", "bk:spike_ring": "Anello acuminato", "bk:spike_ring_desc": "I tuoi nemici devono essere ##puniti##!", "bk:fire_ring": "Anello di fuoco", "bk:fire_ring_desc": "Lascia che i tuoi nemici brucino", "bk:ice_ring": "Anello di ghiaccio", "bk:ice_ring_desc": "Ghiaccia i tuoi nemici", "bk:duck_ring": "Anello papera", "bk:duck_ring_desc": "Ti teletrasporta se ti fanno male", "bk:dull_blade": "Lama dalla punta arrotondata", "bk:dull_blade_desc": "Finto autolesionista", "bk:sharp_blade": "Lama affilata", "bk:sharp_blade_desc": "Attento che taglia", "bk:obsidian_shield": "Scudo di ossidiana", "bk:obsidian_shield_desc": "Contraccolpo = 0", "bk:bill": "Banconota", "bk:bill_desc": "99 dollari", "control_6": "Usa un oggetto attivo con [ic 0][ic 1]", "bk:clover": "Quadrifoglio", "bk:clover_desc": "Fortunato!", "bk:d4": "D4", "bk:d4_desc": "^^Ripesca %%i tuoi artefatti%%!^^", "brastin_0": "trova il quadro del [cl purple]gatto[cl]!", "elon_1": "Ecco qua, divertiti", "bk:maanex_head": "Testa di Maanex", "bk:maanex_head_desc": "Hmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Fa pensare i nemici", "mob_0": "Hmmmm", "bk:map_greenprints": "Map Greenprints", "bk:map_greenprints_desc": "Rivela la mappa", "bk:map": "Mappa", "bk:map_desc": "Rivela la mappa per sempre", "milt_1": "Voglio un regalo", "mapuzzle_0": "Gravita'.", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Copiato!", "isaac_0": "La vita non ha sensooo...", "isaac_1": "Percheeeeeeee", "isaac_2": ":sob:", "discord_0": "Vieni a salutarci! discord.gg\/rexcellent", "old_man_5": "rotola, stolto!", "tutorial": "Tutorial", "bk:crying_bomb": "Bomba Piangente", "bk:crying_bomb_desc": "Adesso anche le bombe piangono!", "bk:matches": "Fiammiferi", "bk:matches_desc": "Tempo di esplosione piu breve", "bk:bomb_pack": "Pacco di bombe", "bk:bomb_pack_desc": "Abbiamo messo bombe nelle nostre bombe!", "bk:tnt": "TNT", "bk:tnt_desc": "99 bombe", "bk:weird_mushroom_desc": "Raddoppia tutto", "bk:weird_mushroom": "Che strano fungo", "bk:bomb_shower": "Pioggia di bombe", "bk:bomb_shower_desc": "Piovono bombee", "bk:black_belt": "Cintura nera", "bk:black_belt_desc": "Non esplodere piu'", "bk:ninjia_bomb": "Bombe Ninjia", "bk:ninjia_bomb_desc": "Essere colpiti fa apparire bombe", "start_new_run": "La partita corrente andra' persa!", "bk:laser_pointer": "Puntatore laser", "bk:laser_pointer_desc": "La mira e' piu chiara!", "ach_bk:marauder": "Assassino", "ach_bk:marauder_desc": "Uccidi il negoziante!", "ach_bk:treasure_hunter": "Cacciatore di tesori!", "ach_bk:treasure_hunter_desc": "Trova la stanza segreta", "ach_bk:dodge_master": "Maestro dello schivo", "ach_bk:dodge_master_desc": "Uccidi un boss senza essere colpito", "ach_bk:dodge_overlord": "Padrone supremo dello schivo", "ach_bk:dodge_overlord_desc": "Finisci un livello senza mai colpito", "ach_bk:quackers": "Quackers", "ach_bk:quackers_desc": "Overquack", "ach_bk:tea_party": "Tea Party", "ach_bk:tea_party_desc": "Fai merenda con la nonna", "ach_bk:not_a_thief": "Non un ladro", "ach_bk:not_a_thief_desc": "Finisci una partita senza prendere nessun oggetto", "ach_bk:npc_party2": "NPC Party", "ach_bk:npc_party2_desc": "salva tutti gli NPCs", "bk:gold_coin": "Moneta d'oro", "bk:iron_coin": "Moneta d'argento", "bk:copper_coin": "Moneta di rame", "bk:platinum_coin": "Moneta di platino", "bk:voodoo_doll": "Bambola voodoo", "bk:voodoo_doll_desc": "Uccide tutti i nemici nella stanza", "hub": "Citta della schivata", "castle": "Le rovine del castello", "charger_0": "NESSUN OGGETTO ATTIVO RILEVATO", "charger_1": "L'OGGETTO ATTIVO E' GIA CARICO", "charger_2": "DOVE SONO I MIEI SOLDI?!", "charger_3": "##HO DETTO DAMMI I MIEI SOLDI!##", "charger_4": "##CONQUISTERO' IL MONDO!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Certo, facciamolo!", "maanex_6_1": "Nah.", "maanex_6": "Ok, dammi [cl yellow][vr cost] monete[cl] e ti lasciero' aprire uno di questi scrigni. Ok?", "maanex_5": "Hey amico, vuoi ^^tentare^^ la fortuna?", "maanex_7": "E' stato divertente!", "maanex_8": "Buona fortuna", "maanex_9": "be, questa volta non e' andata:(", "maanex_10": "%%^^WOAH^^%%", "maanex_11": "Ma non hai abbastanza soldi!", "maanex_12": "##FIGLIOLO?!##", "bk:amurs_arrow": "La freccia di cupido", "bk:amurs_arrow_desc": "Proiettili amorosi", "bk:amurs_bow": "Arco di cupido", "bk:amurs_bow_desc": "Vedo l'amore", "bk:poison_flask": "Fiaschetta del veleno", "bk:poison_flask_desc": "Proiettili velenosi", "bk:snowball": "Palladineve", "bk:snowball_desc": "Proiettili gelati", "bk:peper_desc": "Proiettili piccanti", "bk:peper": "Peperoncino", "bk:sale_coupon": "Buono spesa", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Amico in scatola", "bk:pet_box_desc": "C'e' qualcuno?", "bk:crate": "Cratere Orbitante", "bk:crate_desc": "C'e' nessuno?", "bk:strawberry": "Fragola", "bk:strawberry_desc": "Dolci Memorie", "bk:wings": "Ali", "bk:wings_desc": "I belive I can fly", "bk:coin_pouch": "Sacca delle monete", "bk:coin_pouch_desc": "Ti da' monete", "bk:key_pouch": "Sacca delle chiavi", "bk:key_pouch_desc": "Ti da' chiavi", "bk:bomb_pouch": "Sacca delle bombe", "bk:bomb_pouch_desc": "Ti da' Bombs", "bk:pouch_pouch": "Sacca delle sacche", "bk:pouch_pouch_desc": "Ti da' sacche", "bk:lightsaber": "Svetsaber", "bk:lightsaber_desc": "Eri il prescielto!", "bk:snail": "Lumachina", "bk:snail_desc": "Rallentatore di massa", "bk:spike": "Trappola", "bk:spike_desc": "Danno maggiore", "bk:mushroom": "Funghetto", "bk:mushroom_desc": "Velocita' maggiore", "bk:candy": "Caramella", "bk:candy_desc": "^^Pieno di zuccheri^^, velocita' di fuoco maggiore", "bk:glasses": "Occhiali", "bk:glasses_desc": "precisione maggiore", "bk:ruler": "Righello", "bk:ruler_desc": "portata piu lunga", "bk:stopwatch": "Cronometro", "bk:stopwatch_desc": "Venir colpito ti fa controllare il tempo", "bk_0": "##NON TI AZZARDARE A TOCCARLO!##", "bk_1": "##TI HO DETTO NON TOCCARE!##", "bk_2": "##NON POTRAI MAI SCONFIGGERE [cl red]IL BURNING KNIGHT[cl], SCIOCCO!##", "bk_3": "##PREPARATI A MORIRE!##", "bk_4": "^^CHE ASSURDITA'^^", "shopkeeper_18": "[cl red]^^OFFERTONE![cl]", "dm_0": "@@Benvenuto@@", "ach_bk:deal": "Fantastica decisione", "ach_bk:deal_desc": "Fai un affare con il mago oscuro", "ach_bk:grannys_gift": "Regalo di nonna", "ach_bk:grannys_gift_desc": "prendi un regalino dalla nonna", "ach_bk:shopper": "Compra a piu' non posso", "ach_bk:shopper_desc": "Compra ogni oggetto nel negozio", "bk_5": "NON CI PROVEREI NEANCHE A PARLARE CON LUI", "bk_6": "##UCCIDILO, [cl lime]EDWARD[cl]!##", "bk_7": "[cl lime]EDWARD[cl], ##NOOOOOO!!!!##", "bk_8": "OH ANDIAMO, SMETTILA DI ESPLODERMI IL CASTELLO!", "bk_9": "[cl pink]NONNA[cl],[dl] POTRESTI MORIRE, PERFAVORE##?!?##", "bk_10": "MAESTRO,[dl] LE HO PORTATO [cl green]GOBLIN[cl]", "dm_1": "Molto bene[dl], grazie[dl], [cl red]Limpor[cl]", "dm_2": "##SII, si, ho bisogno di piu' [cl orange]potere[cl]!##", "dm_3": "##PIU' [cl orange]POTERE[cl]!", "dm_4": "Posso sentire il [cl orange]potere[cl] scorrermi nelle vene!", "granny_3": "Tu sarai il primo, [cl red]Limpor[cl]!", "granny_4": "Benvenuto, [cl green]Gobbo[cl]!", "granny_5": "Buona fortuna nella tua triste avventura!", "bk:meat_guy": "Meat Guy", "bk:meat_guy_desc": "Figo!", "bk:bullet_stone": "Protettili di pietra", "bk:bullet_stone_desc": "He attac, he protec, but most importantly, he cute as hecc", "bk:batman": "Batman", "bk:batman_desc": "non aiuta, ma ti rifornisce di BATterie", "vibration": "Vibrazione", "bk:sharp_arrow": "Freccia affilata", "bk:sharp_arrow_desc": "proiettili penetranti", "machine_0": "Inserisci una [cl yellow]moneta", "player_0": "Papa'?? ##Che cosa ti han fatto?!?##", "bk:boomerang": "Boomerang", "bk:boomerang_desc": "Proiettili boomerang", "bk:backpack": "Zaino", "bk:backpack_desc": "il mio amico orso", "place_an_item": "metti un oggetto", "bk:crystal": "Cristallo", "bk:crystal_desc": "Il potere dell'arcobaleno", "bk:prism": "Prisma", "bk:prism_desc": "Proiettili -> arcobaleno", "scourged": "Maledetto", "bk:bomb": "Bomba", "bk:scourge_of_egg": "Maledizione delle uova", "bk:scourge_of_egg_desc": "mischia i nomi degli oggetti", "bk:scourge_of_unknown": "Maledizione dell'ignoto", "bk:scourge_of_unknown_desc": "Oggetti nascosti", "bk:scourge_of_blood": "Maledizione del sangue", "bk:scourge_of_blood_desc": "Difficolta' doppia (e nemici)", "bk:scourge_of_risk": "Maledizione del rischio", "bk:scourge_of_risk_desc": "Vita nascosta", "bk:scourge_of_keys": "Maledizione delle chiavi", "bk:scourge_of_keys_desc": "consumabili nascosti", "bk:scourge_of_lost": "Maledizione dei perduti", "bk:scourge_of_lost_desc": "Amnesia", "bk:scourge_of_scourged": "Maledizione delle Maledizioni", "bk:scourge_of_scourged_desc": "Maledizioni ovunque", "bk:scourge_of_illness": "Maledizione della malattia", "bk:scourge_of_illness_desc": "raccogliere cuori cura molto meno", "bk:scourge_of_death": "Maledizione della morte", "bk:scourge_of_death_desc": "Modalita' difficile", "bk:ancient_revolver": "Revolver antico", "bk:ancient_revolver_desc": "Sembra figo", "bk:assault_rifle": "Fucile d'assalto", "bk:assault_rifle_desc": "Raffiche", "fountain_0": "Porta 5 monete e sarai benedetto", "fountain_1": "Sei stato parzialmente purificato", "fountain_2": "Sei stato pienamente purificato", "fountain_3": "Sei gia stato purificato", "buffed": "Buffed", "nerfed": "Nerfed", "restored": "Restaurata", "damaged": "Danneggiato", "cleansed": "Purificato", "gifted": "Migliorato", "lucky": "Fortunato", "unlucky": "Sfortunato", "max_hp": "Vita massima", "touch": "tocca", "break": "rompi", "no_coins": "Nessuna moneta", "old_man_6": "It's dangerous to go alone, take this!", "roger_0": "Kaboom!", "roger_1": "##*BOOM*##", "roger_2": "Boom boom shakataka!", "bk:shield": "Scudo", "bk:gift": "Regalo", "bk:shield_pouch": "Sacca degli scudi", "bk:shield_pouch_desc": "Ti da' scudi", "bk:shield_buddy": "Amico scudo", "bk:shield_buddy_desc": "Protegge", "bk:skeleton_key": "Chiave scheletro", "bk:skeleton_key_desc": "99 chiavi", "bk:jar": "Vasetto della vita", "bk:jar_desc": "clinck!", "bk:star": "Stella", "bk:star_desc": "protegge", "bk:car_bomb": "Automobile bomba", "bk:car_bomb_desc": "Servizio di consegna delle bombe", "bk:grenade": "Granata", "bk:grenade_desc": "Fa' detonare le bombe in un sol colpo ", "trash_goblin_0": "Liberami dalla mia [cl purple]maledizione[cl]! Perfavore!", "trash_goblin_1": "Sono libero![dl] Grazie infinite!", "boxy_0": "chiaveccellente!", "boxy_1": "Che scatola fantastica!", "boxy_2": "Hai bisogno di carta regalo?", "trash_goblin_2": "^^Smoke on the water [ic 0] [ic 1]^^", "bk:vampire_bat": "Ammazzavampiri", "bk:vampire_bat_desc": "Rigenera", "shields": "Scudi", "bk:mustache": "Baffi", "bk:mustache_desc": "VIP", "bk:bloody_chest": "Scrigno insanguinato", "bk:bloody_chest_desc": "Scrigno che cura", "bk:bloody_shield": "Scudo insanguinato", "bk:bloody_shield_desc": "Scudi per sempre!", "bk:cutsaw": "sega", "bk:cutsaw_desc": "i nemici pagheranno", "vampire_0": "Yum!", "vampire_1": "fantastico!", "vampire_2": "Cosi dolce!", "vampire_3": "Conosciamo le regole, [cl red]^^vero[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "Di che gruppo sanguineo sei?", "vampire_6": "Gustosissimo", "duck_2": "Ti piacerebbe partecipare in un sondaggio?", "duck_7_0": "Si", "duck_7_1": "No", "duck_7": "Prenderai questo baule?", "duck_4": "Ottimo lavoro! Tieni questo baule", "duck_5": "Non sono daccordo...", "duck_6_0": "L'universo", "duck_6_1": "^^Quark^^", "duck_6": "A cosa sto pensando?", "duck_8_0": "[cl red]Rosso[cl]", "duck_8_1": "[cl blue]Blu[cl]", "duck_8": "Qual'e' il mio ^^%%colore%%^^ preferito?", "duck_9_0": "Un gatto", "duck_9_1": "L'hai appena detto", "duck_9": "Chi ha detto miao?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "Cos'e' meglio?", "duck_11_0": "Cosa, uovo?", "duck_11_1": "\\[_Lo accoltella_]", "duck_11": "Tu sei un tipo da salsa", "duck_12_0": "Pulcino", "duck_12_1": "Uovo", "duck_12": "Cos'e venuto prima?", "duck_13_0": "Niente.", "duck_13_1": "Uno snack.", "duck_13_2": "Un uovo.", "duck_13_3": "Pollo fritto.", "duck_13": "Cos'hai mangiato oggi?", "duck_14": "Ouch.", "duck_17_0": "Certo", "duck_17_1": "##NAAAAAH##", "duck_17": "Vuoi della ananas sulla tua pizza?", "duck_18_0": "Bianco!", "duck_18_1": "[cl yellow]Giallo[cl]!", "duck_18": "Di che colore e' il formaggio?", "nurse_0": "Sei uno splendore, dolcezza!", "nurse_1": "Potrei curarti un po, ma ho bisogno di [cl yellow][vr price] soldi[cl]", "nurse_2": "Spero non abbia fatto male", "elon_4": "Tutto fatto, divertiti", "elon_2_0": "andiamo", "elon_2_1": "Spetta", "elon_2": "Vuoi provare la mia magia?", "elon_3": "Posso trasformare la tua arma in un altra", "elon_5": "Vabbe'", "elon_7": "hei, che arma hai???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*blush*", "gobetta_4": "Sei.. tu?", "gobetta_5": "E' passato cosi' tanto tempo...", "ach_bk:desert": "arido e asciutto", "ach_bk:desert_desc": "Raggiungi il Palazzo del Deserto", "ach_bk:jungle": "Api", "ach_bk:jungle_desc": "Raggiungi la Giungla Antica", "rooms_explored": "Stanze esplorate", "bk:shadow_cloak_desc": "No tu", "bk:shadow_cloak": "Mantello d'Ombra", "bk:dynamite_stick": "Candela di dinamite", "bk:dynamite_stick_desc": "Vuoi esplodere?", "bk:chalice_of_blood": "Calice di sangue", "bk:chalice_of_blood_desc": "Il dolore invoca rabbia, rabbia invoca danno", "bk:detonator": "Detonatore", "bk:detonator_desc": "Detonatore esplosivo", "invincibility_time": "Tempo di invincibilita'", "accuracy": "Precisione", "range": "Range", "fire_rate": "velocita' di fuoco", "speed": "velocita'", "bk:talisman_of_foresight": "Talismano della premunizione", "bk:talisman_of_foresight_desc": "Apri gli occhi e vedi le stanze vicine!", "bk:scourge_ring": "Anello della maledizione", "bk:scourge_ring_desc": "Niente piu' maledizioni", "snek_0": "buona.", "snek_1": "Grazzzie", "snek_2": "Fantassstico", "snek_3": "come sssstai?", "snek_4": "Buona giornata", "snek_5": "Vuoi comprare qualcossssa?", "snek_6": "Devo sssoddisfare i miei clienti...", "snek_7": "Faro' cio' che devo!", "bk:snek": "Serpe", "bk:snek_desc": "ssnack?", "boxy_3": "^^:wave:^^", "boxy_4": "Hei, hai una chiave in piu'?", "boxy_5": "Avresti qualche chiave da regalarmi?", "bk:blank": "Blank", "bk:blank_desc": "_Blank Text_", "bk:blank_bombs": "Blank Bombs", "bk:blank_bombs_desc": "Bullet Shield", "bk:explosive_bullets": "Proiettili esplosivi", "bk:explosive_bullets_desc": "Esplosivi", "bk:random_bullets": "Proiettili a caso", "bk:random_bullets_desc": "RNG", "bk:cup": "Tazza", "bk:cup_desc": "Tazza per la nonna", "bk:cartridge": "Cartuccia", "bk:cartridge_desc": "Cartuccia per il mago nero", "bk:marriage_ring": "Anello di matrimonio", "bk:marriage_ring_desc": "Mago nero e nonna per sempre !", "boxy_7": "Voglio chiavi", "boxy_8": "Non hai abbastanza chiavi :(", "boxy_9": "Ho finalmente abbastanza chiavi per ^^aprire^^!", "roger_3": "Ti dispiace pagare?", "roger_4": "Niente sconti oggi", "roger_5": "Prima le bombe", "vampire_7": "Non hai abbastanza vita", "vampire_8": "Non faccio sconti", "vampire_9": "La tua vita e troppo bassa", "ach_bk:scourged": "Maledetto", "ach_bk:scourged_desc": "Prendi un gettone per una maledizione", "ach_bk:scourged_weapon": "Arma maledetta", "ach_bk:scourged_weapon_desc": "Prendi un arma maledetta", "rerolled": "Ripesca", "ach_bk:open_up": "Apri", "ach_bk:open_up_desc": "Compra tutto da Boxy", "ach_bk:snek": "Serpente domestico", "ach_bk:snek_desc": "Un serpente come amico", "bk:scourge_of_greed": "Maledizione dell'avidita'", "bk:scourge_of_greed_desc": "Prezzi alti", "killed_by": "Ucciso da", "kills": "Uccisioni", "time": "Tempo", "depth": "Profondita'", "bk:blank_bullets": "Proiettili Blank", "bk:blank_bullets_desc": "Blank", "bk:lego": "Costruttore", "bk:lego_desc": "pestarli fa male...", "bk:iron_armor": "Armatura di metallo", "bk:iron_armor_desc": "Da' scudi", "bk:round_shield": "Scudo rotondo", "bk:round_shield_desc": "assorbe danni da contatto", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "La leggenda in persona", "bk:inverted_arkhalis": "Arkhalis invertito", "bk:inverted_arkhalis_desc": "L'aiuto arriverà a chi e' a corto di salute", "bk:gun_sword": "Spada pistola", "bk:gun_sword_desc": "Preparatevi a passare dei guai, dei guai molto grossi!", "ach_bk:scourge_king_desc": "10 punti maledizione", "ach_bk:scourge_king": "Cavaliere maledetto", "ach_bk:sting_operation": "Operazione pungilione", "ach_bk:sting_operation_desc": "Sconfiggi l'ape regina", "ach_bk:mummified": "Mummificato", "ach_bk:mummified_desc": "Sconfiggi il faraone", "ach_bk:democracy": "Democrazia", "ach_bk:democracy_desc": "Sconfiggi il Vecchio Re", "pharaoh_scream": "##PREPARATI AD ESSERE MUMMIFICATO!##", "queen_bee_scream": "##PER [cl yellow]LORD MIELE[cl]!##", "bk:half_heart": "Mezzo Cuore", "right": "Destra", "down": "Giu'", "left": "Sinistra", "up": "Su", "painting_cat": "Gatto Dipinto", "bk:axe": "Ascia", "bk:axe_desc": "Ha promesso di ritornare", "bk:guitar": "Chitarra", "bk:guitar_desc": "Non e' accordata", "bk:glass_sword": "Spada di Vetro", "bk:glass_sword_desc": "L'arma dei Maestri", "bk:chicken": "Aletta di Pollo", "bk:chicken_desc": "E' piccante", "bk:pickaxe": "Piccone", "bk:pickaxe_desc": "Scava, villico!", "bk:mana": "Mana", "bk:half_mana": "meta' Mana", "bk:lava_wand": "Bacchetta Lava", "bk:lava_wand_desc": "Roba Bollente", "bk:web_wand": "Bacchetta spada", "bk:web_wand_desc": "Fornitore di World-wide web", "bk:slap_stick": "Batacchio", "bk:slap_stick_desc": "Slap", "sensivity": "Sensibilita'", "no": "No", "scale": "Scala", "ach_bk:ice": "Era Glaciale", "ach_bk:ice_desc": "Raggiungi le Rovine Ghiacciate", "ach_bk:library": "Testi Sacri", "ach_bk:library_desc": "Raggiungi la Biblioteca Segreta", "bk:ice_skates": "Pattini da ghiaccio", "bk:ice_skates_desc": "Immunita' al ghiaccio", "bk:campfire_in_bottle": "Falo' in bottiglia", "bk:campfire_in_bottle_desc": "Immunita' al gelo", "library": "Biblioteca Segreta", "ach_bk:cat_without_a_hat": "Gatto senza Cappello", "ach_bk:cat_without_a_hat_desc": "Trova il Dipinto del Gatto", "ach_bk:rich": "Carta igenica", "ach_bk:rich_desc": "Ottieni 99 monete", "ach_bk:rescue_operation": "Operazione di salvataggio", "ach_bk:rescue_operation_desc": "Salva un NPC", "ach_bk:tutorial": "Guru", "ach_bk:tutorial_desc": "Finisci il tutorial", "ach_bk:fancy_hat": "Cappello di Lusso", "ach_bk:fancy_hat_desc": "Compra un cappello", "ach_bk:unlock": "Sbloccatore", "ach_bk:unlock_desc": "Sblocca un oggetto", "floor_brightness": "Luminosita' del pavimento", "ach_bk:shielded": "Scudi su", "ach_bk:shielded_desc": "Ottieni uno scudo", "run_type": "modalita'", "run_regular": "Normale", "run_challenge": "Sfida", "damage_taken": "Danno subito", "km": "km", "distance_traveled": "Distanza Percorsa", "seed": "Seme", "score": "Punteggio", "new_high_score": "Nuovo Record!", "items_collected": "Oggetti collezionati", "boss_rush": "Boss Rush", "run_bossrush": "Boss rush", "bk:blindfold_desc": "RIP le mie armi", "bk:blindfold": "Bendato", "daily_run": "Partita Giornaliera", "builder_0_0": "certo, tieni", "builder_0_1": "non ho soldi per ste cose scusa :(", "builder_0": "Stavo pensando di fare una scorciatoia dal villaggio a qui, ma ho bisogno di altre [vr need] [ic 0] monete. Puoi aiutarmi?", "builder_1": "Ma non hai monete! :(", "builder_2": "Grazie per il tuo investimento!", "builder_3": "Finalmente ho abbastanza soldi per completare il progetto! Grazie mille!", "builder_4": "Okay, tranquillo :)!", "shortcut_is_broken": "La scorciatoia e' rotta", "ach_bk:boss_rush": "Sfidante dei Boss", "ach_bk:boss_rush_desc": "Sconfiggi tutti i Boss nella Boss Rush", "ach_bk:daily": "Gloria giornaliera", "ach_bk:daily_desc": "Completa la sfida giornaliera", "ach_bk:desert_shortcut": "Scorciatoia del Palazzo del Deserto", "ach_bk:desert_shortcut_desc": "Aggiusta la scorciatoria del Palazzo del Deserto", "ach_bk:jungle_shortcut": "Scorciatoia della Giungla Antica", "ach_bk:jungle_shortcut_desc": "Aggiusta la scorciatoria della Giungla Antica", "ach_bk:ice_shortcut": "Scorciatoia delle Rovine Ghiacciate", "ach_bk:ice_shortcut_desc": "Aggiusta la scorciatoria del Rovine Ghiacciate", "ach_bk:library_shortcut": "Scorciatoia della Bibloteca Segreta", "ach_bk:library_shortcut_desc": "Aggiusta la scorciatoria della Bibloteca Segreta", "ach_bk:fashion_matters2": "Le apparenze contano", "ach_bk:fashion_matters2_desc": "Compra tutti i cappelli", "ach_bk:10_challenges": "Sfidante", "ach_bk:10_challenges_desc": "Completa 10 sfide", "ach_bk:20_challenges": "Sfidante 2.0", "ach_bk:20_challenges_desc": "Completa 20 sfide", "ach_bk:30_challenges": "Sfidante 3.0", "ach_bk:30_challenges_desc": "Completa 30 sfide", "ach_bk:bk_no_more": "Niente piu' BK", "ach_bk:bk_no_more_desc": "Sconfiggi il Burning Knight", "ach_bk:dm_no_more": "Niente piu' Mago Nero", "ach_bk:dm_no_more_desc": "Sconfiggi il Mago Nero", "ach_bk:egor_no_more": "Niente piu' Egor", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Ci risamo", "ach_bk:loop_desc": "Entra nel loop", "coins_collected": "Monete raccolte", "bk:cup_head": "Cup Head", "bk:cup_head_desc": "Fatti una tazza di te", "bk:mustache_hat": "Baffi", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Cappello elica", "bk:propeller_hat_desc": "Gira!", "bk:sunglasses": "Occhiali da sole", "bk:sunglasses_desc": "Funzionano anche con la luna!", "bk:cap": "Cappello", "bk:cap_desc": "Cool @-@", "bk:eyes": "Occhi", "bk:eyes_desc": "@ @", "bk:eye": "Occhio", "bk:eye_desc": "@", "bk:hair": "Capelli", "bk:hair_desc": "Elegante", "won": "vinto", "won_message": "Hai vinto!", "garderobe_sign": "Camerino", "darkmarket_tip": "~~[cl purple]Maledizione[cl] o [cl yellow]30 monete[cl]@@", "mike_0": "Devi pagarmi [cl green]3 smeraldi", "mike_1": "Prova la Boss Rush per soli [cl green]3 smeraldi[cl]!", "bk:weird_potion": "Strana Pozione", "bk:weird_potion_desc": "Strani Proiettili", "bk:megaphone": "Megafono", "bk:megaphone_desc": "Proiettili Espandibili", "scourge": "Maledizione", "scourge_stats": "Maledizioni", "run_daily": "Giornaliera", "completed_on": "Completata il", "complete": "completata", "next_daily_in": "[cl gray]La prossima comincia in[cl]", "hours": "ore", "minutes": "minuti", "seconds": "secondi", "ach_bk:star": "La stella dello show", "ach_bk:star_desc": "Ottieni 3 orbitali", "ach_bk:family": "Piccola Famiglia Felice", "ach_bk:family_desc": "Ottieni 3 animali domestici", "ach_bk:return_to_sender": "No tu", "ach_bk:return_to_sender_desc": "Uccidi un nemico con il suo stesso proiettile", "ach_bk:van_no_gogh": "Van No Gogh", "ach_bk:van_no_gogh_desc": "Distruggi 100 dipinti", "ach_bk:dark_market": "Nascondiglio criminale", "ach_bk:dark_market_desc": "Scendi nel Mercato Nero", "ach_bk:spikes": "Roba Affilata", "ach_bk:spikes_desc": "Attiva 100 trappole in una sola partita", "ach_bk:white_flag": "Senza armi!", "ach_bk:white_flag_desc": "Completa una stanza senza mai usare armi", "quack": "[cl yellow]Quack![cl]", "pixel_perfect": "Pixel Perfect", "bk_11": "TI PERDONO PER STA VOLTA.. MA ##NON## RIFARLO PIU'!", "leaderboard": "Leaderboard", "display": "Display", "around_you": "Intorno a te", "friends": "Amici", "global": "Globale", "loading": "Caricamento", "generating": "Generando", "cursor_radius": "Raggio Cursore", "no_scores_yet": "Nessun punteggio ancora", "no_score_yet": "Nessun punteggio ancora", "run": "Partita", "top": "Miglior", "quick_restart": "Ricomincia veloce", "painting_dungeon": "Dungeon", "painting_goose": "Mini Oca", "painting_chess": "Elefante volante", "painting_peach": "Un pesco", "bk:no_lamp": "Nessuna lampada", "bk:explosive_lamp": "Lampada esplosiva", "bk:explosive_lamp_desc": "Quando i boom sono piu' significativi", "bk:shielded_lamp": "Lampada scudo", "bk:shielded_lamp_desc": "Scudi su!", "lamp": "Lampada", "bk:brain": "Mega Cervello", "bk:brain_desc": "Dimensioni cervello: Mega", "bk:heart_amulet": "Amuleto Cuore", "bk:heart_amulet_desc": "+1 alla dimensione del cuore", "bk:star_amulet_desc": "Mana su", "bk:star_amulet": "Amuleto Stella", "bk:coin_amulet": "Amuleto Moneta", "bk:coin_amulet_desc": "Le monete valgono di piu'", "bk:key_amulet": "Amuleto Chiave", "bk:key_amulet_desc": "Le chiavi valgono di piu'", "bk:bomb_amulet": "Amuleto Bomba", "bk:bomb_amulet_desc": "Le bombe valgono di piu'", "bk:eye_amulet": "Amuleto Occhio", "bk:eye_amulet_desc": "Fa male essere inaccurati", "bk:eye_patch": "Benda sull'occhio", "bk:eye_patch_desc": "Siete pronti ragazzi?", "bk:toilet_paper": "Carta Igenica", "bk:toilet_paper_desc": "E sempre finita", "bk:decoy": "Esca", "bk:decoy_desc": "Esplode", "bk:wallet": "Amico portafoglio", "bk:wallet_desc": "Contiene le tue monete", "bk:skele_buddy": "Amico scheletrico", "bk:skele_buddy_desc": "SpaventosooOoO!", "bk:mega_bomb": "Mega bombe", "bk:mega_bomb_desc": "Dimensione Bombe: Mega", "bk:condensed_milk": "Latte condensato", "bk:condensed_milk_desc": "Pixel veloci - nemici piu' lenti", "bk:marshmallow": "Marshmallow", "bk:marshmallow_desc": "Appiccicoso", "bk:orbital_multiplier": "Moltiplicatore di orbitali", "bk:orbital_multiplier_desc": "Piu' orbitali!", "bk:pet_multiplier": "Moltiplicatore di animali domestici", "bk:pet_multiplier_desc": "Piu amici!", "bk:ghost_bullets": "Proiettli fantasma", "bk:ghost_bullets_desc": "I muri non li fermeranno", "bk:weight": "Pesi pesanti", "bk:weight_desc": "Moltiplicatore di gravita", "bk:d2": "D2", "bk:d2_desc": "Prendere o lasciare", "bk:ethernal_d6": "D6 Eterno", "bk:ethernal_d6_desc": "Ritira E\/O Distruggi", "bk:billiard": "Biliardo", "bk:billiard_desc": "I proiettili rimbalzano", "bk:enraged_bullets": "Proiettili furiosi", "bk:enraged_bullets_desc": "Proiettile batte proiettile", "bk:rewind_button": "Pulsante per riavvolgere", "bk:rewind_button_desc": "Aspetta un attim..", "bk:piggy_bank": "Salvadanaio", "bk:piggy_bank_desc": "I miei risparmi di una vita", "coins": "Monete", "bk:death_star": "Death Star", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Saldatore", "bk:soldering_iron_desc": "E' caldo", "bk:can": "Lattina", "bk:can_desc": "Proiettili doppi", "bk:swimming_mask": "Maschera da nuoto", "bk:swimming_mask_desc": "E' un arma segreta", "bk:bullet_chair": "Sedia proiettile", "bk:bullet_chair_desc": "$ gambe 4 pistole", "bk:cell": "Cellula", "bk:cell_desc": "I proiettili si moltiplicano", "bk:brick": "iBrick", "bk:brick_desc": "Livelli piu grandi", "bk:ring_of_pain": "Anello del dolore", "bk:ring_of_pain_desc": "Farsi male fa male a tutti", "bk:schrodingers_cat": "Il Gatto di Schrödingers", "bk:schrodingers_cat_desc": "Essere o non essere (50% probabilita')", "bk:smoke_bomb": "Bomba fumogena", "bk:smoke_bomb_desc": "Fuga stile ninja", "bk:chest_ring": "Anello dei bauli", "bk:chest_ring_desc": "Piu' Bauli!", "bk:empty_shell": "Cartuccia vuota", "bk:empty_shell_desc": "Possibilita' di distruggerei proiettili nemici", "bk:parachute": "Paracadute", "bk:parachute_desc": "Immune ai dirupi", "bk:spiked_cookie": "Biscotto spinato", "bk:spiked_cookie_desc": "(munch) hei ha le spine (munch)", "bk:shooty": "Shooty", "bk:shooty_desc": "Spara!", "bk:rabbit_bullets": "Proiettili coniglio", "bk:rabbit_bullets_desc": "Si moltiplicano", "bk:pandoras_box": "Vaso di pandora", "bk:pandoras_box_desc": "C'e' il male dentro", "bk:bubbles": "Bolle", "bk:bubbles_desc": "Amici di bolla", "bk:match": "Fiammifero", "bk:match_desc": "Fuoco per tutti", "bk:hammer": "Martello", "bk:hammer_desc": "Rompe l'armatura", "bk:helmet": "Elmo di metallo", "bk:helmet_desc": "Possibilita' di ignorare danni subiti", "bk:beer": "Birra", "bk:beer_desc": "Danno furioso", "bk:the_eye": "L'occhio", "bk:the_eye_desc": "Sta guardando", "bk:mimics_tooth": "Il dente del Mimic", "bk:mimics_tooth_desc": "Attrae Mimics", "ach_bk:mimic": "Lo Spavento", "ach_bk:mimic_desc": "Trova un Mimic", "bk:paper_airplane": "Aereoplanino di carta", "bk:paper_airplane_desc": "Proiettili automatici", "ach_bk:ice_boss": "Let It Go", "ach_bk:ice_boss_desc": "Uccidi la regina di ghiaccio", "ice_queen_scream": "^^[cl cyan]Ahem", "painting_agency": "Benvenuto in agenzia", "language": "Lingua", "inventory": "Inventario", "guitar": "Piu' volume!", "bk:pouch": "Borsa", "bk:alien_glasses": "Occhiali Alieni", "bk:alien_glasses_desc": "Vedo di piu'", "bk:led": "LED", "bk:led_desc": "Lampada", "bk:fragile_lamp": "Lampada Fragile", "bk:fragile_lamp_desc": "1 hit K.O.", "painting_guitar": "Alza il volume!", "ach_bk:maanex": "Et tu, Brut?", "ach_bk:maanex_desc": "Uccidi Maanex mentre indossi la sua maschera", "dad_0": "figliolo![dl] Devo andare a trovare [cl red]la Lampada[cl]. Ti lascio al comando.", "dad_1": "Se non ritorno, non cercarmi. Ciao!", "son_0": "##NOOOOOOO##", "gobbo_0": "figliolo, [cl green]mio padre[cl] miha lasciato 20 anni fa. Devo andare a cercarlo.", "gobbo_1": "Ti lascio al comando. Ciao!", "dm_5": "Un nuovo e ^^migliore^^ [cl red]pupazzo[cl]![dl] ##MUHAHAHA##", "dm_6": "Mi senti, [cl red]Limpor?", "heinur_0": "##NO[dl], NON DI NUOVO!##", "nbk_0": "##SI, PADRONE##", "bk_12": "##HO FINITO I RE, COMBATTI CON ME, SCIOCCO!##", "bk:headshot_gun": "Pistola Storta", "bk:headshot_gun_desc": "Colpo alla testa", "bk:laser_cannon": "Cannone Laser", "bk:laser_cannon_desc": "Haha, laser go pew pew", "credits": "Credits", "head_0": "sciocco", "tech": "Techno", "ach_bk:collector": "Collezionista", "ach_bk:collector_desc": "Sblocca tutti gli oggetti", "bk:treasure_key": "Chiave Rossa", "bk:treasure_key_desc": "Apre Scappatoie", "bk:pass": "Pass", "bk:pass_desc": "Identificati!", "bk:bucket": "Secchio", "bk:bucket_desc": "Inutile senza il suo contenuto", "bk:water_bucket": "Secchio d'acqua", "bk:water_bucket_desc": "Calma [cl red]il Fuoco[cl]", "bk:snow_bucket": "Secchio di neve", "bk:snow_bucket_desc": "Forse, si scioglie", "m2_0": "Non mi riprenderò mai finanziariamente", "m2_1": "Ottimo lavoro!", "m2_2": "Hey, vuoi ^^migliorare^^ le tue %%abilità%%?", "m2_3": "Usa ^^%%il Computer%%^^ per controllare la Chela!", "maanex2_0_0": "Prendi i miei soldi!", "maanex2_0_1": "Non questa volta, grazie.", "maanex2_0": "Okay, dammi[cl yellow][vr cost] monete[cl] e puoi provare la Chela!", "dm_7": "Facciamo una partita", "bkw_0": "UN ALTRO[cl red]INTRUSO[cl]!", "bkw_1": "##FUORI DI QUI##[dl], O USERO' LA FORZA!", "bkw_2": "Sto cercando [cl green]mio padre", "bkw_3": "TI HO _AVVERTITO_", "spanish_inquisition": "[cl red]Inquisizione Spagnola", "lp_0": "Ottimo lavoro, [cl purple]Ritta[cl][dl], riavvio [cl green]la simulazione[cl][dl].[dl].[dl].", "bk:broken_bucket": "Secchio Rotto", "bk:broken_bucket_desc": "Protecc", "bk:ankh": "Ankh", "bk:ankh_desc": "Vita Eterna", "bk:broken_ankh": "Ankh Rotto", "bk:broken_ankh_desc": "Vita Eterna?", "bk:what": "cosa", "bk:what_desc": "sul serio, COSA?", "bk:gold_minigun": "Minigun d'Oro", "bk:gold_minigun_desc": "Haha budget go brrr", "bk:gold_dagger": "Pugnale d'Oro", "bk:gold_dagger_desc": "Old but gold", "bk:gold_revolver": "Revolver d'Oro", "bk:gold_revolver_desc": "Ricoprimi d'Oro", "bk:gold_axe": "Ascia d'Oro", "bk:gold_axe_desc": "solo un ascia d'Oro", "painting_code": "Codice", "bk:katana": "Katana", "bk:katana_desc": "Chi e'[cl orange]il propietario[cl]?", "bk:smart_gun": "Smart Gun", "bk:smart_gun_desc": "Sa'", "bk:pop_gun": "Pop Gun", "bk:pop_gun_desc": "Molto Popolare", "bk:the_button": "Il Bottone", "bk:the_button_desc": "attacca in 8 direzioni", "bk:gold_sword": "Spada d'Oro", "bk:gold_sword_desc": "quando non hai nient'altro da comprare", "bk:donut": "Ciambella", "bk:donut_desc": "Non esitare", "bk:sudoku": "Sudoku", "bk:sudoku_desc": "Mezza stanza 'puff', ridotta in atomi", "bk:gps_ring": "Anello con GPS", "bk:gps_ring_desc": "possibilita' di rivelare la mappa ", "bk:shield_potion": "Pozione Scudo", "bk:shield_potion_desc": "Succo di Scudo", "bk:trash_generator": "Generatore di Spazzatura", "bk:trash_generator_desc": "Si.", "bk:crabs_claw": "La chela del granchio", "bk:crabs_claw_desc": "Rompe qualsiasi armatura", "eg_3": "Buona giornata, signore", "eg_0_0": "Prendi ^^[cl lime]gli smeraldi[cl]^^", "eg_0_1": "Lasciali", "eg_0": "Prendi [cl lime]i miei smeraldi[cl], Ti supplico!", "eg_1": "Esco", "bk:reverse_card": "Carta Inverti", "bk:reverse_card_desc": "Rotolare attraverso i proiettili li riflette", "bk:magnet": "Magnete", "bk:magnet_desc": "Affetto ed Attrazione", "bk:glowing_mushroom": "Funghetti luminosi", "bk:glowing_mushroom_desc": "frequenze positive", "bk:tinfoil_hat": "cappello di carta stagnola", "bk:tinfoil_hat_desc": "Feels safe", "bk:rear_window": "Finestra sul Retro", "bk:rear_window_desc": "Ti guarda le spalle", "bk:refractor": "Rifrattore", "bk:refractor_desc": "Possibilita' di attaccare in tutte le direzioni", "bk:fork": "Forchetta", "bk:fork_desc": "Fa male", "bk:rock": "Pietra", "bk:rock_desc": "Danno ad un prezzo", "bk:coffee_grinder": "Macina Caffe'", "bk:coffee_grinder_desc": "proiettili piccoli e veloci", "integrations": "Integrazioni", "twitch": "Twitch", "streamer_username": "Streamer Username", "bk:shawarma": "Shwarma", "bk:shawarma_desc": "A volte i proiettili sono piu' grandi", "bk:cats_ear": "Orecchio di Gatto", "bk:cats_ear_desc": "schivata assurda", "luck": "fortuna", "bk:gamepad": "Gamepad", "bk:gamepad_desc": "FPS Stabili", "bk:hotdog": "Hotdog", "bk:bomb_shell": "Bomba Scudo", "bk:bomb_shell_desc": "Vita Strana", "painting_no_idea": "Nessun Idea", "painting_tinkerer": "Il Pensatore", "painting_in_loving_memory_of_ali": "In memoria di Ali", "painting_happy_accident": "incidente felice", "painting_observing_cheese": "Formaggio osservatore", "painting_chicken_enemy_unknown": "Gallina nemico sconosciuto", "painting_know_stuff": "Cose che si sanno", "painting_whoops": "Whoops", "painting_too_lake": "troppo lago", "painting_step_through": "Soglia", "painting_thats_a_moon": "E' una luna", "painting_totem": "Cerchio Magico", "painting_too_late": "Troppo Tardi", "painting_whipped_cream": "Panna Montata", "painting_beet_boys": "Beet Bois", "painting_moonshine": "Liquore di luna", "painting_void": "Il Vuoto", "painting_peasants": "Villici" } ================================================ FILE: BurningKnight/Content/Locales/pl.json ================================================ { "bk:halo": "Aureola", "bk:halo_desc": "Zdrowie zwiekszone", "bk:revolver": "Rewolwer", "bk:sword": "Drewniany Miecz", "bk:sword_desc": "Nie jakis tam patyk", "bk:heart": "Serce", "resume": "Wznów", "settings": "Opcje", "restart": "Restart", "death_message": "Umarles", "descend": "Zejdz", "ascend": "Wejdz", "exit": "Wyjdz", "painting_rexcellent": "Wysmienicie", "painting_grannylisa": "Babciolisa", "painting_maanex": "Mysliciel", "painting_bk": "Przypieczony Rycerz", "painting_failpositive": "Imprezotwórca", "painting_old_man": "Naprawde Stary Czlowiek", "painting_arthouse": "Dom Sztuki", "painting_black": "Wszechswiat", "painting_milt": "Chlopiec w sniegu", "painting_skyscraper": "Samotny drapacz chmur", "painting_egor": "Plonacy Rex", "painting_null": "NULL", "painting_badosz": "Samotny Chlopiec w Lesie", "painting_banana": "BANANA", "painting_tv": "TV na niebie", "painting_company": "Dobre Towarzystwo", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Pies da Trasevol", "painting_lamp": "Bierz to", "painting_scream": "Lód", "painting_stars": "Strrraszna noc", "painting_fog": "W Oceanach", "painting_nufflee": "Hau", "by": "Autor:", "old_man_0": "To niebezpieczne!", "continue_run": "Kontynuuj Podejscie", "new_run": "Nowe Podejscie", "was_unlocked": "Zostal odblokowany!", "bk:revolver_desc": "Rece do góry, @everyone!", "bk:shovel": "Niebieska Lopata", "bk:shovel_desc": "Dlaczego jest niebieska???", "beet_0": "Siemka!", "beet_2": "Powiedz mi jego imie!", "npc_hurt_0": "Ojej.", "npc_hurt_1": "To boli.", "npc_hurt_2": "O nie.", "beet_3": "Dzieki <3", "beet_1": "Czy chcialbys zasadzic ^^nasionko^^?", "beet_1_0": "Tak!", "beet_1_1": "Nah.", "beet_4": "Seed to [vr seed]. Czy chcesz to zmienic?", "beet_4_0": "Tak!", "beet_4_1": "Nah.", "beet_5": "Niewazne", "beet_4_2": "Pozwólmy mu byc losowym!", "beet_6": "Ok. Seed to teraz [vr seed]!", "bk:idol": "Idol", "bk:idol_desc": "To pulapka!", "bk:key": "Zloty Klucz", "bk:infinite_bomb": "Nieskonczona Bomba", "bk:infinite_bomb_desc": "Bomba uzytkowa", "throw_coin": "Wrzuc Monete", "bk:potatoo": "Ziemniok", "bk:potatoo_desc": "Dzieli pociski", "bk:spectacles": "Okulary", "bk:spectacles_desc": "Odkrywa sekrety", "bk:cross": "Krzyz", "bk:cross_desc": "Zwieksza czas nietykalnosci po otrzymaniu obrazen", "bk:slime": "Szlam", "bk:slime_desc": "Odbijajace pociski", "bk:missile": "Rakieta", "bk:missile_desc": "Naprawadzajace pociski", "bk:rod_of_discord": "Rózdzka Discorda", "bk:rod_of_discord_desc": "Teleporter dla @everyone", "bk:goo": "Glut", "bk:goo_desc": "Orbitujacy przyjaciel", "bk:jelly": "Galaretka", "bk:jelly_desc": "^^Sprezysta^^", "bk:broken_stone": "Podniszczony Kamien", "bk:broken_stone_desc": "Porzadnie zbudowany orbital", "bk:nano_orb": "Nano Kula", "bk:nano_orb_desc": "Malutki przyjaciel", "bk:saturn": "Planeta", "bk:saturn_desc": "Oczywiscie, nadal ja kochamy", "bk:soap": "Mydlo", "bk:soap_desc": "Spowalnia twoje pociski", "bk:d6": "D6", "bk:d6_desc": "^^Przelosuj^^ przedmioty!", "bk:my_heart": "Moje Serduszko", "bk:my_heart_desc": "Zwieksza zdrowie", "bk:broken_heart": "Zlamane Serce", "bk:broken_heart_desc": "Zwieksza zdrowie", "bk:parcel": "Paczka", "bk:parcel_desc": "Zawiera lekarstwa", "bk:glass": "Szklo", "bk:glass_desc": "##Kruche## pociski", "bk:glass_bullet": "Szklany Pocisk", "bk:glass_bullet_desc": "Strzelaj nad kamieniami", "bk:broken_guitar": "Zepsuta Gitara", "bk:broken_guitar_desc": "Rock and Roll!", "bk:machine_gun": "Karabin", "bk:machine_gun_desc": "Maszynowy", "bk:grenade_launcher": "Granatnik", "bk:grenade_launcher_desc": "Kaboom!", "bk:shotgun": "Strzelba", "bk:shotgun_desc": "Prosto w twarz!", "bk:missile_launcher": "Rakietnica", "bk:missile_launcher_desc": "Cel namierzony!", "bk:burst_gun": "Pistolet maszynowy", "bk:burst_gun_desc": "Predkosc swiatla", "bk:flak_cannon": "Dzialo Odlamkowe", "bk:flak_cannon_desc": "Czas sie zabawic!", "bk:disk_gun": "Pistolet Dyskowy", "bk:disk_gun_desc": "Ostro pogrywasz", "bk:duck_gun": "Kacza Bron", "bk:duck_gun_desc": "Kwakers!", "bk:follower": "Podazacz", "bk:follower_desc": "Za mna!", "bk:portal_gun": "Pistolet Portalowy", "bk:portal_gun_desc": "Ciasto to klamstwo", "bk:snowflake": "Platek Sniegu", "bk:snowflake_desc": "Zimno.", "bk:restock": "Dostawa", "bk:restock_desc": "Nieskonczona dostawa do sklepu", "bk:charisma_ring_desc": "Czarny piatek!", "bk:charisma_ring": "Pierscien Charyzmy", "bk:battery": "Bateria", "tomb_0": "Tutaj spoczywa [cl green]Gobbo[cl] Wielki", "bk:homemade_dice": "Kostka Domowej Roboty", "bk:homemade_dice_desc": "^^Przelosuj^^ przedmioty! (Zrób to sam)", "shopkeeper_0": "##POWIEDZIALEM NIE RÓB TEGO!##", "shopkeeper_1": "Prosze, przestan!", "shopkeeper_2": "Nie rób tego.", "shopkeeper_3": "[cl red]##PRZYGOTUJ SIE NA SMIERC!##", "shopkeeper_4": "[cl red]ZLODZIEJ!", "shopkeeper_5": "[cl red]BRAC GO!", "desert": "Pustynny Palac", "jungle": "Starozytna Dzungla", "ice": "Lodowe Ruiny", "bk:iron_boots": "Metalowe Buty", "bk:iron_boots_desc": "Kolce cie nie skrzywdza. Nigdy wiecej.", "bk:mimic_totem": "Totem Mimików", "bk:mimic_totem_desc": "##NIGDY WIECEJ MIMIKÓW##", "back_to_town": "Wróc do Miasta", "bk:glass_gun": "Szklana Giwera", "bk:glass_gun_desc": "##Krucha##", "bk:glass_shard": "Odlamek Szkla", "bk:glass_shard_desc": "Raczej nic z tego nie ulozysz.", "bk:disk_10": "Plyta nr 10", "bk:disk_10_desc": "Sklepikarz", "bk:disk_1": "Plyta nr 1", "bk:disk_1_desc": "Dom", "bk:disk_2": "Plyta nr 2", "bk:disk_2_desc": "Las", "bk:disk_3": "Plyta nr 3", "bk:disk_3_desc": "Dzungla", "bk:disk_4": "Plyta nr 4", "bk:disk_4_desc": "Lód", "bk:disk_5": "Plyta nr 5", "bk:disk_5_desc": "Loch", "bk:disk_6": "Plyta nr 6", "bk:disk_6_desc": "Pieklo", "bk:disk_7": "Plyta nr 7", "bk:disk_7_desc": "???", "bk:disk_8": "Plyta nr 8", "bk:disk_8_desc": "Otchlan", "bk:disk_9": "Plyta nr 9", "bk:disk_9_desc": "Tnij", "bk:dagger": "Sztylet", "bk:dagger_desc": "Nostalgia...", "bk:spear": "Dzida", "bk:spear_desc": "Dluzsze rece?", "shopkeeper_6": "Witaj :)", "shopkeeper_7": "Siemka, moze [cl yellow]herbatki[cl]?", "shopkeeper_8": "Jak tam?", "back": "Wróc", "master_volume": "Dzwiek", "music": "Muzyka", "sfx": "Efekty Dzwiekowe", "graphics": "Grafika", "audio": "Audio", "ui_sfx": "Efekty Dzwiekowe w UI", "on": "Wlaczone", "off": "Wylaczone", "fullscreen": "Pelny Ekran", "vsync": "V-Sync", "fps": "Licznik FPS", "speedrun_timer": "Timer dla Speedrunerów", "screenshake": "Wstrzasy Ekranu", "freeze_frames": "Freeze Frames", "flash_frames": "Flash Frames", "reset_progress": "Zresetuj Progres", "blood_n_gore": "Krew i Flaki", "vegan_mode": "Tryb dla Weganów", "reset_settings": "Ustawienia Domyslne", "are_you_sure": "Czy jestes pewien?", "yes": "Tak", "reset_progress_dis": "To skasuje CALY twój postep!", "reset_settings_dis": "To ustawi WSZYSTKIE ustawienia na domyslne!", "autosave": "Automatyczny Zapis", "autopause": "Automatyczna Pauza", "input": "Wejscie", "use": "Uzyj", "active": "Aktywne", "bomb": "Bomba", "interact": "Interakcja", "swap": "Zmiana Broni", "roll": "Unik", "duck": "Kaczka", "pause": "Pauza", "none": "Nic", "keyboard_controls": "Klawiatura – Kontrolki", "gamepad_controls": "Pad - Kontrolki", "keyboard": "Klawiatura", "gamepad": "Pad", "game": "Gra", "select": "Wybierz", "cursor": "Kursor", "bk:rip": "RIP", "ach_bk:rip_desc": "Najpopularniejsze Osiagniecie", "ach_bk:overshake": "Przetrzesienie", "ach_bk:overshake_desc": "1000% wstrzasów ekranu", "ach_bk:rip": "Umrzyj", "bk:emerald": "Szmaragd", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Dzieki!^^", "shopkeeper_11": "Co za %%wymiana%%!", "shopkeeper_12": "Chcialbys moze ^^cos^^ [cl red]kupic[cl]?", "shopkeeper_13": "Tylko dla [cl green]ciebie[cl], tylko dzisiaj!", "shopkeeper_14": "Co za [cl yellow]oferta[cl]!", "bk:magnifier": "Lupa", "bk:magnifier_desc": "Duze pociski", "bk:mushroom_hat": "Grzybia Czapka", "bk:mushroom_hat_desc": "Zjadlbys?", "bk:stone_hat": "Kamienna Czapka", "bk:stone_hat_desc": "Ciezka", "bk:knight_hat": "Rycerska Czapka", "bk:knight_hat_desc": "Starzy dobrzy wrogowie...", "bk:cowboy_hat": "Kowbojski Kapelusz", "bk:cowboy_hat_desc": "Dzika Pólnoc..? Moze poludnie?", "bk:soup_hat": "Zupna Czapka", "bk:soup_hat_desc": "^^Mniam^^", "bk:gold_hat": "Zlota Czapka", "bk:gold_hat_desc": "[cl yellow]Bogactwo!", "bk:viking_hat": "Helm Vikingów", "bk:viking_hat_desc": "Ameryka!", "bk:dunce_hat": "Osla Czapka", "bk:dunce_hat_desc": "Osiol!", "bk:top_hat": "Cylinder", "bk:top_hat_desc": "Elegancja i klasa!", "bk:ushanka": "Uszatka", "bk:ushanka_desc": "Gdzie jest moja ##balalajka?##", "bk:valkyrie_hat": "Helm Walkirii", "bk:valkyrie_hat_desc": "Wierze ze ^^moge latac!^^, ale nie tym razem", "bk:skull_hat": "Czaszkoczapa", "bk:skull_hat_desc": "Pieniadze albo zycie!", "bk:grandma_head": "Glowa Babci", "bk:grandma_head_desc": "Herbatki?", "bk:diamond_helmet": "Diamentowy Helm", "bk:diamond_helmet_desc": "Nie kop prosto pod siebie!", "bk:villager_head": "Glowa Wiesniaka", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fez", "bk:fez_desc": "Czerwony", "bk:no_hat": "Usun Czapke", "bk:no_hat_desc": "Nie ma czapki, nie ma problemów!", "bk:null_hat": "NULL", "bk:null_hat_desc": "Attempt to call a null value", "accessorytrader_0": "##WYNOCHA STAD!## [dl]Albo kup te ^^piekniutkie^^ przedmiociki za jedyne ^^%%99 diamentów za sztuke%%^^!", "accessorytrader_1": "Czesc!", "accessorytrader_2": "Siemson!", "weapontrader_0": "Wejdz!", "weapontrader_1": "Dzien dobry, sir!", "weapontrader_2": "Chcialbys cos kupic?", "activetrader_0": "Najlepsze oferty na rynku!", "activetrader_1": "Placisz za 2 dostajesz 2!", "activetrader_2": "Daj mi donuta, [dl]prosze!!", "hattrader_0": "Chcesz byc taki cool jak ja? [dl]Kup sobie czapke!", "hattrader_1": "Chcesz byc taki cool jak ja? [dl]Ja tez, heh", "hattrader_2": "^^Cza cza czapki!^^", "granny_0": "Chcialbys troche herbatki, wnusiu?", "granny_1": "Moze herbaty?", "granny_2": "Herbaty?", "bk:xmas_hat": "Mikolajowa Czapka", "bk:xmas_hat_desc": "Wesolych Swiat!", "bk:pumpkin_hat": "Dynia", "bk:pumpkin_hat_desc": "^^Buuu^^", "bk:cage_key": "Klucz do klatki", "bk:cage_key_desc": "Ocal ^^jakiegos goscia^^!", "npc_0": "Uratuj mnie! Znajdz klucz!", "npc_1": "Dzieki za ratunek!", "npc_2": "Szybciej! Otwórz drzwi!", "npc_3": "Prosze! Pomóz mi!", "control_0": "Wcisnij [ic 0][ic 1] aby postawic bombe", "control_1": "Unikac mozesz ty! Nacisnij [ic 0][ic 1] aby moc zdobyc!", "control_2": "Nacisnij [ic 0][ic 1] aby zaatakowac", "control_3": "Nacisnij [ic 0][ic 1] aby zaczac interakcje", "control_4": "Kwa? [ic 0][ic 1]!", "control_5": "Nacisnij [ic 0][ic 1] aby zmienic bron", "shopkeeper_15": "Nie ma promocji!", "shopkeeper_16": "Zgarnij wiecej kasy i wróc!", "shopkeeper_17": "Najpierw zaplac!", "bk:frog": "Telezabs", "bk:frog_desc": "Szybka Podróz?", "bk:sword_orbital": "Miecz Orbitalny", "bk:sword_orbital_desc": "Sprawiedliwosc", "robbed": "Okradziony", "bk:gift_desc": "Co jest w srodku? Oby nie skarpetki.", "bk:spike_ring": "Pierscien z Kolcami", "bk:spike_ring_desc": "Twoi przeciwnicy musza zostac ##ukarani##!", "bk:fire_ring": "Pierscien Ognia", "bk:fire_ring_desc": "Pozwól twoim wrogom plonac", "bk:ice_ring": "Pierscien Mrozu", "bk:ice_ring_desc": "Ale z ciebie zimny typ", "bk:duck_ring": "Kaczy Pierscien", "bk:duck_ring_desc": "Teleportuj sie po trafieniu", "bk:dull_blade": "Tepe Ostrze", "bk:dull_blade_desc": "Zalacza efekt okaleczenia", "bk:sharp_blade": "Ostre Ostrze", "bk:sharp_blade_desc": "Samookaleczanie", "bk:obsidian_shield": "Obsydianowa Tarcza", "bk:obsidian_shield_desc": "Odrzut = 0", "bk:bill": "Rachunek", "bk:bill_desc": "99 dolarów", "control_6": "Uzyj przedmiotu aktywnego naciskajac [ic 0][ic 1]", "bk:clover": "Czterolistna Koniczyna", "bk:clover_desc": "Szczesciarz!", "bk:d4": "D4", "bk:d4_desc": "^^Przelosuj %%swoje artefakty%%!^^", "brastin_0": "Znajdz obraz [cl purple]kota[cl]!", "elon_0": "Moge zamienic twoja bron w inna", "elon_1": "Prosze! Baw sie dobrze.", "bk:maanex_head": "Glowa Maanexa", "bk:maanex_head_desc": "Hmmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Zmus wrogów do naglych rozmyslan", "mob_0": "Hmmmm", "bk:map_greenprints": "Plany Pietra", "bk:map_greenprints_desc": "Odkrywa mape", "bk:map": "Mapa", "bk:map_desc": "Pernamentnie odkrywa mape", "milt_1": "Chce prezent", "mapuzzle_0": "Grawitacja", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Skopiowane!", "isaac_0": "Zycie nia ma sensu...", "isaac_1": "Dlaczegoooooooo", "isaac_2": ":szloch:", "discord_0": "Powiedz hi! discord.gg\/rexcellent", "old_man_5": "Unikaj, glupcze!", "tutorial": "Poradnik", "bk:the_key": "Klucz", "bk:the_key_desc": "Otwiera wyjscie", "bk:crying_bomb": "Placzaca Bomba", "bk:crying_bomb_desc": "Bomby teraz placza!", "bk:matches": "Zapalki", "bk:matches_desc": "Krótszy czas przed eksplozja", "bk:bomb_pack": "Paczka Bomb", "bk:bomb_pack_desc": "Wlozymy bomby w twoje bomby!", "bk:tnt": "TNT", "bk:tnt_desc": "99 bomb", "bk:weird_mushroom_desc": "Podwaja wszystko", "bk:weird_mushroom": "Dziwny Grzyb", "bk:bomb_shower": "Prysznic z Bomb", "bk:bomb_shower_desc": "Uwazaj podczas uzywania tej zabawki", "bk:black_belt": "Czarny Pas", "bk:black_belt_desc": "Wybuchów nigdy wiecej", "bk:ninjia_bomb": "Ninja Bomba", "bk:ninjia_bomb_desc": "Ból przywoluje bomby", "start_new_run": "Twoje obecne podejscie bedzie stracone!", "bk:laser_pointer": "Celownik Laserowy", "bk:laser_pointer_desc": "Wiem gdzie strzelac!", "ach_bk:marauder": "Rabus", "ach_bk:marauder_desc": "Zabij sklepikarza", "ach_bk:treasure_hunter": "Poszukiwacz skarbów", "ach_bk:treasure_hunter_desc": "Znajdz sekretny pokój", "ach_bk:dodge_master": "Mistrz uników", "ach_bk:dodge_master_desc": "Zabij bossa bez otrzymania obrazen", "ach_bk:dodge_overlord": "Lord Uników", "ach_bk:dodge_overlord_desc": "Ukoncz pietro bez otrzymania obrazen", "ach_bk:quackers": "Kwakers", "ach_bk:quackers_desc": "Overkwak", "ach_bk:tea_party": "Impreza u Babci", "ach_bk:tea_party_desc": "Badz na babcinej herbatkowej imprezie", "ach_bk:not_a_thief": "Nie Zlodziej", "ach_bk:not_a_thief_desc": "Ukoncz podejscie bez podnoszenia przedmiotów", "ach_bk:npc_party2": "Druzyna NPC", "ach_bk:npc_party2_desc": "Ocal wszystkich NPC", "bk:gold_coin": "Zlota Moneta", "bk:iron_coin": "Srebrna Moneta", "bk:copper_coin": "Miedziana Moneta", "bk:platinum_coin": "Platynowa Moneta", "bk:voodoo_doll": "Lalka Voodoo", "bk:voodoo_doll_desc": "Zabija wszystkich przeciwników w pokoju", "hub": "Miasto Unik", "castle": "Ruiny Zamku", "charger_0": "NIE WYKRYTO PRZEDMIOTU AKTYWNEGO", "charger_1": "PRZEDMIOT AKTYWNY JEST JUZ NALADOWANY", "charger_2": "GDZIE SA MOJE PIENIADZE, WORKU MIESA!", "charger_3": "##POWIEDZIALEM DAJ MI MOJE PIENIADZE!##", "charger_4": "##PRZEJME KONTROLE NAD SWIATEM!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Okej, zróbmy to!", "maanex_6_1": "Nah.", "maanex_6": "Dobra, daj mi [cl yellow][vr cost] monet[cl] A ja pozwole ci otworzyc jedna z tych trzech skrzyn. Okej?", "maanex_5": "Hej ty, chcialbys ^^wypróbowac^^ swoje szczescie?", "maanex_7": "To byla niezla frajda!", "maanex_8": "Zycze szczescia!", "maanex_9": "Cóz, nie tym razem :(", "maanex_10": "%%^^WOAH^^%%", "maanex_11": "Ale nie masz wystarczajacej ilosci pieniedzy!", "maanex_12": "##SYN?!##", "bk:amurs_arrow": "Strzala Amora", "bk:amurs_arrow_desc": "Zauraczajace pociski", "bk:amurs_bow": "Luk Amora", "bk:amurs_bow_desc": "Widze milosc", "bk:poison_flask": "Fiolka z Trucizna", "bk:poison_flask_desc": "Zatrute pociski", "bk:snowball": "Sniezka", "bk:snowball_desc": "Lodowe pociski", "bk:peper_desc": "Gorace pociski", "bk:peper": "Papryczka Chili", "bk:sale_coupon": "Kupon na Wyprzedaz", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Zwierzak w Pudelku", "bk:pet_box_desc": "Kto jest w srodku?", "bk:crate": "Skrzynka z Orbitalem", "bk:crate_desc": "Kto jest w srodku?", "bk:strawberry": "Truskawka", "bk:strawberry_desc": "Slodkie wspomnienia", "bk:wings": "Skrzydla", "bk:wings_desc": "Wierze, ze moge latac", "bk:coin_pouch": "Sakiewka z Monetami", "bk:coin_pouch_desc": "Daje monety", "bk:key_pouch": "Sakiewka z Kluczami", "bk:key_pouch_desc": "Daje klucze", "bk:bomb_pouch": "Sakiewka z Bombami", "bk:bomb_pouch_desc": "Daje bomby", "bk:pouch_pouch": "Sakiewka z Sakiewkami", "bk:pouch_pouch_desc": "Daje sakiewki", "bk:lightsaber": "Miecz Swietlówkowy", "bk:lightsaber_desc": "Byles wybrancem!", "bk:snail": "Slimak", "bk:snail_desc": "Slimak, slimak pokaz rogi", "bk:spike": "Kolczasta Kula", "bk:spike_desc": "Obrazenia zwiekszone", "bk:mushroom": "Grzyb", "bk:mushroom_desc": "Szybkosc zwiekszona", "bk:candy": "Cukierek", "bk:candy_desc": "^^Cukier^^, szybkosc strzelania zwiekszona", "bk:glasses": "Bryle", "bk:glasses_desc": "Celnosc zwiekszona", "bk:ruler": "Linijka", "bk:ruler_desc": "Zasieg strzalu zwiekszony", "bk:stopwatch": "Stopczas", "bk:stopwatch_desc": "Obrywanie kontroluje czas", "bk_0": "##NIE WAZ SIE TEGO TKNAC!##", "bk_1": "##POWIEDZIALEM NIE DOTYKAJ!##", "bk_2": "##NIE MOZESZ POKONAC [cl red]PLONACEGO RYCERZA[cl], GLUPCZE!##", "bk_3": "##SZYKUJ SIE NA SMIERC!##", "bk_4": "^^ZABAWNE^^", "shopkeeper_18": "[cl red]^^Goraca wyprzedaz![cl]", "dm_0": "@@Witaj@@", "ach_bk:deal": "Niespodziewany Ruch", "ach_bk:deal_desc": "Dokonaj interesu z Mrocznym Magiem", "ach_bk:grannys_gift": "Prezent od Babci", "ach_bk:grannys_gift_desc": "Wez prezent od Babci", "ach_bk:shopper": "Kupuj Póki Mozesz", "ach_bk:shopper_desc": "Kup przedmiot w sklepie", "bk_5": "NA TWOIM MIEJSCU BYM Z NIM NIE ROZMAWIAL", "bk_6": "##ZABIJ GO, [cl lime]EDWARD[cl]!##", "bk_7": "[cl lime]EDWARD[cl], ##NIEEEEEE!!!!##", "bk_8": "OH PROSZE CIE, PRZESTAN WYSADZAC MÓJ ZAMEK!", "bk_9": "[cl pink]BABCIA[cl],[dl] CZY NIE MOZESZ PO PROSTU UMRZEC##?!?##", "bk_10": "MISTRZU,[dl] PRZYNIOSLEM [cl green]GOBLINA[cl]", "dm_1": "Bardzo dobrze[dl], dziekuje[dl] ci, [cl red]Limpor[cl]", "dm_2": "##Tak, tak, potrzebuje wiecej [cl orange]mocy[cl]!##", "dm_3": "##WIECEJ [cl orange]MOCY[cl]!", "dm_4": "Czuje [cl orange]moc[cl] pulsuje we mnie!", "granny_3": "Ty bedziesz pierwszy, [cl red]Limpor[cl]!", "granny_4": "Witaj, [cl green]Gobbo[cl]!", "granny_5": "Zycze ci szczescia z twoim smutnym zadaniem!", "bk:meat_guy": "Miesogosc", "bk:meat_guy_desc": "Nadal nienawidzi Tofugoscia!", "bk:bullet_stone": "Pociskoglaz", "bk:bullet_stone_desc": "Nadal czuje niechec do mieczy!", "bk:batman": "Batman", "bk:batman_desc": "Nie pomaga, ale daje baterie", "vibration": "Wibracja", "bk:sharp_arrow": "Ostra Strzala", "bk:sharp_arrow_desc": "Pociski przenikaja przez wrogów", "machine_0": "Wrzuc [cl yellow]monete", "player_0": "Tatus?? ##Co oni ci zrobili?!?##", "bk:boomerang": "Bumerang", "bk:boomerang_desc": "Bumerangowe pociski ", "bk:backpack": "Plecak", "bk:backpack_desc": "Mój drogi przyjaciel (ok 10-15 monet)", "place_an_item": "Polóz Przedmiot", "bk:crystal": "Krysztal", "bk:crystal_desc": "Moc teczy", "bk:prism": "Pryzmat", "bk:prism_desc": "Pociski -> Tecza", "scourged": "Przeklety", "bk:bomb": "Bomba", "bk:scourge_of_egg": "Klatwa Jajka", "bk:scourge_of_egg_desc": "Pozamieniane nazwy przedmiotów", "bk:scourge_of_unknown": "Klatwa Niewiadomego", "bk:scourge_of_unknown_desc": "Ukryte Przedmioty", "bk:scourge_of_blood": "Klatwa Krwi", "bk:scourge_of_blood_desc": "Podwójne Klopoty (i przeciwnicy)", "bk:scourge_of_risk": "Klatwa Ryzyka", "bk:scourge_of_risk_desc": "Ukryte Zdrowie", "bk:scourge_of_keys": "Klatwa Kluczy", "bk:scourge_of_keys_desc": "Ukryte Znajdzki", "bk:scourge_of_lost": "Klatwa Zgubienia", "bk:scourge_of_lost_desc": "Amnezja", "bk:scourge_of_scourged": "Klatwa Przekletego", "bk:scourge_of_scourged_desc": "Klatwa Wszedzie", "bk:scourge_of_illness": "Klatwa Choroby", "bk:scourge_of_illness_desc": "Leczenie jest Oslabione", "bk:scourge_of_death": "Klatwa Smierci", "bk:scourge_of_death_desc": "Tryb Trudny", "bk:ancient_revolver": "Antyczny Rewolwer", "bk:ancient_revolver_desc": "Wyglada Fajnie", "bk:assault_rifle": "Karabin Szturmowy", "bk:assault_rifle_desc": "Piu piu", "fountain_0": "Przynies 5 monet a zostaniesz poblogoslawiony", "fountain_1": "Zostales czesciowo oczyszczony", "fountain_2": "Zostales calkowicie oczyszczony", "fountain_3": "Juz jestes czysty", "buffed": "Wzmocniony", "nerfed": "Oslabiony", "restored": "Zregenerowany", "damaged": "Skrzywdzony", "cleansed": "Oczyszczony", "gifted": "Obdarowany", "lucky": "Szczesliwy", "unlucky": "Pechowy", "max_hp": "Max HP", "touch": "Dotknij", "break": "Zniszcz", "no_coins": "Nie ma Monet", "old_man_6": "Niebezpiecznie jest isc samemu, wez to!", "roger_0": "Kabuum!", "roger_1": "##*BUUM*##", "roger_2": "Buum bum szakataka!", "bk:shield": "Tarcza", "bk:gift": "Prezent", "bk:shield_pouch": "Sakiewka z Tarczami", "bk:shield_pouch_desc": "Daje tarcze", "bk:shield_buddy": "Tarczowy Kumpel", "bk:shield_buddy_desc": "Obrywa za Ciebie", "bk:skeleton_key": "Kosciany Klucz", "bk:skeleton_key_desc": "99 kluczy", "bk:jar": "Sloik Zdrowia", "bk:jar_desc": "Jar Jar Klinks", "bk:star": "Gwiazda", "bk:star_desc": "On chronic", "bk:car_bomb": "Chodzaca Bomba", "bk:car_bomb_desc": "Bombowy Serwis Dostawczy", "bk:grenade": "Granat", "bk:grenade_desc": "Bomby wybuchaja przy dotknieciu", "trash_goblin_0": "Uwolnij mnie od mojej [cl purple]klatwy[cl]! Prosze!", "trash_goblin_1": "Jestem wolny! [dl] Dziekuje ci!", "boxy_0": "Czuje sie dzis kluczowo!", "boxy_1": "Jakie fajne pudelko!", "boxy_2": "Potrzebujesz papieru do pakowania?", "trash_goblin_2": "^^Przybiezeli do Betlejem...^^", "bk:vampire_bat": "Nietoperz Wampir", "bk:vampire_bat_desc": "Regen", "shields": "Tarcze", "bk:mustache": "Wasy", "bk:mustache_desc": "VIP", "bk:bloody_chest": "Krwawa Skrzynia", "bk:bloody_chest_desc": "Skrzynie lecza", "bk:bloody_shield": "Krwawa Tarcza", "bk:bloody_shield_desc": "Tarcze na zawsze", "bk:cutsaw": "Pila", "bk:cutsaw_desc": "Wrogowie zaplaca", "vampire_0": "Mniam!", "vampire_1": "Krwawo!", "vampire_2": "Jaka slodka!", "vampire_3": "Znamy zasady, [cl red]^^prawda[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "Jaka masz grupe krwi?", "vampire_6": "Jaka pyszna", "duck_2": "Chcialbys uczestniczyc w ankiecie?", "duck_7_0": "Tak", "duck_7_1": "Nie", "duck_7": "Czy dostaniesz ta skrzynie?", "duck_4": "Dobra robota, bierz swoja nagrode!", "duck_5": "Nie moge sie z toba zgodzic...", "duck_6_0": "Wszechswiat", "duck_6_1": "^^Kwaczki^^", "duck_6": "O czym mysle?", "duck_8_0": "[cl red]Czerwony[cl]", "duck_8_1": "[cl blue]Niebieski[cl]", "duck_8": "Jaki jest mój ulubiony ^^%%kolor%%^^?", "duck_9_0": "Kot", "duck_9_1": "Ty", "duck_9": "Kto powiedzial miau?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "Co lepsze", "duck_11_0": "Co, jajko?", "duck_11_1": "\\[_Dzga go._]", "duck_11": "Jestes fajnym chlopaczkiem", "duck_12_0": "Kurczak", "duck_12_1": "Jajko", "duck_12": "Co bylo pierwsze?", "duck_13_0": "Nic", "duck_13_1": "Przekaske", "duck_13_2": "Jajko", "duck_13_3": "Pieczony kurczak", "duck_13": "Co dzisiaj jadles?", "duck_14": "Aua.", "duck_17_0": "Oczywiscie", "duck_17_1": "##NJEEEEEE##", "duck_17": "Chcialbys ananasa na pizzy?", "duck_18_0": "Bialy!", "duck_18_1": "[cl yellow]Zólty[cl]!", "duck_18": "Jakiego koloru jest ser?", "nurse_0": "Wygladasz bardzo dobrze, slonko!", "nurse_1": "Moglabym cie uleczyc, ale potrzebuje [cl yellow][vr price] coins[cl]", "nurse_2": "Mam nadzieje ze nie bolalo", "elon_4": "Prosze, zabaw sie", "elon_2_0": "Okej", "elon_2_1": "Nah", "elon_2": "Pokazac ci magie?", "elon_3": "Moge zmienic twoja bron w inna", "elon_5": "Niewazne", "elon_7": "Ziom, gdzie twoja bron???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*Rumieni sie*", "gobetta_4": "Czy to... ty?", "gobetta_5": "To bylo tak dawno...", "ach_bk:desert": "Goraco", "ach_bk:desert_desc": "Dojdz do Pustynnego Palacu", "ach_bk:jungle": "Brzeczace Pszczólki", "ach_bk:jungle_desc": "Dojdz do Starozytnej Dzungli", "rooms_explored": "Odkrytych pokoi", "bk:shadow_cloak_desc": "Badz niczym cien", "bk:shadow_cloak": "Plaszcz Cienia", "bk:dynamite_stick": "Dynamit", "bk:dynamite_stick_desc": "Czy ty sie czlowieku chcesz wysadzic?", "bk:chalice_of_blood": "Kielich z Krwia", "bk:chalice_of_blood_desc": "Ból wywoluje gniew, gniew wywoluje obrazenia.", "bk:detonator": "Detonator", "bk:detonator_desc": "Powoduje detonacje materialów wybuchowych", "invincibility_time": "Czas Nietykalnosci", "accuracy": "Celnosc", "range": "Zasieg", "fire_rate": "Predkosc Strzalu", "speed": "Szybkosc", "bk:talisman_of_foresight": "Talizman Dalekowzrocznosci", "bk:talisman_of_foresight_desc": "Otwórz swe oczy i zobacz okoliczne pokoje!", "bk:scourge_ring": "Pierscien Klatwy", "bk:scourge_ring_desc": "Klatw nigdy wiecej", "snek_0": "Niezle.", "snek_1": "Dzieki ziomek", "snek_2": "Sssuper", "snek_3": "Sssiema", "snek_4": "Dzien dobry, ssssir", "snek_5": "Ssssprzedaje ciekawe przedmioty", "snek_6": "Klient musi byc usssatysssfakcjonowany...", "snek_7": "Zrobie, co bede musial!", "bk:snek": "Wunsz", "bk:snek_desc": "Przekassske?", "boxy_3": "^^:wave:^^", "boxy_4": "Masz zapasowy klucz?", "boxy_5": "Moze oddasz nam troche kluczy?", "bk:blank": "Pustak", "bk:blank_desc": "_Pusty Tekst_", "bk:blank_bombs": "Puste Bomby", "bk:blank_bombs_desc": "Tarcza z pocisków", "bk:explosive_bullets": "Wybuchowe Pociski", "bk:explosive_bullets_desc": "Wybuchowe", "bk:random_bullets": "Losowe Pociski", "bk:random_bullets_desc": "RNG", "bk:cup": "Kubek", "bk:cup_desc": "Babcia ma ochote sie pojawic", "bk:cartridge": "Kartridz", "bk:cartridge_desc": "Mroczny Mag ma ochote sie pojawic", "bk:marriage_ring": "Pierscionek Zareczynowy", "bk:marriage_ring_desc": "MM & Babcia na Zawsze!", "boxy_7": "Chce klucze", "boxy_8": "Wydaje mi sie, ze nie masz wystarczajacej ilosci kluczy :(", "boxy_9": "Nareszcie mam wystarczajaco kluczy, aby sie troche ^^otworzyc^^!", "roger_3": "Moze bys zaplacil, dla odmiany?", "roger_4": "Nie ma znizek", "roger_5": "Najpierw bomby", "vampire_7": "Nie jestes wystarczajaco zdrowy", "vampire_8": "U mnie nie ma znizek", "vampire_9": "Gosciu, ja nie chce cie zabic, wiesz?", "ach_bk:scourged": "Przeklety", "ach_bk:scourged_desc": "Podnies Przeklety Amulet", "ach_bk:scourged_weapon": "Przekleta Bron", "ach_bk:scourged_weapon_desc": "Podnies Przekleta Bron", "rerolled": "Przelosowane", "ach_bk:open_up": "Otwieranko", "ach_bk:open_up_desc": "Kup wszystko od Boxiego", "ach_bk:snek": "Wunsz Przyjaciel", "ach_bk:snek_desc": "Uzyj Wunsza jako swojego zwierzaka", "bk:scourge_of_greed": "Klatwa Chciwosci", "bk:scourge_of_greed_desc": "Wysokie ceny", "killed_by": "Zabity przez", "kills": "Zabójstwa", "time": "Czas", "depth": "Pietro", "bk:blank_bullets": "Puste Naboje", "bk:blank_bullets_desc": "Nazwa stwierdza ze sa puste", "bk:lego": "Konstruktor", "bk:lego_desc": "Zaczynasz wspólczuc swoim wrogom...", "bk:iron_armor": "Zelazna Zbroja", "bk:iron_armor_desc": "Daje tarcze", "bk:round_shield": "Okragla Tarcza", "bk:round_shield_desc": "Chroni przed obrazeniami kontaktowymi", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "Legenda we wlasnej osobie", "bk:inverted_arkhalis": "Odwrócona Arkhalis", "bk:inverted_arkhalis_desc": "Pomaga kiedy slabo u ciebie z zyciem", "bk:gun_sword": "Giweromiecz", "bk:gun_sword_desc": "Miecz czy giwera?", "ach_bk:scourge_king_desc": "Zdobadz 10 punktów klatwy", "ach_bk:scourge_king": "Przeklety Król", "ach_bk:sting_operation": "Operacja Zadlo", "ach_bk:sting_operation_desc": "Pokonaj Królowa Pszczól", "ach_bk:mummified": "Zmumifikowany", "ach_bk:mummified_desc": "Pokonaj Faroka", "ach_bk:democracy": "DEMOKRACJA", "ach_bk:democracy_desc": "Pokonaj Starego Króla", "pharaoh_scream": "##PRZYGOTUJ SIE NA MUMIFIKACJE!##", "queen_bee_scream": "##ZA LORDA [cl yellow]MIODU[cl]!##", "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?", "duck_20": "Kwaks! ", "bk:half_heart": "Pól Serca", "right": "Prawo", "down": "Dól", "left": "Lewo", "up": "Góra", "painting_cat": "Obraz Kota", "bk:axe": "Siekiera", "bk:axe_desc": "Obiecal ze wróci", "bk:guitar": "Gitara", "bk:guitar_desc": "Rozstrojona", "bk:glass_sword": "Szklany Miecz", "bk:glass_sword_desc": "Bron mistrzów", "bk:chicken": "Skrzydelko z Kurczaka", "bk:chicken_desc": "Gorace", "bk:pickaxe": "Kilof", "bk:pickaxe_desc": "Kop, plebsie!", "bk:mana": "Mana", "bk:half_mana": "Pól Many", "bk:lava_wand": "Lawowa Rózdzka", "bk:lava_wand_desc": "Goraco sie liczy", "bk:web_wand": "Pajecza Rózdzka", "bk:web_wand_desc": "Dostarcza siec na calym swiecie", "bk:slap_stick": "Patyk do Policzkowania", "bk:slap_stick_desc": "Klep", "sensivity": "Wrazliwosc", "no": "Nie", "scale": "Skala", "ach_bk:ice": "Epoka Lodowcowa", "ach_bk:ice_desc": "Dotrzyj do Lodowych Ruin", "ach_bk:library": "Swiete Teksty", "ach_bk:library_desc": "Dotrzyj do Sekretnej Biblioteki", "bk:ice_skates": "Lyzwy", "bk:ice_skates_desc": "Odpornosc na lód", "bk:campfire_in_bottle": "Ognisko w Butelce", "bk:campfire_in_bottle_desc": "Odpornosc na Zimno", "library": "Sekretna Biblioteka", "ach_bk:cat_without_a_hat": "Kot nie na plot", "ach_bk:cat_without_a_hat_desc": "Znajdz obraz kota", "ach_bk:rich": "Papier Toaletowy", "ach_bk:rich_desc": "+99 monet", "ach_bk:rescue_operation": "Operacja Ratunkowa", "ach_bk:rescue_operation_desc": "Uratuj NPC", "ach_bk:tutorial": "Guru", "ach_bk:tutorial_desc": "Ukoncz poradnik", "ach_bk:fancy_hat": "Niezla Czapka", "ach_bk:fancy_hat_desc": "Kup czapke", "ach_bk:unlock": "Odblokowywacz", "ach_bk:unlock_desc": "Odblokuj przedmiot", "floor_brightness": "Jasnosc Podlogi", "ach_bk:shielded": "Obrona", "ach_bk:shielded_desc": "Zdobadz tarcze", "run_type": "Typ podejscia", "run_regular": "Zwykly", "run_challenge": "Wyzwanie", "damage_taken": "Otrzymanych obrazen", "km": "km", "distance_traveled": "Przebyty dystans", "seed": "Seed", "score": "Wynik", "new_high_score": "Nowy rekord!", "items_collected": "Zdobyte przedmioty", "boss_rush": "Wyzwanie Bossów", "run_bossrush": "Wyzwanie Bossów", "bk:blindfold_desc": "RIP moje bronie", "bk:blindfold": "Na oslep", "daily_run": "Dzienne Podejscie", "builder_0_0": "Ta", "builder_0_1": "Potrzebuje tych pieniedzy", "builder_0": "Planuje wybudowac tu skrót, ale potrzebuje jeszcze [vr need] [ic 0] wiecej monet. Pomozesz mi?", "builder_1": "Ale nie masz zadnych pieniedzy! :(", "builder_2": "Dziekuje za panska inwestycje!", "builder_3": "Nareszcie mam wystarczajaco kasy na ten projekt! Bardzo dziekuje!", "builder_4": "Okej, przepraszam!", "shortcut_is_broken": "Skrót jest zepsuty", "ach_bk:boss_rush": "Pogromca Bossów", "ach_bk:boss_rush_desc": "Pokonaj wszystkich Bossów w Wyzwaniu Bossów", "ach_bk:daily": "Dzienna Chwala", "ach_bk:daily_desc": "Wygraj Dzienne Podejscie", "ach_bk:desert_shortcut": "Skrót do Pustynnego Palacu", "ach_bk:desert_shortcut_desc": "Napraw skrót do Pustynnego Palacu", "ach_bk:jungle_shortcut": "Skrót do Starozytnej Dzungli", "ach_bk:jungle_shortcut_desc": "Napraw skrót do Starozytnej Dzungli", "ach_bk:ice_shortcut": "Skrót do Lodowych Ruin", "ach_bk:ice_shortcut_desc": "Napraw skrót do Lodowych Ruin", "ach_bk:library_shortcut": "Skrót do Sekretnej Biblioteki", "ach_bk:library_shortcut_desc": "Napraw skrót do Sekretnej Biblioteki", "ach_bk:fashion_matters2": "Moda", "ach_bk:fashion_matters2_desc": "Wykup czapki", "ach_bk:10_challenges": "Twardziel", "ach_bk:10_challenges_desc": "Wygraj 10 wyzwan", "ach_bk:20_challenges": "Twardziel 2.0", "ach_bk:20_challenges_desc": "Wygraj 20 wyzwan", "ach_bk:30_challenges": "Twardziel 3.0", "ach_bk:30_challenges_desc": "Wygraj 30 wyzwan", "ach_bk:bk_no_more": "PR nigdy wiecej", "ach_bk:bk_no_more_desc": "Pokonaj Plonacego Rycerza", "ach_bk:dm_no_more": "MM nigdy wiecej", "ach_bk:dm_no_more_desc": "Pokonaj Mrocznego Maga", "ach_bk:egor_no_more": "Egora nigdy wiecej", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Eh, no to jeszcze raz", "ach_bk:loop_desc": "Wejdz do petli", "coins_collected": "Zebranych monet", "bk:cup_head": "Filizanka", "bk:cup_head_desc": "Juz piata!", "bk:mustache_hat": "Wasy", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Czapka z Wiatraczkiem", "bk:propeller_hat_desc": "Kreci sie!", "bk:sunglasses": "Okulary Przeciwsloneczne", "bk:sunglasses_desc": "Na swiatlo ksiezycowe tez dzialaja!", "bk:cap": "Czapka", "bk:cap_desc": "Fajno @-@", "bk:eyes": "Oczy", "bk:eyes_desc": "@ @", "bk:eye": "Oko", "bk:eye_desc": "@", "bk:hair": "Wlosy", "bk:hair_desc": "Tylko dla bogatych", "won": "Wygrana", "won_message": "Wygrales!", "you_won_demo": "To koniec demo :)", "garderobe_sign": "Przebieralnia", "darkmarket_tip": "~~[cl purple]Klatwa[cl] lub [cl yellow]30 monet[cl]@@", "mike_0": "Zaplac mi [cl green]3 szmaragdy", "mike_1": "Wypróbuj Wyzwanie Bossów za jedyne [cl green]3 szmaragdy[cl]!", "bk:weird_potion": "Dziwna Mikstura", "bk:weird_potion_desc": "Dziwne Pociski", "bk:megaphone": "Megafon", "bk:megaphone_desc": "Rozszerzajace sie pociski", "scourge": "Klatwa", "scourge_stats": "Klatwa", "run_daily": "Dzienny", "full_version": "Drzwi beda otwarte w pelnej wersji!", "completed_on": "Zaliczony w", "complete": "Zaliczony", "wishlist_pls": "Podoba ci sie demo, dodaj nas do listy zyczen na Steam! [cl red]burningknight.net\/steam", "next_daily_in": "[cl gray]Nastepny zaczyna sie w[cl]", "hours": "godzin", "minutes": "minut", "seconds": "sekund", "ach_bk:star": "Gwiazda Show", "ach_bk:star_desc": "Zdobadz 3 orbitale", "ach_bk:family": "Szczesliwa Mala Rodzinka", "ach_bk:family_desc": "Zdobadz 3 zwierzatka", "ach_bk:return_to_sender": "Nje bo ty", "ach_bk:return_to_sender_desc": "Zabij przeciwnika jego wlasnym strzalem", "ach_bk:van_no_gogh": "Van Nie Gogh", "ach_bk:van_no_gogh_desc": "Zniszcz 100 obrazów", "ach_bk:boom": "Reakcja Lancuchowa", "ach_bk:boom_desc": "Rozsadz Lancuch 3 TNT", "ach_bk:dark_market": "Kryjówka Zbrodni", "ach_bk:dark_market_desc": "Wejdz do Czarnego Marketu", "ach_bk:spikes": "Ostro!", "ach_bk:spikes_desc": "Aktywuj 100 kolców podczas jednego podejscia", "ach_bk:white_flag": "Nie zawiera glutenu i broni", "ach_bk:white_flag_desc": "Pokonaj pokój bez uzywania broni", "quack": "[cl yellow]Kwa![cl]", "pixel_perfect": "Pixel Perfect", "bk_11": "TYM RAZEM CI WYBACZAM... ALE ##NIE## RÓB TEGO WIECEJ!", "leaderboard": "Tabela Wyników", "display": "Pokaz", "around_you": "Wokól Ciebie", "friends": "Przyjaciele", "global": "Globalnie", "loading": "Ladowanie", "generating": "Generowanie", "cursor_radius": "Odleglosc Kursora", "no_scores_yet": "Jeszcze nie ma wyników", "no_score_yet": "Jeszcze nie ma wyniku", "run": "Podejscie", "top": "Top", "quick_restart": "Szybki Restart", "painting_dungeon": "Loch", "painting_goose": "Mala Gaska", "painting_chess": "Latajacy Slon", "painting_peach": "Drzewo Brzoskwiniowe", "bk:no_lamp": "Bez Lampy", "bk:explosive_lamp": "Wybuchowa Lampa", "bk:explosive_lamp_desc": "Kiedy bum znaczy wiecej", "bk:shielded_lamp": "Tarczowa Lampa", "bk:shielded_lamp_desc": "Tarcze w góre!", "lamp": "Lampa", "bk:brain": "Mega Mózg", "bk:brain_desc": "Wielkosc Umyslu: Mega", "bk:heart_amulet": "Sercowy Amulet", "bk:heart_amulet_desc": "+1 do Wielkosci Serc", "bk:star_amulet_desc": "Zwiekszenie many", "bk:star_amulet": "Gwiezdny Amulet", "bk:coin_amulet": "Pieniezny Amulet", "bk:coin_amulet_desc": "Monety sa warte wiecej", "bk:key_amulet": "Kluczowy Amulet", "bk:key_amulet_desc": "Kluczowy przedmiot, klucze warte wiecej", "bk:bomb_amulet": "Bombowy Amulet", "bk:bomb_amulet_desc": "Bombowa rzecz, bomby warte wiecej", "bk:eye_amulet": "Oczny Amulet", "bk:eye_amulet_desc": "To boli, gdy nie mozesz trafic", "bk:eye_patch": "Opaska na Oko", "bk:eye_patch_desc": "Jestescie gotowi?", "bk:toilet_paper": "Papier Toaletowy", "bk:toilet_paper_desc": "Zawsze sie konczy", "bk:decoy": "Wabik", "bk:decoy_desc": "Wybucha", "bk:wallet": "Portfelowy Kumpel", "bk:wallet_desc": "Trzyma twoje Monety", "bk:skele_buddy": "Szkiele Kumpel", "bk:skele_buddy_desc": "Straszny", "bk:mega_bomb": "Mega Bomba", "bk:mega_bomb_desc": "Wielkosc Bomby: Mega", "bk:condensed_milk": "Skondensowane Mleko", "bk:condensed_milk_desc": "Szybkie pixele - Wolni przeciwnicy", "bk:marshmallow": "Pianka", "bk:marshmallow_desc": "Klei sie", "bk:orbital_multiplier": "Podwajacz Orbitali", "bk:orbital_multiplier_desc": "Wiecej oritali!", "bk:pet_multiplier": "Podwajacz zwierzaków", "bk:pet_multiplier_desc": "Wiecej zwierzaków!", "bk:ghost_bullets": "Duchowe Pociski", "bk:ghost_bullets_desc": "Mur ich nie powstrzyma", "bk:weight": "Ciezki Odwaznik", "bk:weight_desc": "Grawitacja+", "bk:d2": "D2", "bk:d2_desc": "Bierz albo zostaw", "bk:ethernal_d6": "Wieczne D6", "bk:ethernal_d6_desc": "Przerzuca i/lub Niszczy", "bk:billiard": "Kula Biliardowa", "bk:billiard_desc": "Odbijajace pociski", "bk:enraged_bullets": "Zdenerwowane Pociski", "bk:enraged_bullets_desc": "Pociski niszcza Pociski", "bk:rewind_button": "Przycisk Przewijania", "bk:rewind_button_desc": "No chyba nie", "bk:piggy_bank": "Swinka Skarbonka", "bk:piggy_bank_desc": "Oszczednosci Zyciowe", "coins": "Monety", "bk:death_star": "Gwiazda Smierci", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Lutowane Zelazo", "bk:soldering_iron_desc": "Gorace", "bk:can": "Puszka", "bk:can_desc": "Podwójne pociski", "bk:swimming_mask": "Maska do Plywania", "bk:swimming_mask_desc": "To sekretna bron", "bk:bullet_chair": "Pociskrzeslo", "bk:bullet_chair_desc": "4 nogi 4 giwery", "bk:cell": "Komórka", "bk:cell_desc": "Pociski sie mnoza", "bk:brick": "iBrick", "bk:brick_desc": "Wieksze pietra", "bk:ring_of_pain": "Pierscien Bólu", "bk:ring_of_pain_desc": "Oberwanie bije wszystkich", "bk:schrodingers_cat": "Kot Schrödingera", "bk:schrodingers_cat_desc": "Byc albo nie byc (50% szans)", "bk:smoke_bomb": "Bomba Dymna", "bk:smoke_bomb_desc": "Poczuj sie jak Ninja", "bk:chest_ring": "Skrzyniowy Pierscien", "bk:chest_ring_desc": "Wiecej Skrzyn!", "bk:empty_shell": "Pusta Luska", "bk:empty_shell_desc": "Szansa na zniszczenie pocisków przeciwników", "bk:parachute": "Spadochron", "bk:parachute_desc": "Odpornosc na Dziury", "bk:spiked_cookie": "Kolczaste Ciasteczko", "bk:spiked_cookie_desc": "Kolczasty Slodziak", "bk:shooty": "Strzelik", "bk:shooty_desc": "On byc strzelac", "bk:rabbit_bullets": "Królicze Pociski", "bk:rabbit_bullets_desc": "Mnoza sie", "bk:pandoras_box": "Puszka Pandory", "bk:pandoras_box_desc": "Trzyma zlo", "bk:bubbles": "Baniek", "bk:bubbles_desc": "Przyjaciel Banka", "bk:match": "Zapalki", "bk:match_desc": "Ogien dla wszystkich", "bk:hammer": "Mlotek", "bk:hammer_desc": "Niszczyciel Zbroi", "bk:helmet": "Zelazny Helm", "bk:helmet_desc": "Szansa na zignorowanie obrazen", "bk:beer": "Piwo", "bk:beer_desc": "Zwieksza obrazenia po otrzymaniu obrazen", "bk:the_eye": "Oko", "bk:the_eye_desc": "On byc widziec", "bk:mimics_tooth": "Zab Mimika", "bk:mimics_tooth_desc": "Przyciaga Mimiki", "ach_bk:mimic": "Jump Scare", "ach_bk:mimic_desc": "Znajdz Mimika", "bk:paper_airplane": "Papierowy Samolocik", "bk:paper_airplane_desc": "Samonaprawadzajace pociski", "ach_bk:ice_boss": "Mam te Moc", "ach_bk:ice_boss_desc": "Zabij Królowa Lodu", "ice_queen_scream": "^^[cl cyan]Ahem", "painting_agency": "Witamy w Agencji", "inventory": "Ekwipunek", "language": "Jezyk", "bk:pouch": "Sakiewka", "bk:alien_glasses": "Kosmiczne Okulary", "bk:alien_glasses_desc": "Widze wiecej", "bk:led": "LED", "bk:led_desc": "Celna Lampa", "bk:fragile_lamp": "Kruchliwa Lampa", "bk:fragile_lamp_desc": "1 hit K.O.", "guitar": "Glosniej!", "painting_guitar": "Glosniej!", "ach_bk:maanex": "Et tu, Brut?", "ach_bk:maanex_desc": "Zabij Maanexa noszac jego glowe", "dad_0": "Hej synek![dl] Musze odejsc i znalezc [cl red]Lampe[cl]. Zostawiam cie jako wladce.", "dad_1": "Jesli nie wroce, nie szukaj mnie. Pa!", "son_0": "##NIEEEEEE##", "gobbo_0": "Synu, [cl green]moj ojciec[cl] zostawil mnie 20 lat temu. Musze go odnalezc.", "gobbo_1": "Zostajesz nowym wladca. Pa!", "dm_5": "Nowy i ^^lepszy^^ [cl red]slugus[cl]![dl] ##MUHAHAHA##", "dm_6": "Slyszysz mnie, [cl red]Limpor?", "heinur_0": "##NIE[dl], NIE ZNOWU!##", "nbk_0": "##TAK, MISTRZU##", "bk_12": "##JESTEM KROLEM KROLOW, WIEC WALCZ ZE MNA, GLUPCZE!##", "bk:headshot_gun": "Wygiety Pistolet", "bk:headshot_gun_desc": "Headshot", "bk:laser_cannon": "Dzialo Laserowe", "bk:laser_cannon_desc": "Haha, laser robi piu piu", "credits": "Napisy", "head_0": "Glupiec", "tech": "Techno", "ach_bk:collector": "Kolekcjoner", "ach_bk:collector_desc": "Odblokuj wszystkie przedmioty", "bk:treasure_key": "Czerwony Klucz", "bk:treasure_key_desc": "Otwiera dziury w petli", "bk:pass": "Przepustka", "bk:pass_desc": "Ciekawe skad on mial twoje ID?", "bk:bucket": "Wiadro", "bk:bucket_desc": "Bezuzyteczne... bez zawartosci", "bk:water_bucket": "Wiadro z Woda", "bk:water_bucket_desc": "Uspokaja [cl red]Ogien[cl]", "bk:snow_bucket": "Wiadro ze Sniegiem", "bk:snow_bucket_desc": "Prawdopodobnie sie rozpusci", "m2_0": "Nigdy sie z tego finansowo nie wygrzebie", "m2_1": "Dobra robota!", "m2_2": "Hej ty, chcialbys ^^wyprobowac^^ twoje %%umiejetnosci%%?", "m2_3": "Uzyj ^^%%Komputera%%^^, aby kontrolowac lape!", "maanex2_0_0": "Bierz moje pieniadze!", "maanex2_0_1": "Nie tym razem, tnx.", "maanex2_0": "Okej, daj mi [cl yellow][vr cost] monet[cl] i mozesz wyprobowac lape szczescia!", "dm_7": "Zagrajmy w gre", "bkw_0": "KOLEJNY [cl red]INTRUZ[cl]!", "bkw_1": "##WYNOS SIE STAD##[dl], ALBO UZYJE SILY!", "bkw_2": "Szukam [cl green]mojego ojca", "bkw_3": "DALEM CI _OSTRZEZENIE_", "spanish_inquisition": "[cl red]Hiszpanska Inkwizycja", "lp_0": "Dobra robota, [cl purple]Ritta[cl][dl], restartujemy [cl green]symulacje[cl][dl].[dl].[dl].", "bk:broken_bucket": "Dziurawe Wiadro", "bk:broken_bucket_desc": "Szkoda ze Dziurawe...", "bk:ankh": "Ankh", "bk:ankh_desc": "Zycie Wieczne", "bk:broken_ankh": "Podniszczony Ankh", "bk:broken_ankh_desc": "Zycie Wieczne?", "bk:what": "co", "bk:what_desc": "Serio, CO?", "bk:gold_minigun": "Zloty Minigun", "bk:gold_minigun_desc": "Powiedz mi, czy slowo budzet naprawde istnieje?", "bk:gold_dagger": "Zloty Sztylet", "bk:gold_dagger_desc": "Stary ale zloty", "bk:gold_revolver": "Zloty Rewolwer", "bk:gold_revolver_desc": "Obsyp mnie zlotem", "bk:gold_axe": "Zlota Siekiera", "bk:gold_axe_desc": "Po prostu siekiera", "painting_code": "Kod", "bk:katana": "Katana", "bk:katana_desc": "Kto tu jest [cl orange]wlascicielem[cl]?", "bk:smart_gun": "Inteligenta Bron", "bk:smart_gun_desc": "On wie", "bk:pop_gun": "Pop Gun", "bk:pop_gun_desc": "Zadziwiajaco popularny", "bk:the_button": "Przycisk", "bk:the_button_desc": "Prosze, nie dotykaj niczego", "bk:gold_sword": "Zloty Miecz", "bk:gold_sword_desc": "Zloto jest zlote", "bk:donut": "Donut", "bk:donut_desc": "Nie wachaj sie", "bk:sudoku": "Sudoku", "bk:sudoku_desc": "Nie ma polowy pokoju, zredukowana do atomow", "bk:gps_ring": "Ring GPS", "bk:gps_ring_desc": "Szansa na odkrycie mapy", "bk:shield_potion": "Mikstura Obrony", "bk:shield_potion_desc": "Duzy lyk soku z tarczy", "bk:trash_generator": "Generator Smieci", "bk:trash_generator_desc": "Tak.", "bk:crabs_claw": "Krabie Kleszcze", "bk:crabs_claw_desc": "Niszczy kazda zbroje", "eg_3": "Dzien dobry, sir", "eg_0_0": "Wez ^^[cl lime]szmaragdy[cl]^^", "eg_0_1": "Zostaw je", "eg_0": "Zabierz [cl lime]moje szmaragdy[cl], blagam!", "eg_1": "Spadam z tad", "bk:reverse_card": "Karta Odwrotu", "bk:reverse_card_desc": "Rolowanie sie przez pociski odbija je", "bk:magnet": "Magnes", "bk:magnet_desc": "Przyciaganie i Dzialanie", "bk:glowing_mushroom": "Swiecacy Grzyb", "bk:glowing_mushroom_desc": "On byc wibru wibru", "bk:tinfoil_hat": "Czapka Foliowa", "bk:tinfoil_hat_desc": "Nareszcie... jestem bezpieczny", "bk:rear_window": "Lusterko", "bk:rear_window_desc": "Zabezpiecza tyly", "bk:refractor": "Refraktor", "bk:refractor_desc": "Szansa na atak we wszystkie strony", "bk:fork": "Widelec", "bk:fork_desc": "To boli", "bk:rock": "Kamien", "bk:rock_desc": "Obrazenia kazdym kosztem", "bk:coffee_grinder": "Maszyna do Kawy", "bk:coffee_grinder_desc": "Male i szybkie pociski", "integrations": "Integracje", "twitch": "Twitch", "streamer_username": "Nick Streamera", "bk:shawarma": "Shwarma", "bk:shawarma_desc": "Czasami pociski sa wieksze", "bk:cats_ear": "Ucho Kota", "bk:cats_ear_desc": "Slaby unik", "luck": "Szczescie", "bk:gamepad": "Pad", "bk:gamepad_desc": "Stabilne FPS", "bk:hotdog": "Hotdog", "bk:bomb_shell": "Skorupa Bomby", "bk:bomb_shell_desc": "Dziwne Zdrowie", "painting_no_idea": "Nie mam pojecia", "painting_tinkerer": "Majsterkowicz", "painting_in_loving_memory_of_ali": "We wspomnieniu Ali", "painting_happy_accident": "Szczesliwy Przypadek", "painting_observing_cheese": "Obserwacja Sera", "painting_chicken_enemy_unknown": "Kurczak Wrog Nieznany", "painting_know_stuff": "Wiem Rzeczy", "painting_whoops": "Whoops", "painting_too_lake": "Jezioro", "painting_step_through": "Prog", "painting_thats_a_moon": "To Ksiezyc", "painting_totem": "Magiczny Krag", "painting_too_late": "Za Pozno", "painting_whipped_cream": "Bita Smietana", "painting_beet_boys": "Buraki Polaki", "painting_moonshine": "Swiatlo", "painting_void": "Pustka", "painting_peasants": "Plebs", "bk:gold_lamp": "Zlota Lampa", "bk:gold_lamp_desc": "Kasa kasa kasa", "bk:sharp_lamp": "Ostra Lampa", "bk:sharp_lamp_desc": "Ostro", "bk:ancient_sword": "Antyczny Miecz", "bk:ancient_sword_desc": "Bardzo stary patyk", "ach_bk:unstoppable": "Niepowstrzymany", "ach_bk:unstoppable_desc": "Przejdz gre z dowolna Lampa", "no_emeralds": "Brak Szmaragdow", "bk:emerald_gun": "Szmaragdowa Giwera", "bk:emerald_gun_desc": "Najdrozsza bron na rynku" } ================================================ FILE: BurningKnight/Content/Locales/pt.json ================================================ { "bk:halo": "Auréola", "bk:halo_desc": "Aumenta a vida", "bk:revolver": "Revólver", "bk:sword": "Espada de Madeira", "bk:sword_desc": "É mais do que um simples pedaço de pau", "bk:heart": "Coração", "resume": "Continuar", "settings": "Opções", "restart": "Reiniciar", "death_message": "Você morreu", "descend": "Descer", "ascend": "Subir", "exit": "Sair", "painting_rexcellent": "Excelente", "painting_grannylisa": "Grannylisa", "painting_maanex": "PENSADOR", "painting_bk": "Cavaleiro Torrado", "painting_failpositive": "Festeiro", "painting_old_man": "Cara muito velho", "painting_arthouse": "Casa da Arte", "painting_black": "Universo", "painting_milt": "Garoto na neve", "painting_skyscraper": "Arranha-céu solitário", "painting_egor": "Burning Rex", "painting_null": "NULO", "painting_badosz": "Garoto perdido na floresta", "painting_banana": "BANANA", "painting_tv": "TV nos céus", "painting_company": "Bem acompanhado", "painting_pico": "PICO-8", "painting_liko": "LIKO-12", "painting_trasevol": "Dog du Trasevol", "painting_lamp": "Pegue", "painting_scream": "Sorvete", "painting_stars": "Noite assustadora", "painting_fog": "Sete mares", "painting_nufflee": "Latido", "by": "por", "old_man_0": "É perigoso!", "continue_run": "Continuar partida", "new_run": "Nova partida", "was_unlocked": "Foi desbloqueado!", "bk:revolver_desc": "Mãos pra cima, @todos!", "bk:shovel": "Pá Azul", "bk:shovel_desc": "Mas por quê é azul???", "beet_0": "Oi!", "beet_2": "Me diga o nome!", "npc_hurt_0": "Ai.", "npc_hurt_1": "Isso dói.", "npc_hurt_2": "Ah não.", "beet_3": "Valeu <3", "beet_1": "Quer plantar uma ^^semente^^?", "beet_1_0": "Sim!", "beet_1_1": "Nah.", "beet_4": "A semente é [vr seed]. Quer mudar?", "beet_4_0": "Sim!", "beet_4_1": "Nah.", "beet_5": "Tanto faz.", "beet_4_2": "Quero que seja aleatória!", "beet_6": "Ok. A semente agora é [vr seed]!", "bk:idol": "Ídolo", "bk:idol_desc": "Uma armadilha escondida foi ativada!", "bk:key": "Chave Dourada", "bk:infinite_bomb": "Bomba Infinita", "bk:infinite_bomb_desc": "Bomba reutilizável", "throw_coin": "Jogue uma moeda", "bk:potatoo": "Batataaa", "bk:potatoo_desc": "Divide projéteis", "bk:spectacles": "Óculos", "bk:spectacles_desc": "Revela segredos", "bk:cross": "Cruz", "bk:cross_desc": "Aumenta o tempo de invencibilidade", "bk:slime": "Meleca", "bk:slime_desc": "Tiros ricocheteiam", "bk:missile": "Míssil", "bk:missile_desc": "Tiros teleguiados", "bk:rod_of_discord": "Bastão da Discórdia", "bk:rod_of_discord_desc": "Teleporte para @todos", "bk:goo": "Goo", "bk:goo_desc": "Amigo orbital", "bk:jelly": "Geléia!", "bk:jelly_desc": "^^Saltitante^^", "bk:broken_stone": "Pedra Quebrada", "bk:broken_stone_desc": "Orbital bem construído", "bk:nano_orb": "Nano Orbe", "bk:nano_orb_desc": "Micro-amigo", "bk:saturn": "Planeta", "bk:saturn_desc": "Mas é claro que ainda ainda o amamos", "bk:soap": "Sabonete", "bk:soap_desc": "Desacelera seus projéteis", "bk:d6": "D6", "bk:d6_desc": "^^Rola novamente^^ os itens!", "bk:my_heart": "Meu Coração", "bk:my_heart_desc": "Aumenta a vida", "bk:broken_heart": "Coração Partido", "bk:broken_heart_desc": "Aumenta a vida", "bk:parcel": "Pacote", "bk:parcel_desc": "Cura reutilizável", "bk:glass": "Vidro", "bk:glass_desc": "Projéteis ##frágeis##", "bk:glass_bullet": "Bala de Vidro", "bk:glass_bullet_desc": "Atire sobre pedras", "bk:broken_guitar": "Guitarra Quebrada", "bk:broken_guitar_desc": "Roll'n'rock!", "bk:machine_gun": "Metralhadora", "bk:machine_gun_desc": "Automática", "bk:grenade_launcher": "Lança-granada", "bk:grenade_launcher_desc": "Buuumm!", "bk:shotgun": "Escopeta", "bk:shotgun_desc": "Sal na cara!", "bk:missile_launcher": "Lança-mísseis", "bk:missile_launcher_desc": "Alvo confirmado!", "bk:burst_gun": "Arma de Rajada", "bk:burst_gun_desc": "Velocidade da luz", "bk:flak_cannon": "Canhão Espalhado", "bk:flak_cannon_desc": "É hora da festa!", "bk:disk_gun": "Arma de Discos", "bk:disk_gun_desc": "Cortante", "bk:duck_gun": "Arma Patológica", "bk:duck_gun_desc": "Quakers!", "bk:follower": "Seguidor", "bk:follower_desc": "Siga-me os bons!", "bk:portal_gun": "Arma de Portal", "bk:portal_gun_desc": "O bolo é mentira", "bk:snowflake": "Floco de neve", "bk:snowflake_desc": "Congela todo mundo!", "bk:restock": "Reabastecer", "bk:restock_desc": "Suprimento infinito na loja", "bk:charisma_ring_desc": "Promoções Reais", "bk:charisma_ring": "Anel do Carisma", "bk:battery": "Bateria", "tomb_0": "Aqui jaz [cl green]Gobbo[cl] o Grande", "bk:homemade_dice": "Dado Improvisado", "bk:homemade_dice_desc": "^^Rola novamente^^ os itens! (DIY)", "shopkeeper_0": "##EU FALEI PRA NÃO FAZER ISSO!##", "shopkeeper_1": "Por favor, pare!", "shopkeeper_2": "Não faça isso.", "shopkeeper_3": "[cl red]##PREPARE-SE PARA MORRER!##", "shopkeeper_4": "[cl red]LADRÃO!", "shopkeeper_5": "[cl red]PEGA ELE!", "desert": "Palácio do Deserto", "jungle": "Floresta Antiga", "ice": "Ruínas de Gelo", "bk:iron_boots": "Botas de Ferro", "bk:iron_boots_desc": "Chega de se machucar nos espinhos", "bk:mimic_totem": "Totem de Mímico", "bk:mimic_totem_desc": "##CHEGA DE MÍMICOS##", "back_to_town": "Voltar para a Cidade", "bk:glass_gun": "Arma de Vidro", "bk:glass_gun_desc": "##Frágil##", "bk:glass_shard": "Pedaço de Vidro", "bk:glass_shard_desc": "Só uma parte de um todo", "bk:dagger": "Adaga", "bk:dagger_desc": "Nostalgia...", "bk:spear": "Lança", "bk:spear_desc": "Braços mais compridos?", "shopkeeper_6": "Boas-vindas :)", "shopkeeper_7": "E aí, tá afim de um pouco de [cl yellow]chá[cl]?", "shopkeeper_8": "Como vai?", "back": "Voltar", "master_volume": "Volume Geral", "music": "Música", "sfx": "Efeitos Sonoros", "graphics": "Gráficos", "audio": "Áudio", "ui_sfx": "Efeitos Sonoros de Interface", "on": "Ligado", "off": "Desligado", "fullscreen": "Tela Cheia", "vsync": "V-Sync", "fps": "Contador de FPS", "speedrun_timer": "Temporizador de Speedrun", "screenshake": "Tremor da Tela", "reset_progress": "Zerar Progresso", "blood_n_gore": "Sangue e Violência", "vegan_mode": "Modo Vegano", "reset_settings": "Zerar Configurações", "are_you_sure": "Tem certeza?", "yes": "Sim", "reset_progress_dis": "Isso apagará TODO o seu progresso!", "reset_settings_dis": "Isso vai voltar TODAS as configurações aos valores padrões!", "autosave": "Save Automático", "autopause": "Pause Automático", "input": "Comandos", "use": "Usar", "active": "Ativar", "bomb": "Bomba", "interact": "Interagir", "swap": "Trocar armas", "roll": "Rolar", "duck": "Pato", "pause": "Pausar", "none": "Nada", "keyboard_controls": "Comandos do Teclado", "gamepad_controls": "Comandos do Controle", "keyboard": "Teclado", "gamepad": "Controle", "game": "Jogo", "select": "Selecionar", "cursor": "Cursor", "bk:rip": "RIP", "ach_bk:rip_desc": "Morra", "ach_bk:overshake": "Tremor Exagerado", "ach_bk:overshake_desc": "1000% tremor de tela", "ach_bk:rip": "Conquista mais popular", "bk:emerald": "Esmeralda", "shopkeeper_9": "%%^^$$$^^%%", "shopkeeper_10": "^^Obrigado!^^", "shopkeeper_11": "Mas que %%pechincha%%!", "shopkeeper_12": "Quer [cl red]comprar[cl] ^^alguma coisa^^?", "shopkeeper_13": "Só pra [cl green]você[cl], só hoje!", "shopkeeper_14": "Que bela [cl yellow]oferta[cl]!", "bk:magnifier": "Lupa", "bk:magnifier_desc": "Projéteis maiores", "bk:mushroom_hat": "Chapéu de Cogumelo", "bk:mushroom_hat_desc": "Gostoso?", "bk:stone_hat": "Chapéu de Pedra", "bk:stone_hat_desc": "Pesado", "bk:knight_hat": "Chapéu de Cavaleiro", "bk:knight_hat_desc": "Bons e velhos inimigos...", "bk:cowboy_hat": "Chapéu de Caubói", "bk:cowboy_hat_desc": "Velho oeste!", "bk:soup_hat": "Chapéu de Sopa", "bk:soup_hat_desc": "^^Nham-nham^^", "bk:gold_hat": "Chapéu Dourado", "bk:gold_hat_desc": "[cl yellow]Riqueza!", "bk:viking_hat": "Chapéu de Viking", "bk:viking_hat_desc": "América", "bk:dunce_hat": "Chapéu de Pedra", "bk:dunce_hat_desc": "@-@", "bk:top_hat": "Cartola", "bk:top_hat_desc": "Elegância!", "bk:ushanka": "Ushanka", "bk:ushanka_desc": "Cadê minha ##balalaika?##", "bk:valkyrie_hat": "Chapéu de Valkíria", "bk:valkyrie_hat_desc": "I believe ^^I can fly!^^", "bk:skull_hat": "Chapéu de Crânio", "bk:skull_hat_desc": "Dinheiro ou vida!", "bk:grandma_head": "Cabeça da Vovó", "bk:grandma_head_desc": "Chá?", "bk:diamond_helmet": "Elmo de Diamante", "bk:diamond_helmet_desc": "Cale a boca e cave!", "bk:villager_head": "Chapéu de Aldeão", "bk:villager_head_desc": "Hmm?", "bk:fez": "Fez", "bk:fez_desc": "Cúbito", "bk:no_hat": "Remover Chapéu", "bk:no_hat_desc": "Sem chapéu - sem problema!", "bk:null_hat": "NULO", "bk:null_hat_desc": "Tenta chamar um valor nulo", "accessorytrader_0": "##SAIA DAQUI!## [dl]Ou compre estes ^^deliciosos^^ itens por apenas ^^%%99 diamantes cada%%^^!", "accessorytrader_1": "Olá", "accessorytrader_2": "E aí?", "weapontrader_0": "Entre!", "weapontrader_1": "Bom dia, senhor!", "weapontrader_2": "Compre algo, sim?", "activetrader_0": "As melhores ofertas do mercado!", "activetrader_1": "Pague dois e leve dois!", "activetrader_2": "Me dê rosquinhas, [dl]por favor!!", "hattrader_0": "Quer ser descolado como eu? [dl]Compre uns chapéus!", "hattrader_1": "Quer ser descolado como eu? [dl]Eu também, garoto!", "hattrader_2": "^^Cha cha chapéus!^^", "granny_0": "Quer um pouco de chá?", "granny_1": "Faça uma pausa para o chá!", "granny_2": "Chá?", "bk:xmas_hat": "Gorro de Natal", "bk:xmas_hat_desc": "Feliz Natal!", "bk:pumpkin_hat": "Abóbora Esculpida", "bk:pumpkin_hat_desc": "^^Esqueleto muito muito assustador^^", "bk:cage_key": "Chave da Cela", "bk:cage_key_desc": "Salve ^^o cara^^!", "npc_0": "Me ajude! Ache a chave!", "npc_1": "Valeu por me salvar!", "npc_2": "Mais rápido! Destranque a porta!", "npc_3": "Por favor! Me ajude!", "control_0": "Pressione [ic 0][ic 1] para colocar uma bomba", "control_1": "Rolar você pode! Pressione [ic 0][ic 1] para adquirir o poder!", "control_2": "Pressione [ic 0][ic 1] para atacar", "control_3": "Pressione [ic 0][ic 1] para interagir", "control_4": "Quack? [ic 0][ic 1]!", "control_5": "Pressione [ic 0][ic 1] para mudar de arma", "shopkeeper_15": "Sem desconto pra você!", "shopkeeper_16": "Consiga mais dinheiro e volte!", "shopkeeper_17": "Primeiro o pagamento!", "bk:frog": "Tele Sapo", "bk:frog_desc": "Viagem rápida?", "bk:sword_orbital": "Espada Orbital", "bk:sword_orbital_desc": "Justiça", "robbed": "Roubado", "bk:gift_desc": "O que tem dentro?", "bk:spike_ring": "Anel de Espinho", "bk:spike_ring_desc": "Seus inimigos devem ser ##punidos##!", "bk:fire_ring": "Anel de Fogo", "bk:fire_ring_desc": "Deixe que seus inimigos queimem", "bk:ice_ring": "Anel de Gelo", "bk:ice_ring_desc": "Pare seus inimigos", "bk:duck_ring": "Anel do Pato", "bk:duck_ring_desc": "Teleporta após ser atingido", "bk:dull_blade": "Lâmina Cega", "bk:dull_blade_desc": "Aciona efeito de ferimento", "bk:sharp_blade": "Lâmina Afiada", "bk:sharp_blade_desc": "Dano a si próprio", "bk:obsidian_shield": "Escudo Obsidiano", "bk:obsidian_shield_desc": "Repulsão = 0", "bk:bill": "Conta", "bk:bill_desc": "99 dinheiros", "control_6": "Use o item ativo com [ic 0][ic 1]", "bk:clover": "Trevo de 4 Folhas", "bk:clover_desc": "Sorte!", "bk:d4": "D4", "bk:d4_desc": "^^Rola novamente %%seus artefatos%%!^^", "brastin_0": "Encontre a pintura do [cl purple]gato[cl]!", "elon_1": "Aqui está, divirta-se", "bk:maanex_head": "Cabeça do Maanex", "bk:maanex_head_desc": "Hmmmmm", "bk:maanex": "Maanex", "bk:maanex_desc": "Faz os inimigos pensarem um pouco", "mob_0": "Hmmmm", "bk:map_greenprints": "Esboços de Mapa", "bk:map_greenprints_desc": "Revela o mapa", "bk:map": "Mapa", "bk:map_desc": "Revela o mapa permanentemente", "milt_1": "Eu quero presente", "mapuzzle_0": "Gravidade.", "nullptr_0": "SEGFAULT.", "copied_to_clipboard": "Copiado!", "isaac_0": "A vida não faz sentido...", "isaac_1": "Por quêêêê", "isaac_2": ":snif:", "discord_0": "Diga oi! discord.gg/rexcellent", "old_man_5": "Role, tolo!", "tutorial": "Tutorial", "bk:crying_bomb": "Bomba Chorona", "bk:crying_bomb_desc": "As bombas agora choram!", "bk:matches": "Fósforos", "bk:matches_desc": "Tempo de explosão mais curto", "bk:bomb_pack": "Bomba Empacotada", "bk:bomb_pack_desc": "Colocamos bombas nas suas bombas!", "bk:tnt": "TNT", "bk:tnt_desc": "99 bombas", "bk:weird_mushroom_desc": "Tudo em dobro", "bk:weird_mushroom": "Cogumelo Esquisito", "bk:bomb_shower": "Chuva de Bombas", "bk:bomb_shower_desc": "Nublado com chance de bombas", "bk:black_belt": "Faixa Preta", "bk:black_belt_desc": "Explodir não mais", "bk:ninjia_bomb": "Bomba Ninja", "bk:ninjia_bomb_desc": "Coloca bombas quando atingido", "start_new_run": "Sua partida atual será perdida!", "bk:laser_pointer": "Apontador Laser", "bk:laser_pointer_desc": "Mira limpa!", "ach_bk:marauder": "Saqueador", "ach_bk:marauder_desc": "Mate o vendedor", "ach_bk:treasure_hunter": "Caçador de Tesouro", "ach_bk:treasure_hunter_desc": "Encontre uma sala secreta", "ach_bk:dodge_master": "Mestre da Esquiva", "ach_bk:dodge_master_desc": "Mate um chefe sem ser atingido", "ach_bk:dodge_overlord": "Deus da Esquiva", "ach_bk:dodge_overlord_desc": "Complete um andar sem ser atingido uma única vez", "ach_bk:quackers": "Quackers", "ach_bk:quackers_desc": "Overquack", "ach_bk:tea_party": "Festa do Chá", "ach_bk:tea_party_desc": "Junte-se à Vovó na sua festa do chá", "ach_bk:not_a_thief": "Não sou um ladrão", "ach_bk:not_a_thief_desc": "Complete uma partida sem pegar nenhum item", "ach_bk:npc_party2": "Festa dos NPCs", "ach_bk:npc_party2_desc": "Salve todos os NPCs", "bk:gold_coin": "Moeda de Ouro", "bk:iron_coin": "Moeda de Ferro", "bk:copper_coin": "Moeda de Cobre", "bk:platinum_coin": "Moeda de Platina", "bk:voodoo_doll": "Boneca Vodu", "bk:voodoo_doll_desc": "Mata todos os inimigos da sala", "hub": "Cidade Dodge", "castle": "Ruínas do Castelo", "charger_0": "NENHUM ITEM ATIVO DETECTADO", "charger_1": "ITEM ATIVO JÁ ESTÁ CARREGADO", "charger_2": "CADÊ MEU DINHEIRO, SEU SACO DE CARNE!", "charger_3": "##EU DISSE PARA ME DAR MEU DINHEIRO!##", "charger_4": "##EU VOU DOMINAR O MUNDO!##", "charger_5": "##MUHAHAHAHA##", "maanex_6_0": "Claro, vamos nessa!", "maanex_6_1": "Nah.", "maanex_6": "Ok, me dê [cl yellow][vr cost] moedas[cl] e eu deixo você abrir um desses baús. Ok?", "maanex_5": "Ei cara, quer ^^tentar a sorte^^?", "maanex_7": "Isso foi divertido!", "maanex_8": "Boa sorte!", "maanex_9": "Bom, não desta vez :(", "maanex_10": "%%^^UAU^^%%", "maanex_11": "Mas você não tem dinheiro suficiente!", "maanex_12": "##FILHO?!##", "bk:amurs_arrow": "Flecha de Amur", "bk:amurs_arrow_desc": "Projéteis encantadores", "bk:amurs_bow": "Arco de Amur", "bk:amurs_bow_desc": "Eu vejo o amor", "bk:poison_flask": "Frasco de Veneno", "bk:poison_flask_desc": "Projéteis envenenados", "bk:snowball": "Bola de Neve", "bk:snowball_desc": "Projéteis congelados", "bk:peper_desc": "Projéteis picantes", "bk:peper": "Pimenta Malagueta", "bk:sale_coupon": "Cupom de Desconto", "bk:sale_coupon_desc": "-50%!", "bk:pet_box": "Mascote na Caixa", "bk:pet_box_desc": "Quem está aí dentro?", "bk:crate": "Caixa Orbital", "bk:crate_desc": "Quem está aí dentro?", "bk:strawberry": "Morango", "bk:strawberry_desc": "Doces lembranças", "bk:wings": "Asas", "bk:wings_desc": "I belive I can fly", "bk:coin_pouch": "Bolsa de Moedas", "bk:coin_pouch_desc": "Fornece moedas", "bk:key_pouch": "Bolsa de Chaves", "bk:key_pouch_desc": "Fornece chaves", "bk:bomb_pouch": "Bolsa de Bombas", "bk:bomb_pouch_desc": "Fornece bombas", "bk:pouch_pouch": "Bolsa de Bolsa", "bk:pouch_pouch_desc": "Fornece bolsas", "bk:lightsaber": "Svetsabre", "bk:lightsaber_desc": "Você foi o escolhido!", "bk:snail": "Lesma", "bk:snail_desc": "Lentidão total", "bk:spike": "Espinho", "bk:spike_desc": "Dano aumentado", "bk:mushroom": "Cogumelo", "bk:mushroom_desc": "Velocidade aumentada", "bk:candy": "Guloseima", "bk:candy_desc": "^^Êxtase do açucar^^, cadência de disparo aumentada", "bk:glasses": "Óculos", "bk:glasses_desc": "Mais precisão", "bk:ruler": "Régua", "bk:ruler_desc": "Mais alcance", "bk:stopwatch": "Cronômetro", "bk:stopwatch_desc": "Ser ferido controla o tempo", "bk_0": "##NÃO OUSE TOCAR NISSO!##", "bk_1": "##EU DISSE PARA NÃO TOCAR NISSO!##", "bk_2": "##VOCÊ NÃO PODE DERROTAR [cl red]O CAVALEIRO ARDENTE[cl], SEU TOLO!##", "bk_3": "##PREPARE-SE PARA MORRER!##", "bk_4": "^^QUE PIADA^^", "shopkeeper_18": "[cl red]^^Promoção especial![cl]", "dm_0": "@@Boas-vindas@@", "ach_bk:deal": "Movimento Excepcional", "ach_bk:deal_desc": "Faça negócio com o Mago Negro", "ach_bk:grannys_gift": "Presente da Vovó", "ach_bk:grannys_gift_desc": "Receba um presente da Vovó", "ach_bk:shopper": "Compre até Cair", "ach_bk:shopper_desc": "Compre um item em qualquer loja", "bk_5": "EU NEM PERDERIA TEMPO FALANDO COM ELE", "bk_6": "##MATE ELE, [cl lime]EDWARD[cl]!##", "bk_7": "[cl lime]EDWARD[cl], ##NÃÃÃOOO!!!!##", "bk_8": "AH QUALÉ, PARE DE EXPLODIR MEU CASTELO!", "bk_9": "[cl pink]VOVÓ[cl],[dl] TEM COMO VOCÊ MORRER, POR FAVOR##?!?##", "bk_10": "MEU MESTRE,[dl] EU TROUXE O [cl green]GOBLIN[cl]", "dm_1": "Muito bem[dl], obrigado[dl], [cl red]Limpor[cl]", "dm_2": "##Sim, sim, preciso de mais [cl orange]poder[cl]!##", "dm_3": "##MAIS [cl orange]PODER[cl]!", "dm_4": "Posso sentir [cl orange]o poder[cl] pulsando dentro de mim!", "granny_3": "Você será o primeiro, [cl red]Limpor[cl]!", "granny_4": "Bem-vindo, [cl green]Gobbo[cl]!", "granny_5": "Boa sorte na sua triste missão!", "bk:meat_guy": "Cara de Carne", "bk:meat_guy_desc": "Loucura!", "bk:bullet_stone": "Bala de Pedra", "bk:bullet_stone_desc": "Ele atac, ele proteg, mas o principal, ele é fofo pra caramb", "bk:batman": "Batman", "bk:batman_desc": "Não ajuda em nada, mas fornece baterias", "vibration": "Vibração", "bk:sharp_arrow": "Flecha Afiada", "bk:sharp_arrow_desc": "Projéteis penetrantes", "machine_0": "Insira uma [cl yellow]moeda", "player_0": "Papai?? ##O que eles fizeram com você?!?##", "bk:boomerang": "Bumerangue", "bk:boomerang_desc": "Projéteis bumerangue", "bk:backpack": "Mochila", "bk:backpack_desc": "Meu amigo urso", "place_an_item": "Coloque um item", "bk:crystal": "Cristal", "bk:crystal_desc": "O poder do arco-íris", "bk:prism": "Prisma", "bk:prism_desc": "Projéteis -> Arco-íris", "scourged": "Flagelado", "bk:bomb": "Bomba", "bk:scourge_of_egg": "Flagelo do Ovo", "bk:scourge_of_egg_desc": "Nomes dos itens embaralhados", "bk:scourge_of_unknown": "Flagelo do Desconhecido", "bk:scourge_of_unknown_desc": "Itens ocultos", "bk:scourge_of_blood": "Flagelo do Sangue", "bk:scourge_of_blood_desc": "Duplos problemas (e inimigos)", "bk:scourge_of_risk": "Flagelo do Risco", "bk:scourge_of_risk_desc": "Vida oculta", "bk:scourge_of_keys": "Flagelo das Chaves", "bk:scourge_of_keys_desc": "Consumíveis ocultos", "bk:scourge_of_lost": "Flagelo do Perdido", "bk:scourge_of_lost_desc": "Amnésia", "bk:scourge_of_scourged": "Flagelo do Flagelado", "bk:scourge_of_scourged_desc": "Flagelo por todo lado", "bk:scourge_of_illness": "Flagelo da Doença", "bk:scourge_of_illness_desc": "Vida nerfada", "bk:scourge_of_death": "Flagelo da Morte", "bk:scourge_of_death_desc": "Modo difícil", "bk:ancient_revolver": "Revólver Antigo", "bk:ancient_revolver_desc": "Parece bem legal", "bk:assault_rifle": "Rifle de Assalto", "bk:assault_rifle_desc": "Rajadas", "fountain_0": "Traga 5 moedas e terá uma benção", "fountain_1": "Recebeu purificação parcial", "fountain_2": "Recebeu purificação total", "fountain_3": "Você já está purificado", "buffed": "Bufado", "nerfed": "Nerfado", "restored": "Restaurado", "damaged": "Danificado", "cleansed": "Purificado", "gifted": "Presenteado", "lucky": "Sortudo", "unlucky": "Azarado", "max_hp": "Vida Máx.", "touch": "Toque", "break": "Quebre", "no_coins": "Sem moedas", "old_man_6": "É perigoso ir sozinho, leve isto!", "roger_0": "Buuumm!", "roger_1": "##*BUUM*##", "roger_2": "Boom boom shakataka!", "bk:shield": "Escudo", "bk:gift": "Presente", "bk:shield_pouch": "Bolsa de Escudos", "bk:shield_pouch_desc": "Fornece escudos", "bk:shield_buddy": "Amigo Escudo", "bk:shield_buddy_desc": "Ele proteg", "bk:skeleton_key": "Chave mestra", "bk:skeleton_key_desc": "99 chaves", "bk:jar": "Jarra de Vida", "bk:jar_desc": "Jar Jar Clinks", "bk:star": "Estrela", "bk:star_desc": "Ela proteg", "bk:car_bomb": "Carro Bomba", "bk:car_bomb_desc": "Serviço de entrega de bombas", "bk:grenade": "Granada", "bk:grenade_desc": "Detona ao contato", "trash_goblin_0": "Liberte-me do meu [cl purple]flagelo[cl]! Por favor!", "trash_goblin_1": "Estou livre![dl] Muito obrigado!", "boxy_0": "Chavexcelente!", "boxy_1": "Que caixa maneira!", "boxy_2": "Você precisa de papel para embrulho?", "trash_goblin_2": "^^Smoke on the water [ic 0] [ic 1]^^", "bk:vampire_bat": "Morcego Vampiro", "bk:vampire_bat_desc": "Regeneração", "shields": "Escudos", "bk:mustache": "Bigode", "bk:mustache_desc": "VIP", "bk:bloody_chest": "Baú Sangrento", "bk:bloody_chest_desc": "Baús curam", "bk:bloody_shield": "Escudo Sangrento", "bk:bloody_shield_desc": "Escudos eternos", "bk:cutsaw": "Serrote", "bk:cutsaw_desc": "Os inimigos vão pagar", "vampire_0": "Nham!", "vampire_1": "Incrível pra caramba!", "vampire_2": "Tão doce!", "vampire_3": "Nós conhecemos as regras, [cl red]^^certo[cl]?", "vampire_4": "^^Mmmmmmm^^", "vampire_5": "Qual seu tipo sanguíneo?", "vampire_6": "Tão gostoso", "duck_2": "Se importa em participar de uma pesquisa?", "duck_7_0": "Sim", "duck_7_1": "Não", "duck_7": "Você vai pegar este baú?", "duck_4": "Bom trabalho, fique com este baú!", "duck_5": "Não posso concordar com você...", "duck_6_0": "O universo", "duck_6_1": "^^Quarks^^", "duck_6": "No que estou pensando?", "duck_8_0": "[cl red]Vermelho[cl]", "duck_8_1": "[cl blue]Azul[cl]", "duck_8": "Qual é a minha ^^%%cor%%^^ favorita?", "duck_9_0": "Um gato", "duck_9_1": "Você acabou de dizer isso", "duck_9": "Quem disse miau?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "O que é melhor?", "duck_11_0": "O que, seu ovo?", "duck_11_1": "\\[_Ele o esfaqueou._]", "duck_11": "Você é um garoto atrevido", "duck_12_0": "Galinha", "duck_12_1": "Ovo", "duck_12": "Quem veio primeiro?", "duck_13_0": "Nada.", "duck_13_1": "Um lanchinho.", "duck_13_2": "Um ovo.", "duck_13_3": "Frango frito.", "duck_13": "O que você comeu hoje?", "duck_14": "Ai.", "duck_17_0": "Claro rapaz", "duck_17_1": "##NAAAAAH##", "duck_17": "Você gosta de abacaxi na sua pizza?", "duck_18_0": "Branco!", "duck_18_1": "[cl yellow]Amarelo[cl]!", "duck_18": "Qual é a cor do queijo?", "nurse_0": "Você está com uma ótima aparência, querido!", "nurse_1": "Eu poderia curá-lo um pouco, mas preciso de [cl yellow][vr price] moedas[cl]", "nurse_2": "Espero que não tenha machucado", "elon_4": "Aqui está, divirta-se", "elon_2_0": "Vambora", "elon_2_1": "Espere", "elon_2": "Quer experimentar minha mágica?", "elon_3": "Eu posso transformar sua arma em outra.", "elon_5": "Tanto faz.", "elon_7": "Mano, cadê sua arma???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*corando*", "gobetta_4": "É... você?", "gobetta_5": "Já faz tanto tempo...", "ach_bk:desert": "Quente e Seco", "ach_bk:desert_desc": "Chegue no Palácio do Deserto", "ach_bk:jungle": "Abelhas Barulhentas", "ach_bk:jungle_desc": "Chegue na Floresta Antiga", "rooms_explored": "Salas exploradas", "bk:shadow_cloak_desc": "Não, você", "bk:shadow_cloak": "Capa das Sombras", "bk:dynamite_stick": "Banana de Dinamite", "bk:dynamite_stick_desc": "Você quer explodir?", "bk:chalice_of_blood": "Cálice de Sangue", "bk:chalice_of_blood_desc": "A dor traz a fúria, a fúria traz mais dano", "bk:detonator": "Detonador", "bk:detonator_desc": "Detona explosivos", "invincibility_time": "Tempo de invencibilidade", "accuracy": "Precisão", "range": "Alcance", "fire_rate": "Cadência de Disparo", "speed": "Velocidade", "bk:talisman_of_foresight": "Talismã de Clarividência", "bk:talisman_of_foresight_desc": "Abra seus olhos e veja as salas ao redor!", "bk:scourge_ring": "Anel do Flagelo", "bk:scourge_ring_desc": "Sem mais flagelos", "snek_0": "Legal.", "snek_1": "Valeuuuu cara", "snek_2": "Innncrível", "snek_3": "E aí", "snek_4": "Bom dia, sssenhor!", "snek_5": "Tu quer comprar algo?", "snek_6": "Preciso ssssatisfazer o consumidor...", "snek_7": "Farei o que for precissso!", "bk:snek": "Snek", "bk:snek_desc": "Lanchinho?", "boxy_3": "^^:wave:^^", "boxy_4": "Tem uma chave sobrando?", "boxy_5": "Se importa em doar algumas chaves?", "bk:blank": "Branco", "bk:blank_desc": "_Texto em branco_", "bk:blank_bombs": "Bombas em Branco", "bk:blank_bombs_desc": "Bala escudo", "bk:explosive_bullets": "Balas Explosivas", "bk:explosive_bullets_desc": "Explosivo", "bk:random_bullets": "Balas Aleatórias", "bk:random_bullets_desc": "RNG", "bk:cup": "Xícara", "bk:cup_desc": "A Vovó não vai resistir", "bk:cartridge": "Cartucho", "bk:cartridge_desc": "O Mago Negro não vai resistir", "bk:marriage_ring": "Anel de Casamento", "bk:marriage_ring_desc": "Mago Negro S2 Vovó pra sempre!", "boxy_7": "Eu quero chaves", "boxy_8": "Parece que você não tem chaves suficientes :(", "boxy_9": "Finalmente tenho bastante chaves para ^^abrir^^!", "roger_3": "Se importa em pagar?", "roger_4": "Sem descontos hoje", "roger_5": "Bombas em primeiro lugar", "vampire_7": "Você não está saudável o suficiente", "vampire_8": "Eu não dou desconto", "vampire_9": "Parece que sua vida está baixa", "ach_bk:scourged": "Flagelado", "ach_bk:scourged_desc": "Pegue uma Ficha de Flagelo", "ach_bk:scourged_weapon": "Arma Flagelada", "ach_bk:scourged_weapon_desc": "Pegue uma Arma Flagelada", "rerolled": "Rolado novamente", "ach_bk:open_up": "Abra", "ach_bk:open_up_desc": "Compre tudo do Boxy", "ach_bk:snek": "Mascote Snek", "ach_bk:snek_desc": "Faça Snek ser seu mascote", "bk:scourge_of_greed": "Flagelo da Ganância", "bk:scourge_of_greed_desc": "Preços altos", "killed_by": "Morto por", "kills": "Abates", "time": "Tempo", "depth": "Profundidade", "bk:blank_bullets": "Balas em Branco", "bk:blank_bullets_desc": "Branco", "bk:lego": "Construtor", "bk:lego_desc": "Não tanto pisar neles...", "bk:iron_armor": "Armadura de Ferro", "bk:iron_armor_desc": "Fornece escudos", "bk:round_shield": "Escudo Redondo", "bk:round_shield_desc": "Anula dano de colisão", "bk:arkhalis": "Arkhalis", "bk:arkhalis_desc": "A lenda em pessoa", "bk:inverted_arkhalis": "Arkhalis invertido", "bk:inverted_arkhalis_desc": "A ajuda virá quando a vida estiver baixa", "bk:gun_sword": "Espada Revólver", "bk:gun_sword_desc": "Prepare-se para problemas em dobro!", "ach_bk:scourge_king_desc": "Consiga 10 pontos de flagelo", "ach_bk:scourge_king": "Rei do Flagelo", "ach_bk:sting_operation": "Operação Picada", "ach_bk:sting_operation_desc": "Derrote a Abelha Rainha", "ach_bk:mummified": "Mumificado", "ach_bk:mummified_desc": "Derrote o Faraó", "ach_bk:democracy": "Democracia", "ach_bk:democracy_desc": "Derrote Velho Rei", "pharaoh_scream": "##PREPARE-SE PARA SER MUMIFICADO!##", "queen_bee_scream": "##PELO [cl yellow]SENHOR DO MEL[cl]!##", "bk:half_heart": "Meio Coração", "right": "Direita", "down": "Baixo", "left": "Esquerda", "up": "Cima", "painting_cat": "Pintura de Gato", "bk:axe": "Machado", "bk:axe_desc": "Ele prometeu voltar", "bk:guitar": "Violão", "bk:guitar_desc": "Está desafinado", "bk:glass_sword": "Espada de Vidro", "bk:glass_sword_desc": "A arma dos mestres", "bk:chicken": "Asa de Galinha", "bk:chicken_desc": "Picante", "bk:pickaxe": "Picareta", "bk:pickaxe_desc": "Cave, subordinado!", "bk:mana": "Mana", "bk:half_mana": "Meia-mana", "bk:lava_wand": "Varinha de Lava", "bk:lava_wand_desc": "Assuntos quentes", "bk:web_wand": "Varinha Aranha", "bk:web_wand_desc": "Provedor world-wide web", "bk:slap_stick": "Bastão de Tapa", "bk:slap_stick_desc": "Tapa", "sensivity": "Sensibilidade", "no": "Não", "scale": "Escala", "ach_bk:ice": "Era do Gelo", "ach_bk:ice_desc": "Chegue nas Ruínas Congeladas", "ach_bk:library": "Textos Sagrados", "ach_bk:library_desc": "Chegue na Biblioteca Secreta", "bk:ice_skates": "Patins de Gelo", "bk:ice_skates_desc": "Imunidade ao gelo", "bk:campfire_in_bottle": "Fogueira engarrafada", "bk:campfire_in_bottle_desc": "Imunidade a congelamento", "library": "Biblioteca Secreta", "ach_bk:cat_without_a_hat": "Gato sem chapéu", "ach_bk:cat_without_a_hat_desc": "Encontre a pintura do gato", "ach_bk:rich": "Papel Higiênico", "ach_bk:rich_desc": "Adquira 99 moedas", "ach_bk:rescue_operation": "Operação Resgate", "ach_bk:rescue_operation_desc": "Salve um NPC", "ach_bk:tutorial": "Guru", "ach_bk:tutorial_desc": "Conclua o tutorial", "ach_bk:fancy_hat": "Chapéu Maneiro", "ach_bk:fancy_hat_desc": "Compre um chapéu", "ach_bk:unlock": "Destravador", "ach_bk:unlock_desc": "Desbloqueie um item", "floor_brightness": "Brilho do chão", "ach_bk:shielded": "Levantar Escudos", "ach_bk:shielded_desc": "Adquira um coração escudo", "run_type": "Tipo de partida", "run_regular": "Regular", "run_challenge": "Desafio", "damage_taken": "Dano recebido", "km": "km", "distance_traveled": "Distância percorrida", "seed": "Semente", "score": "Pontuação", "new_high_score": "Novo recorde!", "items_collected": "Itens coletados", "boss_rush": "Boss Rush", "run_bossrush": "Boss rush", "bk:blindfold_desc": "RIP minhas armas", "bk:blindfold": "Venda", "daily_run": "Partida Diária", "builder_0_0": "É", "builder_0_1": "Vou precisar do dinheiro", "builder_0": "Estou planejando construir um atalho aqui, mas preciso de mais [vr need] [ic 0] moedas. Você pode me ajudar?", "builder_1": "Mas você não tem dinheiro! :(", "builder_2": "Obrigado pelo investimento!", "builder_3": "Finalmente tenho dinheiro o suficiente para terminar esse projeto! Muito obrigado!", "builder_4": "Ok, desculpe!", "shortcut_is_broken": "O atalho está quebrado", "ach_bk:boss_rush": "Desafiador de Chefes", "ach_bk:boss_rush_desc": "Derrote todos os chefes no modo Boss Rush", "ach_bk:daily": "Glória do Dia", "ach_bk:daily_desc": "Complete a Partida Diária", "ach_bk:desert_shortcut": "Atalho para o Palácio do Deserto", "ach_bk:desert_shortcut_desc": "Consertou o atalho para o Palácio do Deserto", "ach_bk:jungle_shortcut": "Atalho para a Floresta Antiga", "ach_bk:jungle_shortcut_desc": "Consertou o atalho para a Floresta Antiga", "ach_bk:ice_shortcut": "Atalho para as Ruínas Congeladas", "ach_bk:ice_shortcut_desc": "Consertou o atalho para as Ruínas Congeladas", "ach_bk:library_shortcut": "Atalho para a Biblioteca Secreta", "ach_bk:library_shortcut_desc": "Consertou o atalho para a Biblioteca Secreta", "ach_bk:fashion_matters2": "Questão de moda", "ach_bk:fashion_matters2_desc": "Compre cada chapéu", "ach_bk:10_challenges": "Desafiador", "ach_bk:10_challenges_desc": "Complete 10 desafios", "ach_bk:20_challenges": "Desafiador 2.0", "ach_bk:20_challenges_desc": "Complete 20 desafios", "ach_bk:30_challenges": "Desafiador 3.0", "ach_bk:30_challenges_desc": "Complete 30 desafios", "ach_bk:bk_no_more": "Chega de BK", "ach_bk:bk_no_more_desc": "Derrote o próprio Burning Knight", "ach_bk:dm_no_more": "Chega de MN", "ach_bk:dm_no_more_desc": "Derrote o Mago Negro", "ach_bk:egor_no_more": "Chega de Egor", "ach_bk:egor_no_more_desc": "???", "ach_bk:loop": "Ah, lá vamos nós de novo", "ach_bk:loop_desc": "Entre no loop", "coins_collected": "Moedas coletadas", "bk:cup_head": "Cabeça de Xícara", "bk:cup_head_desc": "Tome uma xícara de chá", "bk:mustache_hat": "Bigode", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Chapéu Propulsor", "bk:propeller_hat_desc": "Ele gira", "bk:sunglasses": "Óculos de sol", "bk:sunglasses_desc": "Funciona à noite também!", "bk:cap": "Boné", "bk:cap_desc": "Da hora @-@", "bk:eyes": "Olhos", "bk:eyes_desc": "@ @", "bk:eye": "Olho", "bk:eye_desc": "@", "bk:hair": "Cabelo", "bk:hair_desc": "Que chique", "won": "Venceu", "won_message": "Você venceu!", "garderobe_sign": "Provador", "darkmarket_tip": "~~[cl purple]Flagelo[cl] ou [cl yellow]30 moedas[cl]@@", "mike_0": "Tem que me pagar [cl green]3 esmeraldas", "mike_1": "Experimente o modo boss rush por [cl green]3 esmeraldas[cl]!", "bk:weird_potion": "Poção Esquisita", "bk:weird_potion_desc": "Projéteis estranhos", "bk:megaphone": "Megafone", "bk:megaphone_desc": "Projéteis expansivos", "scourge": "Flagelo", "scourge_stats": "Flagelo", "run_daily": "Diária", "completed_on": "Concluído em", "complete": "concluído", "next_daily_in": "[cl gray]Próxima começa em[cl]", "hours": "horas", "minutes": "minutos", "seconds": "segundos", "ach_bk:star": "A Estrela do Show", "ach_bk:star_desc": "Adquira 3 orbitais", "ach_bk:family": "Família felizinha", "ach_bk:family_desc": "Adquira 3 mascotes", "ach_bk:return_to_sender": "Não, você", "ach_bk:return_to_sender_desc": "Mate um inimigo com seu próprio projétil", "ach_bk:van_no_gogh": "Van sem Gogh", "ach_bk:van_no_gogh_desc": "Destrua 100 pinturas", "ach_bk:dark_market": "Esconderijo do Crime", "ach_bk:dark_market_desc": "Desça até o Mercado Negro", "ach_bk:spikes": "Assuntos Espinhosos", "ach_bk:spikes_desc": "Ative 100 espinhos em uma única partida", "ach_bk:white_flag": "Sem Armas", "ach_bk:white_flag_desc": "Conclua uma sala sem usar armas nem uma vez", "quack": "[cl yellow]Quack![cl]", "pixel_perfect": "Pixel Perfeito", "bk_11": "EU TE PERDOO DESTA VEZ... MAS ##NÃO FAÇA## ISSO DE NOVO!", "leaderboard": "Leaderboard", "display": "Display", "around_you": "Ao seu redor", "friends": "Amigos", "global": "Global", "loading": "Carregando", "generating": "Gerando", "cursor_radius": "Raio do cursor", "no_scores_yet": "Sem pontuações ainda", "no_score_yet": "Sem pontuação ainda", "run": "Partida", "top": "Topo", "quick_restart": "Quack Reiniciar", "painting_dungeon": "Masmorra", "painting_goose": "Mini ganso", "painting_chess": "Elefante Voador", "painting_peach": "Pessegueira", "bk:no_lamp": "Sem lâmpada", "bk:explosive_lamp": "Lâmpada Explosiva", "bk:explosive_lamp_desc": "Quando o bum significa mais", "bk:shielded_lamp": "Lâmpada Protegida", "bk:shielded_lamp_desc": "Levantar Escudos!", "lamp": "Lâmpada", "bk:brain": "Mega Cérebro", "bk:brain_desc": "Poder da mente: Mega", "bk:heart_amulet": "Amuleto Coração", "bk:heart_amulet_desc": "+1 Tamanho de Coração", "bk:star_amulet_desc": "Mais mana", "bk:star_amulet": "Amuleto Estrela", "bk:coin_amulet": "Amuleto Moeda", "bk:coin_amulet_desc": "Moedas valem mais", "bk:key_amulet": "Amuleto Chave", "bk:key_amulet_desc": "Chaves valem mais", "bk:bomb_amulet": "Amuleto Bomba", "bk:bomb_amulet_desc": "Bombas valem mais", "bk:eye_amulet": "Amuleto Olho", "bk:eye_amulet_desc": "Dói ser tão impreciso", "bk:eye_patch": "Tapa-olho", "bk:eye_patch_desc": "Estão prontas, crianças?", "bk:toilet_paper": "Papel Higiênico", "bk:toilet_paper_desc": "Está sempre acabando", "bk:decoy": "Isca", "bk:decoy_desc": "Isso explode", "bk:wallet": "Amigo Carteira", "bk:wallet_desc": "Guarda suas moedas", "bk:skele_buddy": "Esquele-amigo", "bk:skele_buddy_desc": "Assustador", "bk:mega_bomb": "Mega Bomba", "bk:mega_bomb_desc": "Tamanho da bomba: Mega", "bk:condensed_milk": "Leite Condensado", "bk:condensed_milk_desc": "Pixeis mais rápidos, inimigos mais lentos", "bk:marshmallow": "Marshmallow", "bk:marshmallow_desc": "Pegajoso", "bk:orbital_multiplier": "Multiplicador Orbital", "bk:orbital_multiplier_desc": "Mais orbitais!", "bk:pet_multiplier": "Multiplicador de Mascotes", "bk:pet_multiplier_desc": "Mais mascotes!", "bk:ghost_bullets": "Balas Fantasmas", "bk:ghost_bullets_desc": "Não param nas paredes", "bk:weight": "Peso Pesado", "bk:weight_desc": "Ajuda a gravidade", "bk:d2": "D2", "bk:d2_desc": "É pegar ou largar", "bk:ethernal_d6": "D6 Eterno", "bk:ethernal_d6_desc": "Rola novamente e/ou destrói", "bk:billiard": "Bilhar", "bk:billiard_desc": "Projéteis ricocheteiam", "bk:enraged_bullets": "Balas Furiosas", "bk:enraged_bullets_desc": "Projéteis quebram projéteis", "bk:rewind_button": "Botão de Voltar", "bk:rewind_button_desc": "Espere aí", "bk:piggy_bank": "Cofrinho", "bk:piggy_bank_desc": "Minha economia inteira", "coins": "Moedas", "bk:death_star": "Estrela da Morte", "bk:death_star_desc": "RIP Alderan", "bk:soldering_iron": "Ferro de Solda", "bk:soldering_iron_desc": "É quente pra caramba", "bk:can": "Lata", "bk:can_desc": "Projéteis duplos", "bk:swimming_mask": "Máscara de Mergulho", "bk:swimming_mask_desc": "É uma arma secreta", "bk:bullet_chair": "Bala Cadeira", "bk:bullet_chair_desc": "4 pernas 4 armas", "bk:cell": "Célula", "bk:cell_desc": "Projéteis multiplicados", "bk:brick": "iTijolo", "bk:brick_desc": "Níveis maiores", "bk:ring_of_pain": "Anel da Dor", "bk:ring_of_pain_desc": "Ser ferido fere todo mundo", "bk:schrodingers_cat": "Gatos Schrödingers", "bk:schrodingers_cat_desc": "Ser Ou Não Ser (50% de chance)", "bk:smoke_bomb": "Bomba de Fumaça", "bk:smoke_bomb_desc": "Fuga no estilo ninja", "bk:chest_ring": "Anel do Baú", "bk:chest_ring_desc": "Mais baús!", "bk:empty_shell": "Casca Vazia", "bk:empty_shell_desc": "Chance de destruir projéteis inimigos", "bk:parachute": "Paraquedas", "bk:parachute_desc": "Imunidade a abismos", "bk:spiked_cookie": "Biscoito Espinhento", "bk:spiked_cookie_desc": "Menino espinhento", "bk:shooty": "Shooty", "bk:shooty_desc": "Ele, quem atira", "bk:rabbit_bullets": "Balas-coelho", "bk:rabbit_bullets_desc": "Elas se multiplicam", "bk:pandoras_box": "Caixa de Pandora", "bk:pandoras_box_desc": "Armazene o mal", "bk:bubbles": "Bolhas", "bk:bubbles_desc": "Amigo Bolha", "bk:match": "Fósforo", "bk:match_desc": "Fogo para todos", "bk:hammer": "Martelo", "bk:hammer_desc": "Quebra armaduras", "bk:helmet": "Elmo de Ferro", "bk:helmet_desc": "Chance de ignorar o dano", "bk:beer": "Cerveja", "bk:beer_desc": "Dano enfurece", "bk:the_eye": "O Olho", "bk:the_eye_desc": "Ele está observando", "bk:mimics_tooth": "Dente do Mímico", "bk:mimics_tooth_desc": "Atrai mímicos", "ach_bk:mimic": "Sustinho", "ach_bk:mimic_desc": "Encontre um mímico", "bk:paper_airplane": "Aviãozinho de papel", "bk:paper_airplane_desc": "Projéteis teleguiados", "ach_bk:ice_boss": "Livre Estou", "ach_bk:ice_boss_desc": "Mate a Rainha do Gelo", "ice_queen_scream": "^^[cl cyan]Aham", "painting_agency": "Boas-vindas à agência", "language": "Idioma", "bk:pouch": "Bolsa", "bk:alien_glasses": "Óculos Alienígenas", "bk:alien_glasses_desc": "Eu vejo mais", "inventory": "Inventário", "bk:led": "LED", "bk:led_desc": "Lâmpada precisa", "bk:fragile_lamp": "Lâmpada Frágil", "bk:fragile_lamp_desc": "1 golpe mata", "painting_guitar": "Mais volume!", "ach_bk:maanex": "Até tu, Brutus?", "ach_bk:maanex_desc": "Mate Maanex usando sua cabeça" } ================================================ FILE: BurningKnight/Content/Locales/qu.json ================================================ {"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","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":" Радуга", "scourged": "Проклят", "bk:bomb": "Бомба", "bk:scourge_of_egg": "Проклятие Яйца", "bk:scourge_of_egg_desc": "Перепутанные названия", "bk:scourge_of_unknown": "Проклятие Неизвестности", "bk:scourge_of_unknown_desc": "Спрятанные предметы", "bk:scourge_of_blood": "Проклятие Крови", "bk:scourge_of_blood_desc": "Больше врагов", "bk:scourge_of_risk": "Проклятие Риска", "bk:scourge_of_risk_desc": "Спрятанное здоровье", "bk:scourge_of_keys": "Проклятие Ключей", "bk:scourge_of_keys_desc": "Спрятанные пикапы", "bk:scourge_of_lost": "Проклятие Потерянного", "bk:scourge_of_lost_desc": "Амнезия", "bk:scourge_of_scourged": "Проклятие Проклятого", "bk:scourge_of_scourged_desc": "Проклятия Везде", "bk:scourge_of_illness": "Проклятие Больного", "bk:scourge_of_illness_desc": "Сердца лечат меньше", "bk:scourge_of_death": "Проклятие Смерти", "bk:scourge_of_death_desc": "Хардмод", "bk:ancient_revolver": "Древний револьвер", "bk:ancient_revolver_desc": "Выглядит Классно", "bk:assault_rifle": "Штурмовая винтовка", "bk:assault_rifle_desc": "Пиу-пиу!", "fountain_0": "Принеси пять монет и я благославлю тебя", "fountain_1": "Ты был частично очищен", "fountain_2": "Ты был полностью очищен", "fountain_3": "Ты уже очищен", "buffed": "Баффнут", "nerfed": "Понерфлен", "restored": "Возрождён", "damaged": "Увечен", "damage": "Урон", "cleansed": "Очищен", "gifted": "Одарён", "lucky": "Счастливчик", "unlucky": "Неудачник", "max_hp": "Максимальные HP", "touch": "Потрогать", "break": "Сломать", "no_coins": "Нет монет", "old_man_6": "Опасно идти одному, возми это!", "roger_0": "Бум!", "roger_1": "##*БУМ*##", "roger_2": "Бум бум шакалака!", "bk:shield": "Щит", "bk:gift": "Подарок", "bk:shield_pouch": "Мешочек с щитами", "bk:shield_pouch_desc": "Дает щиты", "bk:shield_buddy": "Щитовик", "bk:shield_buddy_desc": "Защитник", "bk:skeleton_key": "Ключ Скелета", "bk:skeleton_key_desc": "99 ключиков", "bk:jar": "Склянка со Здоровьем", "bk:jar_desc": "Джем", "bk:star": "Звезда", "bk:star_desc": "Защита", "bk:car_bomb": "Бомбы на Колесах", "bk:car_bomb_desc": "Система доставки бомб к врагам", "bk:grenade": "Граната", "bk:grenade_desc": "Бомбы взрываются при касании", "trash_goblin_0": "Спаси меня от моего [cl purple]проклятия[cl]! Пожалуйста!", "trash_goblin_1": "Я свободен![dl] Спасибо тебе огромное!", "boxy_0": "Балдёж", "boxy_1": "Какая упаковка!", "boxy_2": "Тебе нужна обёрточная бумага?", "trash_goblin_2": "^^Туман над рекой^^", "bk:vampire_bat": "Мышь-вампир", "bk:vampire_bat_desc": "Реген", "shields": "Щиты", "bk:mustache": "Усы", "bk:mustache_desc": "ВИП", "bk:bloody_chest": "Кровавый Сундук", "bk:bloody_chest_desc": "Сундуки лечят", "bk:bloody_shield": "Кровавый щит", "bk:bloody_shield_desc": "Щиты навсегда", "bk:cutsaw": "Пила", "bk:cutsaw_desc": "Враги заплатят", "vampire_0": "Нам!", "vampire_1": "Балдёж", "vampire_2": "Мммм", "vampire_3": "Мы знаем правила, [cl red]^^не так ли[cl]?", "vampire_4": "^^Мммммм^^", "vampire_5": "Какая у тебя группа крови?", "vampire_6": "Вкуснятина", "duck_2": "Ответишь на пару вопросов?", "duck_7_0": "Давай", "duck_7_1": "Не", "duck_7": "Ты получишь этот сундук?", "duck_4": "Красавчик, держи сундук!", "duck_5": "Не могу согласиться...", "duck_6_0": "Вселенная", "duck_6_1": "^^Кваки^^", "duck_6": "О чём я думаю?", "duck_8_0": "[cl red]Красный[cl]", "duck_8_1": "[cl blue]Синий[cl]", "duck_8": "Какой мой любимый ^^%%цвет%%^^?", "duck_9_0": "Кошка", "duck_9_1": "Ты", "duck_9": "Кто сказал \"мяу\"?", "duck_10_0": "0", "duck_10_1": "1", "duck_10": "Что лучше?", "duck_11_0": "Да что, ты, яйцо?", "duck_11_1": "\\[_Он ударил его._]", "duck_11": "Ты соус", "duck_12_0": "Курица", "duck_12_1": "Яйцо", "duck_12": "Что было первым?", "duck_13_0": "Ничего.", "duck_13_1": "Снек.", "duck_13_2": "Яйцо.", "duck_13_3": "Жаренная курица.", "duck_13": "Что я ел сегодня?", "duck_14": "Ой.", "duck_17_0": "Конечно", "duck_17_1": "##НАНИ##", "duck_17": "Как насчёт ананасов на твоей пицце?", "duck_18_0": "Белого!", "duck_18_1": "[cl yellow]Желтого[cl]!", "duck_18": "Какого цвета сыр?", "nurse_0": "Ты выглядишь прекрасно, дорогой!", "nurse_1": "Я могу тебя подлечить, но мне нужно [cl yellow][vr price] монет[cl]", "nurse_2": "Надеюсь, это было не больно", "elon_4": "Держи, удачи", "elon_2_0": "Поехали", "elon_2_1": "Погодь", "elon_2": "Хочешь испытать мою магию?", "elon_3": "Я могу трансмутировать твое оружие", "elon_5": "Ну ладно", "elon_7": "Бро, где твое оружие???", "gobetta_0": "<3", "gobetta_1": ":3", "gobetta_2": "=)", "gobetta_3": "*blush*", "gobetta_4": "Это... ты?", "gobetta_5": "Столько лет прошло...", "ach_bk:desert": "Сухо да Жарко", "ach_bk:desert_desc": "Дойди до Пустынного замка", "ach_bk:jungle": "Жужжащие пчёлки", "ach_bk:jungle_desc": "Доберись до Древних джунгей", "rooms_explored": "Комнат исследовано", "bk:shadow_cloak_desc": "No U", "bk:shadow_cloak": "Мантия-неведимка", "bk:dynamite_stick": "Гильза динамита", "bk:dynamite_stick_desc": "Хочешь бомбануть?", "bk:chalice_of_blood": "Кубок с кровью", "bk:chalice_of_blood_desc": "Боль вызывает злость, злость повышает урон", "bk:detonator": "Детонатор", "bk:detonator_desc": "Активирует взрывы", "invincibility_time": "Время неуязвимости", "accuracy": "Точность", "range": "Дальность", "fire_rate": "Скорость атаки", "speed": "Скорость", "bk:talisman_of_foresight": "Талисман Предвидения", "bk:talisman_of_foresight_desc": "Открой глаза и увидь соседние комнаты!", "bk:scourge_ring": "Проклятое кольцо", "bk:scourge_ring_desc": "Иммунитет к проклятиям", "snek_0": "Найс.", "snek_1": "Шшшшпасибо", "snek_2": "Класшшш", "snek_3": "Привет", "snek_4": "Доброго времени шшуток", "snek_5": "Купи шшшто-нибудь?", "snek_6": "Мне нужно удоволетворить покупателя...", "snek_7": "Я шшшшделаю то, шшшто я должен!", "bk:snek": "Смей", "bk:snek_desc": "Снэк?", "boxy_3": "^^:wave:^^", "boxy_4": "Найдется лишний ключ?", "boxy_5": "Дай пару ключей?", "bk:blank": "Пустышка", "bk:blank_desc": "_Пустой текст_", "bk:blank_bombs": "Пустые бомбы", "bk:blank_bombs_desc": "_Пустота_", "bk:explosive_bullets": "Бомбические пули", "bk:explosive_bullets_desc": "Взрываются", "bk:random_bullets": "Случайные пули", "bk:random_bullets_desc": "Заруинет ваш забег (или спасет)", "bk:cup": "Чашка", "bk:cup_desc": "Бабуля не сможет не прийти", "bk:cartridge": "Картридж", "bk:cartridge_desc": "Темный Маг обещал зайти поиграть", "bk:marriage_ring": "Обручальное кольцо", "bk:marriage_ring_desc": "Темный Маг & Бабуля навсегда!", "boxy_7": "Я хочу ключей", "boxy_8": "У тебя не достаточно ключей :(", "boxy_9": "Теперь у меня хватает ключей чтобы ^^открыться^^!", "roger_3": "Я не против если ты заплатишь", "roger_4": "Сегодня нет скидок", "roger_5": "Бомбы вперед", "vampire_7": "Ты нездоров", "vampire_8": "Я не даю скидок", "vampire_9": "Кажется, уровень твоего здоровья оставляет желать лучшего.", "ach_bk:scourged": "Проклятый", "ach_bk:scourged_desc": "Получи токен проклятия", "ach_bk:scourged_weapon": "Проклятое оружие", "ach_bk:scourged_weapon_desc": "Получи проклятое оружие", "rerolled": "Зарероленно", "ach_bk:open_up": "Открывашка", "ach_bk:open_up_desc": "Купи всё в магазине Бокси", "ach_bk:snek": "Змея в сапоге", "ach_bk:snek_desc": "Заполучи торговца змея в качестве питомца", "bk:scourge_of_greed": "Проклятие жадности", "bk:scourge_of_greed_desc": "Высокие цены", "killed_by": "Убийца", "kills": "Убито существ", "time": "Время", "depth": "Уровень", "bk:blank_bullets": "Пустые пули", "bk:blank_bullets_desc": "Пусто", "bk:lego": "Конструктор", "bk:lego_desc": "На него так больно наступать...", "bk:iron_armor": "Стальная броня", "bk:iron_armor_desc": "Даёт щиты", "bk:round_shield": "Круглый щит", "bk:round_shield_desc": "Иммунитет к контактному урону", "bk:arkhalis": "Аркалис", "bk:arkhalis_desc": "Легендарный меч", "bk:inverted_arkhalis": "Анти-Аркалис", "bk:inverted_arkhalis_desc": "Подмога при 1 _HP_", "bk:gun_sword": "Пушкамеч", "bk:gun_sword_desc": "Мутант", "ach_bk:scourge_king_desc": "Живи теперь с этим", "ach_bk:scourge_king": "Проклятый Король", "ach_bk:sting_operation": "Жальная операция", "ach_bk:sting_operation_desc": "Победи Королеву Пчелу", "ach_bk:mummified": "Мумифицирован", "ach_bk:mummified_desc": "Победи Фараона", "ach_bk:democracy": "Демократия", "ach_bk:democracy_desc": "Победи Короля", "pharaoh_scream": "##ПРИГОТОВЬСЯ СТАТЬ МУМИЕЙ!##", "queen_bee_scream": "##ЗА [cl yellow]HONEY LORD'A[cl]!##", "bk:half_heart": "Пол сердца", "right": "Вправо", "down": "Вниз", "left": "Влево", "up": "Вверх", "painting_cat": "Кот", "bk:axe": "Топор", "bk:axe_desc": "Он улетел, но обещал вернуться", "bk:guitar": "Гитара", "bk:guitar_desc": "Сильно расстроена.", "bk:glass_sword": "Стеклянный Меч", "bk:glass_sword_desc": "Оружие мастеров", "bk:chicken": "Крылышко", "bk:chicken_desc": "Ай, пальчики обжёг", "bk:pickaxe": "Кирка", "bk:pickaxe_desc": "Копай давай", "bk:mana": "Мана", "bk:half_mana": "Пол-очка Маны", "bk:lava_wand": "Посох лавы", "bk:lava_wand_desc": "Горячий", "bk:web_wand": "Паучий посох", "bk:web_wand_desc": "Провайдер web-сервисов", "bk:slap_stick": "Палка-шлепалка", "bk:slap_stick_desc": "Шлёп", "sensivity": "Чувствительность", "no": "Нет", "scale": "Приближение", "ach_bk:ice": "Ледниковый период", "ach_bk:ice_desc": "Доберись до Ледяных развалин", "ach_bk:library": "Пропавшие тексты", "ach_bk:library_desc": "Доберись до Секретной бибилотеки", "bk:ice_skates": "Коньки", "bk:ice_skates_desc": "Иммунитет ко льду", "bk:campfire_in_bottle": "Костёр в бутылке", "bk:campfire_in_bottle_desc": "Иммунитет к заморозке", "library": "Секретная библиотека", "ach_bk:cat_without_a_hat": "Кот без шляпы", "ach_bk:cat_without_a_hat_desc": "Найди картину с Котом", "ach_bk:rich": "Туалетная бумага", "ach_bk:rich_desc": "Собери 99 монет", "ach_bk:rescue_operation": "Спасательная операция", "ach_bk:rescue_operation_desc": "Спаси NPC", "ach_bk:tutorial": "Гуру", "ach_bk:tutorial_desc": "Закончи туториал", "ach_bk:fancy_hat": "Клевая шляпа", "ach_bk:fancy_hat_desc": "Купи шляпу", "ach_bk:unlock": "Открыватель", "ach_bk:unlock_desc": "Разблокируй предмет", "floor_brightness": "Яркость пола", "ach_bk:shielded": "Поднять щиты", "ach_bk:shielded_desc": "Заполучи сердце-щит", "run_type": "Тип забега", "run_regular": "Обычный", "run_challenge": "Испытание", "damage_taken": "Урон получен", "km": "км", "distance_traveled": "Дистанция", "seed": "Сид", "score": "Счет", "new_high_score": "Новый рекорд!", "items_collected": "Вещей собрано", "boss_rush": "Босс-раш", "run_bossrush": "Босс-раш", "bk:blindfold": "Повязка", "daily_run": "Дейлик", "builder_0_0": "Да", "builder_0_1": "Мне самому нужны деньги", "builder_0": "Я планирую построить туннель сюды, но мне нужно еще [vr need] [ic 0]. Можешь помочь?", "builder_1": "Но у тебя вообще нет денег!", "builder_2": "Спасибо за инвестицию!", "builder_3": "У меня наконец достаточно денег для окончания этого проекта! Спасибо огромное!", "builder_4": "Ок, прости!", "shortcut_is_broken": "Туннель сломан", "ach_bk:boss_rush": "Покоритель боссов", "ach_bk:boss_rush_desc": "Победи всех боссов в Босс-раше", "ach_bk:daily": "Дневная слава", "ach_bk:daily_desc": "Выйграй дейлик", "ach_bk:desert_shortcut": "Пустынный туннель", "ach_bk:desert_shortcut_desc": "Почини туннель, ведущий в Пустынный дворец", "ach_bk:jungle_shortcut": "Туннель в джунгли", "ach_bk:jungle_shortcut_desc": "Почини туннель, ведущий в Древние джунгли", "ach_bk:ice_shortcut": "Ледяной туннель", "ach_bk:ice_shortcut_desc": "Почини туннель, ведущий в Ледяные развалины", "ach_bk:library_shortcut": "Туннель в библиотеку", "ach_bk:library_shortcut_desc": "Почини туннель, ведущий в Секретную библиотеку", "ach_bk:fashion_matters2": "Мода важна", "ach_bk:fashion_matters2_desc": "Купи все шапки", "ach_bk:10_challenges": "Упорный", "ach_bk:10_challenges_desc": "Выполни 10 вызовов", "ach_bk:20_challenges": "Упорный 2.0", "ach_bk:20_challenges_desc": "Выполни 20 вызовов", "ach_bk:30_challenges": "Упорный 3.0", "ach_bk:30_challenges_desc": "Выполни 30 вызовов", "ach_bk:bk_no_more": "Конец Горящему рыцарю", "ach_bk:bk_no_more_desc": "Победи самого Горящего рыцаря", "ach_bk:dm_no_more": "Конец Тёмному магу", "ach_bk:dm_no_more_desc": "Победи Тёмного мага", "ach_bk:egor_no_more": "Конец Егору", "ach_bk:egor_no_more_desc": "(ツ)", "ach_bk:loop": "Давай по новой...", "ach_bk:loop_desc": "Войди в петлю", "coins_collected": "Монет собрано", "bk:cup_head": "Чашкаголова", "bk:cup_head_desc": "Выпей чаю", "bk:mustache_hat": "Усы", "bk:mustache_hat_desc": "AFK", "bk:propeller_hat": "Шапка с моторчиком", "bk:propeller_hat_desc": "Он крутится", "bk:sunglasses": "Солнечные очки", "bk:sunglasses_desc": "Также работают с Луной!", "bk:cap": "Кепка", "bk:cap_desc": "Крутой @-@", "bk:eyes": "Глаза", "bk:eyes_desc": "@ @", "bk:eye": "Глаз", "bk:eye_desc": "@", "bk:hair": "Волосы", "bk:hair_desc": "Ну наконец", "won": "Победа", "won_message": "Ты победил!", "garderobe_sign": "Гардероб", "darkmarket_tip": "~~[cl purple]Проклятие[cl] или [cl yellow]30 монет[cl]@@", "mike_0": "Заплати мне [cl green]3 изумруда", "mike_1": "Попробуй Босс-раш всего за [cl green]3 изумруда[cl]!", "bk:weird_potion": "Стрёмное-зелье", "bk:weird_potion_desc": "Странные пули", "bk:megaphone": "Мегафон", "bk:megaphone_desc": "Увелечение пуль", "scourge": "Проклятия", "scourge_stats": "Проклятия", "run_daily": "Дейлик", "completed_on": "Достигнуто", "complete": "достигнуто", "next_daily_in": "[cl gray]Следующий начинается через[cl]", "hours": "часов", "minutes": "минут", "seconds": "секунд", "ach_bk:star": "Звезда Шоу", "ach_bk:star_desc": "Собери 3 орбитала", "ach_bk:family": "Счастливая семья", "ach_bk:family_desc": "Собери 3 питомца", "ach_bk:return_to_sender": "No U", "ach_bk:return_to_sender_desc": "Убей врага его же пулей", "ach_bk:van_no_gogh": "Ван Не Гог", "ach_bk:van_no_gogh_desc": "Сломай 100 картин", "ach_bk:boom": "Цепная реакция", "ach_bk:boom_desc": "Взорви цепь из 3 динамитов", "ach_bk:dark_market": "Криминальная нычка", "ach_bk:dark_market_desc": "Спустись в Тёмный рынок", "ach_bk:spikes": "Шипами Замок не испортишь", "ach_bk:spikes_desc": "Активируй 100 шипов за 1 забег", "ach_bk:white_flag": "Пацифист", "ach_bk:white_flag_desc": "Зачисти комнату не используя оружия", "quack": "[cl yellow]Кряк![cl]", "pixel_perfect": "Pixel Perfect", "bk_11": "Я ПРОЩАЮ ТЕБЯ. НО ##НЕ ДЕЛАЙ## ЭТО ОПЯТЬ!", "leaderboard": "Таблица рекордов", "display": "Фильтр", "around_you": "Вокруг Тебя", "friends": "Друзья", "global": "Все", "loading": "Загружаем", "generating": "Генерируем", "cursor_radius": "Радиус Курсора", "no_scores_yet": "Еще нет счетов", "no_score_yet": "Еще нет счета", "run": "Забег", "top": "Топ", "quick_restart": "Быстрый рестарт", "painting_dungeon": "Замок", "painting_goose": "Мини-гусь", "painting_chess": "Летучий слон", "painting_peach": "Персиковое дерево", "bk:no_lamp": "Нет лампы", "bk:explosive_lamp": "Взрывная лампа", "bk:explosive_lamp_desc": "Когда ты слишком любишь все взрывать", "bk:shielded_lamp": "Щитовая лампа", "bk:shielded_lamp_desc": "Поднять щиты!", "lamp": "Лампа", "bk:brain": "Мегамозг", "bk:brain_desc": "Что если использовать разум на 100%", "bk:heart_amulet": "Сердечный амулет", "bk:heart_amulet_desc": "+1 к размеру сердца", "bk:star_amulet_desc": "+1 к Мане", "bk:star_amulet": "Звёздный амулет", "bk:coin_amulet": "Денежный амулет", "bk:coin_amulet_desc": "Ценность монет выше", "bk:key_amulet": "Амулет ключей", "bk:key_amulet_desc": "Ключей дается больше", "bk:bomb_amulet": "Бомбический амулет", "bk:bomb_amulet_desc": "Бомб даётся больше", "bk:eye_amulet": "Глазной амулет", "bk:eye_amulet_desc": "Как же больно быть неточным", "bk:eye_patch": "Повязка на глаз", "bk:eye_patch_desc": "Так точно капитан!", "bk:toilet_paper": "Туалетная бумага", "bk:toilet_paper_desc": "Всегда заканчиватся", "bk:decoy": "Приманка", "bk:decoy_desc": "Она взрывается", "bk:wallet": "Кошелёчек", "bk:wallet_desc": "Хранит деньги", "bk:skele_buddy": "Хранитель замка", "bk:skele_buddy_desc": "Стрёмный", "bk:mega_bomb": "Мегабомба", "bk:mega_bomb_desc": "Мега бом-бом!", "bk:condensed_milk": "Сгущёнка", "bk:condensed_milk_desc": "Шустрые пиксели — медленные противники", "bk:marshmallow": "Маршмеллоу X_X", "bk:marshmallow_desc": "Липкая штука", "bk:orbital_multiplier": "Множитель орбиталов", "bk:orbital_multiplier_desc": "Больше орбиталов богу орбиталов!", "bk:pet_multiplier": "Множитель питомцев", "bk:pet_multiplier_desc": "Больше питомцев!", "bk:ghost_bullets": "Пули-привидения", "bk:ghost_bullets_desc": "Стены не помеха", "bk:weight": "Гиря", "bk:weight_desc": "Усиливает гравитацию", "bk:d2": "Д2", "bk:d2_desc": "Возьми или оставь", "bk:ethernal_d6": "Небесный Д6", "bk:ethernal_d6_desc": "Рероллит и\/или уничтожает", "bk:billiard": "Бильярдный шар", "bk:billiard_desc": "Пули отскакивают от пуль", "bk:enraged_bullets": "Разозленные пули", "bk:enraged_bullets_desc": "Пули ломают пули", "bk:rewind_button": "Кнопка Перемотки", "bk:rewind_button_desc": "Исправь своё будещее", "bk:piggy_bank": "Свинка-копилка", "bk:piggy_bank_desc": "Мои сбережения", "coins": "Монеты", "bk:death_star": "Звезда смерти", "bk:death_star_desc": "RIP Альдеран", "bk:soldering_iron": "Паяльник", "bk:soldering_iron_desc": "Горячий", "bk:can": "Банка", "bk:can_desc": "Удвоенные пули", "bk:swimming_mask": "Плавательная маска", "bk:swimming_mask_desc": "Секретное оружие", "bk:bullet_chair": "Реактивный стул", "bk:bullet_chair_desc": "4 ноги 4 пухи", "bk:cell": "Клетка", "bk:cell_desc": "Пули рождаются", "bk:brick": "iКирпич", "bk:brick_desc": "Оверпрайснутые уровни", "bk:ring_of_pain": "Кольцо Боли", "bk:ring_of_pain_desc": "Получение урона бьет всех", "bk:schrodingers_cat": "Кот Шредингера", "bk:schrodingers_cat_desc": "Бить или не быть (50% шанс)", "bk:smoke_bomb": "Дымовуха", "bk:smoke_bomb_desc": "Побег в стиле ниндзя", "bk:chest_ring": "Кольцо сундуков", "bk:chest_ring_desc": "Больше сундуков!", "bk:empty_shell": "Пустая гильза", "bk:empty_shell_desc": "Шанс уничтожить пули противников", "bk:parachute": "Парашют", "bk:parachute_desc": "Иммунитет к дыркам", "bk:spiked_cookie": "Шипастая печенька", "bk:spiked_cookie_desc": "Я бы её не съел", "bk:shooty": "Стреляка", "bk:shooty_desc": "Он стреляет", "bk:rabbit_bullets": "Кроличьи пули", "bk:rabbit_bullets_desc": "Они размножаются", "bk:pandoras_box": "Коробка Пандоры", "bk:pandoras_box_desc": "Ты должен был бороться со злом!", "bk:bubbles": "Мыльные пузыри", "bk:bubbles_desc": "Друг", "bk:match": "Спичка", "bk:match_desc": "Огонь для всех", "bk:hammer": "Молот", "bk:hammer_desc": "Я твою броню ломал", "bk:helmet": "Стальной шлем", "bk:helmet_desc": "Шанс не получить урон", "bk:beer": "Пивко", "bk:beer_desc": "Урон вызывает злость", "bk:the_eye": "Глазик", "bk:the_eye_desc": "Он смотрит", "bk:mimics_tooth": "Зуб Мимика", "bk:mimics_tooth_desc": "Притягивает Мимиков", "ach_bk:mimic": "Рояль в кустах", "ach_bk:mimic_desc": "Найди мимика", "bk:paper_airplane": "Бумажный самолётик", "bk:paper_airplane_desc": "Самонаводящиеся пули", "ach_bk:ice_boss": "Отпусти её, да забудь", "ach_bk:ice_boss_desc": "Убей Снежную королеву", "ice_queen_scream": "^^[cl cyan]Кхе-кхе", "painting_agency": "Добро пожаловать в агенство", "painting_horatio": "Гораций", "painting_zweihandler": "Звейгандлер", "language": "Язык", "bk:pouch": "Мешочек", "bk:alien_glasses": "Инопланетные очки", "bk:alien_glasses_desc": "Я вижу больше", "inventory": "Хлам", "bk:led": "Светодиод", "bk:led_desc": "Точная лампа", "bk:fragile_lamp": "Хрупкая лампочка", "bk:fragile_lamp_desc": "1 хит K.O.", "painting_guitar": "Больше Звука!", "ach_bk:maanex": "И ты, Брут?", "ach_bk:maanex_desc": "Убей Маанекса с его шляпой на голове", "dad_0": "Сын, [dl] я ухожу искать [cl red]Лампу[cl]. Я оставляю тебя править вместо меня.", "dad_1": "Если я не вернусь, не ищи меня. Прощай!", "son_0": "##НЕЕЕЕТ##", "gobbo_0": "Сын, [cl green]мой отец[cl] оставил меня 20 лет назад. Я отправляюсь его искать.", "gobbo_1": "Ты остаёшься за главного. Расти большой, не будь лапшой. Прощай!", "dm_5": "Новая и ^^улучшенная^^ [cl red]марионетка[cl]![dl] ##АХАХАХА##", "dm_6": "Ты слышишь меня, [cl red]Лимпор?", "heinur_0": "##НЕТ[dl], ТОЛЬКО НЕ ОПЯТЬ!##", "nbk_0": "##ДА, МОЙ ПОВЕЛИТЕЛЬ##", "bk_12": "##У МЕНЯ ЗАКОНЧИЛИСЬ СОСУДЫ, ТАК ЧТО ДЕРИСЬ СО МНОЙ, ГЛУПЕЦ!##", "bk:headshot_gun": "Погнутый пистоль", "bk:headshot_gun_desc": "Headshot", "bk:laser_cannon": "Лазерная пуха", "bk:laser_cannon_desc": "Не канон", "credits": "Кредиты", "head_0": "Глупец", "tech": "Техно", "ach_bk:collector": "Коллектор", "ach_bk:collector_desc": "Собери все предметы", "bk:treasure_key": "Красный ключ", "bk:treasure_key_desc": "Открывает временные дыры", "bk:pass": "Пропуск", "bk:pass_desc": "Ты кто?", "bk:bucket": "Ведро", "bk:bucket_desc": "Бесполезно само по себе", "bk:water_bucket": "Ведро с водой", "bk:water_bucket_desc": "Тушит [cl red]Огонь[cl]", "bk:snow_bucket": "Ведро со снегом", "bk:snow_bucket_desc": "А снег не растает?", "m2_0": "Я обанкротился", "m2_1": "Красавчик!", "m2_2": "Эй, не хочешь ^^потесить^^ свой %%скилл%%?", "m2_3": "Используй ^^%%Компуктор%%^^ чтоб управлять [cl yellow]Клешнёй[cl]!", "maanex2_0_0": "Погнали!", "maanex2_0_1": "Не в этот раз, спс.", "maanex2_0": "Дай мне [cl yellow][vr cost] монет[cl] и я дам тебе одну попытку!", "dm_7": "Давай поиграем", "bkw_0": "ЕЩЕ ОДИН [cl red]ШПИОН[cl]!", "bkw_1": "##МАРШ ОТСЮДА##[dl], ИЛИ Я ТЕБЯ ЗАСТАВЛЮ!", "bkw_2": "Но я ищу [cl green]своего отца[cl]...", "bkw_3": "Я ТЕБЯ _ПРЕДУПРЕДИЛ_", "spanish_inquisition": "[cl red]Испанская инквизиция", "lp_0": "Молодец, [cl purple]Рита[cl][dl], перезапускаю [cl green]симуляцию[cl][dl].[dl].[dl].", "bk:broken_bucket": "Сломанное ведро", "bk:broken_bucket_desc": "Бульк", "bk:ankh": "Анкх", "bk:ankh_desc": "Жизнь Свыше", "bk:broken_ankh": "Сломанный Анкх", "bk:broken_ankh_desc": "Жизнь Свыше?", "bk:what": "Что", "bk:what_desc": "Серьезно, ЧТО?", "bk:gold_minigun": "Золотой миниган", "bk:gold_minigun_desc": "Хаха, прощай бюджет", "bk:gold_dagger": "Золотой кинжал", "bk:gold_dagger_desc": "Мал да удал", "bk:gold_revolver": "Золотой Револьвер", "bk:gold_revolver_desc": "Покрой меня золотом", "bk:gold_axe": "Золотой топор", "bk:gold_axe_desc": "Вот ответ на все вопросы", "painting_code": "Код", "bk:katana": "Катана", "bk:katana_desc": "Кто же [cl orange]хозяин[cl]?", "bk:smart_gun": "Умный пистолет", "bk:smart_gun_desc": "Он знает", "bk:pop_gun": "Хлопушка", "bk:pop_gun_desc": "Очень популярная", "bk:the_button": "Кнопка", "bk:the_button_desc": "Бласт-волна", "bk:gold_sword": "Золотой меч", "bk:gold_sword_desc": "Когда денег столько, что девать их некуда", "bk:donut": "Пончик", "bk:donut_desc": "Не сопротивляйся", "bk:sudoku": "Судоку", "bk:sudoku_desc": "Сносит половину комнаты", "bk:gps_ring": "GPS Кольцо", "bk:gps_ring_desc": "Шанс полностью открыть карту", "bk:shield_potion": "Щитовое зелье", "bk:shield_potion_desc": "Дает... щиты!", "bk:trash_generator": "Генератор мусора", "bk:trash_generator_desc": "Угу.", "bk:crabs_claw": "Клешня краба", "bk:crabs_claw_desc": "Ломает любую броню", "eg_3": "Доброго времени суток", "eg_0_0": "Взять ^^[cl lime]изумруды[cl]^^", "eg_0_1": "Оставить", "eg_0": "Прошу тебя, возьми [cl lime]мои изумруды[cl]!", "eg_1": "Пожалуй, я пойду, всего хорошего", "bk:reverse_card": "Карта смены хода", "bk:reverse_card_desc": "Перекат через пули отражает их", "bk:magnet": "Магнит", "bk:magnet_desc": "Притягивает сомнительные личности", "bk:glowing_mushroom": "Шапка трюфеля", "bk:glowing_mushroom_desc": "Ему классно", "bk:tinfoil_hat": "Шапочка из фольги", "bk:tinfoil_hat_desc": "Ощущение безопасности", "bk:rear_window": "Зеркало заднего вида", "bk:rear_window_desc": "Прикроет спину", "bk:refractor": "Отражатель", "bk:refractor_desc": "Шанс атаковать во все направления", "bk:fork": "Вилка", "bk:fork_desc": "Один удар — четыре дырки", "bk:rock": "Каменюга", "bk:rock_desc": "Урон за плату", "bk:coffee_grinder": "Кофемолка", "bk:coffee_grinder_desc": "Мелкие и быстрые пульки", "integrations": "Интеграции", "twitch": "Твитч", "streamer_username": "Ник Стримера", "bk:shawarma": "Шавуха", "bk:shawarma_desc": "Иногда пули больше", "bk:cats_ear": "Ухо кота", "bk:cats_ear_desc": "Sick dodge", "luck": "Удача", "bk:gamepad": "Геймпад", "bk:gamepad_desc": "Стабильный FPS", "bk:hotdog": "Стильный хот-дог", "bk:hotdog_desc": "Удача & _HP_", "bk:bomb_shell": "Оболочка бомбы", "bk:bomb_shell_desc": "Странное здоровье", "painting_no_idea": "Без понятия", "painting_tinkerer": "Мыслитель", "painting_in_loving_memory_of_ali": "В память об Али", "painting_happy_accident": "Счастливая случайность", "painting_observing_cheese": "Наблюдая сыр", "painting_chicken_enemy_unknown": "Куриный враг неизвестен", "painting_know_stuff": "Знай", "painting_whoops": "Упс", "painting_too_lake": "Слишком мокро", "painting_step_through": "Переход", "painting_thats_a_moon": "Это луна", "painting_totem": "Магический круг", "painting_too_late": "Слишком поздно", "painting_whipped_cream": "Взбитые сливки", "painting_beet_boys": "Редиски", "painting_moonshine": "Лунный свет", "painting_void": "Пустота", "painting_peasants": "Работники", "logged_in_as": "Залогинен как", "not_logged_in": "Не залогинен", "failed_to_login": "Попытка залогинится провалилась", "logging_in": "Логинимся[dl].[dl].[dl].", "twitch_0": "Pog!", "twitch_1_0": "Нда", "twitch_1_1": "Ннет", "twitch_1": "Ты хочешь врубить режим Стримера?", "twitch_2": "Скажи мне твой ник на Твитче!", "twitch_3": "Добро пожаловать в чат, [cl purple]@[vr username][cl]!", "twitch_4": "Окейла.", "twitch_5_0": "Угу", "twitch_5_1": "Нее", "twitch_5": "Твой ник на твитче [cl purple]@[vr username][cl]. Хочешь изменить его?", "run_twitch": "Твитч", "happening_bk:hurt": "Ауч", "happening_bk:big_hurt": "Большой ауч", "happening_bk:omega_hurt": "ОМЕГА АУЧ", "happening_bk:confused": "Конфуз", "happening_bk:snail": "Улитка", "happening_bk:broken": "Сломанная бронь", "happening_bk:darkness": "Минус свет", "happening_bk:scourge_token": "Плохой токен", "happening_bk:risk": "Скрытое здоровье", "happening_bk:double_trouble": "Двойные проблемы", "happening_bk:rage": "Приступ злости", "happening_bk:regular_tp": "Телепорт", "happening_bk:reset": "Хард-ресет", "happening_bk:sudoku": "Судоку", "happening_bk:items_hurt": "Предметы бьют", "happening_bk:scourged": "Загрязние", "happening_bk:reroll_items": "Реролл", "happening_bk:reroll_weapon": "Новые оружия", "happening_bk:nerf": "Нерф", "happening_bk:rob": "Кража", "happening_bk:steal": "Минус оружие", "happening_bk:give_artifact": "Рандомный артифакт", "happening_bk:give_weapon": "Рандомное оружие", "happening_bk:give_random_item": "Рандомный предмет", "happening_bk:give_random_consumable": "Рандомный пикап", "happening_bk:invincible": "Неуязвимость", "happening_bk:treasure_tp": "Кладоискатель", "happening_bk:small_heal": "Нанохилка", "happening_bk:heal": "Хилка", "happening_bk:omega_heal": "ОМЕГА ХИЛКА", "happening_bk:shielded": "Защита", "happening_bk:cleanse": "Очищение", "happening_bk:chest": "Сокровище", "happening_bk:buffed": "Баффнут", "happening_bk:gift": "Подарок", "happening_bk:entrance_tp": "Опять 25", "happening_bk:exit_tp": "Пора валить", "twitch_next": "Что будет дальше?", "total_votes": "голоса", "bk:gold_lamp": "Золотая лампа", "bk:gold_lamp_desc": "Время — деньги, а денег что? Мало.", "bk:sharp_lamp": "Острая Лампа", "bk:sharp_lamp_desc": "Для любителей Melee", "bk:ancient_sword": "Древний Меч", "bk:ancient_sword_desc": "Супер старая палка", "ach_bk:unstoppable": "Неостановимый", "ach_bk:unstoppable_desc": "Пройди игру с любой лампой", "no_emeralds": "Нет изумрудов", "bk:emerald_gun": "Изумрудный пистоль", "bk:emerald_gun_desc": "Самое дорогое оружие в стране", "minimap": "Миникарта", "quality": "Качество", "normal": "Нормальное", "potato": "Картошка", "happening_bk:bomb": "Взрывная атака", "happening_bk:slide": "Ледниковый период", "20_years_later": "20 лет спустя", "painting_ducktective": "Селезень-сыщик", "boss_oldking" : "Старый Король", "boss_pharaoh" : "Фараон", "boss_queenbee" : "Королева Пчела", "boss_icequeen" : "Королева Льда", "boss_burningknight" : "Горящий Рыцарь", "boss_dm" : "Темный Маг", "painting_bug" : "Не баг, а фича!", "revive" : "Воскресить", "cave": "Изумрудные Пещеры", "coop_sign": "Нажми любую кнопку на геймпаде, чтобы присоединиться", "bk:party_hat": "Парти Шапка", "bk:party_hat_desc": "Почему же мне так грустно", "bk:police_hat": "Полишапка", "bk:police_hat_desc": "Держис подальше от порталов", "bk:spike_hat": "Шипошляп", "bk:spike_hat_desc": "Тык", "bk:hood": "Плащ", "bk:hood_desc": "Найди кольцо", "bk:bullet_hat": "Пустая Гильза", "bk:bullet_hat_desc": "Пиу", "remove_player" : "Зажми [ic 0] чтобы убрать игрока", "bk:spook": "Спук", "bk:spook_desc": "Бу", "bk:mask": "Маска", "bk:mask_desc": "Оставайся на 127.0.0.1", "bk:sword_polish": "Масло Для Меча", "bk:sword_polish_desc": "Большие Мелее Аттаки", "bk:pumpkin_juice": "Тыквенный Сок", "bk:pumpkin_juice_desc": "Балдеж", "bk:bouncy_glove": "Прыгучая Перчатка", "bk:bouncy_glove_desc": "Бонкь", "seeded": "(сидованный)" } ================================================ FILE: BurningKnight/Content/README.txt ================================================ https://bit.ly/2SMSOLM ================================================ FILE: BurningKnight/Content/Shaders/bk.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif Texture2D SpriteTexture; sampler s0; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float time; float a; float2 pos; float2 size; float4 MainPS(VertexShaderOutput input) : COLOR { float2 cof = float2(1.0 / size.x, 1.0 / size.y); float x = (pos.x - input.TextureCoordinates.x) * cof.x; float y = (pos.y - input.TextureCoordinates.y) * cof.y; float v = floor(sin(time * 4.0 + y * 8.0)); float2 ps = float2( clamp(input.TextureCoordinates.x + v / (cof.x * 10.0), pos.x, pos.x + size.x), clamp(input.TextureCoordinates.y + floor(sin(time * 2.0 + x)) / (cof.y * 20.0), pos.y, pos.y + size.y) ); float4 color = tex2D(s0, ps); float xx = (ps.x - pos.x) * cof.x; float yy = (ps.y - pos.y) * cof.y; float dx = (xx - 0.5); float dy = (yy + 0.5); float d = sqrt(dx * dx + dy * dy); float sum = max(0.0, 1.41 - d * 2.0 + cos(time * 1.4)); color.r = min(1.0, sum + color.r); color.g = min(1.0, sum + color.g); color.b = min(1.0, sum + color.b); return float4(1.0, abs(cos(time * 2.0) / 2.5) + color.g, color.b * 0.5, color.a * a); } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/chasm.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif Texture2D SpriteTexture; sampler s0; // Flash float y; float h; bool enabled; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float4 MainPS(VertexShaderOutput input) : COLOR { float4 color = tex2D(s0, input.TextureCoordinates); if (enabled) { color.rgb = color.rgb * (1 - (input.TextureCoordinates.y - y) / h); } return color; } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/entity.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif Texture2D SpriteTexture; sampler s0; // Flash float flash; float flashReplace; float4 flashColor; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float4 MainPS(VertexShaderOutput input) : COLOR { float4 color = tex2D(s0, input.TextureCoordinates); if (flash > 0.01f && color.a > 0.01f) { if (flashReplace > 0.5f) { color = flashColor * flash; } else { color += flashColor * flash; } } return color; } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/fog.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; Texture2D SpriteTexture; sampler s0; float time; float cx; float cy; float tx; float ty; #define mod(x,y) (x-y*floor(x/y)) sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; float4 MainPS(VertexShaderOutput input) : COLOR { float v = (tex2D(s0, float2( mod(input.TextureCoordinates.x + cx + tx * time, 1.0), mod(input.TextureCoordinates.y + cy + ty * time, 1.0) )).r * cos(time * 100.0 + tex2D(s0, float2( mod(input.TextureCoordinates.x + cx + tx * time, 1.0), mod(input.TextureCoordinates.y + cy + ty * time, 1.0) )).r * 10.0) * 0.5 + 0.5); return float4(v, v, v, v * 0.15f);//v * (1 - smoothstep(0.75f, 0.3f, length(input.TextureCoordinates - float2(0.5f, 0.5f))))); } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/item.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif Texture2D SpriteTexture; sampler s0; float time; float size; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float4 MainPS(VertexShaderOutput input) : COLOR { float4 color = tex2D(s0, input.TextureCoordinates); if ((time + input.TextureCoordinates.x + input.TextureCoordinates.y) % 0.5f < size) { color.r = 1; color.g = 1; color.b = 1; } return color; } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/screen.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_5_0 #define PS_SHADERMODEL ps_5_0 #endif Texture2D SpriteTexture; sampler s0; float blur; float split; bool vignette; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float4 MainPS(VertexShaderOutput input) : COLOR { float4 color; if (split > 0.001f) { float smx = 1.0f / 320 * split; float smy = 1.0f / 180 * split; float4 l = tex2D(s0, float2(input.TextureCoordinates.x + smx, input.TextureCoordinates.y + smy)); color = float4(l.r, tex2D(s0, float2(input.TextureCoordinates.x, input.TextureCoordinates.y)).g, tex2D(s0, float2(input.TextureCoordinates.x - smx, input.TextureCoordinates.y - smy)).b, l.a); } else { color = tex2D(s0, float2(input.TextureCoordinates.x, input.TextureCoordinates.y)); } float v = 1.0f; if (vignette) { v = smoothstep(0.75f, 0.2f, length(input.TextureCoordinates - float2(0.5f, 0.5f))) * 0.75f + 0.25f; } if (blur > 0.001f) { float mx = 1.0f / 320 * blur; float my = 1.0f / 180 * blur; for (int xx = -2; xx < 3; xx++) { for (int yy = -2; yy < 3; yy++) { if (xx != 0 || yy != 0) { color += tex2D(s0, input.TextureCoordinates + float2(mx * xx , my * yy)) / sqrt(xx * xx + yy * yy); } } } color /= 14.8203f; } return color * v; } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/terrain.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_4_0_level_9_1 #define PS_SHADERMODEL ps_4_0_level_9_1 #endif struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; Texture2D SpriteTexture; sampler s0; bool enabled; float2 tilePosition; float2 edgePosition; float flow; float time; float sy; float h; #define mod(x,y) (x-y*floor(x/y)) sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; float4 MainPS(VertexShaderOutput input) : COLOR { float cy = input.TextureCoordinates.y; if (flow > 0.1f) { cy -= tilePosition.y; cy -= time * flow - sy; cy -= h * floor(cy / h); cy += tilePosition.y; } float4 color = tex2D(s0, float2(input.TextureCoordinates.x, cy)); if (enabled == true) { float4 mask = tex2D(s0, float2( input.TextureCoordinates.x - tilePosition.x + edgePosition.x, input.TextureCoordinates.y - tilePosition.y + edgePosition.y )); if (mask.r == 1 && mask.g == 0 && mask.b == 0 && mask.a == 1) { if (flow > 0.6f) { color.a = 0.5f; } return color; } return mask; } return color; } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/Shaders/ui.fx ================================================ #if OPENGL #define SV_POSITION POSITION #define VS_SHADERMODEL vs_3_0 #define PS_SHADERMODEL ps_3_0 #else #define VS_SHADERMODEL vs_5_0 #define PS_SHADERMODEL ps_5_0 #endif Texture2D SpriteTexture; sampler s0; float black; float bx; float by; float bottom; sampler2D SpriteTextureSampler = sampler_state { Texture = ; }; struct VertexShaderOutput { float4 Position : SV_POSITION; float4 Color : COLOR0; float2 TextureCoordinates : TEXCOORD0; }; float4 MainPS(VertexShaderOutput input) : COLOR { if (black < 1.0f) { float dx = input.TextureCoordinates.x - bx; float dy = (input.TextureCoordinates.y - by) * 0.5625f; if (sqrt(dx * dx + dy * dy) > black) { return float4(0, 0, 0, 1); } } return 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)); } technique SpriteDrawing { pass P0 { PixelShader = compile PS_SHADERMODEL MainPS(); } }; ================================================ FILE: BurningKnight/Content/achievements.json ================================================ { "bk:overshake": { "secret": true }, "bk:rip": {}, "bk:marauder": { "group": "b" }, "bk:treasure_hunter": {}, "bk:dodge_master": { "group": "b" }, "bk:dodge_overlord": { "group": "b" }, "bk:quackers": { "secret": true }, "bk:not_a_thief": { "secret": true }, "bk:npc_party2": { "max": 13, "group": "c" }, "bk:scourge_king": { "group": "b" }, "bk:deal": {}, "bk:grannys_gift": {}, "bk:shopper": {}, "bk:desert": { "group": "a" }, "bk:jungle": { "group": "a" }, "bk:scourged": {}, "bk:scourged_weapon": {}, "bk:open_up": { "group": "b" }, "bk:snek": { "group": "b" }, "bk:sting_operation": { "group": "d" }, "bk:mummified": { "group": "d" }, "bk:democracy": { "group": "d" }, "bk:ice": { "group": "a" }, "bk:library": { "group": "a" }, "bk:cat_without_a_hat": { "group": "c" }, "bk:rich": { "group": "b" }, "bk:rescue_operation": { "group": "c" }, "bk:tutorial": {}, "bk:fancy_hat": {}, "bk:unlock": {}, "bk:shielded": {}, "bk:boss_rush": { "group": "d" }, "bk:daily": { "group": "d" }, "bk:desert_shortcut": { "group": "a" }, "bk:jungle_shortcut": { "group": "a" }, "bk:ice_shortcut": { "group": "a" }, "bk:library_shortcut": { "group": "a" }, "bk:fashion_matters2": { "max": 29 }, "bk:ice_boss": { "group": "d" }, "bk:bk_no_more": { "group": "d" }, "bk:dm_no_more": { "secret": true }, "bk:loop": {}, "bk:star": { "unlock": "bk:star" }, "bk:family": {}, "bk:return_to_sender": { "group": "d" }, "bk:van_no_gogh": {}, "bk:dark_market": {}, "bk:spikes": { "unlock": "bk:iron_boots" }, "bk:white_flag": {}, "bk:mimic": { "unlock": "bk:mimic_totem", "secret": true }, "bk:maanex": { "secret": true }, "bk:collector": {}, "bk:unstoppable": {} } ================================================ FILE: BurningKnight/Content/bin/Shaders/test ================================================ ================================================ FILE: BurningKnight/Content/items.json ================================================ {"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":{}}} ================================================ FILE: BurningKnight/Content/keys.json ================================================ { "left" : [ "A" ], "right" : [ "D" ], "up" : [ "W" ], "down" : [ "S" ], "move" : [ "left_stick" ], "cursor": [ "right_stick" ], "shift" : [ "L-Shift", "R-Shift" ], "roll" : [ "Mouse1", "button_leftshoulder" ], "use" : [ "Mouse0", "button_rightshoulder" ], "scroll" : [ "MouseWheel" ], "switch" : [ "L-Shift", "R-Shift", "button_b" ], "active" : [ "Space", "button_a" ], "bomb" : [ "Q", "button_y" ], "interact" : [ "E", "button_x" ], "pause" : [ "Escape", "button_back" ], "mouse" : [ "Mouse0" ], "start" : [ "Space", "Mouse0", "Mouse1", "button_start", "Return", "Enter", "button_x", "button_a", "button_rightshoulder", "button_leftshoulder" ], "map" : [ "Tab", "dpad_up" ], "toggle_minimap" : [ "M" ], "zoom_out" : [ "-" ], "zoom_in" : [ "=" ], "ui_up" : [ "Up", "dpad_up" ], "ui_down" : [ "Down", "dpad_down" ], "ui_right" : [ "Right", "dpad_right" ], "ui_left" : [ "Left", "dpad_left" ], "ui_accept" : [ "Mouse0", "Return", "Enter", "button_x", "button_a", "button_rightshoulder", "button_leftshoulder" ] } ================================================ FILE: BurningKnight/Events.cs ================================================ using System; namespace BurningKnight { public class Events { public static bool XMas; public static bool Halloween; static Events() { var now = DateTime.Now; XMas = now.Month == 12 && now.Day < 26; Halloween = now.Month == 10; } } } ================================================ FILE: BurningKnight/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("BurningKnight")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BurningKnight")] [assembly: AssemblyCopyright("Copyright © 2019")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("D31D0D40-105E-47D5-A5D0-F6E30328BF86")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: BurningKnight/README.md ================================================ # Burning Knight Content This is the juicy bit, the content of the game. The quality of code kept drifting lower and lower in the end of the project, but please, give me some points for even just finishing this massive project. Have fun exploring the place, I recommend doing it inside of an IDE, Github is not too friendly for exploring huge amount of files. Here are some starting pointers for you: * [0x32a3bbaa](https://en.wikipedia.org/wiki/Memory_corruption) * [Player class](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/entity/creature/player/Player.cs) * [Level class](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/level/Level.cs) * [InGameState class (main game state)](https://github.com/egordorichev/BurningKnight/blob/dev/BurningKnight/state/InGameState.cs) ================================================ FILE: BurningKnight/Settings.cs ================================================ using BurningKnight.level; using BurningKnight.save; using Lens; using Lens.assets; using Lens.entity.component.logic; using Lens.graphics.gamerenderer; using Microsoft.Xna.Framework; namespace BurningKnight { public class Settings { // Audio public static float MasterVolume { get => Audio.MasterVolume; set { Audio.MasterVolume = value; Audio.UpdateMusicVolume(Audio.MasterVolume * musicVolume); } } private static float musicVolume; public static float MusicVolume { get => musicVolume; set { musicVolume = value; Audio.UpdateMusicVolume(Audio.MasterVolume * musicVolume); } } public static float SfxVolume { get => Audio.SfxVolume; set => Audio.SfxVolume = value; } // Graphics public static bool Fullscreen; public static bool Vsync; public static bool Blood; public static bool UiSfx; public static bool Minimap; public static int Cursor; public static bool RotateCursor; public static float FreezeFrames; public static float FlashFrames; public static bool ShowFps; public static bool Flashes; public static bool LowQuality; public static bool Vignette; public static bool PixelPerfect { get => Engine.PixelPerfect; set => Engine.PixelPerfect = value; } private static float floorDarkness; public static float FloorDarkness { get => floorDarkness; set { floorDarkness = value; Level.FloorColor = new Color(floorDarkness, floorDarkness, floorDarkness, 1f); } } public static float GameScale { get => PixelPerfectGameRenderer.GameScale; set => PixelPerfectGameRenderer.GameScale = value; } // Game public static bool SpeedrunMode; public static bool SpeedrunTimer; public static float Screenshake; public static bool Vegan; public static bool Autopause; public static bool Autosave; public static string Gamepad; public static bool Vibrate; public static float Sensivity; public static float CursorRadius; public static string Language; // Not saved public static bool HideUi; public static bool HideCursor; static Settings() { Setup(); } public static void Setup() { Fullscreen = true; ShowFps = false; Blood = true; UiSfx = true; Vsync = true; Screenshake = 0.35f; SpeedrunMode = false; SpeedrunTimer = false; FreezeFrames = 0.5f; FlashFrames = 0.5f; SfxVolume = 0.6f; MusicVolume = 0.4f; Audio.MasterVolume = 1f; Cursor = 0; RotateCursor = false; Vegan = false; Vignette = true; Autopause = false; Autosave = true; Gamepad = null; Vibrate = true; Sensivity = 1.5f; GameScale = 1f; FloorDarkness = 1f; PixelPerfect = false; CursorRadius = 1f; Minimap = true; Flashes = true; LowQuality = false; Language = Locale.PrefferedClientLanguage; ShakeComponent.Modifier = Screenshake; Engine.FreezeModifier = FreezeFrames; Engine.FlashModifier = FlashFrames; Engine.Flashes = Flashes; } public static void Load() { Fullscreen = GlobalSave.IsTrue("s_fullscreen"); ShowFps = GlobalSave.IsTrue("s_fps"); Blood = GlobalSave.IsTrue("s_blood"); UiSfx = GlobalSave.IsTrue("s_uisfx"); Vsync = GlobalSave.IsTrue("s_vsync"); SpeedrunMode = GlobalSave.IsTrue("s_sm"); SpeedrunTimer = GlobalSave.IsTrue("s_stmr"); Screenshake = GlobalSave.GetFloat("s_screenshake"); SfxVolume = GlobalSave.GetFloat("s_sfx"); FreezeFrames = GlobalSave.GetFloat("s_frf"); FlashFrames = GlobalSave.GetFloat("s_ff"); MusicVolume = GlobalSave.GetFloat("s_music"); MasterVolume = GlobalSave.GetFloat("s_master"); Cursor = GlobalSave.GetInt("s_cursor"); RotateCursor = GlobalSave.IsTrue("s_rotate_cursor", true); Vegan = GlobalSave.IsTrue("s_v", false); Autosave = GlobalSave.IsTrue("s_as"); Autopause = GlobalSave.IsTrue("s_ap"); Gamepad = GlobalSave.GetString("s_gp"); Vibrate = GlobalSave.IsTrue("s_vb", true); Minimap = GlobalSave.IsTrue("s_mm", true); Flashes = GlobalSave.IsTrue("s_fl", true); Vignette = GlobalSave.IsTrue("s_vgn", true); LowQuality = GlobalSave.IsTrue("s_lq", false); Sensivity = GlobalSave.GetFloat("s_ss", 1); GameScale = GlobalSave.GetFloat("s_gs", 1); FloorDarkness = GlobalSave.GetFloat("s_fd", 1); PixelPerfect = GlobalSave.IsTrue("s_pp", false); CursorRadius = GlobalSave.GetFloat("s_cr", 1); Language = GlobalSave.GetString("s_ln", Locale.PrefferedClientLanguage); Locale.Load(Language); ShakeComponent.Modifier = Screenshake; Engine.FreezeModifier = FreezeFrames; Engine.FlashModifier = FlashFrames; Engine.Flashes = Flashes; } public static void Save() { GlobalSave.Put("s_fullscreen", Fullscreen); GlobalSave.Put("s_fps", ShowFps); GlobalSave.Put("s_blood", Blood); GlobalSave.Put("s_uisfx", UiSfx); GlobalSave.Put("s_vsync", Vsync); GlobalSave.Put("s_sm", SpeedrunMode); GlobalSave.Put("s_stmr", SpeedrunTimer); GlobalSave.Put("s_frf", FreezeFrames); GlobalSave.Put("s_ff", FlashFrames); GlobalSave.Put("s_screenshake", Screenshake); GlobalSave.Put("s_sfx", SfxVolume); GlobalSave.Put("s_music", MusicVolume); GlobalSave.Put("s_master", MasterVolume); GlobalSave.Put("s_cursor", Cursor); GlobalSave.Put("s_rotate_cursor", RotateCursor); GlobalSave.Put("s_v", Vegan); GlobalSave.Put("s_as", Autosave); GlobalSave.Put("s_ap", Autopause); GlobalSave.Put("s_gp", Gamepad); GlobalSave.Put("s_vb", Vibrate); GlobalSave.Put("s_ss", Sensivity); GlobalSave.Put("s_gs", GameScale); GlobalSave.Put("s_fd", FloorDarkness); GlobalSave.Put("s_pp", PixelPerfect); GlobalSave.Put("s_cr", CursorRadius); GlobalSave.Put("s_ln", Language); GlobalSave.Put("s_mm", Minimap); GlobalSave.Put("s_fl", Flashes); GlobalSave.Put("s_lq", LowQuality); GlobalSave.Put("s_vgn", Vignette); } public static void Generate() { Setup(); Save(); } } } ================================================ FILE: BurningKnight/Tags.cs ================================================ using Lens.entity; namespace BurningKnight { public class Tags { public static int Player = new BitTag("player"); public static int PlayerTarget = new BitTag("player_target"); public static int Cursor = new BitTag("cursor"); public static int Mob = new BitTag("mob"); public static int Boss = new BitTag("boss"); public static int BurningKnight = new BitTag("burning_knight"); public static int PlayerSave = new BitTag("player_save"); public static int LevelSave = new BitTag("level_save"); public static int Bomb = new BitTag("bomb"); public static int Room = new BitTag("room"); public static int TeleportTrigger = new BitTag("teleport_trigger"); public static int Lock = new BitTag("lock"); public static int MustBeKilled = new BitTag("must_be_killed"); public static int Teleport = new BitTag("teleport"); public static int Statue = new BitTag("statue"); public static int HasShadow = new BitTag("shadow"); public static int Mess = new BitTag("mess"); public static int Checkpoint = new BitTag("checkpoint"); public static int Entrance = new BitTag("entrance"); public static int HiddenEntrance = new BitTag("hidden_entrance"); public static int Item = new BitTag("item"); public static int ShopKeeper = new BitTag("shop_keeper"); public static int Npc = new BitTag("npc"); public static int Button = new BitTag("button"); public static int Chest = new BitTag("chest"); public static int Projectile = new BitTag("projectile"); public static int MobProjectile = new BitTag("mob_projectile"); public static int PlayerProjectile = new BitTag("player_projectile"); public static int Laser = new BitTag("laser"); public static int FireParticle = new BitTag("fire_particle"); public static int TextParticle = new BitTag("text_particle"); public static int Door = new BitTag("door"); public static string[] AllTags; static Tags() { AllTags = new string[BitTag.Total]; var i = 0; foreach (var t in BitTag.Tags) { AllTags[i] = t.Name; i++; if (i == BitTag.Total) { break; } } } } } ================================================ FILE: BurningKnight/assets/CommonAse.cs ================================================ using BurningKnight.entity.item; using Lens.assets; using Lens.graphics; using Lens.graphics.animation; namespace BurningKnight.assets { public static class CommonAse { public static AnimationData Items; public static AnimationData Ui; public static AnimationData Projectiles; public static AnimationData Particles; public static AnimationData Props; public static TextureRegion Missing; public static void Load() { Items = Animations.Get("items"); Ui = Animations.Get("ui"); Projectiles = Animations.Get("projectiles"); Particles = Animations.Get("particles"); Props = Animations.Get("props"); Missing = Items.GetSlice("missing"); Textures.Missing = Missing; Item.UnknownRegion = Items.GetSlice("unknown"); } } } ================================================ FILE: BurningKnight/assets/Dialogs.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.ui.dialog; using BurningKnight.ui.imgui; using BurningKnight.ui.imgui.node; using Lens.assets; using Lens.lightJson; using Lens.util; using Lens.util.file; namespace BurningKnight.assets { public static class Dialogs { private static Dictionary dialogs = new Dictionary(); public static void RegisterCallback(string id, Func callback) { var a = Get(id)?.Callbacks; if (a == null) { return; } a.Clear(); a.Add(callback); } public static void Load() { var dir = FileHandle.FromRoot("Dialogs"); foreach (var f in dir.ListFileHandles()) { if (f.Extension == ".json") { try { var name = f.NameWithoutExtension; var root = JsonValue.Parse(f.ReadAll()); // Create nodes foreach (var vl in root.AsJsonArray) { try { ImNode.Create(name, vl); } catch (Exception e) { } } // Connect em foreach (var node in ImNodes.Nodes) { node.Value.ReadOutputs(); } // Parse foreach (var node in ImNodes.Nodes) { ParseNode(node.Value); } ImNodes.Nodes.Clear(); ImNode.LastId = 0; } catch (Exception e) { Log.Error(e); } } } } private static void ParseNode(ImNode node) { if (node is DialogNode n) { Add(n.Convert()); } } public static void Add(Dialog dialog) { dialogs[dialog.Id] = dialog; } public static Dialog Get(string id) { if (!dialogs.TryGetValue(id, out var dialog)) { return null; } return dialog; } } } ================================================ FILE: BurningKnight/assets/Font.cs ================================================ using Lens.assets; using Microsoft.Xna.Framework.Graphics; using MonoGame.Extended.BitmapFonts; namespace BurningKnight.assets { public class Font { public static BitmapFont Small; public static BitmapFont Medium; public static SpriteFont Test; public static void Load() { Small = LoadFont("Fonts/small_font"); Medium = LoadFont("Fonts/large_font"); // Test = Assets.Content.Load("Fonts/fnt"); } public static BitmapFont LoadFont(string name) { return Assets.Content.Load(name); } } } ================================================ FILE: BurningKnight/assets/ImGuiHelper.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.ui.imgui; using BurningKnight.ui.imgui.node; using ImGuiNET; using Lens; using Lens.assets; using Lens.input; using Lens.lightJson; using Lens.util; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Vector2 = System.Numerics.Vector2; namespace BurningKnight.assets { public static class ImGuiHelper { public static ImGuiRenderer Renderer; public static IntPtr ItemsTexture; public static IntPtr ProjectilesTexture; public static unsafe ImGuiTextFilterPtr filter2 = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); public static void Init() { try { Renderer = new ImGuiRenderer(Engine.Instance); ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 4f); } catch (Exception e) { } } public static void BindTextures() { try { ItemsTexture = Renderer.BindTexture(CommonAse.Items.Texture); ProjectilesTexture = Renderer.BindTexture(CommonAse.Projectiles.Texture); Assets.ImGuiEnabled = true; } catch (Exception e) { } } private static List toRemove = new List(); private static bool loadedFont; private static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private static Vector2 size = new Vector2(200, 400); private static Color gridColor = new Color(0.15f, 0.15f, 0.15f, 1f); private static Color gridMainColor = new Color(0.35f, 0.15f, 0.15f, 1f); private static int gridSize = 128; private static Vector2? target; private static bool grid = true; public static void Begin() { if (!loadedFont) { loadedFont = true; Renderer.RebuildFontAtlas(); } Renderer.BeforeLayout(Engine.GameTime); } public static void End() { Renderer.AfterLayout(); } public static void ClearNodes() { ImNodes.Nodes.Clear(); ImNode.LastId = 0; } public static void Node(ImNode node) { ImNodes.Nodes[node.Id] = node; } public static bool BeforeRender() { if (grid) { var list = ImGui.GetBackgroundDrawList(); var width = Engine.Instance.GetScreenWidth(); var height = Engine.Instance.GetScreenHeight(); var off = ImNode.Offset; for (float x = off.X % gridSize; x <= width - off.X % gridSize; x += gridSize) { list.AddLine(new Vector2(x, 0), new Vector2(x, height), ((int) (off.X - x) == 0 ? gridMainColor : gridColor).PackedValue); } for (float y = off.Y % gridSize; y <= height - off.Y % gridSize; y += gridSize) { list.AddLine(new Vector2(0, y), new Vector2(width, y), ((int) (off.Y - y) == 0 ? gridMainColor : gridColor).PackedValue); } } RenderVoidMenu(); if (target.HasValue) { ImNode.Offset += (target.Value - ImNode.Offset) * Engine.Delta * 10f; if ((target.Value - ImNode.Offset).Length() <= 3f) { target = null; } } else if (ImGui.IsMouseDragging(2) || Input.Keyboard.IsDown(Keys.Space, true)) { ImNode.Offset += ImGui.GetIO().MouseDelta; } foreach (var n in ImNodes.Nodes) { var node = n.Value; if (!hideFiltred || filter.PassFilter(node.GetName())) { node.Render(); } if (node.Done) { toRemove.Add(n.Key); } } CurrentActive?.RemoveEmptyConnection(); if (toRemove.Count > 0) { var c = ImNodes.Nodes.Count - 1; foreach (var k in toRemove) { if (ImNodes.Nodes[k].Id == c) { ImNode.LastId--; } ImNodes.Nodes.Remove(k); } toRemove.Clear(); } if (pasted != null) { try { var root = JsonValue.Parse(pasted); if (root.IsJsonObject) { var val = root["imnode"]; var node = ImNode.Create(val, true); if (node != null) { node.New = true; node.Position = ImGui.GetIO().MousePos; ImNode.Focused = node; } } } catch (Exception e) { Log.Error(e); } pasted = null; } if (toAdd != null) { var node = ImNodeRegistry.Create(toAdd); if (node != null) { node.New = true; node.Position = ImGui.GetIO().MousePos; node.File = DialogEditor.Current; ImNode.Focused = node; } Node(node); toAdd = null; } ImGui.SetNextWindowSize(size, ImGuiCond.Once); if (!ImGui.Begin("Nodes")) { ImGui.End(); return false; } return true; } public static void RenderNodes() { ImGui.Checkbox("Show grid", ref grid); filter.Draw("Filter"); ImGui.Checkbox("Hide filtred", ref hideFiltred); ImGui.Separator(); RenderMenu(); ImNode first = null; var sawFocused = false; foreach (var p in ImNodes.Nodes) { var node = p.Value; var name = node.GetName(); if (!filter.PassFilter(name)) { continue; } if (first == null) { first = node; } if (ImNode.Focused == node) { node.ForceFocus = true; sawFocused = true; } if (ImGui.Selectable($"#{node.Id} {name}", ImNode.Focused == node)) { ImNode.Focused = node; node.ForceFocus = true; sawFocused = true; target = -node.RealPosition + new Vector2((Engine.Instance.GetScreenWidth() - node.Size.X) / 2, (Engine.Instance.GetScreenHeight() - node.Size.Y) / 2); } if (ImGui.OpenPopupOnItemClick("node_menu", 1)) { CurrentMenu = node; } } if (!sawFocused) { ImNode.Focused = first; } ImGui.End(); } public static ImNode CurrentMenu; private static string pasted; private static string toAdd; private static bool hideFiltred; public static void RenderPaste() { if (ImGui.Selectable("Paste (Ctrl+V)")) { Paste(); } } public static void RenderVoidMenu() { if (ImGui.BeginPopupContextVoid("void_menu")) { RenderPaste(); RenderAddNew(); } if (Input.Keyboard.IsDown(Keys.LeftControl, true) || Input.Keyboard.IsDown(Keys.RightControl, true)) { if (Input.Keyboard.WasPressed(Keys.C, true)) { Copy(false); } if (Input.Keyboard.WasPressed(Keys.V, true)) { Paste(); } if (Input.Keyboard.WasPressed(Keys.D, true) && ImNode.Focused != null) { ImNode.Focused.Remove(); } } } private static void RenderAddNew() { ImGui.Separator(); foreach (var p in ImNodeRegistry.Defined) { if (ImGui.Selectable(p.Key)) { toAdd = p.Key; } } } private static void Copy(bool menu = true) { var root = new JsonObject(); if (menu && CurrentMenu != null) { CurrentMenu.Save(root); } else if (ImNode.Focused != null) { ImNode.Focused.Save(root); } ImGui.SetClipboardText($"{{ \"imnode\" : {root} }}"); } private static void Paste() { try { var text = ImGui.GetClipboardText(); pasted = text; } catch (Exception e) { Log.Error(e); } } public static void RenderMenu(bool window = false) { if (window ? ImGui.BeginPopupContextWindow("window_node_menu", 1) : ImGui.BeginPopupContextItem("node_menu", 1)) { if (ImGui.Selectable("Copy (Ctrl+C)")) { Copy(); } RenderPaste(); if (ImGui.Selectable("Delete (Ctrl+D)")) { CurrentMenu.Remove(); } RenderAddNew(); ImGui.EndPopup(); } } public static ImNode CurrentActive; } } ================================================ FILE: BurningKnight/assets/Palette.cs ================================================ using System.Collections.Generic; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.assets { public static class Palette { public static Dictionary Colors = new Dictionary(); public static Color[] Default = new[] { ColorUtils.FromHex("#ff0040"), ColorUtils.FromHex("#131313"), ColorUtils.FromHex("#1b1b1b"), ColorUtils.FromHex("#272727"), ColorUtils.FromHex("#3d3d3d"), ColorUtils.FromHex("#5d5d5d"), ColorUtils.FromHex("#858585"), ColorUtils.FromHex("#b4b4b4"), ColorUtils.FromHex("#ffffff"), ColorUtils.FromHex("#c7cfdd"), ColorUtils.FromHex("#92a1b9"), ColorUtils.FromHex("#657392"), ColorUtils.FromHex("#424c6e"), ColorUtils.FromHex("#2a2f4e"), ColorUtils.FromHex("#1a1932"), ColorUtils.FromHex("#0e071b"), ColorUtils.FromHex("#1c121c"), ColorUtils.FromHex("#391f21"), ColorUtils.FromHex("#5d2c28"), ColorUtils.FromHex("#8a4836"), ColorUtils.FromHex("#bf6f4a"), ColorUtils.FromHex("#e69c69"), ColorUtils.FromHex("#f6ca9f"), ColorUtils.FromHex("#f9e6cf"), ColorUtils.FromHex("#edab50"), ColorUtils.FromHex("#e07438"), ColorUtils.FromHex("#c64524"), ColorUtils.FromHex("#8e251d"), ColorUtils.FromHex("#ff5000"), ColorUtils.FromHex("#ed7614"), ColorUtils.FromHex("#ffa214"), ColorUtils.FromHex("#ffc825"), ColorUtils.FromHex("#ffeb57"), ColorUtils.FromHex("#d3fc7e"), ColorUtils.FromHex("#99e65f"), ColorUtils.FromHex("#5ac54f"), ColorUtils.FromHex("#33984b"), ColorUtils.FromHex("#1e6f50"), ColorUtils.FromHex("#134c4c"), ColorUtils.FromHex("#0c2e44"), ColorUtils.FromHex("#00396d"), ColorUtils.FromHex("#0069aa"), ColorUtils.FromHex("#0098dc"), ColorUtils.FromHex("#00cdf9"), ColorUtils.FromHex("#0cf1ff"), ColorUtils.FromHex("#94fdff"), ColorUtils.FromHex("#fdd2ed"), ColorUtils.FromHex("#f389f5"), ColorUtils.FromHex("#db3ffd"), ColorUtils.FromHex("#7a09fa"), ColorUtils.FromHex("#3003d9"), ColorUtils.FromHex("#0c0293"), ColorUtils.FromHex("#03193f"), ColorUtils.FromHex("#3b1443"), ColorUtils.FromHex("#622461"), ColorUtils.FromHex("#93388f"), ColorUtils.FromHex("#ca52c9"), ColorUtils.FromHex("#c85086"), ColorUtils.FromHex("#f68187"), ColorUtils.FromHex("#f5555d"), ColorUtils.FromHex("#ea323c"), ColorUtils.FromHex("#c42430"), ColorUtils.FromHex("#891e2b"), ColorUtils.FromHex("#571c27") }; static Palette() { Define("red", Default[60]); Define("green", Default[36]); Define("blue", Default[41]); Define("yellow", Default[32]); Define("orange", Default[30]); Define("brown", Default[20]); Define("gray", Default[6]); Define("purple", Default[56]); Define("pink", Default[59]); Define("lime", Default[34]); Define("blue", Default[11]); Define("cyan", Default[43]); } public static void Define(string s, Color c) { Colors[s] = c; } } } ================================================ FILE: BurningKnight/assets/Shaders.cs ================================================ using Lens; using Lens.assets; using Lens.graphics.gamerenderer; using Microsoft.Xna.Framework.Graphics; namespace BurningKnight.assets { public class Shaders { public static Effect Ui; public static Effect Entity; public static Effect Terrain; public static Effect Screen; public static Effect Fog; public static Effect Chasm; public static Effect Item; public static Effect Bk; public static void Load() { Ui = Effects.Get("ui"); Entity = Effects.Get("entity"); Terrain = Effects.Get("terrain"); Screen = Effects.Get("screen"); Fog = Effects.Get("fog"); Chasm = Effects.Get("chasm"); Item = Effects.Get("item"); Bk = Effects.Get("bk"); Engine.Instance.StateRenderer.GameEffect = Screen; // Engine.Instance.StateRenderer.UiEffect = Ui; } public static void Begin(Effect effect) { var state = Engine.Instance.StateRenderer; state.End(); state.SurfaceEffect = effect; state.SpriteSortMode = SpriteSortMode.Immediate; effect.CurrentTechnique.Passes[0].Apply(); state.Begin(); } public static void End() { var state = Engine.Instance.StateRenderer; state.End(); state.SpriteSortMode = GameRenderer.DefaultSortMode; state.SurfaceEffect = null; state.Begin(); } } } ================================================ FILE: BurningKnight/assets/achievements/Achievement.cs ================================================ using Lens.entity; using Lens.lightJson; namespace BurningKnight.assets.achievements { public class Achievement { public readonly string Id; public bool Unlocked { get; internal set; } public int Max; public string Unlock = ""; public bool Secret; public string Group = ""; public string CompletionDate = "???"; public Achievement(string id) { Id = id; } public void Load(JsonValue root) { Max = root["max"].Int(0); Unlock = root["unlock"].String(""); Secret = root["secret"].Bool(false); Group = root["group"].String(""); } public void Save(JsonValue root) { if (Max > 0) { root["max"] = Max; } if (Unlock.Length > 0) { root["unlock"] = Unlock; } if (Secret) { root["secret"] = true; } if (Group.Length > 0) { root["group"] = Group; } } public class UnlockedEvent : Event { public Achievement Achievement; } public class LockedEvent : Event { public Achievement Achievement; } } } ================================================ FILE: BurningKnight/assets/achievements/Achievements.cs ================================================ using System; using System.Collections.Generic; using System.IO; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.save; using BurningKnight.ui.imgui; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.input; using Lens.lightJson; using Lens.lightJson.Serialization; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework.Input; namespace BurningKnight.assets.achievements { public delegate void AchievementUnlockedCallback(string id); public delegate void AchievementLockedCallback(string id); public delegate void AchievementProgressSetCallback(string id, int progress, int max); public static class Achievements { public static Dictionary Defined = new Dictionary(); public static List AchievementBuffer = new List(); public static List ItemBuffer = new List(); private static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400); public static AchievementUnlockedCallback UnlockedCallback; public static AchievementLockedCallback LockedCallback; public static AchievementProgressSetCallback ProgressSetCallback; public static Action PostLoadCallback; public static Achievement Get(string id) { return Defined.TryGetValue(id, out var a) ? a : null; } public static void Load() { Load(FileHandle.FromRoot("achievements.json")); LoadState(); } private static void Load(FileHandle handle) { if (!handle.Exists()) { Log.Error($"Achievement data {handle.FullPath} does not exist!"); return; } var root = JsonValue.Parse(handle.ReadAll()); foreach (var item in root.AsJsonObject) { var a = new Achievement(item.Key); a.Load(item.Value); Defined[item.Key] = a; } } public static void Save() { var root = new JsonObject(); foreach (var a in Defined.Values) { var data = new JsonObject(); a.Save(data); root[a.Id] = data; } var file = File.CreateText(FileHandle.FromRoot("achievements.json").FullPath); var writer = new JsonWriter(file); writer.Write(root); file.Close(); Locale.Save(); } public static void LockAll() { try { foreach (var a in Defined.Values) { a.Unlocked = false; } } catch (Exception e) { Log.Error(e); } } public static void LoadState() { foreach (var a in Defined.Values) { a.Unlocked = GlobalSave.IsTrue($"ach_{a.Id}"); a.CompletionDate = GlobalSave.GetString($"ach_{a.Id}_date", "???"); } } public static void SetProgress(string id, int progress, int max = -1) { if (Assets.DataModified) { return; } if (progress == 0) { return; } var a = Get(id); if (a == null) { Log.Error($"Unknown achievement {id}!"); return; } if (a.Unlocked) { return; } if (max == -1) { Log.Info($"Reading max as {a.Max} for {id}"); max = a.Max; } if (max == 0) { Log.Error($"Max for {id} is 0"); return; } var idt = $"ach_{a.Id}"; if (progress < max) { GlobalSave.Put(idt, progress); } try { ProgressSetCallback?.Invoke(id, progress, max); } catch (Exception e) { Log.Error(e); } if (progress >= max) { Log.Info($"Progress {progress} is >= than {max} for {id}"); ReallyUnlock(id, a); } } public static void Unlock(string id) { if (Assets.DataModified) { return; } var a = Get(id); if (a == null) { Log.Error($"Unknown achievement {id}!"); return; } if (a.Unlocked || GlobalSave.IsTrue($"ach_{a.Id}")) { a.Unlocked = true; return; } ReallyUnlock(id, a); } private static void ReallyUnlock(string id, Achievement a) { a.Unlocked = true; a.CompletionDate = DateTime.Now.ToString("dd/MM/yyy"); GlobalSave.Put($"ach_{a.Id}", true); GlobalSave.Put($"ach_{a.Id}_date", a.CompletionDate); Log.Info($"Achievement {id} was complete on {a.CompletionDate}!"); var e = new Achievement.UnlockedEvent { Achievement = a }; Engine.Instance?.State?.Area?.EventListener?.Handle(e); Engine.Instance?.State?.Ui?.EventListener?.Handle(e); if (!string.IsNullOrEmpty(a.Unlock)) { Items.Unlock(a.Unlock); } try { UnlockedCallback?.Invoke(id); } catch (Exception ex) { Log.Error(ex); } if (!AchievementBuffer.Contains(id)) { AchievementBuffer.Add(id); } var area = Engine.Instance?.State?.Area; if (area != null) { var player = LocalPlayer.Locate(area); if (player != null) { AnimationUtil.Confetti(player.Center); } } } public static void Lock(string id) { var a = Get(id); if (a == null) { Log.Error($"Unknown achievement {id}!"); return; } if (!a.Unlocked) { return; } a.Unlocked = false; GlobalSave.Put($"ach_{a.Id}", false); Log.Info($"Achievement {id} was locked!"); var e = new Achievement.LockedEvent { Achievement = a }; Engine.Instance.State.Area.EventListener.Handle(e); Engine.Instance.State.Ui.EventListener.Handle(e); try { LockedCallback?.Invoke(id); } catch (Exception ex) { Log.Error(ex); } } private static string achievementName = ""; private static Achievement selected; private static bool hideLocked; private static bool hideUnlocked; private static bool forceFocus; private static void RenderSelectedInfo() { var open = true; if (!ImGui.Begin("Achievement", ref open, ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.End(); return; } if (!open) { selected = null; ImGui.End(); return; } ImGui.Text(selected.Id); ImGui.Separator(); ImGui.InputText("Unlocks", ref selected.Unlock, 128); ImGui.InputText("Group", ref selected.Group, 128); ImGui.InputInt("Max progress", ref selected.Max); ImGui.Checkbox("Secret", ref selected.Secret); var u = selected.Unlocked; if (ImGui.Checkbox("Unlocked", ref u)) { if (u) { Unlock(selected.Id); } else { Lock(selected.Id); } } ImGui.SameLine(); if (ImGui.Button("Delete##ach")) { Defined.Remove(selected.Id); selected = null; ImGui.End(); return; } ImGui.Separator(); var k = $"ach_{selected.Id}"; var name = Locale.Get(k); if (ImGui.InputText("Name##ac", ref name, 64)) { Locale.Map[k] = name; } var key = $"ach_{selected.Id}_desc"; var desc = Locale.Get(key); if (ImGui.InputText("Description##ac", ref desc, 256)) { Locale.Map[key] = desc; } ImGui.End(); } private static int count; public static void RenderDebug() { if (!WindowManager.Achievements) { return; } if (selected != null) { RenderSelectedInfo(); } ImGui.SetNextWindowSize(size, ImGuiCond.Once); if (!ImGui.Begin("Achievements")) { ImGui.End(); return; } if (ImGui.Button("New")) { ImGui.OpenPopup("New achievement"); } ImGui.SameLine(); if (ImGui.Button("Save")) { Log.Info("Saving achievements"); Save(); } if (ImGui.BeginPopupModal("New achievement")) { ImGui.PushItemWidth(300); ImGui.InputText("Id", ref achievementName, 64); ImGui.PopItemWidth(); if (ImGui.Button("Create") || Input.Keyboard.WasPressed(Keys.Enter, true)) { Defined[achievementName] = selected = new Achievement(achievementName); achievementName = ""; forceFocus = true; ImGui.CloseCurrentPopup(); } ImGui.SameLine(); if (ImGui.Button("Cancel") || Input.Keyboard.WasPressed(Keys.Escape, true)) { achievementName = ""; ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } ImGui.Separator(); if (ImGui.Button("Unlock all")) { foreach (var a in Defined.Keys) { Unlock(a); } } ImGui.SameLine(); if (ImGui.Button("Lock all")) { foreach (var a in Defined.Keys) { Lock(a); } } ImGui.Separator(); ImGuiHelper.filter2.Draw("Search"); ImGui.SameLine(); ImGui.Text($"{count}"); count = 0; ImGui.Checkbox("Hide unlocked", ref hideUnlocked); ImGui.SameLine(); ImGui.Checkbox("Hide locked", ref hideLocked); ImGui.Separator(); var height = ImGui.GetStyle().ItemSpacing.Y; ImGui.BeginChild("ScrollingRegionItems", new System.Numerics.Vector2(0, -height), false, ImGuiWindowFlags.HorizontalScrollbar); foreach (var i in Defined.Values) { ImGui.PushID(i.Id); if (forceFocus && i == selected) { ImGui.SetScrollHereY(); forceFocus = false; } if (ImGuiHelper.filter2.PassFilter(i.Id)) { if ((hideLocked && !i.Unlocked) || (hideUnlocked && i.Unlocked)) { continue; } count++; if (ImGui.Selectable(i.Id, i == selected)) { selected = i; if (ImGui.IsMouseDown(1)) { if (ImGui.Button("Give")) { LocalPlayer.Locate(Engine.Instance.State.Area) ?.GetComponent() .Pickup(Items.CreateAndAdd( selected.Id, Engine.Instance.State.Area ), true); } } } } ImGui.PopID(); } ImGui.EndChild(); ImGui.End(); } public static bool IsComplete(string id) { var ach = Get(id); return ach != null && ach.Unlocked; } public static bool IsGroupComplete(string group) { var found = false; foreach (var a in Defined.Values) { if (a.Group == group) { found = true; if (!a.Unlocked) { return false; } } } return found; } } } ================================================ FILE: BurningKnight/assets/input/Control.cs ================================================ using Lens.input; using Microsoft.Xna.Framework.Input; namespace BurningKnight.assets.input { public class Control { public Keys[] Keys; public MouseButtons[] MouseButtons; public Buttons[] Buttons; public string Id; public Control(string id, params Keys[] keys) { Id = id; Keys = keys; } public Control Gamepad(params Buttons[] buttons) { Buttons = buttons; return this; } public Control Mouse(params MouseButtons[] buttons) { MouseButtons = buttons; return this; } } } ================================================ FILE: BurningKnight/assets/input/Controls.cs ================================================ using System; using System.Collections.Generic; using System.IO; using BurningKnight.save; using Lens.input; using Lens.lightJson; using Lens.lightJson.Serialization; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework.Input; namespace BurningKnight.assets.input { public static class Controls { private static List controls = new List(); private static List custom = new List(); public static FileHandle BindingsHandle => new FileHandle($"{SaveManager.SaveDir}keybindings_{Version}.json"); public const int Version = 2; public const string Up = "up"; public const string Left = "left"; public const string Down = "down"; public const string Right = "right"; public const string Active = "active"; public const string Use = "use"; public const string Bomb = "bomb"; public const string Interact = "interact"; public const string Swap = "swap"; public const string Roll = "roll"; public const string Duck = "duck"; public const string Map = "map"; public const string Pause = "pause"; public const string GameStart = "game_start"; public const string Cancel = "cancel"; public const string Fullscreen = "fullscreen"; public const string Fps = "fps"; public const string UiUp = "ui_up"; public const string UiDown = "ui_down"; public const string UiLeft = "ui_left"; public const string UiRight = "ui_right"; public const string UiAccept = "ui_accept"; public const string UiSelect = "ui_select"; public const string UiBack = "ui_back"; public const string QuickRestart = "quick_restart"; static Controls() { controls.Clear(); controls.Add(new Control(Up, Keys.W, Keys.Up)); controls.Add(new Control(Left, Keys.A, Keys.Left)); controls.Add(new Control(Down, Keys.S, Keys.Down)); controls.Add(new Control(Right, Keys.D, Keys.Right)); controls.Add(new Control(Active, Keys.Space).Gamepad(Buttons.RightShoulder)); controls.Add(new Control(Use).Mouse(MouseButtons.Left).Gamepad(Buttons.RightTrigger)); controls.Add(new Control(Bomb, Keys.Q).Gamepad(Buttons.LeftShoulder)); controls.Add(new Control(Interact, Keys.E).Gamepad(Buttons.X)); controls.Add(new Control(Swap, Keys.LeftShift).Gamepad(Buttons.A)); controls.Add(new Control(Roll).Mouse(MouseButtons.Right).Gamepad(Buttons.LeftTrigger)); controls.Add(new Control(Duck, Keys.R).Gamepad(Buttons.B)); controls.Add(new Control(Map, Keys.M).Gamepad(Buttons.RightShoulder)); controls.Add(new Control(Pause, Keys.Escape).Gamepad(Buttons.Back)); controls.Add(new Control(Fullscreen, Keys.F11)); controls.Add(new Control(Fps, Keys.F2)); controls.Add(new Control(Cancel, Keys.Escape).Gamepad(Buttons.Back)); controls.Add(new Control(GameStart, Keys.Space, Keys.Enter, Keys.X, Keys.Enter, Keys.Space).Gamepad(Buttons.X, Buttons.Start)); controls.Add(new Control(UiUp, Keys.W, Keys.Up).Gamepad(Buttons.LeftThumbstickUp, Buttons.RightThumbstickUp, Buttons.DPadUp)); controls.Add(new Control(UiDown, Keys.S, Keys.Down).Gamepad(Buttons.LeftThumbstickDown, Buttons.RightThumbstickDown, Buttons.DPadDown)); controls.Add(new Control(UiLeft, Keys.A, Keys.Left).Gamepad(Buttons.LeftThumbstickLeft, Buttons.RightThumbstickLeft, Buttons.DPadLeft)); controls.Add(new Control(UiRight, Keys.D, Keys.Right).Gamepad(Buttons.LeftThumbstickRight, Buttons.RightThumbstickRight, Buttons.DPadRight)); controls.Add(new Control(UiAccept).Mouse(MouseButtons.Left, MouseButtons.Right)); controls.Add(new Control(UiSelect, Keys.X, Keys.Enter, Keys.Space).Gamepad(Buttons.X, Buttons.A, Buttons.Y)); controls.Add(new Control(UiBack, Keys.Escape).Gamepad(Buttons.Back, Buttons.B)); controls.Add(new Control(QuickRestart, Keys.R, Keys.P).Gamepad(Buttons.X)); } public static void Bind() { Bind(custom); } public static void BindDefault() { Bind(controls); } private static void Bind(List controls) { Input.ClearBindings(); foreach (var c in controls) { if (c.Keys != null) { Input.Bind(c.Id, c.Keys); } if (c.Buttons != null) { Input.Bind(c.Id, c.Buttons); } if (c.MouseButtons != null) { Input.Bind(c.Id, c.MouseButtons); } } } public static void Save() { try { var p = BindingsHandle.FullPath; Log.Info($"Saving keybindings to {p}"); var file = File.CreateText(p); var writer = new JsonWriter(file, true); var root = new JsonObject(); foreach (var t in (custom.Count == 0 ? controls : custom)) { var o = new JsonObject(); if (t.Keys != null) { var a = new JsonArray(); foreach (var k in t.Keys) { a.Add(k.ToString()); } o["keys"] = a; } if (t.MouseButtons != null) { var a = new JsonArray(); foreach (var k in t.MouseButtons) { a.Add(k.ToString()); } o["mouse"] = a; } if (t.Buttons != null) { var a = new JsonArray(); foreach (var k in t.Buttons) { a.Add(k.ToString()); } o["gamepad"] = a; } root[t.Id] = o; } writer.Write(root); file.Close(); } catch (Exception e) { Log.Error(e); } } public static void Load() { try { var handle = BindingsHandle; if (!handle.Exists()) { Log.Info("Keybindings file was not found, creating new one"); BindDefault(); Save(); return; } Log.Info("Loading keybindings"); var root = JsonValue.Parse(handle.ReadAll()); custom.Clear(); foreach (var pair in root.AsJsonObject) { var control = new Control(pair.Key); if (pair.Value["keys"].IsJsonArray) { var l = new List(); foreach (var k in pair.Value["keys"].AsJsonArray) { if (Enum.TryParse(k.String(""), out var key)) { l.Add(key); } else { Log.Error($"Unknown key {k}"); } } control.Keys = l.ToArray(); } if (pair.Value["mouse"].IsJsonArray) { var l = new List(); foreach (var k in pair.Value["mouse"].AsJsonArray) { if (Enum.TryParse(k.String(""), out var key)) { l.Add(key); } else { Log.Error($"Unknown mouse button {k}"); } } control.MouseButtons = l.ToArray(); } if (pair.Value["gamepad"].IsJsonArray) { var l = new List(); foreach (var k in pair.Value["gamepad"].AsJsonArray) { if (Enum.TryParse(k.String(""), out var key)) { l.Add(key); } else { Log.Error($"Unknown gamepad button {k}"); } } control.Buttons = l.ToArray(); } custom.Add(control); } Bind(); } catch (Exception e) { Log.Error(e); } } public static string Find(string id, bool gamepad, bool both = false) { var k = "None"; string a = null; string b = null; if (!gamepad) { both = false; } foreach (var c in (custom.Count == 0 ? controls : custom)) { if (c.Id == id) { if (c.Buttons != null && c.Buttons.Length > 0) { a = c.Buttons[0].ToString(); } if (c.Keys != null && c.Keys.Length > 0) { b = c.Keys[0].ToString(); } else if (c.MouseButtons != null && c.MouseButtons.Length > 0) { b = c.MouseButtons[0].ToString(); } } } if (both) { if (a != null && b != null) { k = $"{a} / {b}"; } else if (a != null) { k = a; } } else if (gamepad && a != null) { k = a; } else if (!gamepad && b != null) { k = b; } if (k == "Left") { k = "LMB"; } else if (k == "Right") { k = "RMB"; } else if (k == "Middle") { k = "MMB"; } else if (k.Length == 2 && k[0] == 'D') { k = k[1].ToString(); } else if (k.StartsWith("Left")) { k = $"Left {k.Substring(4, k.Length - 4)}"; } else if (k.StartsWith("Right")) { k = $"Right {k.Substring(5, k.Length - 5)}"; } else if (k.EndsWith("Left")) { k = $"{k.Substring(0, k.Length - 4)} Left"; } else if (k.EndsWith("Right")) { k = $"{k.Substring(0, k.Length - 5)} Right"; } else if (k.EndsWith("Down")) { k = $"{k.Substring(0, k.Length - 4)} Down"; } else if (k.EndsWith("Up")) { k = $"{k.Substring(0, k.Length - 2)} Up"; } return k; } public static string FindSlice(string name, bool gamepad) { var id = Find(name, gamepad); if (id == null) { return null; } if (gamepad) { if (id == "Left Trigger") { return "button_lt"; } if (id == "Left Shoulder") { return "button_lb"; } if (id == "Right Trigger") { return "button_rt"; } if (id == "Right Shoulder") { return "button_rb"; } return $"button_{id.ToLower()}"; } else { id = id.ToLower(); if (id == "lmb") { return "button_lmb"; } if (id == "rmb") { return "button_rmb"; } if (id.Contains("shift")) { return "key_shift"; } if (id.Contains("caps")) { return "key_capslock"; } if (id.Contains("ntrl")) { return "key_control"; } return $"key_{id}"; } return id; } public static void Replace(string id, Keys key) { foreach (var c in (custom.Count == 0 ? controls : custom)) { if (c.Id == id) { c.Keys = new[] {key}; c.MouseButtons = null; break; } } } public static void Replace(string id, Buttons button) { foreach (var c in (custom.Count == 0 ? controls : custom)) { if (c.Id == id) { c.Buttons = new[] {button}; break; } } } public static void Replace(string id, MouseButtons button) { foreach (var c in (custom.Count == 0 ? controls : custom)) { if (c.Id == id) { c.MouseButtons = new[] {button}; c.Keys = null; break; } } } } } ================================================ FILE: BurningKnight/assets/items/ItemData.cs ================================================ using BurningKnight.entity.item; using BurningKnight.save; using Lens.lightJson; namespace BurningKnight.assets.items { public class ItemData { public JsonValue Root; public JsonValue Uses; public JsonValue Renderer; public bool AutoPickup; public bool Automatic; public bool SingleUse; public string Animation; public string Id; public float UseTime; public ItemType Type; public ItemQuality Quality; public Chance Chance; public int Pools; public bool Single = true; public bool Lockable; public bool Scourged; public int UnlockPrice = 1; public WeaponType WeaponType; public bool Unlocked => !Lockable || GlobalSave.IsTrue(Id); } } ================================================ FILE: BurningKnight/assets/items/Items.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using BurningKnight.assets.achievements; using BurningKnight.entity.creature.player; using BurningKnight.entity.item; using BurningKnight.entity.item.renderer; using BurningKnight.entity.item.use; using BurningKnight.save; using BurningKnight.state; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.lightJson; using Lens.lightJson.Serialization; using Lens.util; using Lens.util.file; using Lens.util.math; namespace BurningKnight.assets.items { public static class Items { public const string PlaceholderItem = "bk:my_heart"; public static Dictionary Datas = new Dictionary(); private static Dictionary> byType = new Dictionary>(); private static Dictionary> byPool = new Dictionary>(); public static void Load() { Load(FileHandle.FromRoot("items.json")); } public static void Load(FileHandle handle) { if (!handle.Exists()) { Log.Error($"Item data {handle.FullPath} does not exist!"); return; } if (handle.IsDirectory()) { foreach (var file in handle.ListFileHandles()) { Load(file); } foreach (var file in handle.ListDirectoryHandles()) { Load(file); } return; } if (handle.Extension != ".json") { return; } var d = handle.ReadAll(); var num = JsonCounter.Calculate(d); Log.Debug($"Item data number is {num}"); if (num != Assets.ItemData) { Assets.DataModified = true; } var root = JsonValue.Parse(d); foreach (var item in root.AsJsonObject) { ParseItem(item.Key, item.Value); } } public static void Save() { var root = new JsonObject(); foreach (var item in Datas.Values) { var data = new JsonObject(); data["id"] = item.Id; if (item.Animation != null) { data["animation"] = item.Animation; } if (Math.Abs(item.UseTime) > 0.01f) { data["time"] = item.UseTime; } if (item.Type != ItemType.Artifact) { data["type"] = (int) item.Type; } if (Math.Abs(item.Chance.Any - 1f) > 0.01f) { data["chance"] = item.Chance.ToJson(); } if (item.Single) { data["single"] = item.Single; } if (item.Scourged) { data["scourged"] = true; } if (item.Quality != ItemQuality.Wooden) { data["quality"] = (int) item.Quality; } if (item.AutoPickup) { data["auto_pickup"] = item.AutoPickup; } if (item.Automatic) { data["auto"] = item.Automatic; } if (item.SingleUse) { data["single_use"] = item.SingleUse; } data["pool"] = item.Pools; data["uses"] = item.Uses; if (item.Renderer.IsJsonObject) { data["renderer"] = item.Renderer; } if (item.Lockable) { data["lock"] = item.Lockable; data["uprice"] = item.UnlockPrice; } if (item.Type == ItemType.Weapon) { data["weapon"] = (int) item.WeaponType; } root[item.Id] = data; } var file = File.CreateText(FileHandle.FromRoot("items.json").FullPath); var writer = new JsonWriter(file); writer.Write(root); file.Close(); Locale.Save(); } private static void OnChanged(object sender, FileSystemEventArgs args) { Log.Debug($"Reloading {args.FullPath}"); Load(new FileHandle(args.FullPath)); } private static int TryToApply(ItemData data, int pool, ItemPool pl) { if (!pl.Contains(pool)) { List datas; if (!byPool.TryGetValue(pl.Id, out datas)) { datas = new List(); byPool[pl.Id] = datas; } datas.Add(data); return pl.Apply(pool); } return pool; } private static void ParseItem(string id, JsonValue item) { var a = item["animation"]; var animation = a == JsonValue.Null ? null : a.AsString; var type = (ItemType) item["type"].Int(0); var p = item["auto_pickup"]; var pickup = p == JsonValue.Null ? (type == ItemType.Key || type == ItemType.Bomb || type == ItemType.Heart || type == ItemType.Coin) : p.Bool(false); var data = new ItemData { Id = id, UseTime = item["time"].Number(0), Type = type, Quality = (ItemQuality) item["quality"].AsInteger, Root = item, Uses = item["uses"], Renderer = (item["renderer"].IsJsonObject ? item["renderer"] : JsonValue.Null), Animation = animation, AutoPickup = pickup, Single = item["single"].Bool(true), Automatic = item["auto"].Bool(false), SingleUse = item["single_use"].Bool(false), Scourged = item["scourged"].Bool(false), Chance = Chance.Parse(item["chance"]), Lockable = item["lock"].Bool(false) }; if (data.Type == ItemType.Weapon) { data.WeaponType = (WeaponType) item["weapon"].Int(0); } if (data.Lockable) { data.UnlockPrice = item["uprice"]; } var pl = item["pool"]; var pools = 0; if (pl == JsonValue.Null) { switch (data.Type) { case ItemType.Key: case ItemType.Coin: case ItemType.Bomb: case ItemType.Heart: pools = TryToApply(data, pools, ItemPool.Consumable); break; case ItemType.Artifact: case ItemType.Weapon: case ItemType.Active: pools = TryToApply(data, pools, ItemPool.Treasure); break; } } else { var pls = pl.Int(0); for (var i = 0; i < ItemPool.Count; i++) { if (ItemPool.ById[i].Contains(pls)) { pools = TryToApply(data, pools, ItemPool.ById[i]); } } } data.Pools = pools; Datas[id] = data; List all; if (!byType.TryGetValue(data.Type, out all)) { all = new List(); byType[data.Type] = all; } all.Add(data); } private static string[] coinIds = { "bk:copper_coin", "bk:iron_coin", "bk:gold_coin", "bk:platinum_coin" }; private static float[] coinChances = { 1f, 1f / 10f, 1f / 50f, 1f / 100f }; public static Item Create(string id) { if (id == null) { return null; } if (id == "bk:coin") { id = coinIds[Rnd.Chances(coinChances)]; } if (!Datas.TryGetValue(id, out var data)) { Log.Error($"Unknown item {id}"); return null; } return Create(data); } public static Item Create(ItemData data) { var item = new Item { UseTime = data.UseTime, Id = data.Id, Type = data.Type, AutoPickup = data.AutoPickup, Animation = data.Animation, Automatic = data.Automatic, SingleUse = data.SingleUse, Scourged = data.Scourged, Uses = ParseUses(data.Uses) }; if (data.Renderer != JsonValue.Null) { if (data.Renderer.IsString) { var name = data.Renderer.AsString; item.Renderer = RendererRegistry.Create(name); CheckRendererForNull(item, name); } else if (data.Renderer.IsJsonObject) { var name = data.Renderer["id"].String("bk:Angled"); item.Renderer = RendererRegistry.Create(name); CheckRendererForNull(item, name); if (item.Renderer != null) { item.Renderer.Item = item; item.Renderer.Setup(data.Renderer); } } else { Log.Error($"Invalid renderer declaration in item {data.Id}"); } } foreach (var u in item.Uses) { u.Item = item; u.Init(); } return item; } private static void CheckRendererForNull(Item item, string name) { if (item.Renderer == null) { Log.Error($"Unknown renderer {name} in item {item.Id}, did you register it?"); } } public static ItemUse[] ParseUses(JsonValue data) { if (data != JsonValue.Null) { var uses = new List(); if (data.IsString) { var use = ParseItemUse(data.AsString, null); if (use != null) { uses.Add(use); } } else if (data.IsJsonArray) { foreach (var d in data.AsJsonArray) { if (d.IsJsonObject) { if (!d["id"].IsString) { Log.Error("Item has no id"); continue; } var use = ParseItemUse(d["id"], d); if (use != null) { uses.Add(use); } } else if (d.IsString) { var use = ParseItemUse(d.AsString, null); if (use != null) { uses.Add(use); } } } } else if (data.IsJsonObject) { var obj = data.AsJsonObject; if (!obj["id"].IsString) { Log.Error("Item has no id"); } else { var use = ParseItemUse(obj["id"], obj); if (use != null) { uses.Add(use); } } } else { Log.Error("Invalid item use declaration"); } return uses.ToArray(); } return new ItemUse[0]; } private static ItemUse ParseItemUse(string id, JsonValue? data) { var use = UseRegistry.Create(id); if (use == null) { Log.Error($"Invalid item use id ({id}), did you register it?"); return null; } if (data.HasValue) { use.Setup(data.Value); } return use; } public static void Destroy() { } public static List GetPool(ItemPool pool) { return byPool.TryGetValue(pool.Id, out var b) ? b : new List(); } private static string[] veganProofItems = { "bk:chicken", "bk:shawarma", "bk:hotdog" }; public static bool ShouldAppear(string id) { if (id == "bk:coin") { return true; } if (id == "bk:blindfold") { return false; } if (!Datas.TryGetValue(id, out var data)) { return false; } if (Settings.Vegan && veganProofItems.Contains(id)) { return false; } return ShouldAppear(data); } public static bool ShouldAppear(ItemData t) { if (LevelSave.MeleeOnly && t.Type == ItemType.Weapon && t.WeaponType != WeaponType.Melee) { return false; } return (Run.Type == RunType.Daily || !t.Lockable || GlobalSave.IsTrue(t.Id)) && (!t.Single || Run.Statistics == null || (!Run.Statistics.Items.Contains(t.Id) && !Run.Statistics.Banned.Contains(t.Id))) && t.Id != "bk:the_sword"; } public static List GeneratedOnFloor = new List(); public static List GeneratePool(List types, Func filter = null, PlayerClass c = PlayerClass.Any) { var datas = new List(); foreach (var t in types) { if (ShouldAppear(t) && (filter == null || filter(t)) && !GeneratedOnFloor.Contains(t.Id)) { datas.Add(t); } } return datas; } public static string GenerateAndRemove(List datas, Func filter = null, bool removeFromFloor = false) { double sum = 0; foreach (var chance in datas) { if (filter == null || filter(chance)) { sum += chance.Chance.Calculate(PlayerClass.Any); } } var value = Rnd.Double(sum); sum = 0; string id = null; ItemData data = null; foreach (var t in datas) { if (filter == null || filter(t)) { sum += t.Chance.Calculate(PlayerClass.Any); if (value < sum) { id = t.Id; data = t; break; } } } if (id != null) { if (removeFromFloor) { GeneratedOnFloor.Add(id); } datas.Remove(data); return id; } return PlaceholderItem; } private static string Generate(List types, Func filter, PlayerClass c) { double sum = 0; var datas = GeneratePool(types, filter, c); foreach (var chance in datas) { sum += chance.Chance.Calculate(c); } var value = Rnd.Double(sum); sum = 0; foreach (var t in datas) { sum += t.Chance.Calculate(c); if (value < sum) { return t.Id; } } return PlaceholderItem; } public static string Generate(ItemType type, Func filter = null, PlayerClass c = PlayerClass.Any) { if (!byType.TryGetValue(type, out var types)) { return null; } return Generate(types, filter, c); } public static string Generate(ItemPool pool, Func filter = null, PlayerClass c = PlayerClass.Any) { if (!byPool.TryGetValue(pool.Id, out var types)) { return null; } return Generate(types, filter, c); } public static string Generate(Func filter = null, PlayerClass c = PlayerClass.Any) { return Generate(Datas.Values.ToList(), filter, c); } public static Item CreateAndAdd(string id, Area area, bool scourgeFree = true) { var item = Create(id); if (item == null) { return null; } area.Add(item); item.AddDroppedComponents(); if (scourgeFree && (!Datas.ContainsKey(id) || !Datas[id].Scourged)) { item.Scourged = false; } return item; } public static bool Has(string id) { return Datas.ContainsKey(id); } public static void Unlock(string id) { if (!Datas.TryGetValue(id, out var data)) { Log.Error($"Unknown item {id}"); return; } if (!data.Lockable) { return; } if (data.Unlocked) { return; } GlobalSave.Put(data.Id, true); var e = new Item.UnlockedEvent { Data = data }; try { Engine.Instance.State.Ui.EventListener.Handle(e); Engine.Instance.State.Area.EventListener.Handle(e); if (!Achievements.ItemBuffer.Contains(id)) { Achievements.ItemBuffer.Add(id); } } catch (Exception er) { Log.Error(er); } CheckForCollector(); } public static void CheckForCollector() { if (Achievements.Get("bk:collector").Unlocked) { return; } foreach (var item in Datas.Values) { if (item.Lockable && !item.Unlocked) { Log.Info($"Collector achievement was not unlocked cuz {item.Id}"); return; } } Achievements.Unlock("bk:collector"); } } } ================================================ FILE: BurningKnight/assets/lighting/EntityLight.cs ================================================ using Lens.entity; using Microsoft.Xna.Framework; namespace BurningKnight.assets.lighting { public class EntityLight : Light { public Entity Entity; public override Vector2 GetPosition() { return Entity.Center; } } } ================================================ FILE: BurningKnight/assets/lighting/Light.cs ================================================ using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.assets.lighting { public abstract class Light { private bool dirty = true; private bool locked; protected float radius = 32; public float Radius { get => radius; set { if (!locked) { radius = value; dirty = true; } } } public Color Color; public Vector2 Scale = Vector2.Zero; public void Lock() { if (locked) { return; } locked = true; Tween.To(0, Color.A, x => { Color.A = (byte) x; }, 0.4f).OnEnd = () => Lights.Remove(this, true); } public void Start(float target) { radius = target; Tween.To(255, Color.A, x => { Color.A = (byte) x; }, 0.4f); } public void Update(float dt) { if (dirty) { UpdateCache(); } } public void UpdateCache() { Scale.X = radius / 128f; Scale.Y = Scale.X; } public abstract Vector2 GetPosition(); } } ================================================ FILE: BurningKnight/assets/lighting/LightComponent.cs ================================================ using ImGuiNET; using Lens.entity; using Lens.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.assets.lighting { public class LightComponent : Component { public Light Light; public LightComponent(Entity entity, float radius, Color color) { Light = Lights.New(entity, radius, color); Light.UpdateCache(); } public LightComponent(Light light) { Light = light; Lights.Add(light); Light.UpdateCache(); } public override void Update(float dt) { Light.Update(dt); } public override void Destroy() { base.Destroy(); Lights.Remove(Light); } public override void RenderDebug() { base.RenderDebug(); var v = Light.Radius; if (ImGui.DragFloat("Radius", ref v)) { Light.Radius = v; } var color = new System.Numerics.Vector4(Light.Color.R / 255f, Light.Color.G / 255f, Light.Color.B / 255f, Light.Color.A / 255f); if (ImGui.DragFloat4("Color", ref color)) { Light.Color = new Color(color.X * 255, color.Y * 255, color.Z * 255, color.W * 255); } } } } ================================================ FILE: BurningKnight/assets/lighting/Lights.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.debug; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.ui.imgui; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.graphics.gamerenderer; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace BurningKnight.assets.lighting { public static class Lights { public static float Flash; public const byte AuraAlpha = 100; private static TextureRegion region; private static List lights = new List(); private static RenderTarget2D surface; public static BlendState Blend; private static BlendState messBlend; public static void Init() { var v = Run.Depth == 0 ? 0.9f : 0.25f; ClearColor = new Color(v, v, v, 1f); if (region == null) { region = Textures.Get("light"); Blend = new BlendState { ColorSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.One, ColorDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.One, ColorBlendFunction = BlendFunction.Add }; messBlend = new BlendState { ColorBlendFunction = BlendFunction.Add, ColorSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.DestinationColor, ColorDestinationBlend = Microsoft.Xna.Framework.Graphics.Blend.Zero, AlphaSourceBlend = Microsoft.Xna.Framework.Graphics.Blend.DestinationAlpha }; surfaceBlend = messBlend; } if (surface == null) { surface = new RenderTarget2D( Engine.GraphicsDevice, Display.Width + 1, Display.Height + 1, false, Engine.Graphics.PreferredBackBufferFormat, DepthFormat.Depth24 ); } } public static void Render() { if (Flash > 0) { Flash -= Engine.Delta * 8; return; } if (!LevelLayerDebug.Lights || !(Engine.Instance.State is InGameState)) { return; } if (EnableFog) { InGameState.RenderFog(); } var state = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer; state.End(); Engine.GraphicsDevice.SetRenderTarget(surface); Graphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, state.RasterizerState, null, Camera.Instance?.Matrix); Graphics.Clear(Color.Transparent); Graphics.Color.A = AuraAlpha; foreach (var p in Run.Level.Area.Tagged[Tags.Projectile]) { ((BasicProjectileGraphicsComponent) p.GraphicsComponent).RenderLight(); } foreach (var p in Run.Level.Area.Tagged[Tags.Laser]) { ((LaserGraphicsComponent) p.GraphicsComponent).RenderTopLight(); } state.End(); Engine.GraphicsDevice.SetRenderTarget(state.GameTarget); Graphics.Batch.Begin(SpriteSortMode.Immediate, BlendState.Additive, SamplerState.PointClamp, DepthStencilState.None, state.RasterizerState, null, Camera.Instance?.Matrix); Graphics.Render(surface, Camera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, Camera.Instance.Position.Y % 1)); state.End(); Graphics.Color.A = 255; Engine.GraphicsDevice.SetRenderTarget(surface); Graphics.Batch.Begin(SpriteSortMode.Immediate, lightBlend, SamplerState.PointClamp, DepthStencilState.None, state.RasterizerState, null, Camera.Instance?.Matrix); Graphics.Clear(ClearColor); foreach (var light in lights) { Graphics.Color = light.Color; Graphics.Render(region, light.GetPosition(), 0, region.Center, light.Scale * RadiusMod); } Graphics.Color = ColorUtils.WhiteColor; Run.Level?.RenderTileLights(); Graphics.Batch.End(); Engine.GraphicsDevice.SetRenderTarget(state.GameTarget); var c = Camera.Instance; var z = c.Zoom; var n = Math.Abs(z - 1) > 0.01f; if (n) { c.Zoom = 1; c.UpdateMatrices(); } Graphics.Batch.Begin(SpriteSortMode.Immediate, surfaceBlend, SamplerState.PointClamp, DepthStencilState.None, state.RasterizerState, null, Camera.Instance?.Matrix); Graphics.Color = new Color(color.X, color.Y, color.Z, alpha); Graphics.Render(surface, Camera.Instance.TopLeft - new Vector2(Camera.Instance.Position.X % 1, Camera.Instance.Position.Y % 1)); Graphics.Color = Color.White; Graphics.Batch.End(); if (n) { c.Zoom = z; c.UpdateMatrices(); } Engine.GraphicsDevice.SetRenderTarget(state.GameTarget); state.Begin(); } private static float alpha = 1f; private static System.Numerics.Vector3 color = System.Numerics.Vector3.One; private static BlendState surfaceBlend = BlendState.NonPremultiplied; private static int surfaceBlendId = 5; public static float RadiusMod = 1; public static bool EnableFog = true; public static Color ClearColor; private static BlendState lightBlend = BlendState.Additive; private static int lightBlendId = 0; private static string[] blends = { "Additive", "AlphaBlend", "NonPremultiplied", "Opaque", "Level", "Mess" }; private static BlendState BlendIdToBlend(int id) { switch (id) { case 0: default: return BlendState.Additive; case 1: return BlendState.AlphaBlend; case 2: return BlendState.NonPremultiplied; case 3: return BlendState.Opaque; case 4: return Blend; case 5: return messBlend; } } public static void RenderDebug() { if (!WindowManager.Lighting) { return; } if (!ImGui.Begin("Lighting", ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.End(); return; } ImGui.Checkbox("Enabled", ref LevelLayerDebug.Lights); ImGui.Checkbox("Enable fog", ref EnableFog); ImGui.DragFloat("Radius mod", ref RadiusMod); ImGui.Separator(); ImGui.InputFloat("Surface alpha", ref alpha); ImGui.InputFloat3("Surface tint", ref color); if (ImGui.Combo("Surface blend", ref surfaceBlendId, blends, blends.Length)) { surfaceBlend = BlendIdToBlend(surfaceBlendId); } ImGui.Separator(); if (ImGui.Combo("Light blend", ref lightBlendId, blends, blends.Length)) { lightBlend = BlendIdToBlend(lightBlendId); } var c = new System.Numerics.Vector4(ClearColor.R / 255f, ClearColor.G / 255f, ClearColor.B / 255f, ClearColor.A / 255f); if (ImGui.InputFloat4("Color", ref c)) { ClearColor = new Color(c.X, c.Y, c.Z, c.W); } ImGui.End(); } public static void Destroy() { lights.Clear(); } public static void DestroySurface() { surface?.Dispose(); surface = null; } public static Light New(Entity entity, float radius, Color color) { var light = new EntityLight { Radius = 0, Entity = entity, Color = color }; light.Start(radius); Add(light); return light; } public static void Add(Light light) { lights.Add(light); } public static void Remove(Light light, bool fast = false) { if (fast) { lights.Remove(light); return; } light.Lock(); } } } ================================================ FILE: BurningKnight/assets/lighting/PositionedLight.cs ================================================ using Microsoft.Xna.Framework; namespace BurningKnight.assets.lighting { public class PositionedLight : Light { public Vector2 Position; public override Vector2 GetPosition() { return Position; } } } ================================================ FILE: BurningKnight/assets/loot/Drops.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.mod; using BurningKnight.entity.creature.drop; using BurningKnight.entity.item; using Lens.util; namespace BurningKnight.assets.loot { public static class Drops { public static Dictionary Defined = new Dictionary(); static Drops() { Define("wooden_chest", new OneOfDrop( new AnyDrop( new SimpleDrop(0.7f, 1, 2, "bk:key"), new SimpleDrop(0.5f, 1, 2, "bk:bomb"), new SimpleDrop(0.5f, 1, 2, "bk:troll_bomb"), new SimpleDrop(0.6f, 1, 4, "bk:coin") ), new PoolDrop(ItemPool.WoodenChest) )); Define("gold_chest", new PoolDrop(ItemPool.GoldChest)); Define("double_chest", new PoolDrop(ItemPool.DoubleChest)); Define("triple_chest", new PoolDrop(ItemPool.TripleChest)); Define("red_chest", new PoolDrop(ItemPool.RedChest)); Define("stone_chest", new AnyDrop( new PoolDrop(ItemPool.StoneChest), new AnyDrop( new SimpleDrop(0.7f, 1, 2, "bk:key"), new SimpleDrop(0.5f, 1, 2, "bk:bomb"), new SimpleDrop(0.5f, 1, 2, "bk:troll_bomb"), new SimpleDrop(0.6f, 1, 4, "bk:coin") ) { Chance = 0.5f } )); Define("scourged_chest", new PoolDrop(ItemPool.ScourgedChest)); Define("duck_chest", new PoolDrop(ItemPool.DuckChest)); Define("pouch", new OneOfDrop( new SimpleDrop(0.7f, 1, 2, "bk:key"), new SimpleDrop(0.5f, 1, 2, "bk:bomb"), new SimpleDrop(0.5f, 1, 2, "bk:troll_bomb"), new SimpleDrop(0.6f, 1, 4, "bk:coin") )); Define("rock", new SingleDrop("bk:pickaxe", 0.001f)); Define("tinted_rock", new OneOfDrop( new SimpleDrop(0.2f, 1, 2, "bk:key"), new SimpleDrop(0.2f, 1, 2, "bk:bomb"), new SimpleDrop(0.2f, 1, 2, "bk:troll_bomb"), new SimpleDrop(0.4f, 1, 1, "bk:heart"), new SimpleDrop(0.5f, 1, 2, "bk:shield") )); Define("safe", new AnyDrop( new SimpleDrop { Items = new [] { "bk:coin" }, Chance = 0.8f, Min = 3, Max = 10 }, new SimpleDrop { Items = new[] { "bk:key" }, Chance = 0.5f, Min = 1, Max = 4 }, new SimpleDrop { Items = new [] { "bk:bomb" }, Chance = 0.3f, Min = 1, Max = 2 }, new PoolDrop(ItemPool.Safe) )); Define("charger", new AnyDrop( new SimpleDrop { Items = new [] { "bk:battery" }, Chance = 0.5f, Min = 1, Max = 2 }, new SimpleDrop { Items = new [] { "bk:coin" }, Chance = 0.5f, Min = 1, Max = 3 }, new PoolDrop(ItemPool.Charger, 0.5f) )); Define("vending_machine", new AnyDrop( new SimpleDrop { Chance = 1f, Items = new[] { "bk:coin" }, Min = 2, Max = 7 }, new SimpleDrop { Chance = 0.3f, Items = new[] { "bk:key" } } )); Define("boxy", new OneOfDrop( new OneOfDrop( new SimpleDrop(0.7f, 1, 1, "bk:coin_pouch"), new SimpleDrop(0.5f, 1, 1, "bk:bloody_chest"), new SimpleDrop(0.5f, 1, 1, "bk:backpack"), new SimpleDrop(0.6f, 1, 1, "bk:star") ) { Chance = 0.9f }, new SimpleDrop { Items = new [] { "bk:coin" }, Chance = 0.8f, Min = 5, Max = 8 } )); } public static Drop Get(string drop) { if (!Defined.TryGetValue(drop, out var d)) { Log.Error($"Unknown drop {drop}"); return null; } return d; } public static void Define(string id, Drop drop, Mod mod = null) { Defined[$"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}"] = drop; } } } ================================================ FILE: BurningKnight/assets/loot/LootTables.cs ================================================ using System; using System.Collections.Generic; using System.IO; using BurningKnight.entity.creature.drop; using ImGuiNET; using Lens.lightJson; using Lens.lightJson.Serialization; using Lens.util; using Lens.util.file; namespace BurningKnight.assets.loot { public static class LootTables { public static Dictionary Defined = new Dictionary(); public static Dictionary Data = new Dictionary(); public static int LastDropId; public static void Load() { if (true) { return; } Load(FileHandle.FromRoot("Loot/")); } private static void Load(FileHandle handle) { if (!handle.Exists()) { Log.Error($"Loot table {handle.FullPath} does not exist!"); return; } if (handle.IsDirectory()) { foreach (var file in handle.ListFileHandles()) { Load(file); } foreach (var file in handle.ListDirectoryHandles()) { Load(file); } return; } if (handle.Extension != ".json") { return; } var root = JsonValue.Parse(handle.ReadAll()); foreach (var table in root.AsJsonObject) { try { ParseTable(table.Key, table.Value); } catch (Exception e) { Log.Error(e); } } } public static void Save() { Log.Info("Saving loot tables"); var root = new JsonObject(); foreach (var d in Data) { root[d.Key] = d.Value; } var file = File.CreateText(FileHandle.FromRoot("Loot/loot.json").FullPath); var writer = new JsonWriter(file); writer.Write(root); file.Close(); } public static void ParseTable(string id, JsonValue table) { var drop = ParseDrop(table); if (drop == null) { return; } Defined[id] = drop; Data[id] = table; } public static JsonValue WriteDrop(Drop drop) { var o = new JsonObject(); o["type"] = drop.GetId(); drop.Save(o); return o; } public static Drop ParseDrop(JsonValue table) { var type = table["type"].String(null); if (type == null) { return null; } if (!DropRegistry.Defined.TryGetValue(type, out var t)) { Log.Error($"Unknown drop type {type}"); return null; } var drop = (Drop) Activator.CreateInstance(t.Type); table["id"] = LastDropId++; drop.Load(table); return drop; } public static bool RenderDrop(JsonValue drop) { var id = drop["type"].String("missing"); if (DropRegistry.Defined.TryGetValue(id, out var info)) { if (ImGui.TreeNode($"{id}%##{drop["id"].AsInteger}")) { info.Render(drop); ImGui.TreePop(); return true; } } else { ImGui.BulletText($"Unknown type {id}"); } return false; } } } ================================================ FILE: BurningKnight/assets/mod/Mod.cs ================================================ using System; using System.Reflection; using Lens.util; using Lens.util.file; namespace BurningKnight.assets.mod { public abstract class Mod { public string Prefix { get; protected set; } = "null"; public abstract void Init(); public abstract void Destroy(); public abstract void Update(float dt); public abstract void Render(); public static Mod Load(FileHandle file) { var dll = Assembly.LoadFile(file.FullPath); foreach (var type in dll.ExportedTypes) { if (typeof(Mod).IsAssignableFrom(type)) { try { var mod = (Mod) Activator.CreateInstance(type); return mod; } catch (Exception e) { Log.Error(e); return null; } } } return null; } } } ================================================ FILE: BurningKnight/assets/mod/Mods.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using Lens.assets; using Lens.util; using Lens.util.file; namespace BurningKnight.assets.mod { public static class Mods { public static Dictionary Loaded = new Dictionary(); public static string BurningKnight = "bk"; public static void Load() { if (!Assets.LoadMods) { return; } var dir = FileHandle.FromRoot("Mods/"); if (!dir.Exists()) { Log.Error("Mod directory was not found, creating and exiting."); dir.MakeDirectory(); return; } Log.Info("Found mod directory"); foreach (var handle in dir.ListFileHandles()) { if (handle.Extension != ".dll") { continue; } var mod = Mod.Load(handle); if (mod == null) { Log.Error($"Failed to load mod {handle.Name}"); continue; } var prefix = mod.Prefix; if (Loaded.ContainsKey(prefix)) { Log.Error($"Conflicting mods with the same prefix {prefix}"); continue; } Log.Info($"Loaded mod {prefix}"); Loaded[prefix] = mod; mod.Init(); } } public static void Update(float dt) { foreach (var mod in Loaded.Values) { mod.Update(dt); } } public static void Render() { foreach (var mod in Loaded.Values) { mod.Render(); } } public static void Destroy() { foreach (var mod in Loaded.Values) { mod.Destroy(); } } } } ================================================ FILE: BurningKnight/assets/particle/AnimatedParticle.cs ================================================ using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using Lens.assets; using Lens.graphics.animation; namespace BurningKnight.assets.particle { public class AnimatedParticle : Particle { public Animation Animation; public AnimatedParticle(ParticleController controller, ParticleRenderer renderer, string animation, string tag = null) : base(controller, renderer) { Animation = Animations.Create(animation); if (tag != null) { Animation.Tag = tag; } Animation.OnEnd += () => { Done = true; }; } public override void Update(float dt) { base.Update(dt); Animation.Update(dt); } } } ================================================ FILE: BurningKnight/assets/particle/Particle.cs ================================================ using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle { public class Particle { public ParticleController Controller; public ParticleRenderer Renderer; public Vector2 Position; public Vector2 Velocity; public float Z; public float Zv; public float Angle; public float AngleVelocity; public float T; public float Alpha = 1f; public float Scale = 1f; public bool Done; public int Rnd; public Particle(ParticleController controller, ParticleRenderer renderer) { Controller = controller; Renderer = renderer; Angle = Lens.util.math.Rnd.AnglePI(); Rnd = Lens.util.math.Rnd.Int(1024); T = Lens.util.math.Rnd.Float(1f); } public virtual void Update(float dt) { } } } ================================================ FILE: BurningKnight/assets/particle/ParticleEmitter.cs ================================================ using System; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle { public class ParticleEmitter : ParticleSystem { public float Rate; public float Elapsed; public float TillDeath; public ParticleEmitter(Func create, int min, int max, Vector2 position, float rate, float time = -1) : base(create, min, max, position) { Rate = rate; TillDeath = time; } public override void Update(float dt) { if (TillDeath > -1) { TillDeath -= dt; if (TillDeath <= 0) { Done = true; return; } } Elapsed += dt; while (Elapsed > Rate) { Elapsed -= Rate; AddParticle(); } base.Update(dt); } } } ================================================ FILE: BurningKnight/assets/particle/ParticleEntity.cs ================================================ using BurningKnight.entity; using BurningKnight.entity.component; using Lens.entity; using Lens.util.math; namespace BurningKnight.assets.particle { // Wraps particle for cases, when particle system is too much public class ParticleEntity : Entity { public Particle Particle; public ParticleEntity(Particle particle) { Particle = particle; } public override void Init() { base.Init(); Width = 0; Height = 0; Particle.Controller.Init(Particle, this); AlwaysActive = true; Depth = Layers.FloorParticles; } public override void Update(float dt) { base.Update(dt); if (Particle.Controller.Update(Particle, dt) || Particle.Done) { Done = true; return; } if (Depth == Layers.FloorParticles || Depth == Layers.FlyingMob) { Depth = Particle.Z > 1 ? Layers.FlyingMob : Layers.FloorParticles; } Position = Particle.Position; } public override void Render() { base.Render(); if (!Particle.Done) { Particle.Renderer.Render(Particle); } } public void AddShadow() { AddComponent(new ShadowComponent(RenderShadow)); } private void RenderShadow() { if (!Particle.Done) { Particle.Renderer.RenderShadow(Particle); } } } } ================================================ FILE: BurningKnight/assets/particle/ParticleSystem.cs ================================================ using System; using System.Collections.Generic; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle { public class ParticleSystem : Entity { public List Particles = new List(); public Func Create; public ParticleSystem(Func create, int min, int max, Vector2 position) { Create = create; Position = position; var count = Rnd.Int(min, max + 1); for (int i = 0; i < count; i++) { AddParticle(); } } public void AddParticle() { var particle = Create(); particle.Controller.Init(particle, this); Particles.Add(particle); } public override void Update(float dt) { for (int i = Particles.Count - 1; i >= 0; i--) { var particle = Particles[i]; if (particle.Controller.Update(particle, dt) || particle.Done) { Particles.RemoveAt(i); } } if (Particles.Count == 0) { Done = true; } } public override void Render() { foreach (var particle in Particles) { if (!particle.Done) { particle.Renderer.Render(particle); } } } } } ================================================ FILE: BurningKnight/assets/particle/Particles.cs ================================================ using System; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle { public static class Particles { private static ParticleRenderer[] dustRenderers = { new TexturedParticleRenderer("dust_0"), new TexturedParticleRenderer("dust_1"), new TexturedParticleRenderer("dust_2") }; private static ParticleRenderer[] ashRenderers = { new TexturedParticleRenderer("d_1"), new TexturedParticleRenderer("d_2"), new TexturedParticleRenderer("d_3"), new TexturedParticleRenderer("d_4") }; private static ParticleRenderer[] rainRenderers = { new TexturedParticleRenderer("rain_1"), new TexturedParticleRenderer("rain_2"), new TexturedParticleRenderer("rain_3") }; private static ParticleRenderer planksRenderer = new RandomFrameRenderer("planks_particle"); public static ParticleRenderer BkDeathRenderer = new TexturedParticleRenderer("natural"); public static ParticleRenderer SparkRenderer = new TexturedParticleRenderer("spark"); public static ParticleRenderer BloodRenderer = new TexturedParticleRenderer("blood"); public static ParticleRenderer ScourgeRenderer = new TexturedParticleRenderer("curse"); public static ParticleRenderer AnimatedRenderer = new AnimatedParticleRenderer(); public static ParticleRenderer LavaRenderer = new TexturedParticleRenderer("lava"); public static Particle Textured(string slice) { return new Particle(Controllers.Simple, new TexturedParticleRenderer(slice)); } public static AnimatedParticle Animated(string animation, string tag = null) { return new AnimatedParticle(Controllers.Animated, AnimatedRenderer, animation, tag); } public static Particle Lava() { return new Particle(Controllers.Lava, LavaRenderer); } public static Particle Dust() { return new Particle(Controllers.Simple, dustRenderers[Rnd.Int(3)]); } public static Particle Ash() { return new Particle(Controllers.Ash, ashRenderers[Rnd.Int(3)]); } public static Particle Scourge() { return new Particle(Controllers.Scourge, ScourgeRenderer); } public static Particle Plank() { return new Particle(Controllers.Destroy, planksRenderer); } public static Particle Spark() { return new Particle(Controllers.Spark, SparkRenderer); } public static Particle Rain() { return new Particle(Controllers.Rain, rainRenderers[Rnd.Int(3)]); } public static ParticleEntity Wrap(Particle particle, Area area, Vector2 where) { var e = new ParticleEntity(particle); e.Position = where; e.Particle.Position = where; area.Add(e); return e; } public static void BreakSprite(Area area, TextureRegion region, Vector2 position, int depth = -1) { var s = 5; for (int x = 0; x < region.Width; x += s) { for (int y = 0; y < region.Height; y += s) { var r = new TextureRegion(region, s, s); r.Source.X += x; r.Source.Y += y; var part = new ParticleEntity(new Particle(Controllers.Destroy, new TexturedParticleRenderer { Region = r })); part.Particle.Angle = (float) (Math.Atan2(r.Center.Y - y, r.Center.X - x) - Math.PI + Rnd.Float(-1, 1)); part.Position = position + new Vector2(x, y); area.Add(part); if (depth != -1) { part.Depth = depth; } } } } } } ================================================ FILE: BurningKnight/assets/particle/controller/AnimatedParticleController.cs ================================================ using System; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.controller { public class AnimatedParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); particle.AngleVelocity = Rnd.Float(0.6f, 1) * 16 * (Rnd.Chance() ? -1 : 1); var a = Rnd.AnglePI(); var f = Rnd.Float(0.6f, 1f) * 40f; particle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f); } public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; if (particle.Scale <= 0f) { particle.Scale = 0; return true; } particle.AngleVelocity -= particle.AngleVelocity * dt * 4; particle.Velocity -= particle.Velocity * dt * 4; return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/AshController.cs ================================================ namespace BurningKnight.assets.particle.controller { public class AshController : ParticleController { public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Position += particle.Velocity * dt; particle.Velocity -= particle.Velocity * dt * 2; if (particle.T >= 0.3f) { particle.Scale -= dt * 1.5f; if (particle.Scale <= 0) { return true; } } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/BkDeathParticleController.cs ================================================ using System; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.controller { public class BkDeathParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); var a = Rnd.AnglePI(); var d = Rnd.Float(60, 90); particle.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); } public override bool Update(Particle particle, float dt) { particle.Position += particle.Velocity * dt; particle.Velocity -= particle.Velocity * (dt * 2); particle.Alpha -= dt; if (particle.Alpha <= 0) { return true; } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/BloodParticleController.cs ================================================ using Lens.entity; using Lens.util.math; namespace BurningKnight.assets.particle.controller { public class BloodParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); particle.AngleVelocity = Rnd.Float(0.6f, 1) * 5 * (Rnd.Chance() ? -1 : 1); } public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; particle.Scale -= dt * 2f; if (particle.Scale <= 0f) { particle.Scale = 0; return true; } particle.Velocity.X -= particle.Velocity.X * dt; particle.Velocity.Y += dt * 256; return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/Controllers.cs ================================================ namespace BurningKnight.assets.particle.controller { public static class Controllers { public static ParticleController Simple = new SimpleParticleController(); public static ParticleController Destroy = new DestroyParticleController(); public static ParticleController Float = new FloatParticleController(); public static ParticleController BkDeath = new BkDeathParticleController(); public static ParticleController Spark = new SparkParticleController(); public static ParticleController Blood = new BloodParticleController(); public static ParticleController Scourge = new ScourgeController(); public static ParticleController Ash = new AshController(); public static ParticleController Animated = new AnimatedParticleController(); public static ParticleController Rain = new RainParticleController(); public static ParticleController Lava = new LavaController(); } } ================================================ FILE: BurningKnight/assets/particle/controller/DestroyParticleController.cs ================================================ using System; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.controller { public class DestroyParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { particle.Position = owner.Center; particle.AngleVelocity = Rnd.Float(0.6f, 1) * Rnd.Float(24, 48) * (Rnd.Chance() ? -1 : 1); var a = particle.Angle; var f = Rnd.Float(0.6f, 1f) * Rnd.Float(80, 120f); particle.Angle = 0; particle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f); particle.Zv = Rnd.Float(1, 3); particle.T = Rnd.Float(1f); } public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; particle.AngleVelocity -= particle.AngleVelocity * dt * 4; particle.Velocity -= particle.Velocity * dt * 2; particle.Z += particle.Zv * dt * 60; if (particle.Z <= 0) { particle.Z = 0; particle.Zv = 0; particle.Velocity.X = 0; particle.Velocity.Y = 0; } else { particle.Zv -= dt * 5; } particle.Update(dt); if (particle.T >= 5f) { particle.Alpha -= dt * 0.3f; if (particle.Alpha <= 0) { return true; } } return false; } } } ================================================ FILE: BurningKnight/assets/particle/controller/FloatParticleController.cs ================================================ namespace BurningKnight.assets.particle.controller { public class FloatParticleController : ParticleController { public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Position += particle.Velocity * dt; particle.Velocity -= particle.Velocity * dt * 2; if (particle.T >= 1.7f) { particle.Scale -= dt * 3f; if (particle.Scale <= 0) { return true; } } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/HealthParticleController.cs ================================================ namespace BurningKnight.assets.particle.controller { public class HealthParticleController : ParticleController { public override bool Update(Particle particle, float dt) { particle.Velocity.Y += dt * 256; particle.Position.Y += particle.Velocity.Y * dt; particle.Alpha -= dt; if (particle.Alpha <= 0) { return true; } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/LavaController.cs ================================================ namespace BurningKnight.assets.particle.controller { public class LavaController : ParticleController { public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Position += particle.Velocity * dt; particle.Velocity.X -= particle.Velocity.X * dt * 4; particle.Velocity.Y += dt * 40; if (particle.Velocity.Y > 0) { particle.Scale -= dt * 0.5f; if (particle.Scale <= 0) { return true; } } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/ParticleController.cs ================================================ using Lens.entity; namespace BurningKnight.assets.particle.controller { public class ParticleController { public virtual void Init(Particle particle, Entity owner) { particle.Position = owner.Center; } public virtual bool Update(Particle particle, float dt) { particle.Update(dt); return false; } } } ================================================ FILE: BurningKnight/assets/particle/controller/RainParticleController.cs ================================================ using Lens.entity; using Lens.util.math; namespace BurningKnight.assets.particle.controller { public class RainParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); particle.AngleVelocity = Rnd.Float(0.6f, 1) * 5 * (Rnd.Chance() ? -1 : 1); } public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; particle.Scale -= dt * 4f; if (particle.Scale <= 0f) { particle.Scale = 0; return true; } particle.Velocity.X -= particle.Velocity.X * dt; particle.Velocity.Y += dt * 256; return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/ScourgeController.cs ================================================ namespace BurningKnight.assets.particle.controller { public class ScourgeController : SimpleParticleController { public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; particle.Scale -= dt * 0.5f; if (particle.Scale <= 0f) { particle.Scale = 0; return true; } particle.AngleVelocity -= particle.AngleVelocity * dt * 4; particle.Velocity.X -= particle.Velocity.X * dt * 5; particle.Velocity.Y -= dt * 60f; return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/SimpleParticleController.cs ================================================ using System; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.controller { public class SimpleParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); particle.AngleVelocity = Rnd.Float(0.6f, 1) * 16 * (Rnd.Chance() ? -1 : 1); var a = Rnd.AnglePI(); var f = Rnd.Float(0.6f, 1f) * 40f; particle.Velocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f); } public override bool Update(Particle particle, float dt) { particle.T += dt; particle.Angle += particle.AngleVelocity * dt; particle.Position += particle.Velocity * dt; particle.Scale -= dt; if (particle.Scale <= 0f) { particle.Scale = 0; return true; } particle.AngleVelocity -= particle.AngleVelocity * dt * 4; particle.Velocity -= particle.Velocity * dt * 4; return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/controller/SparkParticleController.cs ================================================ using Lens.entity; using Lens.util.math; namespace BurningKnight.assets.particle.controller { public class SparkParticleController : ParticleController { public override void Init(Particle particle, Entity owner) { base.Init(particle, owner); particle.AngleVelocity = Rnd.Sign() * Rnd.Float(1, 2); particle.Scale = 0; particle.Alpha = 1f; particle.T = 0; } public override bool Update(Particle particle, float dt) { particle.Angle += particle.AngleVelocity * dt; particle.T += dt; if (particle.T < 1f) { particle.Scale += dt; if (particle.Scale >= 1f) { particle.Scale = 1f; } } else { particle.AngleVelocity -= particle.AngleVelocity * dt; if (particle.T > 2f) { particle.Scale -= dt * 0.5f; if (particle.Scale <= 0) { return true; } } } return base.Update(particle, dt); } } } ================================================ FILE: BurningKnight/assets/particle/custom/BuffParticle.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using Lens; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class BuffParticle : Entity { public Buff Buff; public Entity Entity; public int Id; private TextureRegion region; private Vector2 scale = new Vector2(0, Display.UiScale * 3); private bool removing; public BuffParticle(Buff buff, Entity entity) { Buff = buff; Entity = entity; Id = entity.GetComponent().Particles.Count; region = CommonAse.Ui.GetSlice(buff.GetIcon()); Width = 8 * Display.UiScale; Height = region.Height * Display.UiScale; Tween.To(Display.UiScale, scale.X, x => scale.X = x, 0.3f); Tween.To(Display.UiScale, scale.Y, x => scale.Y = x, 0.3f); } public override void Init() { base.Init(); AlwaysActive = true; AlwaysVisible = true; } public override void Update(float dt) { base.Update(dt); if (Entity.Done) { Remove(); } } public void Remove() { if (removing) { return; } removing = true; Tween.To(Display.UiScale * 4, scale.X, x => scale.X = x, 0.3f); Tween.To(0, scale.Y, x => scale.Y = x, 0.3f).OnEnd = () => { Done = true; foreach (var p in Entity.GetComponent().Particles) { if (p.Id > Id) { p.Id--; p.lastX -= (Width + 4) * 0.5f; } } }; } private float lastX; public override void Render() { var origin = region.Center; var tar = (Entity.GetComponent().Particles.Count - 1) * (Width + 4) * 0.5f; lastX += (tar - lastX) * Engine.Delta * 5; var x = Id * (Width + 4) - lastX; var pos = Entity.TopCenter; if (Entity.TryGetComponent(out var z)) { pos -= new Vector2(0, z.Z); } Center = Camera.Instance.CameraToUi(pos) + new Vector2(x, scale.X - Display.UiScale - 8); Graphics.Render(region, Position + origin, 0, origin, scale); } } } ================================================ FILE: BurningKnight/assets/particle/custom/ConfettiParticle.cs ================================================ using System; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class ConfettiParticle : Entity { private TextureRegion region; private float t; private float rotationOffset; private float z; private float vz; private float vx; private float speed; private Color color; private float scale = 1; public override void AddComponents() { base.AddComponents(); color = ColorUtils.FromHSV(Rnd.Float(360), 100, 100); speed = Rnd.Float(0.5f, 2f); vx = Rnd.Float(-5, 5); vz = -Rnd.Float(5, 12); t = Rnd.Float(10); rotationOffset = Rnd.Float(0.5f, 2f); AlwaysActive = true; Width = Rnd.Float(6, 10); Height = Width * 0.3f; region = CommonAse.Particles.GetSlice("fire"); } public override void Update(float dt) { base.Update(dt); t += dt * speed * 6; X += vx * dt * 50; vx -= vx * dt * 10; z += vz * dt * 10; vz += 20 * dt; if (vz >= 0) { if (z > 0) { z = 0; } scale -= dt; if (scale <= 0) { Done = true; } } } public override void Render() { Graphics.Color = color; Graphics.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)); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/assets/particle/custom/ConsumableParticle.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class ConsumableParticle : Entity { private Vector2 target = new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4)); private TextureRegion region; private float angle; private float angleV; private float speed; private bool tweened; private Player player; private Vector2 scale = new Vector2(0, Display.UiScale * 2); private Action callback; private Vector2 offset; public ConsumableParticle(TextureRegion r, Player p, bool item = false, Action call = null, bool emerald = false) { AlwaysActive = true; AlwaysVisible = true; region = r; Width = region.Width; Height = region.Height; player = p; offset = new Vector2(Rnd.Int(-4, 4), Height + Rnd.Int(-4, 4)); speed = Rnd.Float(1, 2f) * (Rnd.Chance() ? -1 : 1); var s = item ? Display.UiScale : Rnd.Float(1f, 2f); Tween.To(s, scale.X, x => scale.X = x, 0.3f); Tween.To(s, scale.Y, x => scale.Y = x, 0.3f); if (item) { target += new Vector2(Display.UiWidth, Display.UiHeight); } else if (emerald) { target += new Vector2(Display.UiWidth, 0); } callback = call; } public override void PostInit() { base.PostInit(); if (player == null || Camera.Instance == null) { Done = true; return; } Center = Camera.Instance.CameraToUi(player.TopCenter) - offset; Timer.Add(() => { tweened = true; callback?.Invoke(); Tween.To(target.X, X, x => X = x, 1f, Ease.QuadInOut); Tween.To(target.Y, Y, x => Y = x, 1f, Ease.QuadInOut).OnEnd = () => { Done = true; }; }, 1f); } public override void Update(float dt) { base.Update(dt); if (tweened) { angleV += dt * speed * 2; angle += angleV * dt * 20; scale.X -= dt * 2.2f; scale.Y -= dt * 2.2f; if (scale.X <= 0) { Done = true; } } else { var pos = player.TopCenter; if (player.TryGetComponent(out var z)) { pos -= new Vector2(0, z.Z); } Center = Camera.Instance.CameraToUi(pos) - offset; } } public override void Render() { var origin = region.Center; Graphics.Render(region, Position + origin, angle, origin, scale); } } } ================================================ FILE: BurningKnight/assets/particle/custom/EpicSpawn.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.lighting; using BurningKnight.entity; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class EpicSpawn : Entity { private TextureRegion region; private TextureRegion ray; private float scale; private float angle; private float t; private List rays = new List(); private float tt; private float lastRay = 0.25f; public Action OnEnd; public override void AddComponents() { base.AddComponents(); tt = Rnd.Float(1024); Depth = Layers.Ui; AlwaysActive = true; AlwaysVisible = true; region = CommonAse.Particles.GetSlice("epic_spawn"); ray = CommonAse.Particles.GetSlice("ray"); Width = region.Width; Height = region.Height; AddComponent(new LightComponent(this, 64f, ColorUtils.WhiteColor)); Tween.To(0.5f, scale, x => scale = x, 0.5f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); lastRay -= dt; if (lastRay <= 0) { lastRay = Math.Max(0.1f, (5f - t) / 20f); rays.Add(new Ray { Angle = Rnd.AnglePI() }); } GetComponent().Light.Radius = scale * 2f; t += dt; tt += dt; if (t > 0.5f) { angle += (t - 0.5f) * 300 * dt; scale += dt * scale; } if (scale >= 12) { Done = true; OnEnd?.Invoke(); } foreach (var r in rays) { r.Scale.Y = r.Scale.X = Math.Min(1, r.Scale.X + dt); } } public override void Render() { Graphics.Render(region, Position + region.Center, angle, region.Center, new Vector2(scale)); foreach (var r in rays) { Graphics.Render(ray, Center, r.Angle + t - (0.5f) * (1 + t * 0.02f), new Vector2(0, 30), r.Scale); } } private class Ray { public float Angle; public Vector2 Scale; } } } ================================================ FILE: BurningKnight/assets/particle/custom/FadingParticle.cs ================================================ using Lens.entity; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class FadingParticle : Entity { private TextureRegion region; private Vector2 scale = Vector2.One; private Vector4 color; public FadingParticle(TextureRegion sprite, Color tint) { region = sprite; AlwaysActive = true; Width = sprite.Width; Height = sprite.Height; color.X = tint.R / 255f; color.Y = tint.G / 255f; color.Z = tint.B / 255f; color.W = tint.A / 255f; } public override void Init() { base.Init(); AlwaysActive = true; } public override void Update(float dt) { base.Update(dt); scale.X -= dt * 0.8f; scale.Y = scale.X; if (scale.X <= 0) { Done = true; } } public override void Render() { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(color); Graphics.Render(region, Center, 0, region.Center, scale); Shaders.End(); } } } ================================================ FILE: BurningKnight/assets/particle/custom/FireEmitter.cs ================================================ using System; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class FireEmitter : Entity { private TextureRegion region; private float t; public float Scale = 1; public override void Init() { base.Init(); region = CommonAse.Particles.GetSlice("fire_emitter"); Width = region.Width; Height = region.Height; t = Rnd.Float(6); } public override void Update(float dt) { base.Update(dt); t += dt * 10; } private static Color ca = new Color(1f, 0.5f, 0f, 0.5f); private static Color cb = new Color(1f, 0.5f, 0f, 1f); public override void Render() { var s = Scale * (float) ((Math.Cos(t * 0.5f) * Math.Sin((t + 0.2f) * 0.8f)) * 0.25f + 0.75f); Graphics.Color = ca; Graphics.Render(region, Position, 0, region.Center, new Vector2(s)); Graphics.Color = cb; Graphics.Render(region, Position, 0, region.Center, new Vector2(s * 0.5f)); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/assets/particle/custom/FireParticle.cs ================================================ using System; using BurningKnight.entity; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.biome; using BurningKnight.state; using Lens; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using VelcroPhysics.Dynamics; using MathUtils = Lens.util.MathUtils; namespace BurningKnight.assets.particle.custom { public class FireParticle : Entity { public static TextureRegion Region; public Entity Owner; public float Delay; public float T; public float Scale; public float ScaleTar; public Vector2 Offset; public float Vy; public float Vx; public bool Growing; public float SinOffset; public float Mod; public float R = 1f; public float G = 1f; public float B = 1f; public float Size = 1; public bool Hurts; public Vector2? Target; public override void Init() { base.Init(); if (Region == null) { Region = CommonAse.Particles.GetSlice("fire"); } AddTag(Tags.FireParticle); AlwaysActive = true; AlwaysVisible = true; Growing = true; ScaleTar = Rnd.Float(0.5f, 0.9f) * Size; if (Mod < 0.01f) { Mod = Rnd.Float(0.7f, 1f); } SinOffset = Rnd.Float(3.2f); if (Math.Abs(Offset.X) + Math.Abs(Offset.Y) < 0.1f) { Offset = new Vector2(Rnd.Float(-4, 4) * XChange, Rnd.Float(-2, 2)); } Depth = Layers.TileLights + 1; } public override void AddComponents() { base.AddComponents(); if (Hurts) { AddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true, true)); } } public override void Update(float dt) { if (Delay > 0) { Delay -= dt; return; } T += dt; if (T > 0.3f) { if (Run.Level != null && Run.Level.Biome is CaveBiome) { R = Math.Max(0, R - dt * 3 * Mod); G = Math.Max(0, G - dt * 0.3f * Mod); B = Math.Max(0, B - dt * Mod); } else { R = Math.Max(0, R - dt * 0.3f * Mod); G = Math.Max(0, G - dt * Mod); B = Math.Max(0, B - dt * 3 * Mod); } } if (Growing) { Scale += dt; if (Scale >= ScaleTar) { Scale = ScaleTar; Growing = false; } } else { Scale -= dt * (Target.HasValue ? 0.33f : 0.5f); if (Scale <= 0) { Done = true; return; } } Vy += dt * Mod * 20; if (Target.HasValue) { var t = Target.Value; var dx = t.X - Position.X - Offset.X; var dy = t.Y - Position.Y - Offset.Y; var d = MathUtils.Distance(Vx, Vy) + dt * 30; var angle = Math.Atan2(dy, dx); var va = Math.Atan2(-Vy, -Vx); va = MathUtils.LerpAngle(va, angle, dt * 4); Vx = (float) -Math.Cos(va) * d; Vy = (float) -Math.Sin(va) * d; } Offset.X -= Vx * dt; Offset.Y -= Vy * dt; if (Owner != null) { X = Owner.CenterX; Y = Owner.Bottom; if (Owner.TryGetComponent(out var z)) { Y -= z.Z; } } if (Hurts) { GetComponent().Position = Position + Offset; } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Player p) { p.GetComponent().ModifyHealth(-1, this); } } return base.HandleEvent(e); } public float XChange = 1; public override void Render() { } public void ActuallyRender() { if (Delay > 0) { return; } var a = (float) Math.Cos(T * 5f + SinOffset) * 0.4f; var pos = Position + Offset + Region.Center; pos.X += (float) Math.Cos(SinOffset + T * 2.5f) * Scale * 8 * XChange; Graphics.Color = new Color(R, G, B, 0.5f); Graphics.Render(Region, pos, a, Region.Center, new Vector2(Scale * 10)); Graphics.Color = new Color(R, G, B, 1f); Graphics.Render(Region, pos, a, Region.Center, new Vector2(Scale * 5)); } public static void Hook(Area area) { area.Add(new RenderTrigger(() => { var state = Engine.Instance.StateRenderer; state.End(); var b = state.BlendState; state.BlendState = BlendState.Additive; state.Begin(); foreach (var e in area.Tagged[Tags.FireParticle]) { ((FireParticle) e).ActuallyRender(); } Graphics.Color = ColorUtils.WhiteColor; state.End(); state.BlendState = b; state.Begin(); }, Layers.WindFx)); } } } ================================================ FILE: BurningKnight/assets/particle/custom/ProjectileParticle.cs ================================================ using Lens; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class ProjectileParticle : Entity { private TextureRegion region; private float scale; private float angle; private Color color = new Color(0.5f, 0.5f, 1f, 1f); private Color secondColor = new Color(0.5f, 0.5f, 1f, 0.5f); public override void AddComponents() { base.AddComponents(); AlwaysActive = true; scale = Rnd.Float(5, 8); angle = Rnd.AnglePI(); region = CommonAse.Particles.GetSlice("fire"); Width = scale; Height = scale; Depth = 0; } public override void Update(float dt) { base.Update(dt); scale -= dt * 10; angle += scale * dt * 6; if (scale <= 0) { Done = true; } } public override void Render() { Graphics.Color = secondColor; Graphics.Render(region, Position, angle, region.Center, new Vector2(scale)); Graphics.Color = color; Graphics.Render(region, Position, angle, region.Center, new Vector2(scale * 0.5f)); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/assets/particle/custom/RainParticle.cs ================================================ using System; using BurningKnight.entity; using BurningKnight.entity.creature.player; using BurningKnight.level; using BurningKnight.util; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.assets.particle.custom { public class RainParticle : Entity { private Color color; private float target; private float size; private float speed; private bool poofed; public bool End; public bool Custom; private float delay; public override void Init() { base.Init(); AlwaysActive = true; AlwaysVisible = true; Depth = Layers.WindFx; Reset(); if (!Custom) { Y = Camera.Instance.Y + Rnd.Float(Display.Height + 100); } else { delay = Rnd.Float(0, 2f); } } private void Reset() { if (End) { Done = true; return; } color = 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)); X = Rnd.Float(Camera.Instance.X - 150, Camera.Instance.Right + 150); Y = Camera.Instance.Y - Rnd.Float(50, 60); size = Rnd.Float(20, 50); target = Camera.Instance.Y + Rnd.Float(Display.Height + 100); speed = Rnd.Float(1f, 1.5f); poofed = false; } public override void Update(float dt) { base.Update(dt); if (delay > 0) { delay -= dt; return; } var s = dt * 300f * speed; Position += MathUtils.CreateVector(Weather.RainAngle, s); if (Y >= target) { if (!poofed) { poofed = true; var pos = Position + MathUtils.CreateVector(Weather.RainAngle, size); if (!Player.InBuilding) { var c = Rnd.Int(2, 5); for (var i = 0; i < c; i++) { var part = new ParticleEntity(Particles.Rain()); part.Position = pos; part.Particle.Velocity = new Vector2(Rnd.Float(-40, 40), Rnd.Float(-30, -50)); part.Particle.Scale = Rnd.Float(1f, 1.6f); Area.Add(part); part.Depth = 0; } } } size -= 0.5f * s * (float) Math.Sin(Weather.RainAngle); if (size <= 0) { Reset(); return; } } if (Position.Y > Camera.Instance.Bottom + 20) { Reset(); } } public override void Render() { if (Player.InBuilding) { return; } Graphics.Batch.DrawLine(X, Y, X + (float) Math.Cos(Weather.RainAngle) * size, Y + (float) Math.Sin(Weather.RainAngle) * size, color); } } } ================================================ FILE: BurningKnight/assets/particle/custom/SnowParticle.cs ================================================ using System; using System.Numerics; using BurningKnight.entity; using BurningKnight.entity.creature.player; using BurningKnight.level; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; using Vector2 = Microsoft.Xna.Framework.Vector2; namespace BurningKnight.assets.particle.custom { public class SnowParticle : Entity { private static TextureRegion region; private Color color; private float target; private Vector2 size; private float speed; private float delay; private float t; public bool End; public bool Custom; public override void Init() { base.Init(); if (region == null) { region = CommonAse.Particles.GetSlice("circ"); } AlwaysActive = true; Depth = Layers.WindFx; Reset(); delay = 0; if (!Custom) { Y = Camera.Instance.Y + Rnd.Float(Display.Height + 20); } else { delay = Rnd.Float(0, 10f); } } private void Reset() { if (End) { Done = true; return; } var v = Rnd.Float(0.8f, 1f); color = new Color(v, v, v, Rnd.Float(0.8f, 1f)); X = Rnd.Float(Camera.Instance.X - 150, Camera.Instance.Right + 150); Y = Camera.Instance.Y - Rnd.Float(50, 60); size = new Vector2(Rnd.Float(0.05f, 0.3f)); target = Camera.Instance.Y + Rnd.Float(Display.Height + 20); speed = Rnd.Float(1f, 1.5f); delay = Rnd.Float(0, 5f); t = Rnd.Float(3); } public override void Update(float dt) { base.Update(dt); t += dt; if (delay > 0) { delay -= dt; if (!Custom && OnScreen) { delay = 0; } else { return; } } if (Y >= target) { size.X -= dt * 0.1f; size.Y = size.X; if (size.X <= 0) { Custom = false; Reset(); } return; } Position += MathUtils.CreateVector(Weather.RainAngle, dt * 30f * speed) + new Vector2((float) Math.Cos(t * 2 * speed) * dt * 10, 0); if (Position.Y > Camera.Instance.Bottom + 20) { Reset(); } } public override void Render() { if (Player.InBuilding) { return; } Graphics.Color = color; Graphics.Render(region, Position, 0, Vector2.Zero, size); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/assets/particle/custom/TextParticle.cs ================================================ using Lens; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.custom { public class TextParticle : Entity { private string text; public string Text { get => text; set { if (tweened) { return; } text = value; fullText = $"{(HasSign ? (Negative ? "-" : "+") : "")}{(count > 0 ? $"{count} " : "")} {text}"; var size = Font.Medium.MeasureString(fullText); origin = size / 2; Width = size.Width; Height = size.Height; gamePosition = start; scale.X = 0; scale.Y = 3; t = 0; Tween.To(1, scale.X, x => scale.X = x, 0.3f); Tween.To(1, scale.Y, x => scale.Y = x, 0.3f); } } private float count; public float Count { get => count; set { count = value; // To update the text Text = text; } } public bool HasSign; public bool Negative; public bool Stacks = true; private string fullText; private Vector2 start; private Vector2 origin; private Vector2 scale; private float t; private bool tweened; private Vector2 gamePosition; private Vector2 offset; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; AlwaysVisible = true; scale.X = 0; scale.Y = 0; Tween.To(1, scale.X, x => scale.X = x, 0.2f); Tween.To(1, scale.Y, x => scale.Y = x, 0.2f); offset.Y = 8; Tween.To(0, offset.Y, x => offset.Y = x, 0.3f); AddTag(Tags.TextParticle); } public override void PostInit() { base.PostInit(); start = Center; gamePosition = Center; } public override void Update(float dt) { base.Update(dt); if (Camera.Instance == null) { Done = true; return; } t += dt; if (!tweened && t >= 2f) { tweened = true; Tween.To(0, scale.X, x => scale.X = x, 0.15f, Ease.QuadIn); Tween.To(3, scale.Y, x => scale.Y = x, 0.15f, Ease.QuadIn).OnEnd = () => { Done = true; }; Tween.To(-18, offset.Y, x => offset.Y = x, 0.15f, Ease.QuadIn); } if (!tweened) { foreach (var p in Area.Tagged[Tags.TextParticle]) { var part = (TextParticle) p; if (part == this) { continue; } var rect = new Rectangle((int) gamePosition.X, (int) gamePosition.Y, (int) Width, (int) Height); if (rect.Intersects(new Rectangle((int) part.gamePosition.X, (int) part.gamePosition.Y, (int) part.Width, (int) part.Height))) { var s = dt * 300; if (part.gamePosition.Y <= gamePosition.Y) { part.gamePosition.Y -= s; } else { // gamePosition.Y += s; } } } } Center = Camera.Instance.CameraToUi(gamePosition) + offset; } public override void Render() { if (fullText != null) { Graphics.Print(fullText, Font.Medium, Center, 0, origin, scale); } } public static TextParticle Add(Entity owner, string text, float count = 0, bool hasSign = false, bool minus = false) { var where = owner.TopCenter - new Vector2(0, 4); var min = 72f; TextParticle prt = null; foreach (var p in Engine.Instance.State.Ui.Tagged[Tags.TextParticle]) { var pr = (TextParticle) p; if (!pr.Stacks) { continue; } if (pr.text == text && pr.Negative == minus && !pr.tweened) { var d = (pr.gamePosition - where).Length(); if(d < min) { min = d; prt = pr; } } } if (prt != null) { prt.Count += count; return prt; } var part = new TextParticle(); part.BottomCenter = where; Engine.Instance.State.Ui.Add(part); part.HasSign = hasSign; part.Count = count; part.Negative = minus; part.Text = text; return part; } } } ================================================ FILE: BurningKnight/assets/particle/custom/TileParticle.cs ================================================ using BurningKnight.entity; using BurningKnight.entity.component; using BurningKnight.level.tile; using BurningKnight.state; using Lens; using Lens.entity; using Lens.graphics; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; using Tile = BurningKnight.level.tile.Tile; namespace BurningKnight.assets.particle.custom { public class TileParticle : Entity { private static Vector2 origin = new Vector2(8, 24); private static Vector2 originB = new Vector2(8, 8); public static float MaxZ = Display.Height; public TextureRegion Top; public TextureRegion TopTarget; public TextureRegion Side; public TextureRegion Sides; public Vector2 Scale = new Vector2(0, 3); public float Z; public Tile Tile; public Tile OriginalTile; public bool FromBottom; public Vector2 Target; public float TargetZ; public override void AddComponents() { base.AddComponents(); Height = 24; AlwaysActive = true; if (FromBottom) { var level = Run.Level; var x = (int) (X / 16); var y = (int) ((Y + 8) / 16); OriginalTile = level.Get(x, y); if (OriginalTile == Tile.Chasm) { Done = true; return; } if (!OriginalTile.IsWall()) { Z = -8; } Scale.X = 1; Scale.Y = 1; level.Set(x, y, Tile.Chasm); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); Tween.To(MaxZ, Z, z => { if (z > 8) { Depth = Layers.FlyingMob; } Z = z; }, 0.5f, Ease.QuadIn).OnEnd = () => { Tween.To(Target.X, X, v => X = v, 1f, Ease.QuadInOut); Tween.To(Target.Y, Y, v => Y = v, 1f, Ease.QuadInOut).OnEnd = () => { x = (int) ((Target.X + 8) / 16); y = (int) ((Target.Y + 8) / 16); if (level.Get(x, y) != Tile.Chasm) { Top = TopTarget; } else { TargetZ = -8; Tile = OriginalTile; } AnimateFall(); }; }; } else { Z = MaxZ; Depth = Layers.FlyingMob; Tween.To(1f, Scale.X, x => Scale.X = x, 0.4f); Tween.To(1f, Scale.Y, x => Scale.Y = x, 0.4f); AnimateFall(); } AddComponent(new ShadowComponent(RenderShadow)); } private void AnimateFall() { Tween.To(TargetZ, Z, x => { Z = x; if (Z <= 8f) { Depth = 0; } }, 0.5f, Ease.QuadIn).OnEnd = () => { if (TargetZ >= -0.01f) { Scale.X = 3; Scale.Y = 0.3f; } AudioEmitterComponent.Dummy(Area, Center).Emit($"level_rock_{Rnd.Int(1, 3)}", 0.5f); if (TargetZ < 0) { Finish(); } else { Tween.To(1, Scale.X, x => Scale.X = x, 0.5f); Tween.To(1, Scale.Y, x => Scale.Y = x, 0.5f).OnEnd = () => { Finish(); }; } }; } private void Finish() { var level = Run.Level; var x = (int) (CenterX / 16); var y = (int) ((Y + 8) / 16); level.Liquid[level.ToIndex(x, y)] = 0; level.Set(x, y, Tile); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); Done = true; } public void RenderShadow() { if (Z >= 0) { var or = Top.Center; Graphics.Render(Top, Position + or + new Vector2(0, 16), 0, or, Scale); } } public override void Render() { var v = Position + originB - new Vector2(0, Z - 16); Graphics.Render(Top, Position + origin - new Vector2(0, Z), 0, origin, Scale); if (Z >= 0) { Graphics.Render(Side, v, 0, originB, Scale); Graphics.Render(Sides, v, 0, originB, Scale); } } } } ================================================ FILE: BurningKnight/assets/particle/renderer/AnimatedParticleRenderer.cs ================================================ using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.renderer { public class AnimatedParticleRenderer : ParticleRenderer { public override void Render(Particle particle) { var part = (AnimatedParticle) particle; var region = part.Animation.GetCurrentTexture(); Graphics.Render(region, part.Position, part.Angle, region.Center, new Vector2(particle.Scale)); } public override void RenderShadow(Particle particle) { var part = (AnimatedParticle) particle; var region = part.Animation.GetCurrentTexture(); Graphics.Render(region, part.Position + new Vector2(0, 6), part.Angle, region.Center, new Vector2(particle.Scale)); } } } ================================================ FILE: BurningKnight/assets/particle/renderer/HealthParticleRenderer.cs ================================================ using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.renderer { public class HealthParticleRenderer : TexturedParticleRenderer { private float scale; public HealthParticleRenderer(TextureRegion r, float sx) { Region = r; scale = sx; } public override void Render(Particle particle) { Graphics.Color = new Color(1f, 1f, 1f, particle.Alpha); Graphics.Render(Region, particle.Position, 0, Vector2.Zero, new Vector2(scale, 1)); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/assets/particle/renderer/ParticleRenderer.cs ================================================ namespace BurningKnight.assets.particle.renderer { public class ParticleRenderer { public virtual void Render(Particle particle) { } public virtual void RenderShadow(Particle particle) { } } } ================================================ FILE: BurningKnight/assets/particle/renderer/RandomFrameRenderer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.util; using Lens.assets; using Lens.graphics; using Lens.graphics.animation; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.renderer { public class RandomFrameRenderer : ParticleRenderer { private List animation; public RandomFrameRenderer(string anim) { animation = Animations.Get(anim).Layers.First().Value; } public override void Render(Particle particle) { var region = animation[particle.Rnd % animation.Count].Texture; Graphics.Color.A = (byte) MathUtils.Clamp(0, 255, particle.Alpha * 255); Graphics.Render(region, particle.Position - new Vector2(0, particle.Z), particle.Angle, region.Center, new Vector2(particle.Scale)); Graphics.Color.A = 255; } } } ================================================ FILE: BurningKnight/assets/particle/renderer/TexturedParticleRenderer.cs ================================================ using Lens.assets; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.assets.particle.renderer { public class TexturedParticleRenderer : ParticleRenderer { public TextureRegion Region; public TexturedParticleRenderer(string slice) { Region = Animations.Get("particles").GetSlice(slice); } public TexturedParticleRenderer(TextureRegion r) { Region = r; } public TexturedParticleRenderer() { } public override void Render(Particle particle) { var s = particle.Alpha <= 0.99f; if (s) { Graphics.Color = new Color(1f, 1f, 1f, particle.Alpha); } Graphics.Render(Region, particle.Position - new Vector2(0, particle.Z), particle.Angle, Region.Center, new Vector2(particle.Scale)); if (s) { Graphics.Color = ColorUtils.WhiteColor; } } public override void RenderShadow(Particle particle) { if (particle.Z > 0.9f) { Graphics.Render(Region, particle.Position, particle.Angle, Region.Center, new Vector2(particle.Scale)); } } } } ================================================ FILE: BurningKnight/assets/prefabs/Prefab.cs ================================================ using System; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.rooms; using BurningKnight.save; using Lens.util.file; using Microsoft.Xna.Framework; namespace BurningKnight.assets.prefabs { public class Prefab { public PrefabData[] Datas; public Level Level; public void Place(Level level, int x, int y) { var pos = new Vector2(x * 16, y * 16); var reader = new FileReader(null); foreach (var d in Datas) { if (d.Type == typeof(Level)) { continue; } var e = (SaveableEntity) Activator.CreateInstance(d.Type); level.Area.Add(e, false); reader.SetData(d.Data); e.Load(reader); if (e is Room r) { r.MapX += x; r.MapY += y; } else { e.Position += pos; } e.PostInit(); } for (int ty = 0; ty < Level.Height && ty + y < level.Height; ty++) { for (int tx = 0; tx < Level.Width && tx + x < level.Width; tx++) { var i = Level.ToIndex(tx, ty); var i2 = level.ToIndex(tx + x, ty + y); level.Tiles[i2] = Level.Tiles[i]; level.Liquid[i2] = Level.Liquid[i]; } } } } } ================================================ FILE: BurningKnight/assets/prefabs/Prefabs.cs ================================================ using System; using System.Collections.Generic; using System.IO; using BurningKnight.save; using BurningKnight.state; using BurningKnight.util; using Lens; using Lens.entity; using Lens.util; using Lens.util.file; namespace BurningKnight.assets.prefabs { public static class Prefabs { private static Dictionary loaded = new Dictionary(); private static List paths = new List(); private static PrefabSaver saver = new PrefabSaver(); public static void Reload() { loaded.Clear(); Load(); } public static void Load() { Load(FileHandle.FromRoot("Prefabs/")); Run.Level = null; } public static Prefab Get(string id) { return loaded.TryGetValue(id, out var fab) ? fab : null; } private static void Load(FileHandle handle) { if (!handle.Exists()) { return; } if (handle.IsDirectory()) { foreach (var file in handle.ListFileHandles()) { Load(file); } foreach (var file in handle.ListDirectoryHandles()) { Load(file); } return; } if (handle.Extension != ".lvl") { return; } Log.Info($"Loading prefab {handle.FullPath}"); try { var prefab = new Prefab(); var stream = new FileReader(handle.FullPath); if (stream.ReadInt32() != SaveManager.MagicNumber) { Log.Error("Invalid magic number!"); return; } var version = stream.ReadInt16(); if (version > SaveManager.Version) { Log.Error($"Unknown version {version}"); } else if (version < SaveManager.Version) { // do something on it } if (stream.ReadByte() != (byte) SaveType.Level) { return; } saver.Load(new Area {NoInit = true}, stream, false); prefab.Level = Run.Level; prefab.Datas = ArrayUtils.Clone(saver.Datas); saver.Datas.Clear(); loaded[handle.NameWithoutExtension] = prefab; Run.Level = null; } catch (Exception e) { Log.Error($"Failed to load prefab {handle.NameWithoutExtension}"); Log.Error(e); } } private static void OnChanged(object sender, FileSystemEventArgs args) { Log.Debug($"Reloading {args.FullPath}"); Load(new FileHandle(args.FullPath)); } public static void Destroy() { loaded.Clear(); } } } ================================================ FILE: BurningKnight/debug/BiomeCommand.cs ================================================ using BurningKnight.level.biome; namespace BurningKnight.debug { public class BiomeCommand : ConsoleCommand { public BiomeCommand() { Name = "biome"; ShortName = "b"; } public override void Run(Console Console, string[] Args) { if (Args.Length == 1) { state.Run.Level.SetBiome(BiomeRegistry.Get(Args[0])); } else { Console.Print("/biome [id]"); } } } } ================================================ FILE: BurningKnight/debug/BuffCommand.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; namespace BurningKnight.debug { public class BuffCommand : ConsoleCommand { public BuffCommand() { ShortName = "bf"; Name = "buff"; } public override void Run(Console Console, string[] Args) { if (Args.Length > 0 && Args.Length < 2) { var id = Args[0]; if (!id.Contains(":")) { id = $"{Mods.BurningKnight}:{id}"; } var player = LocalPlayer.Locate(Console.GameArea); player.GetComponent().Add(id).TimeLeft = 128; } } } } ================================================ FILE: BurningKnight/debug/CheatWindow.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.ui.imgui; using ImGuiNET; using Lens; namespace BurningKnight.debug { public static class CheatWindow { public static bool AutoGodMode = BK.Version.Dev; public static bool InfiniteActive; public static bool NoSleep; public static void Render() { if (!WindowManager.Cheats) { return; } if (!ImGui.Begin("Cheats", ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.End(); return; } var player = LocalPlayer.Locate(Engine.Instance.State.Area); if (player != null) { ImGui.Checkbox("God Mode", ref player.GetComponent().Unhittable); } if (ImGui.Checkbox("Auto god mode", ref AutoGodMode) && player != null) { player.GetComponent().Unhittable = AutoGodMode; } ImGui.Separator(); if (ImGui.Checkbox("Infinite active charge", ref InfiniteActive) && player != null && InfiniteActive) { player.GetComponent().Pickup(Items.CreateAndAdd("bk:battery", player.Area)); } ImGui.Checkbox("No Sleep", ref NoSleep); ImGui.End(); } } } ================================================ FILE: BurningKnight/debug/Console.cs ================================================ using System; using System.Collections.Generic; using System.Numerics; using BurningKnight.assets; using BurningKnight.entity; using BurningKnight.state; using BurningKnight.ui.imgui; using ImGuiNET; using Lens; using Lens.entity; using Lens.graphics; using Lens.input; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Vector2 = Microsoft.Xna.Framework.Vector2; namespace BurningKnight.debug { public unsafe class Console { private static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 200); private static System.Numerics.Vector2 spacer = new System.Numerics.Vector2(4, 1); private static System.Numerics.Vector4 color = new System.Numerics.Vector4(1, 0.4f, 0.4f, 1f); private ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private List commands = new List(); private string input = ""; public List Lines = new List(); public Area GameArea; public static bool Open; private bool forceFocus; public Console(Area area) { GameArea = area; commands.Add(new SpawnCommand()); commands.Add(new GiveCommand()); commands.Add(new HealCommand()); commands.Add(new GodModeCommand()); commands.Add(new LevelCommand()); commands.Add(new DebugCommand()); commands.Add(new DieCommand()); commands.Add(new ZoomCommand()); commands.Add(new HurtCommand()); commands.Add(new EntityCommand()); commands.Add(new SaveCommand()); commands.Add(new BiomeCommand()); commands.Add(new ExploreCommand()); commands.Add(new PassableCommand()); commands.Add(new BuffCommand()); commands.Add(new TileCommand()); commands.Add(new HappeningCommand()); } public void AddCommand(ConsoleCommand command) { commands.Add(command); } public void Print(string str) { Lines.Add(str); Log.Debug(str); } public void Update(float dt) { if (InGameState.ToolsEnabled && Input.Keyboard.WasPressed(Keys.F1, true)) { Open = !Open; Camera.Instance.Detached = Open; Input.EnableImGuiFocus = Open; } } public void Render() { if (!WindowManager.Console) { return; } if (forceFocus) { ImGui.SetNextWindowCollapsed(false); } ImGui.SetNextWindowSize(size, ImGuiCond.Once); ImGui.SetNextWindowPos(new System.Numerics.Vector2(10, Engine.Instance.GetScreenHeight() - size.Y - 10), ImGuiCond.Once); ImGui.Begin("Console", ImGuiWindowFlags.NoTitleBar); /* filter.Draw("##console"); ImGui.SameLine(); if (ImGui.Button("Clear")) { Lines.Clear(); } ImGui.Separator();*/ var height = ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeightWithSpacing(); ImGui.BeginChild("ScrollingRegionConsole", new System.Numerics.Vector2(0, -height), false, ImGuiWindowFlags.HorizontalScrollbar); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, spacer); foreach (var t in Lines) { if (filter.PassFilter(t)) { var popColor = false; if (t[0] == '>') { popColor = true; ImGui.PushStyleColor(ImGuiCol.Text, color); } ImGui.TextUnformatted(t); if (popColor) { ImGui.PopStyleColor(); } } } ImGui.PopStyleVar(); ImGui.EndChild(); ImGui.Separator(); if (ImGui.InputText("##Input", ref input, 128, ImGuiInputTextFlags.EnterReturnsTrue)) { RunCommand(input); input = ""; } ImGui.SetItemDefaultFocus(); if (forceFocus) { ImGui.SetKeyboardFocusHere(-1); } forceFocus = false; ImGui.End(); } public void RunCommand(string input) { input = input.TrimEnd(); Lines.Add($"> {input}"); var parts = input.Split(null); var name = parts[0]; foreach (var command in commands) { if (command.Name.Equals(name) || command.ShortName.Equals(name)) { var args = new string[parts.Length - 1]; for (int i = 0; i < args.Length; i++) { args[i] = parts[i + 1]; } try { command.Run(this, args); } catch (Exception e) { Log.Error(e); } return; } } Print("Unknown command"); } } } ================================================ FILE: BurningKnight/debug/ConsoleCommand.cs ================================================ namespace BurningKnight.debug { public abstract class ConsoleCommand { public enum Access { Everyone, Testers, Developers } public Access RunPermission = Access.Everyone; public string Name; public string ShortName; public abstract void Run(Console Console, string[] Args); public virtual string AutoComplete(string input) { return ""; } } } ================================================ FILE: BurningKnight/debug/DebugCommand.cs ================================================ using BurningKnight.physics; namespace BurningKnight.debug { public class DebugCommand : ConsoleCommand { public DebugCommand() { _Init(); } protected void _Init() { { Name = "debug"; ShortName = "d"; } } public override void Run(Console Console, string[] Args) { Physics.RenderDebug = !Physics.RenderDebug; } } } ================================================ FILE: BurningKnight/debug/DieCommand.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.debug { public class DieCommand : ConsoleCommand { public DieCommand() { _Init(); } protected void _Init() { { Name = "kill"; ShortName = "k"; } } public override void Run(Console Console, string[] Args) { foreach (var player in Console.GameArea.Tagged[Tags.Player]) { player.GetComponent().Kill(null); } } } } ================================================ FILE: BurningKnight/debug/EntityCommand.cs ================================================ using Lens.game; namespace BurningKnight.debug { public class EntityCommand : ConsoleCommand { public EntityCommand() { Name = "entity"; ShortName = "e"; } public override void Run(Console Console, string[] Args) { GameState.RenderDebug = !GameState.RenderDebug; } } } ================================================ FILE: BurningKnight/debug/ExploreCommand.cs ================================================ namespace BurningKnight.debug { public class ExploreCommand : ConsoleCommand { public ExploreCommand() { Name = "explore"; ShortName = "ex"; } public override void Run(Console Console, string[] Args) { var level = state.Run.Level; for (var i = 0; i < level.Explored.Length; i++) { level.Explored[i] = true; } } } } ================================================ FILE: BurningKnight/debug/GiveCommand.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.item; using Lens.input; using Lens.util; namespace BurningKnight.debug { public class GiveCommand : ConsoleCommand { public GiveCommand() { _Init(); } protected void _Init() { { ShortName = "gv"; Name = "give"; } } public override void Run(Console Console, string[] Args) { var player = LocalPlayer.Locate(Console.GameArea); for (var i = 0; i < Args.Length; i++) { var id = Args[i]; var count = 1; var cursed = false; if (!id.Contains(":")) { id = $"{Mods.BurningKnight}:{id}"; } if (id.EndsWith("_")) { id = id.Substring(0, id.Length - 1); cursed = true; } if (i < Args.Length - 1) { var c = Args[i + 1]; if (int.TryParse(c, out count) && count > 0) { i++; } else { count = 1; } } if (id != "bk:coin" && !Items.Has(id)) { Console.Print($"Unknown item {id}"); continue; } Log.Info($"Giving {id} x{count}"); for (var j = 0; j < count; j++) { var item = Items.CreateAndAdd(id, Console.GameArea); if (cursed) { item.Scourged = true; } player?.GetComponent().Pickup(item); } } } } } ================================================ FILE: BurningKnight/debug/GodModeCommand.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; namespace BurningKnight.debug { public class GodModeCommand : ConsoleCommand { public GodModeCommand() { _Init(); } protected void _Init() { { Name = "gm"; ShortName = "g"; } } public override void Run(Console Console, string[] Args) { var all = Console.GameArea.Tagged[Tags.Player]; foreach (var player in all) { var health = player.GetComponent(); health.Unhittable = !health.Unhittable; TextParticle.Add(player, "God Mode", 1, true, !health.Unhittable); Console.Print(health.Unhittable ? "God mode is on" : "God mode is off"); } } } } ================================================ FILE: BurningKnight/debug/HappeningCommand.cs ================================================ using System; using BurningKnight.entity.creature.player; using BurningKnight.entity.twitch.happening; using Lens; using Lens.util; using Lens.util.timer; namespace BurningKnight.debug { public class HappeningCommand : ConsoleCommand { public HappeningCommand() { Name = "HappeningCommand"; ShortName = "hp"; } public override void Run(Console Console, string[] Args) { if (Args.Length == 1) { var h = HappeningRegistry.Get(Args[0]); if (h == null) { return; } try { var p = LocalPlayer.Locate(Engine.Instance.State.Area); h.Happen(p); Timer.Add(() => { h.End(p); }, h.GetVoteDelay()); } catch (Exception e) { Log.Error(e); } } } } } ================================================ FILE: BurningKnight/debug/HealCommand.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.debug { public class HealCommand : ConsoleCommand { public HealCommand() { _Init(); } protected void _Init() { { Name = "heal"; ShortName = "h"; } } public override void Run(Console Console, string[] Args) { foreach (var player in Console.GameArea.Tagged[Tags.Player]) { var component = player.GetComponent(); component.SetHealth(component.MaxHealth, null); } } } } ================================================ FILE: BurningKnight/debug/HurtCommand.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.debug { public class HurtCommand : ConsoleCommand { public HurtCommand() { _Init(); } protected void _Init() { { Name = "hurt"; ShortName = "o"; } } public override void Run(Console Console, string[] Args) { foreach (var player in Console.GameArea.Tagged[Tags.Player]) { player.GetComponent().ModifyHealth(-1, player); } } } } ================================================ FILE: BurningKnight/debug/LevelCommand.cs ================================================ using System; using BurningKnight.entity; using BurningKnight.entity.creature.player; using Microsoft.Xna.Framework; namespace BurningKnight.debug { public class LevelCommand : ConsoleCommand { public LevelCommand() { _Init(); } protected void _Init() { { Name = "lvl"; ShortName = "l"; } } public override void Run(Console Console, string[] Args) { if (Args.Length > 0) { state.Run.Depth = Int32.Parse(Args[0]); state.Run.ActualDepth = -10; if (Args.Length > 1) { state.Run.Loop = Int32.Parse(Args[1]); } } } } } ================================================ FILE: BurningKnight/debug/LevelLayerDebug.cs ================================================ using BurningKnight.ui.imgui; using ImGuiNET; namespace BurningKnight.debug { public static class LevelLayerDebug { public static bool Chasms = true; public static bool Floor = true; public static bool Liquids = true; public static bool Mess = true; public static bool Sides = true; public static bool Walls = true; public static bool Blood = true; public static bool Lights = true; public static bool TileLight = true; public static bool Shadows = true; public static bool Rocks = true; public static void Render() { if (!WindowManager.LayerDebug) { return; } if (!ImGui.Begin("Layer Debug", ImGuiWindowFlags.AlwaysAutoResize)) { ImGui.End(); return; } if (ImGui.Button("Show")) { Chasms = Floor = Liquids = Mess = Sides = Walls = Blood = Lights = TileLight = Rocks = Shadows = true; } ImGui.SameLine(); if (ImGui.Button("Hide")) { Chasms = Floor = Liquids = Mess = Sides = Walls = Blood = Lights = TileLight = Rocks = Shadows = false; } ImGui.Checkbox("Chasms", ref Chasms); ImGui.Checkbox("Floor", ref Floor); ImGui.Checkbox("Mess", ref Mess); ImGui.Checkbox("Liquids", ref Liquids); ImGui.Checkbox("Shadows", ref Shadows); ImGui.Checkbox("Sides", ref Sides); ImGui.Checkbox("Walls", ref Walls); ImGui.Checkbox("Blood", ref Blood); ImGui.Checkbox("Lights", ref Lights); ImGui.Checkbox("Tile Light", ref TileLight); ImGui.Checkbox("Rocks", ref Rocks); ImGui.End(); } } } ================================================ FILE: BurningKnight/debug/LootTableEditor.cs ================================================ using BurningKnight.assets.loot; using BurningKnight.entity.creature.drop; using BurningKnight.ui.imgui; using ImGuiNET; using Lens.input; using Lens.lightJson; using Microsoft.Xna.Framework.Input; using ImGui = ImGuiNET.ImGui; namespace BurningKnight.debug { public static class LootTableEditor { private static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400); private static int id; private static int count; private static string selectedTable; private static string poolName = ""; public static void Render() { if (!WindowManager.LootTable) { return; } ImGui.SetNextWindowSize(size, ImGuiCond.Once); if (!ImGui.Begin("Loot Table Editor")) { ImGui.End(); return; } if (ImGui.Button("Save")) { LootTables.Save(); } ImGui.SameLine(); if (ImGui.Button("New##pe")) { ImGui.OpenPopup("Add Item##pe"); } if (selectedTable != null) { ImGui.SameLine(); if (ImGui.Button("Delete")) { LootTables.Defined.Remove(selectedTable); LootTables.Data.Remove(selectedTable); selectedTable = null; } } filter.Draw(""); ImGui.SameLine(); ImGui.Text($"{count}"); if (ImGui.BeginPopupModal("Add Item##pe")) { ImGui.PushItemWidth(300); ImGui.InputText("Id", ref poolName, 64); ImGui.PopItemWidth(); if (ImGui.Button("Add") || Input.Keyboard.WasPressed(Keys.Enter, true)) { selectedTable = poolName; LootTables.Defined[poolName] = new AnyDrop(); LootTables.Data[poolName] = new JsonObject { ["type"] = "any" }; poolName = ""; ImGui.CloseCurrentPopup(); } ImGui.SameLine(); if (ImGui.Button("Cancel") || Input.Keyboard.WasPressed(Keys.Escape, true)) { poolName = ""; ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (selectedTable != null) { ImGui.SameLine(); if (ImGui.Button("Remove##pe")) { LootTables.Defined.Remove(selectedTable); selectedTable = null; } } count = 0; ImGui.Separator(); var height = ImGui.GetStyle().ItemSpacing.Y; ImGui.BeginChild("rolingRegionItems##Pe", new System.Numerics.Vector2(0, -height), false, ImGuiWindowFlags.HorizontalScrollbar); foreach (var i in LootTables.Defined) { ImGui.PushID($"{id}___m"); if (filter.PassFilter(i.Key)) { count++; if (ImGui.Selectable($"{i.Key}##ped", i.Key == selectedTable)) { selectedTable = i.Key; } } ImGui.PopID(); id++; } id = 0; ImGui.EndChild(); ImGui.End(); if (selectedTable == null) { return; } var show = true; ImGui.SetNextWindowSize(size, ImGuiCond.Once); if (!ImGui.Begin("Loot Table", ref show)) { ImGui.End(); return; } if (!show) { selectedTable = null; ImGui.End(); return; } LootTables.RenderDrop(LootTables.Data[selectedTable]); ImGui.End(); } } } ================================================ FILE: BurningKnight/debug/PassableCommand.cs ================================================ using BurningKnight.level; namespace BurningKnight.debug { public class PassableCommand : ConsoleCommand { public PassableCommand() { Name = "passable"; ShortName = "p"; } public override void Run(Console Console, string[] Args) { Level.RenderPassable = !Level.RenderPassable; } } } ================================================ FILE: BurningKnight/debug/PoolEditor.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.item; using BurningKnight.state; using BurningKnight.ui.imgui; using BurningKnight.util; using ImGuiNET; using Lens.input; using Microsoft.Xna.Framework.Input; namespace BurningKnight.debug { public static class PoolEditor { private static unsafe ImGuiTextFilterPtr filter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private static unsafe ImGuiTextFilterPtr popupFilter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private static System.Numerics.Vector2 size = new System.Numerics.Vector2(300, 400); private static System.Numerics.Vector2 popupSize = new System.Numerics.Vector2(400, 400); private static string selectedItem; private static int id; private static int count; public static int Pool; public static void Render() { if (!WindowManager.PoolEditor) { return; } ImGui.SetNextWindowSize(size, ImGuiCond.Once); if (!ImGui.Begin("Pool Editor##re")) { ImGui.End(); return; } ImGui.Combo("Pool##pe", ref Pool, ItemPool.Names, ItemPool.Count); ImGui.Separator(); filter.Draw(""); ImGui.SameLine(); ImGui.Text($"{count}"); if (ImGui.Button("Add##pe")) { ImGui.OpenPopup("Add Item##pe"); } if (ImGui.BeginPopupModal("Add Item##pe")) { ImGui.SetWindowSize(popupSize); popupFilter.Draw(""); ImGui.BeginChild("ScrollinegionUses##reee", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), false, ImGuiWindowFlags.HorizontalScrollbar); ImGui.Separator(); foreach (var i in Items.Datas) { ImGui.PushID($"{id}__itm"); if (!BitHelper.IsBitSet(i.Value.Pools, Pool) && popupFilter.PassFilter(i.Key) && ImGui.Selectable($"{i.Key}##d", selectedItem == i.Key)) { selectedItem = i.Key; } ImGui.PopID(); id++; } id = 0; ImGui.EndChild(); ImGui.Separator(); if (selectedItem != null && (ImGui.Button("Add") || Input.Keyboard.WasPressed(Keys.Enter, true))) { ItemEditor.Selected = Items.Datas[selectedItem]; ItemEditor.ForceFocus = true; ItemEditor.Selected.Pools = BitHelper.SetBit(ItemEditor.Selected.Pools, Pool, true); ImGui.CloseCurrentPopup(); } ImGui.SameLine(); if (ImGui.Button("Cancel") || Input.Keyboard.WasPressed(Keys.Escape, true)) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } if (ItemEditor.Selected != null) { ImGui.SameLine(); if (ImGui.Button("Remove##pe")) { ItemEditor.Selected.Pools = BitHelper.SetBit(ItemEditor.Selected.Pools, Pool, false); ItemEditor.Selected = null; } } count = 0; ImGui.Separator(); var height = ImGui.GetStyle().ItemSpacing.Y; ImGui.BeginChild("rollingRegionItems##Pe", new System.Numerics.Vector2(0, -height), false, ImGuiWindowFlags.HorizontalScrollbar); foreach (var i in Items.Datas.Values) { ImGui.PushID($"{id}___m"); if (filter.PassFilter(i.Id)) { if (!BitHelper.IsBitSet(i.Pools, Pool)) { continue; } count++; if (ImGui.Selectable($"{i.Id}##ped", i == ItemEditor.Selected)) { if (i != ItemEditor.Selected) { ItemEditor.Selected = i; ItemEditor.ForceFocus = true; WindowManager.ItemEditor = true; } } } ImGui.PopID(); id++; } id = 0; ImGui.EndChild(); ImGui.End(); } } } ================================================ FILE: BurningKnight/debug/SaveCommand.cs ================================================ using System.Threading; using BurningKnight.save; using Lens; using Lens.util.file; namespace BurningKnight.debug { public class SaveCommand : ConsoleCommand { public SaveCommand() { Name = "save"; ShortName = "s"; } public override void Run(Console console, string[] args) { if (args.Length == 0 || args.Length > 3) { console.Print("save [save path] (save type)"); return; } var path = args[0]; var saveType = args.Length == 1 ? "all" : args[1]; var area = Engine.Instance.State.Area; var thread = new Thread(() => { switch (saveType) { case "all": { SaveManager.Save(area, SaveType.Level, false, path); SaveManager.Save(area, SaveType.Player, false, path); SaveManager.Save(area, SaveType.Game, false, path); SaveManager.Save(area, SaveType.Global, false, path); break; } case "level": { SaveManager.Save(area, SaveType.Level, false, path); break; } case "player": { SaveManager.Save(area, SaveType.Player, false, path); break; } case "game": { SaveManager.Save(area, SaveType.Game, false, path); break; } case "global": { SaveManager.Save(area, SaveType.Global, false, path); break; } case "run": { SaveManager.Save(area, SaveType.Level, false, path); SaveManager.Save(area, SaveType.Player, false, path); SaveManager.Save(area, SaveType.Game, false, path); break; } case "prefab": { SaveManager.Save(area, SaveType.Level, false, $"{FileHandle.FromRoot("Prefabs/").FullPath}/{path}.lvl"); break; } default: { console.Print($"Unknown save type {saveType}. Should be one of all, level, player, game, global, run, prefab"); break; } } console.Print($"Done saving {saveType}"); }); thread.Start(); } } } ================================================ FILE: BurningKnight/debug/SpawnCommand.cs ================================================ using System; using BurningKnight.ui.editor; using Lens.entity; using Lens.util; namespace BurningKnight.debug { public class SpawnCommand : ConsoleCommand { public SpawnCommand() { Name = "spawn"; ShortName = "s"; } public override void Run(Console Console, string[] Args) { if (Args.Length != 1) { Console.Print("Usage: spawn [entity]"); return; } var name = Args[0]; var small = name.ToLower(); foreach (var type in EntityEditor.Types) { if (type.Name.ToLower() == small) { try { var entity = (Entity) Activator.CreateInstance(type.Type); Console.GameArea.Add(entity); entity.BottomCenter = Console.GameArea.Tagged[Tags.Player][0].BottomCenter; } catch (Exception e) { Log.Error(e); Console.Print($"Failed to create entity {name}, consult @egordorichev"); } return; } } Console.Print($"Unknown entity {name}"); } } } ================================================ FILE: BurningKnight/debug/TileCommand.cs ================================================ namespace BurningKnight.debug { public class TileCommand : ConsoleCommand { public TileCommand() { Name = "tile"; ShortName = "t"; } public override void Run(Console Console, string[] Args) { var level = state.Run.Level; if (level != null) { // level.Resize(level.Width, level.Height); level.RefreshSurfaces(); level.TileUp(true); } } } } ================================================ FILE: BurningKnight/debug/ZoomCommand.cs ================================================ using System; using Lens; namespace BurningKnight.debug { public class ZoomCommand : ConsoleCommand { public ZoomCommand() { _Init(); } protected void _Init() { { Name = "zoom"; ShortName = "z"; } } public override void Run(Console Console, string[] Args) { if (Args.Length == 0) { return; } float Zoom = Math.Max(0, Single.Parse(Args[0])); Engine.Instance.SetWindowed((int) (Display.Width * Zoom), (int) (Display.Height * Zoom)); } } } ================================================ FILE: BurningKnight/entity/BlankMaker.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity { public static class BlankMaker { public const float Radius = 48f; public static void Make(Vector2 where, Area area, float r = Radius) { foreach (var p in area.Tagged[Tags.Projectile]) { if (p.DistanceTo(where) <= r) { ((Projectile) p).Break(); } } foreach (var e in area.Tagged[Tags.MustBeKilled]) { if (e.DistanceTo(where) <= r) { e.GetAnyComponent()?.KnockbackFrom(where, 10f); } } for (var i = 0; i < 10; i++) { var a = i * 0.1f * Math.PI * 2 + Rnd.Float(-0.1f, 0.1f); AnimationUtil.PoofFrom(where + MathUtils.CreateVector(a, r - 8), where); } for (var i = 0; i < 10; i++) { var a = Rnd.AnglePI(); var d = Rnd.Float(r); AnimationUtil.PoofFrom(where + MathUtils.CreateVector(a, d), where); } Camera.Instance.Shake(6); } } } ================================================ FILE: BurningKnight/entity/Cursor.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.state; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.input; using Lens.util; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity { public class Cursor : Entity, CustomCameraJumper { private static TextureRegion[] regions; private Vector2 scale = new Vector2(1); private Vector2 stickOffset; private bool needsAdjusting = true; private bool readTint = true; private Color tint; private Vector2 lastPos; public Player Player; public Vector2 GamePosition; public override void Init() { base.Init(); AlwaysActive = true; AlwaysVisible = true; Depth = Layers.Cursor; Width = 0; Height = 0; AddTag(Tags.Cursor); if (regions == null) { regions = new[] { CommonAse.Ui.GetSlice("cursor_a"), CommonAse.Ui.GetSlice("cursor_b"), CommonAse.Ui.GetSlice("cursor_c"), CommonAse.Ui.GetSlice("cursor_d"), CommonAse.Ui.GetSlice("cursor_e"), CommonAse.Ui.GetSlice("cursor_f"), CommonAse.Ui.GetSlice("cursor_g"), CommonAse.Ui.GetSlice("cursor_j"), CommonAse.Ui.GetSlice("cursor_k") }; } } public override void Update(float dt) { base.Update(dt); if (Player.Dead) { var found = false; foreach (var e in Area.Entities.Entities) { if (e is Cursor && e != this) { found = true; break; } } if (found) { Done = true; return; } } if (readTint) { readTint = false; tint = Player.Tint; } var input = Player.GetComponent(); if (input.KeyboardEnabled && (Input.Mouse.WasMoved || !input.GamepadEnabled || input.GamepadData == null || input.GamepadData.Attached)) { var pos = Input.Mouse.ScreenPosition; if (pos != lastPos) { lastPos = pos; Position = Camera.Instance.CameraToUi(GamePosition = Camera.Instance.ScreenToCamera(pos)); } } var controller = input.GamepadEnabled ? input.GamepadData : null; if (controller != null && Engine.Instance.State is InGameState st && !st.Paused && !st.Died && !Run.Won) { if (needsAdjusting) { needsAdjusting = false; Position = Camera.Instance.CameraToUi(GamePosition = Player.Center); } var stick = controller.GetRightStick(); var dx = stick.X; var dy = stick.Y; var d = (float) Math.Sqrt(dx * dx + dy * dy); if (d > 1) { stick /= d; } else { stick *= d; } var l = stick.Length(); if (l > 0.25f) { var target = MathUtils.CreateVector(Math.Atan2(dy, dx), 1f); dx = target.X - stickOffset.X; dy = target.Y - stickOffset.Y; d = (float) Math.Sqrt(dx * dx + dy * dy); if (d > 1) { dx /= d; dy /= d; } else { dx *= d; dy *= d; } stickOffset += l * new Vector2(dx, dy) * dt * 10f * Settings.Sensivity; Position = Camera.Instance.CameraToUi(GamePosition = (Player.Center + stickOffset * (48 * Settings.CursorRadius))); double a = 0; var pressed = false; if (controller.DPadLeftCheck) { a = Math.PI; pressed = true; } else if (controller.DPadDownCheck) { a = Math.PI / 2f; pressed = true; } else if (controller.DPadUpCheck) { a = Math.PI * 1.5f; pressed = true; } else if (controller.DPadRightCheck) { pressed = true; } if (pressed) { Position = Camera.Instance.CameraToUi(GamePosition = (Player.Center + MathUtils.CreateVector(a, 48))); } } } if (Input.WasPressed(Controls.Use, input)) { Tween.To(1.3f, scale.X, x => { scale.X = scale.Y = x; }, 0.05f).OnEnd = () => Tween.To(1f, scale.X, x => { scale.X = scale.Y = x; }, 0.15f); } } public override void Render() { if (Settings.HideCursor) { return; } var r = regions[Settings.Cursor]; if (InGameState.Multiplayer) { Graphics.Color = tint; } Graphics.Render(r, Position, 0, r.Center, scale); Graphics.Color = ColorUtils.WhiteColor; } public Vector2 Jump(Camera.Target target) { return new Vector2(); /*Position = Camera.Instance.CameraToUi(GamePosition = Camera.Instance.ScreenToCamera(Input.Mouse.ScreenPosition)); return new Vector2((CenterX - Display.UiWidth * 0.5f) * target.Priority, (CenterY - Display.UiHeight * 0.5f) * target.Priority * Display.Viewport * 1.6f)*/; } } } ================================================ FILE: BurningKnight/entity/DamageType.cs ================================================ namespace BurningKnight.entity { public enum DamageType { Regular, Explosive, Custom, Contact, Melee } } ================================================ FILE: BurningKnight/entity/ExplosionMaker.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.assets.particle; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util; using BurningKnight.util.geometry; using Lens; using Lens.assets; using Lens.entity; using Lens.util; using Lens.util.camera; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity { public static class ExplosionMaker { public static void BreakRock(Level level, Dot ww, int x, int y, Tile l) { AudioEmitterComponent.Dummy(level.Area, ww).Emit($"level_rock_{Rnd.Int(1, 3)}", 0.5f); if (l.IsRock()) { Drop.Create(l == Tile.TintedRock ? "bk:tinted_rock" : "bk:rock", null, level.Area, ww); } for (var i = 0; i < 3; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = ww; level.Area.Add(part); } Particles.BreakSprite(level.Area, (l == Tile.TintedRock ? level.Tileset.TintedRock : (l == Tile.MetalBlock ? level.Tileset.MetalBlock : level.Tileset.Rock))[Rnd.Int(4)], ww); level.Set(x, y, Tile.Ember); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); } public static void Make(Entity whoHurts, float hurtRadius = 32f, bool leave = true, Vec2 where = null, float damage = 16, float scale = 1, bool damageOwner = true) { Camera.Instance.Shake(10 * scale); Audio.SfxVolumeBuffer = 0.5f; Audio.SfxVolumeBufferResetTimer = 1f; var w = where == null ? whoHurts.Center : new Vector2(where.X, where.Y); AnimationUtil.Explosion(w, scale); for (var i = 0; i < 4; i++) { var explosion = new ParticleEntity(Particles.Animated("explosion", "smoke")); explosion.Position = w; whoHurts.Area.Add(explosion); explosion.Depth = 31; explosion.Particle.Scale = scale; explosion.Particle.AngleVelocity = 0; explosion.AddShadow(); var a = explosion.Particle.Angle - Math.PI / 2; var d = 16; explosion.Particle.Position += new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); if (i == 0) { explosion.AddComponent(new AudioEmitterComponent { DestroySounds = false }); explosion.GetComponent().EmitRandomizedPrefixed("level_explosion", 3); } } for (var i = 0; i < 6; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = w + new Vector2(Rnd.Int(-4, 4), Rnd.Int(-4, 4)); whoHurts.Area.Add(part); part.Depth = 30; part.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 80); } Engine.Instance.Split = 1f; Engine.Instance.Flash = 1f; Engine.Instance.Freeze = 1f; var damager = whoHurts; if (whoHurts is Bomb b && b.Owner != null) { damager = b.Owner; } foreach (var e in whoHurts.Area.GetEntitesInRadius(w, hurtRadius, typeof(ExplodableComponent))) { if (e == whoHurts && !damageOwner) { continue; } e.GetAnyComponent()?.KnockbackFrom(whoHurts, 4f); e.GetComponent().HandleExplosion(damager, whoHurts, damage); } if (Settings.Flashes) { Camera.Instance.TextureZoom -= 0.05f; Tween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.2f); } if (leave) { whoHurts.Area.Add(new ExplosionLeftOver { Center = w }); } var xx = (int) Math.Floor(w.X / 16f); var yy = (int) Math.Floor(w.Y / 16f); var r = (int) Math.Floor(hurtRadius / 16f); var level = Run.Level; var ice = level.Biome is IceBiome; for (int x = -r; x <= r; x++) { for (int y = -r; y <= r; y++) { var xm = x * 16; var ym = y * 16; if (Math.Sqrt(xm * xm + ym * ym) <= hurtRadius) { var index = level.ToIndex(x + xx, y + yy); var l = level.Get(index, true); var ww = new Dot((x + xx) * 16 + 8, (y + yy) * 16 + 8); if (l.IsRock()) { BreakRock(level, ww, x + xx, y + yy, l); continue; } var tile = level.Get(index); if (tile == Tile.Crack) { DiscoverCrack(whoHurts, level, x + xx, y + yy); } else if (tile == Tile.Planks || (ice && tile == Tile.WallA)) { level.Break((x + xx) * 16, (y + yy) * 16); } } } } } public static void CheckForCracks(Level level, Room room, Entity who) { if (room != null) { for (var y = room.MapY; y < room.MapY + room.MapY; y++) { for (var x = room.MapX; x < room.MapX + room.MapW; x++) { if (level.IsInside(x, y) && level.Get(x, y) == Tile.Crack) { DiscoverCrack(who, level, x, y); } } } } } public static void DiscoverCrack(Entity who, Level level, int x, int y) { var index = level.ToIndex(x, y); level.Set(index, Tile.FloorA); level.Set(index, Tile.Ember); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); level.LoadPassable(); who.HandleEvent(new SecretRoomFoundEvent { Who = who }); Achievements.Unlock("bk:treasure_hunter"); LightUp(x * 16 + 8, y * 16 + 8); Level.Animate(who.Area, x, y); } public static void LightUp(float X, float Y) { var x = (int) (X / 16f); var y = (int) (Y / 16f); var d = 2; for (int xx = -d; xx <= d; xx++) { for (int yy = -d; yy <= d; yy++) { var ds = Math.Sqrt(xx * xx + yy * yy); if (ds <= d) { var level = Run.Level; var index = level.ToIndex(xx + x, yy + y); level.Light[index] = (float) Math.Max(level.Light[index], Math.Max(0.1f, (d - ds) / d)); } } } } } } ================================================ FILE: BurningKnight/entity/HealthType.cs ================================================ namespace BurningKnight.entity { public enum HealthType { Regular, Shield, Bomb } } ================================================ FILE: BurningKnight/entity/Layers.cs ================================================ namespace BurningKnight.entity { public static class Layers { public const int Chasm = -12; public const int UnderFloor = -11; public const int Floor = -10; public const int Blood = -9; public const int Liquid = -8; public const int FloorParticles = -7; public const int Entrance = -6; public const int Shadows = -5; public const int Rocks = -4; public const int Sides = -2; public const int Door = 0; public const int Creature = 0; public const int Lock = 2; public const int Wall = 3; public const int WallDecor = 4; public const int FlyingMob = 5; public const int TileLights = 6; public const int WindFx = 7; public const int InGameUi = 8; public const int Light = 9; public const int Ui = 10; public const int Console = 11; public const int Bk = 12; public const int Cursor = 13; } } ================================================ FILE: BurningKnight/entity/Lego.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.util; using Lens.entity; using Lens.util.camera; using Lens.util.math; namespace BurningKnight.entity { public class Lego : Entity { public override void AddComponents() { base.AddComponents(); AddComponent(new ScalableSliceComponent("particles", $"lego_{Rnd.Int(3)}")); var s = GetComponent(); var region = s.Sprite; Width = region.Width; Height = region.Height; s.Origin.Y = Height; s.Animate(); AddComponent(new ShadowComponent()); AddComponent(new SensorBodyComponent(0, 0, Width, Height)); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Creature c && !c.IsFriendly()) { if (c.GetComponent().ModifyHealth(-10, this, DamageType.Custom)) { AnimationUtil.Ash(Center); Done = true; Camera.Instance.Shake(5); } } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/RenderTrigger.cs ================================================ using System; using Lens.entity; using Lens.util; namespace BurningKnight.entity { public class RenderTrigger : Entity { private Action method; public Entity Entity; public RenderTrigger(Action method, int depth) { Depth = depth; AlwaysActive = true; AlwaysVisible = true; this.method = method; } public RenderTrigger(Entity entity, Action method, int depth) { Depth = depth; Entity = entity; AlwaysActive = true; AlwaysVisible = true; this.method = method; } public override void Render() { if (Entity != null && Entity.Done) { Done = true; return; } method(); } } } ================================================ FILE: BurningKnight/entity/RenderTriggerManager.cs ================================================ using System.Collections.Generic; using Lens.entity; namespace BurningKnight.entity { public class RenderTriggerManager { private Entity entity; private List triggers = new List(); public RenderTriggerManager(Entity e) { entity = e; } public void Add(RenderTrigger trigger) { entity.Area.Add(trigger); triggers.Add(trigger); } public void Update() { if (entity.Done) { Destroy(); return; } foreach (var t in triggers) { if (t.Done || t.Area != entity.Area) { t.Done = false; t.Area = null; t.Components = null; entity.Area.Add(t); } } } public void Destroy() { foreach (var t in triggers) { t.Done = true; entity.Area.Remove(t); } } } } ================================================ FILE: BurningKnight/entity/SpawnPoint.cs ================================================ using BurningKnight.save; using BurningKnight.ui.editor; using Lens; using Lens.graphics; using MonoGame.Extended; namespace BurningKnight.entity { public class SpawnPoint : SaveableEntity, PlaceableEntity { public override void AddComponents() { base.AddComponents(); AddTag(Tags.Checkpoint); } public override void Render() { if (Engine.EditingLevel) { Graphics.Batch.FillRectangle(X, Y, Width, Height, ColorUtils.WhiteColor); } } } } ================================================ FILE: BurningKnight/entity/bomb/Bomb.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.physics; using Lens.entity; using Lens.input; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.bomb { public delegate void BombUpdateCallback(Bomb b, float dt); public delegate void BombDeathCallback(Bomb b); public class Bomb : Entity, CollisionFilterEntity { public const float ExplosionTime = 1f; private readonly float explosionTime; public BombUpdateCallback Controller; public BombDeathCallback OnDeath; public Bomb Parent; public Entity Owner; public float Scale; public float T; public bool ExplodeOnTouch; public Bomb(Entity owner, float time = ExplosionTime, Bomb parent = null) { explosionTime = time + Rnd.Float(-0.1f, 1f); Parent = parent; Owner = owner; Scale = parent?.Scale * 0.7f ?? 1; Camera.Instance.Shake(6); } public override void AddComponents() { base.AddComponents(); AddComponent(new BombGraphicsComponent("items", "bomb")); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new ExplodableComponent()); AddComponent(new RoomComponent()); AddComponent(new LightComponent(this, 32f * Scale, new Color(1f, 0.3f, 0.3f, 1f))); AddTag(Tags.Bomb); Width = 10 * Scale; Height = 13 * Scale; AlwaysActive = true; AddComponent(new RectBodyComponent(0, 0, Width, Height)); AddComponent(new ExplodeComponent { Radius = 32, Timer = explosionTime }); AddComponent(new AudioEmitterComponent()); GetComponent().EmitRandomized("bomb_placed"); } private void RenderShadow() { GraphicsComponent.Render(true); } public void MoveToMouse() { VelocityTo(AngleTo(Owner.GetComponent().Cursor.GamePosition)); } public void VelocityTo(float angle, float force = 100f) { var component = GetComponent(); var vec = new Vector2((float) Math.Cos(angle) * force, (float) Math.Sin(angle) * force); Position += vec * 0.05f; component.Body.LinearDamping = 5; component.Velocity = vec; } public bool ShouldCollide(Entity entity) { return !(entity is Creature); } private bool sent; public override void Update(float dt) { base.Update(dt); T += dt; if (!sent) { sent = true; // Not placed in init, so that room component had a chance to guess the room Owner?.HandleEvent(new BombPlacedEvent { Bomb = this, Owner = Owner }); } Controller?.Invoke(this, dt); } public void Explode() { OnDeath?.Invoke(this); Done = true; var r = GetComponent().Radius; ExplosionMaker.Make(this, r, scale: r / 32f); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Projectile p) { GetComponent().KnockbackFrom(p); if (!p.HasFlag(ProjectileFlags.FlyOverStones)) { p.Break(); } } else if (ExplodeOnTouch && cse.Entity is Creature ca && Owner is Creature cb && ca.IsFriendly() != cb.IsFriendly()) { Explode(); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/bomb/controller/TargetBombController.cs ================================================ using System; using BurningKnight.entity.component; using Lens.entity; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.bomb.controller { public static class TargetBombController { public static BombUpdateCallback Make(Entity target, float speed = 1f) { return (p, dt) => { var b = p.GetAnyComponent(); var d = Math.Max(100, b.Velocity.Length()); var a = b.Velocity.ToAngle(); if (target == null) { var md = 320000f; foreach (var m in (p.Owner.TryGetComponent(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) { if (m.GetComponent().Unhittable) { continue; } var dd = m.DistanceTo(p); if (dd < md) { md = dd; target = m; } } if (target == null) { return; } } if (target.Done) { target = null; return; } a = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 4); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); }; } } } ================================================ FILE: BurningKnight/entity/buff/ArmoredBuff.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.buff { public class ArmoredBuff : Buff { public const string Id = "bk:armored"; public ArmoredBuff() : base(Id) { Duration = 10; } public override void Init() { base.Init(); Entity.GetComponent().Remove(); } public override void HandleEvent(Event e) { if (e is HealthModifiedEvent hme) { if (hme.Amount < 0) { hme.Amount /= 2; } } base.HandleEvent(e); } public override string GetIcon() { return "armor"; } } } ================================================ FILE: BurningKnight/entity/buff/BleedingBuff.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class BleedingBuff : Buff { public static Vector4 Color = new Vector4(0.5f, 0f, 0f, 1f); public const string Id = "bk:bleeding"; public const float Delay = 0.5f; private float tillDamage = Delay; public BleedingBuff() : base(Id) { } public override void Update(float dt) { base.Update(dt); tillDamage -= dt; if (tillDamage <= 0) { tillDamage = Delay; Entity.GetComponent().ModifyHealth(-1, Entity); } } public override string GetIcon() { return "blood"; } } } ================================================ FILE: BurningKnight/entity/buff/BrokenArmorBuff.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.buff { public class BrokenArmorBuff : Buff { public const string Id = "bk:broken_armor"; public BrokenArmorBuff() : base(Id) { Duration = 10; } public override void Init() { base.Init(); Entity.GetComponent().Remove(); } public override void HandleEvent(Event e) { if (e is HealthModifiedEvent hme) { if (hme.Amount < 0) { hme.Amount *= 2; } } base.HandleEvent(e); } public override string GetIcon() { return "broken_armor"; } } } ================================================ FILE: BurningKnight/entity/buff/Buff.cs ================================================ using Lens.entity; namespace BurningKnight.entity.buff { public class Buff { public Entity Entity; public float TimeLeft; public float Duration = 1f; public bool Infinite; public readonly string Type; public Buff(string id) { Type = id; } public virtual void Init() { TimeLeft = Duration; } public virtual void Destroy() { } public virtual void Update(float dt) { if (!Infinite) { TimeLeft -= dt; } } public virtual void HandleEvent(Event e) { } public virtual string GetIcon() { return null; } } } ================================================ FILE: BurningKnight/entity/buff/BuffCheckEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.buff { public class BuffCheckEvent : Event { public Entity Entity; public Buff Buff; } } ================================================ FILE: BurningKnight/entity/buff/BuffInfo.cs ================================================ using System; using BurningKnight.entity.projectile; namespace BurningKnight.entity.buff { public class BuffInfo { public Type Buff; public ProjectileGraphicsEffect Effect; } } ================================================ FILE: BurningKnight/entity/buff/BuffRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.projectile; namespace BurningKnight.entity.buff { public static class BuffRegistry { public static Dictionary All = new Dictionary(); static BuffRegistry() { Add(BurningBuff.Id, ProjectileGraphicsEffect.Burning); Add(CharmedBuff.Id, ProjectileGraphicsEffect.Charming); Add(PoisonBuff.Id, ProjectileGraphicsEffect.Poison); Add(FrozenBuff.Id, ProjectileGraphicsEffect.Freezing); Add(SlowBuff.Id, ProjectileGraphicsEffect.Slowing); Add(ArmoredBuff.Id); Add(BrokenArmorBuff.Id, ProjectileGraphicsEffect.BrokenArmor); Add(InvincibleBuff.Id); Add(RageBuff.Id); Add(InvisibleBuff.Id); Add(BuffedBuff.Id); Add(BleedingBuff.Id); Add(ConfusedBuff.Id); } public static void Add(string id, ProjectileGraphicsEffect effect = ProjectileGraphicsEffect.Normal) where T : Buff { All[id] = new BuffInfo { Buff = typeof(T), Effect = effect }; } public static void Remove(string id) { All.Remove(id); } public static Buff Create(string id) { if (!All.TryGetValue(id, out var buff)) { return null; } return (Buff) Activator.CreateInstance(buff.Buff); } public static Buff Create() where T : Buff { return (Buff) Activator.CreateInstance(typeof(T)); } } } ================================================ FILE: BurningKnight/entity/buff/BuffedBuff.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.item.util; using Lens.entity; namespace BurningKnight.entity.buff { public class BuffedBuff : Buff { public const string Id = "bk:buffed"; public BuffedBuff() : base(Id) { Duration = 10; } public override string GetIcon() { return "buffed"; } public override void HandleEvent(Event e) { if (e is MeleeArc.CreatedEvent meae) { meae.Arc.Damage *= 2; } else if (e is ProjectileCreatedEvent pce) { pce.Projectile.Damage *= 2; } else if (e is HealthModifiedEvent hme) { if (hme.Amount < 0) { hme.Amount *= 0.5f; } } base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/buff/BurningBuff.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class BurningBuff : Buff { public static Vector4 Color = new Vector4(0.5f, 0f, 0f, 1f); public const string Id = "bk:burning"; public const float Delay = 1f; private float tillDamage = Delay; private float lastParticle; public BurningBuff() : base(Id) { Infinite = true; } public override void Init() { base.Init(); Entity.GetComponent().Remove(); } public override void Update(float dt) { base.Update(dt); lastParticle += dt; if (lastParticle >= 0.5f) { lastParticle = 0; Entity.Area.Add(new FireParticle { Owner = Entity }); } tillDamage -= dt; if (tillDamage <= 0) { tillDamage = Delay; Entity.GetComponent().ModifyHealth(-1, Entity); } } public override string GetIcon() { return "fire"; } } } ================================================ FILE: BurningKnight/entity/buff/CharmedBuff.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.component; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class CharmedBuff : Buff { public const string Id = "bk:charmed"; public static Vector4 Color = new Vector4(0.5f, -0.2f, 0.5f, 1f); private float lastParticle; public CharmedBuff() : base(Id) { Duration = 10; } public override void Update(float dt) { base.Update(dt); lastParticle += dt; if (lastParticle >= 0.4f) { lastParticle = 0; var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"heart_{Rnd.Int(1, 4)}")))); part.Position = Entity.Center; if (Entity.TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Entity.Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.9f; part.Depth = Layers.InGameUi; } } public override string GetIcon() { return "love"; } } } ================================================ FILE: BurningKnight/entity/buff/ConfusedBuff.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.entity.buff { public class ConfusedBuff : Buff { public const string Id = "bk:confused"; public ConfusedBuff() : base(Id) { Duration = 128; } public override void Init() { base.Init(); if (Entity.TryGetComponent(out var b)) { b.Confused = true; } if (Entity.TryGetComponent(out var sb)) { sb.Confused = true; } if (Entity.TryGetComponent(out var cb)) { cb.Confused = true; } } public override void Destroy() { base.Destroy(); if (Entity.TryGetComponent(out var b)) { b.Confused = false; } if (Entity.TryGetComponent(out var sb)) { sb.Confused = false; } if (Entity.TryGetComponent(out var cb)) { cb.Confused = false; } } public override string GetIcon() { return "confused"; } } } ================================================ FILE: BurningKnight/entity/buff/FrozenBuff.cs ================================================ using BurningKnight.entity.component; using Lens.entity.component.logic; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class FrozenBuff : Buff { public const string Id = "bk:frozen"; public static Vector4 Color = new Vector4(0.5f, 0.5f, 1f, 1f); public FrozenBuff() : base(Id) { Duration = 3; } public override void Init() { base.Init(); Entity.GetComponent().Remove(); if (Entity.TryGetComponent(out var s)) { s.Pause++; } var a = Entity.GetAnyComponent(); if (a != null) { a.Animation.Paused = true; } } public override void Update(float dt) { base.Update(dt); var body = Entity.GetAnyComponent(); if (body != null) { body.Velocity -= body.Velocity * (dt * 20); } } public override void Destroy() { base.Destroy(); if (Entity.TryGetComponent(out var s)) { s.Pause--; } var a = Entity.GetAnyComponent(); if (a != null) { a.Animation.Paused = false; } } public override string GetIcon() { return "snow"; } } } ================================================ FILE: BurningKnight/entity/buff/InvincibleBuff.cs ================================================ using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.buff { public class InvincibleBuff : Buff { public const string Id = "bk:invincible"; public InvincibleBuff() : base(Id) { Duration = 10; } public override void HandleEvent(Event e) { if (e is HealthModifiedEvent hme) { hme.Handled = true; } base.HandleEvent(e); } public override string GetIcon() { return "star"; } } } ================================================ FILE: BurningKnight/entity/buff/InvisibleBuff.cs ================================================ using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class InvisibleBuff : Buff { public static Vector4 Color = new Vector4(0.3f, 0.3f, 0.7f, 0.5f); public const string Id = "bk:invisible"; public InvisibleBuff() : base(Id) { Duration = 10; } public override string GetIcon() { return "invisible"; } } } ================================================ FILE: BurningKnight/entity/buff/PoisonBuff.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.component; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class PoisonBuff : Buff { public static Vector4 Color = new Vector4(0.1f, 0.5f, 0.1f, 1f); public const string Id = "bk:poison"; private const float Delay = 2f; private float tillDamage = Delay; private float lastParticle; public PoisonBuff() : base(Id) { Duration = 10; } public override void Update(float dt) { base.Update(dt); lastParticle += dt; if (lastParticle >= 0.5f) { lastParticle = 0; var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"poison_{Rnd.Int(1, 4)}")))); part.Position = Entity.Center; if (Entity.TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Entity.Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.8f; part.Depth = Layers.InGameUi; } tillDamage -= dt; if (tillDamage <= 0) { tillDamage = Delay; Entity.GetComponent().ModifyHealth(-2, Entity); } } public override string GetIcon() { return "poison"; } } } ================================================ FILE: BurningKnight/entity/buff/ProjectileShaderHelper.cs ================================================ using BurningKnight.entity.projectile; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public static class ProjectileShaderHelper { public static Color GetColor(this ProjectileGraphicsEffect effect) { switch (effect) { case ProjectileGraphicsEffect.Poison: return ProjectileColor.Green; case ProjectileGraphicsEffect.Charming: return ProjectileColor.Pink; case ProjectileGraphicsEffect.Freezing: return ProjectileColor.Cyan; case ProjectileGraphicsEffect.Slowing: return ProjectileColor.Brown; case ProjectileGraphicsEffect.Burning: return ProjectileColor.Orange; case ProjectileGraphicsEffect.BrokenArmor: return ProjectileColor.Gray; default: return ProjectileColor.Yellow; } } } } ================================================ FILE: BurningKnight/entity/buff/RageBuff.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using Lens.assets; using Lens.entity; namespace BurningKnight.entity.buff { public class RageBuff : Buff { public const string Id = "bk:rage"; public RageBuff() : base(Id) { Duration = 10; } public override string GetIcon() { return "rage"; } public override void Init() { base.Init(); if (Entity is Player) { TextParticle.Add(Entity, Locale.Get("damage"), 1, true); } } public override void Destroy() { base.Destroy(); if (Entity is Player) { TextParticle.Add(Entity, Locale.Get("damage"), 1, true, true); } } public override void HandleEvent(Event e) { if (e is MeleeArc.CreatedEvent meae) { meae.Arc.Damage *= 2; } else if (e is ProjectileCreatedEvent pce) { pce.Projectile.Damage *= 2; } base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/buff/SlowBuff.cs ================================================ using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.buff { public class SlowBuff : Buff { public const string Id = "bk:slow"; public static Vector4 Color = new Vector4(0.4f - 0.5f, 0.26f - 0.5f, 0.12f - 0.5f, 1f); public SlowBuff() : base(Id) { Duration = 5; } public override void Init() { base.Init(); if (Entity.TryGetComponent(out var b)) { b.Slow = true; } if (Entity.TryGetComponent(out var sb)) { sb.Slow = true; } if (Entity.TryGetComponent(out var cb)) { cb.Slow = true; } } public override void Destroy() { base.Destroy(); if (Entity.TryGetComponent(out var b)) { b.Slow = false; } if (Entity.TryGetComponent(out var sb)) { sb.Slow = false; } if (Entity.TryGetComponent(out var cb)) { cb.Slow = false; } } public override string GetIcon() { return "snail"; } } } ================================================ FILE: BurningKnight/entity/component/AimComponent.cs ================================================ using BurningKnight.entity.creature.mob; using Lens.entity.component; using Lens.input; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class AimComponent : Component { public enum AimType { Cursor, Target, AnyPlayer } public AimComponent(AimType t) { TheType = t; } public AimType TheType; public Vector2 Aim; public Vector2 RealAim; public Vector2 Center; public bool ShowLaserLine; public override void Update(float dt) { base.Update(dt); if (TheType == AimType.Cursor) { Aim = Entity.GetComponent().Cursor.GamePosition; } else if (TheType == AimType.Target) { RealAim = Aim = ((Mob) Entity).Target?.Center ?? Input.Mouse.GamePosition; } else { var a = GetComponent().Room.Tagged[Tags.Player]; if (a.Count > 0) { RealAim = Aim = a[0].Center; } } if (TheType == AimType.Cursor) { return; } Center = Entity.Center; if (Entity.TryGetComponent(out var z)) { Center.Y -= z.Z; } } } } ================================================ FILE: BurningKnight/entity/component/AnimationComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.buff; using BurningKnight.entity.creature.player; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.graphics; using Lens.entity.component.logic; using Lens.graphics; using Lens.graphics.animation; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class AnimationComponent : GraphicsComponent { public Animation Animation; public Color Tint = Color.White; private string name; private ColorSet set; public float ShadowOffset; public Vector2 Scale = Vector2.One; public float Angle; public float OriginY; public float OriginX; public bool AddOrigin = true; public bool Centered; public bool Flash; public readonly string Id; public AnimationComponent(string animationName, string layer = null, string tag = null) { name = animationName; Id = animationName; ReloadAnimation(layer, tag); } public AnimationComponent(string animationName, ColorSet set) { name = animationName; Id = animationName; this.set = set; ReloadAnimation(); } public void SetAutoStop(bool stop) { Animation.AutoStop = stop; } private void ReloadAnimation(string layer = null, string tag = null) { var data = set == null ? Animations.Get(name) : Animations.GetColored(name, set); if (data != null) { Animation = data.CreateAnimation(layer); if (tag != null) { Animation.Tag = tag; } OriginX = Animation.GetCurrentTexture().Width / 2f; OriginY = Animation.GetCurrentTexture().Height; } } public override void Update(float dt) { base.Update(dt); if (Animations.Reload) { ReloadAnimation(); } Animation?.Update(dt); } public override void Render(bool shadow) { var pos = (Centered ? Entity.Center : Entity.Position) + Offset; if (shadow) { FlippedVerticaly = !FlippedVerticaly; pos.Y += Animation.GetCurrentTexture().Height - ShadowOffset * 2; } if (Entity.TryGetComponent(out var component) && component.OutlineAlpha > 0.05f) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(component.OutlineAlpha); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); foreach (var d in MathUtils.Directions) { CallRender(pos + d, shadow); } Shaders.End(); } var stopShader = !shadow && StartShaders(); Graphics.Color = Tint; CallRender(pos, shadow); Graphics.Color = ColorUtils.WhiteColor; if (stopShader) { Shaders.End(); } if (shadow) { FlippedVerticaly = !FlippedVerticaly; } } protected bool StartShaders() { if (Flash || (Entity.TryGetComponent(out var health) && health.RenderInvt && (health.InvincibilityTimer > health.InvincibilityTimerMax / 2f || health.InvincibilityTimer % 0.1f > 0.05f))) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); return true; } if (Entity.TryGetComponent(out var buffs)) { if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(InvisibleBuff.Color); return true; } if (buffs.Has()) { var shader = Shaders.Entity; var t = buffs.Buffs[typeof(InvincibleBuff)].TimeLeft; if (t < 2f && t % 0.3f < 0.15f) { return false; } Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.FromHSV(Engine.Time * 180 % 360, 100, 100).ToVector4()); return true; } if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(0f); shader.Parameters["flashColor"].SetValue(FrozenBuff.Color); return true; } if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(0f); shader.Parameters["flashColor"].SetValue(BurningBuff.Color); return true; } if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(0f); shader.Parameters["flashColor"].SetValue(PoisonBuff.Color); return true; } if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(0f); shader.Parameters["flashColor"].SetValue(SlowBuff.Color); return true; } if (buffs.Has()) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(0f); shader.Parameters["flashColor"].SetValue(CharmedBuff.Color); return true; } } return false; } protected virtual void CallRender(Vector2 pos, bool shadow) { if (Animation == null) { return; } var region = Animation.GetCurrentTexture(); var or = new Vector2(OriginX, shadow ? region.Height - OriginY : OriginY); Graphics.Render(region, AddOrigin ? pos + or : pos, shadow ^ Flipped ? -Angle : Angle, or, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly)); } public override bool HandleEvent(Event e) { if (e is StateChangedEvent ev && Animation != null) { var tag = ev.NewState.Name.ToLower().Replace("state", ""); if (Animation.HasTag(tag)) { Animation.Tag = tag; } } return base.HandleEvent(e); } public void Animate(Action callback = null) { Tween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f); Tween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, Scale.X, x => Scale.X = x, 0.4f); Tween.To(1, Scale.Y, x => Scale.Y = x, 0.4f); callback?.Invoke(); }; } } } ================================================ FILE: BurningKnight/entity/component/AudioEmitterComponent.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; namespace BurningKnight.entity.component { public class AudioEmitterComponent : Component { public static AudioListener Listener; public static Vector2 ListenerPosition; public static float PositionScale = 0.00000001f; public static float Distance = 200; public AudioEmitter Emitter = new AudioEmitter(); public float PitchMod; public bool DestroySounds = false; public Dictionary Playing = new Dictionary(); public class Sfx { public SoundEffectInstance Effect; public float BaseVolume = 1f; public bool KeepAround; public bool ApplyBuffer; } public override void Destroy() { base.Destroy(); if (DestroySounds) { StopAll(); } } public void StopAll() { foreach (var s in Playing.Values) { s.Effect.Stop(); s.Effect.Dispose(); } Playing.Clear(); } private void UpdatePosition() { Emitter.Position = new Vector3(Entity.CenterX * PositionScale, 0, Entity.CenterY * PositionScale); if (Listener != null) { var d = (ListenerPosition - Entity.Center).Length(); foreach (var s in Playing.Values) { s.Effect.Volume = MathUtils.Clamp(0, 1, (1 - Math.Min(Distance, d) / Distance) * Settings.MasterVolume * Settings.SfxVolume * s.BaseVolume * (s.ApplyBuffer ? Audio.SfxVolumeBuffer : 1)); } } } // 6y0204mm public override void Update(float dt) { base.Update(dt); if (Playing.Count == 0) { return; } UpdatePosition(); var keys = Playing.Keys.ToArray(); foreach (var k in keys) { var s = Playing[k]; if (!s.KeepAround && s.Effect.State != SoundState.Playing) { Playing.Remove(k); } else if (Listener != null) { s.Effect.Apply3D(Listener, Emitter); } } } public SoundEffectInstance EmitRandomizedPrefixed(string sfx, int prefixMax, float volume = 1f, bool insert = true, bool looped = false, bool tween = false, float sz = 0.4f) { if (sfx == null) { return null; } return Emit($"{sfx}_{Rnd.Int(1, prefixMax + 1)}", volume, PitchMod + Rnd.Float(-sz, sz), insert, looped, tween); } public SoundEffectInstance EmitRandomized(string sfx, float volume = 1f, bool insert = true, bool looped = false, bool tween = false, float sz = 0.4f) { if (sfx == null) { return null; } return Emit(sfx, volume, PitchMod + Rnd.Float(-sz, sz), insert, looped, tween); } public SoundEffectInstance Emit(string sfx, float volume = 1f, float pitch = 0f, bool insert = true, bool looped = false, bool tween = false) { if (!Assets.LoadSfx || sfx == null) { return null; } Sfx instance; var v = volume * 0.8f; if (!insert) { v *= Audio.MasterVolume * Audio.SfxVolume * Audio.SfxVolumeBuffer; } var applyBuffer = !sfx.StartsWith("level_explosion"); /*if (applyBuffer) { v *= Audio.SfxVolumeBuffer; }*/ if (!insert || !Playing.TryGetValue(sfx, out instance)) { var sound = Audio.GetSfx(sfx); if (sound == null) { return null; } instance = new Sfx { Effect = sound.CreateInstance(), KeepAround = tween, ApplyBuffer = applyBuffer }; if (insert) { Playing[sfx] = instance; } instance.Effect.IsLooped = looped; } instance.BaseVolume = tween ? 0 : v; if (tween) { var t = Tween.To(v, 0, x => instance.BaseVolume = x, 0.5f); t.Delay = 1f; t.OnStart = () => { instance.Effect.Play(); instance.KeepAround = false; instance.Effect.Apply3D(Listener, Emitter); }; } UpdatePosition(); instance.Effect.Stop(); instance.Effect.Pitch = MathUtils.Clamp(-1f, 1f, pitch); if (!tween) { instance.Effect.Play(); } if (Listener != null) { instance.Effect.Apply3D(Listener, Emitter); } return instance.Effect; } public static AudioEmitterComponent Dummy(Area area, Vector2 where) { var entity = new EmitterDummy(); var component = new AudioEmitterComponent(); area.Add(entity); entity.AddComponent(component); entity.Center = where; entity.AlwaysActive = true; return component; } private class EmitterDummy : Entity { public override void Update(float dt) { base.Update(dt); if (GetComponent().Playing.Count == 0) { Done = true; } } } } } ================================================ FILE: BurningKnight/entity/component/BodyComponent.cs ================================================ using System; using BurningKnight.entity.events; using BurningKnight.physics; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.component { public class BodyComponent : SaveableComponent { public Body Body; public Vector2 Acceleration; public Vector2 Knockback; public float KnockbackModifier = 1; public Vector2 Offset; public bool Slow; public bool CanCollide = true; public bool Confused; public Vector2 Velocity { get => Slow ? Body.LinearVelocity * 2 : Body.LinearVelocity; set => Body.LinearVelocity = Slow ? value / 2 : value; } public Vector2 Position { get => Body.Position; set => Body.Position = value; } public float Angle { get => Body.Rotation; set => Body.Rotation = value; } protected virtual void PositionChangedListener() { if (Body != null) { try { Body.Position = Entity.Position + Offset; } catch (Exception e) { Log.Error(e); } } } public override void Init() { base.Init(); Entity.PositionChanged += PositionChangedListener; if (Body != null) { try { Body.Position = Entity.Position + Offset; } catch (Exception e) { Log.Error(e); } } } public override void Destroy() { base.Destroy(); Entity.PositionChanged -= PositionChangedListener; if (Body != null) { try { Physics.RemoveBody(Body); } catch (Exception e) { Log.Error(e); } Body = null; } } public virtual bool ShouldCollide(Entity entity) { if (Entity is CollisionFilterEntity filter) { return filter.ShouldCollide(entity); } return true; } public virtual void OnCollision(Entity entity) { Entity.HandleEvent(new CollisionStartedEvent { Entity = entity, Body = this }); } public virtual void OnCollisionEnd(Entity entity) { Entity.HandleEvent(new CollisionEndedEvent { Entity = entity, Body = this }); } public void KnockbackFrom(Entity entity, float force = 1f, float rnd = 0) { if (entity == null) { return; } if (entity.TryGetComponent(out var s)) { force *= s.Knockback; } if (entity == Entity) { KnockbackFrom(Rnd.AnglePI(), force, rnd); } else { KnockbackFrom(entity.Center, force, rnd); } } public void KnockbackFrom(Vector2 point, float force = 1f, float rnd = 0) { KnockbackFrom(Entity.AngleTo(point) - (float) Math.PI, force, rnd); } public virtual void KnockbackFrom(float a, float force = 1f, float rnd = 0) { force *= KnockbackModifier * 30; if (force <= 0.02f) { return; } if (rnd > 0.01f) { a += Rnd.Float(-rnd, rnd); } Knockback.X += (float) Math.Cos(a) * force; Knockback.Y += (float) Math.Sin(a) * force; } public override void Update(float dt) { base.Update(dt); if (Body == null) { return; } var velocity = Body.LinearVelocity; velocity.X += Acceleration.X + Knockback.X * dt * 60; velocity.Y += Acceleration.Y + Knockback.Y * dt * 60; Knockback.X -= Knockback.X * dt * 10f; Knockback.Y -= Knockback.Y * dt * 10f; if (Entity.GraphicsComponent != null && !Entity.GraphicsComponent.CustomFlip && velocity.Length() > 0.1f) { Entity.GraphicsComponent.Flipped = velocity.X < 0; } Body.LinearVelocity = velocity; Entity.Position = Body.Position - Offset; } public override void Load(FileReader reader) { base.Load(reader); Body?.SetTransform(Entity.Position, 0); } public override void RenderDebug() { ImGui.DragFloat("Knockback modifier", ref KnockbackModifier); if (Body == null) { ImGui.BulletText("Body is null"); } else { var vel = Body.LinearVelocity; var v = new System.Numerics.Vector2(vel.X, vel.Y); if (ImGui.DragFloat2("Velocity", ref v)) { Body.LinearVelocity = vel; } if (ImGui.Button("Sync body")) { PositionChangedListener(); } } } public virtual void Resize(float x, float y, float w, float h, bool center = false) { } } } ================================================ FILE: BurningKnight/entity/component/BombGraphicsComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.bomb; using Lens.entity.component.graphics; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class BombGraphicsComponent : SliceComponent { public BombGraphicsComponent(string image, string slice) : base(image, slice) { } public override void Render(bool shadow) { var timer = Entity.GetComponent(); var origin = new Vector2(Sprite.Center.X, shadow ? 0 : Sprite.Source.Height); var stopShader = false; var bomb = (Bomb) Entity; if (!shadow && (timer.Timer < 1f ? timer.Timer % 0.3f > 0.1f : timer.Timer % 0.5f > 0.4f)) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); stopShader = true; } Graphics.Render(Sprite, Entity.Position + new Vector2(origin.X, origin.Y + (shadow ? Sprite.Height : 0)), 0, origin, new Vector2( (float) ((Math.Cos(timer.Timer * 16) / 2f) + 1) * bomb.Scale * Math.Min(bomb.T * 4f, 1), (float) ((Math.Cos(timer.Timer * 16 + Math.PI) / 3f) + 1) * bomb.Scale ), Graphics.ParseEffect(false, shadow)); if (stopShader) { Shaders.End(); } } } } ================================================ FILE: BurningKnight/entity/component/BuffsComponent.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.assets.particle.custom; using BurningKnight.entity.buff; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.state; using ImGuiNET; using Lens; using Lens.entity; using Lens.entity.component; using Lens.util.file; namespace BurningKnight.entity.component { public class BuffsComponent : SaveableComponent { public Dictionary Buffs = new Dictionary(); private List immune = new List(); public List Particles = new List(); public bool IceImmunity; public bool PitImmunity; public void AddImmunity() { var type = typeof(T); if (!immune.Contains(type)) { immune.Add(type); } } public Buff Add(Buff buff) { if (buff == null) { return null; } var type = buff.GetType(); if (Buffs.ContainsKey(type)) { return null; } foreach (var t in immune) { if (t == type) { return null; } } if (Send(new BuffCheckEvent { Entity = Entity, Buff = buff })) { return null; } Buffs[type] = buff; buff.Entity = Entity; buff.Init(); Send(new BuffAddedEvent { Buff = buff }); if (Engine.Instance.State is InGameState && buff.GetIcon() != null) { var part = new BuffParticle(buff, Entity); Particles.Add(part); Engine.Instance.State.Ui.Add(part); } return buff; } public Buff Add(string id) { return Add(BuffRegistry.Create(id)); } public bool Has() { return Buffs.ContainsKey(typeof(T)); } public void Remove() { Remove(typeof(T)); } public void Remove(Type type) { if (Buffs.TryGetValue(type, out var buff)) { if (!Send(new BuffRemovedEvent { Buff = buff })) { buff.Destroy(); Buffs.Remove(type); var toRemove = -1; for (var i = 0; i < Particles.Count; i++) { if (Particles[i].Buff == buff) { toRemove = i; Particles[i].Remove(); break; } } if (toRemove != -1) { Particles.RemoveAt(toRemove); } } } } private bool addedIcons; public override void Update(float dt) { base.Update(dt); if (!addedIcons) { addedIcons = true; foreach (var b in Buffs.Values) { var part = new BuffParticle(b, Entity); Particles.Add(part); Engine.Instance.State.Ui.Add(part); } } foreach (var buff in Buffs.Values) { buff.Update(dt); } foreach (var key in Buffs.Keys.ToList()) { var buff = Buffs[key]; if (buff.TimeLeft <= 0) { Remove(key); } } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte((byte) Buffs.Count); foreach (var buff in Buffs.Values) { stream.WriteString(buff.Type); stream.WriteFloat(buff.TimeLeft); } } public override void Load(FileReader reader) { base.Load(reader); var count = reader.ReadByte(); for (int i = 0; i < count; i++) { var buff = Add(reader.ReadString()); buff.TimeLeft = reader.ReadFloat(); buff.Entity = Entity; buff.Init(); } } public override bool HandleEvent(Event e) { foreach (var b in Buffs.Values) { b.HandleEvent(e); } if (e is TileCollisionStartEvent tileStart) { if (tileStart.Tile == Tile.Water) { Remove(); } }/* else if (e is FlagCollisionStartEvent flagStart) { if (flagStart.Flag == Flag.Burning) { Add(); } }*/ return base.HandleEvent(e); } private static string toAdd = ""; public override void RenderDebug() { if (ImGui.InputText("Buff", ref toAdd, 128)) { Add(toAdd); toAdd = ""; } ImGui.SameLine(); if (ImGui.Button("Add")) { Add(toAdd); toAdd = ""; } if (Buffs.Count == 0) { ImGui.BulletText("No buffs"); return; } if (ImGui.Button("Remove all")) { foreach (var b in Buffs.Values) { b.TimeLeft = 0; } } foreach (var b in Buffs.Values) { if (toAdd.Length > 0 && !BuffRegistry.All.ContainsKey(toAdd)) { ImGui.BulletText("Unknown buff"); } if (ImGui.TreeNode($"{b.Type}")) { ImGui.Text($"{b.TimeLeft} seconds left"); if (ImGui.Button($"Remove##{b.Type}")) { b.TimeLeft = 0; } ImGui.SameLine(); if (ImGui.Button($"Renew##{b.Type}")) { b.TimeLeft = b.Duration; } ImGui.Checkbox($"Infinite##{b.Type}", ref b.Infinite); ImGui.TreePop(); } } } } } ================================================ FILE: BurningKnight/entity/component/CircleBodyComponent.cs ================================================ using BurningKnight.physics; using Microsoft.Xna.Framework; using VelcroPhysics.Collision.Shapes; using VelcroPhysics.Dynamics; using VelcroPhysics.Factories; namespace BurningKnight.entity.component { public class CircleBodyComponent : BodyComponent { public CircleBodyComponent(float x, float y, float r, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) { if (center) { x -= r; y -= r; Offset = new Vector2(r, r); } Body = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type); Body.FixedRotation = true; Body.UserData = this; Body.LinearDamping = 0; Body.CreateFixture(new CircleShape(r, 1) { Position = new Vector2(x + r, y + r), }).IsSensor = sensor; } public override void Resize(float x, float y, float w, float h, bool center = false) { var fixture = Body.FixtureList[0]; var sensor = fixture.IsSensor; Body.DestroyFixture(fixture); var r = w / 2f; if (center) { x -= r; y -= r; Offset = new Vector2(r, r); } Body.CreateFixture(new CircleShape(r, 1) { Position = new Vector2(x + r, y + r), }).IsSensor = sensor; } } } ================================================ FILE: BurningKnight/entity/component/CloseDialogComponent.cs ================================================ using System; using BurningKnight.level; using BurningKnight.physics; using BurningKnight.ui.dialog; using Lens.entity; using Lens.entity.component; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class CloseDialogComponent : Component { public int Radius = 32 * 32; public int RadiusMax = 64 * 64; public bool UseLineOfSight = true; public string[] Variants; private Entity trigger; public Func CanTalk; public Func DecideVariant; public CloseDialogComponent(params string[] vars) { Variants = vars; } public override void Update(float dt) { if (!Entity.OnScreen || Variants.Length == 0) { return; } if (!Entity.TryGetComponent(out var d)) { return; } if (d.Current != null) { if (trigger != null && trigger.DistanceToSquared(Entity) > RadiusMax) { trigger = null; d.Close(); } return; } foreach (var p in Entity.Area.Tagged[Tags.Player]) { if (p.DistanceToSquared(Entity) <= Radius && (!UseLineOfSight || CanSee(p.Center, Entity))) { if (CanTalk == null || CanTalk(Entity)) { d.Start(DecideVariant?.Invoke(p) ?? Variants[Rnd.Int(Variants.Length)]); trigger = p; return; } } } } private static bool RayShouldCollide(Entity entity) { return entity is ProjectileLevelBody; } protected bool CanSee(Vector2 from, Entity e) { var min = 1f; var found = false; Physics.World.RayCast((fixture, point, normal, fraction) => { if (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) { min = fraction; found = true; } return min; }, from, e.Center); return !found; } } } ================================================ FILE: BurningKnight/entity/component/CollisionFilterComponent.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.physics; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class CollisionFilterComponent : Component { public List> Filter = new List>(); public CollisionResult Invoke(Entity colliding) { foreach (var f in Filter) { var v = f(Entity, colliding); if (v != CollisionResult.Default) { return v; } } return CollisionResult.Default; } public static void Add(Entity e, Func filter) { CollisionFilterComponent c; if (!e.TryGetComponent(out c)) { c = new CollisionFilterComponent(); e.AddComponent(c); } c.Filter.Add(filter); } } } ================================================ FILE: BurningKnight/entity/component/CursorComponent.cs ================================================ using Lens.entity.component; namespace BurningKnight.entity.component { public class CursorComponent : Component { public Cursor Cursor; } } ================================================ FILE: BurningKnight/entity/component/DoorBodyComponent.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.projectile; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.component { public class DoorBodyComponent : RectBodyComponent { public 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) { } public override void Init() { base.Init(); Body.IsSensor = false; } private bool ShouldBeSensor() { return !(Entity.TryGetComponent(out var l) && l.Lock.IsLocked); } public override bool ShouldCollide(Entity entity) { /*if (entity is Projectile) { return false; }*/ if (entity is Player && ShouldBeSensor()) { return false; } return true; } } } ================================================ FILE: BurningKnight/entity/component/DropModifier.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.item; namespace BurningKnight.entity.component { public interface DropModifier { void ModifyDrops(List drops); } } ================================================ FILE: BurningKnight/entity/component/DropsComponent.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.entity.creature; using BurningKnight.entity.creature.drop; using BurningKnight.entity.item; using Lens.entity.component; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.component { public class DropsComponent : Component { public List Drops = new List(); public DropsComponent() { } public DropsComponent(string dropId) { Add(dropId); } public void Add(string dropId) { if (!assets.loot.Drops.Defined.TryGetValue(dropId, out var d)) { Log.Error($"Unknown drop {dropId}"); return; } Drops.Add(d); } public void Add(params Drop[] drops) { Drops.AddRange(drops); } public void SpawnDrops() { Drop.Create(Drops, Entity); } } } ================================================ FILE: BurningKnight/entity/component/ExplodableComponent.cs ================================================ using System; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class ExplodableComponent : Component { public Action OnExplosion; public void HandleExplosion(Entity entity, Entity origin, float damage) { OnExplosion?.Invoke(); Send(new ExplodedEvent { Who = entity, Origin = origin ?? entity, Damage = damage }); } } } ================================================ FILE: BurningKnight/entity/component/ExplodeComponent.cs ================================================ using BurningKnight.entity.bomb; using Lens.entity.component; namespace BurningKnight.entity.component { public class ExplodeComponent : Component { public float Timer; public float Radius = 32f; public override void Update(float dt) { base.Update(dt); Timer -= dt; if (Timer <= 0) { if (Entity is Bomb b) { b.Explode(); return; } Entity.Done = true; ExplosionMaker.Make(Entity, Radius); } } } } ================================================ FILE: BurningKnight/entity/component/ExtraAnimationComponent.cs ================================================ using Lens.graphics.animation; namespace BurningKnight.entity.component { public class ExtraAnimationComponent : AnimationComponent { public ExtraAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } public ExtraAnimationComponent(string animationName, ColorSet set) : base(animationName, set) { } } } ================================================ FILE: BurningKnight/entity/component/FollowerComponent.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.entity.creature.player; using BurningKnight.util; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class FollowerComponent : Component { public Entity Following; public Entity Follower; public float MaxDistance = 16; public float Pause = -1; public bool Paused; public float FollowSpeed = 3; public void DestroyAll() { if (Follower != null) { Follower.GetComponent().DestroyAll(); Follower.Done = true; } } public void Remove() { if (Following != null) { var f = Following.GetComponent(); f.Follower = Follower; if (Follower != null) { f.Follower.GetComponent().Following = Following; } } Follower = null; Following = null; } public override void Update(float dt) { base.Update(dt); if (Follower != null && Follower.Done) { Follower = null; } if (Following != null) { if (Following.Done) { Following.GetComponent().Remove(); Following = null; } if (Following == null) { return; } var body = Entity.GetAnyComponent(); if (body == null) { return; } var sp = dt * 16f; body.Velocity -= body.Velocity * (sp * 0.4f); if (Paused) { return; } if (Pause > 0) { Pause -= dt; return; } var dx = Following.DxTo(Entity); var dy = Following.DyTo(Entity); var d = Math.Sqrt(dx * dx + dy * dy); if (d > 1024f || !Entity.OnScreen) { AnimationUtil.Poof(Entity.Center); Entity.Center = Following.Center + Rnd.Vector(-16, 16); AnimationUtil.Poof(Entity.Center); return; } if (d < 12) { sp *= -1; } else if (d < MaxDistance) { return; } if (Following.TryGetComponent(out var rb)) { body.Velocity = body.Velocity.Lerp(rb.Velocity, dt * FollowSpeed); } else if (Following.TryGetComponent(out var cb)) { body.Velocity = body.Velocity.Lerp(cb.Velocity, dt * FollowSpeed); } else if (Following.TryGetComponent(out var sb)) { body.Velocity = body.Velocity.Lerp(sb.Velocity, dt * FollowSpeed); } body.Velocity -= new Vector2(dx * sp, dy * sp); } } public void AddFollower(Entity e) { if (e == Entity) { return; } if (!e.HasComponent()) { e.AddComponent(new FollowerComponent()); } if (Follower != null) { Follower.GetComponent().AddFollower(e); } else { Follower = e; e.GetComponent().Following = Entity; } if (Entity is Player) { var depth = 0; var entity = Entity; while (entity != null) { entity = entity.GetComponent().Follower; if (entity != null) { depth++; } } if (depth >= 3) { Achievements.Unlock("bk:family"); } } } } } ================================================ FILE: BurningKnight/entity/component/GamepadComponent.cs ================================================ using System; using BurningKnight.assets.items; using Lens.entity.component; using Lens.entity.component.logic; using Lens.input; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework.Input; namespace BurningKnight.entity.component { public class GamepadComponent : Component { public static GamepadData Current; private GamepadData controller; public GamepadData Controller { get => controller; set { controller = value; Entity.GetComponent().GamepadData = value; } } public string GamepadId; static GamepadComponent() { Camera.OnShake += () => { if (Current == null || !Settings.Vibrate || Settings.Gamepad == null) { return; } var am = Camera.Instance.GetComponent().Amount; if (am < 5) { return; } var a = Math.Max(1, am / 20f); Current.Rumble(a, Math.Max(0.1f, a * 0.5f)); }; } public override void Init() { base.Init(); UpdateState(); } public override void Destroy() { base.Destroy(); Controller?.StopRumble(); } private void UpdateState() { if (Settings.Gamepad != GamepadId && Settings.Gamepad != null) { for (int i = 0; i < 4; i++) { var c = GamePad.GetCapabilities(i); if (c.IsConnected && c.Identifier == Settings.Gamepad) { Controller = Input.Gamepads[i]; GamepadId = Settings.Gamepad; Current = Controller; Log.Info($"Connected {GamePad.GetState(i)}"); Items.Unlock("bk:gamepad"); break; } } Settings.Gamepad = null; } else if (Controller == null) { for (int i = 0; i < 4; i++) { if (GamePad.GetCapabilities(i).IsConnected) { Controller = Input.Gamepads[i]; GamepadId = GamePad.GetCapabilities(i).Identifier; Current = Controller; Settings.Gamepad = GamepadId; Log.Info($"Connected {GamePad.GetState(i)}"); Items.Unlock("bk:gamepad"); return; } } Settings.Gamepad = null; } } public override void Update(float dt) { base.Update(dt); UpdateState(); } } } ================================================ FILE: BurningKnight/entity/component/HatComponent.cs ================================================ using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.entity.creature.player; using BurningKnight.entity.item; using BurningKnight.save; using Lens.input; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class HatComponent : ItemComponent { public bool DoNotRender; private bool loaded; public override void Init() { base.Init(); Entity.GetComponent().InitCallback = Setup; } public void Setup() { loaded = true; if (Item == null) { var hat = GlobalSave.GetString($"hat_{Entity.GetComponent().Index}"); Log.Debug($"hat_{Entity.GetComponent().Index}"); if (hat != null) { Set(Items.CreateAndAdd(hat, Entity.Area), false); } else { Set(Items.CreateAndAdd("bk:no_hat", Entity.Area), false); } } } protected override bool ShouldReplace(Item item) { return item.Type == ItemType.Hat; } public override void Set(Item item, bool animate = true) { base.Set(item, animate); if (loaded) { GlobalSave.Put($"hat_{Entity.GetComponent().Index}", item?.Id); } if (item != null) { DoNotRender = item.Id == "bk:no_hat"; if (Entity.HasComponent()) { Entity.GetComponent().Light.Color = item.Id == "bk:glowing_mushroom" ? new Color(0.05f, 0.4f, 1f, 1f) : Player.LightColor; } } } protected override void OnItemSet(Item previous) { base.OnItemSet(previous); foreach (var i in Entity.Area.Tagged[Tags.Item]) { if (i is EmeraldStand st) { st.RecalculatePrice(); } } } } } ================================================ FILE: BurningKnight/entity/component/HealthComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.custom; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.buff; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class HealthComponent : SaveableComponent { private float health; public byte Phases; public bool RenderInvt; public float Health => health; public int MaxHealthCap = -1; public bool AutoKill = true; public bool SaveMaxHp; public bool PreventDamageInInvincibility = true; public bool HasNoHealth => health <= 0.01f; public float Percent => Health / MaxHealth; public bool SetHealth(float hp, Entity setter, bool mod = true, DamageType type = DamageType.Regular) { if (Math.Abs(hp - health) < 0.01f) { return false; } if (hp < health) { if (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0)) { return false; } } var old = health; var h = MathUtils.Clamp(0, maxHealth, hp); var e = new HealthModifiedEvent { Amount = h - old, Who = Entity, From = setter, Type = type }; if (!Send(e)) { h = old + e.Amount; if (old > h) { InvincibilityTimer = mod ? InvincibilityTimerMax : 0.1f; } if (e.Amount > 0) { EmitParticles(HealthType.Regular); } health = h; Send(new PostHealthModifiedEvent { Amount = e.Amount, Who = Entity, From = setter, Type = type }); TryToKill(setter, type); return true; } return false; } private void TryToKill(Entity e, DamageType type) { if (health <= 0.1f && (!Entity.TryGetComponent(out var c) || c.Total == 0) && AutoKill) { Kill(e, type); } } public bool LastModifiedHearts; public bool ModifyHealth(float amount, Entity setter, DamageType type = DamageType.Regular) { LastModifiedHearts = false; if (amount < 0 && Entity is Player && (Run.Depth != -2 && Run.Depth < 1)) { if (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0) || Health <= 0.01f) { return false; } Send(new HealthModifiedEvent { Amount = 0, Who = Entity, From = null }); InvincibilityTimer = InvincibilityTimerMax; return false; } if (amount < 0) { if (Entity.TryGetComponent(out var hearts)) { if (hearts.Total > 0) { if (Unhittable || (PreventDamageInInvincibility && InvincibilityTimer > 0)) { return false; } if (hearts.Hurt((int) Math.Round(amount), setter, type)) { InvincibilityTimer = InvincibilityTimerMax; TryToKill(setter, type); LastModifiedHearts = true; return true; } return false; } } } return SetHealth(health + (amount), setter, true, type); } private int maxHealth; public int MaxHealth { get => maxHealth; set { if (maxHealth == value) { return; } var old = maxHealth; var nw = Math.Max(0, value); if (MaxHealthCap > -1) { nw = Math.Min(MaxHealthCap, nw); } if (!Send(new MaxHealthModifiedEvent { Who = Entity, Amount = nw - old })) { maxHealth = nw; health = Math.Min(health, maxHealth); } } } public int InitMaxHealth { set { maxHealth = value; health = maxHealth; } } private bool dead; public bool Unhittable; public float InvincibilityTimer; public float InvincibilityTimerMax = 0.5f; public bool Dead => dead; public void Kill(Entity from, DamageType damageType = DamageType.Regular) { if (Phases > 0) { Phases--; maxHealth = Math.Max(1, maxHealth); health = (int) Math.Floor((Entity is Player ? 0.5f : 1f) * maxHealth); Send(new RevivedEvent { WhoDamaged = from, Who = Entity }); return; } if (dead) { Entity.Done = true; return; } health = 0; if (!Send(new DiedEvent { From = from, Who = Entity, DamageType = damageType })) { dead = true; Entity.Done = true; } } // Needed for loading public HealthComponent() { } public void EmitParticles(HealthType type) { var slice = "heart"; switch (type) { case HealthType.Shield: { slice = "shield"; break; } case HealthType.Bomb: { slice = "bomb"; break; } } for (var i = 0; i < 3; i++) { Timer.Add(() => { var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"{slice}_{Rnd.Int(1, 4)}")))); part.Position = Entity.Center; if (Entity.TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Entity.Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.9f; part.Depth = Layers.InGameUi; }, i * 0.5f); } } public override bool HandleEvent(Event e) { if (e is ItemCheckEvent ev && ev.Item.Type == ItemType.Heart) { Send(new ItemAddedEvent { Item = ev.Item, Who = Entity }); Audio.PlaySfx(ev.Item.Id == "bk:shield" ? "item_shield" : "item_heart"); ev.Item.Use(Entity); Engine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null ? ev.Item.GetComponent().Animation.GetFirstCurrent() : ev.Item.Region, (Player) Entity)); ev.Item.Done = true; return true; } else if (e is ExplodedEvent b && !b.Handled) { Items.Unlock("bk:infinite_bomb"); if (Entity is Player && b.Who == Entity && Entity.GetComponent().Item?.Id == "bk:explosive_lamp") { } else { ModifyHealth(Entity is Player ? -2 : -b.Damage, b.Who, DamageType.Explosive); var component = Entity.GetAnyComponent(); component?.KnockbackFrom(b.Who, 2); } } return base.HandleEvent(e); } public bool IsFull() { return Math.Abs(health - MaxHealth) < 0.01f; } public bool CanPickup(Item item) { if (item.Id.Contains("heart")) { return !IsFull(); } if (!Entity.TryGetComponent(out var h)) { return false; } return h.CanHaveMore; } public override void Update(float dt) { base.Update(dt); InvincibilityTimer = Math.Max(0, InvincibilityTimer - dt); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteFloat(health); stream.WriteByte(Phases); if (SaveMaxHp) { stream.WriteByte((byte) maxHealth); } } public override void Load(FileReader stream) { base.Load(stream); health = stream.ReadFloat(); Phases = stream.ReadByte(); if (SaveMaxHp) { maxHealth = stream.ReadByte(); } } public override void RenderDebug() { var hp = health; if (ImGui.InputFloat("Health", ref hp)) { health = hp; } ImGui.InputInt("Max health", ref maxHealth); var v = (int) Phases; if (ImGui.InputInt("Phases", ref v)) { Phases = (byte) v; } ImGui.Checkbox("Unhittable", ref Unhittable); if (ImGui.Button("Heal")) { ModifyHealth(maxHealth - health, null); } ImGui.SameLine(); if (ImGui.Button("Hurt")) { ModifyHealth(-1, null); } ImGui.SameLine(); if (ImGui.Button("Kill")) { ModifyHealth(-health, null); } } } } ================================================ FILE: BurningKnight/entity/component/InteractDialogComponent.cs ================================================ using BurningKnight.ui.dialog; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class InteractDialogComponent : Component { private string dialog; private bool started; private Entity toStart; public InteractDialogComponent(string d) { dialog = d; } public override void Init() { base.Init(); Entity.AddComponent(new InteractableComponent(Interact) { CanInteract = e => !started }); } public override void Update(float dt) { base.Update(dt); // Delayed setup to avoid interaction flowing into this dialog if (toStart != null) { var d = GetComponent(); d.OnNext += OnNext; d.Start(dialog, toStart); started = true; toStart = null; } } private void OnNext(DialogComponent d) { if (d.Current == null) { d.OnNext -= OnNext; started = false; } } private bool Interact(Entity e) { if (started) { return false; } toStart = e; return true; } } } ================================================ FILE: BurningKnight/entity/component/InteractableComponent.cs ================================================ using System; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class InteractableComponent : Component { public Func Interact; public Func CanInteract; public Action OnStart; public Action OnEnd; public Func AlterInteraction; public Entity CurrentlyInteracting; public float OutlineAlpha; public InteractableComponent(Func interact) { Interact = interact; } public override void Update(float dt) { base.Update(dt); OutlineAlpha += ((CurrentlyInteracting == null ? 0 : 1) - OutlineAlpha) * dt * 8; } } } ================================================ FILE: BurningKnight/entity/component/InteractableSliceComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.util; using Lens.entity.component.graphics; using Lens.graphics; using Lens.graphics.animation; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class InteractableSliceComponent : SliceComponent { public Vector2 Scale = Vector2.One; public InteractableSliceComponent(string image, string slice) : base(image, slice) {} public InteractableSliceComponent(AnimationData image, string slice) : base(image, slice) {} public override void Render(bool shadow) { var origin = new Vector2(Sprite.Width / 2, Sprite.Height); var pos = Entity.Position + origin + Offset; if (shadow) { Graphics.Render(Sprite, pos, 0, new Vector2(origin.X, 0), Scale, Graphics.ParseEffect(Flipped, !FlippedVerticaly)); return; } if (Entity.TryGetComponent(out var z)) { pos -= new Vector2(0, z.Z); } if (Entity.TryGetComponent(out var component) && component.OutlineAlpha > 0.05f) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(component.OutlineAlpha); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); foreach (var d in MathUtils.Directions) { Graphics.Render(Sprite, pos + d, 0, origin, Scale); } Shaders.End(); } var stopShader = false; if (Entity.TryGetComponent(out var health) && health.RenderInvt) { var i = health.InvincibilityTimer; if (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); stopShader = true; } } Graphics.Render(Sprite, pos, 0, origin, Scale); if (stopShader) { Shaders.End(); } } } } ================================================ FILE: BurningKnight/entity/component/InventoryComponent.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.assets.particle; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.level; using BurningKnight.state; using ImGuiNET; using Lens.entity; using Lens.entity.component; using Lens.util.file; using Lens.util.math; namespace BurningKnight.entity.component { public class InventoryComponent : SaveableComponent { public List Items = new List(); public bool Busy; public bool Pickup(Item item, bool animate = true) { if (item == null) { return false; } var e = new ItemCheckEvent { Item = item, Animate = animate }; if (!Send(e)) { if (e.Blocked) { return false; } if (Entity is Player p && (item.Type == ItemType.Scourge || item.Type == ItemType.Artifact || item.Type == ItemType.ConsumableArtifact)) { if (item.Type == ItemType.ConsumableArtifact) { p.AnimateItemPickup(item, () => { item.Use(p); item.Done = true; }, false); } else if (animate) { p.AnimateItemPickup(item, () => { if (item.Type == ItemType.Scourge) { Achievements.Unlock("bk:scourged"); var center = Entity.Center; for (var i = 0; i < 10; i++) { var part = new ParticleEntity(Particles.Scourge()); part.Position = center + Rnd.Vector(-4, 4); part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Entity.Area.Add(part); part.Depth = 1; } } }); } else { Add(item); if (item.Type == ItemType.Scourge) { Achievements.Unlock("bk:scourged"); } } } } item.Unknown = false; Entity.Area.Remove(item); item.Done = false; return true; } public bool Has(string id) { foreach (var i in Items) { if (i.Id == id) { return true; } } return false; } public void Add(Item item) { if (item == null) { return; } if (item.HasComponent()) { item.RemoveComponent(); } Items.Add(item); item.RemoveDroppedComponents(); item.AddComponent(new OwnerComponent(Entity)); item.Use(Entity); if (Entity is Player && !item.Touched && item.Scourged) { Run.AddScourge(true); } var e = new ItemAddedEvent { Item = item, Who = Entity }; Send(e); item.Touched = true; } public void RemoveAndDispose(string id) { foreach (var i in Items) { if (i.Id == id) { Remove(i, true); break; } } } public void Remove(Item item, bool dispose = false) { Items.Remove(item); var e = new ItemRemovedEvent { Item = item, Owner = Entity }; Send(e); item.HandleEvent(e); if (dispose) { item.Done = true; return; } item.Center = Entity.Center; Entity.Area.Add(item); item.AddDroppedComponents(); item.RemoveComponent(); } public override bool HandleEvent(Event e) { foreach (var item in Items) { if (item.HandleOwnerEvent(e)) { return true; } } return base.HandleEvent(e); } public override void Update(float dt) { base.Update(dt); for (int i = Items.Count - 1; i >= 0; i--) { var item = Items[i]; if (item.Done) { Remove(item); } else { var o = item.Owner; foreach (var u in item.Uses) { u.Update(o, item, dt); } } } } public override void Save(FileWriter stream) { stream.WriteInt16((short) Items.Count); foreach (var item in Items) { item.Save(stream); } } public override void Load(FileReader stream) { var count = stream.ReadInt16(); for (var i = 0; i < count; i++) { var item = new Item(); Entity.Area.Add(item, false); item.Load(stream); item.LoadedSelf = false; item.PostInit(); Pickup(item, false); Entity.Area.Remove(item); item.Done = false; } } public override void RenderDebug() { ImGui.Text($"Total {Items.Count} items"); foreach (var item in Items) { ImGui.BulletText(item.Id); } } } } ================================================ FILE: BurningKnight/entity/component/ItemComponent.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.entity.component; using Lens.entity.component.logic; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class ItemComponent : SaveableComponent { public Item Item { get; protected set; } public bool DontSave; public bool UpdateItem; public bool Has(string id) { return Item?.Id == id; } public virtual void Set(Item item, bool animate = true) { var prev = Item; if (!animate && Item != null) { Drop(); Item = null; #if DEBUG debugItem = ""; #endif } if (item == null) { Item = null; return; } Entity.Area.Remove(item); item.RemoveDroppedComponents(); item.AddComponent(new OwnerComponent(Entity)); if (!animate) { SetupItem(item, prev); return; } if (Item != null) { Drop(); Item = null; #if DEBUG debugItem = ""; #endif } if (Entity is Player p) { p.AnimateItemPickup(item, () => { SetupItem(item, prev); }, false); } else { SetupItem(item, prev); } } private void SetupItem(Item item, Item previous) { Send(new ItemAddedEvent { Item = item, Component = this, Who = Entity, Old = previous }); Item = item; if (Entity is Player && !item.Touched && item.Scourged) { Run.AddScourge(true); } item.Done = false; item.Touched = true; item.RemoveDroppedComponents(); #if DEBUG debugItem = item.Id; #endif OnItemSet(previous); } protected virtual void OnItemSet(Item previous) { } public Item Drop() { var e = new ItemRemovedEvent { Item = Item }; Send(e); Item.Center = Entity.Center - new Vector2(0, 4); Entity.Area.Add(Item); Item.RemoveComponent(); Item.AddDroppedComponents(); var item = Item; Item = null; #if DEBUG debugItem = ""; #endif return item; } public override void Update(float dt) { base.Update(dt); if (Item != null) { if (Item.Done) { Item = null; #if DEBUG debugItem = ""; #endif } else { Item.Center = Entity.Center; if (UpdateItem) { Item.Update(dt); } } } } protected virtual bool ShouldReplace(Item item) { return Item == null; } public override bool HandleEvent(Event e) { if (Item != null && Item.HandleOwnerEvent(e)) { return true; } if (e is ItemCheckEvent ev && !ev.Handled && ShouldReplace(ev.Item)) { if (Entity is Player && Item != null && Item.Scourged) { AnimationUtil.ActionFailed(); ev.Blocked = true; Entity.GetComponent().StartAndClose($"~~{Locale.Get("scourged")}~~", 2); return false; } Set(ev.Item, ev.Animate); return true; } return base.HandleEvent(e); } public override void Save(FileWriter stream) { if (DontSave) { stream.WriteBoolean(false); return; } stream.WriteBoolean(Item != null); Item?.Save(stream); } public override void Load(FileReader stream) { if (stream.ReadBoolean()) { var item = new Item(); Entity.Area.Add(item, false); item.Load(stream); item.LoadedSelf = false; item.PostInit(); Set(item, false); } } public void Exchange(ItemComponent component) { var tmp = component.Item; component.Item = Item; if (Item != null) { if (!Item.HasComponent()) { Item.AddComponent(new OwnerComponent(component.Entity)); } else { Item.GetComponent().Owner = component.Entity; } } Item = tmp; if (Item == null) { return; } if (!Item.HasComponent()) { Item.AddComponent(new OwnerComponent(Entity)); } else { Item.GetComponent().Owner = Entity; } } #if DEBUG private string debugItem = ""; public override void RenderDebug() { if (Item != null) { ImGui.Text($"Use time: {Item.UseTime}"); ImGui.Text($"Delay: {Item.Delay}"); } if (ImGui.InputText("Item", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) { var item = Items.CreateAndAdd(debugItem, Entity.Area); Set(item); } } #endif public void Cleanse() { if (Item != null && Item.Scourged) { Item.Scourged = false; } } } } ================================================ FILE: BurningKnight/entity/component/LockComponent.cs ================================================ using System; using BurningKnight.entity.door; using BurningKnight.entity.events; using Lens; using Lens.entity; using Lens.entity.component; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.component { public class LockComponent : Component, Subscriber { public Lock Lock; public Action OnOpen; private Vector2 offset; public LockComponent(Entity entity, Lock l, Vector2 offset) { Lock = l; l.Owner = entity; Lock.AlwaysActive = true; Lock.Move = false; entity.Area.Add(Lock); entity.Area.EventListener.Subscribe(this); if (Lock.Interactable()) { Lock.AddComponent(new RectBodyComponent(-(entity.Width - Lock.Width) / 2f - offset.X - 2, -(entity.Height - Lock.Height) / 2f - offset.Y - 2, entity.Width + 4, entity.Height + 4, BodyType.Static, true)); } Lock.Center = entity.Center + offset; this.offset = offset; } public override void Init() { base.Init(); Lock.AddComponent(new OwnerComponent(Entity)); } public override void Update(float dt) { base.Update(dt); if (Lock.Done) { if (Engine.EditingLevel && Entity is ConditionDoor) { Entity.Done = true; } return; } Lock.Center = Entity.Center + offset; } public override bool HandleEvent(Event e) { if (e is LockOpenedEvent ev && ev.Lock == Lock) { OnOpen?.Invoke(ev.Who); } return base.HandleEvent(e); } public override void Destroy() { base.Destroy(); Lock.Done = true; } } } ================================================ FILE: BurningKnight/entity/component/ManaComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.custom; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class ManaComponent : SaveableComponent { private byte manaMax = 6; private byte mana = 6; public int ManaMax { get => manaMax; set { manaMax = (byte) MathUtils.Clamp(2, 254, value); mana = (byte) MathUtils.Clamp(2, manaMax, mana); } } public int Mana => mana; public void ModifyMana(int amount) { mana = (byte) MathUtils.Clamp(0, manaMax, mana + amount); } public void SetMana(int amount) { mana = (byte) MathUtils.Clamp(0, manaMax, amount); } public override void Load(FileReader stream) { base.Load(stream); manaMax = stream.ReadByte(); mana = stream.ReadByte(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte(manaMax); stream.WriteByte(mana); } public override bool HandleEvent(Event e) { if (e is ItemCheckEvent ev && ev.Item.Type == ItemType.Mana) { Send(new ItemAddedEvent { Item = ev.Item, Who = Entity }); Audio.PlaySfx("item_mana"); for (var i = 0; i < 3; i++) { Timer.Add(() => { var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"star_{Rnd.Int(1, 4)}")))); part.Position = Entity.Center; if (Entity.TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Entity.Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.9f; part.Depth = Layers.InGameUi; }, i * 0.2f); } ev.Item.Use(Entity); Engine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null ? ev.Item.GetComponent().Animation.GetFirstCurrent() : ev.Item.Region, (Player) Entity)); ev.Item.Done = true; return true; } return base.HandleEvent(e); } public override void RenderDebug() { var v = (int) mana; if (ImGui.InputInt("Mana", ref v)) { mana = (byte) v; } v = manaMax; if (ImGui.InputInt("Max Mana", ref v)) { manaMax = (byte) v; } if (ImGui.Button("Reset")) { ModifyMana(manaMax - mana); } } public bool IsFull() { return mana == manaMax; } public bool CanPickup(Item item) { return !IsFull(); } } } ================================================ FILE: BurningKnight/entity/component/MobAnimationComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.creature.mob; using Lens.graphics; using Lens.graphics.animation; using Lens.util; namespace BurningKnight.entity.component { public class MobAnimationComponent : AnimationComponent { public MobAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } public MobAnimationComponent(string animationName, ColorSet set) : base(animationName, set) { } public override void Render(bool shadow) { if (!shadow) { var m = (Mob) Entity; if (m.HasPrefix) { var p = m.Prefix; var pos = Entity.Position + Offset; var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(p.GetColor()); foreach (var d in MathUtils.Directions) { CallRender(pos + d, false); } Shaders.End(); } } base.Render(shadow); } } } ================================================ FILE: BurningKnight/entity/component/NoCornerBodyComponent.cs ================================================ using BurningKnight.physics; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; using VelcroPhysics.Factories; using VelcroPhysics.Shared; namespace BurningKnight.entity.component { public class NoCornerBodyComponent : BodyComponent { public NoCornerBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) { if (center) { x -= w / 2; y -= h / 2; } Body = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type); Body.FixedRotation = true; Body.UserData = this; Body.LinearDamping = 0; float mx = w / 3f; float my = h / 3f; FixtureFactory.AttachPolygon(new Vertices(4) { new Vector2(x, y + my), new Vector2(x + mx, y), new Vector2(x + w - mx, y), new Vector2(x + w, y + my), new Vector2(x + w, y + h - my), new Vector2(x + w - mx, y + h), new Vector2(x + mx, y + h), new Vector2(x, y + h - my) }, 1f, Body); } } } ================================================ FILE: BurningKnight/entity/component/OrbitGiverComponent.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.entity.creature.player; using Lens.entity; using Lens.entity.component; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class OrbitGiverComponent : Component { public List Orbiting = new List(); public float RadiusMultiplier = 1; public float T; public float Speed = 1; private float count; private Vector2 center; public void DestroyAll() { foreach (var o in Orbiting) { o.Done = true; } Orbiting.Clear(); } public override void Update(float dt) { base.Update(dt); T += dt * Speed; count += (Orbiting.Count - count) * dt * 4; if (Entity.DistanceTo(center) > 32f) { center = Entity.Center; } else { center += (Entity.Center - center) * (dt * 8); } for (var i = Orbiting.Count - 1; i >= 0; i--) { var e = Orbiting[i]; var component = e.GetComponent(); var d = component.Radius * RadiusMultiplier; var a = i / count * Math.PI * 2 - T * 1.5f; if (e.Done) { RemoveOrbiter(e); continue; } component.CurrentAngle = (float) a; var target = center + new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); if (component.Lerp) { e.Center += (target - e.Center) * (dt * 8); } else { e.Center = target; } } } public void AddOrbiter(Entity e) { if (!e.HasComponent()) { e.AddComponent(new OrbitalComponent()); } /*if (Entity is Player && Orbiting.Count == 0) { Entity.GetComponent().Emit("item_orbitals", 0.5f, looped: true, tween: true); } */ e.GetComponent().Orbiting = Entity; Orbiting.Add(e); if (Entity is Player && Orbiting.Count >= 3) { Achievements.Unlock("bk:star"); } } public void RemoveOrbiter(Entity e) { Orbiting.Remove(e); e.GetComponent().Orbiting = null; if (Orbiting.Count == 0) { RemoveSound(); } } public override void Destroy() { base.Destroy(); foreach (var o in Orbiting) { o.GetComponent().Orbiting = null; } RemoveSound(); Orbiting.Clear(); } private void RemoveSound() { /*if (Entity is Player) { var c = Entity.GetComponent(); foreach (var s in c.Playing) { if (s.Key == "item_orbitals") { var e = s.Value; e.Effect.IsLooped = false; e.Effect.Pause(); Tween.To(0, 1f, x => e.BaseVolume = x, 0.3f); break; } } }*/ } } } ================================================ FILE: BurningKnight/entity/component/OrbitalComponent.cs ================================================ using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class OrbitalComponent : Component { public float Radius = 20; public bool Lerp; public Entity Orbiting; public float CurrentAngle; } } ================================================ FILE: BurningKnight/entity/component/OwnerComponent.cs ================================================ using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class OwnerComponent : Component { public Entity Owner; public OwnerComponent(Entity owner) { Owner = owner; } } } ================================================ FILE: BurningKnight/entity/component/PoolDropsComponent.cs ================================================ using BurningKnight.entity.creature; using BurningKnight.entity.creature.drop; using BurningKnight.entity.item; namespace BurningKnight.entity.component { public class PoolDropsComponent : DropsComponent { public PoolDropsComponent(ItemPool pool, float chance, int min, int max) { Add(new PoolDrop(pool, chance, min, max)); } } } ================================================ FILE: BurningKnight/entity/component/QuackInteractionComponent.cs ================================================ using System; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class QuackInteractionComponent : Component { private Action action; public QuackInteractionComponent(Action callback) { action = callback; } public override void Init() { base.Init(); Entity.Subscribe(); } public override bool HandleEvent(Event e) { if (e is QuackEvent q) { if (q.Player.DistanceTo(Entity) <= 72f) { action(q.Player); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/component/RandomFrameComponent.cs ================================================ using System.Linq; using Lens.assets; using Lens.entity.component.graphics; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class RandomFrameComponent : GraphicsComponent { public TextureRegion Sprite; public Color Tint = ColorUtils.WhiteColor; public RandomFrameComponent(string anim) { var list = Animations.Get(anim).Layers.First().Value; Sprite = list[Rnd.Int(list.Count)].Texture; } public override void Render(bool shadow) { Graphics.Color = Tint; if (shadow) { Graphics.Render(Sprite, Entity.Position + new Vector2(0, Sprite.Height), 0, Vector2.Zero, Vector2.One, Graphics.ParseEffect(Flipped, !FlippedVerticaly)); } else { var pos = Entity.Position; if (Entity.TryGetComponent(out var c)) { pos.Y -= c.Z; } Graphics.Render(Sprite, pos); } Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/component/RectBodyComponent.cs ================================================ using BurningKnight.physics; using Lens.util; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; using VelcroPhysics.Factories; using VelcroPhysics.Shared; namespace BurningKnight.entity.component { public class RectBodyComponent : BodyComponent { public RectBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool sensor = false, bool center = false) { if (center) { x -= w / 2; y -= h / 2; Offset = new Vector2(w / 2, h / 2); } Body = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, type); Body.FixedRotation = true; Body.UserData = this; Body.LinearDamping = 0; if (type == BodyType.Static) { KnockbackModifier = 0; } FixtureFactory.AttachPolygon(new Vertices(4) { new Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h) }, 1f, Body).IsSensor = sensor; } public override void Resize(float x, float y, float w, float h, bool center = false) { var fixture = Body.FixtureList[0]; var sensor = fixture.IsSensor; Body.DestroyFixture(fixture); if (center) { x -= w / 2; y -= h / 2; Offset = new Vector2(w / 2, h / 2); } FixtureFactory.AttachPolygon(new Vertices(4) { new Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h) }, 1f, Body).IsSensor = sensor; } } } ================================================ FILE: BurningKnight/entity/component/RoomComponent.cs ================================================ using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.events; using BurningKnight.entity.room; using BurningKnight.level.rooms; using ImGuiNET; using Lens.entity.component; namespace BurningKnight.entity.component { public class RoomComponent : Component { public Room Room; public override void Init() { base.Init(); FindRoom(); Entity.PositionChanged += FindRoom; } public override void Update(float dt) { base.Update(dt); if (Room == null) { FindRoom(); } } public void FindRoom() { var old = Room; if (old != null) { if ((Entity is Boss b && b.Target != null) || old.Contains(Entity.Center)) { return; } } foreach (var room in Entity.Area.Tagged[Tags.Room]) { if (room.Contains(Entity.Center)) { Room = (Room) room; break; } } if (old != null && Entity is Mob && !(Entity is Boss) && !old.Contains(Entity.Center)) { old = null; } if (old != Room) { old?.Tagged.Remove(Entity); Room?.Tagged.Add(Entity); Send(new RoomChangedEvent { Who = Entity, Old = old, New = Room, WasDiscovered = Room == null || Room.Explored, JustDiscovered = Room != null && !Room.Explored }); } } public override void Destroy() { base.Destroy(); Room?.Tagged.Remove(Entity); } public override void RenderDebug() { ImGui.Text(Room == null ? "null" : $"{Room.Type}#{Room.Y}"); } public override void OnTagRemoved(int i) { base.OnTagRemoved(i); if (Room == null) { return; } Room.Tagged[i].Remove(Entity); } public override void OnTagAdded(int i) { base.OnTagAdded(i); if (Room == null) { return; } var a = Room.Tagged[i]; if (!a.Contains(Entity)) { a.Add(Entity); } } } } ================================================ FILE: BurningKnight/entity/component/ScalableSliceComponent.cs ================================================ using System; using BurningKnight.assets; using Lens.graphics; using Lens.graphics.animation; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class ScalableSliceComponent : SliceComponent { public Vector2 Scale = Vector2.One; public Vector2 Origin; public ScalableSliceComponent(TextureRegion region) : base("", null) { Sprite = region; } public ScalableSliceComponent(string image, string slice) : base(image, slice) { } public ScalableSliceComponent(AnimationData image, string slice) : base(image, slice) { } public override void Set(TextureRegion region) { base.Set(region); Origin = Sprite.Center; } public override void Render(bool shadow) { if (shadow) { Graphics.Render(Sprite, Entity.Position + Origin + new Vector2(0, ShadowZ + Sprite.Height), Angle, Origin, Scale, Graphics.ParseEffect(Flipped, ShadowZ > 0 ? FlippedVerticaly : !FlippedVerticaly)); return; } var stopShader = false; if (Entity.TryGetComponent(out var health) && health.RenderInvt) { var i = health.InvincibilityTimer; if (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); stopShader = true; } } Graphics.Render(Sprite, Entity.Position + Origin, Angle, Origin, Scale); if (stopShader) { Shaders.End(); } } public void Animate(Action callback = null) { Tween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f); Tween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, Scale.X, x => Scale.X = x, 0.4f); Tween.To(1, Scale.Y, x => Scale.Y = x, 0.4f); callback?.Invoke(); }; } } } ================================================ FILE: BurningKnight/entity/component/SensorBodyComponent.cs ================================================ using VelcroPhysics.Dynamics; namespace BurningKnight.entity.component { public class SensorBodyComponent : RectBodyComponent { public SensorBodyComponent(float x, float y, float w, float h, BodyType type = BodyType.Dynamic, bool center = false) : base(x, y, w, h, type, true, center) { } public override void KnockbackFrom(float a, float force = 1, float rnd = 0) { } } } ================================================ FILE: BurningKnight/entity/component/ShadowComponent.cs ================================================ using System; using Lens.entity.component; namespace BurningKnight.entity.component { public class ShadowComponent : Component { public Action Callback; public ShadowComponent(Action render = null) { Callback = render ?? (() => { Entity.GraphicsComponent.Render(true); }); } public override void Init() { base.Init(); Entity.AddTag(Tags.HasShadow); } public override void Destroy() { base.Destroy(); Entity.RemoveTag(Tags.HasShadow); } } } ================================================ FILE: BurningKnight/entity/component/SimpleZAnimationComponent.cs ================================================ using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class SimpleZAnimationComponent : AnimationComponent { public SimpleZAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } protected override void CallRender(Vector2 pos, bool shadow) { var component = GetComponent(); var region = Animation.GetCurrentTexture(); var origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height); if (!shadow) { pos.Y -= component.Z; } Graphics.Render(region, pos + origin, shadow ^ Flipped ? -Angle : Angle, origin, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly)); } } } ================================================ FILE: BurningKnight/entity/component/SliceComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.items; using Lens.assets; using Lens.entity.component.graphics; using Lens.graphics; using Lens.graphics.animation; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class SliceComponent : GraphicsComponent { public TextureRegion Sprite; public int ShadowZ; public float Angle; public SliceComponent(string image, string slice) { Set(image, slice); } public SliceComponent(AnimationData image, string slice) { Set(image.GetSlice(slice)); } public SliceComponent(TextureRegion region) { Set(region); } public void Set(string image, string slice) { if (image == null || slice == null) { Sprite = Textures.Missing; return; } Set(Animations.Get(image).GetSlice(slice)); } public virtual void Set(TextureRegion region) { Sprite = region; } public void AddShadow() { Entity.AddComponent(new ShadowComponent(RenderShadow)); } private void RenderShadow() { Render(true); } public void SetOwnerSize() { Entity.Width = Sprite.Width; Entity.Height = Sprite.Height; } public override void Render(bool shadow) { var o = Sprite.Center; if (shadow) { Graphics.Render(Sprite, Entity.Position + new Vector2(0, (int) Sprite.Height + ShadowZ) + o, Angle, o, Vector2.One, Graphics.ParseEffect(Flipped, ShadowZ > 0 ? FlippedVerticaly : !FlippedVerticaly)); return; } var stopShader = false; if (Entity.TryGetComponent(out var health) && health.RenderInvt) { var i = health.InvincibilityTimer; if (i > health.InvincibilityTimerMax / 2f || i % 0.1f > 0.05f) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); stopShader = true; } } Graphics.Render(Sprite, Entity.Position + o, Angle, o); if (stopShader) { Shaders.End(); } } } } ================================================ FILE: BurningKnight/entity/component/SparkEmitterComponent.cs ================================================ using BurningKnight.assets.particle; using Lens.entity.component; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class SparkEmitterComponent : Component { private readonly float delay; private readonly float chance; private float sinceLast; public SparkEmitterComponent(float delay, float chance) { this.delay = delay; this.chance = chance; } public override void Update(float dt) { base.Update(dt); sinceLast += dt; if (sinceLast > delay) { sinceLast = 0; if (Rnd.Chance(chance)) { var p = Particles.Wrap(Particles.Spark(), Entity.Area, new Vector2(Rnd.Float(Entity.Width) + Entity.X, Rnd.Float(Entity.Height) + Entity.Y)); p.Depth = 1; } } } } } ================================================ FILE: BurningKnight/entity/component/StatsComponent.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using BurningKnight.level.rooms; using ImGuiNET; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.file; namespace BurningKnight.entity.component { public class StatsComponent : SaveableComponent { private float speed = 1; private float damage = 1; private float fireRate = 1; private float rangedRate = 1; private float accuracy = 1; private float range = 1; private float knockback = 1; public float DMChance; public float GrannyChance; public bool SawDeal; public bool TookDeal; public bool TookDamageInRoom; public bool TookDamageInLastRoom; public bool TookDamageOnLevel; public bool UsedWeaponInRoom; public int HeartsPayed; public float Speed { get => speed; set => speed = MathUtils.Clamp(0.02f, 3f, value); } public float Damage { get => damage; set => damage = MathUtils.Clamp(0.1f, 100f, value); } public float FireRate { get => fireRate; set => fireRate = MathUtils.Clamp(0.1f, 3f, value); } public float RangedRate { get => rangedRate; set => rangedRate = MathUtils.Clamp(0.1f, 3f, value); } public float Accuracy { get => accuracy; set => accuracy = MathUtils.Clamp(0.1f, 10f, value); } public float Range { get => range; set => range = MathUtils.Clamp(0.1f, 3f, value); } public float Knockback { get => knockback; set => knockback = MathUtils.Clamp(0f, 4f, value); } public override void RenderDebug() { base.RenderDebug(); ImGui.InputFloat("Speed", ref speed); ImGui.InputFloat("Damage", ref damage); ImGui.InputFloat("Fire Rate", ref fireRate); ImGui.InputFloat("Ranged Rate", ref rangedRate); ImGui.InputFloat("Accuracy", ref accuracy); ImGui.InputFloat("Range", ref range); ImGui.InputFloat("Knockback", ref knockback); ImGui.Separator(); ImGui.InputFloat("DM Chance", ref DMChance); ImGui.InputFloat("Granny Chance", ref GrannyChance); ImGui.Checkbox("Saw Deal", ref SawDeal); ImGui.Checkbox("Took Deal", ref TookDeal); ImGui.Separator(); ImGui.Checkbox("Took Damage in Room", ref TookDamageInRoom); ImGui.Checkbox("Took Damage on Level", ref TookDamageOnLevel); ImGui.InputInt("Containers payed", ref HeartsPayed); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(SawDeal); stream.WriteBoolean(TookDeal); stream.WriteBoolean(TookDamageInRoom); stream.WriteBoolean(TookDamageOnLevel); stream.WriteInt32(HeartsPayed); } public override void Load(FileReader stream) { base.Load(stream); SawDeal = stream.ReadBoolean(); TookDeal = stream.ReadBoolean(); TookDamageInRoom = stream.ReadBoolean(); TookDamageOnLevel = stream.ReadBoolean(); HeartsPayed = stream.ReadInt32(); } public override bool HandleEvent(Event e) { if (e is PlayerHurtEvent) { if (!TookDamageOnLevel) { DMChance -= 0.5f; } var rm = Entity.GetComponent().Room; if (rm != null && !TookDamageInRoom && rm.Type == RoomType.Boss) { DMChance -= 0.25f; } TookDamageInRoom = true; TookDamageOnLevel = true; } else if (e is RoomChangedEvent rce) { if (rce.JustDiscovered) { TookDamageInLastRoom = TookDamageInRoom; TookDamageInRoom = false; UsedWeaponInRoom = false; } } else if (e is NewLevelStartedEvent) { TookDamageOnLevel = false; TookDamageInRoom = false; TookDamageInLastRoom = false; GrannyChance = 0.5f; DMChance = 1f; } else if (e is ProjectileCreatedEvent pce) { var projectile = pce.Projectile; projectile.Damage *= Damage; // Can turn out to be a disaster if (projectile.T > 0) { projectile.T *= Range; } } else if (e is MeleeArc.CreatedEvent mace) { var arc = mace.Arc; arc.Damage *= Damage; arc.Width *= Math.Max(1, Range); } else if (e is RoomClearedEvent rr) { if (!UsedWeaponInRoom && rr.Room != null) { var t = rr.Room.Type; if (t == RoomType.Regular || t == RoomType.Challenge || t == RoomType.Boss) { Achievements.Unlock("bk:white_flag"); } } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/component/SupportableComponent.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.room.controllable; using Lens.entity; using Lens.entity.component; namespace BurningKnight.entity.component { public class SupportableComponent : Component { public List Supports = new List(); public override void Destroy() { base.Destroy(); Supports.Clear(); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && cse.Entity is Support ss) { if (!Supports.Contains(ss) && (!(Entity is Player) || !(cse.Body is SensorBodyComponent))) { Supports.Add(ss); ss.Supporting.Add(Entity); ss.HandleEvent(new Support.StartedSupportingEvent { Support = ss, Entity = Entity }); } } else if (e is CollisionEndedEvent cee && cee.Entity is Support se) { if (Supports.Contains(se)) { Supports.Remove(se); se.Supporting.Remove(Entity); se.HandleEvent(new Support.EndedSupportingEvent { Support = se, Entity = Entity }); } } return base.HandleEvent(e); } public override void Update(float dt) { base.Update(dt); foreach (var s in Supports) { s.Apply(Entity, dt); } } public bool HasAnotherSupportBesides(Support support) { foreach (var s in Supports) { if (s != support) { return true; } } return false; } } } ================================================ FILE: BurningKnight/entity/component/TextGraphicsComponent.cs ================================================ using BurningKnight.assets; using Lens.entity.component.graphics; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class TextGraphicsComponent : GraphicsComponent { private string text; public Color Color = Color.White; public float Scale = 1; public float Angle; public byte A { get => Color.A; set => Color.A = value; } public TextGraphicsComponent(string str) { text = str; } public override void Render(bool shadow) { if (shadow) { Graphics.Print(text, Font.Medium, Entity.Position, 0, Vector2.Zero, Vector2.One, Graphics.ParseEffect(Flipped, FlippedVerticaly)); return; } var origin = new Vector2(Entity.Width / 2f, Entity.Height / 2); Graphics.Color = Color; Graphics.Print(text, Font.Medium, Entity.Position + origin, Angle, origin, new Vector2(Scale)); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/component/TileInteractionComponent.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.particle; using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.entity.room.controllable; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util.geometry; using Lens; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class TileInteractionComponent : Component { public bool[] LastTouching; public bool[] Touching; public bool[] LastFlags; public bool[] Flags; public bool HasNoSupport; public bool HadNoSupport; public bool HasNoTileSupport; public Vector2 LastSupportedPosition; public TileInteractionComponent() { Touching = new bool[(int) Tile.Total]; LastTouching = new bool[(int) Tile.Total]; LastFlags = new bool[8]; Flags = new bool[8]; } public override void Update(float dt) { base.Update(dt); if (Entity is Creature c && c.InAir()) { HasNoSupport = false; return; } for (int i = 0; i < Touching.Length; i++) { LastTouching[i] = Touching[i]; Touching[i] = false; } for (int i = 0; i < Flags.Length; i++) { LastFlags[i] = Flags[i]; Flags[i] = false; } HadNoSupport = HasNoSupport; HasNoTileSupport = true; var h = Entity.TryGetComponent(out var sp); HasNoSupport = !h || sp.Supports.Count == 0; if (h && sp.Supports.Count > 0) { LastSupportedPosition = Entity.Position; } ApplyForAllTouching(InspectTile); for (int i = 0; i < Touching.Length; i++) { CheckTile(i); } for (int i = 0; i < Flags.Length; i++) { CheckFlag(i); } CheckSupport(); } private void InspectTile(int index, int x, int y) { var level = Run.Level; if (!level.IsInside(x, y)) { return; } var tile = level.Tiles[index]; var liquid = level.Liquid[index]; if (tile > 0) { Touching[tile] = true; if (HasNoTileSupport) { var t = (Tile) tile; if (t != Tile.Chasm && (!t.IsWall() || (level.IsInside(x, y + 1) && !level.Get(x, y + 1).IsWall() && level.Get(x, y + 1) != Tile.Chasm))) { HasNoSupport = false; HasNoTileSupport = false; LastSupportedPosition = new Vector2((int) x * 16, (int) y * 16); } } } if (liquid > 0) { Touching[liquid] = true; } if (level.CheckFlag(index, Flag.Burning)) { Flags[Flag.Burning] = true; } } public void ApplyForAllTouching(Action action) { var ex = Entity.X + Entity.Width / 6f; var ey = Entity.Y + Entity.Height / 2f; var ew = Entity.Width / 6f * 4f; var eh = Entity.Height / 2f; var rect = new Rect((int) ex, (int) ey, (int) (ex + ew), (int) (ey + eh)); var startX = (int) Math.Floor(ex / 16f); var startY = (int) Math.Floor(ey / 16f); var endX = (int) Math.Floor((ex + ew) / 16f); var endY = (int) Math.Floor((ey + eh) / 16f); var level = Run.Level; for (int x = startX; x <= endX; x++) { for (int y = startY; y <= endY; y++) { var index = level.ToIndex(x, y); if (!level.IsInside(index)) { continue; } if (new Rect(x * 16, y * 16, x * 16 + 16, y * 16 + 16).Intersects(rect)) { action(index, x, y); } } } } private void CheckSupport() { if (!HadNoSupport && HasNoSupport && !Engine.EditingLevel) { if (Send(new LostSupportEvent { Who = Entity })) { return; } Entity.Position = LastSupportedPosition; for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Entity.Center; part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Entity.Area.Add(part); } } } private void CheckTile(int tile) { if (!LastTouching[tile] && Touching[tile]) { Send(new TileCollisionStartEvent { Who = Entity, Tile = (Tile) tile }); } else if (LastTouching[tile] && !Touching[tile]) { Send(new TileCollisionEndEvent { Who = Entity, Tile = (Tile) tile }); } } private void CheckFlag(int flag) { if (!LastFlags[flag] && Flags[flag]) { Send(new FlagCollisionStartEvent { Who = Entity, Flag = flag }); } else if (LastFlags[flag] && !Flags[flag]) { Send(new FlagCollisionEndEvent { Who = Entity, Flag = flag }); } } } } ================================================ FILE: BurningKnight/entity/component/WallAnimationComponent.cs ================================================ using System; using Lens.graphics; using Lens.graphics.animation; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class WallAnimationComponent : MobAnimationComponent { public float WallAngle; public WallAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } public WallAnimationComponent(string animationName, ColorSet set) : base(animationName, set) { } protected override void CallRender(Vector2 pos, bool shadow) { var region = Animation.GetCurrentTexture(); var origin = new Vector2(0, region.Height / 2); var w = region.Width / 2f; Graphics.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); } } } ================================================ FILE: BurningKnight/entity/component/ZAnimationComponent.cs ================================================ using Lens.graphics; using Lens.graphics.animation; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class ZAnimationComponent : MobAnimationComponent { public Vector2 Scale = Vector2.One; public ZAnimationComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } public ZAnimationComponent(string animationName, ColorSet set) : base(animationName, set) { } protected override void CallRender(Vector2 pos, bool shadow) { var component = GetComponent(); var region = Animation.GetCurrentTexture(); var origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height); if (!shadow) { pos.Y -= component.Z; } Graphics.Render(region, pos + origin, shadow ^ Flipped ? -Angle : Angle, origin, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly)); } } } ================================================ FILE: BurningKnight/entity/component/ZComponent.cs ================================================ using System; using BurningKnight.entity.buff; using Lens.entity.component; using Lens.util.math; namespace BurningKnight.entity.component { public class ZComponent : Component { public float Z; public float ZVelocity; public bool Float; public float Gravity = 1; private float t; public override void Init() { base.Init(); t = Rnd.Float(5f); } public override void Update(float dt) { base.Update(dt); if (Float) { t += dt; Z = 2.5f + (float) Math.Sin(t * 5f) * 1.5f; return; } Z += ZVelocity * dt * 20 * (Entity.TryGetComponent(out var buffs) && buffs.Has() ? 0.5f : 1f); ZVelocity -= dt * 10 * Gravity; if (Z <= 0) { Z = 0; ZVelocity = 0; } } } } ================================================ FILE: BurningKnight/entity/component/ZSliceComponent.cs ================================================ using System; using Lens.assets; using Lens.entity.component.graphics; using Lens.graphics; using Lens.graphics.animation; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.component { public class ZSliceComponent : GraphicsComponent { public TextureRegion Sprite; public Vector2 Scale = Vector2.One; public Vector2 Origin; public ZSliceComponent(TextureRegion region) { Sprite = region; } public ZSliceComponent(string image, string slice) { Sprite = Animations.Get(image).GetSlice(slice); } public ZSliceComponent(AnimationData image, string slice) { Sprite = image.GetSlice(slice); } public override void Render(bool shadow) { if (shadow) { Graphics.Render(Sprite, Entity.Position + new Vector2(0, Sprite.Height), 0, Origin, Scale, Graphics.ParseEffect(Flipped, !FlippedVerticaly)); return; } Graphics.Render(Sprite, Entity.Position - new Vector2(0, Entity.GetComponent().Z), 0, Origin, Scale, Graphics.ParseEffect(Flipped, FlippedVerticaly)); } public void Animate(Action callback = null) { Tween.To(1.8f, Scale.X, x => Scale.X = x, 0.1f); Tween.To(0.2f, Scale.Y, x => Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, Scale.X, x => Scale.X = x, 0.4f); Tween.To(1, Scale.Y, x => Scale.Y = x, 0.4f); callback?.Invoke(); }; } } } ================================================ FILE: BurningKnight/entity/creature/Creature.cs ================================================ using System; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.entity.bomb; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.npc.dungeon; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.entity.item; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.physics; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using BurningKnight.util; using Lens; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature { public class Creature : SaveableEntity, CollisionFilterEntity, PlaceableEntity { public bool Flying; public override void AddComponents() { base.AddComponents(); AddComponent(new BuffsComponent()); AddComponent(new HealthComponent { RenderInvt = true, AutoKill = false }); AddComponent(new StateComponent()); AddComponent(new RoomComponent()); AddComponent(new ExplodableComponent()); AddComponent(new DropsComponent()); AddComponent(new TileInteractionComponent()); AddComponent(new SupportableComponent()); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new AudioEmitterComponent()); AddDrops(new SingleDrop("bk:heart", /*0.0015f*/ 0.0001f)); AddDrops(new SingleDrop("bk:half_heart", /*0.003f*/ 0.0002f)); AddDrops(new SingleDrop("bk:shield", 0.001f)); AddDrops(new SingleDrop("bk:bomb", 0.01f)); AddDrops(new SingleDrop("bk:key", 0.01f)); } protected virtual void Become() { GetComponent().Become(); } public virtual void Kill(Entity w, DamageType type = DamageType.Regular) { GetComponent().Kill(w, type); } public override bool HandleEvent(Event e) { if (e is PostHealthModifiedEvent ev && ev.Amount < 0) { if (HasNoHealth(ev)) { Kill(ev.From, ev.Type); } else if (!ev.PressedForBomb) { GetComponent().EmitRandomized(GetHurtSfx()); } if (ev.From != null && !ev.Handled && !ev.PressedForBomb) { var b = GetAnyComponent(); if (b != null && ev.Amount < 0) { b.KnockbackFrom(ev.From); if (Settings.Blood && !Settings.LowQuality) { for (var i = 0; i < 8; i++) { var p = Particles.Wrap(new Particle(Controllers.Blood, Particles.BloodRenderer), Area, Center + Rnd.Vector(-4, 4)); var a = ev.From.AngleTo(this); p.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.5f, 0.5f), Rnd.Float(80, 120)); p.Particle.Velocity.Y -= 8f; p.Particle.Velocity += b.Velocity * 0.5f; } } } } } else if (e is DiedEvent d) { if (!e.Handled) { try { if (HandleDeath(d)) { return true; } } catch (Exception ex) { Log.Error(ex); } } } else if (e is LostSupportEvent) { if (!(this is Player)) { Done = true; return true; } } else if (e is TileCollisionStartEvent tce) { if (tce.Tile == Tile.Lava) { if (GetComponent().ModifyHealth(-1, Run.Level)) { // GetComponent().Add(BurningBuff.Id); var set = false; var center = Center; var count = 0; GetComponent().ApplyForAllTouching((i, x, y) => { if (Run.Level.Get(x, y, true) == Tile.Lava) { var v = new Vector2(x * 16, y * 16); count++; if (!set) { set = true; center = v; } else { center += v; } } }); GetAnyComponent()?.KnockbackFrom(center / count, 1.5f); } } } return base.HandleEvent(e); } protected virtual bool HandleDeath(DiedEvent d) { AnimateDeath(d); if (d.From is Creature c) { d.From.HandleEvent(new KilledEvent { Who = this, KilledBy = c }); } return false; } public virtual void AnimateDeath(DiedEvent d) { AudioEmitterComponent.Dummy(Area, Center).EmitRandomized(GetDeadSfx(), sz: 0.2f); if (!GetComponent().HasNoSupport) { GetComponent().SpawnDrops(); } Done = true; for (var i = 0; i < 5; i++) { var part = new ParticleEntity(Particles.Ash()); part.Position = Center; part.Particle.Scale = Rnd.Float(1.5f, 2f); part.Particle.Velocity = new Vector2(Rnd.Float(20, 30) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(40, 66)); Run.Level.Area.Add(part); part.Depth = 1; } if (Settings.Blood) { for (var i = 0; i < Rnd.Int(2, 8); i++) { Area.Add(new SplashParticle { Position = Center - new Vector2(2.5f), Color = GetBloodColor() }); } } } protected virtual TextureRegion GetDeathFrame() { return GetAnyComponent()?.Animation.GetFrame("dead", 0); } protected virtual void CreateGore(DiedEvent d) { Engine.Instance.Freeze = 0.5f; Camera.Instance.ShakeMax(5); if (!Settings.Blood) { return; } var gore = new Gore(); var r = GetDeathFrame(); if (r == null) { Log.Error($"Failed to find dead frame for {GetType().Name}"); return; } Area.Add(gore); gore.Position = Position; gore.AddComponent(new ZSliceComponent(r)); gore.Width = r.Width; gore.Height = r.Height; var b = new RectBodyComponent(0, 0, gore.Width, gore.Height); gore.AddComponent(b); b.Body.LinearDamping = 2f; b.Body.Restitution = 1; b.Body.Friction = 0; if (d != null) { var v = MathUtils.CreateVector(d.From is Player ? AngleTo(d.From) - Math.PI : Rnd.AnglePI(), 64); b.Body.LinearVelocity = v; if (v.X > 0) { gore.GetComponent().Flipped = true; } } } protected void AddDrops(params Drop[] drops) { GetComponent().Add(drops); } public virtual bool HasNoHealth(HealthModifiedEvent e = null) { return GetComponent().HasNoHealth || Math.Abs(GetComponent().Health - (-e?.Amount ?? 0)) < 0.01f; } public virtual bool HasNoHealth(PostHealthModifiedEvent e = null) { return GetComponent().HasNoHealth; } public virtual bool InAir() { return Flying; } public virtual bool IgnoresProjectiles() { return false; } public virtual bool ShouldCollideWithDestroyableInAir() { return false; } public virtual bool ShouldCollide(Entity entity) { return !((entity is Creature && !(entity is DungeonShopNpc || entity is Mimic)) || (InAir() && (entity is Chasm || entity is Item || entity is Bomb || (!ShouldCollideWithDestroyableInAir() && entity is HalfWall)))); } public virtual bool IsFriendly() { return true; } protected virtual void RenderShadow() { GraphicsComponent?.Render(true); } protected virtual Color GetBloodColor() { return Color.Red; } protected virtual string GetHurtSfx() { return $"hurt{Rnd.Int(1, 3)}"; } protected virtual string GetDeadSfx() { return $"dead{Rnd.Int(1, 4)}"; } } } ================================================ FILE: BurningKnight/entity/creature/Decoy.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; namespace BurningKnight.entity.creature { public class Decoy : Creature { public Action OnDeath; public override void AddComponents() { base.AddComponents(); Width = 11; Height = 10; AddTag(Tags.PlayerTarget); RemoveTag(Tags.LevelSave); AddComponent(new SensorBodyComponent(0, 0, 11, 10)); AddComponent(new RectBodyComponent(0, 9, 11, 1)); GetComponent().KnockbackModifier = 0.1f; AddComponent(new SliceComponent("items", "bk:decoy")); AddComponent(new ShadowComponent()); var h = GetComponent(); h.InitMaxHealth = 6; h.RenderInvt = true; GetComponent().Drops.Clear(); } private float t; public override void Update(float dt) { base.Update(dt); var r = GetComponent().Room; if (r != null && r.Tagged[Tags.MustBeKilled].Count == 0) { Kill(this); return; } t += dt; if (t >= 20f) { Kill(this); } } public override void AnimateDeath(DiedEvent d) { base.AnimateDeath(d); ExplosionMaker.Make(this); OnDeath?.Invoke(); } } } ================================================ FILE: BurningKnight/entity/creature/Gore.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.level; using BurningKnight.physics; using Lens.entity; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature { public class Gore : Entity, CollisionFilterEntity { public bool ShouldCollide(Entity entity) { return entity is Level || entity is Chasm || entity is Door; } private float vz; private float t; private float a = 1; public override void AddComponents() { base.AddComponents(); AddComponent(new ZComponent()); AddComponent(new ShadowComponent(RenderShadow)); vz = 1; AlwaysActive = true; } public override void Render() { Graphics.Color = new Color(0.5f, 0.5f, 0.5f, a); base.Render(); Graphics.Color = ColorUtils.WhiteColor; } private void RenderShadow() { Graphics.Color.A = (byte) (a * 255f); GraphicsComponent.Render(true); Graphics.Color.A = 255; } private bool did; private bool zdid; public override void Update(float dt) { base.Update(dt); t += dt; if (t >= 20f) { a -= dt * 0.5f; if (a <= 0) { Done = true; } } if (!Settings.Blood) { Done = true; } if (!zdid) { var z = GetComponent(); vz -= dt * 4; z.Z = Math.Max(z.Z + vz, 0); if (z.Z <= 0) { zdid = true; if (TryGetComponent(out var bd)) { bd.Body.LinearVelocity *= 0.5f; } } } if (did) { return; } var b = GetComponent().Body; if (b.LinearVelocity.Length() < 4) { b.LinearVelocity = Vector2.Zero; RemoveComponent(); did = true; } else { Position += b.LinearVelocity * (dt * 1.5f); } } } } ================================================ FILE: BurningKnight/entity/creature/SmartState.cs ================================================ using Lens.entity; using Lens.entity.component.logic; namespace BurningKnight.entity.creature { public class SmartState : EntityState where T: Entity { public new T Self; public override void Assign(Entity self) { base.Assign(self); Self = (T) self; } } } ================================================ FILE: BurningKnight/entity/creature/bk/BkGraphicsComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using Lens.graphics; using Lens.graphics.animation; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.bk { public class BkGraphicsComponent : AnimationComponent { private float t; public float Alpha = 1f; public BkGraphicsComponent(string animationName, string layer = null, string tag = null) : base(animationName, layer, tag) { } public override void Update(float dt) { base.Update(dt); t += dt; } public override void Render(bool shadow) { var pos = Entity.Position + Offset; if (shadow) { FlippedVerticaly = !FlippedVerticaly; pos.Y += Animation.GetCurrentTexture().Height - ShadowOffset * 2 + 4; Graphics.Color.A = (byte) (Alpha * 255); } else { var shader = Shaders.Bk; var region = Animation.GetCurrentTexture(); shader.Parameters["pos"].SetValue(new Vector2(region.Source.X / (float) region.Texture.Width, region.Source.Y / (float) region.Texture.Height)); shader.Parameters["size"].SetValue(new Vector2(region.Width / (float) region.Texture.Width, region.Height / (float) region.Texture.Height)); shader.Parameters["time"].SetValue(t); shader.Parameters["a"].SetValue(Alpha); Shaders.Begin(shader); } CallRender(pos, shadow); if (shadow) { Graphics.Color.A = 255; FlippedVerticaly = !FlippedVerticaly; } else { Shaders.End(); } } } } ================================================ FILE: BurningKnight/entity/creature/bk/BkOrbital.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.desert; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.level; using Lens.entity; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.bk { public class BkOrbital : Mob { protected const float DefaultZ = 2; public int Id; protected override void SetStats() { base.SetStats(); SetMaxHp(50); RemoveTag(Tags.LevelSave); Width = 12; Height = 13; TouchDamage = 2; var body = new SensorBodyComponent(1, 2, 10, 10); AddComponent(body); body.Body.LinearDamping = 4; AddComponent(new ZAnimationComponent("bk_orbital")); AddComponent(new ZComponent()); AddComponent(new OrbitalComponent()); AddComponent(new OrbitalComponent { Radius = 24, Lerp = true }); Depth = Layers.Wall; Become(); } public override bool InAir() { return true; } private void Fire() { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); var an = AngleTo(Target); var builder = new ProjectileBuilder(this, "big") { Scale = 0.8f, LightRadius = 32f, Color = ProjectileColor.Orange, Damage = 2 }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); builder.Shoot(an, 8f); var projectile = builder.Build(); projectile.Center = Center + MathUtils.CreateVector(an, 4f); ProjectileCallbacks.AttachUpdateCallback(projectile, TargetProjectileController.Make(Target, 0.2f)); }; }; } #region Fly States public class OrbitingState : SmartState { public override void Init() { base.Init(); T = Self.Id * 1f; var component = Self.GetComponent(); Tween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); if (T >= 10f) { T = 0; Self.Fire(); } var o = Self.GetComponent().Orbiting; if (o == null || o.Done) { Self.Kill(Self); } } } #endregion public override bool ShouldCollide(Entity entity) { return !(entity is Level) && base.ShouldCollide(entity); } protected override string GetDeadSfx() { return "mob_fly_death"; } } } ================================================ FILE: BurningKnight/entity/creature/bk/BurningKnight.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.lighting; using BurningKnight.assets.particle.custom; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.entity.cutscene.entity; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.entity.projectile.pattern; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui; using BurningKnight.ui.dialog; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using VelcroPhysics.Dynamics; using Color = Microsoft.Xna.Framework.Color; using Vector2 = Microsoft.Xna.Framework.Vector2; namespace BurningKnight.entity.creature.bk { public class BurningKnight : Boss { private static Color tint = new Color(234, 50, 60, 200); private Boss captured; private bool raging; private int timesRaged; public bool Passive; public bool Hidden => GetComponent().StateInstance is HiddenState; public override void AddComponents() { base.AddComponents(); AddTag(Tags.BurningKnight); AddTag(Tags.PlayerSave); RemoveTag(Tags.Boss); RemoveTag(Tags.Mob); RemoveTag(Tags.LevelSave); RemoveTag(Tags.MustBeKilled); Width = 22; Height = 27; Flying = true; TargetEverywhere = true; AlwaysActive = true; AlwaysVisible = true; HasHealthbar = false; Depth = Layers.Bk; TouchDamage = 0; var b = new RectBodyComponent(6, 8, 10, 15, BodyType.Dynamic, true) { KnockbackModifier = 0 }; AddComponent(b); b.Body.LinearDamping = 3; AddComponent(new BkGraphicsComponent("old_burning_knight")); var health = GetComponent(); health.Unhittable = true; SetMaxHp(300); // health.AutoKill = false; GetComponent().Become(); AddComponent(new OrbitGiverComponent()); AddComponent(new LightComponent(this, 64, new Color(1f, 0.2f, 0.1f, 0.5f))); var buffs = GetComponent(); buffs.AddImmunity(); buffs.AddImmunity(); buffs.AddImmunity(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); GetComponent().Dialog.Voice = 25; AddComponent(new AimComponent(AimComponent.AimType.Target)); } public override void PostInit() { base.PostInit(); Timer.Add(() => { GetComponent().Emit("mob_bk_hovering_loop", 0.3f, looped: true, tween: true); GetComponent().Emit(Run.Depth == 10 ? "mob_bk_fight_loop" : "mob_bk_flame_loop", 0.3f, looped: true, tween: true); }, 2f); } public override void Destroy() { base.Destroy(); GetComponent().StopAll(); } protected override void OnTargetChange(Entity target) { if (Hidden) { return; } if (!Awoken && target != null) { Awoken = true; Become(); } else if (target == null) { Become(); Awoken = false; } base.OnTargetChange(target); } private void FreeSelf() { if (!Hidden) { return; } var graphics = GetComponent(); graphics.Alpha = 0; Center = captured.Center; GetComponent().Unhittable = true; Tween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f).OnEnd = () => { GetComponent().Emit("mob_bk_roar_4", 0.8f); Timer.Add(() => { if (captured.Done) { Become(); // YOU CAN'T DEFEAT THE BURNING KNIGHT!!! GetComponent().StartAndClose("bk_2", 5); } else { captured = null; Become(); CheckForScourgeRage(); } }, 1f); }; } public override bool HandleEvent(Event e) { if (e is DefeatedEvent bde) { if (bde.Boss == captured) { FreeSelf(); } if (bde.Boss == this) { return base.HandleEvent(e); } return false; } if (Hidden) { return base.HandleEvent(e); } if (e is RoomChangedEvent rce) { if (!InFight) { var p = rce.Who is Player; var bs = rce.Who is BurningKnight; if ((p || bs) && rce.New != null) { var t = rce.New.Type; if (t == RoomType.Boss) { CheckCapture(); } else if (p) { if (t == RoomType.Treasure) { foreach (var item in rce.New.Tagged[Tags.Item]) { if (item is SingleChoiceStand stand && stand.Item != null) { GetComponent().StartAndClose("bk_0", 5); break; } } } else if (t == RoomType.Granny) { // GRANNY, CAN YOU JUST DIE, PLEASE?? GetComponent().StartAndClose("bk_9", 3); } else if (t == RoomType.OldMan) { // MY MASTER, I BROUGHT THE GOBLIN GetComponent().StartAndClose("bk_10", 5); } } } } } else if (e is ItemTakenEvent ite) { if (!InFight && ite.Stand is SingleChoiceStand && ite.Who is Player) { GetComponent().StartAndClose("bk_1", 5); var state = GetComponent(); if (!(state.StateInstance is HiddenState)) { Timer.Add(() => { timesRaged++; GetComponent().Emit("mob_bk_roar_1", 0.8f); state.Become(); }, 3); } } } else if (e is Dialog.EndedEvent dse) { if (!InFight && dse.Owner is ShopKeeper && dse.Dialog.Id == "shopkeeper_18") { // What a joke Timer.Add(() => { GetComponent().StartAndClose("bk_4", 5); }, 1); } } else if (e is ShopNpc.SavedEvent) { // I WOULDN'T BOTHER EVEN TALKING TO THEM Timer.Add(() => { GetComponent().StartAndClose("bk_5", 5); }, 2f); } else if (e is ShopKeeper.EnragedEvent skee) { if (skee.ShopKeeper.GetComponent().Room.Explored) { // KILL HIM, EDWARD! GetComponent().StartAndClose("bk_6", 5); } } else if (e is DiedEvent de) { if (de.Who is ShopKeeper) { // EDWARD, NOOOOOO! GetComponent().StartAndClose("bk_7", 5); return false; } else if (de.Who == this) { died = true; return base.HandleEvent(e); } else { return false; } } else if (e is SecretRoomFoundEvent) { // OH COMON, STOP EXPLODING MY CASTLE! GetComponent().StartAndClose("bk_8", 5); } else if (e is NewLevelStartedEvent) { if (!InFight) { CheckForScourgeRage(); var state = GetComponent().StateInstance; if (raging && !(state is AttackState || state is ChaseState || state is FlyAwayAttackingState)) { raging = false; sayNoRage = true; } } } return base.HandleEvent(e); } private bool died; private bool sayNoRage; public override void Load(FileReader stream) { base.Load(stream); raging = stream.ReadBoolean(); timesRaged = stream.ReadInt32(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(raging); stream.WriteInt32(timesRaged); } private float lastFadingParticle; public override void Update(float dt) { base.Update(dt); if (!Placed) { Done = false; } if (Hidden) { return; } if (lasers.Count > 0) { spinV += dt; foreach (var l in lasers) { if (l.Done) { lasers.Clear(); break; } l.Angle += spinV * dt * 0.2f * spinDir; } } lastFadingParticle -= dt; if (lastFadingParticle <= 0 && !(GetComponent().StateInstance is FlameAttack)) { lastFadingParticle = 0.2f; var particle = new FadingParticle(GetComponent().Animation.GetCurrentTexture(), tint); Area.Add(particle); particle.Depth = Depth - 1; particle.Center = Center; var room = GetComponent().Room; if (room != null && room.Type == RoomType.Boss) { CheckCapture(); } else if (Target != null) { room = Target.GetComponent().Room; if (room != null && room.Type == RoomType.Boss) { CheckCapture(); } } } } public bool ForcedRage; public void CheckForScourgeRage() { if (InFight) { return; } var s = GetComponent().StateInstance; if (s is ChaseState || s is AttackState || s is HiddenState) { return; } if (ForcedRage || Run.Scourge >= 10) { Become(); } } private void CheckForScourgeRageFree() { if (InFight) { return; } if (Target == null) { Become(); } var s = GetComponent().StateInstance; if (s is IdleState || s is ChaseState || s is FollowState || s is HiddenState || s is FlyAwayAttackingState || s is AttackState) { return; } if (!ForcedRage && Run.Scourge < 10) { Become(); } } #region Buring Knight States while calm public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { Self.CheckForScourgeRage(); } } } public class FollowState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Become(); return; } Self.CheckForScourgeRage(); var d = Self.DistanceTo(Self.Target); var force = 200f * dt; if (d < 48f) { Self.Become(); } else if (d <= 72f) { return; } else if (d >= 300) { Self.Become(); } var room = Self.Target.GetComponent().Room; if (Self.OnScreen && room != null && room.Type == RoomType.Regular && room.Tagged[Tags.MustBeKilled].Count > 0 && room.Contains(Self, 16f)) { var aa = Self.AngleTo(room); force = 400f * dt; Self.GetComponent().Velocity -= new Vector2((float) Math.Cos(aa) * force, (float) Math.Sin(aa) * force); return; } var a = Self.AngleTo(Self.Target); Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } public class FlyAwayState : SmartState { public override void Update(float dt) { base.Update(dt); Self.CheckForScourgeRage(); var d = Self.DistanceTo(Self.Target); var force = -300f * dt; if (d > 80f) { Self.Become(); return; } var a = Self.AngleTo(Self.Target); Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } private void CheckCapture() { if (InFight) { return; } var room = Target?.GetComponent()?.Room; if (room != null && room.Type == RoomType.Boss) { foreach (var p in room.Tagged[Tags.Player]) { if (!((Player) p).Teleported) { return; } } if (Run.Level.Biome is LibraryBiome) { BeginFight(); return; } foreach (var mob in room.Tagged[Tags.Boss]) { if (mob != this && mob is Boss b && !(b is bk.BurningKnight)) { captured = b; Become(); break; } } } } public class CutsceneState : SmartState { public override void Init() { base.Init(); var bkDialog = Self.GetComponent(); var playerDialog = Self.Target.GetComponent(); Start(bkDialog, "bkw_0", Self.Target, () => { Start(bkDialog, "bkw_1", Self.Target, () => { bkDialog.Close(); Start(playerDialog, "bkw_2", Self.Target, () => { playerDialog.Close(); Start(bkDialog, "bkw_3", Self.Target, () => { Become(); bkDialog.OnEnd(); GlobalSave.Put("bk_who", true); Self.Target.GetComponent().Unhittable = false; }); }); }); }); } private void Start(DialogComponent d, string id, Entity to, Action callback = null) { d.Start(id, to); if (callback != null) { d.Dialog.ShowArrow = true; d.Dialog.OnEnd = () => { Timer.Add(callback, 0.1f); return true; }; } } } public class TeleportState : SmartState { private bool did; public override void Update(float dt) { base.Update(dt); if (did) { return; } did = true; Self.GetComponent().Close(); var graphics = Self.GetComponent(); Tween.To(0, graphics.Alpha, x => graphics.Alpha = x, 0.3f, Ease.QuadIn).OnEnd = () => { if (Self.Target != null) { Self.Center = Self.Target.Center + MathUtils.CreateVector(Rnd.AnglePI(), 64f); } Tween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f).OnEnd = () => { if (Run.Depth == 1 && GlobalSave.IsFalse("bk_who")) { Self.Become(); return; } if (Self.sayNoRage) { Self.sayNoRage = false; Self.GetComponent().StartAndClose("bk_11", 5); } if (Self.Target != null) { Self.Become(); } else { Self.Become(); } }; }; } public override void Destroy() { base.Destroy(); Self.CheckCapture(); } } #endregion #region Burning Knight States while chasing public class FlyAwayAttackingState : SmartState { public override void Init() { base.Init(); Self.raging = true; } public override void Update(float dt) { base.Update(dt); Self.CheckForScourgeRageFree(); var d = Self.DistanceTo(Self.Target); var force = -300f * dt; if (d > 96f) { Self.Become(); return; } var a = Self.AngleTo(Self.Target); Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } public class ChaseState : SmartState { public override void Init() { base.Init(); Self.raging = true; } public override void Update(float dt) { base.Update(dt); Self.CheckForScourgeRageFree(); var d = Self.DistanceTo(Self.Target); var force = 300f * dt; if (d < 64f) { Self.Become(); } else if (d <= 128f) { var r = Self.Target.GetComponent().Room; if (r.Type == RoomType.Shop || r.Type == RoomType.SubShop || r.Type == RoomType.OldMan) { } else { Self.Become(); } } var room = Self.Target.GetComponent().Room; if (Self.OnScreen && room != null && room.Type == RoomType.Regular && room.Tagged[Tags.MustBeKilled].Count > 0 && room.Contains(Self, 16f)) { var aa = Self.AngleTo(room); force = 400f * dt; Self.GetComponent().Velocity -= new Vector2((float) Math.Cos(aa) * force, (float) Math.Sin(aa) * force); return; } var a = Self.AngleTo(Self.Target); Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } public class AttackState : SmartState { private int count; public override void Init() { base.Init(); Self.raging = true; count = Math.Min(1, Self.timesRaged); } public override void Update(float dt) { base.Update(dt); Self.CheckForScourgeRageFree(); if (Self.DistanceTo(Self.Target) < 64f) { Self.Become(); return; } var r = Self.Target.GetComponent().Room; if (r.Type == RoomType.Shop || r.Type == RoomType.SubShop || r.Type == RoomType.OldMan) { Self.Become(); return; } if (T >= 1f) { Self.GetComponent().Emit("mob_bk_fire"); var c = 1; if (Self.timesRaged > 2 && Self.timesRaged < 5) { c = 3; } var builder = new ProjectileBuilder(Self, "circle") { Scale = Rnd.Float(1f, 1f + Self.timesRaged * 0.1f), Color = ProjectileColor.BkRed, LightRadius = 32f }; builder.AddFlags(ProjectileFlags.FlyOverWalls); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < c; i++) { var p = builder.Shoot(Self.AngleTo(Self.Target) + Rnd.Float(-0.4f, 0.4f) + (c == 1 ? 0 : (i - 1) * Math.PI * 0.2f), 8 + Self.timesRaged * 0.3f).Build(); p.Center = Self.Center; p.Depth = Self.Depth; if (Self.timesRaged > 4) { ProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.Make(Self.Target, 0.5f)); p.T = 5f + Rnd.Float(1f); } } count--; T -= 0.25f + (Self.timesRaged - 1) * 0.1f; if (count <= 0) { Become(); } } } } #endregion public class CaptureState : SmartState { public override void Init() { base.Init(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(Self, 0.3f); Timer.Add(() => { Camera.Instance.Follow(Self.captured, 0.3f); }, 0.5f); } public override void Update(float dt) { base.Update(dt); var d = Self.DistanceTo(Self.captured); if (d <= 8) { Audio.PlayMusic("Fatiga", true); // PREPARE TO DIE! Self.captured.GetComponent().StartAndClose(Self.captured.GetScream(), 5); Self.captured.GetComponent().EmitRandomized("mob_bk_capture"); Camera.Instance.Unfollow(Self); Become(); Self.captured.SelectAttack(); } else if (d >= 400f && Self.GetComponent().Room != Self.captured.GetComponent().Room) { Become(); return; } var a = Self.AngleTo(Self.captured); var force = 500f * dt; if (d <= 64f) { force *= 2; } Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } public class HiddenState : SmartState { private bool teleported; public override void Init() { base.Init(); Camera.Instance.Shake(20); Self.Position = Vector2.Zero; Timer.Add(() => { ((InGameState) Engine.Instance.State).ResetFollowing(); Camera.Instance.Shake(10); }, 1); } public override void Update(float dt) { base.Update(dt); if (!teleported && (Self.captured.Done || Self.captured.GetComponent().StateInstance is FriendlyState)) { teleported = true; Self.FreeSelf(); } } } public override void RenderImDebug() { base.RenderImDebug(); if (ImGui.Checkbox("Raging", ref raging)) { if (raging) { Become(); } else { Become(); } } ImGui.InputInt("Times Raged", ref timesRaged); } public override void PlaceRewards() { var head = new BkHead(); Area.Add(head); head.Center = Center; Audio.PlayMusic("Last chance"); } protected override void CreateGore(DiedEvent d) { } public bool InFight; private void AddOrbitals(int count) { for (var i = 0; i < count; i++) { var orbital = new BkOrbital { Id = i }; Area.Add(orbital); orbital.Center = Center; GetComponent().AddOrbiter(orbital); } } private void BeginFight() { if (InFight || Passive) { return; } var r = GetComponent().Room; if (r == null) { return; } GetComponent().StartAndClose("bk_12", 3); AddOrbitals(6); InFight = true; HasHealthbar = true; if (HealthBar == null) { HealthBar = new HealthBar(this); Engine.Instance.State.Ui.Add(HealthBar); AddPhases(); } AddTag(Tags.Boss); AddTag(Tags.Mob); AddTag(Tags.MustBeKilled); var a = r.Tagged[Tags.MustBeKilled]; if (!a.Contains(this)) { a.Add(this); } a = r.Tagged[Tags.Mob]; if (!a.Contains(this)) { a.Add(this); } a = r.Tagged[Tags.Boss]; if (!a.Contains(this)) { a.Add(this); } Become(); GetComponent().Unhittable = false; TouchDamage = 2; Center = Target.GetComponent().Room.Center; } protected override void Become() { if (!Passive || typeof(T) == typeof(IdleState)) { base.Become(); } } protected override void AddPhases() { HealthBar.AddPhase(0.5f); } /* * The actual boss battle */ private int count; public class FightState : SmartState { public override void Update(float dt) { base.Update(dt); if (T >= 1f) { switch (Self.count) { case 0: { Become(); break; } case 1: { Become(); break; } case 2: { Become(); break; } case 3: { Become(); break; } case 4: { Become(); break; } case 5: { Become(); break; } case 6: { Become(); break; } } Self.count = (Self.count + 1) % (Self.Raging ? 7 : 6); } } } public bool Raging => GetComponent().Percent <= 0.5f; public class LaserSwingAttack : SmartState { private Laser laser; private float vy; private float angle; public override void Init() { base.Init(); angle = Self.AngleTo(Self.Target) - (Rnd.Chance() ? -1 : 1) * 1.2f; Self.WarnLaser(angle); } public override void Update(float dt) { base.Update(dt); if (laser == null) { if (T < 1f) { return; } if (Self.Raging) { Self.StartLasers(); } laser = Laser.Make(Self, 0, 0, damage: 2, scale: 3, range: 64); laser.LifeTime = 10f; laser.Position = Self.Center; laser.Angle = angle; Self.GetComponent().EmitRandomizedPrefixed("item_laser", 4); } if (laser.Done) { Become(); return; } laser.Position = Self.Center; var aa = laser.Angle; var a = Self.AngleTo(Self.Target); vy += (float) MathUtils.ShortAngleDistance(aa, a) * dt * 4; laser.Angle += vy * dt * 0.5f; } } private List lasers = new List(); private float spinV; private int spinDir; private void WarnLaser(float angle, Vector2? offset = null) { var builder = new ProjectileBuilder(this, Raging ? "big" : "circle") { LightRadius = 32f, Color = ProjectileColor.Red }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); for (var i = 0; i < 3; i++) { Timer.Add(() => { var projectile = builder.Shoot(angle, Raging ? 15f : 10f).Build(); projectile.Center += MathUtils.CreateVector(angle, 8); if (offset != null) { projectile.Center += offset.Value; } }, i * 0.3f); } } private void StartLasers() { lasers.Clear(); spinV = 0; spinDir = Rnd.Chance() ? 1 : -1; Timer.Add(() => { GetComponent().EmitRandomizedPrefixed("item_laser", 4); }, 1f); for (var i = 0; i < 4; i++) { var angle = AngleTo(Target) + (i / 4f + 1 / 8f) * (float) Math.PI * 2f; WarnLaser(angle); Timer.Add(() => { var laser = Laser.Make(this, 0, 0, damage: 2, scale: 3, range: 64); laser.LifeTime = 10f; laser.Position = Center; laser.Angle = angle; lasers.Add(laser); }, 1f); } } public class LaserRotateAttack : SmartState { public override void Init() { base.Init(); Self.StartLasers(); } public override void Update(float dt) { base.Update(dt); if (T >= 3f && Self.lasers.Count == 0) { Become(); } } } public class SkullAttack : SmartState { private int count; private bool explode; public override void Init() { base.Init(); explode = Rnd.Chance(); } public override void Update(float dt) { base.Update(dt); if ((count + 1) * (Self.Raging ? 0.7f : 1f) <= T) { count++; if (Self.Target == null || Self.Died) { return; } var a = Self.GetComponent(); Self.GetComponent().EmitRandomized("mob_oldking_shoot"); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f); if (Self.Target == null || Self.Died) { return; } var builder = new ProjectileBuilder(Self, explode ? "skull" : "skup") { Range = 5 }.Shoot(Rnd.AnglePI(), explode ? Rnd.Float(5, 12) : 14); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); var skull = builder.Build(); ProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(Self.Target, 0.5f)); if (explode) { /*skull.NearDeath += p => { var c = new AudioEmitterComponent { DestroySounds = false }; p.AddComponent(c); c.Emit("mob_oldking_explode"); };*/ ProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => { if (!t) { return; } var b = new ProjectileBuilder(Self, "small"); b.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < 16; i++) { var bullet = b.Shoot(((float) i) / 8 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build(); bullet.Center = p.Center; } }); } skull.GetComponent().IgnoreRotation = true; if (count == (Self.Raging ? 6 : 4)) { Self.Become(); } }; } } } private static string[] swordData = { " x ", "xxxxxxx", " x ", }; public class SwordAttackState : SmartState { public override void Init() { base.Init(); Timer.Add(() => { Self.GetComponent().EmitRandomized("mob_fire_static"); var a = Self.AngleTo(Self.Target); var p = new ProjectilePattern(KeepShapePattern.Make(0)) { Position = Self.Center }; Self.Area.Add(p); ProjectileTemplate.MakeFast(Self, "small", Self.Center, a, (pr) => { pr.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); p.Add(pr); pr.Color = ProjectileColor.Red; }, swordData, () => { Timer.Add(() => { p.Launch(a, 30); Self.GetComponent().EmitRandomized("mob_fire_static"); Become(); }, 0.2f); }); }, 1f); } } public class LaserCageAttack : SmartState { private Laser[] lasers = new Laser[8]; private Vector2 spot; private const float boxHalfSize = 32; private static Vector2[] laserOffsets = { new Vector2(-boxHalfSize, 0), new Vector2(-boxHalfSize, 0), new Vector2(boxHalfSize, 0), new Vector2(boxHalfSize, 0), new Vector2(0, -boxHalfSize), new Vector2(0, -boxHalfSize), new Vector2(0, boxHalfSize), new Vector2(0, boxHalfSize), }; private static double[] laserAngles = { Math.PI * 0.5f, Math.PI * 1.5f, Math.PI * 0.5f, Math.PI * 1.5f, Math.PI, 0, Math.PI, 0 }; public override void Init() { base.Init(); spot = Self.Center; for (var i = 0; i < 8; i++) { Self.WarnLaser((float) laserAngles[i], laserOffsets[i]); } Timer.Add(() => { Self.GetComponent().EmitRandomizedPrefixed("item_laser", 4); for (var i = 0; i < 8; i++) { var laser = Laser.Make(Self, 0, (float) laserAngles[i], damage: 2, scale: 3, range: 64); laser.LifeTime = 10f; laser.Position = spot + laserOffsets[i]; lasers[i] = laser; } }, 1); } public override void Update(float dt) { base.Update(dt); if (T < 1f) { return; } spot = spot.Lerp(Self.Target.Center, dt * 0.5f); for (var i = 0; i < 8; i++) { var laser = lasers[i]; if (laser == null) { continue; } if (laser.Done) { foreach (var l in lasers) { if (l != null) { l.Done = true; } } Become(); return; } laser.Position = spot + laserOffsets[i]; } } } public class FlameAttack : SmartState { private float r; private List last = new List(); public override void Init() { base.Init(); var graphics = Self.GetComponent(); Self.GetComponent().Unhittable = true; Tween.To(0, graphics.Alpha, x => graphics.Alpha = x, 0.3f); Self.TouchDamage = 0; } public override void Destroy() { base.Destroy(); var graphics = Self.GetComponent(); Self.GetComponent().Unhittable = false; Self.TouchDamage = 2; Tween.To(1, graphics.Alpha, x => graphics.Alpha = x, 0.3f); foreach (var l in last) { Run.Level.SetFlag(l, Flag.Burning, false); } } public override void Update(float dt) { base.Update(dt); if (T >= 10f) { Become(); return; } r = Math.Min(1.5f, r + dt * 60); var x = (int) Math.Floor(Self.CenterX / 16); var y = (int) Math.Floor(Self.CenterY / 16); for (var xx = (int) -r; xx <= r; xx++) { for (var yy = (int) -r; yy <= r; yy++) { if (Math.Sqrt(xx * xx + yy * yy) <= r) { var i = Run.Level.ToIndex(x + xx, y + yy); if (!Run.Level.CheckFlag(i, Flag.Burning)) { Run.Level.SetFlag(i, Flag.Burning, true); last.Add(i); Timer.Add(() => { last.Remove(i); Run.Level.SetFlag(i, Flag.Burning, false); }, Rnd.Float(1.5f, 2.5f)); } } } } var force = 250f * dt; var a = Self.AngleTo(Self.Target); Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } public class SpawnAttack : SmartState { private int count; private float delay; public override void Init() { base.Init(); count = Rnd.Int(4, 10); } public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { delay = 0.3f; Self.GetComponent().Animate(); var angle = Rnd.AnglePI() * 0.5f + count * (float) Math.PI; var builder = new ProjectileBuilder(Self, "big") { LightRadius = 32f, Color = ProjectileColor.Orange }.Shoot(angle, 15f); builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); var projectile = builder.Build(); projectile.Center += MathUtils.CreateVector(angle, 8); ProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => { var x = (int) Math.Floor(p.CenterX / 16); var y = (int) Math.Floor(p.CenterY / 16); var mob = new WallCrawler(); Self.Area.Add(mob); mob.X = x * 16; mob.Y = y * 16 - 8; mob.GeneratePrefix(); AnimationUtil.Poof(mob.Center, 1); }); count--; if (count <= 0) { Become(); } } } } } } ================================================ FILE: BurningKnight/entity/creature/bk/SpawnTrigger.cs ================================================ using System; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.level; using BurningKnight.level.entities.decor; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using Lens; using Lens.assets; using Lens.entity; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.bk { public class SpawnTrigger : SaveableEntity { public byte[] Tiles; public byte[] Liquid; public ushort RoomX; public ushort RoomY; public byte RoomWidth; public byte RoomHeight; public bool Triggered; public bool Interrupted; public bool ReadyToSpawn; private float t; private bool did; public override void Update(float dt) { base.Update(dt); if (!did && Triggered) { Camera.Instance.Shake(0.5f); t += dt; if (t >= 1f) { did = true; var r = (int) Math.Ceiling(Math.Sqrt((RoomWidth + 1) * (RoomWidth + 1) + (RoomHeight + 1) * (RoomHeight + 1))); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(this, 3f); Tween.To(0.5f, Camera.Instance.Zoom, x => Camera.Instance.Zoom = x, 0.3f); for (var j = 1; j < r; j++) { var level = Run.Level; var j1 = j; Timer.Add(() => { if (Interrupted) { level.CreateBody(); return; } for (var y = 0; y < RoomHeight; y++) { for (var x = 0; x < RoomWidth; x++) { var dx = x - RoomWidth / 2f; var dy = y - RoomHeight / 2f; if (Math.Sqrt(dx * dx + dy * dy) > j1) { continue; } var i = x + y * RoomWidth; if (Tiles[i] == 255) { continue; } var li = level.ToIndex(RoomX + x, RoomY + y); if (level.Get(li).IsWall()) { level.Variants[li] = 0; } // tmp Area.Add(new TileFx { X = (RoomX + x) * 16, Y = (RoomY + y) * 16 - 8 }); level.ReCreateBodyChunk(RoomX + x, RoomY + y); level.Tiles[li] = Tiles[i]; level.Liquid[li] = Liquid[i]; Tiles[i] = 255; // Mark as already checked; } } for (var y = -1; y < RoomHeight + 1; y++) { for (var x = -1; x < RoomWidth + 1; x++) { LevelTiler.TileUp(level, level.ToIndex(RoomX + x, RoomY + y)); } } Camera.Instance.Shake(2); }, j * 0.05f); } Timer.Add(() => { if (Interrupted) { return; } Tween.To(1f, Camera.Instance.Zoom, x => Camera.Instance.Zoom = x, 0.3f); Timer.Add(() => { if (Interrupted) { return; } Done = true; ReadyToSpawn = true; }, 1f); }, r * 0.05f + 1f); } } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte((byte) Width); stream.WriteByte((byte) Height); stream.WriteUInt16(RoomX); stream.WriteUInt16(RoomY); stream.WriteByte(RoomWidth); stream.WriteByte(RoomHeight); for (var i = 0; i < RoomWidth * RoomHeight; i++) { stream.WriteByte(Tiles[i]); stream.WriteByte(Liquid[i]); } } public override void Load(FileReader stream) { base.Load(stream); Width = stream.ReadByte(); Height = stream.ReadByte(); RoomX = stream.ReadUInt16(); RoomY = stream.ReadUInt16(); RoomWidth = stream.ReadByte(); RoomHeight = stream.ReadByte(); var s = RoomWidth * RoomHeight; Tiles = new byte[s]; Liquid = new byte[s]; for (var i = 0; i < s; i++) { Tiles[i] = stream.ReadByte(); Liquid[i] = stream.ReadByte(); } } public override void PostInit() { base.PostInit(); Subscribe(); AddComponent(new RoomComponent()); AddComponent(new RectBodyComponent(8, 8, Width - 16, Height - 16, BodyType.Static, true)); } public override bool HandleEvent(Event e) { if (e is BurningStatue.BrokenEvent) { Interrupted = true; Done = true; return base.HandleEvent(e); } if (Triggered) { return base.HandleEvent(e); } if (e is CollisionStartedEvent cse) { if (cse.Entity is Player p) { Timer.Add(() => { Triggered = true; }, 1f); var xx = (int) Math.Floor(CenterX / 16); var xy = (int) Math.Floor(CenterY / 16); Painter.Rect(Run.Level, xx - 3, xy - 3, 6, 6, Tile.Chasm); /*var torches = GetComponent().Room.Tagged[Tags.Torch]; foreach (var t in torches) { ((Torch) t).On = false; } Timer.Add(() => { if (Interrupted) { return; } foreach (var t in torches) { var tr = (Torch) t; tr.On = true; tr.XSpread = 0.1f; } }, 3f);*/ HandleEvent(new TriggeredEvent { Trigger = this, Who = p }); for (var x = X - 16; x < X + Width + 16; x += 16) { for (var i = 0; i < Rnd.Int(3, 9); i++) { Area.Add(new FireParticle { Position = new Vector2(x + Rnd.Float(-2, 18), Y - 16 + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new FireParticle { Position = new Vector2(x + Rnd.Float(-2, 18), Y + Height + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new TileFx { Position = new Vector2(x, Y - 16) }); Area.Add(new TileFx { Position = new Vector2(x, Y + Height) }); } } for (var y = Y; y < Y + Height; y += 16) { for (var i = 0; i < Rnd.Int(3, 9); i++) { Area.Add(new FireParticle { Position = new Vector2(X + Rnd.Float(-2, 18) - 16, y + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new FireParticle { Position = new Vector2(X + Width + Rnd.Float(-2, 18), y + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new TileFx { Position = new Vector2(X - 16, y) }); Area.Add(new TileFx { Position = new Vector2(X + Width, y) }); } } } } return base.HandleEvent(e); } public class TriggeredEvent : Event { public SpawnTrigger Trigger; public Player Who; } } } ================================================ FILE: BurningKnight/entity/creature/drop/AnyDrop.cs ================================================ using System.Collections.Generic; namespace BurningKnight.entity.creature.drop { public class AnyDrop : OneOfDrop { public AnyDrop() { } public AnyDrop(params Drop[] drops) : base(drops) { } public override List GetItems() { var items = new List(); foreach (var d in Drops) { var i = d.GetItems(); if (i != null) { items.AddRange(i); } } return items; } public override string GetId() { return "any"; } } } ================================================ FILE: BurningKnight/entity/creature/drop/Drop.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.assets.loot; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.util.geometry; using Lens.entity; using Lens.lightJson; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.drop { public abstract class Drop { // From 0 to 1 public float Chance = 1f; public virtual List GetItems() { return new List(); } public abstract string GetId(); public virtual void Load(JsonValue root) { Chance = root["chance"].Number(1); } public virtual void Save(JsonValue root) { root["chance"] = Chance; } public static void Create(string id, Entity entity, Area area = null, Dot where = null) { var drop = Drops.Get(id); if (drop == null) { return; } Create(new List { drop }, entity, area, where); } public static void Create(List dr, Entity entity, Area area = null, Dot where = null) { var drops = new List(); var ar = entity?.Area ?? area; var wh = entity?.BottomCenter ?? where; foreach (var drop in dr) { if (Rnd.Float() > drop.Chance) { continue; } var ids = drop.GetItems(); foreach (var id in ids) { if (id != null) { if (id == "bk:troll_bomb") { var bomb = new Bomb(entity); ar.Add(bomb); bomb.Center = wh; continue; } var item = Items.Create(id); if (item != null) { drops.Add(item); } } } } if (entity is DropModifier d) { d.ModifyDrops(drops); } foreach (var item in drops) { item.CenterX = wh.X; item.CenterY = wh.Y + 4; ar.Add(item); item.AddDroppedComponents(); item.RandomizeVelocity(1f); } } } } ================================================ FILE: BurningKnight/entity/creature/drop/DropInfo.cs ================================================ using System; using Lens.lightJson; namespace BurningKnight.entity.creature.drop { public struct DropInfo { public string Id; public Type Type; public Action Render; } } ================================================ FILE: BurningKnight/entity/creature/drop/DropRegistry.cs ================================================ using System; using System.Collections.Generic; using Lens.lightJson; namespace BurningKnight.entity.creature.drop { public static class DropRegistry { public static Dictionary Defined = new Dictionary(); static DropRegistry() { Define("any", AnyDrop.RenderDebug); Define("empty", EmptyDrop.RenderDebug); Define("one", OneOfDrop.RenderDebug); Define("pool", PoolDrop.RenderDebug); Define("simple", SimpleDrop.RenderDebug); Define("single", SingleDrop.RenderDebug); } public static void Define(string id, Action render) where T : Drop { Defined[id] = new DropInfo { Render = render, Id = id, Type = typeof(T) }; } } } ================================================ FILE: BurningKnight/entity/creature/drop/EmptyDrop.cs ================================================ using System.Collections.Generic; using Lens.lightJson; namespace BurningKnight.entity.creature.drop { public class EmptyDrop : Drop { public EmptyDrop(float chance = 1) { Chance = chance; } public override List GetItems() { return null; } public override string GetId() { return "empty"; } public override void Load(JsonValue root) { } public override void Save(JsonValue root) { } public static void RenderDebug(JsonValue root) { } } } ================================================ FILE: BurningKnight/entity/creature/drop/OneOfDrop.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.loot; using BurningKnight.util; using ImGuiNET; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.creature.drop { public class OneOfDrop : Drop { public static string[] DropNames; public static int CurrentDrop; public Drop[] Drops; public OneOfDrop(params Drop[] drops) { Drops = drops; } public override List GetItems() { var items = base.GetItems(); if (Drops != null) { var sum = 0f; var dropResults = new List[Drops.Length]; var i = 0; foreach (var drop in Drops) { var results = drop.GetItems(); dropResults[i++] = results; if (results == null || results.Count > 0) { sum += drop.Chance; } } var value = Rnd.Float(sum); sum = 0; i = 0; foreach (var drop in Drops) { var d = dropResults[i++]; if (d != null && d.Count == 0) { continue; } sum += drop.Chance; if (value <= sum) { if (d != null) { items.AddRange(d); } break; } } } return items; } public override string GetId() { return "one"; } public override void Load(JsonValue root) { base.Load(root); if (root["drops"].IsJsonArray) { var drops = root["drops"].AsJsonArray; Drops = new Drop[drops.Count]; for (var i = 0; i < Drops.Length; i++) { Drops[i] = LootTables.ParseDrop(drops[i]); } } } public override void Save(JsonValue root) { base.Save(root); var drops = new JsonArray(); foreach (var d in Drops) { drops.Add(LootTables.WriteDrop(d)); } root["drops"] = drops; } public static void RenderDebug(JsonValue root) { root.InputFloat("Chance", "chance"); if (!root["drops"].IsJsonArray) { root["drops"] = new JsonArray(); } var drops = root["drops"].AsJsonArray; var toRemove = -1; for (var i = 0; i < drops.Count; i++) { if (LootTables.RenderDrop(drops[i]) && ImGui.Button("Remove drop")) { toRemove = i; } } if (toRemove > -1) { drops.Remove(toRemove); } if (DropNames == null) { DropNames = new string[DropRegistry.Defined.Count]; var i = 0; foreach (var v in DropRegistry.Defined.Values) { DropNames[i++] = v.Id; } } ImGui.Separator(); ImGui.Combo("##tp", ref CurrentDrop, DropNames, DropNames.Length); ImGui.SameLine(); if (ImGui.Button("Add drop")) { drops.Add(new JsonObject { ["type"] = DropNames[CurrentDrop] }); } } } } ================================================ FILE: BurningKnight/entity/creature/drop/PoolDrop.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.debug; using BurningKnight.entity.item; using BurningKnight.ui.imgui; using BurningKnight.util; using ImGuiNET; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.creature.drop { public class PoolDrop : Drop { public ItemPool Pool; public int Min; public int Max; public PoolDrop() { } public PoolDrop(ItemPool pool, float chance = 1f, int min = 1, int max = 1) { Pool = pool; Chance = chance; Min = min; Max = max; } public override List GetItems() { var list = new List(); for (var i = 0; i < Rnd.Int(Min, Max + 1); i++) { list.Add(Items.Generate(Pool)); } return list; } public override string GetId() { return "pool"; } public override void Load(JsonValue root) { base.Load(root); Min = root["min"].Int(1); Max = root["max"].Int(1); Pool = ItemPool.ById[root["pool"].Int(0)]; } public override void Save(JsonValue root) { base.Save(root); root["min"] = Min; root["max"] = Max; root["pool"] = Pool.Id; } public static void RenderDebug(JsonValue root) { root.InputFloat("Chance", "chance"); root.InputInt("Min Count", "min"); root.InputInt("Max Count", "max"); var pool = root["pool"].Int(0); if (ImGui.Combo("Pool##p", ref pool, ItemPool.Names, ItemPool.Count)) { root["pool"] = pool; } if (ImGui.Button("View pool")) { WindowManager.PoolEditor = true; PoolEditor.Pool = pool; } } } } ================================================ FILE: BurningKnight/entity/creature/drop/SimpleDrop.cs ================================================ using System.Collections.Generic; using BurningKnight.state; using BurningKnight.ui.imgui; using BurningKnight.util; using ImGuiNET; using Lens.input; using Lens.lightJson; using Lens.util.math; using Microsoft.Xna.Framework.Input; namespace BurningKnight.entity.creature.drop { public class SimpleDrop : Drop { private static System.Numerics.Vector2 popupSize = new System.Numerics.Vector2(400, 400); private static unsafe ImGuiTextFilterPtr popupFilter = new ImGuiTextFilterPtr(ImGuiNative.ImGuiTextFilter_ImGuiTextFilter(null)); private static string selectedItem; private static int id; public string[] Items; public int Min = 1; public int Max = 1; public SimpleDrop(float chance, int min, int max, params string[] items) { Chance = chance; Min = min; Max = max; Items = items; } public SimpleDrop() { } public override List GetItems() { var items = new List(); if (Items != null) { for (var i = 0; i < Rnd.Int(Min, Max + 1); i++) { foreach (var item in Items) { if (assets.items.Items.ShouldAppear(item)) { items.Add(item); } } } } return items; } public override string GetId() { return "simple"; } public override void Load(JsonValue root) { base.Load(root); Min = root["min"].Int(1); Max = root["max"].Int(1); if (root["items"].IsJsonArray) { var items = root["items"].AsJsonArray; Items = new string[items.Count]; for (var i = 0; i < Items.Length; i++) { Items[i] = items[i].AsString; } } } public override void Save(JsonValue root) { base.Save(root); var items = new JsonArray(); foreach (var item in Items) { items.Add(item); } root["min"] = Min; root["max"] = Max; root["items"] = items; } public static void RenderDebug(JsonValue root) { root.InputFloat("Chance", "chance"); root.InputInt("Min", "min"); root.InputInt("Max", "max"); if (!root["items"].IsJsonArray) { root["items"] = new JsonArray(); } var toRemove = -1; var items = root["items"].AsJsonArray; for (var i = 0; i < items.Count; i++) { if (ImGui.SmallButton($"{items[i]}##s")) { WindowManager.ItemEditor = true; ItemEditor.Selected = assets.items.Items.Datas[items[i]]; } ImGui.SameLine(); if (ImGui.SmallButton("-")) { toRemove = i; } } if (toRemove != -1) { items.Remove(toRemove); } if (ImGui.Button("Add")) { ImGui.OpenPopup("Add Item##p"); } ImGui.Separator(); if (ImGui.BeginPopupModal("Add Item##p")) { ImGui.SetWindowSize(popupSize); popupFilter.Draw(""); ImGui.BeginChild("ScrollinegionUses##reee", new System.Numerics.Vector2(0, -ImGui.GetStyle().ItemSpacing.Y - ImGui.GetFrameHeightWithSpacing() - 4), false, ImGuiWindowFlags.HorizontalScrollbar); ImGui.Separator(); foreach (var i in assets.items.Items.Datas) { ImGui.PushID($"{id}__itm"); if (popupFilter.PassFilter(i.Key) && !items.Contains(i.Key) && ImGui.Selectable($"{i.Key}##dd", selectedItem == i.Key)) { selectedItem = i.Key; } ImGui.PopID(); id++; } id = 0; ImGui.EndChild(); ImGui.Separator(); if (selectedItem != null && (ImGui.Button("Add") || Input.Keyboard.WasPressed(Keys.Enter, true))) { items.Add(selectedItem); selectedItem = null; ImGui.CloseCurrentPopup(); } ImGui.SameLine(); if (ImGui.Button("Cancel") || Input.Keyboard.WasPressed(Keys.Escape, true)) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } } } } ================================================ FILE: BurningKnight/entity/creature/drop/SingleDrop.cs ================================================ using System.Collections.Generic; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.drop { public class SingleDrop : Drop { public string Item; public SingleDrop() { } public SingleDrop(string id, float chance = 1f) { Item = id; Chance = chance; } public override List GetItems() { var items = new List(); if (assets.items.Items.ShouldAppear(Item)) { items.Add(Item); } else { Log.Error($"Blocked {Item}"); } return items; } public override string GetId() { return "single"; } public override void Load(JsonValue root) { base.Load(root); Item = root["item"].String(""); } public override void Save(JsonValue root) { base.Save(root); root["item"] = Item; } public static void RenderDebug(JsonValue root) { } } } ================================================ FILE: BurningKnight/entity/creature/mob/Dummy.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.entity.component.logic; using Lens.util.math; using Lens.util.timer; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.mob { public class Dummy : Mob { protected override void SetStats() { base.SetStats(); AddComponent(new RectBodyComponent(4, 2, 8, 14, BodyType.Static)); AddComponent(new DialogComponent()); GetComponent().Dialog.Voice = 2; AddAnimation("dummy"); SetMaxHp(1); RemoveTag(Tags.MustBeKilled); Become(); var health = GetComponent(); health.InvincibilityTimerMax = 0; health.RenderInvt = false; TouchDamage = 0; } public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent ev && ev.Amount < 0) { Become(); GraphicsComponent.Flipped = ev.From.CenterX > CenterX; GetComponent().EmitRandomized(GetHurtSfx()); if (Run.Depth < 1 && Rnd.Chance(30)) { var dialog = GetComponent(); if (dialog.Current == null) { dialog.StartAndClose($"npc_hurt_{Rnd.Int(3)}", 2); } } return true; } return base.HandleEvent(e); } #region Dummy States public class IdleState : EntityState { } public class HurtState : EntityState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(true); } } } #endregion protected override string GetHurtSfx() { return "mob_dummy"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/LoopChance.cs ================================================ namespace BurningKnight.entity.creature.mob { public class LoopChance : SpawnChance { public LoopChance(float chance, params string[] areas) : base(chance, areas) { LoopOnly = true; } } } ================================================ FILE: BurningKnight/entity/creature/mob/Mimic.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob { public class Mimic : Slime { public string Kind; public string Pool = "bk:wooden_chest"; private bool invoked; protected override void SetStats() { base.SetStats(); Width = 16; Height = 13; SetMaxHp(40 + Run.Depth * 7); var body = CreateBodyComponent(); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(CreateSensorBodyComponent()); } public override void PostInit() { base.PostInit(); if (Kind == null) { Kind = "wooden_chest"; } AddComponent(new InteractableSliceComponent("props", Kind)); GetComponent().Add(Pool); if (!invoked) { RemoveTag(Tags.MustBeKilled); RemoveTag(Tags.Mob); Become(); TouchDamage = 0; AddComponent(new InteractableComponent(Interact) { CanInteract = e => !invoked }); } } private bool Interact(Entity e) { if (invoked) { return true; } e.GetComponent().ModifyHealth(-2, this, DamageType.Custom); Target = e; Become(); return true; } public override bool HandleEvent(Event e) { if (!invoked && e is HealthModifiedEvent hme && hme.Amount < 0) { Become(); } return base.HandleEvent(e); } protected override TextureRegion GetDeathFrame() { return CommonAse.Props.GetSlice($"{Kind}_open"); } protected virtual BodyComponent CreateBodyComponent() { return new RectBodyComponent(0, 12, 16, 1); } protected virtual BodyComponent CreateSensorBodyComponent() { return new SensorBodyComponent(0, 0, 16, 13); } protected override void OnJump() { base.OnJump(); var builder = new ProjectileBuilder(this, "circle") { LightRadius = 32f }; builder.AddFlags(ProjectileFlags.FlyOverStones); builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); for (var i = 0; i < 3; i++) { Timer.Add(() => { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = AngleTo(Target) + Rnd.Float(-0.1f, 0.1f); var projectile = builder.Shoot(a, 9f).Build(); projectile.Center = Center + MathUtils.CreateVector(a, 5f) - new Vector2(0, GetComponent().Z); }, i * 0.3f); } } protected override void OnLand() { if (Target == null) { return; } var am = 16; GetComponent().EmitRandomized("mob_fire"); var builder = new ProjectileBuilder(this, "small") { LightRadius = 32f }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am); var fast = i % 2 == 0; builder.Slice = fast ? "small" : "circle"; var projectile = builder.Shoot(a, fast ? 7f : 4f).Build(); projectile.Center = BottomCenter; } } protected override void AnimateJump(Action callback) { var anim = GetComponent(); Tween.To(2f, anim.Scale.X, x => anim.Scale.X = x, 0.2f); Tween.To(0.3f, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(0.5f, anim.Scale.X, x => anim.Scale.X = x, 0.3f); Tween.To(2f, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f).OnEnd = () => { Tween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.2f); Tween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f); }; callback(); }; } protected override void AnimateLand() { var anim = GetComponent(); anim.Scale.X = 2f; anim.Scale.Y = 0.3f; Tween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.3f); Tween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f); } public override void Load(FileReader stream) { base.Load(stream); Kind = stream.ReadString(); invoked = stream.ReadBoolean(); Pool = stream.ReadString(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteString(Kind); stream.WriteBoolean(invoked); stream.WriteString(Pool); } private class FriendlyState : SmartState { public override void Destroy() { base.Destroy(); Self.invoked = true; Self.AddTag(Tags.MustBeKilled); Self.AddTag(Tags.Mob); Self.TouchDamage = 1; Achievements.Unlock("bk:mimic"); } } } } ================================================ FILE: BurningKnight/entity/creature/mob/Mob.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.assets.items; using BurningKnight.assets.particle; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.prefix; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.entities; using BurningKnight.level.paintings; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.level.variant; using BurningKnight.physics; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.imgui; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.creature.mob { public class Mob : Creature, DropModifier { public Entity Target; public bool HasPrefix => prefix != null; public Prefix Prefix => prefix; protected List CollidingToHurt = new List(); protected int TouchDamage = 1; protected bool TargetEverywhere; private Prefix prefix; public override void AddComponents() { base.AddComponents(); AddComponent(new AimComponent(AimComponent.AimType.Target)); AlwaysActive = true; AddTag(Tags.Mob); AddTag(Tags.MustBeKilled); SetStats(); AddDrops(new SingleDrop("bk:coin", LevelSave.GenerateShops ? 0.2f : 0.12f)); AddDrops(new SingleDrop("bk:bomb", 0.03f)); var h = GetComponent(); h.InvincibilityTimerMax = 0.3f; h.PreventDamageInInvincibility = false; if (!(this is Boss)) { GetComponent().Pause++; } } public override void PostInit() { base.PostInit(); if (Run.Level?.Variant is SnowLevelVariant || Run.Level?.Biome is IceBiome) { GetComponent().AddImmunity(); } } protected virtual void SetStats() { } protected void AddAnimation(string name, string layer = null) { AddComponent(new MobAnimationComponent(name, layer)); } protected virtual void SetMaxHp(int hp) { if (Run.Loop > 0 && !(this is DM)) { hp *= (this is Boss ? 4 : 1) * (Run.Loop + 1); } var health = GetComponent(); health.InitMaxHealth = hp; } protected virtual void OnTargetChange(Entity target) { if (target == null) { GetComponent().PauseOnChange = true; } else { GetComponent().PauseOnChange = false; GetComponent().Pause = 0; } } private float lastParticle; public override void Update(float dt) { base.Update(dt); if (prefix != null) { prefix.Update(dt); lastParticle -= dt; if (lastParticle <= 0) { lastParticle = Rnd.Float(0.05f, 0.3f); for (var i = 0; i < Rnd.Int(0, 3); i++) { var part = new ParticleEntity(Particles.Scourge()); part.Position = Center + Rnd.Vector(-4, 4); part.Particle.Scale = Rnd.Float(0.5f, 1.2f); Area.Add(part); part.Depth = 1; } } } if (Target == null) { FindTarget(); } else if (Target.Done || Target.GetComponent().Room != GetComponent().Room || (Target is Creature c && c.IsFriendly() == IsFriendly()) || (Target.TryGetComponent(out var b) && b.Has())) { var old = Target; HandleEvent(new MobTargetChange { Mob = this, New = null, Old = old }); FindTarget(); } if (TouchDamage == 0) { return; } var raging = GetComponent().Has(); for (var i = CollidingToHurt.Count - 1; i >= 0; i--) { var entity = CollidingToHurt[i]; if (entity.Done) { CollidingToHurt.RemoveAt(i); continue; } if ((!(entity is Creature c) || c.IsFriendly() != IsFriendly())) { if (entity.GetComponent().ModifyHealth(-TouchDamage * (raging ? 2 : 1), this, DamageType.Contact)) { OnHit(entity); } } } if (GetComponent().Room == null) { Kill(null); } } protected virtual void OnHit(Entity e) { } public override bool HandleEvent(Event e) { if (prefix != null && prefix.HandleEvent(e)) { e.Handled = true; } if (e is BuffAddedEvent add && add.Buff is CharmedBuff || e is BuffRemovedEvent del && del.Buff is CharmedBuff) { // If old target even was a thing, it was from wrong category FindTarget(); } else if (e is CollisionStartedEvent collisionStart) { if (collisionStart.Entity.HasComponent() && CanHurt(collisionStart.Entity)) { CollidingToHurt.Add(collisionStart.Entity); } } else if (e is CollisionEndedEvent collisionEnd) { if (collisionEnd.Entity.HasComponent()) { CollidingToHurt.Remove(collisionEnd.Entity); } } else if (e is DiedEvent de) { var who = de.From; if (de.From != null) { if (de.From.TryGetComponent(out var o)) { who = o.Owner; } else if (who is Projectile p) { who = p.Owner; } } if (who is Player && who.GetComponent().Item?.Id == "bk:explosive_lamp") { AddDrops(new SimpleDrop(1f, 1, 1, "bk:bomb")); } if (!de.BlockClear) { GetComponent().Room?.CheckCleared(who); } } else if (e is HealthModifiedEvent hme && hme.Amount < 0) { if (!(this is bk.BurningKnight) && TryGetComponent(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0) { return true; } if (!rotationApplied) { rotationApplied = true; var a = GetAnyComponent(); if (a != null) { var w = a.Angle; a.Angle += 0.5f; var t = Tween.To(w, a.Angle, x => a.Angle = x, 0.2f); t.Delay = 0.2f; t.OnEnd = () => { rotationApplied = false; }; } } } else if (e is TileCollisionStartEvent tce) { if (tce.Tile == Tile.Cobweb) { var body = GetAnyComponent(); wasSlow = body.Slow; body.Slow = true; } } else if (e is TileCollisionEndEvent tee) { if (tee.Tile == Tile.Cobweb) { var body = GetAnyComponent(); if (!wasSlow && body.Slow && !GetComponent().Has()) { body.Slow = false; } } } return base.HandleEvent(e); } private bool wasSlow; protected virtual bool CanHurt(Entity entity) { return !(entity is BreakableProp || entity is Painting || entity is Prop); } protected void FindTarget() { List targets; if (TargetEverywhere) { targets = Area.Tagged[IsFriendly() ? Tags.Mob : Tags.PlayerTarget]; } else { var room = GetComponent().Room; if (room == null) { return; } targets = room.Tagged[IsFriendly() ? Tags.Mob : Tags.PlayerTarget]; } var closestDistance = float.MaxValue; var friendly = IsFriendly(); Entity closest = null; foreach (var target in targets) { if (target == this || target is bk.BurningKnight || ((Creature) target).IsFriendly() == friendly || (target.TryGetComponent(out var b) && b.Has())) { continue; } var d = target.DistanceToSquared(this); if (d < closestDistance) { closestDistance = d; closest = target; } } if (Target != closest) { HandleEvent(new MobTargetChange { Mob = this, New = closest, Old = Target }); } // Might be null, thats ok Target = closest; OnTargetChange(closest); } public override bool IsFriendly() { return GetComponent().Has(); } private bool rotationApplied; public override void AnimateDeath(DiedEvent d) { base.AnimateDeath(d); CreateGore(d); } #region Path finding protected Vec2 NextPathPoint; private int lastStepBack; private int prevStepBack; private void BuildPath(Vector2 to, bool back = false) { var level = Run.Level; var fp = level.ToIndex((int) Math.Floor(CenterX / 16f), (int) Math.Floor(Bottom / 16f)); var tp = level.ToIndex((int) Math.Floor(to.X / 16f), (int) Math.Floor(to.Y / 16f)); var p = back ? PathFinder.GetStepBack(fp, tp, level.Passable, prevStepBack) : PathFinder.GetStep(fp, tp, level.Passable); if (back) { prevStepBack = lastStepBack; lastStepBack = p; } if (p == -1) { return; } NextPathPoint = new Vec2 { X = level.FromIndexX(p) * 16 + 8, Y = level.FromIndexY(p) * 16 + 8 }; } public bool MoveTo(Vector2 point, float speed, float distance = 8f, bool back = false) { if (!back) { var ds = DistanceToFromBottom(point); if (ds <= distance) { return true; } } else { var ds = DistanceToFromBottom(point); if (ds >= distance) { return true; } } if (NextPathPoint == null) { BuildPath(point, back); if (NextPathPoint == null) { return false; } } var dx = NextPathPoint.X - CenterX; var dy = NextPathPoint.Y - Bottom; var d = (float) Math.Sqrt(dx * dx + dy * dy); if (d <= 2f) { NextPathPoint = null; return false; } speed *= Engine.Delta * 60; GetAnyComponent().Velocity = new Vector2(dx / d * speed, dy / d * speed); return false; } public bool FlyTo(Vector2 point, float speed, float distance = 8f) { var dx = DxTo(point); var dy = DyTo(point); var d = (float) Math.Sqrt(dx * dx + dy * dy); if (d <= distance) { return true; } GetAnyComponent().Velocity = new Vector2(dx / d * speed, dy / d * speed); return false; } #endregion public override void Load(FileReader stream) { base.Load(stream); var str = stream.ReadString(); if (str != null) { SetPrefix(str); } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteString(prefix?.Id); } public void GeneratePrefix() { if (!Rnd.Chance(Run.Scourge * 10 + 0.5f)) { return; } var all = PrefixRegistry.Defined.Keys.ToArray(); SetPrefix(all[Rnd.Int(all.Length)]); } public void SetPrefix(string id) { if (!PrefixRegistry.Defined.TryGetValue(id, out var t)) { return; } try { var p = (Prefix) Activator.CreateInstance(t); prefix = p; p.Id = id; p.Mob = this; p.Init(); } catch (Exception e) { Log.Error(e); return; } } public override void RenderImDebug() { base.RenderImDebug(); ImGui.Text($"Target: {(Target == null ? "null" : Target.GetType().Name)}"); if (Target != null) { if (ImGui.Button("Jump")) { WindowManager.Entities = true; AreaDebug.ToFocus = Target; } } ImGui.Text($"Prefix: {(Prefix == null ? "null" : Prefix.Id)}"); } public override void RenderDebug() { base.RenderDebug(); if (NextPathPoint != null) { Graphics.Batch.DrawLine(CenterX, Bottom, NextPathPoint.X, NextPathPoint.Y, Color.Red); Graphics.Batch.DrawLine(CenterX, Bottom, Run.Level.FromIndexX(prevStepBack) * 16 + 8, Run.Level.FromIndexY(prevStepBack) * 16 + 8, Color.Blue); } } private static bool RayShouldCollide(Entity entity) { return entity is ProjectileLevelBody; } protected bool CanSeeTarget() { if (Target == null) { return false; } var min = 1f; var found = false; Physics.World.RayCast((fixture, point, normal, fraction) => { if (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) { min = fraction; found = true; } return min; }, Center, Target.Center); return !found; } protected void TurnToTarget() { if (Target != null) { GraphicsComponent.Flipped = Target.CenterX < CenterX; } } protected void PushFromOtherEnemies(float dt, Func filter = null) { var room = GetComponent().Room; var body = GetAnyComponent(); if (room == null || body == null) { return; } foreach (var m in room.Tagged[Tags.Mob]) { if (m == this) { continue; } var mob = (Creature) m; if (filter != null && !filter(mob)) { return; } var dx = DxTo(mob); var dy = DyTo(mob); var d = MathUtils.Distance(dx, dy); var force = dt * 800; if (d <= 8) { var a = MathUtils.Angle(dx, dy) - (float) Math.PI; body.Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } } protected void PushOthersFromMe(float dt, Func filter = null) { var room = GetComponent().Room; if (room == null) { return; } foreach (var m in room.Tagged[Tags.Mob]) { if (m == this) { continue; } var mob = (Creature) m; if (filter != null && !filter(mob)) { return; } var dx = DxTo(mob); var dy = DyTo(mob); var d = MathUtils.Distance(dx, dy); var force = dt * 800; if (d <= 12) { var a = MathUtils.Angle(dx, dy) - (float) Math.PI; var b = mob.GetAnyComponent(); if (b != null) { b.Velocity -= new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } } } public void ModifyDrops(List drops) { if (Rnd.Chance(Run.Scourge * 0.5f)) { var c = Rnd.Int(0, 3); for (var i = 0; i < c; i++) { drops.Add(Items.Create("bk:copper_coin")); } } foreach (var p in Area.Tagged[Tags.Player]) { if (p.GetComponent().Item?.Id == "bk:explosive_lamp") { drops.Add(Items.Create("bk:bomb")); break; } } } } } ================================================ FILE: BurningKnight/entity/creature/mob/MobInfo.cs ================================================ using System; using BurningKnight.state; namespace BurningKnight.entity.creature.mob { public class MobInfo { public Type Type; public SpawnChance[] Spawns; public bool SpawnsOnFirst = true; public bool NearWall; public bool Single; public bool AwayFromWall; public float Weight = 1; public float Chance = 1; public static MobInfo New(params SpawnChance[] spawns) where T : Mob { return new MobInfo { Type = typeof(T), Spawns = spawns }; } public MobInfo MarkSingle() { Single = true; return this; } public MobInfo SetWeight(float weight) { Weight = weight; return this; } public MobInfo SetSpawnChance(float chance) { Chance = chance; return this; } public MobInfo RequiresNearWall() { NearWall = true; AwayFromWall = false; return this; } public MobInfo HatesWall() { NearWall = false; AwayFromWall = true; return this; } public MobInfo DisableFirstSpawn() { SpawnsOnFirst = false; return this; } public bool SpawnsIn(string biome) { return GetChanceFor(biome) != null; } public SpawnChance GetChanceFor(string biome) { foreach (var b in Spawns) { foreach (var a in b.Areas) { if (a == biome && (!b.LoopOnly || Run.Loop > 0)) { return b; } } } return null; } } } ================================================ FILE: BurningKnight/entity/creature/mob/MobPair.cs ================================================ namespace BurningKnight.entity.creature.mob { public class MobPair { public int Count; public string Id; } } ================================================ FILE: BurningKnight/entity/creature/mob/MobRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.creature.mob.cave; using BurningKnight.entity.creature.mob.desert; using BurningKnight.entity.creature.mob.ice; using BurningKnight.entity.creature.mob.jungle; using BurningKnight.entity.creature.mob.library; using BurningKnight.level.biome; using BurningKnight.state; using Lens.util.math; using Buffer = BurningKnight.entity.creature.mob.library.Buffer; namespace BurningKnight.entity.creature.mob { public static class MobRegistry { public static List All = new List(); public static List Current = new List(); static MobRegistry() { MobInfo[] infos = { // XD MobInfo.New(new SpawnChance(0.1f, Biome.Castle)).SetSpawnChance(0.5f), // Castle MobInfo.New(new SpawnChance(1f, Biome.Castle)), MobInfo.New(new SpawnChance(0.5f, Biome.Castle)), MobInfo.New(new SpawnChance(0.7f, Biome.Castle)), MobInfo.New(new SpawnChance(0.5f + 3f, Biome.Castle)).RequiresNearWall(), MobInfo.New(new SpawnChance(1f, Biome.Castle), new SpawnChance(0.5f, Biome.Cave)), MobInfo.New(new SpawnChance(0.5f, Biome.Castle)).MarkSingle(), MobInfo.New(new SpawnChance(0.1f, Biome.Castle)), MobInfo.New(new SpawnChance(1f, Biome.Castle)).DisableFirstSpawn(), MobInfo.New(new SpawnChance(0.1f, Biome.Castle)).DisableFirstSpawn().SetWeight(3f), MobInfo.New(new SpawnChance(2f, Biome.Castle)).DisableFirstSpawn(), MobInfo.New(new SpawnChance(0.1f, Biome.Castle)).DisableFirstSpawn().SetWeight(2f), MobInfo.New(new SpawnChance(2f, Biome.Castle)).DisableFirstSpawn(), // Desert MobInfo.New(new SpawnChance(1f, Biome.Desert, Biome.Jungle)).SetWeight(0.5f), MobInfo.New(new SpawnChance(0.8f, Biome.Desert)).SetWeight(2f), MobInfo.New(new SpawnChance(0.7f, Biome.Desert)).SetWeight(1.5f), MobInfo.New(new SpawnChance(1f, Biome.Desert)).RequiresNearWall(), MobInfo.New(new SpawnChance(1f, Biome.Desert)), MobInfo.New(new SpawnChance(1f, Biome.Desert)), MobInfo.New(new SpawnChance(0.5f, Biome.Desert)), MobInfo.New(new SpawnChance(1f, Biome.Desert), new LoopChance(1f, Biome.Castle)), MobInfo.New(new SpawnChance(1f, Biome.Desert), new LoopChance(1f, Biome.Castle)), MobInfo.New(new SpawnChance(1f, Biome.Desert)).DisableFirstSpawn().SetWeight(2f).MarkSingle(), MobInfo.New(new SpawnChance(1f, Biome.Desert)).DisableFirstSpawn().SetWeight(2f).MarkSingle(), // MobInfo.New(new SpawnChance(0f, Biome.Desert)).DisableFirstSpawn(), // Jungle MobInfo.New(new SpawnChance(1f, Biome.Jungle), new LoopChance(1f, Biome.Desert)), MobInfo.New(new SpawnChance(100.5f, Biome.Jungle)).MarkSingle().SetWeight(3f).HatesWall(), MobInfo.New(new SpawnChance(0.3f, Biome.Jungle)), MobInfo.New(new SpawnChance(0.15f, Biome.Jungle)), MobInfo.New(new SpawnChance(0.7f, Biome.Jungle), new LoopChance(1f, Biome.Desert)).SetWeight(2f).MarkSingle(), MobInfo.New(new SpawnChance(1f, Biome.Jungle)).SetWeight(2f).HatesWall(), MobInfo.New(new SpawnChance(1f, Biome.Jungle)).SetWeight(2f).DisableFirstSpawn().HatesWall(), // Ice MobInfo.New(new SpawnChance(1f, Biome.Ice), new LoopChance(1f, Biome.Jungle)), MobInfo.New(new SpawnChance(1f, Biome.Ice)).SetSpawnChance(0.5f).HatesWall(), MobInfo.New(new SpawnChance(1f, Biome.Ice)).SetWeight(0.5f), MobInfo.New(new SpawnChance(1f, Biome.Ice)).RequiresNearWall(), MobInfo.New(new SpawnChance(0.5f, Biome.Ice)).SetSpawnChance(0.5f), MobInfo.New(new SpawnChance(1f, Biome.Ice)), MobInfo.New(new SpawnChance(1f, Biome.Ice)).MarkSingle().HatesWall().DisableFirstSpawn(), MobInfo.New(new SpawnChance(1f, Biome.Ice)).SetWeight(3f).DisableFirstSpawn(), // Library MobInfo.New(new SpawnChance(1f, Biome.Library)).HatesWall().SetWeight(2.5f), MobInfo.New(new SpawnChance(1f, Biome.Library)).HatesWall(), MobInfo.New(new SpawnChance(1f, Biome.Library)).SetSpawnChance(0.5f), MobInfo.New(new SpawnChance(1f, Biome.Library), new LoopChance(1f, Biome.Jungle), new LoopChance(1f, Biome.Ice)).MarkSingle(), MobInfo.New(new SpawnChance(1f, Biome.Library)), MobInfo.New(new SpawnChance(1f, Biome.Library)), // Tech for dm fight MobInfo.New(new SpawnChance(1f, Biome.Tech)), MobInfo.New(new SpawnChance(1f, Biome.Tech)).HatesWall(), MobInfo.New(new SpawnChance(1f, Biome.Tech)).RequiresNearWall(), MobInfo.New(new SpawnChance(1f, Biome.Tech)), MobInfo.New(new SpawnChance(2f, Biome.Tech)), // Caves MobInfo.New(new SpawnChance(1f, Biome.Cave)), MobInfo.New(new SpawnChance(1f, Biome.Cave)).SetWeight(2f), MobInfo.New(new SpawnChance(1f, Biome.Cave)), }; All.AddRange(infos); } public static MobInfo FindFor(Type type) { foreach (var info in All) { if (info.Type == type) { return info; } } return null; } public static Mob Generate() { var chances = new float[Current.Count]; for (var i = 0; i < Current.Count; i++) { if (Current[i].Type == typeof(BeeHive)) { continue; } chances[i] = Current[i].GetChanceFor(Run.Level.Biome.Id).Chance; } var types = new List(); var spawnChances = new List(); for (int i = 0; i < Rnd.Int(2, 6); i++) { var type = Current[Rnd.Chances(chances)]; var found = false; foreach (var t in types) { if (t == type) { found = true; break; } } if (found) { i--; } else { types.Add(type); spawnChances.Add(type.Chance); } } if (types.Count == 0) { return null; } return (Mob) Activator.CreateInstance(types[Rnd.Chances(spawnChances)].Type); } public static void SetupForBiome(string biome) { Current.Clear(); foreach (var info in All) { if (info.SpawnsIn(biome) && (info.SpawnsOnFirst || Run.Depth % 2 == 0)) { Current.Add(info); } } } public static void Remove() where T : Mob { var type = typeof(T); MobInfo i = null; foreach (var info in All) { if (info.Type == type) { i = info; break; } } if (i != null) { All.Remove(i); } } } } ================================================ FILE: BurningKnight/entity/creature/mob/MobSpawnInfo.cs ================================================ using System; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob { public struct MobSpawnInfo { public Vector2 Position; public Type Type; } } ================================================ FILE: BurningKnight/entity/creature/mob/SpawnChance.cs ================================================ namespace BurningKnight.entity.creature.mob { public class SpawnChance { public float Chance; public string[] Areas; public bool LoopOnly; public SpawnChance(float chance, params string[] areas) { Chance = chance; Areas = areas; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/BkHead.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.creature.bk; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.creature.mob.desert; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.entity.cutscene.entity; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.pattern; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.mob.boss { public class BkHead : Boss { public bool CanBeSaved => GetComponent().Percent <= 0.2f; protected override void AddPhases() { base.AddPhases(); HealthBar.AddPhase(0.2f); } public override void AddComponents() { base.AddComponents(); AddComponent(new BkGraphicsComponent("demon")); AddComponent(new RectBodyComponent(2, 4, 12, 15, BodyType.Dynamic, true)); AddComponent(new AimComponent(AimComponent.AimType.Target)); var b = GetComponent(); b.Body.LinearDamping = 2; b.KnockbackModifier = 0; SetMaxHp(600); Depth = Layers.FlyingMob; Awoken = true; } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target != null) { GetComponent().StartAndClose("head_0", 2f); Timer.Add(() => { Become(); }, 1); } } public override void SelectAttack() { base.SelectAttack(); Become(); } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (Target != null && !Died) { var force = 40f * dt; var a = AngleTo(Target); GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } private int counter; private void WarnLaser(float angle, Vector2? offset = null) { var builder = new ProjectileBuilder(this, "circle") { LightRadius = 32f }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); var projectile = builder.Shoot(angle, 20f).Build(); projectile.Center += MathUtils.CreateVector(angle, 8); if (offset != null) { projectile.Center += offset.Value; } } #region Demon States private class IdleState : SmartState { public override void Init() { base.Init(); Self.TouchDamage = 2; } public override void Update(float dt) { base.Update(dt); if (T <= 1f) { return; } switch (Self.counter) { case 0: { Become(); break; } case 1: { Become(); break; } case 2: { Become(); break; } case 3: { Become(); break; } case 4: { Become(); break; } } Self.counter = (Self.counter + 1) % 5; } } private class LaserSnipeState : SmartState { private float delay; private int count; public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { if (count >= 3) { Become(); return; } delay = 0.5f; var a = Self.AngleTo(Self.Target); Self.WarnLaser(a); Timer.Add(() => { Self.GetComponent().EmitRandomizedPrefixed("item_laser", 4); var laser = Laser.Make(Self, a, 0, damage: 2, scale: 3, range: 64); laser.LifeTime = 1f; laser.Position = Self.Center; Self.GetComponent().Animate(); }, 0.2f); count++; } } } private class BulletHellState : SmartState { private float sinceLast; public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast <= 0) { sinceLast = 0.5f; // Self.InFirstPhase ? 0.5f : 0.3f; var amount = 8; var builder = new ProjectileBuilder(Self, "small"); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < amount; i++) { var a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 2f) * Math.PI) * (i % 2 == 0 ? -1 : 1); var projectile = builder.Shoot(a, 8f + (float) Math.Cos(Self.t * 2f) * 3f); projectile.Color = ProjectileColor.DesertRainbow[Rnd.Int(ProjectileColor.DesertRainbow.Length)]; } Self.GetComponent().Animate(); } if (T >= 5f) { Become(); } } } private class MissileState : SmartState { private const int SmallCount = 8; private const int InnerCount = 8; private float delay; private int count; public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { if (count >= 5f) { Become(); return; } delay = 3f; count++; Self.GetComponent().Animate(); var m = new Missile(Self, Self.Target); Self.Area.Add(m); m.HurtOwner = false; ProjectileCallbacks.AttachDeathCallback(m, (p, e, t) => { var bb = new ProjectileBuilder(Self, "small"); bb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < SmallCount; i++) { var an = (float) (((float) i) / SmallCount * Math.PI * 2); var pp = new ProjectilePattern(CircleProjectilePattern.Make(6.5f, 10 * (i % 2 == 0 ? 1 : -1))) { Position = p.Center }; for (var j = 0; j < 5; j++) { pp.Add(bb.Build()); } pp.Launch(an, 40); Self.Area.Add(pp); } var aa = Self.AngleTo(Self.Target); var bbb = new ProjectileBuilder(Self, "circle") { Color = ProjectileColor.Orange }; bbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < InnerCount; i++) { bbb.Scale = Rnd.Float(0.5f, 1f); var b = bbb.Shoot(aa + Rnd.Float(-0.3f, 0.3f), Rnd.Float(2, 12)).Build(); b.Center = p.Center; } }); } } } public class SpawnAttack : SmartState { private int count; private float delay; public override void Init() { base.Init(); count = Rnd.Int(4, 10); } public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { delay = 0.3f; Self.GetComponent().Animate(); var angle = Rnd.AnglePI() * 0.5f + count * (float) Math.PI; var builder = new ProjectileBuilder(Self, "big") { Color = ProjectileColor.Orange, LightRadius = 32f }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); var projectile = builder.Shoot(angle, 15f).Build(); projectile.Center += MathUtils.CreateVector(angle, 8); ProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => { var x = (int) Math.Floor(p.CenterX / 16); var y = (int) Math.Floor(p.CenterY / 16); var mob = Rnd.Chance(40) ? (Mob) new DesertBulletSlime() : new Gunner(); Self.Area.Add(mob); mob.X = x * 16; mob.Y = y * 16 - 8; mob.GeneratePrefix(); AnimationUtil.Poof(mob.Center, 1); }); count--; if (count <= 0) { Become(); } } } } public class LaserSwingAttack : SmartState { private class Data { public Laser Laser; public float Vy; public float Angle; } private Data[] data = new Data[2]; public override void Init() { base.Init(); var a = Self.AngleTo(Self.Target); for (var i = 0; i < 2; i++) { var angle = a - (i == 0 ? -1 : 1) * 1.2f; Self.WarnLaser(angle); data[i] = new Data(); data[i].Angle = angle; } } public override void Update(float dt) { base.Update(dt); if (T < 0.4f) { return; } var made = false; for (var i = 0; i < 2; i++) { var info = data[i]; if (info.Laser == null) { info.Laser = Laser.Make(Self, 0, 0, damage: 2, scale: 3, range: 64); info.Laser.LifeTime = 10f; info.Laser.Angle = info.Angle; if (!made) { made = true; Self.GetComponent().EmitRandomizedPrefixed("item_laser", 4); } Log.Info("made laser"); } else if (info.Laser.Done) { Become(); return; } info.Laser.Position = Self.Center; var aa = info.Laser.Angle; var a = Self.AngleTo(Self.Target); info.Vy += (float) MathUtils.ShortAngleDistance(aa, a) * dt * 4; info.Laser.Angle += info.Vy * dt * 0.5f; } } } public class TeleportState : SmartState { public override void Init() { base.Init(); Tween.To(0, 255, x => Self.GetComponent().Tint.A = (byte) x, 0.5f).OnEnd = () => { var tile = Self.GetComponent().Room.GetRandomFreeTile() * 16; Self.BottomCenter = tile + new Vector2(8, 8); Tween.To(255, 0, x => Self.GetComponent().Tint.A = (byte) x, 0.5f).OnEnd = () => { Become(); }; }; } } #endregion public override void PlaceRewards() { if (saved) { base.PlaceRewards(); } else { ResetCam = false; } Achievements.Unlock("bk:bk_no_more"); } protected override TextureRegion GetDeathFrame() { return CommonAse.Particles.GetSlice("old_gobbo"); } private bool saved; public void Save() { if (saved || Died) { return; } saved = true; GetComponent().Kill(this); Timer.Add(() => PlaceRewards(), 1f); } protected override void CreateGore(DiedEvent d) { base.CreateGore(d); if (saved) { return; } var heinur = new Heinur(); Area.Add(heinur); heinur.Center = Center - new Vector2(0, 32); var g = heinur.GetComponent(); g.Scale = Vector2.Zero; Timer.Add(() => { Tween.To(1, 0, x => g.Scale.X = x, 3f); Tween.To(1, 0, x => g.Scale.Y = x, 3f); }, 1f); var dm = new DarkMage(); Area.Add(dm); dm.Center = Center + new Vector2(0, 32); dm.GetComponent().Animate(); AnimationUtil.Poof(dm.Center); var dmDialog = dm.GetComponent(); var heinurDialog = heinur.GetComponent(); foreach (var p in Area.Tagged[Tags.Player]) { p.RemoveComponent(); } Camera.Instance.Targets.Clear(); Camera.Instance.Follow(dm, 1f); Camera.Instance.Follow(heinur, 1f); dmDialog.Start("dm_5", null, () => Timer.Add(() => { dmDialog.Close(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(dm, 1f); Camera.Instance.Follow(heinur, 1f); heinurDialog.Start("heinur_0", null, () => Timer.Add(() => { heinurDialog.Close(); heinur.Attract = true; Camera.Instance.Targets.Clear(); Camera.Instance.Follow(dm, 1f); Camera.Instance.Follow(heinur, 1f); heinur.Callback = () => { Camera.Instance.Targets.Clear(); Camera.Instance.Follow(dm, 1f); Camera.Instance.MainTarget = dm; foreach (var p in Area.Tagged[Tags.Player]) { p.GetComponent().Hidden = true; p.RemoveComponent(); } var bk = new bk.BurningKnight() { Passive = true }; Area.Add(bk); bk.Center = Center; bk.GetComponent().Animate(); Camera.Instance.Follow(bk, 1f); dmDialog.Start("dm_6", null, () => Timer.Add(() => { dmDialog.Close(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(bk, 1f); var nbkDialog = bk.GetComponent(); nbkDialog.Start("nbk_0", null, () => Timer.Add(() => { nbkDialog.Close(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(bk, 1f); Run.Win(); }, 2f)); }, 2f)); }; }, 1f)); }, 1f)); } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/Boss.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.assets.particle.custom; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.projectile; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.ui; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss { public class Boss : Mob { // Dirty hack, I'm running out of time, don't kill me public static bool Exploding; public bool Awoken; protected bool HasHealthbar = true; protected HealthBar HealthBar; protected bool Died; private float deathTimer; private float lastExplosion; public bool ResetCam = true; public override void AddComponents() { base.AddComponents(); AddComponent(new DialogComponent()); var b = GetComponent(); b.AddImmunity(); b.AddImmunity(); if (!(this is BkHead || this is DM)) { Become(); } GetComponent().AutoKill = true; AddTag(Tags.Boss); } private bool cleared; protected bool Placed; public override void Update(float dt) { base.Update(dt); if (Died) { if (!cleared) { cleared = true; GetComponent().Close(); foreach (var p in Area.Tagged[Tags.Projectile]) { AnimationUtil.Poof(p.Center); ((Projectile) p).Break(null); } try { var a = GetComponent().Room.Tagged[Tags.MustBeKilled].ToArray(); foreach (var p in a) { if (!(p is Boss)) { AnimationUtil.Poof(p.Center); ((Creature) p).Kill(this); } } } catch (Exception e) { Log.Error(e); } } if (deathTimer >= 3f && !Placed) { Placed = true; CreateGore(null); if (this is bk.BurningKnight) { } else { HandleEvent(new DefeatedEvent { Boss = this }); } var player = LocalPlayer.Locate(Area); var doors = new List(); if (player != null) { var stats = player.GetComponent(); var e = new DealChanceCalculateEvent(); if (!stats.TookDamageInRoom) { Achievements.Unlock("bk:dodge_master"); } e.GrannyStartChance = stats.SawDeal && !stats.TookDeal ? stats.GrannyChance : 0; e.GrannyChance = e.GrannyStartChance; e.DmStartChance = stats.DMChance; e.DmChance = e.DmStartChance; player.HandleEvent(e); var gr = Rnd.Chance(e.GrannyChance * 100); var dm = Rnd.Chance(e.DmChance * 100); if (gr || (dm && e.OpenBoth)) { foreach (var r in Area.Tagged[Tags.Room]) { var room = (Room) r; if (room.Type == RoomType.Granny) { room.OpenHiddenDoors(); foreach (var d in room.Doors) { doors.Add(new DoorTile { Door = d, Tile = Tile.GrannyFloor }); } break; } } } if (dm || (gr && e.OpenBoth)) { foreach (var r in Area.Tagged[Tags.Room]) { var room = (Room) r; if (room.Type == RoomType.OldMan) { room.OpenHiddenDoors(); foreach (var d in room.Doors) { doors.Add(new DoorTile { Door = d, Tile = Tile.EvilFloor }); } break; } } } } if (doors.Count > 0) { var rm = GetComponent().Room; var level = Run.Level; var cx = rm.MapX + rm.MapW / 2f; var cy = rm.MapY + rm.MapH / 2f; var grannyDoors = new List(); var evilDoors = new List(); foreach (var d in doors) { if (d.Tile == Tile.GrannyFloor) { grannyDoors.Add(d.Door); } else { evilDoors.Add(d.Door); } } rm.PaintTunnel(grannyDoors, Tile.GrannyFloor); rm.PaintTunnel(evilDoors, Tile.EvilFloor); rm.ApplyToEachTile((x, y) => { var t = level.Get(x, y); if (t == Tile.GrannyFloor || t == Tile.EvilFloor) { level.Set(x, y, Tile.FloorA); Timer.Add(() => { var part = new TileParticle(); part.Top = t == Tile.GrannyFloor ? Tilesets.Biome.GrannyFloor[0] : Tilesets.Biome.EvilFloor[0]; part.TopTarget = Run.Level.Tileset.WallTopADecor; part.Side = Run.Level.Tileset.FloorSidesD[0]; part.Sides = Run.Level.Tileset.WallSidesA[2]; part.Tile = t; part.X = x * 16; part.Y = y * 16; part.Target.X = x * 16; part.Target.Y = y * 16; part.TargetZ = -8f; Area.Add(part); }, 1f + Rnd.Float(0.2f) + MathUtils.Distance(x - cx, y - cy) / 6f); } }, -1); level.TileUp(); level.CreateBody(); } Done = true; PlaceRewards(); if (ResetCam) { Timer.Add(() => { ((InGameState) Engine.Instance.State).ResetFollowing(); }, 0.5f); } } else { deathTimer += dt; lastExplosion -= dt; if (lastExplosion <= 0) { lastExplosion = 0.3f; AnimationUtil.Explosion(Center + new Vector2(Rnd.Float(-16, 16), Rnd.Float(-16, 16))); Camera.Instance.Shake(10); Audio.PlaySfx($"level_explosion_{Rnd.Int(1, 4)}"); } if (deathTimer > 2.5f) { Engine.Instance.FlashColor = new Color(1f, 1f, 1f, (deathTimer - 2.5f) * 2f); Engine.Instance.Flash = 0.01f; } } return; } if (!(GetComponent().StateInstance is FriendlyState) && HasHealthbar && HealthBar == null) { HealthBar = new HealthBar(this); Engine.Instance.State.Ui.Add(HealthBar); AddPhases(); Engine.Instance.State.Ui.Add(new UiBanner(Locale.Get(GetId()))); } } public string GetId() { return $"boss_{(this is BkHead ? "burningknight" : GetType().Name.ToLower())}"; } private struct DoorTile { public Door Door; public Tile Tile; } protected virtual void AddPhases() { } protected override void OnTargetChange(Entity target) { if (target == null) { // Awoken = false; var c = GetAnyComponent(); if (c != null) { c.Animation.Tag = "idle"; } } else { Awoken = true; } base.OnTargetChange(target); } public override bool HandleEvent(Event e) { if (e is DiedEvent de) { if (de.Who == this) { if (!Died) { Exploding = true; Died = true; HealthBar?.Remove(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(this, 1f); Become(); Audio.Stop(); } Done = false; e.Handled = true; } } return base.HandleEvent(e); } public virtual void PlaceRewards() { var exit = new Exit(); Exploding = false; Area.Add(exit); exit.To = Run.Depth + 1; var center = GetComponent().Room.Center; var x = (int) Math.Floor(center.X / 16); var y = (int) Math.Floor(center.Y / 16); var p = new Vector2(x * 16 + 8, y * 16 + 8); exit.Center = p; Painter.Fill(Run.Level, x - 1, y - 1, 3, 3, Tiles.RandomFloor()); Painter.Fill(Run.Level, x - 1, y - 3, 3, 3, Tiles.RandomFloor()); Run.Level.ReTileAndCreateBodyChunks(x - 1, y - 1, 3, 7); var w = p - new Vector2(0, 32f); if (!(this is DM || this is BkHead || Run.Type == RunType.BossRush)) { var stand = new BossStand(); Area.Add(stand); stand.Center = w; stand.SetItem(Items.CreateAndAdd(Items.Generate(ItemPool.Boss), Area), null); } var rewards = new List(); var c = Run.Type == RunType.BossRush ? 2 : Rnd.Int(2, 10); if (Run.Type != RunType.BossRush && !(this is DM || this is BkHead)) { for (var i = 0; i < c; i++) { rewards.Add("bk:emerald"); } var q = Rnd.Int(4, 10); for (var i = 0; i < q; i++) { rewards.Add("bk:copper_coin"); } } if (Run.Type != RunType.BossRush) { var cn = Rnd.Int(0, 3); for (var i = 0; i < cn; i++) { rewards.Add("bk:heart"); } } else { var cn = Rnd.Int(20, 30); for (var i = 0; i < cn; i++) { rewards.Add("bk:coin"); } } var j = 0; foreach (var reward in rewards) { var item = Items.CreateAndAdd(reward, Area); item.Center = w + MathUtils.CreateVector(j / ((float) rewards.Count) * Math.PI * 2 + Rnd.Float(-0.1f, 0.1f), Rnd.Float(12, 18)); j++; } } public virtual void SelectAttack() { } public class DefeatedState : SmartState { } public class FriendlyState : SmartState { public override void Init() { base.Init(); Exploding = false; Self.GetComponent().Unhittable = true; } public override void Destroy() { base.Destroy(); Exploding = false; Self.GetComponent().Unhittable = false; } } public override bool IsFriendly() { return GetComponent().StateInstance is FriendlyState; } public class DefeatedEvent : Event { public Boss Boss; } public override void Kill(Entity w, DamageType type = DamageType.Regular) { } public virtual string GetScream() { return "bk_3"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/BossAttack.cs ================================================ namespace BurningKnight.entity.creature.mob.boss { public class BossAttack : SmartState where T : Boss { } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/BossInfo.cs ================================================ using System; namespace BurningKnight.entity.creature.mob.boss { public class BossInfo { public Type Type; public SpawnChance[] Spawns; public static BossInfo New(params SpawnChance[] spawns) where T : Mob { return new BossInfo { Type = typeof(T), Spawns = spawns }; } public bool SpawnsIn(string biome) { return GetChanceFor(biome) != null; } public SpawnChance GetChanceFor(string biome) { foreach (var b in Spawns) { foreach (var a in b.Areas) { if (a == biome) { return b; } } } return null; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/BossRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.level.biome; using BurningKnight.state; using Lens.util.math; namespace BurningKnight.entity.creature.mob.boss { public static class BossRegistry { public static List All = new List(); static BossRegistry() { BossInfo[] infos = { BossInfo.New(new SpawnChance(1f, Biome.Castle)), BossInfo.New(new SpawnChance(1f, Biome.Desert)), BossInfo.New(new SpawnChance(1f, Biome.Jungle)), BossInfo.New(new SpawnChance(1f, Biome.Ice)), BossInfo.New(new SpawnChance(1f, Biome.Tech)) }; All.AddRange(infos); } public static Boss Generate() { var current = new List(); foreach (var info in All) { if (info.SpawnsIn(Run.Level.Biome.Id)) { current.Add(info); } } var chances = new float[current.Count]; for (var i = 0; i < current.Count; i++) { chances[i] = current[i].GetChanceFor(Run.Level.Biome.Id).Chance; } var index = Rnd.Chances(chances); if (index == -1) { return null; } return (Boss) Activator.CreateInstance(current[index].Type); } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/DM.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.assets.achievements; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss.rooms; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.room; using BurningKnight.entity.room.controllable; using BurningKnight.entity.room.controllable.platform; using BurningKnight.entity.room.controllable.turret; using BurningKnight.entity.room.controller; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.level.entities.decor; using BurningKnight.level.rooms; using BurningKnight.level.rooms.regular; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using BurningKnight.util.geometry; using Lens; using Lens.entity; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.mob.boss { public class DM : Boss { private const int Hp = 5; private List did = new List(); protected override void AddPhases() { base.AddPhases(); for (var i = 1; i < Hp; i++) { HealthBar.AddPhase(i / (float) Hp); } } public override void AddComponents() { base.AddComponents(); Width = 14; Height = 17; AddComponent(new SensorBodyComponent(1, 1, 12, 16)); var body = new RectBodyComponent(1, 16, 12, 1); AddComponent(body); body.KnockbackModifier = 0.5f; body.Body.LinearDamping = 3; AddComponent(new ZComponent()); AddComponent(new ZAnimationComponent("dark_mage")); SetMaxHp(Hp); Flying = true; var b = GetComponent(); b.AddImmunity(); b.AddImmunity(); b.AddImmunity(); b.AddImmunity(); } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target != null) { if (GetComponent().Health > 1) { GetComponent().StartAndClose("dm_7", 2f); } SelectAttack(); } } public override void SelectAttack() { base.SelectAttack(); Become(); Timer.Add(() => { ChangeupRoom(); }, 1f); } public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent hme && hme.Amount < 0) { hme.Amount = Math.Max(-1, hme.Amount); ChangeupRoom(); } return base.HandleEvent(e); } private void ChangeupRoom() { foreach (var p in Area.Tagged[Tags.Player]) { Timer.Add(() => { AnimationUtil.TeleportAway(p, () => { }); }, 0.5f); } Camera.Instance.Shake(6); AnimationUtil.TeleportAway(this, () => { GetComponent().Room.Hide(); Timer.Add(() => { foreach (var r in Area.Tagged[Tags.Room]) { var room = (Room) r; if (room.Type != RoomType.Boss) { room.Done = true; } } foreach (var d in Area.Tagged[Tags.Door]) { d.Done = true; } foreach (var e in Area.Entities.Entities) { if (e is WallTorch || e is Torch || e is Prop || e is Entrance || (e is Creature && !(e is Player || e is Boss)) || e is Turret || e is SpawnPoint || e is Projectile || e is MovingPlatform || e is RoomControllable || e is Gore) { e.Done = true; } } var rm = GetComponent().Room; var level = Run.Level; Type type; if (GetComponent().Health <= 0) { type = typeof(DmEndRoom); } else { var arr = DmRoomRegistry.Rooms.ToList(); foreach (var t in did) { arr.Remove(t); } type = arr[Rnd.Int(arr.Count)]; did.Add(type); } for (var i = rm.Controllers.Count - 1; i >= 0; i--) { if (!(rm.Controllers[i] is BossRoomController)) { rm.Controllers.RemoveAt(i); } } var rmdef = (DmRoom) Activator.CreateInstance(type); rm.Parent = rmdef; rm.MapW = Math.Min(Rnd.Int(rmdef.GetMinWidth(), rmdef.GetMaxWidth()), level.Width - 2); rm.MapH = Math.Min(Rnd.Int(rmdef.GetMinHeight(), rmdef.GetMaxHeight()), level.Height - 2); rm.MapX = (int) Math.Ceiling((level.Width - rm.MapW) / 2f); rm.MapY = (int) Math.Ceiling((level.Height - rm.MapH) / 2f); rm.UpdateSize(); rmdef.Set(rm.MapX, rm.MapY, rm.MapX + rm.MapW - 1, rm.MapY + rm.MapH - 1); Painter.Fill(level, new Rect(0, 0, level.Width, level.Height), Tile.WallA); Painter.Fill(level, rmdef, 1, Tile.FloorA); rmdef.PaintFloor(level); rmdef.Paint(level, rm); rmdef.PlaceMage(rm, this); foreach (var p in Area.Tagged[Tags.Player]) { var s = new SpawnPoint(); Area.Add(s); rmdef.PlacePlayer(rm, (Player) p); s.Center = p.Center; AnimationUtil.TeleportIn(p); } Painter.ReplaceTiles(level, rmdef); Painter.UpdateTransition(level); level.TileUp(); level.RecreateBody(); Engine.Instance.Flash = 2f; for (var i = 0; i < level.Size; i++) { level.Light[i] = 1f; } AnimationUtil.TeleportIn(this); }, 1f); }); } private int counter; #region DM States public class IdleState : SmartState { public override void Init() { base.Init(); Self.TouchDamage = 0; } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Room.Tagged[Tags.Mob].Count > 1) { Become(); } } } public class FlyingState : SmartState { public override void Init() { base.Init(); Self.TouchDamage = 0; Self.GetComponent().Unhittable = true; Self.GetComponent().Tint.A = 140; Self.GetComponent().Float = true; } public override void Destroy() { base.Destroy(); Self.TouchDamage = 0; Self.GetComponent().Unhittable = false; Self.GetComponent().Tint.A = 255; Self.GetComponent().Float = false; } public override void Update(float dt) { base.Update(dt); Self.GetComponent().Unhittable = true; if (Self.GetComponent().Room.Tagged[Tags.Mob].Count <= 1) { Become(); } } } #endregion public override void PlaceRewards() { base.PlaceRewards(); Achievements.Unlock("bk:dm_no_more"); Done = false; Died = false; Target.RemoveComponent(); GetComponent().Start("lp_0", Target, () => { Timer.Add(() => { Run.ActualDepth = -1; Run.Depth = 1; Run.Loop++; Achievements.Unlock("bk:loop"); }, 1f); }); } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/IceQueen.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.assets.particle.custom; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.bk; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.entity.projectile.pattern; using BurningKnight.util; using Lens.entity; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss { public class IceQueen : Boss { private static Color tint = new Color(50, 60, 234, 200); public bool InSecondPhase { get { var p = GetComponent().Percent; return p > 0.33f && p <= 0.66f; } } public bool InThirdPhase => GetComponent().Percent <= 0.33f; public bool InFirstPhase => GetComponent().Percent > 0.66f; protected override void AddPhases() { base.AddPhases(); HealthBar.AddPhase(0.33f); HealthBar.AddPhase(0.66f); } public override void AddComponents() { base.AddComponents(); Width = 10; Height = 19; AddComponent(new SensorBodyComponent(1, 2, 8, 17)); var body = new RectBodyComponent(1, 18, 8, 1); AddComponent(body); body.KnockbackModifier = 0.5f; body.Body.LinearDamping = 3; AddAnimation("ice_queen"); SetMaxHp(550); } public void ModifyBuilder(ProjectileBuilder builder) { if (InThirdPhase) { builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); } } private void Animate() { GetComponent().Animate(); } public override void SelectAttack() { base.SelectAttack(); Become(); } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target == null) { Become(); } } private float lastFadingParticle; public override void Update(float dt) { base.Update(dt); if (Target != null) { GraphicsComponent.Flipped = Target.CenterX < CenterX; } lastFadingParticle -= dt; if (lastFadingParticle <= 0) { lastFadingParticle = 0.2f; var particle = new FadingParticle(GetComponent().Animation.GetCurrentTexture(), tint); Area.Add(particle); particle.Depth = Depth - 1; particle.Center = Center; } } private int counter; #region Ice Queen States protected class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (T >= (Self.InThirdPhase ? 1f : 3f)) { T = 0; switch (Self.counter) { case 0: { Become(); break; } case 1: { Become(); break; } case 3: { if (Self.InThirdPhase) { Become(); } else { Become(); } break; } case 2: case 4: { Become(); break; } case 5: { Become(); break; } case 6: { Become(); break; } case 7: { Become(); break; } } Self.counter = (Self.counter + 1) % (Self.InSecondPhase ? 7 : (Self.InThirdPhase ? 8 : 5)); } } } public class SpinCircleAttack : SmartState { private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (T >= 0.15f) { T = 0; var amount = 4; var builder = new ProjectileBuilder(Self, "small"); Self.ModifyBuilder(builder); for (var i = 0; i < amount; i++) { var a = Math.PI * 2 * ((float) i / amount) + Math.Cos(t * 0.8f) * Math.PI; builder.Slice = (t % 0.5f < 0.25f) ^ (i % 2 == 0) ? "small" : "big"; builder.Color = t % 1f < 0.5f ? ProjectileColor.Blue : ProjectileColor.Purple; builder.Shoot(a, 6f + t * 2).Build(); } Self.Animate(); } if (t >= 3f) { Become(); } } } public class BulletCircleAttack : SmartState { private List projectiles = new List(); private bool second; public override void Destroy() { base.Destroy(); foreach (var p in projectiles) { p.Break(); } } public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Become(); return; } if (T >= 0.15f) { T = 0; if (second) { var p = projectiles[0]; projectiles.RemoveAt(0); Self.GetComponent().Emit("mob_fire_static", pitch: (projectiles.Count / 16f - 0.5f) * 2); if (!p.Done) { p.BodyComponent.Velocity = MathUtils.CreateVector(p.AngleTo(Self.Target), 200f); } else { p.Break(); } if (projectiles.Count == 0) { Become(); } } else { var builder = new ProjectileBuilder(Self, projectiles.Count % 2 == 0 ? "circle" : "small"); Self.ModifyBuilder(builder); var p = builder.Shoot(Self.AngleTo(Self.Target), 0).Build(); p.Color = projectiles.Count % 2 == 0 ? ProjectileColor.Blue : ProjectileColor.Cyan; p.Center = Self.Center + MathUtils.CreateVector(projectiles.Count / 4f * Math.PI, 20 + projectiles.Count * 2); p.Depth = 1; Self.GetComponent().Emit("mob_flower_charging", pitch: projectiles.Count / 8f); projectiles.Add(p); if (projectiles.Count == 16) { second = true; } Self.Animate(); } } } } protected class ExplosiveBulletsState : SmartState { private const int SmallCount = 4; private const int InnerCount = 8; private int count; public override void Init() { base.Init(); T = 10f; } public override void Update(float dt) { base.Update(dt); if (T >= 1f) { T = 0; count++; var a = Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f) + (count == 1 ? 0 : Math.PI); var builder = new ProjectileBuilder(Self, "square") { LightRadius = 32f, Range = 5 }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); var projectile = builder.Shoot(a, 15f).Build(); Self.Animate(); projectile.Color = ProjectileColor.Red; projectile.Center += MathUtils.CreateVector(a, 8); var tt = 0f; ProjectileCallbacks.AttachUpdateCallback(projectile, (p, dtt) => { tt += dtt; if (tt >= 0.3f) { tt = 0; var s = projectile.BodyComponent.Velocity.Length(); if (s < 3f) { return; } var bb = new ProjectileBuilder(Self, "small") { Scale = Rnd.Float(0.8f, 1.2f) }; Self.ModifyBuilder(builder); var z = bb.Shoot(a - Math.PI + Rnd.Float(-0.1f, 0.1f), s).Build(); z.Center = projectile.Center; } }); ProjectileCallbacks.AttachUpdateCallback(projectile, SlowdownProjectileController.Make()); ProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => { for (var i = 0; i < SmallCount; i++) { var an = (float) (((float) i) / SmallCount * Math.PI * 2); var pp = new ProjectilePattern(CircleProjectilePattern.Make(4.5f, 10 * (i % 2 == 0 ? 1 : -1))) { Position = p.Center }; var bb = new ProjectileBuilder(Self, "small") { LightRadius = 32f }; bb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var j = 0; j < 4; j++) { var b = bb.Build(); pp.Add(b); b.Color = ProjectileColor.Red; } pp.Launch(an, 40); Self.Area.Add(pp); } var bbb = new ProjectileBuilder(Self, "snowflake") { Color = ProjectileColor.Cyan }; bbb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < InnerCount; i++) { bbb.Scale = Rnd.Float(0.5f, 1f); var b = bbb.Shoot(Rnd.AnglePI(), Rnd.Float(10, 40)).Build(); b.Center = p.Center; ProjectileCallbacks.AttachUpdateCallback(b, SlowdownProjectileController.Make(Rnd.Float(0.5f, 4f))); } }); if (count == 2) { Become(); } } } } protected class SpamBulletsState : SmartState { private const int InnerCount = 32; private int count; public override void Init() { base.Init(); T = 10f; } public override void Update(float dt) { base.Update(dt); if (T >= 4f) { T = 0; count++; var a = Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f) + (count == 1 ? 0 : Math.PI); var builder = new ProjectileBuilder(Self, "big") { LightRadius = 32f }; builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); var projectile = builder.Shoot(a, 7).Build(); Self.Animate(); projectile.Color = ProjectileColor.Blue; projectile.Center += MathUtils.CreateVector(a, 8); ProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => { var bb = new ProjectileBuilder(Self, "snowflake") { Color = ProjectileColor.Blue, LightRadius = 32 }; bb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); bb.AddFlags(ProjectileFlags.AutomaticRotation); for (var i = 0; i < InnerCount; i++) { var b = bb.Shoot((float) i / InnerCount * Math.PI * 2, i % 2 == 0 ? 6 : 12).Build(); b.Center = p.Center; } }); if (count == 1) { Become(); } } } } protected class MoveState : SmartState { private Vector2 to; public override void Init() { base.Init(); to = Self.Target.Center; Self.Animate(); } public override void Destroy() { base.Destroy(); var aa = Self.AngleTo(Self.Target); Self.Animate(); var builder = new ProjectileBuilder(Self, "donut") { Scale = 1.5f, Color = ProjectileColor.Green, LightRadius = 32f }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var j = 0; j < 2; j++) { var projectile = builder.Shoot(aa + (j % 2 == 0 ? -1 : 1) * 0.3f, 14f).Build(); projectile.Center += MathUtils.CreateVector(aa, 8); ProjectileCallbacks.AttachDeathCallback(projectile, (p, e, t) => { var v = p.GetAnyComponent().Velocity; var a = v.ToAngle() - (float) Math.PI; var s = v.Length(); var c = p.HasComponent(); var b = new ProjectileBuilder(Self, p.Slice) { Parent = p, Scale = p.Scale * Rnd.Float(0.4f, 1.5f) }; Self.ModifyBuilder(b); for (var i = 0; i < Rnd.Int(3, 5); i++) { b.Shoot(a + Rnd.Float(-1.4f, 1.4f), s * Rnd.Float(0.3f, 1.5f)).Build().Center = p.Center; } }); } } public override void Update(float dt) { base.Update(dt); var dx = Self.DxTo(to); var dy = Self.DyTo(to); var d = MathUtils.Distance(dx, dy); if (d <= 16f) { Become(); } else { var s = 120 * dt / d; Self.Position += new Vector2(dx * s, dy * s); } } } #endregion public override void PlaceRewards() { base.PlaceRewards(); Achievements.Unlock("bk:ice_boss"); } public override string GetScream() { return "ice_queen_scream"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/OldKing.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.entity.projectile.pattern; using BurningKnight.level; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util.camera; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss { public class OldKing : Boss { public bool Raging => GetComponent().Percent <= 0.25f; protected override void AddPhases() { base.AddPhases(); HealthBar.AddPhase(0.25f); } public override void AddComponents() { base.AddComponents(); Width = 19; Height = 27; AddComponent(new SensorBodyComponent(2, 10, 14, 17)); var body = new RectBodyComponent(2, 26, 14, 1); AddComponent(body); body.KnockbackModifier = 0.05f; body.Body.LinearDamping = 1; AddComponent(new ZComponent { Gravity = 2 }); AddComponent(new ZAnimationComponent("old_king")); SetMaxHp(100); } private float lastParticle; public override void Update(float dt) { base.Update(dt); lastParticle -= dt; if (lastParticle <= 0) { lastParticle = 0.1f; if (!IsFriendly()) { Area.Add(new FireParticle { Offset = new Vector2(-2, -13), Owner = this, Size = 0.5f, Depth = Depth + 1 }); Area.Add(new FireParticle { Offset = new Vector2(2, -13), Owner = this, Size = 0.5f, Depth = Depth + 1 }); } } } public override bool ShouldCollide(Entity entity) { if (entity is Chasm) { return true; } return base.ShouldCollide(entity); } public override bool InAir() { var state = GetComponent().StateInstance; return state is UpState || state is DownState; } #region Old King States private int lastAttack; protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target == null) { Become(); } } public class IdleState : SmartState { public override void Update(float dt) { if (Self.Target == null) { return; } base.Update(dt); if (T >= (Self.Raging ? 1f : 2f)) { if (Rnd.Chance(95)) { Self.lastAttack = (Self.lastAttack + 1) % 2; } if (Self.lastAttack == 0) { Become(); } else { Become(); } } } } public class SkullAttack : SmartState { private int count; public override void Update(float dt) { base.Update(dt); if ((count + 1) * (Self.Raging ? 0.7f : 1.5f) <= T) { count++; if (Self.Target == null || Self.Died) { return; } var a = Self.GetComponent(); Self.GetComponent().EmitRandomized("mob_oldking_shoot"); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f); if (Self.Target == null || Self.Died) { return; } var builder = new ProjectileBuilder(Self, "skull") { Range = 5f }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); var skull = builder.Shoot(Self.AngleTo(Self.Target), 8).Build(); ProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => { if (!t) { return; } Camera.Instance.ShakeMax(8); var b = new ProjectileBuilder(Self, "small"); b.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < 8; i++) { var bullet = b.Shoot(((float) i) / 4 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build(); bullet.Center = p.Center; } }); ProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(Self.Target, 0.5f)); skull.GetComponent().IgnoreRotation = true; if (count == (Self.Raging ? 6 : 4)) { Self.Become(); } }; } } } public class JumpState : SmartState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Become(); Self.GetComponent().EmitRandomized("mob_oldking_jump"); } } } public class UpState : SmartState { public override void Init() { base.Init(); var a = Self.Target == null || (!Self.Raging && Rnd.Chance()) ? Rnd.AnglePI() : Self.AngleTo(Self.Target) + Rnd.Float(-0.1f, 0.1f); var force = Rnd.Float(20f) + (Self.Raging ? 240 : 120); Self.GetComponent().Velocity = new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); Self.GetComponent().ZVelocity = 10; Self.TouchDamage = 0; Self.Depth = Layers.FlyingMob; } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().ZVelocity <= 0) { Become(); } } } public class DownState : SmartState { public override void Destroy() { base.Destroy(); Self.TouchDamage = 1; Self.Depth = Layers.Creature; } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Z <= 0) { Become(); } } } private int jumpCounter; public class LandState : SmartState { private const int SmallCount = 8; private const int InnerCount = 8; public override void Init() { base.Init(); var a = Self.GetComponent(); a.SetAutoStop(true); Camera.Instance.ShakeMax(12); Self.GetComponent().EmitRandomized("mob_oldking_land"); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f); }; Self.GetComponent().Velocity = Vector2.Zero; var bb = new ProjectileBuilder(Self, "small"); bb.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < SmallCount; i++) { var an = (float) (((float) i) / SmallCount * Math.PI * 2); var pp = new ProjectilePattern(CircleProjectilePattern.Make(4.5f, 10 * (i % 2 == 0 ? 1 : -1))) { Position = Self.BottomCenter }; for (var j = 0; j < 2; j++) { pp.Add(bb.Build()); } pp.Launch(an, 40); Self.Area.Add(pp); } var aa = Self.AngleTo(Self.Target); var builder = new ProjectileBuilder(Self, "small") { Color = ProjectileColor.Green, Bounce = 2 }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < InnerCount; i++) { builder.Scale = Rnd.Float(0.5f, 1f); var b = builder.Shoot(aa + Rnd.Float(-0.3f, 0.3f), Rnd.Float(2, 12)).Build(); b.Center = Self.BottomCenter; } } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); var animation = Self.GetComponent().Animation; if (animation.Paused) { if (Self.Raging) { if (Self.jumpCounter < 2) { Become(); Self.jumpCounter++; return; } Self.jumpCounter = 0; } Become(); } } } #endregion public override void SelectAttack() { base.SelectAttack(); Become(); } public override void PlaceRewards() { base.PlaceRewards(); Achievements.Unlock("bk:democracy"); } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/Pharaoh.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.desert; using BurningKnight.entity.projectile; using BurningKnight.entity.room.controllable; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util.geometry; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; namespace BurningKnight.entity.creature.mob.boss { public class Pharaoh : Boss { public bool InSecondPhase { get { var p = GetComponent().Percent; return p > 0.33f && p <= 0.66f; } } public bool InThirdPhase => GetComponent().Percent <= 0.33f; public bool InFirstPhase => GetComponent().Percent > 0.66f; public int Phase => (InThirdPhase ? 3 : (InSecondPhase ? 2 : 1)); private int lastPhase = 1; public override void AddComponents() { base.AddComponents(); Width = 15; Height = 18; AddComponent(new SensorBodyComponent(1, 1, 13, 17)); var body = new RectBodyComponent(2, 17, 11, 1); AddComponent(body); body.KnockbackModifier = 0.1f; body.Body.LinearDamping = 4; AddAnimation("pharaoh"); SetMaxHp(250); } protected override void AddPhases() { base.AddPhases(); HealthBar.AddPhase(0.33f); HealthBar.AddPhase(0.66f); } private float lastParticle; private float t; public override void Update(float dt) { base.Update(dt); lastParticle -= dt; t += dt; if (lastParticle <= 0) { lastParticle = 0.1f; if (!IsFriendly()) { Area.Add(new FireParticle { Offset = new Vector2(-2, -11), Owner = this, Size = 0.5f, Depth = Depth + 1 }); Area.Add(new FireParticle { Offset = new Vector2(2, -11), Owner = this, Size = 0.5f, Depth = Depth + 1 }); if (Died) { return; } var p = Phase; if (lastPhase != p) { lastPhase = p; Become(); } } } } public override void SelectAttack() { base.SelectAttack(); Become(); } private int counter; protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target == null) { Become(); } } #region Pharaoh States public class IdleState : SmartState { public override void Update(float dt) { if (Self.Target == null) { return; } base.Update(dt); if (T >= (Self.InThirdPhase ? 0.01f : 0.3f)) { var v = Self.counter; if (v == 0) { Become(); } else if (v == 1) { if (Self.InThirdPhase) { Become(); } else { Become(); } } else if (v == 2) { Become(); } else if (v == 3) { Become(); } else if (v == 4) { Become(); } else if (v == 5) { Become(); } else if (v == 6) { if (Self.InThirdPhase) { Become(); } else { Become(); } } Self.counter = (v + 1) % 7; } } } public class SimpleSpiralState : SmartState { private float sinceLast; private int count; public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast <= 0) { sinceLast = 0.2f; var amount = 2 + (Self.Phase - 1); var builder = new ProjectileBuilder(Self, "small"); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < amount; i++) { var a = Math.PI * 2 * ((float) i / amount) + Math.Cos(Self.t * 0.8f) * Math.PI; builder.Color = count % 4 == 0 ? ProjectileColor.Orange : ProjectileColor.Red; builder.Scale = count % 2 == 0 ? 1.5f : 2f; builder.Shoot(a, 8f).Build(); } Self.GetComponent().EmitRandomized("mob_pharaoh_shot"); count++; } if (T >= 8f) { Become(); } } } public class AdvancedSpiralState : SmartState { private float sinceLast; private int count; public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast <= 0) { sinceLast = Self.InFirstPhase ? 0.6f : 0.4f; var amount = 8; var builder = new ProjectileBuilder(Self, "small") { Scale = 1.5f }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < amount; i++) { var a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 1) * Math.PI * 0.25f) * (i % 2 == 1 ? -1 : 1); builder.Color = ProjectileColor.DesertRainbow[count % ProjectileColor.DesertRainbow.Length]; builder.Shoot(a, 6f + (float) Math.Cos(Self.t * 1) * 2f).Build(); } Self.GetComponent().EmitRandomized("mob_pharaoh_shot_wave"); count++; } if (T >= 10f) { Become(); } } } public class BulletHellState : SmartState { private float sinceLast; public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast <= 0) { sinceLast = Self.InFirstPhase ? 0.4f : 0.2f; var amount = 4; var builder = new ProjectileBuilder(Self, "small") { Scale = 1.5f }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < amount; i++) { builder.Color = ProjectileColor.DesertRainbow[Rnd.Int(ProjectileColor.DesertRainbow.Length)]; var a = Math.PI * 2 * ((float) i / amount) + (Math.Cos(Self.t * 2f) * Math.PI) * (i % 2 == 0 ? -1 : 1); builder.Shoot(a, 7f + (float) Math.Cos(Self.t * 2f) * 2f).Build(); } } if (T >= 10f) { Become(); } } } public class TileMoveState : SmartState { private Dot PickDot() { var room = Self.GetComponent().Room; var attempt = 0; var toCheck = new List(); toCheck.Add(Self); toCheck.AddRange(room.Tagged[Tags.Player]); Dot spot; do { spot = new Dot(Rnd.Int(room.MapX + 3, room.MapX + room.MapW - 3), Rnd.Int(room.MapY + 3, room.MapY + room.MapH - 3)); var vector = spot * 16 + new Vector2(8, 8); var found = false; foreach (var e in toCheck) { if (e.DistanceTo(vector) <= 48f) { found = true; break; } } if (!found) { return spot; } if (attempt++ > 30) { Become(); return null; } } while (true); return spot; } public override void Init() { base.Init(); var spot = PickDot(); var to = PickDot(); if (spot == null || to == null) { return; } var sx = Rnd.Int(1, 4); var sy = Rnd.Int(1, 4); for (var x = sx > 2 ? -1 : 0; x < sx; x++) { for (var y = sy > 2 ? -1 : 0; y < sy; y++) { var x1 = x; var y1 = y; Timer.Add(() => { var part = new TileParticle(); part.FromBottom = true; part.Top = Run.Level.Tileset.FloorA[0]; part.TopTarget = Run.Level.Tileset.WallTopADecor; part.Side = Run.Level.Tileset.WallA[0]; part.Sides = Run.Level.Tileset.WallSidesA[2]; part.Tile = Tile.WallA; part.X = (spot.X + x1) * 16; part.Y = (spot.Y + y1) * 16 + 8; part.Target.X = (to.X + x1) * 16; part.Target.Y = (to.Y + y1) * 16 + 8; Self.Area.Add(part); }, Rnd.Float(1f)); } } } public override void Update(float dt) { base.Update(dt); if (T >= 4f) { Become(); } } } public class SwitchPhaseState : SmartState { public override void Init() { base.Init(); var am = 24; var builder = new ProjectileBuilder(Self, "small"); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var j = 0; j < 2; j++) { var j1 = j; Timer.Add(() => { var z = (j1 == 0 ? am : am / 2); for (var i = 0; i < z; i++) { var a = Math.PI * 2 * ((i + j1 * 0.5f) / z); builder.Scale = j1 == 0 ? 1f : 2f; builder.Shoot(a, 7f + j1 * 2).Build(); } Self.GetComponent().EmitRandomized("mob_pharaoh_shot"); }, j); } Become(); } public override void Update(float dt) { base.Update(dt); if (T >= 2f) { Become(); } } } public class SummoningState : SmartState { private bool summoned; public override void Update(float dt) { base.Update(dt); if (!summoned && T >= 1f) { summoned = true; var amount = Self.InThirdPhase ? 4 : 2; var d = 16; for (var i = 0; i < amount; i++) { var i1 = i; Timer.Add(() => { Self.GetComponent().EmitRandomized("mob_pharaoh_summon"); var mummy = new Mummy(); Self.Area.Add(mummy); mummy.BottomCenter = Self.BottomCenter + MathUtils.CreateVector(i1 / (float) amount * Math.PI * 2, d); mummy.GetComponent().Become(); }, i * 0.5f); } } else if (summoned && T >= 2f) { Become(); } } } public class TeleportState : SmartState { public override void Init() { base.Init(); Self.GetComponent().EmitRandomized("mob_pharaoh_adidos"); Tween.To(0, 255, x => Self.GetComponent().Tint.A = (byte) x, 0.5f).OnEnd = () => { var tile = Self.GetComponent().Room.GetRandomWallFreeTile() * 16; Self.BottomCenter = tile + new Vector2(8, 8); Self.GetComponent().EmitRandomized("mob_pharaoh_appear"); Tween.To(255, 0, x => Self.GetComponent().Tint.A = (byte) x, 0.5f).OnEnd = () => { Become(); }; }; } } #endregion public override void PlaceRewards() { base.PlaceRewards(); Achievements.Unlock("bk:mummified"); } public override string GetScream() { return "pharaoh_scream"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/QueenBee.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.jungle; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.entity.projectile.pattern; using BurningKnight.level; using BurningKnight.level.entities; using Lens.entity; using Lens.util; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss { public class QueenBee : Boss { public bool InSecondPhase { get { var p = GetComponent().Percent; return p > 0.33f && p <= 0.66f; } } public bool InThirdPhase => GetComponent().Percent <= 0.33f; public bool InFirstPhase => GetComponent().Percent > 0.66f; public int Phase => (InThirdPhase ? 3 : (InSecondPhase ? 2 : 1)); private int lastPhase = 1; private float lastParticle; private int penetrateCount; private int attack; private bool changingPhase; public override void AddComponents() { base.AddComponents(); Width = 23; Height = 19; AddComponent(new SensorBodyComponent(1, 4, 21, 14)); var body = new RectBodyComponent(2, 17, 19, 1); AddComponent(body); body.Body.LinearDamping = 3; AddAnimation("bigbee"); SetMaxHp(340); Flying = true; Depth = Layers.FlyingMob; } protected override void AddPhases() { base.AddPhases(); HealthBar.AddPhase(0.33f); HealthBar.AddPhase(0.66f); } public override void Update(float dt) { base.Update(dt); lastParticle -= dt; if (lastParticle <= 0) { lastParticle = 0.1f; if (!IsFriendly()) { var s = GraphicsComponent.Flipped ? -1 : 1; Area.Add(new FireParticle { Offset = new Vector2(6 * s, -5.5f), Owner = this, Size = 0.5f, Depth = Depth + 1 }); Area.Add(new FireParticle { Offset = new Vector2(9 * s, -5.5f), Owner = this, Size = 0.5f, Depth = Depth + 1 }); if (Died) { return; } var p = Phase; if (lastPhase != p) { lastPhase = p; changingPhase = true; Become(); } } } } public void ModifyBuilder(ProjectileBuilder builder) { if (InThirdPhase) { builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); } } #region Queen Bee States public override void SelectAttack() { base.SelectAttack(); Become(); } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target == null) { Become(); } } public class IdleState : SmartState { public override void Update(float dt) { if (Self.Target == null) { return; } base.Update(dt); if (T >= 0.2f) { if (Self.penetrateCount != 0) { Become(); } else { var a = Self.attack = (Self.attack + 1) % (Self.InFirstPhase ? 3 : 4); if (a == 1) { Self.penetrateCount++; } else if (a == 2) { Become(); } else if (a == 3) { Become(); } else if (a == 0) { if (Self.InSecondPhase || (Self.InThirdPhase && Rnd.Chance())) { Become(); } else { Become(); } } } } } } public class MachineGunState : SmartState { private float sinceLast; public override void Update(float dt) { base.Update(dt); sinceLast += dt; if (sinceLast >= 0.5f) { sinceLast = 0; var a = Self.AngleTo(Self.Target); var second = Self.InThirdPhase; for (var i = 0; i < (second ? 1 : 3); i++) { var i1 = i; Timer.Add(() => { if (second) { var pp = new ProjectilePattern(CircleProjectilePattern.Make(9f, i1 % 2 == 0 ? -10 : 10)) { Position = Self.Center }; var builder = new ProjectileBuilder(Self, "small") { LightRadius = 32f }; Self.ModifyBuilder(builder); for (var j = 0; j < 4; j++) { builder.Slice = j % 2 == 0 ? "circle" : "small"; builder.Color = j % 2 == 0 ? ProjectileColor.Orange : ProjectileColor.Red; pp.Add(builder.Build()); } pp.Launch(a, 80); Self.Area.Add(pp); } else { var builder = new ProjectileBuilder(Self, "circle") { Scale = Rnd.Float(0.8f, 1f), Color = Rnd.Chance() ? ProjectileColor.Yellow : ProjectileColor.Orange, LightRadius = 64 }; Self.ModifyBuilder(builder); builder.Shoot(a + Rnd.Float(-0.1f, 0.1f), 30f).Build(); } Self.GetComponent().EmitRandomized("mob_bee_shot"); }, i * 0.15f); } } var t = T + Math.PI * 0.5f; var r = Self.GetComponent().Room; var x = r.CenterX + (float) Math.Cos(t) * (r.Width * 0.4f); var y = r.CenterY - r.Height * 0.2f + (float) Math.Sin(t * 2) * (r.Height * 0.2f); var dx = x - Self.CenterX; var dy = y - Self.CenterY; var s = (dt * 10); Self.CenterX += dx * s; Self.CenterY += dy * s; Self.GraphicsComponent.Flipped = dx < 0; if (t >= Math.PI * 4.5f) { Become(); } } } public class PrepareToPenetrateState : SmartState { private float x; private bool locked; public override void Init() { base.Init(); Self.penetrateCount++; var r = Self.GetComponent().Room; if (r.CenterX > Self.CenterX) { x = r.X + 32; } else { x = r.Right - 32; } } public override void Update(float dt) { base.Update(dt); if (locked) { if (T >= 0.3f) { Become(); } return; } var body = Self.GetComponent(); body.Velocity += new Vector2((x > Self.CenterX ? 1 : -1) * dt * 360, 0); var py = Self.Target.CenterY; var sy = Self.CenterY; body.Velocity += new Vector2(0, (py > sy ? 1 : -1) * dt * 360); if (Math.Abs(py - sy) < 6 && Math.Abs(x - Self.CenterX) < 16) { Self.GraphicsComponent.Flipped = !Self.GraphicsComponent.Flipped; locked = true; T = 0; body.Velocity = Vector2.Zero; } } } public class CircleState : SmartState { private float sinceLast; public override void Update(float dt) { base.Update(dt); sinceLast += dt; var t = T * (Self.InSecondPhase ? 1.5f : 2f); if (sinceLast >= 0.15f) { sinceLast = 0; var builder = new ProjectileBuilder(Self, "circle") { Scale = Rnd.Float(0.5f, 1f), LightRadius = 64 }; Self.ModifyBuilder(builder); builder.Shoot(t + Math.PI + Rnd.Float(-0.1f, 0.1f), Rnd.Float(4f, 10f)).Build(); } var r = Self.GetComponent().Room; var x = Self.Target.CenterX + (float) Math.Cos(t) * (r.Width * 0.3f); var y = Self.Target.CenterY + (float) Math.Sin(t) * (r.Height * 0.3f); var dx = x - Self.CenterX; var dy = y - Self.CenterY; var s = (dt * 4); Self.CenterX += dx * s; Self.CenterY += dy * s; Self.GraphicsComponent.Flipped = dx < 0; if (t >= Math.PI * 6f) { Become(); } } } public class PenetrateState : SmartState { private float x; private float sign; private float delay = 1; private float lastBullet; public override void Init() { base.Init(); var r = Self.GetComponent().Room; if (r.CenterX < Self.CenterX) { x = r.X + 32; sign = -1; } else { x = r.Right - 32; sign = 1; } Camera.Instance.Shake(10); } public override void Destroy() { base.Destroy(); var v = Self.penetrateCount; var max = 2 + Self.Phase * 2; if (v == max) { Self.penetrateCount = 0; } } public override void Update(float dt) { base.Update(dt); var body = Self.GetComponent(); if ((Self.CenterX - x) * sign >= -16) { body.Velocity -= body.Velocity * (dt * 2); delay -= dt; if (delay <= 0) { Become(); } return; } if (!Self.InFirstPhase) { lastBullet -= dt; if (lastBullet <= 0) { lastBullet = 0.2f; var a = (sign < 0 ? Math.PI : 0) + Rnd.Float(-1f, 1f); var builder = new ProjectileBuilder(Self, "circle") { Bounce = 5, Color = ProjectileColor.Orange, LightRadius = 64, Scale = Rnd.Float(0.6f, 2f) }; Self.ModifyBuilder(builder); var p = builder.Shoot(a, Rnd.Float(3f, 10f)).Build(); ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.25f)); Self.GetComponent().EmitRandomized("mob_bee_shot"); } } Self.X += sign * dt * 360; body.Velocity += new Vector2(sign * dt * 3600, 0); } } public class ToCenterState : SmartState { public override void Update(float dt) { base.Update(dt); var r = Self.GetComponent().Room; var dx = r.CenterX - Self.CenterX; var dy = r.CenterY - Self.CenterY; var d = MathUtils.Distance(dx, dy); if (d <= 32f) { if (Self.changingPhase) { Self.changingPhase = false; Become(); } else { Become(); } return; } var s = (dt * 3600 / d) * (d > 48 ? 1 : d / 48); Self.GetComponent().Velocity += new Vector2(dx * s, dy * s); } } public class SpamBeesState : SmartState { private float sinceLast; private int count; public override void Update(float dt) { base.Update(dt); if (count < 5) { sinceLast += dt; if (sinceLast >= 1f - Self.Phase * 0.25f) { sinceLast = 0; count++; var bee = BeeHive.GenerateBee(); Self.Area.Add(bee); bee.Center = Self.Center; Self.GetComponent().Animate(); } T = 0; } if (T >= 1) { Become(); } } } public class RageState : SmartState { private int count; public override void Init() { base.Init(); Camera.Instance.Shake(10); } public override void Update(float dt) { base.Update(dt); if (T >= 0.1f) { count++; T = 0; if (count == 32) { Become(); return; } var a = (count * 3 / 8f * Math.PI) + Rnd.Float(-0.5f, 0.5f); var builder = new ProjectileBuilder(Self, "circle") { Scale = Rnd.Float(1f, 2f), Color = Rnd.Chance() ? ProjectileColor.Yellow : ProjectileColor.Orange, LightRadius = 64 }; Self.ModifyBuilder(builder); builder.Shoot(a, 30f).Build(); Camera.Instance.Shake(2); Self.GetComponent().EmitRandomized("mob_bee_swirly_shot"); } } } #endregion public override bool ShouldCollide(Entity entity) { if (entity is Prop) { return false; } return base.ShouldCollide(entity) && !(entity is Level); } public override void PlaceRewards() { base.PlaceRewards(); Achievements.Unlock("bk:sting_operation"); } public override string GetScream() { return "queen_bee_scream"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmBulletDodgeRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.entity.room.controllable.turret; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.util.geometry; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmBulletDodgeRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { mage.BottomCenter = new Vector2((Right - 1) * 16 - 8, GetTileCenter().Y * 16 + 8); } public override void PlacePlayer(Room room, Player player) { player.BottomCenter = new Vector2((Left + 1) * 16 + 8, GetTileCenter().Y * 16 + 8); } public override void Paint(Level level, Room room) { var x = (Right - 2) * 16 - 8; var wall = Tiles.Pick(Tile.WallA, Tile.EvilWall); Painter.DrawLine(level, new Dot(Left + 1, Top + 1), new Dot(Right - 7, Top + 1), wall); Painter.DrawLine(level, new Dot(Left + 1, Bottom - 1), new Dot(Right - 7, Bottom - 1), wall); for (var y = Top + 2; y < Bottom - 1; y++) { var turret = new Turret { StartingAngle = 4 }; level.Area.Add(turret); turret.BottomCenter = new Vector2(x, y * 16 + 12); } } public override int GetMinWidth() { return 30; } public override int GetMinHeight() { return 8; } public override int GetMaxWidth() { return 40; } public override int GetMaxHeight() { return 13; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmEndRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmEndRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { mage.Center = room.Center; } public override void PlacePlayer(Room room, Player player) { player.Center = room.Center + new Vector2(0, 32); } public override void Paint(Level level, Room room) { } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmEnemyRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.tile; using BurningKnight.util.geometry; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmEnemyRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { mage.Center = GetTileCenter() * 16 - new Vector2(0, 64); } public override void PlacePlayer(Room room, Player player) { player.Center = GetTileCenter() * 16; } public override void Paint(Level level, Room room) { var c = GetCenter(); Painter.Fill(level, new Rect().Setup(c.X - 2, c.Y - 2, 5, 5), Tile.WallA); Painter.Fill(level, new Rect().Setup(c.X - 1, c.Y - 1, 3, 3), Tiles.RandomFloor()); var placed = false; if (Rnd.Chance()) { placed = true; Painter.Set(level, new Dot(c.X, c.Y - 2), Tiles.RandomFloor()); } if (Rnd.Chance()) { placed = true; Painter.Set(level, new Dot(c.X, c.Y + 2), Tiles.RandomFloor()); } if (Rnd.Chance()) { placed = true; Painter.Set(level, new Dot(c.X - 2, c.Y), Tiles.RandomFloor()); } if (!placed || Rnd.Chance()) { Painter.Set(level, new Dot(c.X + 2, c.Y), Tiles.RandomFloor()); } Painter.Set(level, new Dot(c.X, c.Y), Tile.FloorD); // Tiles.RandomFloor()); MobRegistry.SetupForBiome(Biome.Tech); Painter.PlaceMobs(level, room); } public override float GetWeightModifier() { return 0.25f; } public override int GetMinWidth() { return 20; } public override int GetMinHeight() { return 20; } public override int GetMaxWidth() { return 30; } public override int GetMaxHeight() { return 30; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmMazeRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmMazeRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { mage.BottomCenter = room.GetRandomFreeTile() * 16 + new Vector2(8); } public override void PlacePlayer(Room room, Player player) { player.BottomCenter = room.GetRandomFreeTile() * 16 + new Vector2(8); } public override void Paint(Level level, Room room) { var maze = Maze.Generate(this); var wall = Tile.WallA; for (int x = 1; x < maze.Length - 1; x++) { for (int y = 1; y < maze[0].Length - 1; y++) { if (maze[x][y]) { Painter.Set(level, x + Left, y + Top, wall); } } } } public override int GetMinWidth() { return 30; } public override int GetMinHeight() { return 30; } public override int GetMaxWidth() { return 20; } public override int GetMaxHeight() { return 20; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmPadsRoom.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.util.geometry; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmPadsRoom : DmRoom { private Dot magePos; private Dot playerPos; public override void PlaceMage(Room room, DM mage) { mage.BottomCenter = magePos * 16 + new Vector2(8); } public override void PlacePlayer(Room room, Player player) { player.BottomCenter = playerPos * 16 + new Vector2(8); } public override void PaintFloor(Level level) { } public override void Paint(Level level, Room room) { Painter.Fill(level, this, Tile.WallA); Painter.Fill(level, this, 1, Tile.Chasm); var gap = 2; var xcollumn = Rnd.Int(2, 5); var ycollumn = Rnd.Chance(20) ? Rnd.Int(2, 5) : xcollumn; var w = GetWidth(); var h = GetHeight(); var gx = (gap + xcollumn); var gy = (gap + ycollumn); var xcount = (int) Math.Ceiling((w - (float) xcollumn) / gx); var ycount = (int) Math.Ceiling((h - (float) ycollumn) / gy); var xw = xcount * gx - xcollumn; var yw = ycount * gy - ycollumn; var xo = (int) Math.Min(Math.Floor((w - xw) / 2f), 2); var yo = (int) Math.Min(Math.Floor((h - yw) / 2f), 2); var spots = new List(); for (var x = 0; x < xcount; x++) { for (var y = 0; y < ycount; y++) { spots.Add(new Dot(Left + xo + x * gx, Top + yo + y * gy)); } } var i = Rnd.Int(spots.Count); magePos = spots[i] + new Dot(1); Painter.Fill(level, new Rect(magePos.X - 1, magePos.Y - 1).Resize(Math.Max(3, xcollumn), Math.Max(3, ycollumn)), Tiles.RandomFloor()); Painter.Set(level, magePos.X - 1, magePos.Y - 1, Tile.WallA); Painter.Set(level, magePos.X + 1, magePos.Y - 1, Tile.WallA); Painter.Set(level, magePos.X - 1, magePos.Y + 1, Tile.WallA); Painter.Set(level, magePos.X + 1, magePos.Y + 1, Tile.WallA); spots.RemoveAt(i); i = Rnd.Int(spots.Count); playerPos = spots[i] + new Dot(1); Painter.Fill(level, new Rect(playerPos.X - 1, playerPos.Y - 1).Resize(xcollumn, ycollumn), Tiles.RandomFloor()); spots.RemoveAt(i); foreach (var s in spots) { Painter.Fill(level, new Rect(s.X, s.Y).Resize(xcollumn, ycollumn), Rnd.Chance(5) ? Tiles.RandomFloor() : Tile.SensingSpikeTmp); } } public override int GetMinWidth() { return 20; } public override int GetMinHeight() { return 20; } public override int GetMaxWidth() { return 28; } public override int GetMaxHeight() { return 28; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmPlatformRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.entity.room.controllable.platform; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.util.geometry; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmPlatformRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { mage.BottomCenter = new Dot(Right - 2, Bottom - 2) * 16 + new Vector2(8); } public override void PlacePlayer(Room room, Player player) { player.BottomCenter = new Dot(Left + 2, Top + 2) * 16 + new Vector2(8); } public override void Paint(Level level, Room room) { Painter.Fill(level, this, 1, Tile.Chasm); Painter.Fill(level, new Rect().Setup(Left + 1, Top + 1, 2, 2), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Left + 1, Top + GetHeight() / 2, 2, 2), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Left + 1, Bottom - 2, 2, 2), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Right - 2, Top + 1, 2, 2), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Right - 2, Top + GetHeight() / 2, 2, 2), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Right - 3, Bottom - 3, 3, 3), Tiles.RandomFloor()); Painter.Fill(level, new Rect().Setup(Right - 3, Bottom - 3, 2, 2), Tile.WallA); Painter.Fill(level, new Rect().Setup(Right - 2, Bottom - 2, 2, 2), Tiles.RandomFloor()); Platform(level, Left + 3, Top + 1); Platform(level, Right - 4, Top + GetHeight() / 2); Platform(level, Left + 3, Bottom - 2); Platform(level, Right - 2, Top + GetHeight() / 2 - 3, true); Platform(level, Left + 1, Top + GetHeight() / 2 + 5, true); } private void Platform(Level level, int x, int y, bool vertical = false) { level.Area.Add(new MovingPlatform { Controller = vertical ? PlatformController.UpDown : PlatformController.LeftRight, Position = new Vector2(x, y) * 16 }); } public override int GetMinWidth() { return 16; } public override int GetMinHeight() { return 20; } public override int GetMaxWidth() { return 17; } public override int GetMaxHeight() { return 21; } } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.rooms.regular; namespace BurningKnight.entity.creature.mob.boss.rooms { public abstract class DmRoom : RegularRoom { public abstract void PlaceMage(Room room, DM mage); public abstract void PlacePlayer(Room room, Player player); public abstract void Paint(Level level, Room room); } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmRoomRegistry.cs ================================================ using System; namespace BurningKnight.entity.creature.mob.boss.rooms { public static class DmRoomRegistry { public static Type[] Rooms = { typeof(DmEnemyRoom), typeof(DmMazeRoom), typeof(DmBulletDodgeRoom), typeof(DmPlatformRoom), typeof(DmPadsRoom), typeof(DmSpikeRoom) }; } } ================================================ FILE: BurningKnight/entity/creature/mob/boss/rooms/DmSpikeRoom.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room; using BurningKnight.level; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util.geometry; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.boss.rooms { public class DmSpikeRoom : DmRoom { public override void PlaceMage(Room room, DM mage) { var w = new Dot(Rnd.Int(Left + 1, Right), Top + 2); Painter.Fill(Run.Level, new Rect().Setup(w.X - 1, w.Y - 1, 3, 2), Tile.FloorA); mage.BottomCenter = w * 16 + new Vector2(8, -8); Painter.DrawLine(Run.Level, new Dot(w.X - 1, w.Y), new Dot(w.X + 1, w.Y), Tile.WallA); } public override void PlacePlayer(Room room, Player player) { var w = new Dot(Rnd.Int(Left + 1, Right), Bottom - 1); Painter.Fill(Run.Level, new Rect().Setup(w.X - 1, w.Y - 1, 3, 2), Tile.FloorA); player.BottomCenter = w * 16 + new Vector2(8); } public override void Paint(Level level, Room room) { Painter.Fill(level, this, 1, Tile.SpikeOffTmp); room.AddController("bk:spike_field"); room.Generate(); } public override int GetMinWidth() { return 12; } public override int GetMinHeight() { return 15; } public override int GetMaxWidth() { return 17; } public override int GetMaxHeight() { return 23; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/BabySlime.cs ================================================ using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class BabySlime : Slime { private static readonly Color color = ColorUtils.FromHex("#0069aa"); protected override Color GetBloodColor() { return color; } protected override float GetJumpDelay() { return Rnd.Float(0.5f, 1.2f) - 0.2f; } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent("baby_slime")); SetMaxHp(1); var body = new RectBodyComponent(4, 9, 8, 7); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(new SensorBodyComponent(4, 15, 8, 1)); AddComponent(new LightComponent(this, 32, MotherSlime.LightColor)); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Bandit.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Bandit : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("bandit"); SetMaxHp(Run.Depth); Become(); var body = new RectBodyComponent(3, 13, 10, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(2, 2, 12, 12)); moveId = Rnd.Int(0, 2); } private int moveId; #region Bandit States public class IdleState : SmartState { private float delay; private float fireDelay; private bool fired; public override void Init() { base.Init(); delay = Rnd.Float(1, 2.5f); fireDelay = Self.moveId % 2 == 0 ? 3 : Rnd.Float(0.5f, delay - 0.5f); Self.moveId++; } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); return; } if (!fired && T >= fireDelay) { fired = true; if (!Self.CanSeeTarget()) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { return; } Self.GetComponent().EmitRandomized("mob_fire"); var ac = 0.1f; var angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); var p = new ProjectileBuilder(Self, "small") { Poof = true, LightRadius = 32f }; p.AddFlags(ProjectileFlags.FlyOverStones); p.Shoot(angle, 8f); p.Move(angle, 8f); p.Build(); }; }; } } } public class RunState : SmartState { private Vector2 velocity; private float timer; public override void Init() { base.Init(); timer = Rnd.Float(0.4f, 1f); var angle = Rnd.AnglePI(); var force = 120f + Rnd.Float(50f); if (Rnd.Chance() && Self.Target != null) { var ac = 0.1f; angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); } velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); } else { Self.GetComponent().Velocity = velocity * Math.Min(1, timer - T * 0.4f); } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_bandit_death"; } protected override string GetHurtSfx() { return "mob_bandit_damage"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/BigSlime.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.events; using Lens.util.math; namespace BurningKnight.entity.creature.mob.castle { public class BigSlime : Slime { protected override float GetJumpDelay() { return 1 + Rnd.Float(0.7f, 1.6f); } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent(GetSprite())); SetMaxHp(4); var body = new RectBodyComponent(1, 15, 14, 1); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(new SensorBodyComponent(2, 7, 12, 9)); } protected virtual string GetSprite() { return Events.Halloween ? "spooky_big_slime" : "big_slime"; } protected override bool HandleDeath(DiedEvent d) { if (Rnd.Chance(30)) { var slime = new SimpleSlime(); Area.Add(slime); slime.BottomCenter = BottomCenter; } return base.HandleDeath(d); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/BlueBulletSlime.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using Lens.graphics; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class BlueBulletSlime : BulletSlime { private static readonly Color color = ColorUtils.FromHex("#00cdf9"); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); SetMaxHp(4); } protected override string GetSprite() { return "blue_bullet_slime"; } protected override void DoSpit() { var am = 8; GetComponent().EmitRandomized("mob_fire"); var builder = new ProjectileBuilder(this, "small") { Color = ProjectileColor.Cyan, LightRadius = 32f }; for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am); var projectile = builder.Shoot(a + Rnd.Float(-0.1f, 0.1f), 5f).Build(); projectile.Center = BottomCenter; } Timer.Add(() => { if (GetComponent().Dead) { return; } GetComponent().EmitRandomized("mob_fire"); GetComponent().Animate(); var b = new ProjectileBuilder(this, "small") { Color = ProjectileColor.Blue, LightRadius = 48f }; b.AddFlags(ProjectileFlags.FlyOverStones); b.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am + 0.5f); var projectile = b.Shoot(a + Rnd.Float(-0.1f, 0.1f), 8f).Build(); projectile.Center = BottomCenter; projectile.Color = ProjectileColor.Blue; } }, 1f); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/BulletSlime.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class BulletSlime : Slime { private static readonly Color color = ColorUtils.FromHex("#ff0000"); protected override Color GetBloodColor() { return color; } protected override float GetJumpDelay() { return 1 + Rnd.Float(0.5f, 1.2f); } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent(GetSprite())); SetMaxHp(5); var body = new RectBodyComponent(1, 15, 14, 1); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(new SensorBodyComponent(2, 7, 12, 9)); } protected virtual string GetSprite() { return "bullet_slime"; } protected override void OnLand() { base.OnLand(); if (Target == null) { return; } DoSpit(); } protected virtual void DoSpit() { var am = 8; GetComponent().EmitRandomized("mob_fire"); var builder = new ProjectileBuilder(this, "small") { LightRadius = 32f }; for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am); var projectile = builder.Shoot(a, 5f).Build(); projectile.Center = BottomCenter; } } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Caster.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Caster : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("caster"); SetMaxHp(4); Become(); var body = new RectBodyComponent(8, 3, 8, 13); AddComponent(body); body.KnockbackModifier = 0.5f; body.Body.LinearDamping = 0; Width = 22; AddComponent(new LightComponent(this, 50f, new Color(1f, 1f, 0.7f, 1f))); } #region Caster States public class IdleState : SmartState { private float delay; private float lastBullet; public override void Init() { base.Init(); delay = Rnd.Float(0.5f, 2f); } public override void Update(float dt) { base.Update(dt); if (T < delay) { return; } lastBullet -= dt; if (lastBullet <= 0f) { lastBullet = 1f; if (Self.Target != null) { var an = Self.AngleTo(Self.Target); var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f); var builder = new ProjectileBuilder(Self, "caster") { Color = ProjectileColor.Blue, LightRadius = 32f, Poof = true }; builder.Move(an, 8); builder.AddFlags(ProjectileFlags.AutomaticRotation, ProjectileFlags.FlyOverStones, ProjectileFlags.FlyOverWalls); var projectile = builder.Shoot(an, 7f).Build(); ProjectileCallbacks.AttachUpdateCallback(projectile, MakeController()); }; } } if (T - delay >= 3f) { Become(); } } } private static ProjectileCallbacks.UpdateCallback MakeController() { var lastPart = 0f; return (pr, dt) => { lastPart += dt; if (lastPart >= 0.1f) { lastPart = 0; var p = new ProjectileParticle(); pr.Area.Add(p); p.Center = pr.Center; // + Random.Vector(3, 3); // give some velocity too?? } }; } /* * todo: * projectile particles * tween light radius when tp * delay between appear and dissappear * * dont collide when appearing/dissappearing */ public class DissappearState : SmartState { public override void Init() { base.Init(); Self.GetComponent().EmitRandomized("door_close"); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(); } } } public class AppearState : SmartState { public override void Init() { base.Init(); Self.Center = Self.GetComponent().Room.GetRandomFreeTile() * 16; Self.GetComponent().EmitRandomized("door_close"); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(); } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Clown.cs ================================================ using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Clown : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("clown"); SetMaxHp(3); Become(); var body = new RectBodyComponent(2, 15, 12, 1); AddComponent(body); body.KnockbackModifier = 2; body.Body.LinearDamping = 0; AddComponent(new SensorBodyComponent(2, 2, 12, 12)); AddDrops(new SingleDrop("bk:bomb", 0.1f)); TouchDamage = 0; } #region Clown States public class IdleState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Velocity = Vector2.Zero; } } public class RunState : SmartState { private Vector2 target; private float delay; private bool away; public override void Init() { base.Init(); T = 0; if (away) { target = Self.Center + MathUtils.CreateVector(Self.Target.AngleTo(Self) + Rnd.Float(-1, 1), 96f); delay = Rnd.Float(1f, 2f); return; } delay = Rnd.Float(0.3f, 1f); var toTarget = Self.Target != null && Rnd.Chance(); if (toTarget) { target = Self.Target.Center; } else { target = Self.GetComponent().Room.GetRandomFreeTile(); } } public override void Update(float dt) { base.Update(dt); var dx = Self.DxTo(target); var dy = Self.DyTo(target); var d = MathUtils.Distance(dx, dy); var s = dt * 150; var b = Self.GetComponent(); b.Velocity += new Vector2(dx / d * s, dy / d * s); if (d <= 8 || T >= delay) { if (away) { away = false; } Init(); } if (!away && Self.Target != null && Self.DistanceTo(Self.Target) < 32) { var bomb = new Bomb(Self, 1); Self.Area.Add(bomb); bomb.Center = Self.Center; bomb.VelocityTo(Self.AngleTo(Self.Target)); Self.GetComponent().EmitRandomizedPrefixed("mob_clown_bomb", 2); away = true; Init(); } } } #endregion public override bool HandleEvent(Event e) { if (e is ExplodedEvent ee) { if (ee.Who is Mob) { // GetComponent().ModifyHealth(2, null); return true; } } else if (e is MobTargetChange ev) { if (ev.New == null) { Become(); } else { Become(); } } return base.HandleEvent(e); } protected override string GetHurtSfx() { return "mob_clown_hurt"; } protected override string GetDeadSfx() { return "mob_clown_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Crab.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.entities; using Lens.entity; using Lens.entity.component.logic; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Crab : Mob { protected override void SetStats() { base.SetStats(); vertical = Rnd.Chance(); Width = 18; Height = 14; AddAnimation("crab"); SetMaxHp(3); Become(); var body = new RectBodyComponent(3, 13, 12, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(3, 2, 12, 12)); AddDrops(new SingleDrop("bk:crabs_claw", 0.01f)); } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target != null) { Become(); } else { Become(); } } private bool vertical; #region Bandit States public class WaitState : SmartState { } public class IdleState : SmartState { private Vector2 velocity; private bool a; private float timer; public void Flip(bool force = false) { a = !a; timer = Rnd.Float(1f, 10f); if (force || Rnd.Chance(25)) { Self.vertical = !Self.vertical; a = Rnd.Chance(); } var f = 40; velocity = new Vector2(Self.vertical ? 0 : (a ? -f : f), Self.vertical ? (a ? -f : f) : 0); Self.GetComponent().Velocity = velocity; var an = Self.GetComponent(); an.Animation.Frame = (uint) Rnd.Int(4); an.Animate(); } public override void Init() { base.Init(); a = Rnd.Chance(); Flip(); } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); var b = Self.GetComponent(); if (T >= timer || b.Velocity.Length() < 20) { Flip(T >= timer); T = 0; return; } b.Velocity = velocity; } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door || ev.Entity is Level || ev.Entity is Chasm || (ev.Entity is SolidProp && !(ev.Entity is BreakableProp))) { var s = GetComponent().StateInstance; if (s is IdleState i) { i.Flip(); } } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Ghost.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.level; using BurningKnight.level.entities; using Lens.entity; using Lens.graphics; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Ghost : Mob { public const float TargetRadius = 128f; public const byte Alpha = 50; private static readonly Color color = ColorUtils.FromHex("#5ac54f"); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); AddAnimation("ghost"); SetMaxHp(2); Flying = true; Depth = Layers.FlyingMob; Become(); var body = new SensorBodyComponent(2, 2, 12, 12); AddComponent(body); body.Body.LinearDamping = 3; GetComponent().Tint.A = Alpha; } private bool rage; #region Ghost States public class IdleState : SmartState { public override void Init() { base.Init(); var color = Self.GetComponent().Tint; Tween.To(Alpha, color.A, x => Self.GetComponent().Tint.A = (byte) x, 0.3f); } public override void Destroy() { base.Destroy(); var color = Self.GetComponent().Tint; Tween.To(255f, color.A, x => Self.GetComponent().Tint.A = (byte) x, 0.3f); } public override void Update(float dt) { base.Update(dt); if (Self.Target != null && Self.Target.DistanceTo(Self) < TargetRadius) { Become(); } Self.CheckRage(); } } public class ChaseState : SmartState { private bool rage; public override void Init() { base.Init(); rage = Self.rage; } public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { return; } // Fixme: this target stuff is bad for multiplayer, it will chase only random player, not closest float d = Self.Target.DistanceTo(Self); if (!rage) { Self.CheckRage(); if (Self.rage) { rage = true; } else if (d > TargetRadius + 10f) { Become(); return; } } float a = Self.AngleTo(Self.Target); float force = (rage ? 200f : 100f) * dt; if (T < 0.5f) { force *= 0.1f; } Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); Self.PushFromOtherEnemies(dt); } } #endregion protected void CheckRage() { if (Target == null) { return; } var room = GetComponent().Room; if (room == null) { return; } foreach (var m in room.Tagged[Tags.MustBeKilled]) { if (!(m is Ghost)) { return; } } // RAAAAAAGE MOOOOOOOOOOOODE rage = true; Become(); GetComponent().InitMaxHealth = 4; } public override bool ShouldCollide(Entity entity) { if (entity is Prop) { return false; } return base.ShouldCollide(entity) && !(entity is Level); } protected override string GetHurtSfx() { return $"mob_ghost_hurt_{Rnd.Int(1, 3)}"; } protected override string GetDeadSfx() { return $"mob_ghost_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Gunner.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Gunner : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("gunner"); SetMaxHp(5); Become(); var body = new RectBodyComponent(1, 15, 15, 1); AddComponent(body); body.Body.LinearDamping = 6; AddComponent(new SensorBodyComponent(2, 2, 12, 12)); moveId = Rnd.Int(3); GetComponent().PitchMod = -0.3f; } #region Gunner States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(0.4f, 1f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } } } private int moveId; public class RunState : SmartState { private const float Accuracy = 0.2f; private Vector2 velocity; private float timer; private float lastBullet; private float angle; private bool fire; private float start; private bool saw; public override void Init() { base.Init(); fire = Self.Target != null && Self.moveId % 2 == 0; angle = !fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target); timer = fire ? 0.9f : Rnd.Float(0.8f, 2f); start = Rnd.Float(0f, 10f); var a = angle + Rnd.Float(-Accuracy, Accuracy); var force = fire ? 60 : 120; velocity.X = (float) Math.Cos(a) * force; velocity.Y = (float) Math.Sin(a) * force; Self.GetComponent().Velocity = velocity; Self.moveId++; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); return; } var v = velocity * Math.Min(1, timer - T * 0.4f); Self.GetComponent().Velocity = v; if (!fire) { return; } lastBullet -= dt; if (lastBullet <= 0) { lastBullet = 0.3f; if (!saw && !Self.CanSeeTarget()) { return; } saw = true; var an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * (float) Math.PI * 0.1f; var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f); Self.GetComponent().EmitRandomized("mob_fire", sz: 0.2f); var builder = new ProjectileBuilder(Self, "circle") { LightRadius = 32f }; builder.Move(angle, 8); builder.Shoot(an, 7f).Build(); }; } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_gunner_death"; } protected override string GetHurtSfx() { return "mob_gunner_hurt"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/King.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.entity.creature.mob.castle { public class King : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("king"); SetMaxHp(3); Become(); var body = new RectBodyComponent(2, 2, 12, 12); AddComponent(body); body.Body.LinearDamping = 4; } #region King States public class IdleState : SmartState { } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Knight.cs ================================================ using Lens.entity; using Lens.entity.component.logic; namespace BurningKnight.entity.creature.mob.castle { public class Knight : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("knight"); SetMaxHp(10); Become(); } protected override void OnTargetChange(Entity target) { if (target == null) { Become(); } else { Become(); } } #region Knight States public class IdleState : EntityState { } public class ChaseState : EntityState { } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/MotherSlime.cs ================================================ using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class MotherSlime : SimpleSlime { private static readonly Color color = ColorUtils.FromHex("#0069aa"); public static Color LightColor = new Color(0.5f, 0.5f, 1f, 1f); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent("mother_slime")); SetMaxHp(1); AddComponent(new LightComponent(this, 64, LightColor)); } protected override BodyComponent CreateBodyComponent() { return new RectBodyComponent(2, 7, 12, 9); } protected override BodyComponent CreateSensorBodyComponent() { return new SensorBodyComponent(2, 7, 12, 9); } protected override bool HandleDeath(DiedEvent d) { for (var i = 0; i < 2; i++) { var slime = new BabySlime(); Area.Add(slime); slime.Center = Center + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4)); slime.GetComponent().InvincibilityTimer = 0.1f; slime.GetAnyComponent().KnockbackFrom(d.From, Rnd.Float(1f, 2f), 2); } return base.HandleDeath(d); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/Rat.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class Rat : Mob { protected override void SetStats() { base.SetStats(); Width = 14; Height = 15; AddAnimation("rat"); SetMaxHp(2); Become(); var body = new RectBodyComponent(2, 14, 10, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(2, 1, 10, 14)); } #region Bandit States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(1, 2.5f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } } } public class RunState : SmartState { private Vector2 velocity; private float timer; public override void Init() { base.Init(); timer = Rnd.Float(0.4f, 1f); var angle = Rnd.AnglePI(); var force = 120f + Rnd.Float(50f); if (Rnd.Chance() && Self.Target != null) { var ac = 0.1f; angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); } velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); } else { Self.GetComponent().Velocity = velocity * Math.Min(1, timer - T * 0.4f); } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_bandit_death"; } protected override string GetHurtSfx() { return "mob_bandit_damage"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/SimpleSlime.cs ================================================ using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.level.biome; using BurningKnight.state; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class SimpleSlime : Slime { private static readonly Color color = ColorUtils.FromHex("#33984b"); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent(Events.Halloween ? "spooky_slime" : "slime")); SetMaxHp((Run.Level != null && Run.Level.Biome is CaveBiome) ? 4 : 1 + Run.Depth / 2); var body = CreateBodyComponent(); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(CreateSensorBodyComponent()); AddComponent(new LightComponent(this, 24, new Color(0.5f, 1f, 0.4f))); } protected virtual BodyComponent CreateBodyComponent() { return new RectBodyComponent(2, 12, 10, 1); } protected virtual BodyComponent CreateSensorBodyComponent() { return new SensorBodyComponent(2, 5, 12, 9); } } } ================================================ FILE: BurningKnight/entity/creature/mob/castle/WallCrawler.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.castle { public class WallCrawler : WallWalker { protected override void SetStats() { base.SetStats(); AddComponent(new WallAnimationComponent("crawler")); SetMaxHp(2); } private static readonly Color color = ColorUtils.FromHex("#ffeb57"); protected override Color GetBloodColor() { return color; } #region Crawler States public class IdleState : WallWalker.IdleState { public override void Update(float dt) { base.Update(dt); if (T >= 3f) { Become(); } } public override void Flip() { Self.Left = !Self.Left; if (Self.T >= 3f) { Become(); return; } velocity *= -1; vx *= -1; vy *= -1; Self.GetComponent().Velocity = velocity; T = 0; } } public class FireState : SmartState { private bool fired; public override void Init() { base.Init(); Self.T = 0; Self.GetComponent().Velocity = Vector2.Zero; Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (!fired && Self.GetComponent().Animation.Paused) { fired = true; T = 0; if (Self.Target == null) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { return; } Self.GetComponent().EmitRandomized("mob_fire_wall"); var angle = Self.Direction.ToAngle(); var builder = new ProjectileBuilder(Self, "small") { LightRadius = 32f }; builder.AddFlags(ProjectileFlags.FlyOverStones); builder.Move(angle, 8); if (Run.Depth > 2 || Run.Loop > 0) { builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); builder.Scale *= 1.5f; } builder.Shoot(angle, 5f).Build(); }; }; } else if (fired && T > 1f) { Self.GetComponent().Become(); } } } #endregion protected override Type GetIdleState() { return typeof(IdleState); } public override void Update(float dt) { base.Update(dt); T += dt; } } } ================================================ FILE: BurningKnight/entity/creature/mob/cave/Broco.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.cave { public class Broco : Mob { protected override void SetStats() { base.SetStats(); Width = 12; Height = 11; AddAnimation("broco"); SetMaxHp(2); Become(); var body = new RectBodyComponent(2, 10, 8, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(2, 2, 8, 9)); moveId = Rnd.Int(0, 2); AddComponent(new LightComponent(this, 20, new Color(0.5f, 1f, 0.4f))); AddDrops(new SingleDrop("bk:emerald", 0.001f)); } private int moveId; #region Bandit States public class IdleState : SmartState { private float delay; private float fireDelay; private bool fired; private bool firedLaser; private Laser laser; public override void Init() { base.Init(); delay = Rnd.Float(1.5f, 2.5f); fireDelay = (firedLaser = (Self.moveId % 2 == 0)) ? 3 : Rnd.Float(0.5f, delay - 0.5f); Self.moveId++; } public override void Update(float dt) { base.Update(dt); if (laser != null) { laser.Position = Self.Center; } if (firedLaser && T >= delay) { Become(); return; } if (!firedLaser && !fired && T >= fireDelay) { fired = true; if (!Self.CanSeeTarget()) { firedLaser = true; return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { firedLaser = true; return; } Self.GetComponent().EmitRandomized("mob_fire"); var ac = 0.1f; var angle = Self.AngleTo(Self.Target); var builder = new ProjectileBuilder(Self, "circle") { Color = ProjectileColor.White, LightRadius = 32f }; builder.AddFlags(ProjectileFlags.FlyOverStones); builder.Move(angle, 8); builder.Shoot(angle + Rnd.Float(-ac, ac), 9f); builder.Build(); Timer.Add(() => { if (Self.Done) { return; } laser = Laser.Make(Self, 0, angle + Rnd.Float(-ac * 3f, ac * 3f), scale: 2, range: 16); laser.LifeTime = 2f; laser.Color = ProjectileColor.Green; laser.Position = Self.Center; Self.GetComponent().EmitRandomizedPrefixed("item_laser", 4); Timer.Add(() => { firedLaser = true; Become(); }, 2f); }, 0.8f); }; }; } } } public class RunState : SmartState { private Vector2 velocity; private float timer; public override void Init() { base.Init(); timer = Rnd.Float(0.4f, 1f); var angle = Rnd.AnglePI(); var force = 120f + Rnd.Float(50f); if (Rnd.Chance() && Self.Target != null) { var ac = 0.1f; angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); } velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); } else { Self.GetComponent().Velocity = velocity * Math.Min(1, timer - T * 0.4f); } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_bandit_death"; } protected override string GetHurtSfx() { return "mob_bandit_damage"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/cave/EmeraldGunner.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.cave { public class EmeraldGunner : Mob { protected override void SetStats() { base.SetStats(); Width = 17; Height = 15; AddAnimation("emerald_gunner"); SetMaxHp(4); AddDrops(new SingleDrop("bk:emerald", 0.001f)); Become(); var body = new RectBodyComponent(1, 13, 15, 1); AddComponent(body); body.Body.LinearDamping = 6; AddComponent(new SensorBodyComponent(1, 2, 15, 12)); moveId = Rnd.Int(3); GetComponent().PitchMod = -0.4f; AddComponent(new LightComponent(this, 32, new Color(0.5f, 1f, 0.4f))); } #region Gunner States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(0.4f, 1f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } } } private int moveId; public class RunState : SmartState { private const float Accuracy = 0.2f; private Vector2 velocity; private float timer; private float lastBullet; private float angle; private bool fire; private float start; private bool saw; public override void Init() { base.Init(); fire = Self.Target != null && Self.moveId % 2 == 0; angle = !fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target); timer = fire ? 0.9f : Rnd.Float(0.8f, 2f); start = Rnd.Float(0f, 10f); var a = angle + Rnd.Float(-Accuracy, Accuracy); var force = fire ? 60 : 120; velocity.X = (float) Math.Cos(a) * force; velocity.Y = (float) Math.Sin(a) * force; Self.GetComponent().Velocity = velocity; Self.moveId++; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); return; } var v = velocity * Math.Min(1, timer - T * 0.4f); Self.GetComponent().Velocity = v; if (!fire) { return; } lastBullet -= dt; if (lastBullet <= 0) { lastBullet = 0.3f; if (!saw && !Self.CanSeeTarget()) { return; } saw = true; var an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * (float) Math.PI * 0.1f; var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f); Self.GetComponent().EmitRandomized("mob_fire", sz: 0.2f); var builder = new ProjectileBuilder(Self, "circle") { LightRadius = 32f, Color = ProjectileColor.Green }; builder.Shoot(an, 7f); builder.Move(angle, 8); builder.Build(); var b = new ProjectileBuilder(Self, "circle") { Color = ProjectileColor.DarkGreen, LightRadius = 32f }; b.Move(angle, 8); for (var i = 0; i < 4; i++) { builder.Scale = Rnd.Float(0.4f, 0.7f); builder.Shoot(an + Rnd.Float(-Accuracy * 3, Accuracy * 3), Rnd.Float(7, 10f)); builder.Build(); } }; } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_gunner_death"; } protected override string GetHurtSfx() { return "mob_gunner_hurt"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/cave/Thief.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.door; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component.logic; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.cave { public class Thief : Mob { protected override void SetStats() { base.SetStats(); Width = 16; Height = 16; AddAnimation("thief"); SetMaxHp(3); Become(); var body = new RectBodyComponent(2, 15, 12, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(2, 2, 12, 14)); AddComponent(new LightComponent(this, 20, new Color(0.5f, 1f, 0.4f))); AddDrops(new SingleDrop("bk:emerald", 0.001f)); } #region Bandit States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(0.8f, 1.3f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } } } public class RunState : SmartState { private Vector2 velocity; private float timer; public override void Init() { base.Init(); timer = Rnd.Float(0.3f, 0.6f); var angle = Rnd.AnglePI(); var force = 160f + Rnd.Float(90f); if (Rnd.Chance() && Self.Target != null) { var ac = 0.1f; angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); } velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); } else { Self.GetComponent().Velocity = velocity * Math.Min(1, timer - T * 0.4f); } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_bandit_death"; } protected override string GetHurtSfx() { return "mob_bandit_damage"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Cactus.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.mob.desert { /*public class Cactus : Mob { protected override void SetStats() { base.SetStats(); var body = new RectBodyComponent(4, 2, 8, 14, BodyType.Static, true); AddComponent(body); body.KnockbackModifier = 0; SetMaxHp(10); AddAnimation("cactus"); Become(); counter = Rnd.Int(4); } private int counter; #region Cactus states public class IdleState : SmartState { private bool tweened; public override void Init() { base.Init(); Self.counter++; if (Self.counter > 2) { Self.counter = 0; for (var i = 0; i < 10; i++) { Timer.Add(() => { var projectile = Projectile.Make(Self, "small", Rnd.AnglePI(), Rnd.Float(1, 9)); projectile.Color = ProjectileColor.Green; projectile.Center = Self.Center; projectile.Spectral = true; projectile.BreaksFromWalls = false; projectile.Depth = Layers.Wall + 1; projectile.Controller += SlowdownProjectileController.Make(Rnd.Float(1f, 2f)); projectile.AddLight(32f, ProjectileColor.Green); }, i * 0.1f); } } } public override void Update(float dt) { base.Update(dt); if (!tweened && T >= 1f) { tweened = true; var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f); Become(); }; } } } public class OppositeState : SmartState { private bool tweened; public override void Update(float dt) { base.Update(dt); if (!tweened && T >= 1f) { tweened = true; var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.3f); Become(); }; } } } #endregion }*/ } ================================================ FILE: BurningKnight/entity/creature/mob/desert/DesertBulletSlime.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.projectile; using Lens.graphics; using Lens.util; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class DesertBulletSlime : BulletSlime { private static readonly Color color = ColorUtils.FromHex("#ffeb57"); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); SetMaxHp(8); } protected override void OnJump() { base.OnJump(); var builder = new ProjectileBuilder(this, "small") { LightRadius = 32f }; builder.AddFlags(ProjectileFlags.FlyOverStones); for (var i = 0; i < 3; i++) { Timer.Add(() => { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = AngleTo(Target) + Rnd.Float(-0.1f, 0.1f); var projectile = builder.Shoot(a, 9f).Build(); projectile.Center = Center + MathUtils.CreateVector(a, 5f) - new Vector2(0, GetComponent().Z); }, i * 0.3f); } } protected override string GetSprite() { return "desert_bullet_slime"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/DesertSlime.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.state; using Lens.graphics; using Lens.util; using Color = Microsoft.Xna.Framework.Color; namespace BurningKnight.entity.creature.mob.desert { public class DesertSlime : Slime { private static readonly Color color = ColorUtils.FromHex("#ffeb57"); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent("desert_slime")); SetMaxHp(1 + (int) Math.Round(Run.Depth * 1.5f)); var body = new RectBodyComponent(2, 12, 12, 1); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.5f; AddComponent(new SensorBodyComponent(2, 7, 12, 9)); } protected override void OnLand() { base.OnLand(); if (Target == null) { return; } var a = AngleTo(Target); var builder = new ProjectileBuilder(this, "small") { LightRadius = 48 }; builder.Shoot(a, 5f); builder.Build().Center = Center + MathUtils.CreateVector(a, 5f); GetComponent().KnockbackFrom(a - (float) Math.PI, 0.3f); } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Fly.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.level; using Lens.entity; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class Fly : Mob { protected const float DefaultZ = 2; protected override void SetStats() { base.SetStats(); SetMaxHp(3); var body = new SensorBodyComponent(1, 1, 10, 8); AddComponent(body); TouchDamage = 0; body.Body.LinearDamping = 4; AddComponent(new ZAnimationComponent("fly")); AddComponent(new ZComponent()); AddComponent(new OrbitalComponent { Radius = 12, Lerp = true }); Depth = Layers.Wall; Become(); } public override bool InAir() { return true; } private void Fire() { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); var an = AngleTo(Target); var builder = new ProjectileBuilder(this, "small") { Scale = 0.8f, LightRadius = 24 }; var projectile = builder.Shoot(an, 8).Build(); projectile.Center = Center + MathUtils.CreateVector(an, 2f); }; }; } #region Fly States public class IdleState : SmartState { private bool searched; private Entity target; public override void Init() { base.Init(); var component = Self.GetComponent(); Tween.To(0, component.Z, x => component.Z = x, 0.4f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); if (!searched) { searched = true; target = Self.GetComponent().Room?.FindClosest(Self.Center, Tags.Mob, e => !e.HasComponent() && !(e is WallWalker || e is Boss)); } if (target != null) { if (!target.HasComponent()) { target.AddComponent(new OrbitGiverComponent()); } target.GetComponent().AddOrbiter(Self); Become(); return; } if (Self.Target == null) { return; } var dx = Self.DxTo(Self.Target); var dy = Self.DyTo(Self.Target); var d = MathUtils.Distance(dx, dy); var s = dt * 300; Self.GetComponent().Velocity += new Vector2(dx / d * s, dy / d * s); Self.PushFromOtherEnemies(dt, e => e.InAir()); if (T >= 3f) { T = 0; Self.Fire(); } } } public class OrbitingState : SmartState { public override void Init() { base.Init(); var component = Self.GetComponent(); Tween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); var orbiting = Self.GetComponent().Orbiting; if (orbiting == null) { Become(); return; } if (orbiting.TryGetComponent(out var z)) { Self.GetComponent().Z = z.Z + DefaultZ; } if (T >= 3f) { T = 0; Self.Fire(); } } } #endregion public override bool ShouldCollide(Entity entity) { return !(entity is Level) && base.ShouldCollide(entity); } protected override string GetDeadSfx() { return "mob_fly_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Maggot.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class Maggot : WallWalker { private const float TargetDistance = 4f; private const float Speed = 30f; protected override void SetStats() { base.SetStats(); AddComponent(new WallAnimationComponent("maggot")); SetMaxHp(1); Depth = Layers.Creature + 1; } #region Maggot States public class IdleState : WallWalker.IdleState { private bool stop; public override void DoLogic(float dt) { base.DoLogic(dt); if (Self.Target == null) { ResetVelocity(); return; } if (mx == 0) { if (Math.Abs(Self.DxTo(Self.Target)) <= TargetDistance) { ResetVelocity(); Become(); return; } var left = Self.CenterX > Self.Target.CenterX; if (Self.Left != left) { InvertVelocity(); stop = false; } else { vx = Self.Left ? -1 : 1; vy = 0; } } else { if (Math.Abs(Self.DyTo(Self.Target)) <= TargetDistance) { ResetVelocity(); Become(); return; } var left = Self.CenterY > Self.Target.CenterY; if (Self.Left != left) { InvertVelocity(); stop = false; } else { vx = 0; vy = Self.Left ? -1 : 1; } } if (stop) { vx = 0; vy = 0; } velocity = new Vector2(vx * Speed, vy * Speed); } public override void Flip() { ResetVelocity(); stop = true; } } public class FireState : SmartState { private bool shot; public override void Init() { base.Init(); Self.T = 0; Self.GetComponent().Velocity = Vector2.Zero; Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (!shot && Self.GetComponent().Animation.Paused) { if (Self.Target == null) { Become(); return; } shot = true; var a = Self.GetComponent(); Self.GetComponent().EmitRandomized("mob_fire_wall"); var angle = Self.Direction.ToAngle(); var builder = new ProjectileBuilder(Self, "small") { LightRadius = 30 }; if (Run.Depth > 4 || Run.Loop > 0) { builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); builder.Scale *= 1.5f; } builder.AddFlags(ProjectileFlags.FlyOverStones); var projectile = builder.Shoot(angle, 5f).Build(); projectile.Center += MathUtils.CreateVector(angle, 4); a.Scale.X = 1.8f; a.Scale.Y = 0.2f; Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f).OnEnd = () => { Become(); }; } } } #endregion protected override Type GetIdleState() { return typeof(IdleState); } public override void Update(float dt) { base.Update(dt); T += dt; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/MegaSlime.cs ================================================ using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.events; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class MegaSlime : SimpleSlime { private static readonly Color color = ColorUtils.FromHex("#0069aa"); public static Color LightColor = new Color(0.5f, 0.5f, 1f, 1f); protected override Color GetBloodColor() { return color; } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent("mega_slime")); SetMaxHp(5); AddComponent(new LightComponent(this, 64, LightColor)); } protected override BodyComponent CreateBodyComponent() { return new RectBodyComponent(2, 7, 12, 9); } protected override BodyComponent CreateSensorBodyComponent() { return new SensorBodyComponent(2, 7, 12, 9); } protected override bool HandleDeath(DiedEvent d) { for (var i = 0; i < 2; i++) { var slime = new MotherSlime(); Area.Add(slime); slime.Center = Center + new Vector2(Rnd.Float(-4, 4), Rnd.Float(-4, 4)); slime.GetComponent().InvincibilityTimer = 0.1f; slime.GetAnyComponent().KnockbackFrom(d.From, Rnd.Float(1f, 2f), 2); } return base.HandleDeath(d); } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Mummy.cs ================================================ using System; using BurningKnight.entity.component; using Lens.entity.component.logic; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class Mummy : Mob { private const float DetectionRadius = 70f; protected override void SetStats() { base.SetStats(); SetMaxHp(4); AddAnimation("mummy"); var body = new RectBodyComponent(2, 15, 10, 1); AddComponent(body); body.KnockbackModifier = 3; body.Body.LinearDamping = 6; AddComponent(new SensorBodyComponent(3, 3, 7, 13)); Become(); TouchDamage = 2; } #region Mummy States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Int(1, 2); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().StateInstance is SummonedState) { return; } if (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) { Become(); return; } if (T >= delay) { Become(); } } } public class WanderState : SmartState { private Vector2 velocity; private float timer; private float angle; public override void Init() { base.Init(); angle = Rnd.AnglePI(); timer = Rnd.Float(0.8f, 2f); var force = Rnd.Float(40f, 60f); velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; Self.GetComponent().Animation.Tag = "run"; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) { Become(); return; } if (timer <= T) { Become(); return; } var v = velocity * Math.Min(1, timer - T * 0.4f); Self.GetComponent().Velocity = v; } } public class SummonedState : SmartState { public override void Init() { base.Init(); Self.TouchDamage = 0; var a = Self.GetComponent(); a.Scale.X = 3f; a.Scale.Y = 0f; Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.5f, Ease.BackOut); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.5f, Ease.BackOut).OnEnd = () => { Become(); }; } public override void Destroy() { base.Destroy(); Self.TouchDamage = 1; } } public class RunState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Self.Become(); return; } var d = Self.DistanceTo(Self.Target); if (d > 96f) { Self.Become(); return; } var dx = Self.DxTo(Self.Target); var dy = Self.DyTo(Self.Target); var s = dt * 300; Self.GetComponent().Velocity += new Vector2(dx / d * s, dy / d * s); Self.PushFromOtherEnemies(dt); } } #endregion protected override string GetHurtSfx() { return "mob_mummy_hurt"; } protected override string GetDeadSfx() { return "mob_mummy_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Spelunker.cs ================================================ using System; using BurningKnight.entity.component; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class Spelunker : Mob { private const float DetectionRadius = 64f; private bool Exploded; protected override void SetStats() { base.SetStats(); SetMaxHp(7); AddAnimation("spelunker"); var body = new RectBodyComponent(3, 15, 10, 1); AddComponent(body); body.KnockbackModifier = 2; body.Body.LinearDamping = 6; AddComponent(new SensorBodyComponent(5, 4, 7, 11)); Become(); } #region Spelunker States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Int(1, 2); } public override void Update(float dt) { base.Update(dt); if (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) { Become(); return; } if (T >= delay) { Become(); } } } public class WanderState : SmartState { private Vector2 velocity; private float timer; private float angle; public override void Init() { base.Init(); angle = Rnd.AnglePI(); timer = Rnd.Float(0.8f, 2f); var force = Rnd.Float(60f, 80f); velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; Self.GetComponent().Animation.Tag = "run"; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (Self.Target != null && Self.DistanceTo(Self.Target) < DetectionRadius) { Become(); return; } if (timer <= T) { Become(); return; } var v = velocity * Math.Min(1, timer - T * 0.4f); Self.GetComponent().Velocity = v; } } public class RunState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Self.Become(); return; } var d = Self.DistanceTo(Self.Target); if (d <= 32f) { Self.Become(); } if (d > 96f) { Self.Become(); return; } var dx = Self.DxTo(Self.Target); var dy = Self.DyTo(Self.Target); var s = dt * 250; Self.GetComponent().Velocity += new Vector2(dx / d * s, dy / d * s); Self.PushFromOtherEnemies(dt); } } public class ExplodeState : SmartState { private bool lastFlash; public override void Destroy() { base.Destroy(); Self.GetComponent().Flash = false; } public override void Update(float dt) { base.Update(dt); var d = Self.DistanceTo(Self.Target); if (d > 48f) { Self.Become(); return; } if (T >= 0.66f) { Self.Done = true; Self.Exploded = true; AudioEmitterComponent.Dummy(Self.Area, Self.Center).EmitRandomized("mob_archeolog_explosion", sz: 0.2f); ExplosionMaker.Make(Self, 48f); } var flash = T % 0.33 < 0.15f; if (flash && !lastFlash) { Self.GetComponent().Emit("mob_spelunker_beep", 1f, T); } lastFlash = flash; Self.GetComponent().Flash = flash; } } #endregion protected override string GetDeadSfx() { return Exploded ? null : "mob_archeolog_death"; } protected override string GetHurtSfx() { return "mob_archeolog_hurt"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/desert/Worm.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.desert { public class Worm : Mob { protected override void SetStats() { base.SetStats(); SetMaxHp(1); AddAnimation("worm"); GetComponent().ShadowOffset = 1; var body = new RectBodyComponent(3, 3, 4, 10); AddComponent(body); body.KnockbackModifier = 0; Become(); } #region Worm public class HiddenState : SmartState { private float delay; private Vector2 target; public override void Destroy() { base.Destroy(); var i = 0; do { var spot = Self.GetComponent().Room.GetRandomFreeTile() * 16; if (Self.Target == null || Self.Target.DistanceTo(spot) > 32f) { target = new Vector2(spot.X + 8, spot.Y); break; } i++; if (i > 99) { Log.Error("Failed to find a spot where to dig up"); break; } } while (true); Self.TouchDamage = 0; Self.GetComponent().Unhittable = true; delay = Rnd.Float(0.5f, 1.5f); Self.Center = target; Self.TouchDamage = 1; Self.GetComponent().Unhittable = false; } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } } } public class HidingState : SmartState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Become(); } } } public class ShowingState : SmartState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Become(); } Self.TurnToTarget(); } } public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (T >= 3f) { if (Self.Target == null || Self.DistanceTo(Self.Target) > 96f) { Become(); } else { Become(); } } Self.TurnToTarget(); } } public class FireState : SmartState { private bool fired; public override void Update(float dt) { base.Update(dt); if (!fired && T >= 0.1f) { fired = true; if (Self.Target == null) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f).OnEnd = () => { Become(); }; if (Self.Target == null) { return; } var ac = 0.1f; var angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); var builder = new ProjectileBuilder(Self, "small") { LightRadius = 32f }; builder.Shoot(angle, 8f); var projectile = builder.Build(); projectile.Center += MathUtils.CreateVector(angle, 2f); }; }; } Self.TurnToTarget(); } } #endregion protected override void RenderShadow() { if (GetComponent().StateInstance is HiddenState) { return; } base.RenderShadow(); } public override void Render() { if (GetComponent().StateInstance is HiddenState) { return; } base.Render(); } protected override string GetDeadSfx() { return "mob_worm_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/BigSnowball.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class BigSnowball : Mob { protected override Color GetBloodColor() { return Snowball.BloodColor; } protected override void SetStats() { base.SetStats(); Width = 20; Height = 20; SetMaxHp(10); AddDrops(new SingleDrop("bk:ice_skates", 0.01f)); var body = new RectBodyComponent(3, 19, 10, 5); AddComponent(body); body.Body.LinearDamping = 1f; body.KnockbackModifier = 2f; body.Body.Restitution = 1; body.Body.Friction = 0; AddComponent(new SensorBodyComponent(2, 3, 16, 16)); AddComponent(new MobAnimationComponent("big_snowball") { ShadowOffset = 3 }); Become(); } #region Snowman States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(1f, 5f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } var v = Self.GetComponent().Body.LinearVelocity; if (v.LengthSquared() > 15f) { Become(); } } } public class RollState : SmartState { private const float Accuracy = 0.2f; private float angle; public override void Init() { base.Init(); if (Self.GetComponent().Body.LinearVelocity.LengthSquared() < 15f) { angle = Rnd.Chance() || Self.Target == null ? Rnd.AnglePI() : Self.AngleTo(Self.Target); var a = angle + Rnd.Float(-Accuracy, Accuracy); var force = 200; Vector2 velocity; velocity.X = (float) Math.Cos(a) * force; velocity.Y = (float) Math.Sin(a) * force; Self.GetComponent().Velocity = velocity; Self.GetComponent().Animation.Reverse = velocity.Y < 0; } } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; Self.GetComponent().Animation.Reverse = false; } public override void Update(float dt) { base.Update(dt); var v = Self.GetComponent().Body.LinearVelocity; if (v.LengthSquared() < 15f) { Become(); Self.GetComponent().Body.LinearVelocity = Vector2.Zero; return; } Self.GetComponent().Animation.Reverse = v.Y < 0; } } #endregion public override bool ShouldCollide(Entity entity) { if (entity is BigSnowball) { return true; } return base.ShouldCollide(entity); } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/CupGuy.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class CupGuy : Mob { protected override void SetStats() { base.SetStats(); Width = 14; Height = 15; AddAnimation("cup_guy"); SetMaxHp(10); Become(); var body = new RectBodyComponent(3, 13, 9, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(3, 1, 9, 13)); moveId = Rnd.Int(0, 2); } private int moveId; #region CupGuy States public class IdleState : SmartState { private float delay; private float fireDelay; private bool fired; public override void Init() { base.Init(); delay = Rnd.Float(1, 2.5f); fireDelay = Self.moveId % 2 == 0 ? 3 : Rnd.Float(0.5f, delay - 0.5f); Self.moveId++; } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); return; } if (!fired && T >= fireDelay) { fired = true; if (!Self.CanSeeTarget()) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { return; } Self.GetComponent().EmitRandomized("mob_fire"); var am = Rnd.Int(5, 10); var builder = new ProjectileBuilder(Self, "small") { LightRadius = 32f, Range = 2f }; builder.AddFlags(ProjectileFlags.FlyOverStones); builder.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); for (var i = 0; i < am; i++) { var angle = Rnd.Float(-0.1f, 0.1f) + (float) i / am * Math.PI * 2; var projectile = builder.Shoot(angle, Rnd.Float(3, 6)).Build(); projectile.Center += MathUtils.CreateVector(angle, 8f); AnimationUtil.Poof(projectile.Center); } }; }; } } } public class RunState : SmartState { private Vector2 velocity; private float timer; public override void Init() { base.Init(); timer = Rnd.Float(0.4f, 1f); var angle = Rnd.AnglePI(); var force = 120f + Rnd.Float(50f); if (Rnd.Chance() && Self.Target != null) { var ac = 0.1f; angle = Self.AngleTo(Self.Target) + Rnd.Float(-ac, ac); } velocity.X = (float) Math.Cos(angle) * force; velocity.Y = (float) Math.Sin(angle) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); } else { Self.GetComponent().Velocity = velocity * Math.Min(1, timer - T * 0.4f); } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetDeadSfx() { return "mob_bandit_death"; } protected override string GetHurtSfx() { return "mob_bandit_damage"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/Dino.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class Dino : Mob { private const float FindTime = 3f; protected override void SetStats() { // todo: make him bounce of walls? base.SetStats(); Width = 17; Height = 20; AddAnimation("dino"); SetMaxHp(20); Become(); var body = new RectBodyComponent(2, 19, 13, 1); AddComponent(body); body.Body.LinearDamping = 6; body.Body.Restitution = 1; body.Body.Friction = 0; AddComponent(new SensorBodyComponent(1, 3, 15, 17)); } #region Dino States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(0.4f, 1f); } public override void Update(float dt) { base.Update(dt); if (T >= delay) { Become(); } else { if (Self.CanSeeTarget()) { Self.sawTime += dt; if (Self.sawTime >= FindTime) { Become(); } } else { Self.sawTime = 0; } } } } private bool fire; private float sawTime; public class RunState : SmartState { private const float Accuracy = 0.2f; private Vector2 velocity; private float timer; private float lastBullet; private float angle; private float start; private bool saw; public override void Init() { base.Init(); if (Self.fire = (Self.sawTime >= FindTime)) { Self.sawTime = 0; } angle = !Self.fire ? Rnd.AnglePI() : Self.AngleTo(Self.Target); timer = Self.fire ? 0.9f * 5 : Rnd.Float(0.8f, 2f); start = Rnd.Float(0f, 10f); var a = angle + Rnd.Float(-Accuracy, Accuracy); var force = Self.fire ? 30 : 60; velocity.X = (float) Math.Cos(a) * force; velocity.Y = (float) Math.Sin(a) * force; Self.GetComponent().Velocity = velocity; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (timer <= T) { Become(); return; } var v = velocity * Math.Min(1, timer - T * 0.4f); Self.GetComponent().Velocity = v; if (!Self.fire) { if (Self.CanSeeTarget()) { Self.sawTime += dt; } else { Self.sawTime = 0; } return; } lastBullet -= dt; if (lastBullet <= 0) { lastBullet = 0.2f; if (!saw && !Self.CanSeeTarget()) { return; } saw = true; var an = angle + Rnd.Float(-Accuracy, Accuracy) + Math.Cos(T * 6f + start) * 0.1f; var a = Self.GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.2f); Self.GetComponent().EmitRandomized("mob_fire"); var builder = new ProjectileBuilder(Self, "circle") { Scale = Rnd.Float(0.5f, 1.5f), LightRadius = 32f, Bounce = 1 }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); var projectile = builder.Shoot(an, 15).Build(); projectile.Color = Rnd.Chance(70) ? ProjectileColor.Orange : ProjectileColor.Red; projectile.Center += MathUtils.CreateVector(angle, 8); }; } } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is Door) { var s = GetComponent().StateInstance; if (s is RunState) { Become(); } } } return base.HandleEvent(e); } protected override string GetHurtSfx() { return "mob_dino_hurt"; } protected override string GetDeadSfx() { return "mob_dino_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/IceCrawler.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class IceCrawler : WallWalker { protected override void SetStats() { base.SetStats(); AddComponent(new WallAnimationComponent("ice_crawler")); SetMaxHp(4); AddDrops(new SingleDrop("bk:campfire_in_bottle", 0.01f)); } protected override Color GetBloodColor() { return Snowball.BloodColor; } #region Crawler States public class IdleState : WallWalker.IdleState { public override void Update(float dt) { base.Update(dt); if (T >= 1.5f) { Become(); } } public override void Flip() { Self.Left = !Self.Left; if (Self.T >= 3f) { Become(); return; } velocity *= -1; vx *= -1; vy *= -1; Self.GetComponent().Velocity = velocity; T = 0; } } public class FireState : SmartState { private bool fired; public override void Init() { base.Init(); Self.T = 0; Self.GetComponent().Velocity = Vector2.Zero; Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (!fired && Self.GetComponent().Animation.Paused) { fired = true; T = 0; if (Self.Target == null) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { return; } Self.GetComponent().EmitRandomized("mob_fire_wall"); var angle = Self.Direction.ToAngle(); var builder = new ProjectileBuilder(Self, "circle") { }; builder.AddFlags(ProjectileFlags.FlyOverStones); for (var i = 0; i < 5; i++) { builder.Slice = i == 0 ? "circle" : "small"; builder.Scale = i == 0 ? 1 : Rnd.Float(0.7f, 1f); var projectile = builder.Shoot(angle + (i == 0 ? 0 : Rnd.Float(-0.5f, 0.5f)), i == 0 ? 5f : Rnd.Float(6, 10f)).Build(); projectile.Color = i == 0 ? ProjectileColor.Cyan : ProjectileColor.Blue; projectile.Center += MathUtils.CreateVector(angle, 8); if (i == 0) { ProjectileCallbacks.AttachHurtCallback(projectile, (p, e) => { if (e.TryGetComponent(out var b)) { b.Add(new FrozenBuff() { Duration = 1 }); } }); } AnimationUtil.Poof(projectile.Center); } }; }; } else if (fired && T > 1f) { Self.GetComponent().Become(); } } } #endregion protected override Type GetIdleState() { return typeof(IdleState); } public override void Update(float dt) { base.Update(dt); T += dt; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/Snowball.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.prefabs; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class Snowball : Slime { public static readonly Color BloodColor = ColorUtils.FromHex("#92a1b9"); protected override Color GetBloodColor() { return BloodColor; } protected override float GetJumpDelay() { return Rnd.Float(0.6f, 1f); } protected override float GetJumpAngle() { return Target == null || Rnd.Chance(80) ? Rnd.AnglePI() : AngleTo(Target) + Rnd.Float(-0.1f, 0.1f); } protected override void SetStats() { base.SetStats(); AddComponent(new ZAnimationComponent("snowball") { ShadowOffset = 2 }); SetMaxHp(4); var body = CreateBodyComponent(); AddComponent(body); body.Body.LinearDamping = 2; body.KnockbackModifier = 0.7f; AddComponent(CreateSensorBodyComponent()); JumpForce = 40; ZVelocity = 3; GetComponent().Body.LinearDamping = 1; GetComponent().PitchMod = 0.2f; } protected virtual BodyComponent CreateBodyComponent() { return new RectBodyComponent(1, 11, 11, 1); } protected virtual BodyComponent CreateSensorBodyComponent() { return new SensorBodyComponent(1, 2, 11, 10); } protected override string GetHurtSfx() { return "mob_snowball_hut"; } protected override string GetDeadSfx() { return "mob_snowball_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/Snowflake.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.level; using Lens.entity; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class Snowflake : Mob { protected const float DefaultZ = 2; protected override Color GetBloodColor() { return Snowball.BloodColor; } protected override void SetStats() { base.SetStats(); SetMaxHp(6); GetComponent().Unhittable = true; var body = new SensorBodyComponent(1, 1, 14, 15); AddComponent(body); body.Body.LinearDamping = 0.3f; AddComponent(new ZAnimationComponent("snowflake")); AddComponent(new ZComponent() { Float = true }); AddComponent(new OrbitalComponent { Radius = 32, Lerp = true }); Depth = Layers.Wall; Become(); RemoveTag(Tags.MustBeKilled); } public override bool InAir() { return true; } public override void Update(float dt) { base.Update(dt); var rm = GetComponent().Room; if (rm == null || rm.Tagged[Tags.Player].Count == 0 || rm.Tagged[Tags.MustBeKilled].Count > 0) { return; } var h = GetComponent(); h.Unhittable = false; h.Kill(this); } #region Snowflake States public class IdleState : SmartState { private bool searched; private Entity target; public override void Init() { base.Init(); var component = Self.GetComponent(); Tween.To(0, component.Z, x => component.Z = x, 0.4f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); if (target != null) { if (target.Done) { target = null; return; } var dx = Self.DxTo(target); var dy = Self.DyTo(target); var d = MathUtils.Distance(dx, dy); if (d <= 32) { if (!target.HasComponent()) { target.AddComponent(new OrbitGiverComponent()); } target.GetComponent().AddOrbiter(Self); Become(); return; } var body = Self.GetComponent(); var s = dt * 200; body.Velocity += new Vector2(dx / d * s, dy / d * s); return; } if (!searched) { searched = true; target = Self.GetComponent().Room?.FindClosest(Self.Center, Tags.Mob, e => !e.HasComponent() && !(e is WallWalker || e is Boss)); if (target == null) { Self.Kill(Self); // target = Self.GetComponent().Room?.FindClosest(Self.Center, Tags.Player); } } if (T >= 1f && searched) { searched = false; } // fixme: pursue first, make unhittable but autodying (add tag for autodeath) } } public class OrbitingState : SmartState { public override void Init() { base.Init(); var component = Self.GetComponent(); Tween.To(DefaultZ, component.Z, x => component.Z = x, 0.4f, Ease.BackOut); } public override void Update(float dt) { base.Update(dt); var orbiting = Self.GetComponent().Orbiting; if (orbiting == null) { Become(); return; } if (orbiting.TryGetComponent(out var z)) { Self.GetComponent().Z = z.Z + DefaultZ; } } } #endregion public override bool ShouldCollide(Entity entity) { return !(entity is Level) && base.ShouldCollide(entity); } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/Snowman.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class Snowman : Mob { private float t; protected override Color GetBloodColor() { return Snowball.BloodColor; } protected override void SetStats() { base.SetStats(); Width = 24; Height = 22; t = Rnd.Float(4); SetMaxHp(30); var body = new RectBodyComponent(5, 21, 15, 1); AddComponent(body); body.Body.LinearDamping = 10; body.KnockbackModifier = 0.1f; AddComponent(new SensorBodyComponent(6, 2, 13, 19)); AddComponent(new MobAnimationComponent("snowman") { ShadowOffset = 3 }); Become(); TouchDamage = 0; } private void Fire() { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); GetComponent().InvincibilityTimer = 1f; var an = AngleTo(Target); var builder = new ProjectileBuilder(this, "carrot") { Color = ProjectileColor.Orange, Damage = 10 }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); builder.AddFlags(ProjectileFlags.HurtsEveryone); var projectile = builder.Shoot(an, 8f).Build(); projectile.Center = Center + MathUtils.CreateVector(an, 4f); ProjectileCallbacks.AttachUpdateCallback(projectile, TargetProjectileController.Make(Target)); }; }; } #region Snowman States public class IdleState : SmartState { public override void Init() { base.Init(); T = Self.t; } public override void Update(float dt) { base.Update(dt); if (Self.Target == null || !Self.CanSeeTarget()) { T = Self.t; return; } if (T >= 5f) { T = 0; Self.Fire(); } } } #endregion protected override void CreateGore(DiedEvent d) { var head = new Snowball(); Area.Add(head); head.TopCenter = TopCenter; var body = new SnowmanBody(); Area.Add(body); body.BottomCenter = BottomCenter; } protected override string GetHurtSfx() { return "mob_snowman_hurt"; } protected override string GetDeadSfx() { return "mob_snowman_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/SnowmanBody.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class SnowmanBody : Mob { private float t; public override void Update(float dt) { base.Update(dt); t += dt; } protected override Color GetBloodColor() { return Snowball.BloodColor; } protected override void SetStats() { base.SetStats(); Width = 24; Height = 15; SetMaxHp(20); var body = new RectBodyComponent(4, 14, 17, 1); AddComponent(body); body.Body.LinearDamping = 10; body.KnockbackModifier = 0.1f; AddComponent(new SensorBodyComponent(5, 2, 15, 12)); AddComponent(new MobAnimationComponent("snowman_body") { ShadowOffset = 3 }); GetComponent().PitchMod = -0.2f; Become(); TouchDamage = 0; } private void Fire() { if (Target == null) { return; } GetComponent().EmitRandomized("mob_fire"); var a = GetComponent(); Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); var an = AngleTo(Target) + t * 0.3f; var d = GetComponent().Percent <= 0.3f; var builder = new ProjectileBuilder(this, "carrot"); for (var i = 0; i < (d ? 8 : 4); i++) { var projectile = builder.Shoot(an + i * Math.PI * (d ? 0.25f : 0.5f), 4f).Build(); projectile.Color = d ? ProjectileColor.Red : ProjectileColor.Orange; projectile.Center = Center + MathUtils.CreateVector(an, 4f); } }; } #region Snowman body States public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (T >= 0.6f) { T = 0; Self.Fire(); } } } #endregion protected override string GetHurtSfx() { return "mob_snowman_hurt"; } protected override string GetDeadSfx() { return "mob_snowman_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/ice/Sponge.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.ice { public class Sponge : Mob { protected override Color GetBloodColor() { return Snowball.BloodColor; } protected override void SetStats() { base.SetStats(); Width = 32; Height = 24; SetMaxHp(20); var body = new RectBodyComponent(2, 22, 28, 1); AddComponent(body); body.KnockbackModifier = 0f; AddComponent(new SensorBodyComponent(3, 3, 25, 19)); AddComponent(new MobAnimationComponent("sponge") { ShadowOffset = 8 }); Become(); } private void Fire() { var a = GetComponent(); Tween.To(0.4f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(1.8f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Target != null) { Area.Add(new Missile(this, Target)); } }; } #region Snowman States public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { T = 0; return; } if (T >= 4f) { T = 0; Self.Fire(); } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/Bee.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.entity; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.jungle { public class Bee : Mob { protected float Speed = 1f; private static readonly Color color = ColorUtils.FromHex("#5ac54f"); protected override Color GetBloodColor() { return color; } protected virtual string GetAnimation() { return "bee"; } protected override string GetHurtSfx() { return "mob_bee_damage"; } protected override void SetStats() { base.SetStats(); Height = 12; AddAnimation(GetAnimation()); SetMaxHp(5); Become(); Flying = true; GetComponent().ShadowOffset = -2; AddBody(); var body = GetComponent(); body.Body.LinearDamping = 0.5f; body.Body.Restitution = 1; body.Body.Friction = 0; body.KnockbackModifier = 2.5f; Depth = Layers.FlyingMob; } protected virtual void AddBody() { AddComponent(new RectBodyComponent(2, 9, 12, 1)); AddComponent(new SensorBodyComponent(2, 3, 12, 8)); } protected override void OnHit(Entity e) { base.OnHit(e); if (e is Player) { e.GetComponent().Add(new SlowBuff { Duration = 5 }); } } #region Bee States public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.CanSeeTarget()) { Become(); } } } public class ChaseState : SmartState { private Vector2 lastSeen; public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Become(); return; } var see = Self.CanSeeTarget(); if (see) { lastSeen = Self.Target.Center; } else if (Self.DistanceTo(lastSeen) <= 16) { Become(); return; } var a = Self.AngleTo(lastSeen); var force = 50f * dt * Self.Speed; Self.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); Self.PushFromOtherEnemies(dt * 0.2f); } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/BeeHive.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.level.entities.decor; using BurningKnight.util; using Lens.assets; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.jungle { public class BeeHive : Mob { private const float ZHeight = 8; private bool loaded; private Tree tree; protected override void SetStats() { base.SetStats(); Width = 13; Depth = 1; AddAnimation("beehive"); SetMaxHp(10); Become(); var body = new SensorBodyComponent(2, 3, 9, 11); AddComponent(body); body.KnockbackModifier = 0; GetComponent().ShadowOffset = -ZHeight; } public override void Load(FileReader stream) { base.Load(stream); loaded = true; } public override void PostInit() { base.PostInit(); if (!loaded) { tree = new Tree(); tree.Id = 5; tree.AlwaysShow = true; Area.Add(tree); } Timer.Add(() => { GetComponent().Emit("mob_hive_static", 0.8f, looped: true, tween: true); }, 5f); } public override void Destroy() { base.Destroy(); GetComponent().StopAll(); } public override void Update(float dt) { base.Update(dt); if (tree != null) { tree.Position = Position - new Vector2(15, 16); } } #region Bee Hive States public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { if (T >= 10f) { T = 0; var bee = GenerateBee(); Self.GetComponent().Animate(); Self.Area.Add(bee); bee.BottomCenter = Self.BottomCenter; AnimationUtil.Ash(bee.Center); Self.GetComponent().Emit("mob_hive_pop"); } } else { T = 0; } } } public class FallingState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Emit("mob_hive_breaking"); Self.tree = null; var y = Self.Y; var c = Self.GetComponent(); Tween.To(0, c.ShadowOffset, x => c.ShadowOffset = x, 0.4f, Ease.QuadIn); Tween.To(y + ZHeight, y, x => Self.Y = x, 0.4f, Ease.QuadIn).OnEnd = () => { Audio.PlaySfx("mob_hive_release"); Self.AnimateDeath(null); Self.GetComponent().StopAll(); var am = 16; var builder = new ProjectileBuilder(Self, "circle") { Color = ProjectileColor.Orange, Bounce = 5 }; for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am) + Rnd.Float(-1f, 1f); builder.Scale = Rnd.Float(0.4f, 1f); var p = builder.Shoot(a, Rnd.Float(3f, 10f)).Build(); ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.25f, 0.5f, 1f)); } for (var i = 0; i < Rnd.Int(4, 10); i++) { var bee = GenerateBee(); Self.Area.Add(bee); bee.Center = Self.Center; } }; } } #endregion public static Bee GenerateBee() { var r = Rnd.Float(); if (r < 0.2f) { return new Explobee(); }/* else if (r < 0.3f) { return new BigBee(); }*/ return new Bee(); } protected override bool HandleDeath(DiedEvent d) { Become(); return true; } protected override string GetHurtSfx() { return "mob_hive_hurt"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/BigBee.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.util.math; namespace BurningKnight.entity.creature.mob.jungle { public class BigBee : Bee { public override void Init() { base.Init(); Speed = 0.25f; } protected override string GetAnimation() { return "bigbee"; } protected override bool HandleDeath(DiedEvent d) { for (var i = 0; i < Rnd.Int(2, 5); i++) { var bee = new Bee(); Area.Add(bee); bee.Center = Center; } return base.HandleDeath(d); } protected override void AddBody() { AddComponent(new RectBodyComponent(2, 17, 19, 1)); AddComponent(new SensorBodyComponent(2, 4, 19, 13)); } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/BuffedFlower.cs ================================================ namespace BurningKnight.entity.creature.mob.jungle { public class BuffedFlower : Flower { public override void Init() { base.Init(); ShootAllAtOnce = true; } protected override string GetAnimation() { return "buffed_flower"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/Explobee.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.creature.mob.jungle { public class Explobee : Bee { public override void Init() { base.Init(); Speed = 0.5f; } protected override string GetAnimation() { return "explobee"; } protected override bool HandleDeath(DiedEvent d) { GetAnyComponent().KnockbackFrom(d.From, 2f); if (d.DamageType != DamageType.Melee && d.DamageType != DamageType.Explosive) { ExplosionMaker.Make(this, 16); } return base.HandleDeath(d); } protected override void OnHit(Entity e) { // No slowness debuffs } protected override void AddBody() { AddComponent(new RectBodyComponent(2, 9, 12, 1)); AddComponent(new SensorBodyComponent(2, 3, 10, 10)); } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/Flower.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.jungle { public class Flower : Mob { protected bool ShootAllAtOnce; protected virtual string GetAnimation() { return "flower"; } protected override void SetStats() { base.SetStats(); Width = 18; Height = 21; AddAnimation(GetAnimation()); SetMaxHp(7); Become(); var body = new SensorBodyComponent(1, 1, 16, 19); AddComponent(body); body.KnockbackModifier = 0; } public override void Destroy() { base.Destroy(); foreach (var p in projectiles) { p.Break(); } projectiles.Clear(); } #region Flower States public class IdleState : SmartState { public override void Init() { base.Init(); T = Rnd.Float(1); } public override void Update(float dt) { base.Update(dt); if (!Self.CanSeeTarget()) { T = 0; } else if (T >= 1.5f) { Become(); } } } private List projectiles = new List(); public class FireState : SmartState { private bool second; public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { Become(); return; } if (T >= 0.2f) { T = 0; if (second) { if (Self.ShootAllAtOnce) { Self.GetComponent().Emit("mob_fire_static"); } for (var i = 0; i < (Self.ShootAllAtOnce ? 8 : 1); i++) { var p = Self.projectiles[0]; Self.projectiles.RemoveAt(0); if (!Self.ShootAllAtOnce) { Self.GetComponent().Emit("mob_fire_static", pitch: (Self.projectiles.Count / 16f - 0.5f) * 2); } if (!p.Done) { p.BodyComponent.Velocity = MathUtils.CreateVector(p.AngleTo(Self.Target), 200f); } else { p.Break(); } if (Self.projectiles.Count == 0) { Become(); } } } else { var builder = new ProjectileBuilder(Self, Self.projectiles.Count % 2 == 0 ? "circle" : "small"); var p = builder.Shoot(Self.AngleTo(Self.Target), 0).Build(); p.Center = Self.Position + new Vector2(9) + MathUtils.CreateVector(Self.projectiles.Count / 4f * Math.PI, 10); p.Depth = 1; Self.GetComponent().Emit("mob_flower_charging", pitch: Self.projectiles.Count / 8f); Self.projectiles.Add(p); if (Self.projectiles.Count == 8) { second = true; } } } } } #endregion protected override string GetHurtSfx() { return "mob_flower_hurt"; } protected override string GetDeadSfx() { return "mob_flower_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/Sniper.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.creature.player; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.creature.mob.jungle { public class Sniper : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("sniper"); SetMaxHp(4); Become(); var body = new RectBodyComponent(3, 13, 10, 1); AddComponent(body); body.Body.LinearDamping = 10; AddComponent(new SensorBodyComponent(2, 2, 12, 12)); } protected override bool HandleDeath(DiedEvent d) { ExplosionMaker.Make(this); return base.HandleDeath(d); } private int moveId; #region Bandit States public class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); if (T >= 3f && Self.CanSeeTarget()) { Become(); } } } private float lastAngle; public class AimState : SmartState { private Vector2 lastSeen; public override void Init() { base.Init(); Self.GetComponent().Emit("mob_sniper_focus"); Self.AlwaysVisible = true; // So that the line is visible Self.lastAngle = Self.AngleTo(Self.Target); lastSeen = Self.Target.Center; } public override void Update(float dt) { base.Update(dt); if (T < 1f) { if (Self.CanSeeTarget()) { Self.GraphicsComponent.Flipped = Self.Target.CenterX < Self.CenterX; lastSeen = Self.Target.Center; } Self.lastAngle = (float) MathUtils.LerpAngle(Self.lastAngle, Self.AngleTo(lastSeen), dt * 2f); } else if (T >= 1.5f) { Become(); } } public override void Destroy() { base.Destroy(); Self.AlwaysVisible = false; if (Self.Target == null) { return; } var a = Self.GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Self.Target == null) { return; } Self.GetComponent().EmitRandomized("mob_fire_static"); var builder = new ProjectileBuilder(Self, "rect") { RectHitbox = true, Scale = 1.5f, Damage = 2 }; builder.AddFlags(ProjectileFlags.FlyOverStones); for (var i = 0; i < 3; i++) { var angle = Self.lastAngle + (i - 1) * 0.1f; builder.Shoot(angle, 30f).Build(); } }; }; } } public override void Render() { base.Render(); if (GetComponent().StateInstance is AimState) { Graphics.Batch.DrawLine(Center - new Vector2(0, 2), new Vector2((int) (Center.X + Math.Cos(lastAngle) * Display.UiWidth), (int) (Center.Y + Math.Sin(lastAngle) * Display.UiWidth)), PlayerGraphicsComponent.AimLineColor, 1); } } #endregion protected override string GetDeadSfx() { return "mob_bandit_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/jungle/Wombat.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.mob.jungle { public class Wombat : Mob { protected override void SetStats() { base.SetStats(); AddAnimation("wombat"); SetMaxHp(5); Become(); Flying = true; Height = 12; GetComponent().ShadowOffset = -2; var body = new RectBodyComponent(1, 9, 14, 1); AddComponent(body); body.Body.LinearDamping = 2; body.Body.Restitution = 1; body.Body.Friction = 0; AddComponent(new SensorBodyComponent(1, 2, 14, 8)); } #region Wombat States public class IdleState : SmartState { public override void Init() { base.Init(); T = Rnd.Float(1); } public override void Update(float dt) { base.Update(dt); if (!Self.CanSeeTarget()) { T = 0; } else if (T >= 1.5f) { Become(); } } } public class FireState : SmartState { private float sinceLast; public override void Init() { base.Init(); if (Self.Target == null) { Become(); return; } Self.GetComponent().EmitRandomized("mob_wombat_fly"); Self.GetComponent().Velocity = MathUtils.CreateVector(Self.Target.AngleTo(Self), 10f); } public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast <= 0) { sinceLast = 0.2f; Self.GetComponent().EmitRandomized("mob_fire"); var builder = new ProjectileBuilder(Self, "square") { Scale = Rnd.Float(0.4f, 0.8f), RectHitbox = true }; builder.Shoot(Self.GetComponent().Velocity.ToAngle() - Math.PI + Rnd.Float(-0.2f, 0.2f), Rnd.Float(4, 7)).Build(); } if (T < 5f) { var body = Self.GetComponent(); body.Velocity += body.Velocity * (dt * 40); } else { Become(); } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/library/Book.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.pattern; using Lens.util; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.mob.library { public class Book : Mob { protected override void SetStats() { base.SetStats(); Width = 14; SetMaxHp(25); var body = new RectBodyComponent(0, 15, 14, 1); AddComponent(body); body.KnockbackModifier = 0.1f; body.Body.LinearDamping = 4f; AddComponent(new SensorBodyComponent(0, 0, 14, 16)); AddComponent(new ZAnimationComponent("book")); AddComponent(new ZComponent { Float = true }); Become(); } #region Snowman States public class IdleState : SmartState { private float delay; public override void Init() { base.Init(); delay = Rnd.Float(1f, 5f); } public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { if (T >= delay && Self.CanSeeTarget()) { Become(); } } else { T = 0; } } } public class ToRageState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Animation.Tag = "anim"; } public override void Update(float dt) { base.Update(dt); if (T >= 0.2f) { Become(); } } } public class ToIdleState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Animation.Tag = "anim"; } public override void Update(float dt) { base.Update(dt); if (T >= 0.2f) { Become(); } } } private const string Chars = "abcdefghijklmnopqrstuvwxyz"; public class RageState : SmartState { private bool fired; private float delay; public override void Init() { base.Init(); delay = Rnd.Float(1f, 2f); } public override void Update(float dt) { base.Update(dt); if (T >= 0.2f && !fired) { fired = true; if (Self.Target != null) { var h = Self.Target.GetComponent(); var c = h.Health <= 1 ? 'f' : Chars[Rnd.Int(Chars.Length)]; var a = Self.AngleTo(Self.Target); var color = ProjectileColor.Rainbow[Rnd.Int(ProjectileColor.Rainbow.Length)]; var sprite = Rnd.Chance(60) ? "circle" : "square"; if (LetterTemplateData.Data.TryGetValue(c, out var data)) { var p = new ProjectilePattern(KeepShapePattern.Make(0)) { Position = Self.Center }; Self.Area.Add(p); ProjectileTemplate.MakeFast(Self, sprite, Self.Center, a, (pr) => { p.Add(pr); pr.Color = color; pr.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); pr.BodyComponent.Angle = a; }, data, () => { Timer.Add(() => { p.Launch(a, Rnd.Float(30, 80)); Self.GetComponent().EmitRandomized("mob_fire_static"); }, 0.2f); }); } } } if (T >= delay || Self.Target == null) { Become(); } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/mob/library/Buffer.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.library { public class Buffer : Mob { private const float SafeDistance = 128f; protected override void SetStats() { base.SetStats(); Width = 11; Height = 15; TouchDamage = 0; SetMaxHp(32); var body = new RectBodyComponent(3, 14, 6, 1); AddComponent(body); body.Body.LinearDamping = 4f; AddComponent(new SensorBodyComponent(2, 1, 7, 14)); AddComponent(new MobAnimationComponent("buffer")); Become(); } public override void Destroy() { base.Destroy(); mob?.GetComponent().Remove(); } #region Buffer States public class RunState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { if (!Self.CanSeeTarget() || Self.MoveTo(Self.Target.Center, 60f, SafeDistance, true)) { Become(); } } Self.PushOthersFromMe(dt); } } private Mob mob; public class SummonState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Animation.Tag = "idle"; } public override void Update(float dt) { base.Update(dt); if (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) { Become(); return; } if (T >= 3f) { var list = Self.GetComponent().Room.Tagged[Tags.Mob]; if (list.Count <= 1) { return; } var attempt = 0; do { if (attempt >= 30) { return; } Self.mob = (Mob) list[Rnd.Int(list.Count)]; attempt++; } while (Self.mob == Self); Self.mob.GetComponent().Add(new BuffedBuff() { Infinite = true }); Become(); } } } public class BuffState : SmartState { public override void Destroy() { base.Destroy(); Self.mob?.GetComponent().Remove(); } public override void Update(float dt) { base.Update(dt); if (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) { Become(); return; } if (Self.mob != null && Self.mob.Done) { Self.mob = null; Become(); } } } #endregion protected override string GetHurtSfx() { return "mob_wizard_hurt"; } protected override string GetDeadSfx() { return "mob_wizard_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/library/Skeleton.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.desert; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.library { public class Skeleton : Mob { private const float SafeDistance = 128f; protected override void SetStats() { base.SetStats(); Width = 15; Height = 21; SetMaxHp(40); var body = new RectBodyComponent(2, 20, 11, 1); AddComponent(body); body.Body.LinearDamping = 4f; AddComponent(new SensorBodyComponent(3, 3, 9, 18)); AddComponent(new MobAnimationComponent("skeleton")); Become(); } #region Skeleton States public class RunState : SmartState { public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { if (!Self.CanSeeTarget() || Self.MoveTo(Self.Target.Center, 50f, SafeDistance, true)) { Become(); } } else { Become(); } Self.PushOthersFromMe(dt); } } public class SummonState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Animation.Tag = "idle"; } public override void Update(float dt) { base.Update(dt); if (Self.Target == null) { return; } if (Self.CanSeeTarget() && Self.DistanceTo(Self.Target) < SafeDistance - 16) { Become(); return; } Self.PushOthersFromMe(dt); if (T >= 5f) { T = -5; Self.GetComponent().Animate(() => { var summon = new Mummy(); Self.Area.Add(summon); summon.BottomCenter = Self.BottomCenter + new Vector2(0, 2); summon.Target = Self.Target; }); } } } #endregion protected override string GetHurtSfx() { return "mob_skeleton_hurt"; } protected override string GetDeadSfx() { return "mob_skeleton_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/library/TeleportingMage.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.pattern; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Utilities; using MathUtils = Lens.util.MathUtils; namespace BurningKnight.entity.creature.mob.library { public class TeleportingMage : Mob { private Color color; protected override void SetStats() { base.SetStats(); Width = 10; Height = 14; SetMaxHp(30); var body = new RectBodyComponent(0, 13, 10, 1); AddComponent(body); body.KnockbackModifier = 0f; body.Body.LinearDamping = 4f; AddComponent(new SensorBodyComponent(1, 1, 8, 13)); AddComponent(new MobAnimationComponent("mage")); Become(); color = ProjectileColor.Rainbow[Rnd.Int(ProjectileColor.Rainbow.Length)]; } #region Snowman States public class IdleState : SmartState { private float delay; private bool tweened; public override void Init() { base.Init(); delay = Rnd.Float(4, 10f); } public override void Update(float dt) { base.Update(dt); if (Self.Target != null) { Self.GraphicsComponent.Flipped = Self.Target.CenterX < Self.CenterX; } if (!tweened && T >= delay - 0.4f) { tweened = true; Self.GetComponent().Animate(); } if (T >= delay && Self.CanSeeTarget()) { var p = new ProjectilePattern(KeepShapePattern.Make(Rnd.Chance() ? -4 : 4)) { Position = Self.Center }; Self.Area.Add(p); var sa = Rnd.AnglePI(); var count = 5; var builder = new ProjectileBuilder(Self, "small") { LightRadius = 32f, Color = Self.color }; builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < count; i++) { var i1 = i; Timer.Add(() => { var a = (float) Math.PI * i1 / (count * 0.5f) + sa; var pr = builder.Build(); pr.BodyComponent.Angle = a; pr.Center = Self.Center + MathUtils.CreateVector(a, 12); p.Add(pr); Self.GetComponent().EmitRandomized("mob_fire"); if (i1 == count - 1) { p.Launch(Self.Target == null ? Rnd.AnglePI() : Self.AngleTo(Self.Target), 80); } }, i * 0.1f); } Become(); } } } public class TeleportState : SmartState { private bool teleported; public override void Update(float dt) { base.Update(dt); if (T >= 1.5f && !teleported) { teleported = true; var a = Self.GetComponent(); Tween.To(0.2f, a.Scale.X, x => a.Scale.X = x, 0.5f, Ease.QuadIn); Tween.To(2f, a.Scale.Y, x => a.Scale.Y = x, 0.5f, Ease.QuadIn).OnEnd = () => { var r = Self.GetComponent().Room; Vector2 s; do { s = r.GetRandomFreeTile() * 16 + new Vector2(8); } while (Self.Target != null && Self.Target.DistanceTo(s) < 32); Self.Center = s; Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.5f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.5f).OnEnd = () => { Become(); }; }; } } } #endregion protected override string GetHurtSfx() { return "mob_wizard_hurt"; } protected override string GetDeadSfx() { return "mob_wizard_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefabs/Slime.cs ================================================ using System; using System.Numerics; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.level; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using Vector2 = Microsoft.Xna.Framework.Vector2; namespace BurningKnight.entity.creature.mob.prefabs { public class Slime : Mob { private bool first; private float delay; private static readonly Color color = ColorUtils.FromHex("#5ac54f"); protected override Color GetBloodColor() { return color; } protected override void OnTargetChange(Entity target) { base.OnTargetChange(target); if (target != null) { delay = Rnd.Float(0, 2f); } } protected virtual float GetJumpDelay() { return 1; } protected virtual float GetJumpAngle() { return Target == null ? Rnd.AnglePI() : AngleTo(Target) + Rnd.Float(-0.1f, 0.1f); } protected override void SetStats() { base.SetStats(); AddComponent(new ZComponent()); Become(); AddDrops(new SingleDrop("bk:slime", 0.01f)); } #region Slime States public class IdleState : SmartState { private float delay; private bool tweened; public override void Init() { base.Init(); delay = Self.first ? Rnd.Float(1f) : Self.GetJumpDelay(); Self.first = false; // To avoid exceptions when loading old save due to component not being there if (Self.TryGetComponent(out var c)) { c.Velocity = Vector2.Zero; } } public override void Update(float dt) { if (Self.delay > 0) { Self.delay -= dt; return; } base.Update(dt); if (!tweened && T >= delay) { tweened = true; Self.GetComponent().EmitRandomizedPrefixed("mob_slime_jump", 2); Self.AnimateJump(() => { Become(); }); } } } protected float JumpForce = 120; protected float ZVelocity = 5; protected virtual void AnimateJump(Action callback) { var anim = GetComponent(); Tween.To(2f, anim.Scale.X, x => anim.Scale.X = x, 0.2f); Tween.To(0.3f, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(0.5f, anim.Scale.X, x => anim.Scale.X = x, 0.3f); Tween.To(2f, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f).OnEnd = () => { Tween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.2f); Tween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.2f); }; callback(); }; } protected virtual void AnimateLand() { var anim = GetComponent(); anim.Scale.X = 2f; anim.Scale.Y = 0.3f; Tween.To(1, anim.Scale.X, x => anim.Scale.X = x, 0.3f); Tween.To(1, anim.Scale.Y, x => anim.Scale.Y = x, 0.3f); } public class JumpState : SmartState { public bool InAir; public override void Init() { base.Init(); InAir = true; Self.OnJump(); var a = Self.GetJumpAngle(); var force = Rnd.Float(20f) + Self.JumpForce; Self.GetComponent().Velocity = new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); Self.GetComponent().ZVelocity = Self.ZVelocity; } public override void Destroy() { base.Destroy(); Self.AnimateLand(); Self.GetComponent().Velocity = Vector2.Zero; Self.OnLand(); Self.GetComponent().EmitRandomizedPrefixed("mob_slime_land", 2); } public override void Update(float dt) { base.Update(dt); var component = Self.GetComponent(); if (component.Z >= 4f) { Self.Depth = Layers.FlyingMob; Self.TouchDamage = 0; } else { Self.Depth = Layers.Creature; Self.TouchDamage = 1; } if (T >= 0.1f && component.Z <= 0) { component.Z = 0; InAir = false; Become(); } } } #endregion public override bool InAir() { return (GetComponent().StateInstance is JumpState j && j.InAir); } public override bool ShouldCollide(Entity entity) { if (entity is Chasm) { return !InAir(); } return base.ShouldCollide(entity); } public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent ev && ev.Amount < 0 && InAir() && GetComponent().Z > 4f) { return true; } return base.HandleEvent(e); } public override bool ShouldCollideWithDestroyableInAir() { return true; } public override bool IgnoresProjectiles() { return InAir(); } protected virtual void OnJump() { } protected virtual void OnLand() { if (Target == null) { return; } Area.Add(new SplashFx { Position = Center, Color = ColorUtils.Mod(GetBloodColor()) }); } protected override string GetDeadSfx() { return "mob_slime_death"; } protected override string GetHurtSfx() { return "slime_hurt"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefabs/WallWalker.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.castle; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.level.entities; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.mob.prefabs { public class WallWalker : Mob { protected internal Direction Direction; public bool Left; public float T; public bool Inited; public override bool InAir() { return true; } protected override void SetStats() { base.SetStats(); Width = 16; Height = 16; Left = Rnd.Chance(); GetComponent().AddImmunity(); } private bool locked; private void LockToWall() { try { var dirs = new List(); var x = (int) Math.Round(X / 16f); var y = (int) Math.Round((Y + 8) / 16f); var level = Run.Level; if (level.Get(x + 1, y).IsWall()) { dirs.Add(Direction.Left); } if (level.Get(x - 1, y).IsWall()) { dirs.Add(Direction.Right); } if (level.Get(x, y + 1).IsWall()) { dirs.Add(Direction.Up); } if (level.Get(x, y - 1).IsWall()) { dirs.Add(Direction.Down); } if (dirs.Count == 0) { Log.Error("No walls to lock to!"); Timer.Add(() => { Done = true; }, 0.1f); return; } CenterX = x * 16 + 8; CenterY = y * 16; Direction = dirs[Rnd.Int(dirs.Count)]; var angle = Direction.ToAngle(); var v = Direction == Direction.Up || Direction == Direction.Down; var body = new RectBodyComponent(Direction == Direction.Left ? 8 : 0, Direction == Direction.Up ? 8 : 0, v ? 16 : 8, v ? 8 : 16, BodyType.Dynamic, true); AddComponent(body); body.KnockbackModifier = 0; GetComponent().WallAngle = angle; GetComponent().State = GetIdleState(); } catch (Exception e) { Timer.Add(() => { Done = true; }, 0.1f); } } public override void Save(FileWriter stream) { var y = Y; X = (int) Math.Floor(X / 16f) * 16; Y = (int) Math.Floor(y / 16f) * 16 + 8; base.Save(stream); Y = y; } protected virtual float GetSpeed() { return 30f; } #region Walker States public class IdleState : SmartState { protected Vector2 velocity; protected float vx; protected float vy; protected int mx; protected int my; public void ResetVelocity() { velocity = Vector2.Zero; vx = 0; vy = 0; Self.GetComponent().Velocity = velocity; } public void InvertVelocity() { Self.Left = !Self.Left; velocity *= -1; vx *= -1; vy *= -1; Self.GetComponent().Velocity = velocity; T = 0; } public override void Init() { base.Init(); if (!Self.Inited) { Self.Inited = true; T = Rnd.Float(1f); } var f = Self.GetSpeed(); var a = Self.Direction.ToAngle(); if (Self.Left) { a += (float) Math.PI; } vx = (float) Math.Sin(a); vy = (float) Math.Cos(a); velocity.X = vx * f; velocity.Y = vy * f; mx = Self.Direction.GetMx(); my = Self.Direction.GetMy(); } public override void Update(float dt) { base.Update(dt); /*var mx = Self.CenterX; var my = Self.CenterY; var x = (int) Math.Round(mx / 16f); var y = (int) Math.Round(my / 16f); if (Run.Level.IsInside(x, y) && Run.Level.Get(x, y).IsWall()) { Log.Debug("Killing walker"); Timer.Add(() => { Self.Done = true; }, 0.1f); return; }*/ var mx = Self.X + (this.mx) * 16; var my = Self.CenterY + (this.my) * 16; if (!Run.Level.Get((int) Math.Round(mx / 16f), (int) Math.Round(my / 16f)).IsWall()) { Self.GetComponent().Kill(Self); return; } mx = Self.X + (this.mx + vx * 0.5f) * 16; my = Self.CenterY + (this.my + vy * 0.5f) * 16; var tx = (int) Math.Round(mx / 16f); var ty = (int) Math.Round(my / 16f); if (!Run.Level.Get(tx, ty).IsWall()) { Flip(); return; } mx = Self.X + (vx) * 12; my = Self.CenterY + (vy) * 12; tx = (int) Math.Round(mx / 16f); ty = (int) Math.Round(my / 16f); if (Run.Level.Get(tx, ty).IsWall()) { Flip(); return; } DoLogic(dt); Self.GetComponent().Velocity = velocity; } public virtual void DoLogic(float dt) { } public virtual void Flip() { InvertVelocity(); } } #endregion protected virtual Type GetIdleState() { return typeof(IdleState); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { var en = ev.Entity; if (en is Door || (en is SolidProp && !(en is BreakableProp))) { var state = GetComponent().StateInstance; if (state is IdleState s) { s.Flip(); } } } return base.HandleEvent(e); } public override void Update(float dt) { if (Done) { return; } if (!locked) { locked = true; LockToWall(); } base.Update(dt); T += dt; var room = GetComponent().Room; if (room == null) { return; } if (room.Type != RoomType.Regular && room.Type != RoomType.Boss) { Timer.Add(() => { Done = true; }, 0.1f); return; } /*if (room.Tagged[Tags.Player].Count == 0) { return; } foreach (var m in room.Tagged[Tags.MustBeKilled]) { if (m is Mob && !(m is WallWalker || m is bk.BurningKnight)) { return; } } Kill(this);*/ } protected override string GetDeadSfx() { return "mob_hugger_death"; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/DeathShotPrefix.cs ================================================ using System; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class DeathShotPrefix : Prefix { private static Vector4 color = new Vector4(245 / 255f, 85 / 255f, 93 / 255f, 1); public override bool HandleEvent(Event e) { if (e is DiedEvent) { var am = 8; var builder = new ProjectileBuilder(Mob, "small") { LightRadius = 32 }; for (var i = 0; i < am; i++) { var a = Math.PI * 2 * (((float) i) / am) + Rnd.Float(-0.1f, 0.1f); builder.Shoot(a, 3f).Build(); } } return base.HandleEvent(e); } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/EmeraldPrefix.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class EmeraldPrefix : Prefix { private static Vector4 color = new Vector4(0, 220 / 255f, 152 / 255f, 1); public override void Init() { base.Init(); Mob.GetComponent().Add(new SimpleDrop(1f, 2, 5, "bk:emerald")); } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/ExplosivePrefix.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.bomb; using BurningKnight.entity.events; using Lens.entity; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class ExplosivePrefix : Prefix { private static Vector4 color = new Vector4(138 / 255f, 72 / 255f, 54 / 255f, 1); public override bool HandleEvent(Event e) { if (e is DiedEvent) { var bomb = new Bomb(Mob); Mob.Area.Add(bomb); bomb.Center = Mob.Center; } return base.HandleEvent(e); } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/FragilePrefix.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.util; using Lens.entity; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class FragilePrefix : Prefix { private static Vector4 color = new Vector4(146 / 255f, 161 / 255f, 185 / 255f, 1); public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent hme) { if (hme.Amount < 0) { AnimationUtil.Poof(Mob.Center, 1); var room = Mob.GetComponent().Room; if (room == null) { return base.HandleEvent(e); } Mob.Center = room.GetRandomFreeTile() * 16 + new Vector2(8, 8); AnimationUtil.Poof(Mob.Center, 1); } } return base.HandleEvent(e); } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/GoldPrefix.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class GoldPrefix : Prefix { private static Vector4 color = new Vector4(1f, 200 / 255f, 37 / 255f, 1); public override void Init() { base.Init(); Mob.GetComponent().Add(new SimpleDrop(1f, 1, 3, "bk:copper_coin")); } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/HealthyPrefix.cs ================================================ using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class HealthyPrefix : Prefix { private static Vector4 color = new Vector4(255 / 255f, 0, 64 / 255f, 1); public override void Init() { base.Init(); var health = Mob.GetComponent(); health.InitMaxHealth = health.MaxHealth * 2; } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/Prefix.cs ================================================ using Lens.entity; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public abstract class Prefix { public Mob Mob; public string Id; public virtual void Init() { } public virtual void Update(float dt) { } public virtual bool HandleEvent(Event e) { return false; } public abstract Vector4 GetColor(); } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/PrefixRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.mod; namespace BurningKnight.entity.creature.mob.prefix { public static class PrefixRegistry { public static Dictionary Defined = new Dictionary(); static PrefixRegistry() { Define("explosive"); Define("death_shot"); Define("healthy_shot"); // Define("emerald"); Define("fragile"); Define("gold"); } public static void Define(string id, Mod mod = null) where T : Prefix { Defined[$"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}"] = typeof(T); } } } ================================================ FILE: BurningKnight/entity/creature/mob/prefix/RegenerativePrefix.cs ================================================ using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.mob.prefix { public class RegenerativePrefix : Prefix { private static Vector4 color = new Vector4(237f / 255f, 118 / 255f, 20 / 255f, 1); private float sinceLast; public override void Update(float dt) { base.Update(dt); sinceLast -= dt; if (sinceLast < 0) { sinceLast = 1; var health = Mob.GetComponent(); if (!health.IsFull()) { health.ModifyHealth(1f, Mob); } } } public override Vector4 GetColor() { return color; } } } ================================================ FILE: BurningKnight/entity/creature/npc/AccessoryTrader.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.save; using Lens.util.math; namespace BurningKnight.entity.creature.npc { public class AccessoryTrader : ShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 12; Height = 15; AddComponent(new AnimationComponent("accessory_trader")); var b = new RectBodyComponent(2, 6, Width - 4, Height - 6); AddComponent(b); b.KnockbackModifier = 0; } protected override string GetDialog() { return $"accessorytrader_{Rnd.Int(3)}"; } public override string GetId() { return AccessoryTrader; } protected override bool OwnsStand(ItemStand stand) { return stand is ArtifactStand; } } } ================================================ FILE: BurningKnight/entity/creature/npc/ActiveTrader.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using Lens.util.math; namespace BurningKnight.entity.creature.npc { public class ActiveTrader : ShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 17; Height = 22; AddComponent(new AnimationComponent("active_trader")); var b = new RectBodyComponent(2, 6, Width - 4, Height - 6); AddComponent(b); b.KnockbackModifier = 0; GetComponent().Dialog.Voice = 1; } protected override string GetDialog() { return $"activetrader_{Rnd.Int(3)}"; } public override string GetId() { return ActiveTrader; } protected override bool OwnsStand(ItemStand stand) { return stand is ActiveStand; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Beet.cs ================================================ using System; using System.Text; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.entity.component.logic; using Lens.input; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework.Input; namespace BurningKnight.entity.creature.npc { public class Beet : Npc { private Entity interactingWith; static Beet() { Dialogs.RegisterCallback("beet_0", (d, c) => { c.Dialog.Str.SetVariable("seed", Run.NextSeed); return Dialogs.Get($"beet_{(Run.IgnoreSeed ? 4 : 1)}"); }); Dialogs.RegisterCallback("beet_2", (d, c) => { var a = ((AnswerDialog) d).Answer; Log.Info($"Beet set the seed to {a}"); Rnd.Seed = a; Run.NextSeed = a; Run.IgnoreSeed = true; return null; }); Dialogs.RegisterCallback("beet_4", (d, c) => { if (((ChoiceDialog) d).Choice == 2) { Run.NextSeed = Rnd.GenerateSeed(); Run.IgnoreSeed = false; c.Dialog.Str.SetVariable("seed", Run.NextSeed); Log.Info($"Beet randomly set the seed to {Run.NextSeed}"); } return null; }); } public override void AddComponents() { base.AddComponents(); Width = 18; Height = 19; AddComponent(new AnimationComponent("beet")); AddComponent(new RectBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2) { KnockbackModifier = 0 }); AddComponent(new InteractableComponent(Interact)); GetComponent().Become(); var dialog = GetComponent(); dialog.Dialog.Voice = 1; dialog.OnNext += (c) => { if (c.Current == null && !Run.IgnoreSeed) { GetComponent().Become(); } }; } public override void Update(float dt) { base.Update(dt); if (GetComponent().Current?.Id == "beet_2" && Input.Keyboard.WasPressed(Keys.V) && (Input.Keyboard.IsDown(Keys.LeftControl) || Input.Keyboard.IsDown(Keys.RightControl))) { Log.Info("Pasting the seed"); var seed = "ERROR"; try { // Needs xclip on linux seed = TextCopy.Clipboard.GetText().ToUpper(); } catch (Exception e) { Log.Error(e); } if (seed.Length == 0) { return; } if (seed.Length > 8) { seed = seed.Substring(0, 8); } var builder = new StringBuilder(); for (var i = 0; i < seed.Length; i++) { var c = seed[i]; builder.Append(Rnd.SeedChars.IndexOf(c) != -1 && c != '_' ? c : 'X'); } var result = builder.ToString(); Log.Info($"Initial seed {seed} converted to {result}"); ((AnswerDialog) GetComponent().Current).Answer = result; } } private bool Interact(Entity e) { var state = GetComponent(); if (state.StateInstance is IdleState) { interactingWith = e; state.Become(); } else { GetComponent().Start("beet_0", e); } return true; } #region Beet States public class IdleState : SmartState { } public class PopState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Emit("npc_beet_show"); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(); } } } public class HideState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Emit("npc_beet_hide"); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(); } } } public class PoppedState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Start("beet_0", Self.interactingWith); Self.interactingWith = null; } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/npc/Bird.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class Bird : Npc { public override void AddComponents() { base.AddComponents(); Height = 14; AddComponent(new AnimationComponent("bird")); Subscribe(); AddComponent(new QuackInteractionComponent(p => { Timer.Add(() => { var d = GetComponent(); if (d.Current != null && d.Current.Id != "quack") { d.StartAndClose("quack", 3); } GetComponent().EmitRandomized("quck"); }, 0.5f); })); } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce && rce.Who is Player) { if (rce.New == GetComponent().Room) { GetComponent().Start("^^Spanish^^ or [cl red]##vanish##[cl]!"); } else { GetComponent().Close(); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/npc/Brastin.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class Brastin : Npc { public override void AddComponents() { base.AddComponents(); Width = 13; Height = 18; AddComponent(new AnimationComponent("brastin")); AddComponent(new CloseDialogComponent("brastin_0")); GetComponent().Dialog.Voice = 3; if (Achievements.Get("bk:cat_without_a_hat").Unlocked) { Done = true; } } } } ================================================ FILE: BurningKnight/entity/creature/npc/Builder.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.level.entities.chest; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.util.timer; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc { public class Builder : Npc { private int cost; private int paid; private bool shouldDissappear; private int GetPrice() { return Math.Max(3, cost - paid); } public override void AddComponents() { base.AddComponents(); Width = 7; Height = 17; AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static)); cost = Math.Min(99, Run.Depth * 15); paid = GlobalSave.GetInt("builder_paid", 0); AddComponent(new AnimationComponent("builder")); // GetComponent().Dialog.Voice = 15; var dl = GetComponent(); dl.InitCallback = () => { dl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice("coin")); dl.Dialog.Str.SetVariable("need", GetPrice()); }; AddComponent(new InteractableComponent(e => { dl.Start("builder_0", e); return true; }) { CanInteract = e => !shouldDissappear }); Dialogs.RegisterCallback("builder_0", (d, c) => { if (((ChoiceDialog) d).Choice == 0) { if (!c.To.TryGetComponent(out var component) || component.Coins == 0) { // Bro, you have no money! return Dialogs.Get("builder_1"); } var amount = Math.Min(GetPrice(), component.Coins); paid += amount; component.Coins -= amount; dl.Dialog.Str.SetVariable("need", GetPrice()); if (paid >= cost) { GlobalSave.Put("builder_paid", 0); GlobalSave.Put($"shortcut_{Run.Depth}", true); return Dialogs.Get("builder_3"); } else { GlobalSave.Put("builder_paid", paid); } return Dialogs.Get("builder_2"); } return Dialogs.Get("builder_4"); }); Dialogs.RegisterCallback("builder_3", (d, c) => { shouldDissappear = true; CheckShortcutUnlocks(); Timer.Add(() => { AnimationUtil.Poof(Center); Done = true; }, 5f); return null; }); } public static void CheckShortcutUnlocks() { if (GlobalSave.IsTrue("shortcut_3")) { Achievements.Unlock("bk:desert_shortcut"); } if (GlobalSave.IsTrue("shortcut_5")) { Achievements.Unlock("bk:jungle_shortcut"); } if (GlobalSave.IsTrue("shortcut_7")) { Achievements.Unlock("bk:ice_shortcut"); } if (GlobalSave.IsTrue("shortcut_9")) { Achievements.Unlock("bk:library_shortcut"); } } public override void PostInit() { base.PostInit(); if (GlobalSave.IsTrue($"shortcut_{Run.Depth}")) { Done = true; return; } if (Run.Depth > 0) { GameSave.Put("seen_builder", true); } } public static bool ShouldAppear() { if (Run.Type != RunType.Regular || GameSave.IsTrue("seen_builder")) { return false; } if (Run.Depth == 5 && LevelSave.GenerateMarket && Run.Loop == 0) { return false; } if (Run.Depth == 3 || Run.Depth == 5 || Run.Depth == 7 || Run.Depth == 9) { return GlobalSave.IsFalse($"shortcut_{Run.Depth}"); } return false; } } } ================================================ FILE: BurningKnight/entity/creature/npc/DarkMage.cs ================================================ using System.Timers; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.level.biome; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.math; using Timer = Lens.util.timer.Timer; namespace BurningKnight.entity.creature.npc { public class DarkMage : Npc { public override void AddComponents() { base.AddComponents(); Width = 14; Height = 17; AddComponent(new AnimationComponent("dark_mage")); if (!(Run.Level?.Biome is LibraryBiome)) { AddComponent(new CloseDialogComponent("dm_0")); } Subscribe(); Subscribe(); } public override bool HandleEvent(Event e) { if (e is Dialog.EndedEvent dee) { if (dee.Dialog.Id == "bk_10") { Timer.Add(() => { // Really, well, thank you, Limpor GetComponent().StartAndClose("dm_1", 5); }, 1f); } } else if (e is ItemTakenEvent ite) { if (ite.Stand is DarkMageStand) { // Yes, yes, I need more power! // MORE POWER!!! // I can feel the energy growing in me! GetComponent().StartAndClose($"dm_{Rnd.Int(2, 4)}", 5); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/npc/Discord.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class Discord : Npc { public override void AddComponents() { base.AddComponents(); Width = 10; Height = 12; AddComponent(new AnimationComponent("discord")); // todo: connect discordIntegration CurrentPlayer here AddComponent(new CloseDialogComponent("discord_0")); GetComponent().Dialog.Voice = 2; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Duck.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens; using Lens.util.file; using Lens.util.math; using VelcroPhysics.Utilities; namespace BurningKnight.entity.creature.npc { public class Duck : Npc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 12; Height = 10; AddComponent(new AnimationComponent("duck")); var b = new RectBodyComponent(0, 0, Width, Height); AddComponent(b); b.KnockbackModifier = 0; quantom = Rnd.Chance(1); if (Run.Depth == -2) { AddComponent(new CloseDialogComponent("control_4")); } else { AddComponent(new CloseDialogComponent($"duck_{(quantom ? 20 : 19)}")); } Become(); GetComponent().Dialog.Voice = 4; } private bool set; private float x; private bool quantom; public override void PostInit() { base.PostInit(); x = X; } public override void Save(FileWriter stream) { if (Engine.Instance.State is EditorState) { x = X; } else { X = x; } base.Save(stream); } public override void Update(float dt) { base.Update(dt); if (!set) { set = true; var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Duck, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Duck, true))); } } } #region Duck States private class IdleState : SmartState { private bool toLeft; private float vx; private float pauseTimer; private float tillPause; public override void Update(float dt) { base.Update(dt); Self.GraphicsComponent.Flipped = toLeft; if (pauseTimer > 0) { pauseTimer -= dt; if (pauseTimer <= 0) { tillPause = Rnd.Float(0.5f, 2f); } } else if (tillPause >= 0) { tillPause -= dt; if (tillPause < 0) { tillPause = 0; pauseTimer = Rnd.Float(0.5f, 2f); } vx += (toLeft ? -1 : 1) * (dt * 10); } vx -= vx * (dt * 3); var n = Self.X + vx * (10 * dt); if (Self.quantom) { Self.X = MathUtils.Clamp(n, Self.x - 16, Self.x + 16); if (Math.Abs(Self.X - Self.x) >= 16) { toLeft = !toLeft; Self.X = Self.x + (toLeft ? -16 : 16); vx *= -1; if (Rnd.Chance(10)) { Self.X = Self.x; } } } else { Self.X = MathUtils.Clamp(n, Self.x - 16, Self.x + 16); if (Math.Abs(Self.X - Self.x) >= 16) { toLeft = !toLeft; vx *= -1; } } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/npc/Elon.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class Elon : Npc { public override void AddComponents() { base.AddComponents(); Width = 17; Height = 19; AddComponent(new AnimationComponent("elon")); AddComponent(new CloseDialogComponent("elon_0")); GetComponent().Dialog.Voice = 15; } } } ================================================ FILE: BurningKnight/entity/creature/npc/EmeraldGolem.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.assets.particle; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc { public class EmeraldGolem : Npc { private const int Amount = 20; private bool broken; public override void AddComponents() { base.AddComponents(); Width = 31; Height = 33; AddComponent(new AnimationComponent("emerald_golem")); AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding, BodyType.Static)); AddComponent(new RectBodyComponent(2, 17, 27, 16, BodyType.Static)); AddComponent(new InteractableComponent(Interact) { CanInteract = e => !broken }); GetComponent().Dialog.Voice = 15; Dialogs.RegisterCallback("eg_0", (d, c) => { if (broken) { return null; } if (((ChoiceDialog) d).Choice == 0) { Timer.Add(() => { GetComponent().StartAndClose(Locale.Get("eg_1"), 3); }, 0.2f); var inv = c.To.GetComponent(); var a = c.To.Area; for (var i = 0; i < Amount; i++) { inv.Pickup(Items.CreateAndAdd("bk:emerald", a)); } Timer.Add(() => { inv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a)); }, 1f); Timer.Add(() => { GetComponent().Animate(() => { Done = true; Engine.Instance.Flash = 1f; Camera.Instance.Shake(8); for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Center + Rnd.Vector(-16, 16); part.Particle.Scale = Rnd.Float(1f, 2f); Run.Level.Area.Add(part); part.Depth = 1; } }); }, 4f); broken = true; return null; } else if (GlobalSave.IsTrue("bk:emerald_gun")) { Timer.Add(() => { GetComponent().StartAndClose(Locale.Get("eg_1"), 3); }, 0.2f); var inv = c.To.GetComponent(); var a = c.To.Area; inv.Pickup(Items.CreateAndAdd("bk:emerald_gun", a)); Timer.Add(() => { inv.Pickup(Items.CreateAndAdd(Scourge.GenerateItemId(), a)); }, 1f); Timer.Add(() => { GetComponent().Animate(() => { Done = true; Engine.Instance.Flash = 1f; Camera.Instance.Shake(8); for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Center + Rnd.Vector(-16, 16); part.Particle.Scale = Rnd.Float(1f, 2f); Run.Level.Area.Add(part); part.Depth = 1; } }); }, 4f); broken = true; return null; } return null; }); Subscribe(); } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce && rce.Who is Player) { if (rce.New == GetComponent().Room) { GetComponent().StartAndClose("eg_3", 3); } else { GetComponent().Close(); } } return base.HandleEvent(e); } private bool Interact(Entity e) { GetComponent().Start("eg_0", e); return true; } public override void Load(FileReader stream) { base.Load(stream); broken = stream.ReadBoolean(); // todo: update the sprite } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(broken); } public override bool ShouldCollide(Entity entity) { return true; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Granny.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.level.rooms; using BurningKnight.save; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class Granny : Npc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 15; AddComponent(new AnimationComponent("grandma")); var b = new RectBodyComponent(2, 6, Width - 4, Height - 6); AddComponent(b); b.KnockbackModifier = 0; Subscribe(); Subscribe(); Subscribe(); GetComponent().Dialog.Voice = 19; } private float delay; public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { delay = Rnd.Float(1, 4); GraphicsComponent.Flipped = !GraphicsComponent.Flipped; } } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce) { var room = GetComponent().Room; if (rce.Who is Player && rce.New == room) { GetComponent().EmitRandomized("hi"); // Welcome, gobbo! GetComponent().Dialog.Str.SetVariable("id", MathUtils.ToRoman((int) GlobalSave.RunId)); GetComponent().StartAndClose(room.Type == RoomType.Granny ? "granny_4" : GetDialog(), 3); if (rce.New.Type != RoomType.Granny) { Achievements.Unlock("bk:tea_party"); } } } else if (e is Dialog.EndedEvent dee) { if (dee.Dialog.Id == "bk_9") { Timer.Add(() => { // You will die first, Limpor! GetComponent().StartAndClose("granny_3", 5); }, 1f); } } else if (e is ItemTakenEvent ite) { if (ite.Stand is GrannyStand) { // Good luck on your sad quest! GetComponent().StartAndClose("granny_5", 10); } } return base.HandleEvent(e); } private string GetDialog() { return $"granny_{Rnd.Int(3)}"; } } } ================================================ FILE: BurningKnight/entity/creature/npc/HatTrader.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using Lens.util.math; namespace BurningKnight.entity.creature.npc { public class HatTrader : ShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 13; Height = 20; AddComponent(new AnimationComponent("hat_trader")); var b = new RectBodyComponent(2, 6, Width - 4, Height - 6); AddComponent(b); b.KnockbackModifier = 0; GetComponent().Dialog.Voice = 6; } protected override string GetDialog() { return $"hattrader_{Rnd.Int(3)}"; } public override string GetId() { return HatTrader; } protected override bool OwnsStand(ItemStand stand) { return stand is HatStand; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Isaac.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.entity.creature.npc { public class Isaac : Npc { public override void AddComponents() { base.AddComponents(); Width = 12; Height = 11; AddComponent(new AnimationComponent("isaac")); AddComponent(new CloseDialogComponent("isaac_0", "isaac_1", "isaac_2")); } } } ================================================ FILE: BurningKnight/entity/creature/npc/MaPuzzle.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class MaPuzzle : Npc { public override void AddComponents() { base.AddComponents(); Width = 10; Height = 8; AddComponent(new AnimationComponent("mapuzzle")); AddComponent(new CloseDialogComponent("mapuzzle_0")); GetComponent().Dialog.Voice = 17; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Maanex.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.entities.chest; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class Maanex : Npc { private bool interacted; private bool played; private byte cost; private float t; public override void AddComponents() { base.AddComponents(); Width = 12; Height = 15; var min = Run.Depth * 2; cost = (byte) Rnd.Int(min, min + 5); AddComponent(new AnimationComponent("maanex")); GetComponent().Add(new SingleDrop("bk:maanex_head")); if (Run.Depth == 0) { AddComponent(new CloseDialogComponent("maanex_0", "maanex_1", "maanex_2", "maanex_3", "maanex_4")); } else { if (!interacted) { AddComponent(new InteractableComponent(Interact) { CanInteract = e => !interacted }); AddComponent(new SensorBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2)); } } Dialogs.RegisterCallback("maanex_6", (d, c) => { if (((ChoiceDialog) d).Choice == 0) { if (!c.To.TryGetComponent(out var component) || component.Coins < cost) { return Dialogs.Get("maanex_11"); } var room = GetComponent().Room; if (room == null) { return null; } component.Coins -= cost; interacted = true; foreach (var chest in room.Tagged[Tags.Chest]) { ((Chest) chest).CanOpen = true; } return Dialogs.Get("maanex_8"); } return null; }); Subscribe(); Subscribe(); } public override void PostInit() { base.PostInit(); var h = GetComponent(); h.Unhittable = false; h.InitMaxHealth = 50; h.SetHealth(50, this); } private string GetDialog(Entity e) { var hat = e.GetComponent().Item; if (hat != null && hat.Id == "bk:maanex_head") { return "maanex_12"; } if (Rnd.Chance(0.01f)) { return "spanish_inquisition"; } return $"maanex_{(played ? 7 : 5)}"; } public override bool HandleEvent(Event e) { if (e is Chest.OpenedEvent coe) { if (coe.Chest.GetComponent().Room == GetComponent().Room) { if (coe.Chest.Empty) { GetComponent().StartAndClose("maanex_9", 5f); } else { GetComponent().StartAndClose("maanex_10", 5f); } played = true; foreach (var chest in GetComponent().Room.Tagged[Tags.Chest]) { var c = (Chest) chest; if (c.Scale > 0.9f) { c.CanOpen = false; } } } } else if (e is RoomChangedEvent rce) { if (rce.Who is Player) { var r = GetComponent().Room; if (rce.New == r) { GetComponent().Start(GetDialog(rce.Who)); } else if (rce.Old == r) { GetComponent().Close(); } } } else if (e is DiedEvent de) { Items.Unlock("bk:maanex_head"); ExplosionMaker.Make(this); if (de.From is Player p && p.GetComponent().Item?.Id == "bk:maanex_head") { Achievements.Unlock("bk:maanex"); } } else if (e is HealthModifiedEvent hme && hme.Amount < 0) { GetComponent().StartAndClose(Bruh[Rnd.Int(Bruh.Length)], 2); } return base.HandleEvent(e); } public static string[] Bruh = { "bruh", "bruuh", "BRUH" }; public override void Update(float dt) { base.Update(dt); t += dt; if ((!interacted || played) && t >= 0.1f) { var r = GetComponent().Room; if (r == null) { return; } foreach (var chest in r.Tagged[Tags.Chest]) { ((Chest) chest).CanOpen = false; } } } public bool Interact(Entity e) { var d = GetComponent(); d.Dialog.Str.SetVariable("cost", cost); d.Start("maanex_6", e); return true; } public override void Load(FileReader stream) { base.Load(stream); interacted = stream.ReadBoolean(); cost = stream.ReadByte(); played = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(interacted); stream.WriteByte(cost); stream.WriteBoolean(played); } } } ================================================ FILE: BurningKnight/entity/creature/npc/Maanex2.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.entities; using BurningKnight.level.entities.chest; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.assets; using Lens.entity; using Lens.util.file; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class Maanex2 : Npc { private const int Cost = 8; internal ClawControll clawControll; public override void AddComponents() { base.AddComponents(); Width = 12; Height = 15; AddComponent(new AnimationComponent("maanex")); GetComponent().Add(new SingleDrop("bk:maanex_head")); AddComponent(new InteractableComponent(Interact) { CanInteract = e => !clawControll.Payed }); AddComponent(new SensorBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2)); Subscribe(); Dialogs.RegisterCallback("maanex2_0", (d, c) => { if (((ChoiceDialog) d).Choice == 0) { try { if (!c.To.TryGetComponent(out var component) || component.Coins < Cost) { return Dialogs.Get("maanex_11"); } component.Coins -= Cost; clawControll.Payed = true; Timer.Add(() => { GetComponent().StartAndClose(Locale.Get("m2_3"), 1); }, 0.2f); } catch (Exception e) { GetComponent().StartAndClose(e.Message, 10); } return null; } return null; }); } public override void PostInit() { base.PostInit(); var h = GetComponent(); h.Unhittable = false; h.InitMaxHealth = 50; h.SetHealth(50, this); } private bool Interact(Entity e) { var d = GetComponent(); d.Dialog.Str.SetVariable("cost", Cost); d.Start("maanex2_0", e); return true; } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce) { if (rce.Who is Player) { var r = GetComponent().Room; if (rce.New == r) { // Wanna try out your skill? GetComponent().Start("m2_2"); } else if (rce.Old == r) { GetComponent().Close(); } } } else if (e is DiedEvent de) { Items.Unlock("bk:maanex_head"); ExplosionMaker.Make(this); if (de.From is Player p && p.GetComponent().Item?.Id == "bk:maanex_head") { Achievements.Unlock("bk:maanex"); } } else if (e is HealthModifiedEvent hme && hme.Amount < 0) { GetComponent().StartAndClose(Maanex.Bruh[Rnd.Int(Maanex.Bruh.Length)], 2); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/npc/Mike.cs ================================================ using BurningKnight.entity.component; using BurningKnight.save; namespace BurningKnight.entity.creature.npc { public class Mike : ShopNpc { public override void AddComponents() { base.AddComponents(); Width = 11; Height = 13; AddComponent(new AnimationComponent("mike")); // GetComponent().Dialog.Voice = 15; } protected override string GetDialog() { return "mike_1"; } public override string GetId() { return Mike; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Milt.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class Milt : Npc { public override void AddComponents() { base.AddComponents(); Width = 10; Height = 8; AddComponent(new AnimationComponent("milt")); AddComponent(new CloseDialogComponent("milt_1")); GetComponent().Dialog.Voice = 21; } } } ================================================ FILE: BurningKnight/entity/creature/npc/Npc.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.tween; namespace BurningKnight.entity.creature.npc { public class Npc : Creature { public const int Padding = 4; public override void AddComponents() { base.AddComponents(); AddComponent(new DialogComponent()); GetComponent().Unhittable = true; AddTag(Tags.Npc); } private bool rotationApplied; public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent hme && hme.Amount < 0) { if (!rotationApplied) { rotationApplied = true; var a = GetAnyComponent(); if (a != null) { var w = a.Angle; a.Angle += 0.5f; var t = Tween.To(w, a.Angle, x => a.Angle = x, 0.2f); t.Delay = 0.2f; t.OnEnd = () => { rotationApplied = false; }; } } } return base.HandleEvent(e); } public override void AnimateDeath(DiedEvent d) { base.AnimateDeath(d); CreateGore(d); } } } ================================================ FILE: BurningKnight/entity/creature/npc/NullPtr.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class NullPtr : Npc { public override void AddComponents() { base.AddComponents(); Width = 10; Height = 8; AddComponent(new AnimationComponent("nullptr")); AddComponent(new CloseDialogComponent("nullptr_0")); GetComponent().Dialog.Voice = 18; } } } ================================================ FILE: BurningKnight/entity/creature/npc/OldMan.cs ================================================ using System.Linq; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.biome; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.entity; using Lens.input; using Lens.util.file; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class OldMan : Npc { public bool RickRoll; public override void AddComponents() { base.AddComponents(); Width = 20; Height = 18; AddComponent(new AnimationComponent("old_man")); AddComponent(new RectBodyComponent(-Padding, -Padding, Width + Padding * 2, Height + Padding * 2)); if (Run.Depth == 0) { AddComponent(new CloseDialogComponent("old_man_0")); // AddComponent(new InteractDialogComponent("old_man_1")); } else if (Run.Depth == Run.ContentEndDepth) { GetComponent().Start("old_man_4"); // cycle = !BK.Version.Dev;; } else if (Run.Depth == -2) { set = false; AddComponent(new CloseDialogComponent("control_1") { Radius = 64 * 64, RadiusMax = 72 * 72 }); } else { Subscribe(); Subscribe(); inSecret = true; } AlwaysActive = true; GetComponent().Dialog.Voice = 28; } private string[] song = { "Never gonna give you up", "Never gonna let you down", "Never gonna run around and desert you", "Never gonna make you cry", "Never gonna say goodbye", "Never gonna tell a lie and hurt you" }; private int index; private void StartSong() { if (index >= song.Length) { GetComponent().Close(); return; } GetComponent().Start(song[index], null, () => { Timer.Add(() => { StartSong(); }, 2); if (RickRoll) { foreach (var item in GetComponent().Room.Tagged[Tags.Item]) { item.Done = true; AnimationUtil.Poof(item.Center); } } }); index++; } public override bool HandleEvent(Event e) { if (inSecret) { if (e is RoomChangedEvent rce && rce.Who is Player) { if (rce.New == GetComponent().Room) { if (RickRoll) { StartSong(); index = 0; } else { GetComponent().Start("old_man_6"); } } else { GetComponent().Close(); } } else if (e is ItemTakenEvent ite && ite.Stand.GetComponent().Room == GetComponent().Room) { GetComponent().Animate(() => { Done = true; }); } } return base.HandleEvent(e); } private bool inSecret; private bool set = true; private bool cycle; private float t; public override void Update(float dt) { base.Update(dt); if (cycle) { t += dt; if (t >= 1f) { t = 0; var all = BiomeRegistry.Defined.Values.ToArray(); Run.Level.SetBiome(all[Rnd.Int(all.Length)]); } return; } if (!set) { set = true; var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Roll, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Roll, true))); } } } public override void Load(FileReader stream) { base.Load(stream); RickRoll = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(RickRoll); } } } ================================================ FILE: BurningKnight/entity/creature/npc/Ord.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.creature.npc { public class Ord : Npc { public override void AddComponents() { base.AddComponents(); Width = 16; Height = 20; var anim = new AnimationComponent("ord"); AddComponent(anim); anim.Animation.AutoStop = true; anim.Animation.OnEnd += OnAnimationEnd; AddComponent(new RectBodyComponent(-4, -4, Width + 8, Height + 8)); AddComponent(new InteractableComponent(e => { GetComponent().Animation.Tag = "turnon"; return true; })); } private void OnAnimationEnd() { var anim = GetComponent().Animation; if (anim.Tag == "turnon") { anim.Tag = "choice"; } } } } ================================================ FILE: BurningKnight/entity/creature/npc/ShopKeeper.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.level.entities.machine; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens; using Lens.entity; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Vector2 = Microsoft.Xna.Framework.Vector2; namespace BurningKnight.entity.creature.npc { public class ShopKeeper : Npc { private sbyte _mood = 3; private Item shotgun; public sbyte Mood { get => _mood; set { if (_mood == value || (TryGetComponent(out var room) && room.Room != null && room.Room.Tagged[Tags.Player].Count == 0)) { return; } var r = raging; if (_mood < 0 && value > 0) { return; } var old = _mood; _mood = value; if (_mood < old && _mood < 3 && _mood > -1) { GetComponent().StartAndClose($"shopkeeper_{_mood}", 1); } if (raging) { GameSave.Put("sk_enraged", true); } if (!r && raging) { AddTag(Tags.Mob); AddTag(Tags.MustBeKilled); try { var rm = GetComponent().Room; // Hacky solution tbh rm.Tagged[Tags.Mob].Add(this); rm.Tagged[Tags.MustBeKilled].Add(this); } catch (Exception e) { Log.Error(e); } Become(); GetComponent().StartAndClose($"shopkeeper_{Rnd.Int(3, 5)}", 1); SetItemsFree(); HandleEvent(new EnragedEvent { ShopKeeper = this }); } Recalc(); } } private bool raging => Mood < 0; private void Recalc() { var r = GetComponent().Room; if (r == null) { return; } foreach (var s in r.Tagged[Tags.Item]) { if (s is ShopStand ss) { ss.Recalculate(); } } } public override void AddComponents() { base.AddComponents(); AlwaysActive = true; AddComponent(new QuackInteractionComponent(p => { Timer.Add(() => { var d = GetComponent(); if (d.Current != null && d.Current.Id != "quack") { d.StartAndClose("quack", 3); } GetComponent().EmitRandomized("quck"); }, 0.5f); })); AddComponent(new AimComponent(AimComponent.AimType.AnyPlayer)); AddComponent(new AnimationComponent("shopkeeper")); AddDrops(new SingleDrop("bk:shotgun", 1f)); var h = GetComponent(); h.InitMaxHealth = 10 + Run.Depth * 10; h.Unhittable = false; var b = new RectBodyComponent(4, 2, 10, 14); AddComponent(b); b.Body.LinearDamping = 5; Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); Subscribe(); AddTag(Tags.ShopKeeper); Become(); GetComponent().Dialog.Voice = 3; } public override void Load(FileReader stream) { base.Load(stream); Mood = stream.ReadSbyte(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteSbyte(Mood); } public void Enrage() { if (raging) { return; } Mood = -1; } public override bool HandleEvent(Event e) { if (e is BombPlacedEvent bpe) { if (bpe.Bomb.GetComponent().Room == GetComponent().Room) { Enrage(); } } else if (e is GramophoneBrokenEvent gbe) { if (gbe.Gramophone.GetComponent().Room == GetComponent().Room) { Mood--; } } else if (e is RerollMachine.BrokenEvent rme) { if (rme.Machine.GetComponent().Room == GetComponent().Room) { Mood--; } } else if (e is VendingMachine.BrokenEvent vme) { if (vme.Machine.GetComponent().Room == GetComponent().Room) { Mood--; } } else if (e is HealthModifiedEvent hme && hme.Amount < 0) { if (hme.Amount < 0 && Mood > -2) { Mood = (sbyte) Math.Min(2, Mood - 1); hme.Amount = -1; } } else if (e is RoomChangedEvent rce) { if (rce.Who is Player && rce.New == GetComponent().Room) { if (GameSave.IsTrue("sk_enraged")) { Enrage(); } Recalc(); if (Mood > -1) { GetComponent().EmitRandomized("hi"); GetComponent().StartAndClose($"shopkeeper_{Rnd.Int(6, 9)}", 3); } } } else if (e is ItemBoughtEvent ibe) { if (ibe.Stand.GetComponent().Room == GetComponent().Room) { Mood++; GetComponent().StartAndClose($"shopkeeper_{Rnd.Int(9, 12)}", 3); } } else if (e is DiedEvent) { Achievements.Unlock("bk:marauder"); for (var i = 0; i < 3; i++) { Run.AddScourge(true); } } return base.HandleEvent(e); } private void SetItemsFree() { var r = GetComponent().Room; if (r != null) { foreach (var s in r.Tagged[Tags.Item]) { if (s is ShopStand ss) { ss.Free = true; } } } } protected override bool HandleDeath(DiedEvent d) { Items.Unlock("bk:shotgun"); SetItemsFree(); return base.HandleDeath(d); } protected override string GetDeadSfx() { return "villager6"; } protected override string GetHurtSfx() { return "villager5"; } public override bool IsFriendly() { return !raging || GetComponent().Has(); } private float delay; public override void Update(float dt) { base.Update(dt); if (!raging) { delay -= dt; if (delay <= 0) { delay = Rnd.Float(3, 9f); GetComponent().EmitRandomized($"villager{Rnd.Int(1, 5)}", 0.5f); } } shotgun?.Update(dt); } #region Shopkeeper States /* * Peacefull */ private class IdleState : SmartState { private float actionDelay; public override void Init() { base.Init(); actionDelay = Rnd.Float(2, 6); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Dialog.Saying) { T = 0; return; } if (T >= actionDelay) { Self.Become(); } } } private class MoveToState : SmartState { private Vector2 target; private bool toPlayer; public override void Init() { base.Init(); Self.GetComponent().Animation.Tag = "run"; var r = Self.GetComponent().Room; toPlayer = r.Tagged[Tags.Player].Count > 0 && Rnd.Chance(40); if (toPlayer) { if (Self.DistanceTo(r.Tagged[Tags.Player][0]) < 64f) { toPlayer = false; } else { return; } } var p = r.GetRandomFreeTile(); target = new Vector2(p.X * 16, p.Y * 16); } public override void Update(float dt) { base.Update(dt); var t = target; if (toPlayer) { var a = Self.GetComponent().Room.Tagged[Tags.Player]; if (a.Count > 0) { target = a[0].Center; } } var dx = Self.DxTo(t); var dy = Self.DyTo(t); var d = MathUtils.Distance(dx, dy); var s = dt * 300; var b = Self.GetComponent(); b.Velocity += new Vector2(dx / d * s, dy / d * s); if (d <= 24 || T >= 4f) { if ((toPlayer && Rnd.Chance(80)) || Rnd.Chance(30)) { if (Self.GetComponent().Room.Tagged[Tags.Player].Count > 0) { Self.GetComponent().StartAndClose($"shopkeeper_{(Rnd.Chance(30) ? 18 : Rnd.Int(12, 15))}", 3); } } Self.Become(); } } } public override void Render() { base.Render(); shotgun?.Renderer.Render(false, Engine.Instance.State.Paused, Engine.Delta, false, 0); } protected override void RenderShadow() { base.RenderShadow(); shotgun?.Renderer.Render(false, Engine.Instance.State.Paused, Engine.Delta, true, 0); } /* * Raging */ private class RunState : SmartState { private Vector2 target; private float delay; private bool set; public override void Init() { base.Init(); delay = Rnd.Float(0.2f, 0.8f); Self.GetComponent().Animation.Tag = "run"; var r = Self.GetComponent().Room; if (r != null) { set = true; var p = r.GetRandomFreeTile(); target = new Vector2(p.X * 16, p.Y * 16); if (Self.shotgun == null) { Self.shotgun = Items.CreateAndAdd("bk:shotgun", Self.Area); Self.shotgun.RemoveDroppedComponents(); Self.shotgun.AddComponent(new OwnerComponent(Self)); } } } public override void Update(float dt) { base.Update(dt); if (!set) { Init(); } if (Self.shotgun != null && Self.GetComponent().Room.Tagged[Tags.Player].Count > 0) { Self.shotgun.Use(Self); } var dx = Self.DxTo(target); var dy = Self.DyTo(target); var d = MathUtils.Distance(dx, dy); var s = Math.Min(T * 3, 1f) * dt * 36000; var b = Self.GetComponent(); b.Velocity = new Vector2(dx / d * s, dy / d * s); if (d <= 8 || T >= delay) { T = 0; Init(); } } } #endregion public override bool ShouldCollide(Entity entity) { return !(entity is ItemStand) && base.ShouldCollide(entity); } public class EnragedEvent : Event { public ShopKeeper ShopKeeper; } } } ================================================ FILE: BurningKnight/entity/creature/npc/ShopNpc.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.npc.dungeon; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.npc { public class ShopNpc : Npc { public const string AccessoryTrader = "accessory_trader"; public const string ActiveTrader = "active_trader"; public const string WeaponTrader = "weapon_trader"; public const string HatTrader = "hat_trader"; public const string Mike = "mike"; public const string Snek = "snek"; public const string Boxy = "boxy"; public const string Roger = "roger"; public const string Gobetta = "gobetta"; public const string Vampire = "vampire"; public const string TrashGoblin = "trash_goblin"; public const string Duck = "duck"; public const string Nurse = "nurse"; public const string Elon = "elon"; public static string[] AllNpc = { AccessoryTrader, ActiveTrader, WeaponTrader, HatTrader, Mike, Snek, Boxy, Roger, Gobetta, Vampire, TrashGoblin, Duck, Nurse, Elon }; private float delay; internal bool Hidden; private bool saved; private bool hided; protected bool Remove; protected bool Flips = true; public override void Init() { base.Init(); Subscribe(); Subscribe(); var id = GetId(); saved = id == TrashGoblin || GlobalSave.IsTrue(id); AlwaysActive = true; Hidden = Run.Depth == 0 && !saved; } public override void PostInit() { base.PostInit(); if (Run.Depth == 0) { var h = GetComponent(); h.Unhittable = false; h.InitMaxHealth = 50; h.SetHealth(50, this); } } public override void AddComponents() { base.AddComponents(); if (Run.Depth == 0) { AddComponent(new CloseDialogComponent(GetDialog()) { DecideVariant = e => GetDialog(), Radius = 72 * 72, RadiusMax = 96 * 96 }); AddComponent(new QuackInteractionComponent(p => { Timer.Add(() => { var d = GetComponent(); if (d.Current != null && d.Current.Id != "quack") { d.StartAndClose("quack", 3); } GetComponent().EmitRandomized("quck"); }, 0.5f); })); } } public override void Update(float dt) { if (Hidden) { if (!hided) { hided = true; foreach (var item in Area.Tagged[Tags.Item]) { if (item is ItemStand stand && OwnsStand(stand)) { stand.Done = true; } } } return; } if (saved && Remove && !OnScreen) { Done = true; Hidden = true; var stand = new ItemStand(); Area.Add(stand); stand.Center = Center; stand.SetItem(Items.CreateAndAdd("bk:emerald", Area), null); return; } base.Update(dt); if (!Flips) { return; } delay -= dt; if (delay <= 0) { delay = Rnd.Float(1, 10); GraphicsComponent.Flipped = !GraphicsComponent.Flipped; } } public override void Render() { if (Hidden) { return; } base.Render(); } protected override void RenderShadow() { if (Hidden) { return; } base.RenderShadow(); } protected virtual bool OwnsStand(ItemStand stand) { return false; } protected virtual string GetHiDialog() { return null; } public override bool HandleEvent(Event e) { if (Hidden || Done) { return false; } if (e is RoomChangedEvent rce) { if (rce.Who is Player && rce.New == GetComponent().Room) { if (Run.Depth > 0 && !saved) { GetComponent().EmitRandomized("hi"); if ((rce.Who.TryGetComponent(out var a) && a.Item != null && a.Item.Id == "bk:cage_key") || (rce.Who.TryGetComponent(out var w) && w.Item != null && w.Item.Id == "bk:cage_key")) { GetComponent().StartAndClose("npc_2", 3); } else { GetComponent().StartAndClose("npc_0", 3); } } else { var s = GetHiDialog(); if (s != null) { GetComponent().StartAndClose(s, 3); } } } } else if (e is ItemBoughtEvent ibe) { if (OwnsStand(ibe.Stand) && ibe.Stand.GetComponent().Room == GetComponent().Room) { GetComponent().StartAndClose(GetDealDialog(), 3); OnItemBought(ibe); } } else if (e is DiedEvent) { GlobalSave.Put(GetId(), false); ExplosionMaker.Make(this); } else if (e is HealthModifiedEvent hme && hme.Amount < 0) { GetComponent().StartAndClose($"npc_hurt_{Rnd.Int(3)}", 2); } return base.HandleEvent(e); } protected virtual void OnItemBought(ItemBoughtEvent ibe) { } protected virtual string GetDealDialog() { return $"shopkeeper_{Rnd.Int(9, 12)}"; } public void Save() { if (Run.Depth > 0 && !saved) { saved = true; Remove = true; GetComponent().StartAndClose("npc_1", 6); GlobalSave.Put(GetId(), true); GlobalSave.Put("saved_npc", true); RemoveComponent(); HandleEvent(new SavedEvent { Npc = this }); Achievements.Unlock("bk:rescue_operation"); } } protected virtual string GetDialog() { return $"shopkeeper_{Rnd.Int(6, 9)}"; } public virtual string GetFailDialog() { return $"shopkeeper_{Rnd.Int(15, 18)}"; } public virtual string GetId() { return null; } public class SavedEvent : Event { public ShopNpc Npc; } public static ShopNpc FromId(string id) { switch (id) { case HatTrader: return new HatTrader(); case WeaponTrader: return new WeaponTrader(); case ActiveTrader: return new ActiveTrader(); case AccessoryTrader: return new AccessoryTrader(); case Mike: return new Mike(); case Snek: return new Snek(); case Boxy: return new Boxy(); case Vampire: return new Vampire(); case Roger: return new Roger(); case TrashGoblin: return new TrashGoblin(); case Duck: return new DungeonDuck(); case Nurse: return new Nurse(); case Elon: return new DungeonElon(); case Gobetta: return new Gobetta(); } Log.Error($"Unknown npc id {id}!"); return new Boxy(); } } } ================================================ FILE: BurningKnight/entity/creature/npc/WeaponTrader.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using Lens.util.math; namespace BurningKnight.entity.creature.npc { public class WeaponTrader : ShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 19; Height = 20; AddComponent(new AnimationComponent("weapon_trader")); var b = new RectBodyComponent(2, 6, Width - 4, Height - 6); AddComponent(b); b.KnockbackModifier = 0; GetComponent().Dialog.Voice = 7; } protected override string GetDialog() { return $"weapontrader_{Rnd.Int(3)}"; } public override string GetId() { return WeaponTrader; } protected override bool OwnsStand(ItemStand stand) { return stand is WeaponStand; } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Boxy.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.drop; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.entity; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class Boxy : DungeonShopNpc { private bool open; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 15; Height = 18; Flips = false; AddComponent(new AnimationComponent("boxy")); GetComponent().Animation.Tag = "idle"; GetComponent().Add("bk:boxy"); AddComponent(new RectBodyComponent(0, 9, 15, 9, BodyType.Static)); } public override void PostInit() { base.PostInit(); if (open) { GetComponent().Animation.Tag = "open"; } } protected override void OnItemBought(ItemBoughtEvent ibe) { if (open) { return; } foreach (var s in GetComponent().Room.Tagged[Tags.Item]) { if (s is BoxyStand st && st != ibe.Stand && st.Item != null) { return; } } var d = GetComponent(); d.StartAndClose("boxy_9", 3); Timer.Add(() => { AnimationUtil.Poof(Center); GetComponent().SpawnDrops(); open = true; var a = GetComponent(); a.Animation.Tag = "open"; a.Animate(); Achievements.Unlock("bk:open_up"); }, 4f); } public override string GetId() { return ShopNpc.Boxy; } protected override bool OwnsStand(ItemStand stand) { return stand is BoxyStand; } public static void Place(Vector2 where, Area area) { where.Y -= 16; var snek = new Boxy(); area.Add(snek); snek.BottomCenter = where; var pool = Items.GeneratePool(Items.GetPool(ItemPool.Boxy)); for (var i = -1; i < 2; i++) { var stand = new BoxyStand(); area.Add(stand); stand.Center = where + new Vector2((stand.Width + 4) * i, 4 + stand.Height); var id = Items.GenerateAndRemove(pool, null, true); stand.SetItem(Items.CreateAndAdd(id, area, false), null); } } protected override string GetDealDialog() { return $"boxy_{Rnd.Int(3)}"; } protected override string GetHiDialog() { return $"boxy_{Rnd.Int(3, 6)}"; } public override string GetFailDialog() { return $"boxy_{Rnd.Int(7, 9)}"; } public override void Load(FileReader stream) { base.Load(stream); open = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(open); } public override bool ShouldCollide(Entity entity) { return entity is Creature || base.ShouldCollide(entity); } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/DungeonDuck.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.level.entities.chest; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class DungeonDuck : DungeonShopNpc { private bool interacted; private Chest chest; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 12; Height = 10; AddComponent(new AnimationComponent("duck")); AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static)); GetComponent().Dialog.Voice = 4; if (!interacted) { AddComponent(new InteractableComponent((e) => { GetComponent().Start("duck_2", e); return true; })); Dialogs.RegisterCallback("duck_4", (d, c) => { interacted = true; if (chest != null) { chest.CanOpen = true; } RemoveComponent(); return null; }); Dialogs.RegisterCallback("duck_5", (d, c) => { interacted = true; RemoveComponent(); return null; }); } } public override void Load(FileReader stream) { base.Load(stream); interacted = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(interacted); } public override string GetId() { return ShopNpc.Duck; } public static void Place(Vector2 where, Area area) { where.X -= 8; var duck = new DungeonDuck(); area.Add(duck); duck.BottomCenter = where; where.X += 16; var chest = new DuckChest(); area.Add(chest); chest.BottomCenter = where; } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (chest == null && t >= 0.1f) { foreach (var c in GetComponent().Room.Tagged[Tags.Chest]) { if (c is DuckChest cs) { chest = cs; chest.CanOpen = false; break; } } } } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/DungeonElon.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.item; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class DungeonElon : DungeonShopNpc { private bool interacted; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 17; Height = 19; AddComponent(new AnimationComponent("elon")); AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static)); AddComponent(new InteractableComponent(Interact) { CanInteract = e => !interacted }); Dialogs.RegisterCallback("elon_4", (d, cm) => { var c = cm.To.GetComponent(); if (c.Item == null) { return Dialogs.Get("elon_7"); } interacted = true; var id = Items.Generate(ItemType.Weapon, dt => dt.Id != c.Item.Id); var i = c.Item; c.Drop(); i.Done = true; c.Set(Items.CreateAndAdd(id, Area)); Run.AddScourge(true); return null; }); } private bool Interact(Entity e) { if (interacted) { return true; } GetComponent().Start("elon_3", e); return true; } public override string GetId() { return ShopNpc.Elon; } public static void Place(Vector2 where, Area area) { var elon = new DungeonElon(); area.Add(elon); elon.BottomCenter = where; } public override void Load(FileReader stream) { base.Load(stream); interacted = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(interacted); } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/DungeonShopNpc.cs ================================================ namespace BurningKnight.entity.creature.npc.dungeon { public class DungeonShopNpc : ShopNpc { public override void AddComponents() { base.AddComponents(); Remove = false; } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Gobetta.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.npc.dungeon { public class Gobetta : DungeonShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 15; Height = 13; AddComponent(new AnimationComponent("gobetta")); } public override string GetId() { return ShopNpc.Gobetta; } protected override bool OwnsStand(ItemStand stand) { return stand is GobettaStand; } public static void Place(Vector2 where, Area area) { where.Y -= 16; var gobetta = new Gobetta(); area.Add(gobetta); gobetta.BottomCenter = where; var pool = Items.GeneratePool(Items.GetPool(ItemPool.Gobetta)); var c = 3; var s = (int) Math.Floor(c / 2f) * 18; for (var i = 0; i < c; i++) { var stand = new GobettaStand(); area.Add(stand); stand.Center = where + new Vector2((stand.Width + 4) * i - s, 4 + stand.Height + (i == 1 ? stand.Height * 0.5f : 0)); var id = Items.GenerateAndRemove(pool, null, true); stand.SetItem(Items.CreateAndAdd(id, area, false), null); } } protected override string GetDealDialog() { return $"gobetta_{Rnd.Int(3)}"; } protected override string GetHiDialog() { return $"gobetta_{Rnd.Int(3, 6)}"; } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Nurse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.ui.dialog; using Lens.assets; using Lens.entity; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class Nurse : DungeonShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 40; Height = 43; Flips = false; AddComponent(new AnimationComponent("nurse")); AddComponent(new RectBodyComponent(0, 26, 40, 17, BodyType.Static)); AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2, BodyType.Static)); AddComponent(new InteractableComponent(Interact)); // GetComponent().Dialog.Voice = 4; } private bool Interact(Entity e) { var c = e.GetComponent(); var d = GetComponent(); if (c.IsFull()) { // Ya look pretty good d.StartAndClose("nurse_0", 3); return false; } var price = (int) (c.MaxHealth - c.Health) * 4; var consumables = e.GetComponent(); if (consumables.Coins < price) { d.Dialog.Str.SetVariable("price", price); d.StartAndClose("nurse_1", 5); return false; } c.ModifyHealth(c.MaxHealth, this); TextParticle.Add(e, Locale.Get("coins"), price, true, true); d.StartAndClose("nurse_2", 5); return false; } public override string GetId() { return ShopNpc.Nurse; } public static void Place(Vector2 where, Area area) { var nurse = new Nurse(); area.Add(nurse); nurse.BottomCenter = where + new Vector2(0, 8); } public override bool ShouldCollide(Entity entity) { return entity is Creature || base.ShouldCollide(entity); } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Roger.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.npc.dungeon { public class Roger : DungeonShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 18; Height = 24; Flips = false; AddComponent(new AnimationComponent("roger")); } public override string GetId() { return ShopNpc.Roger; } protected override string GetDealDialog() { return $"roger_{Rnd.Int(3)}"; } protected override bool OwnsStand(ItemStand stand) { return stand is RogerStand; } public static void Place(Vector2 where, Area area) { where.Y -= 16; var roger = new Roger(); area.Add(roger); roger.BottomCenter = where; var pool = Items.GeneratePool(Items.GetPool(ItemPool.Roger)); for (var i = -1; i < 2; i++) { var stand = new RogerStand(); area.Add(stand); stand.Center = where + new Vector2((stand.Width + 8) * i, 4 + stand.Height - (i == 0 ? stand.Height * 0.5f : 0)); var id = Items.GenerateAndRemove(pool, null, true); stand.SetItem(Items.CreateAndAdd(id, area, false), null); } } public override string GetFailDialog() { return $"roger_{Rnd.Int(3, 6)}"; } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Snek.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.entity; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class Snek : DungeonShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 18; Height = 24; Flips = false; AddComponent(new AnimationComponent("snek")); AddComponent(new RectBodyComponent(1, 14, 16, 10, BodyType.Static)); } protected override void OnItemBought(ItemBoughtEvent ibe) { foreach (var s in GetComponent().Room.Tagged[Tags.Item]) { if (s is SnekStand st && st != ibe.Stand && st.Item != null) { return; } } var d = GetComponent(); d.StartAndClose("snek_6", 3); Timer.Add(() => { d.StartAndClose("snek_7", 3); Timer.Add(() => { AnimationUtil.Poof(Center); Done = true; var stand = new SnekStand(); Area.Add(stand); stand.Center = Center; stand.SetItem(Items.CreateAndAdd("bk:snek", Area), this); }, 4f); }, 4f); } public override string GetId() { return ShopNpc.Snek; } public static void Place(Vector2 where, Area area) { var snek = new Snek(); area.Add(snek); snek.BottomCenter = where; var pool = Items.GeneratePool(Items.GetPool(ItemPool.Snek)); for (var i = -1; i < 2; i++) { var stand = new SnekStand(); area.Add(stand); stand.Center = where + new Vector2((stand.Width + 4) * i, 4 + stand.Height); var id = Items.GenerateAndRemove(pool, null, true); stand.SetItem(Items.CreateAndAdd(id, area, false), null); } } public override bool ShouldCollide(Entity entity) { return entity is Creature || base.ShouldCollide(entity); } protected override bool OwnsStand(ItemStand stand) { return stand is SnekStand; } protected override string GetDealDialog() { return $"snek_{Rnd.Int(3)}"; } protected override string GetHiDialog() { return $"snek_{Rnd.Int(3, 6)}"; } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/TrashGoblin.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.level.entities; using BurningKnight.level.entities.chest; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util; using Lens.util.file; using Lens.util.timer; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class TrashGoblin : DungeonShopNpc { private bool freed; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Height = 26; Flips = false; AddComponent(new AnimationComponent("trash_goblin")); AddComponent(new RectBodyComponent(0, 16, 14, 10, BodyType.Static)); var dl = GetComponent(); dl.InitCallback = () => { dl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice("note_0")); dl.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice("note_1")); }; } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(freed); } public override void Load(FileReader stream) { base.Load(stream); freed = stream.ReadBoolean(); } public override void PostInit() { base.PostInit(); if (freed) { GetComponent().Animation.Tag = "free"; } } public override string GetId() { return ShopNpc.TrashGoblin; } public void Free() { if (freed) { return; } freed = true; GetComponent().Animation.Tag = "free"; GetComponent().StartAndClose("trash_goblin_1", 5); Timer.Add(() => { try { ChestRegistry.PlaceRandom(BottomCenter + new Vector2(0, 12), Area); } catch (Exception ex) { Log.Error(ex); } }, 3f); } protected override string GetHiDialog() { return freed ? "trash_goblin_2" : "trash_goblin_0"; } protected override bool OwnsStand(ItemStand stand) { return stand is TrashGoblinStand; } public static void Place(Vector2 where, Area area) { where.Y -= 16; var goblin = new TrashGoblin(); area.Add(goblin); goblin.BottomCenter = where; goblin.X += 1; var stand = new TrashGoblinStand(); area.Add(stand); stand.Center = where + new Vector2(0, 4 + stand.Height); stand.SetItem(Items.CreateAndAdd(Scourge.GenerateItemId(), area, false), null); } public override bool ShouldCollide(Entity entity) { return entity is Creature || base.ShouldCollide(entity); } } } ================================================ FILE: BurningKnight/entity/creature/npc/dungeon/Vampire.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.npc.dungeon { public class Vampire : DungeonShopNpc { public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 22; Height = 30; Flips = false; AddComponent(new AnimationComponent("vampire")); AddComponent(new RectBodyComponent(4, 19, 14, 11, BodyType.Static, false)); AddComponent(new SensorBodyComponent(-Npc.Padding, -Npc.Padding, Width + Npc.Padding * 2, Height + Npc.Padding * 2)); AddComponent(new InteractableComponent(Interact)); } protected override string GetDealDialog() { return $"vampire_{Rnd.Int(3)}"; } protected override string GetHiDialog() { return "vampire_3"; } private bool Interact(Entity entity) { if (entity.GetComponent().ModifyHealth(-1, this)) { for (var i = 0; i < 3; i++) { var coin = Items.CreateAndAdd("bk:copper_coin", Area); coin.TopCenter = BottomCenter; } GetComponent().Start($"vampire_{Rnd.Int(4, 7)}"); } return false; } public override string GetId() { return ShopNpc.Vampire; } public static void Place(Vector2 where, Area area) { var sells = Rnd.Chance(60); if (sells) { where.Y -= 24; } var vampire = new Vampire(); area.Add(vampire); vampire.BottomCenter = where; if (!sells) { return; } var pool = Items.GeneratePool(Items.GetPool(ItemPool.Vampire)); var c = Rnd.Int(1, 4); var s = (int) Math.Floor(c / 2f) * 18; for (var i = 0; i < c; i++) { var stand = new VampireStand(); area.Add(stand); stand.Center = where + new Vector2((stand.Width + 4) * i - s, 4 + stand.Height); var id = Items.GenerateAndRemove(pool, null, true); stand.SetItem(Items.CreateAndAdd(id, area, false), null); } } public override bool ShouldCollide(Entity entity) { return entity is Creature || base.ShouldCollide(entity); } public override string GetFailDialog() { return $"vampire_{Rnd.Int(7, 10)}"; } } } ================================================ FILE: BurningKnight/entity/creature/pet/AnimatedFollowerPet.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class AnimatedFollowerPet : Pet { private string sprite; public AnimatedFollowerPet(string spr) { sprite = spr; } public override void AddComponents() { base.AddComponents(); AddComponent(new AnimationComponent(sprite) { ShadowOffset = -2 }); var region = GetComponent().Animation.GetCurrentTexture(); Width = region.Width; Height = region.Height; AddComponent(new ShadowComponent()); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); GetComponent().Animate(); } } } ================================================ FILE: BurningKnight/entity/creature/pet/Backpack.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.entity.item; using BurningKnight.save; using BurningKnight.ui.dialog; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class Backpack : Pet { private InteractFx fx; private bool open; private TextureRegion itemRegion; public override void AddComponents() { base.AddComponents(); Width = 12; AddComponent(new FollowerComponent { MaxDistance = 96, FollowSpeed = 2 }); AddComponent(new AnimationComponent("backpack") { ShadowOffset = -2 }); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); AddComponent(new ItemComponent()); AddComponent(new InteractableComponent(Interact) { CanInteract = e => e == Owner && (e.GetComponent().Item != null || GetComponent().Item != null), OnStart = e => AddFx() }); try { var id = GameSave.GetString("backpack"); if (id != null) { var item = Items.CreateAndAdd(id, Area); GetComponent().Set(item, false); item.GetComponent().Owner = Owner; itemRegion = item.Region; } } catch (Exception e) { Log.Error(e); } GetComponent().Animate(); } public override void Destroy() { base.Destroy(); GameSave.Put("backpack", GetComponent().Item?.Id); } private void AddFx() { if (fx != null && !fx.Done) { fx.Close(); } var i = GetComponent().Item; Engine.Instance.State.Ui.Add(fx = new InteractFx(this, i == null ? Locale.Get("place_an_item") : i.Name)); } private bool Interact(Entity entity) { var w = entity.GetComponent(); if (w.Item != null && w.Item.Scourged) { entity.GetComponent().StartAndClose($"~~{Locale.Get("scourged")}~~", 2); return true; } var i = GetComponent(); var w2 = entity.GetComponent(); if (i.Item != null && w2.Item == null) { i.Exchange(w2); w.RequestSwap(); } else { i.Exchange(w); } if (w.Item != null) { Audio.PlaySfx(w.Item.Data.WeaponType.GetSwapSfx()); entity.GetComponent().AnimateSwap(); } else if (entity.GetComponent().Item != null) { w.RequestSwap(); } if (i.Item != null) { itemRegion = i.Item.Region; } else { itemRegion = null; } AddFx(); return false; } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (!open && cse.Entity == Owner) { GetComponent().Animate(() => { GetComponent().Animation.Tag = "open"; }); GetComponent().Paused = true; GetComponent().Velocity *= 0.5f; Audio.PlaySfx("unlock"); open = true; } } else if (e is CollisionEndedEvent cee) { if (open && cee.Entity == Owner) { GetComponent().Animate(() => { open = false; GetComponent().Animation.Tag = "idle"; }); GetComponent().Paused = false; Audio.PlaySfx("swap"); } } return base.HandleEvent(e); } public override void Render() { base.Render(); if (open && itemRegion != null) { Graphics.Render(itemRegion, Position + new Vector2(6, 7), 0, itemRegion.Center, GetComponent().Scale); } } } } ================================================ FILE: BurningKnight/entity/creature/pet/BooGraphicsComponent.cs ================================================ using System; using BurningKnight.entity.component; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.graphics; using Lens.entity.component.logic; using Lens.graphics; using Lens.graphics.animation; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.pet { public class BooGraphicsComponent : GraphicsComponent { private Animation animation; private bool flipped; private double angle; private Vector2 scale = Vector2.One; public BooGraphicsComponent(string anim) { animation = Animations.Get(anim).CreateAnimation(); } public override void Update(float dt) { base.Update(dt); animation.Update(dt); } public override void Render(bool shadow) { var slice = animation.GetCurrentTexture(); var origin = slice.Center; var body = Entity.GetAnyComponent(); var vx = Math.Abs(body.Velocity.X); if (vx > 0.1f) { flipped = vx < 0; } angle = MathUtils.LerpAngle(angle, Math.Min(2, vx), Engine.Delta * 8); Graphics.Render(slice, Entity.Position + origin, (float) angle, origin, flipped ? new Vector2(-scale.X, scale.Y) : scale); } public override bool HandleEvent(Event e) { if (e is StateChangedEvent ev && animation != null) { var tag = ev.NewState.Name.ToLower().Replace("state", ""); if (animation.HasTag(tag)) { animation.Tag = tag; } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/Bubblo.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.creature.pet { public class Bubblo : DiagonalPet { private static int[] widths = { 13, 10, 7 }; private static string[] tags = { "idle", "mid", "small" }; private int hits; private int stage; private List Colliding = new List(); private bool hidden; public override void PostInit() { AddGraphics("globbo", false, widths[stage], widths[stage] + 1); base.PostInit(); var a = GetComponent(); a.CustomFlip = true; a.Animation.Tag = tags[stage]; GetComponent().Callback = RenderShadow; } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (!hidden && t >= 0.2f) { t = 0; foreach (var c in Colliding) { if (c.GetComponent().ModifyHealth(-3, this)) { Hit(); } } } } private void Hit() { hits++; if (hits >= 2) { if (stage == 0) { hidden = true; } else { Done = true; } var s = stage + 1; if (s == 3) { Done = true; return; } for (var i = 0; i < 2; i++) { var b = new Bubblo(); b.stage = s; b.Owner = Owner; Area.Add(b); b.Center = Center; } } } protected override void OnJump() { base.OnJump(); if (!hidden && stage > 0) { Done = true; return; } hidden = false; hits = 0; Done = false; } public override void Render() { if (!hidden) { base.Render(); } } protected override void RenderShadow() { if (!hidden) { GraphicsComponent?.Render(true); } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (!hidden && cse.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Add(cse.Entity); if (cse.Entity.GetComponent().ModifyHealth(-3, this)) { Hit(); } } } else if (e is CollisionEndedEvent cee) { if (cee.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Remove(cee.Entity); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/Crystal.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.util; using Lens.util.math; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class Crystal : Pet { public override void AddComponents() { base.AddComponents(); Width = 12; Height = 14; AddComponent(new AnimationComponent("crystal") { ShadowOffset = -2 }); AddComponent(new ShadowComponent(RenderShadow)); var b = new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true); AddComponent(b); b.KnockbackModifier = 0; b.Body.LinearDamping = 100; } private float sinceLastTeleport; public override void Update(float dt) { base.Update(dt); sinceLastTeleport -= dt; if (!OnScreen || sinceLastTeleport <= 0) { sinceLastTeleport = Rnd.Float(2, 5); Teleport(); } } private void Teleport() { GetComponent().Animate(() => { AnimationUtil.Poof(Center, Depth + 1); Center = Owner.Center + MathUtils.CreateVector(Rnd.AnglePI(), Rnd.Float(12, 18)); AnimationUtil.Poof(Center, Depth + 1); }); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && cse.Entity is Projectile p && !p.HasFlag(ProjectileFlags.Artificial) && p.Owner == Owner && p.Parent == null) { var tt = Rnd.Int(5, 8); var body = p.GetAnyComponent(); var builder = new ProjectileBuilder(Owner, p.Slice) { LightRadius = 32f, Parent = p }; builder.AddFlags(ProjectileFlags.Artificial); for (var i = 0; i < tt; i++) { builder.Shoot(body.Angle + (i - tt * 0.5f) * 0.1f, body.Velocity.Length() * 0.05f); var pr = builder.Build(); pr.Color = ProjectileColor.Rainbow[i]; pr.Position = p.Position; } AnimationUtil.Poof(Center, Depth + 1); p.Done = true; } return base.HandleEvent(e); } protected override void Follow() { // NO FOLLOWING, HOW DARE ARE YOU? } } } ================================================ FILE: BurningKnight/entity/creature/pet/DiagonalPet.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.level; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.pet { public class DiagonalPet : RoomBasedPet { private static double[] angles = { Math.PI * 0.25f, Math.PI * 0.75f, Math.PI * 1.25f, Math.PI * 1.75f }; public override void PostInit() { base.PostInit(); var body = GetComponent().Body; body.Restitution = 1; body.Friction = 0; GetComponent().Velocity = MathUtils.CreateVector(angles[Rnd.Int(angles.Length)], 50); } public override bool ShouldCollide(Entity entity) { return entity is ProjectileLevelBody || entity is Door; } public override void Update(float dt) { base.Update(dt); var velocity = GetComponent().Velocity; var a = velocity.ToAngle() - Math.PI * 0.25f; var l = velocity.Length(); if (Math.Abs(a % (Math.PI * 0.5f)) >= 0.1f || l < 40) { a = (float) (Math.Floor(a / (Math.PI * 0.5f)) * (Math.PI * 0.5f) + Math.PI * 0.25f); GetComponent().Velocity = MathUtils.CreateVector(a, Math.Max(l, 40)); } } } } ================================================ FILE: BurningKnight/entity/creature/pet/FollowerPet.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class FollowerPet : Pet { protected string Sprite; public FollowerPet(string spr) { Sprite = spr; } public override void AddComponents() { base.AddComponents(); var region = CommonAse.Items.GetSlice(Sprite); Width = region.Width; Height = region.Height; AddComponent(new ZSliceComponent(CommonAse.Items, Sprite)); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new ZComponent { Float = true }); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); GetComponent().Animate(); } } } ================================================ FILE: BurningKnight/entity/creature/pet/GeneratorPet.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.util.tween; namespace BurningKnight.entity.creature.pet { public class GeneratorPet : Pet { private string sprite; private Func callback; private int numRooms; private int roomsCleared; public GeneratorPet(string spr, int rooms, Func generate) { sprite = spr; numRooms = rooms; callback = generate; } public override void AddComponents() { base.AddComponents(); AddComponent(new ZSliceComponent("items", sprite)); AddComponent(new ZComponent { Float = true }); var region = GetComponent().Sprite; AddComponent(new SensorBodyComponent(0, 0, region.Width, region.Height)); Subscribe(); GetComponent().Animate(); } public override bool HandleEvent(Event e) { if (e is RoomClearedEvent) { roomsCleared++; if (roomsCleared >= numRooms) { GetComponent().Pause = 1f; roomsCleared = 0; var a = GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { var item = callback(Area); if (item != null) { item.Center = Center; } AnimationUtil.Poof(Center); Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.6f); Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.6f); }; }; } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/LampPet.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; using Lens.util.camera; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.pet { public class LampPet : FollowerPet { public LampPet(string spr) : base(spr) { } public override void AddComponents() { base.AddComponents(); AddComponent(new LightComponent(this, 64f, new Color(1f, 0.8f, 0.2f, 1f))); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && Sprite == "bk:sharp_lamp" && cse.Entity is Creature c && !c.IsFriendly()) { c.GetComponent().ModifyHealth(-2, this); } return base.HandleEvent(e); } protected override void Follow() { if (Sprite == "bk:led") { if (!HasComponent()) { AddComponent(new OrbitalComponent()); Owner.GetComponent().AddOrbiter(this); } } else { base.Follow(); } } private float lastFlame; private float t; public override void Update(float dt) { base.Update(dt); t += dt * 0.5f; GetComponent().Light.Radius = 38f + (float) Math.Cos(t) * 6; lastFlame += dt; if (lastFlame > 0.3f) { Area.Add(new FireParticle { X = CenterX, Y = Y + 1, Depth = Layers.Wall + 1 }); lastFlame = 0; } } } } ================================================ FILE: BurningKnight/entity/creature/pet/LilBoo.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.level; using BurningKnight.util; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.pet { public class LilBoo : Pet { public override void AddComponents() { base.AddComponents(); Width = 6; Height = 8; AddComponent(new BooGraphicsComponent("ghost_pet")); var b = new RectBodyComponent(0, 0, Width, Height) { KnockbackModifier = 0.2f }; AddComponent(b); b.Body.LinearDamping = 3; Become(); } public override bool ShouldCollide(Entity entity) { if (entity is Player) { return true; } if (GetComponent().StateInstance is WanderState) { return entity is Level; } return false; } #region Boo states private class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); var d = Self.DistanceTo(Self.Owner); if (d > 48) { Self.Become(); } } } private class FollowState : SmartState { public override void Update(float dt) { base.Update(dt); var dx = Self.DxTo(Self.Owner); var dy = Self.DyTo(Self.Owner); var d = MathUtils.Distance(dx, dy); if (d > 256) { AnimationUtil.Poof(Self.Center); Self.Center = Self.Owner.Center + Rnd.Offset(24); AnimationUtil.Poof(Self.Center); Self.Become(); return; } if (d < 32) { Self.Become(); return; } var body = Self.GetComponent(); var s = dt * 20; body.Velocity += new Vector2(dx / d * s, dy / d * s); } } private class EmotionState : SmartState { public override void Update(float dt) { base.Update(dt); if (T > 1f) { Self.Become(); } } } private class HappyState : EmotionState { } private class WanderState : SmartState { } #endregion } } ================================================ FILE: BurningKnight/entity/creature/pet/Pet.cs ================================================ using System; using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.creature.pet { public class Pet : Creature { public Entity Owner; public Action Controller; protected bool Saveable; private bool findOwner; public override void Update(float dt) { base.Update(dt); Controller?.Invoke(dt); } public override void AddComponents() { base.AddComponents(); AlwaysActive = true; RemoveComponent(); RemoveComponent(); if (!Saveable) { RemoveTag(Tags.LevelSave); } else { findOwner = true; } } public override void PostInit() { base.PostInit(); Follow(); } protected virtual void Follow() { Owner?.GetComponent()?.AddFollower(this); } } } ================================================ FILE: BurningKnight/entity/creature/pet/PetRegistry.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.twitch; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.pet { public static class PetRegistry { private static Dictionary> defined = new Dictionary>(); public static Entity Create(string id, Entity owner) { return !defined.TryGetValue(id, out var d) ? null : d(owner); } public static Entity CreateRandom(Entity owner) { var keys = defined.Keys.ToArray(); return Create(keys[Rnd.Int(keys.Length)], owner); } public static void Define(string id, Func pet, Mod mod = null) { defined[$"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}"] = pet; } public static bool Has(string id) { return defined.ContainsKey(id); } static PetRegistry() { Define("backpack", o => o.Area.Add(new Backpack { Owner = o })); Define("crystal", o => o.Area.Add(new Crystal { Owner = o })); Define("lil_boo", o => o.Area.Add(new LilBoo { Owner = o })); Define("strawberry", o => o.Area.Add(new Strawberry() { Owner = o })); Define("snek", o => o.Area.Add(new SnekPet { Owner = o })); Define("meat_guy", o => { var timer = 0f; var pet = new AnimatedFollowerPet("meat_guy") { Owner = o }; pet.Controller += dt => { timer += dt; if (timer >= 2f) { timer = 0; if ((o.GetComponent().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) { return; } o.GetComponent().EmitRandomizedPrefixed("item_meatguy", 4, 0.5f); var a = pet.AngleTo(o.GetComponent().RealAim); var builder = new ProjectileBuilder(o, "small") { LightRadius = 32f, Color = ProjectileColor.Yellow }; builder.Shoot(a, 10f); var projectile = builder.Build(); projectile.Center = pet.Center + MathUtils.CreateVector(a, 5f); projectile.Owner = pet; } }; o.Area.Add(pet); return pet; }); Define("skele_buddy", o => { var timer = 0f; var pet = new AnimatedFollowerPet("skele_buddy") { Owner = o }; pet.Controller += dt => { timer += dt; if (timer >= 2f) { timer = 0; if ((o.GetComponent().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) { return; } o.GetComponent().EmitRandomizedPrefixed("item_meatguy", 4, 0.5f); var a = pet.AngleTo(o.GetComponent().RealAim) - Math.PI; var builder = new ProjectileBuilder(o, "circle") { Scale = Rnd.Float(0.6f, 1f), LightRadius = 32f, Color = ProjectileColor.Red }; for (var i = 0; i < 3; i++) { var projectile = builder.Shoot(a + (i - 1) * 0.3f + Rnd.Float(-0.1f, 0.1f), Rnd.Float(4, 6)).Build(); projectile.Center = pet.Center + MathUtils.CreateVector(a, 5f); projectile.Owner = pet; } } }; o.Area.Add(pet); return pet; }); Define("coin_pouch", o => o.Area.Add(new GeneratorPet("bk:coin_pouch", 2, a => Items.CreateAndAdd("bk:coin", a)) { Owner = o })); Define("key_pouch", o => o.Area.Add(new GeneratorPet("bk:key_pouch", 3, a => Items.CreateAndAdd("bk:key", a)) { Owner = o })); Define("bomb_pouch", o => o.Area.Add(new GeneratorPet("bk:bomb_pouch", 3, a => Items.CreateAndAdd("bk:bomb", a)) { Owner = o })); Define("batman", o => o.Area.Add(new GeneratorPet("bk:batman", 3, a => Items.CreateAndAdd("bk:battery", a)) { Owner = o })); Define("pouch_pouch", o => o.Area.Add(new GeneratorPet("bk:pouch_pouch", 4, a => Items.CreateAndAdd("bk:pouch", a)) { Owner = o })); Define("shield_pouch", o => o.Area.Add(new GeneratorPet("bk:shield_pouch", 8, a => Items.CreateAndAdd("bk:shield", a)) { Owner = o })); Define("shield_buddy", o => o.Area.Add(new ShieldBuddy() { Owner = o })); Define("wallet", o => o.Area.Add(new Wallet() { Owner = o })); Define("spiked_cookie", o => o.Area.Add(new SpikedCookie() { Owner = o })); Define("shooty", o => o.Area.Add(new Shooty() { Owner = o })); Define("bubblo", o => o.Area.Add(new Bubblo() { Owner = o })); Define("the_eye", o => o.Area.Add(new TheEye() { Owner = o })); Define("twitch", o => o.Area.Add(new TwitchPet() { Owner = o })); } } } ================================================ FILE: BurningKnight/entity/creature/pet/RoomBasedPet.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class RoomBasedPet : Pet { private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (t >= 1f) { t = 0; if (Done) { return; } var r = GetComponent().Room; var rm = Owner.GetComponent().Room; if (r != rm) { AnimationUtil.Poof(Center); Center = rm.GetRandomFreeTile() * 16 + new Vector2(8); AnimationUtil.Poof(Center); GetComponent().Animate(); OnJump(); } } } protected virtual void OnJump() { } protected override void Follow() { } public void AddGraphics(string sprite, bool sensor = true, int w = -1, int h = -1) { AddComponent(new AnimationComponent(sprite) { ShadowOffset = -2 }); var region = GetComponent().Animation.GetCurrentTexture(); if (w == -1) { Width = region.Width; } else { Width = w; } if (h == -1) { Height = region.Height; } else { Height = h; } AddComponent(new ShadowComponent()); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, sensor)); GetComponent().Animate(); } } } ================================================ FILE: BurningKnight/entity/creature/pet/ShieldBuddy.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class ShieldBuddy : Pet { public override void AddComponents() { base.AddComponents(); Width = 12; Height = 13; AddComponent(new AnimationComponent("shield_buddy") { ShadowOffset = -2 }); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); GetComponent().Animate(); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && cse.Entity is Projectile p && p.Owner != Owner) { p.Break(); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/Shooty.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.projectile; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.pet { public class Shooty : DiagonalPet { public override void PostInit() { AddGraphics("shooty", false); base.PostInit(); t = Rnd.Float(2f); } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (t >= 2f) { t = 0; var r = GetComponent().Room; if (r == null) { return; } if (r.Tagged[Tags.MustBeKilled].Count > 0) { var o = Owner; GetComponent().EmitRandomizedPrefixed("item_meatguy", 4, 0.5f); var builder = new ProjectileBuilder(o, "small") { Color = ProjectileColor.Yellow, Range = 32f }; builder.AddFlags(ProjectileFlags.FlyOverStones); for (var i = 0; i < 4; i++) { var a = i * Math.PI * 0.5f; var projectile = builder.Shoot(a, 4f).Build(); projectile.Center = Center + MathUtils.CreateVector(a, 5f); projectile.Owner = this; } GetComponent().Animate(); } } } } } ================================================ FILE: BurningKnight/entity/creature/pet/SnekPet.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class SnekPet : Pet { public override void AddComponents() { base.AddComponents(); Achievements.Unlock("bk:snek"); Width = 18; Height = 24; AddComponent(new SimpleZAnimationComponent("snek")); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new ZComponent { Float = true }); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); GetComponent().Animate(); AddComponent(new FollowerComponent { MaxDistance = 4 }); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Creature c && !c.IsFriendly()) { c.GetComponent().Add(new PoisonBuff()); } } return base.HandleEvent(e); } public override void Update(float dt) { base.Update(dt); var component = GetComponent(); if (component.Following == null || component.Following == this) { Owner.GetComponent().AddFollower(this); } else if (component.Following == Owner) { var room = GetComponent().Room; if (room == null) { return; } var target = room.FindClosest(Center, Tags.MustBeKilled, e => e != this); if (target != null) { if (!target.HasComponent()) { target.AddComponent(new FollowerComponent()); } GetComponent().Remove(); target.GetComponent().AddFollower(this); } } } } } ================================================ FILE: BurningKnight/entity/creature/pet/SpikedCookie.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.creature.pet { public class SpikedCookie : DiagonalPet { private List Colliding = new List(); public override void PostInit() { AddGraphics("spiked_cookie", false); base.PostInit(); } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (t >= 0.2f) { t = 0; foreach (var c in Colliding) { c.GetComponent().ModifyHealth(-3, this); } } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Add(cse.Entity); cse.Entity.GetComponent().ModifyHealth(-3, this); } } else if (e is CollisionEndedEvent cee) { if (cee.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Remove(cee.Entity); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/Strawberry.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using Lens.entity; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.pet { public class Strawberry : FollowerPet { public Strawberry() : base("bk:strawberry") { } private float delay; public override void Update(float dt) { base.Update(dt); delay -= dt; if (delay <= 0) { delay = Rnd.Float(1f, 3f); var cn = Rnd.Int(1, 4); for (var i = 0; i < cn; i++) { Timer.Add(() => { var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"heart_{Rnd.Int(1, 4)}")))); part.Position = Center; if (TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.9f; part.Depth = Layers.InGameUi; }, i * 0.3f); } } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Mob m) { m.GetComponent().Add(new CharmedBuff { Duration = 10 }); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/pet/TheEye.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.entities; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.pet { public class TheEye : RoomBasedPet { private List Colliding = new List(); public override void AddComponents() { base.AddComponents(); AddComponent(new AnimationComponent("eye") { ShadowOffset = -2 }); Width = 25; Height = 19; Depth = Layers.FlyingMob; AddComponent(new ShadowComponent()); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, false)); AddComponent(new StateComponent()); GetComponent().Become(); GetComponent().Animate(); var body = GetComponent().Body; body.Restitution = 1; body.LinearDamping = 10; Flying = true; } protected override void OnJump() { base.OnJump(); GetComponent().Become(); } private float t; public override void Update(float dt) { base.Update(dt); t += dt; if (t >= 0.2f) { t = 0; if (GetComponent().StateInstance is AttackState) { foreach (var c in Colliding) { c.GetComponent().ModifyHealth(-3, this); } } } } public override bool ShouldCollide(Entity entity) { if (entity is Chasm || entity is HalfWall || entity is SolidProp) { return false; } if ((entity is Door || entity is Level) && GetComponent().StateInstance is IdleState) { return false; } return base.ShouldCollide(entity); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (cse.Entity is Level) { if (GetComponent().StateInstance is AttackState) { Become(); } } else if (cse.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Add(cse.Entity); if (GetComponent().StateInstance is AttackState) { cse.Entity.GetComponent().ModifyHealth(-3, this); } } } else if (e is CollisionEndedEvent cee) { if (cee.Entity.HasTag(Tags.MustBeKilled)) { Colliding.Remove(cee.Entity); } } return base.HandleEvent(e); } private Entity target; #region Eye States private class IdleState : SmartState { public override void Init() { base.Init(); Self.Owner.GetComponent().AddFollower(Self); } public override void Destroy() { base.Destroy(); Self.GetComponent().Remove(); } public override void Update(float dt) { base.Update(dt); if (T <= 1f) { return; } var r = Self.Owner.GetComponent().Room; if (r == null || r.Tagged[Tags.MustBeKilled].Count == 0) { return; } Self.target = r.FindClosest(Self.Center, Tags.MustBeKilled); if (Self.target != null) { Become(); } } } private class AttackState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Velocity = MathUtils.CreateVector(Self.AngleTo(Self.target), 600); } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Velocity.LengthSquared() <= 2048) { Become(); } } } #endregion } } ================================================ FILE: BurningKnight/entity/creature/pet/Wallet.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using Lens.entity; using Lens.entity.component.logic; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; using VelcroPhysics.Utilities; using MathUtils = Lens.util.MathUtils; namespace BurningKnight.entity.creature.pet { public class Wallet : Pet { public override void AddComponents() { base.AddComponents(); Width = 12; Height = 13; AddComponent(new AnimationComponent("wallet") { ShadowOffset = -2 }); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new SensorBodyComponent(0, 0, Width, Height, BodyType.Dynamic)); GetComponent().Animate(); AddComponent(new StateComponent()); GetComponent().Become(); GetComponent().Body.LinearDamping = 3; } public override void PostInit() { base.PostInit(); Owner.GetComponent().MaxCoins = 255; } private Item target; #region Wallet States private class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); var r = Self.Owner.GetComponent().Room; if (r != null && r.Tagged[Tags.Item].Count > 0) { var min = float.MaxValue; Self.target = null; foreach (var i in r.Tagged[Tags.Item]) { if (!(i is Item)) { continue; } var item = (Item) i; if (item.Type == ItemType.Coin && !item.HasComponent() && !item.Done) { var d = Self.DistanceTo(i); if (d < min) { min = d; Self.target = item; } } } if (Self.target != null) { Become(); } } } } private class PickupState : SmartState { public override void Init() { base.Init(); Self.GetComponent().Remove(); } public override void Destroy() { base.Destroy(); Self.Follow(); } public override void Update(float dt) { base.Update(dt); if (Self.target.Done || Self.target.HasComponent()) { Self.target = null; Self.Become(); return; } var dx = Self.DxTo(Self.target); var dy = Self.DyTo(Self.target); var d = MathUtils.Distance(dx, dy); var b = Self.GetComponent().Body; var s = 360 * dt / d; b.LinearVelocity += new Vector2(dx * s, dy * s); } } #endregion public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && cse.Entity is Item i && i.Type == ItemType.Coin) { Owner.GetComponent().Pickup(i); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/player/ActiveItemComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.assets.items; using BurningKnight.debug; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.level.biome; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.input; using Lens.util.timer; namespace BurningKnight.entity.creature.player { public class ActiveItemComponent : ItemComponent { public override void PostInit() { base.PostInit(); if (Item != null && Run.Depth < 1) { Item.Done = true; Item = null; } } public override bool HandleEvent(Event e) { if (e is RoomClearedEvent) { if (Item != null && Item.UseTime > 0.02f) { var o = Item.Delay; Item.Delay = Math.Max(Item.Delay - 1, 0f); if (Math.Abs(o) >= 0.01f && Math.Abs(Item.Delay) < 0.01f) { Audio.PlaySfx("item_active_charged"); } } } return base.HandleEvent(e); } protected override void OnItemSet(Item previous) { base.OnItemSet(previous); if (Run.Depth > 0 && GlobalSave.IsFalse("control_active") && GetComponent().Dialog?.Str != null) { var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Active, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Active, true))); } dialog.StartAndClose("control_6", 5); } if (Item.Id == "bk:snow_bucket" && !(Run.Level.Biome is IceBiome)) { Timer.Add(() => { var i = Item; Drop(); i.Done = true; Entity.GetComponent().Pickup(Items.CreateAndAdd("bk:water_bucket", Entity.Area)); }, 3f); } } public override void Update(float dt) { base.Update(dt); if (Run.Depth > 0 && Item != null && !Item.Done && Input.WasPressed(Controls.Active, GetComponent())) { if (GetComponent().InDialog) { return; } if (GetComponent().StateInstance is Player.SleepingState) { GetComponent().Become(); } if (Item.Use((Player) Entity)) { if (CheatWindow.InfiniteActive) { Item.Delay = 0; } if (Run.Depth > 0 && GlobalSave.IsFalse("control_active")) { Entity.GetComponent().Close(); GlobalSave.Put("control_active", true); } Audio.PlaySfx("item_active"); if (Item.SingleUse && !CheatWindow.InfiniteActive) { Item.Done = true; } } } } public void Clear() { Item = null; } protected override bool ShouldReplace(Item item) { return item.Type == ItemType.Active; } public bool IsFullOrEmpty() { return Item == null || Item.Delay <= 0.01f; } public void Charge(int amount) { if (Item != null && Item.UseTime > 0.02f) { Item.Delay = Math.Max(Item.Delay - amount, 0f); } } } } ================================================ FILE: BurningKnight/entity/creature/player/ActiveWeaponComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.use; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.assets; using Lens.entity.component.logic; using Lens.input; namespace BurningKnight.entity.creature.player { public class ActiveWeaponComponent : WeaponComponent { private bool stopped = true; private float timeSinceReady; public ActiveWeaponComponent() { AtBack = false; } public override void Update(float dt) { base.Update(dt); var controller = GetComponent(); var data = controller.GamepadEnabled ? controller.GamepadData : null; var lamp = GetComponent().Item; var useLamp = lamp != null && lamp.Id == "bk:explosive_lamp"; var Item = useLamp ? lamp : this.Item; if ((useLamp || !Disabled) && Item != null) { var ready = Item.Delay <= 0.001f; if (ready) { if (timeSinceReady <= 0.001f && Item.Type == ItemType.Weapon) { var t = Item.Data.WeaponType; if (t == WeaponType.Ranged) { foreach (var u in Item.Uses) { if (u is SimpleShootUse s) { if (s.ReloadSfx) { Entity.GetComponent().EmitRandomizedPrefixed("item_shotgun_reload", 2, 0.8f); } break; } } } else if (t == WeaponType.Melee) { Entity.GetComponent().EmitRandomized("item_sword_cooldown", 0.5f); } } timeSinceReady += dt; } else { timeSinceReady = 0; } var b = GetComponent(); if (b.Has() || b.Has() || GetComponent().StateInstance is Player.RollState) { return; } if ((Input.WasPressed(Controls.Use, controller) || (data != null && ( data.DPadDownCheck || data.DPadLeftCheck || data.DPadUpCheck || data.DPadRightCheck ))) || ((Item.Automatic || timeSinceReady > 0.2f || (data != null && Input.IsDownOnController(Controls.Use, data))) && Input.IsDown(Controls.Use, controller) && ready)) { if (!Entity.TryGetComponent(out var d) || d.InDialog) { return; } if (GetComponent().StateInstance is Player.SleepingState) { GetComponent().Become(); } if (Run.Depth == -2) { GetComponent().Close(); } if (b.Has()) { b.Remove(); } if (useLamp) { GetComponent().SpawnBomb(); Item.Delay = 0.5f; } else { Item.Use((Player) Entity); } GetComponent().UsedWeaponInRoom = true; } } else { timeSinceReady = 0; } if ((Input.WasPressed(Controls.Swap, controller) || (Input.Mouse.WheelDelta != 0 && stopped)) && Run.Depth > 0 && GetComponent().Item != null) { if (!GetComponent().Busy) { stopped = false; Swap(); } } stopped = Input.Mouse.WheelDelta == 0; } protected override bool ShouldReplace(Item item) { return item.Type == ItemType.Weapon && (Item == null || Run.Depth < 1 || Entity.GetComponent().Item != null); } protected override void OnItemSet(Item previous) { base.OnItemSet(previous); previous?.PutAway(); Item?.TakeOut(); if (Item != null && InGameState.Ready) { Audio.PlaySfx(Item.Data.WeaponType.GetSwapSfx()); } if (Run.Depth == -2) { var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Use, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Use, true))); } dialog.StartAndClose("control_2", 5); } } } } ================================================ FILE: BurningKnight/entity/creature/player/ConsumablesComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.input; using BurningKnight.assets.particle; using BurningKnight.assets.particle.custom; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.input; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.creature.player { public class ConsumablesComponent : ItemComponent { private byte bombs; private byte keys; private byte coins; public byte MaxCoins = 99; public int Bombs { set { var n = (byte) MathUtils.Clamp(0, 99, value); if (n != bombs && AcceptChange(n - bombs, n, ItemType.Bomb)) { bombs = (byte) MathUtils.Clamp(0, 99, ((int) bombs + lastAmount)); } } get => bombs; } public int Keys { set { var n = (byte) MathUtils.Clamp(0, 99, value); if (n != keys && AcceptChange(n - keys, n, ItemType.Key)) { keys = (byte) MathUtils.Clamp(0, 99, (int) keys + lastAmount); } } get => keys; } public int Coins { set { var n = (byte) MathUtils.Clamp(0, MaxCoins, value); if (n != coins && AcceptChange(n - coins, n, ItemType.Coin)) { coins = (byte) MathUtils.Clamp(0, MaxCoins, (int) coins + lastAmount); if (coins >= 99) { Achievements.Unlock("bk:rich"); } } } get => coins; } private int lastAmount; private bool AcceptChange(int amount, int totalNow, ItemType type) { var e = amount > 0 ? (Event) new ConsumableAddedEvent { Amount = amount, TotalNow = totalNow, Type = type } : new ConsumableRemovedEvent { Amount = amount, TotalNow = totalNow, Type = type }; lastAmount = amount; if (!Send(e)) { if (e is ConsumableAddedEvent c) { lastAmount = c.Amount; } else { lastAmount = ((ConsumableRemovedEvent) e).Amount; } return true; } return false; } private bool justPlayed; public override bool HandleEvent(Event e) { if (e is ItemCheckEvent ev) { var type = ev.Item.Type; if (type == ItemType.Bomb || type == ItemType.Key || type == ItemType.Coin || type == ItemType.Battery || type == ItemType.Pouch) { // var a = Entity.GetComponent(); switch (type) { case ItemType.Bomb: { if (Run.Depth > 0 && GlobalSave.IsFalse("control_bomb")) { var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Bomb, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Bomb, true))); } dialog.StartAndClose("control_0", 3); GlobalSave.Put("control_bomb", true); } Audio.PlaySfx("item_bomb"); break; } case ItemType.Key: { Audio.PlaySfx("item_key_pickup"); break; } case ItemType.Coin: { switch (ev.Item.Id) { case "bk:emerald": { if (!justPlayed) { Audio.PlaySfx("item_emerald", 1f - Audio.Db3); justPlayed = true; Timer.Add(() => justPlayed = false, 0.1f); } break; } case "bk:platinum_coin": { Audio.PlaySfx("item_platinum_coin", 0.2f); break; } case "bk:gold_coin": { Audio.PlaySfx("item_gold_coin", 0.2f); break; } case "bk:iron_coin": { Audio.PlaySfx("item_silver_coin", 0.2f); break; } default: { Audio.PlaySfx("item_coin", 0.2f); break; } } break; } case ItemType.Battery: { Audio.PlaySfx("item_charge"); break; } case ItemType.Pouch: { Audio.PlaySfx("item_bag"); break; } } Send(new ItemAddedEvent { Item = ev.Item, Who = Entity, Component = this }); var p = (Player) Entity; ev.Item.RemoveDroppedComponents(); for (var i = 0; i < 4; i++) { Entity.Area.Add(new ParticleEntity(Particles.Dust()) { Position = ev.Item.Center, Particle = { Scale = Rnd.Float(0.4f, 0.8f) } }); } Engine.Instance.State.Ui.Add(new ConsumableParticle(ev.Item.Animation != null ? ev.Item.GetComponent().Animation.GetFirstCurrent() : ev.Item.Region, p, false, () => { ev.Item.Use(p); ev.Item.Done = true; }, ev.Item.Id == "bk:emerald")); return true; } } return base.HandleEvent(e); } public override void Update(float dt) { base.Update(dt); if (Run.Depth > 0 && Input.WasPressed(Controls.Bomb, GetComponent())) { SpawnBomb(); } } public void SpawnBomb() { if (GetComponent().InDialog) { return; } if (GetComponent().StateInstance is Player.SleepingState) { GetComponent().Become(); } var spawn = false; if (bombs > 0) { Bombs--; spawn = true; } else { var h = GetComponent(); if (h.Bombs > 0) { h.ModifyBombs(-1, Entity, true); spawn = true; } } if (spawn) { var bomb = new Bomb(Entity); Entity.Area.Add(bomb); bomb.Center = Entity.Center; bomb.MoveToMouse(); } else { AnimationUtil.ActionFailed(); } } public override void Set(Item item, bool animate = true) { item.Done = true; } protected override bool ShouldReplace(Item item) { return item.Type == ItemType.Bomb || item.Type == ItemType.Key || item.Type == ItemType.Coin || item.Type == ItemType.Pouch; } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte(bombs); stream.WriteByte(keys); stream.WriteByte(coins); } public override void Load(FileReader reader) { base.Load(reader); bombs = reader.ReadByte(); keys = reader.ReadByte(); coins = reader.ReadByte(); } } } ================================================ FILE: BurningKnight/entity/creature/player/HeartsComponent.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.events; using ImGuiNET; using Lens.entity; using Lens.entity.component; using Lens.util; using Lens.util.file; namespace BurningKnight.entity.creature.player { public class HeartsComponent : SaveableComponent { public const int Cap = 32; public const int PerRow = Cap / 2; private byte shieldHalfs; private byte bombs; private byte bombsMax; public int ShieldHalfs => shieldHalfs; public int Bombs => bombs; public int BombsMax { get => bombsMax; set { if (bombsMax == value) { return; } var old = bombsMax; var nw = value; if (!Send(new MaxHealthModifiedEvent { Who = Entity, Amount = nw - old })) { bombsMax = (byte) MathUtils.Clamp(0, 255, nw); bombs = Math.Min(bombs, bombsMax); } } } public int Total => ((int) bombs) * 2 + shieldHalfs; public int TotalMax => ((int) bombsMax) * 2 + shieldHalfs; public void ModifyShields(int amount, Entity setter) { var component = GetComponent(); amount = (int) (amount < 0 ? Math.Max(ShieldHalfs, amount) : Math.Min(Cap - component.MaxHealth - Total, amount)); var e = new HealthModifiedEvent { Amount = amount, From = setter, Who = Entity, Default = false, HealthType = HealthType.Shield }; if (amount != 0 && !Send(e)) { if (amount > 0) { Entity.GetComponent().EmitParticles(HealthType.Shield); } shieldHalfs = (byte) Math.Max(0, (float) shieldHalfs + e.Amount); if (shieldHalfs > 0) { Achievements.Unlock("bk:shielded"); } Send(new PostHealthModifiedEvent { Amount = e.Amount, From = setter, Who = Entity, Default = false, HealthType = HealthType.Shield }); } } public void ModifyBombs(int amount, Entity setter, bool pr = false) { var component = GetComponent(); amount = (int) (amount < 0 ? -Math.Min(Bombs, -amount) : Math.Min(bombsMax, amount)); var e = new HealthModifiedEvent { Amount = amount, From = setter, Who = Entity, Default = false, HealthType = HealthType.Bomb, PressedForBomb = pr }; if (amount != 0 && !Send(e)) { if (amount > 0) { Entity.GetComponent().EmitParticles(HealthType.Bomb); } bombs = (byte) Math.Max(0, (float) bombs + e.Amount); Send(new PostHealthModifiedEvent { Amount = e.Amount, From = setter, Who = Entity, Default = false, HealthType = HealthType.Bomb, PressedForBomb = pr }); } } public bool Hurt(int amount, Entity setter, DamageType type = DamageType.Regular) { if (amount > 0) { amount *= -1; } var e = new HealthModifiedEvent { Amount = amount, Type = type, From = setter, Who = Entity, Default = false, HealthType = shieldHalfs > 0 ? HealthType.Shield : HealthType.Bomb }; if (!Send(e)) { if (shieldHalfs > 0) { var iron = Math.Min(e.Amount, shieldHalfs); shieldHalfs = (byte) Math.Max(0, shieldHalfs + iron); Send(new PostHealthModifiedEvent { Amount = e.Amount, From = setter, Type = type, Who = Entity, Default = false, HealthType = HealthType.Shield }); return true; } else if (bombs > 0) { var iron = Math.Min(e.Amount, bombs); bombs = (byte) Math.Max(0, bombs + iron); Send(new PostHealthModifiedEvent { Amount = e.Amount, From = setter, Type = type, Who = Entity, Default = false, HealthType = HealthType.Bomb }); return true; } } return false; } public bool CanHaveMore => Total + GetComponent().MaxHealth < Cap; public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte(shieldHalfs); stream.WriteByte(bombs); stream.WriteByte(bombsMax); } public override void Load(FileReader stream) { base.Load(stream); shieldHalfs = stream.ReadByte(); bombs = stream.ReadByte(); bombsMax = stream.ReadByte(); } public override void RenderDebug() { base.RenderDebug(); ImGui.Text($"Iron halfs: {shieldHalfs}"); var v = (int) bombsMax; if (ImGui.InputInt("Bombs Max", ref v)) { bombsMax = (byte) v; } v = (int) bombs; if (ImGui.InputInt("Bombs", ref v)) { bombs = (byte) v; } } } } ================================================ FILE: BurningKnight/entity/creature/player/InteractorComponent.cs ================================================ using System; using System.Collections.Generic; using System.Security.AccessControl; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.entity.item; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens; using Lens.entity; using Lens.entity.component; using Lens.input; using Lens.util; namespace BurningKnight.entity.creature.player { public class InteractorComponent : Component { public Entity CurrentlyInteracting; public List InteractionCandidates = new List(); public override void Update(float dt) { base.Update(dt); if (CurrentlyInteracting != null && Input.WasPressed(Controls.Interact, GetComponent()) && !GetComponent().Busy) { if (Run.Depth == -2 && GlobalSave.IsFalse("control_interact")) { GlobalSave.Put("control_interact", true); Entity.GetComponent().Close(); } if (CurrentlyInteracting.GetComponent().Interact(Entity)) { Send(new InteractedEvent { Who = Entity, With = CurrentlyInteracting }); EndInteraction(); } } } public void EndInteraction() { if (CurrentlyInteracting.TryGetComponent(out var component)) { component.OnEnd?.Invoke(Entity); component.CurrentlyInteracting = null; } if (InteractionCandidates.Count == 0) { CurrentlyInteracting = null; } else { CurrentlyInteracting = InteractionCandidates[0]; InteractionCandidates.RemoveAt(0); OnStart(); } } private void OnStart() { if (!CurrentlyInteracting.TryGetComponent(out var component)) { return; } component.CurrentlyInteracting = Entity; component.OnStart?.Invoke(Entity); if (Run.Depth == -2) { var hasGamepad = GamepadComponent.Current != null && GamepadComponent.Current.Attached; var region = CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Interact, false)); Engine.Instance.State.Ui.Add(new InteractFx(CurrentlyInteracting, null, region, hasGamepad ? -5 : 0)); if (hasGamepad) { region = CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Interact, true)); Engine.Instance.State.Ui.Add(new InteractFx(CurrentlyInteracting, null, region, 5)); } } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent start) { if (start.Body.CanCollide && CanInteract(start.Entity)) { var entity = start.Entity.GetComponent().AlterInteraction?.Invoke() ?? start.Entity; if (CurrentlyInteracting != entity) { if (CurrentlyInteracting != null) { if (!InteractionCandidates.Contains(entity)) { InteractionCandidates.Add(entity); } } else { CurrentlyInteracting = entity; OnStart(); } } } } else if (e is CollisionEndedEvent end && end.Body.CanCollide) { if (CurrentlyInteracting == end.Entity) { EndInteraction(); } else { InteractionCandidates.Remove(end.Entity); } } return base.HandleEvent(e); } public Func CanInteractCallback; public virtual bool CanInteract(Entity e) { return e.TryGetComponent(out var component) && (component.CanInteract?.Invoke(Entity) ?? true) && (CanInteractCallback == null || CanInteractCallback(e)); } } } ================================================ FILE: BurningKnight/entity/creature/player/LampComponent.cs ================================================ using BurningKnight.assets.items; using BurningKnight.debug; using BurningKnight.entity.component; using BurningKnight.entity.creature.pet; using BurningKnight.entity.item; using BurningKnight.util; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.creature.player { public class LampComponent : ItemComponent { private FollowerPet pet; private bool loaded; private bool hadLamp; private Item prev; public override void Set(Item item, bool animate = true) { base.Set(item, (item == null || item.Id != "bk:no_lamp") && animate); } public override void PostInit() { base.PostInit(); loaded = true; if (Item == null) { Set(Items.CreateAndAdd("bk:no_lamp", Entity.Area), false); } } protected override void OnItemSet(Item previous) { base.OnItemSet(previous); if (pet != null) { if (pet.TryGetComponent(out var f)) { f.Remove(); } else { pet.GetComponent().Orbiting.GetComponent().RemoveOrbiter(pet); } pet.Done = true; pet = null; } if (prev != null && prev.Id != "bk:no_lamp") { Entity.RemoveComponent(); Entity.RemoveComponent(); Entity.RemoveComponent(); Entity.AddComponent(new HealthComponent()); var hp = Entity.GetComponent(); hp.InitMaxHealth = 6; hp.SaveMaxHp = true; hp.MaxHealthCap = 32; hp.InvincibilityTimerMax = 1f; if (CheatWindow.AutoGodMode) { Log.Info("Entering god mode for the player"); hp.Unhittable = true; } Entity.AddComponent(new HeartsComponent()); Entity.AddComponent(new InventoryComponent()); if (Entity.TryGetComponent(out var w)) { w.Disabled = false; } if (Entity.TryGetComponent(out var aw)) { aw.Disabled = false; } } prev = Item; if (loaded) { Item?.Use(Entity); hadLamp = true; } if (Item == null || Item.Id == "bk:no_lamp") { return; } pet = new LampPet(Item.Id) { Owner = Entity }; Entity.Area.Add(pet); pet.Center = Entity.Center + MathUtils.CreateVector(Rnd.AnglePI(), Rnd.Float(16f, 48f)); AnimationUtil.Poof(pet.Center); } protected override bool ShouldReplace(Item item) { return item.Type == ItemType.Lamp; } } } ================================================ FILE: BurningKnight/entity/creature/player/LocalPlayer.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.state; using Lens; using Lens.assets; using Lens.entity; using Lens.util; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.creature.player { public class LocalPlayer : Player { public static LocalPlayer Locate(Area area) { foreach (var player in area.Tagged[Tags.Player]) { if (player is LocalPlayer localPlayer) { return localPlayer; } } return null; } public override void AddComponents() { base.AddComponents(); AddComponent(new GamepadComponent()); AddComponent(new PlayerInputComponent()); } private bool died; public override bool HandleEvent(Event e) { if (e is DiedEvent ev && ev.Who == this) { if (!GetComponent().Dead && !died) { died = true; Done = false; GetComponent().EmitRandomized("player_death"); RemoveComponent(); Achievements.Unlock("bk:rip"); Items.Unlock("bk:dagger"); var body = GetComponent(); body.KnockbackModifier = 0; body.Velocity = Vector2.Zero; if (InGameState.EveryoneDied(this)) { Audio.FadeOut(); ((InGameState) Engine.Instance.State).HandleDeath(); Camera.Instance.Targets.Clear(); Camera.Instance.Follow(this, 1); Tween.To(0.3f, Engine.Instance.Speed, x => Engine.Instance.Speed = x, 0.5f).OnEnd = () => { var t = Tween.To(1, Engine.Instance.Speed, x => Engine.Instance.Speed = x, 0.5f); t.Delay = 0.8f; t.OnEnd = () => ((InGameState) Engine.Instance.State).AnimateDoneScreen(this); HandleEvent(e); AnimateDeath(ev); Done = true; }; } else { HandleEvent(e); AnimateDeath(ev); } return true; } } else if (e is PostHealthModifiedEvent hp && hp.Amount < 0 && !hp.PressedForBomb) { Engine.Instance.Split = 1f; Engine.Instance.Flash = 1f; Engine.Instance.Freeze = 1f; Camera.Instance.Shake(4); if (Camera.Instance != null && Settings.Flashes) { Camera.Instance.TextureZoom -= 0.2f; Tween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.3f); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/creature/player/Player.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.custom; using BurningKnight.assets.particle.renderer; using BurningKnight.debug; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.bk; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.npc; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.entity.projectile; using BurningKnight.entity.room; using BurningKnight.entity.twitch; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.entities; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui; using BurningKnight.ui.dialog; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component; using Lens.entity.component.logic; using Lens.graphics; using Lens.graphics.gamerenderer; using Lens.input; using Lens.util; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.creature.player { public class Player : Creature, DropModifier { private static Color tint = new Color(50, 234, 60, 200); public const int MaxPlayers = 5; public static Color[] IndexTints = { Palette.Default[59], Palette.Default[42], Palette.Default[35], Palette.Default[55], Palette.Default[31] }; public static Vector4[] VectorTints; static Player() { VectorTints = new Vector4[MaxPlayers]; for (var i = 0; i < MaxPlayers; i++) { var color = IndexTints[i]; VectorTints[i] = new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1f); } } public Color Tint => IndexTints[GetComponent().Index]; public static int Quacks; public static bool ToBoss; public static bool InBuilding; public static Color LightColor = new Color(1f, 0.8f, 0.6f, 1f); public static string[] StartingWeapons = new string[MaxPlayers]; public static string[] StartingItems = new string[MaxPlayers]; public static string[] StartingLamps = new string[MaxPlayers]; public static List DailyItems; public string ProjectileTexture = "rect"; public bool ItemDamage; public bool Sliding; public bool Dead; public void AnimateItemPickup(Item item, Action action = null, bool add = true, bool ban = true) { if (ban) { var banner = new UiDescriptionBanner(); banner.Show(item); Engine.Instance.State.Ui.Add(banner); } if (item.Type == ItemType.Weapon && Run.Depth == 0) { Audio.PlaySfx(item.Data.WeaponType.GetPickupSfx()); } else { GetComponent().EmitRandomized("item_pickup"); } if (add || item.Type == ItemType.Lamp || item.Type == ItemType.Active || item.Type == ItemType.ConsumableArtifact || item.Type == ItemType.Weapon || item.Type == ItemType.Hat) { GetComponent().Busy = true; Engine.Instance.State.Ui.Add(new ConsumableParticle(item.Region, this, item.Type != ItemType.Active, () => { item.Area?.Remove(item); item.Done = false; action?.Invoke(); GetComponent().Busy = false; if (item.Type != ItemType.ConsumableArtifact && item.Type != ItemType.Active && item.Type != ItemType.Weapon && item.Type != ItemType.Hat && item.Type != ItemType.Lamp) { GetComponent().Add(item); } })); return; } } public override void AddComponents() { base.AddComponents(); AddComponent(new InputComponent()); AddComponent(new CursorComponent()); InBuilding = false; GetComponent().SaveMaxHp = true; Height = 11; // Graphics if (Run.Depth != 0) { AddComponent(new LightComponent(this, 64, LightColor)); } AddComponent(new PlayerGraphicsComponent { Offset = new Vector2(0, -5) }); // Inventory AddComponent(new LampComponent()); AddComponent(new InventoryComponent()); AddComponent(new ActiveItemComponent()); AddComponent(new ActiveWeaponComponent()); AddComponent(new WeaponComponent()); AddComponent(new ConsumablesComponent()); AddComponent(new HatComponent()); // Stats AddComponent(new ManaComponent()); AddComponent(new HeartsComponent()); AddComponent(new StatsComponent()); // Collisions AddComponent(new RectBodyComponent(4, Height - 1, 8, 1) { CanCollide = false }); AddComponent(new SensorBodyComponent(2, 1, Width - 4, Height - 1, BodyType.Dynamic, true)); GetComponent().Body.SleepingAllowed = false; AddComponent(new InteractorComponent { CanInteractCallback = e => !died && !GetComponent().Busy }); // Other mechanics AddComponent(new OrbitGiverComponent()); AddComponent(new FollowerComponent()); AddComponent(new AimComponent(AimComponent.AimType.Cursor)); AddComponent(new DialogComponent()); AddComponent(new ZComponent()); GetComponent().Become(); AddTag(Tags.Player); AddTag(Tags.PlayerTarget); AddTag(Tags.PlayerSave); RemoveTag(Tags.LevelSave); AlwaysActive = true; InitStats(true); Subscribe(); } public void InitStats(bool fromInit = false) { HasFlight = false; SuperHot = false; Scourge.Clear(); GetComponent().ShowLaserLine = false; GetComponent().DestroyAll(); GetComponent().DestroyAll(); var hp = GetComponent(); if (fromInit) { hp.InitMaxHealth = 6; } hp.MaxHealthCap = 32; hp.InvincibilityTimerMax = 1f; if (CheatWindow.AutoGodMode) { Log.Info("Entering god mode for the player"); hp.Unhittable = true; } } private int lastDepth = -3; public void FindSpawnPoint() { if (Run.StartedNew && Run.Depth > 0) { TwitchBridge.OnNewRun?.Invoke(); var index = GetComponent().Index; if (StartingLamps[index] != null) { var i = Items.CreateAndAdd(StartingLamps[index], Area); i.Scourged = false; GetComponent().Set(i, false); Log.Debug($"Starting lamp: {StartingLamps[index]}"); } if (StartingWeapons[index] == null || !ItemPool.StartingWeapon.Contains(Items.Datas[StartingWeapons[index]].Pools)) { StartingWeapons[index] = Items.Generate(ItemPool.StartingWeapon, item => Item.Unlocked(item.Id)); } if (StartingWeapons[index] != null) { var i = Items.CreateAndAdd(StartingWeapons[index], Area); i.Scourged = false; var l = GetComponent().Item; if (l != null && l.Id == "bk:sharp_lamp" && i.Data.WeaponType != WeaponType.Melee) { StartingWeapons[index] = Items.Generate(ItemPool.StartingWeapon, item => Item.Unlocked(item.Id)); i.Done = true; i = Items.CreateAndAdd(StartingWeapons[index], Area); } GetComponent().Set(i, false); Log.Debug($"Starting weapon: {StartingWeapons[index]}"); } if (StartingItems[index] != null) { var i = Items.CreateAndAdd(StartingItems[index], Area); i.Scourged = false; GetComponent().Set(i, false); Log.Debug($"Starting item: {StartingItems[index]}"); } if (DailyItems != null) { if (Run.Type == RunType.Daily) { var inventory = GetComponent(); foreach (var id in DailyItems) { Log.Info($"Giving {id}"); inventory.Pickup(Items.CreateAndAdd(id, Area), false); } } DailyItems = null; } } findASpawn = true; if (lastDepth == Run.Depth) { Log.Info("Old depth is the same as the current one"); return; } lastDepth = Run.Depth; if (Run.Depth > 1 && !GetComponent().TookDamageOnLevel) { Achievements.Unlock("bk:dodge_overlord"); } HandleEvent(new NewLevelStartedEvent()); } private bool set; private float t; private bool findASpawn; public bool Teleported; private bool FindSpawn() { if (/*BK.Version.Dev || */ToBoss) { ToBoss = false; foreach (var r in Area.Tagged[Tags.Room]) { var rm = (Room) r; if (rm.Type == RoomType.Boss) { Center = r.Center + new Vector2(0, 32) + Rnd.Vector(-0.5f, 0.5f); rm.Discover(); Log.Debug("Teleported to boss room"); return true; } } } foreach (var cc in Area.Tagged[Tags.Checkpoint]) { Center = cc.Center + Rnd.Vector(-0.5f, 0.5f); Log.Debug("Teleported to spawn point"); return true; } foreach (var cc in Area.Tagged[Tags.Entrance]) { Center = cc.Center + new Vector2(0, 4) + Rnd.Vector(-0.5f, 0.5f); Log.Debug("Teleported to entrance"); return true; } foreach (var r in Area.Tagged[Tags.Room]) { var rm = (Room) r; if (rm.Type == RoomType.Entrance) { Center = r.Center + Rnd.Vector(-0.5f, 0.5f); rm.Discover(); Log.Debug("Teleported to entrance room"); return true; } } foreach (var r in Area.Tagged[Tags.Room]) { var rm = (Room) r; if (rm.Type == RoomType.Exit) { Log.Debug("Teleported to exit room"); Center = new Vector2(rm.CenterX, rm.Bottom - 1.4f * 16) + Rnd.Vector(-0.5f, 0.5f); rm.Discover(); return true; } } foreach (var r in Area.Tagged[Tags.Room]) { var rm = (Room) r; Log.Debug("Teleported to random room"); Center = new Vector2(rm.CenterX, rm.Bottom - 1.4f * 16) + Rnd.Vector(-0.5f, 0.5f); rm.Discover(); return true; } Log.Error("Failed to teleport!"); AnimationUtil.Poof(Center, 20); return false; } public override void Update(float dt) { if (findASpawn) { if (FindSpawn()) { Teleported = true; findASpawn = false; if (!CheatWindow.AutoGodMode) { GetComponent().Unhittable = false; } } else { Log.Error("Did not find a spawn point!"); } } base.Update(dt); t += dt; if (!set && t >= 0.3f) { set = true; GetComponent().Room?.Discover(); if (Run.Depth == 0) { CageLock.CheckProgress(); HatStand.CheckHats(); Items.CheckForCollector(); Builder.CheckShortcutUnlocks(); if (Assets.FailedToLoadAudio) { Assets.FailedToLoadAudio = false; ((InGameState) Engine.Instance.State).TopUi.Add(new UiError("Audio Failed", "Failed to init audio device")); } } } } #region Player States public class IdleState : EntityState { public override void Update(float dt) { base.Update(dt); if (!CheatWindow.NoSleep && T >= 6f && Self.HasComponent()) { Become(); } } } public class SittingState : EntityState { public override void Init() { base.Init(); Self.GetComponent().Animate(); } public override void Destroy() { base.Destroy(); var pr = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer; pr.EnableClip = false; Self.GetComponent().Animate(); } public override void Update(float dt) { base.Update(dt); if (T >= 24f && Self.HasComponent()) { Become(); } } } public class SleepingState : EntityState { public override void Init() { base.Init(); Self.GetComponent().Animate(); } public override void Destroy() { base.Destroy(); Self.GetComponent().Animate(); } public override void Update(float dt) { base.Update(dt); if (T >= 3f) { T = 0; for (var i = 0; i < 3; i++) { Timer.Add(() => { var part = new ParticleEntity(new Particle(Controllers.Float, new TexturedParticleRenderer(CommonAse.Particles.GetSlice($"sleep")))); part.Position = Self.Center; if (Self.TryGetComponent(out var z)) { part.Position -= new Vector2(0, z.Z); } Self.Area.Add(part); part.Particle.Velocity = new Vector2(Rnd.Float(8, 16) * (Rnd.Chance() ? -1 : 1), -Rnd.Float(30, 56)); part.Particle.Angle = 0; part.Particle.Alpha = 0.9f; part.Depth = Layers.InGameUi; }, i * 0.5f); } } } } public class DuckState : EntityState { public override void Init() { base.Init(); Quacks++; if (Quacks >= 150) { Achievements.Unlock("bk:quackers"); } var hat = Self.GetComponent().Item; if (hat != null && (hat.Id == "bk:villager_head" || hat.Id == "bk:stone_hat")) { Audio.PlaySfx($"villager{Rnd.Int(1, 5)}", 1f, Rnd.Float(-0.5f, 0.5f)); } else { Audio.PlaySfx("quck", 1f, Rnd.Float(-0.5f, 0.5f)); } Self.HandleEvent(new QuackEvent { Player = (Player) Self }); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Velocity.Length() > 10f) { if (T >= 0.2f) { AnimationUtil.Poof(Self.Center); T = 0; } } else { T = 0; } } } public class RunState : SmartState { private float lastParticle = 0.25f; private uint lastFrame; public override void Update(float dt) { base.Update(dt); lastParticle -= dt; if (lastParticle <= 0) { lastParticle = 0.25f; var part = new ParticleEntity(Particles.Dust()); part.Position = Self.Center; part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Self.Area.Add(part); } if (!Self.HasFlight) { var anim = Self.GetComponent().Animation; if (anim.Frame != lastFrame) { lastFrame = anim.Frame; if (Run.Level != null && (lastFrame == 2 || lastFrame == 6)) { var x = (int) (Self.CenterX / 16); var y = (int) (Self.Bottom / 16); if (!Run.Level.IsInside(x, y)) { return; } var i = Run.Level.ToIndex(x, y); var tile = Run.Level.Get(i); var liquid = Run.Level.Liquid[i]; var room = Self.GetComponent().Room; Audio.PlaySfx(Run.Level.Biome.GetStepSound(liquid == 0 ? tile : (Tile) liquid), room != null && room.Tagged[Tags.MustBeKilled].Count > 0 ? 0.18f : 0.25f); } } } } } public class PostRollState : EntityState { public override void Update(float dt) { base.Update(dt); if (T >= 0.2f) { Self.GetComponent().Acceleration = Vector2.Zero; Become(); } } } public class RollState : EntityState { private const float RollTime = 0.25f; private const float RollForce = 1600f; private float lastParticle = 0.05f; private Vector2 direction; private bool wasUnhittable; public override void Init() { base.Init(); var z = Self.GetComponent(); var start = z.Z; Tween.To(start + 8, start, x => z.Z = x, 0.15f, Ease.QuadIn).OnEnd = () => { Tween.To(start, z.Z, x => z.Z = x, 0.15f, Ease.QuadIn); }; Self.GetComponent().EmitRandomized("player_roll", 0.5f); var hp = Self.GetComponent(); wasUnhittable = hp.Unhittable; hp.Unhittable = true; var body = Self.GetComponent(); var angle = body.Acceleration.LengthSquared() > 0.1f ? body.Acceleration.ToAngle() : (Camera.Instance.ScreenToCamera(Input.Mouse.ScreenPosition) - Self.Center).ToAngle(); direction = new Vector2((float) Math.Cos(angle) * RollForce, (float) Math.Sin(angle) * RollForce); for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Self.Center; part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Self.Area.Add(part); } } public override void Destroy() { base.Destroy(); Self.GetComponent().Unhittable = wasUnhittable; } public override void Update(float dt) { base.Update(dt); if (T >= RollTime) { Become(); return; } var body = Self.GetComponent(); body.Velocity += direction * (RollTime - T * 0.5f); body.Position += body.Velocity * dt * 0.1f; lastParticle -= dt; if (lastParticle <= 0) { lastParticle = 0.1f; var part = new ParticleEntity(Particles.Dust()); part.Position = Self.Center; part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Self.Area.Add(part); } } public void ChangeDirection() { direction *= -1; } } #endregion public override bool ShouldCollide(Entity entity) { if (HasFlight && entity is HalfWall) { return false; } return !(entity is Player || entity is HalfProjectileLevel || entity is ProjectileLevelBody || ((entity is ItemStand || entity is Bomb) && InAir())) && base.ShouldCollide(entity); } public bool HasFlight; public bool SuperHot; public override bool InAir() { return HasFlight || base.InAir() || GetComponent().StateInstance is RollState; } public override bool HasNoHealth(HealthModifiedEvent e = null) { return base.HasNoHealth(e) && GetComponent().Total == 0; } public override bool HasNoHealth(PostHealthModifiedEvent e = null) { return base.HasNoHealth(e) && GetComponent().Total == 0; } public override bool HandleEvent(Event e) { if (e is LostSupportEvent) { if (GetComponent().Unhittable) { return true; } if (!GetComponent().PitImmunity) { GetComponent().ModifyHealth(-1, Run.Level); } for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Center; part.Particle.Scale = Rnd.Float(0.4f, 0.8f); Area.Add(part); } } else if (e is RoomChangedEvent c) { if (c.New == null || Run.Level == null || Camera.Instance == null) { return base.HandleEvent(e); } if (c.New.Tagged[Tags.MustBeKilled].Count > 0) { Audio.PlaySfx("level_door_shut"); foreach (var p in Area.Tagged[Tags.Player]) { if (p.GetComponent().Room != c.New) { AnimationUtil.Poof(p.Center); p.Center = Center; AnimationUtil.Poof(p.Center); } } } ((InGameState) Engine.Instance.State).ResetFollowing(); var pr = (PixelPerfectGameRenderer) Engine.Instance.StateRenderer; if (c.Old != null) { if (Scourge.IsEnabled(Scourge.OfLost)) { c.Old.Hide(); } if (c.Old.Type == RoomType.DarkMarket || c.Old.Type == RoomType.Hidden) { pr.EnableClip = false; c.Old.Hide(true); InBuilding = false; ((InGameState) Engine.Instance.State).UpdateRainVolume(); } } if (c.New.Type == RoomType.DarkMarket) { Achievements.Unlock("bk:dark_market"); } if (c.New.Type == RoomType.DarkMarket || c.New.Type == RoomType.Hidden) { pr.EnableClip = true; pr.ClipPosition = new Vector2(c.New.X + 16, c.New.Y + 16); pr.ClipSize = new Vector2(c.New.Width - 16, c.New.Height - 32); InBuilding = true; ((InGameState) Engine.Instance.State).UpdateRainVolume(); } else { pr.EnableClip = false; } if (c.New.Type == RoomType.Shop) { Audio.PlaySfx("level_door_bell"); } c.New.Discover(); var level = Run.Level; if (InGameState.Ready) { switch (c.New.Type) { case RoomType.Secret: case RoomType.Special: case RoomType.Shop: case RoomType.SubShop: case RoomType.Treasure: { foreach (var door in c.New.Doors) { if (door.TryGetComponent(out var component) && component.Lock is GoldLock) { if (!(c.New.Type == RoomType.Shop && ((door.Rooms[0] != null && door.Rooms[0].Type == RoomType.SubShop) || (door.Rooms[1] != null && door.Rooms[1].Type == RoomType.SubShop)))) { component.Lock.SetLocked(false, this); } } } break; } case RoomType.OldMan: case RoomType.Granny: { if (c.New.Type == RoomType.OldMan) { GetComponent().SawDeal = true; } c.New.OpenHiddenDoors(); foreach (var r in Area.Tagged[Tags.Room]) { var room = (Room) r; if (room.Type == (c.New.Type == RoomType.OldMan ? RoomType.Granny : RoomType.OldMan)) { room.CloseHiddenDoors(); break; } } break; } } if (c.New.Type == RoomType.Secret) { ExplosionMaker.CheckForCracks(level, c.New, this); } } if (c.Old != null) { if (c.Old.Type == RoomType.OldMan) { var found = false; foreach (var p in c.Old.Tagged[Tags.Player]) { if (p != this && p is Player) { found = true; break; } } if (!found) { c.Old.CloseHiddenDoors(); } } else if (c.Old.Type == RoomType.Treasure && Run.Type != RunType.BossRush && !Rnd.Chance(5)) { var found = false; foreach (var p in c.Old.Tagged[Tags.Player]) { if (p != this && p is Player) { found = true; break; } } if (!found) { foreach (var door in c.Old.Doors) { var x = (int) Math.Floor(door.CenterX / 16); var y = (int) Math.Floor(door.Bottom / 16); var t = level.Get(x, y); if (level.Get(x, y).Matches(TileFlags.Passable)) { var index = level.ToIndex(x, y); level.Set(index, level.Biome is IceBiome ? Tile.WallB : Tile.WallA); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); level.LoadPassable(); Camera.Instance.Shake(10); } } c.Old.ApplyToEachTile((x, y) => { if (Run.Level.Get(x, y).IsWall()) { return; } Timer.Add(() => { var part = new TileParticle(); part.Top = Run.Level.Tileset.WallTopADecor; part.TopTarget = Run.Level.Tileset.WallTopADecor; part.Side = Run.Level.Tileset.FloorSidesD[0]; part.Sides = Run.Level.Tileset.WallSidesA[2]; part.Tile = Tile.WallA; part.X = x * 16; part.Y = y * 16; part.Target.X = x * 16; part.Target.Y = y * 16; part.TargetZ = -8f; Area.Add(part); }, Rnd.Float(0.5f)); }); foreach (var d in c.Old.Doors) { d.Done = true; } c.Old.Done = true; } } } // Darken the lighting in evil rooms if (c.New.Type == RoomType.OldMan || c.New.Type == RoomType.Spiked) { Tween.To(0.7f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f); } else if (c.Old != null && (c.Old.Type == RoomType.OldMan || c.Old.Type == RoomType.Spiked)) { Tween.To(1f, Lights.RadiusMod, x => Lights.RadiusMod = x, 0.3f); } } else if (e is HealthModifiedEvent hm) { if (hm.Amount < 0) { if ((hm.From is Mob m && m.HasPrefix) || (hm.From is creature.bk.BurningKnight k && k.InFight) || hm.From is BkOrbital) { hm.Amount = Math.Min(hm.Amount, -2); } else if (hm.Type != DamageType.Custom && hm.Type != DamageType.Explosive) { hm.Amount = Math.Max(-1, hm.Amount); } } } else if (e is PostHealthModifiedEvent h) { if (h.Amount < 0 && !h.PressedForBomb) { HandleEvent(new PlayerHurtEvent { Player = this }); var hp = GetComponent().Health + GetComponent().Total; if (hp > 0) { if (h.HealthType == HealthType.Shield) { Audio.PlaySfx("player_shield_hurt", 1f); } else { Audio.PlaySfx(hp < 2 ? "player_low_hp_hurt" : "player_hurt", 1f); } } if (Settings.Blood) { var cl = GetBloodColor(); if (Rnd.Chance(30)) { for (var i = 0; i < Rnd.Int(1, 3); i++) { Area.Add(new SplashParticle { Position = Center - new Vector2(2.5f), Color = cl }); } } Area.Add(new SplashFx { Position = Center, Color = ColorUtils.Mod(cl) }); } } } else if (e is RoomClearedEvent rce) { Camera.Instance.Unfollow(rce.Room); Audio.PlaySfx("level_room_cleared", 0.25f + Audio.Db3); if (Run.Depth > 0 && !alerted && CheckClear(Area)) { alerted = true; AnimationUtil.Confetti(Center); Audio.PlaySfx("level_cleared"); } } else if (e is NewLevelStartedEvent) { GetComponent().Unhittable = true; } else if (e is ProjectileCreatedEvent pce) { if (Flying || HasFlight) { pce.Projectile.AddFlags(ProjectileFlags.FlyOverStones); } } else if (e is FlagCollisionStartEvent fcse) { if (fcse.Flag == Flag.Burning) { GetComponent().ModifyHealth(-1, Run.Level); } } else if (e is RevivedEvent re) { AnimationUtil.TeleportAway(this, () => { FindSpawn(); Camera.Instance.Jump(); AnimationUtil.TeleportIn(this); }); } else if (e is CollisionStartedEvent cse) { if (ItemDamage && cse.Entity is Item) { GetComponent().ModifyHealth(-1, cse.Entity, DamageType.Custom); } } return base.HandleEvent(e); } private bool alerted; public static bool CheckClear(Area area) { foreach (var r in area.Tagged[Tags.Room]) { var room = (Room) r; if ((room.Type == RoomType.Regular) && !room.Cleared) { return false; } } return true; } public void RenderOutline() { var component = GetComponent(); var color = component.Tint; component.Tint = new Color(0f, 0f, 0f, 0.65f); component.SimpleRender(false); component.Tint = color; } public override bool ShouldCollideWithDestroyableInAir() { return !HasFlight; } protected override bool HandleDeath(DiedEvent d) { Done = false; died = true; var ing = (InGameState) Engine.Instance.State; ing.Killer.Animation = null; ing.Killer.Slice = null; ing.Killer.UseSlice = true; var b = GetComponent(); b.Knockback = Vector2.Zero; b.Velocity = Vector2.Zero; if (d.From != null && d.From != this) { var anim = d.From.GetAnyComponent(); if (anim != null) { ing.Killer.Animation = Animations.Get(anim.Id)?.CreateAnimation(); if (ing.Killer.Animation != null) { ing.Killer.Animation.Tag = "idle"; ing.Killer.UseSlice = false; var c = ing.Killer.Animation.GetCurrentTexture(); ing.Killer.Width = c.Width; ing.Killer.Height = c.Height; } } else { var slice = d.From.GetAnyComponent(); if (slice != null) { ing.Killer.Slice = slice.Sprite; ing.Killer.Width = ing.Killer.Slice.Width; ing.Killer.Height = ing.Killer.Slice.Height; } } } if (d.From == this) { ing.Killer.Slice = CommonAse.Ui.GetSlice("self"); } if (ing.Killer.Slice == null && ing.Killer.Animation == null) { ing.Killer.Slice = CommonAse.Items.GetSlice("unknown"); ing.Killer.Width = ing.Killer.Slice.Width; ing.Killer.Height = ing.Killer.Slice.Height; } ing.Killer.Width *= 2; ing.Killer.Height *= 2; ing.Killer.RelativeCenterX = Display.UiWidth * 0.75f; Log.Info($"Killed by: {(d.From?.GetType().Name ?? "null")}"); return true; } public override bool IgnoresProjectiles() { return GetComponent().StateInstance is RollState; } private bool died; public override void AnimateDeath(DiedEvent d) { Dead = true; base.AnimateDeath(d); for (var i = 0; i < 6; i++) { Area.Add(new ParticleEntity(Particles.Dust()) { Position = Center + new Vector2(Rnd.Int(-4, 4), Rnd.Int(-4, 4)), Depth = 30 }); } GetComponent().DestroyAll(); GetComponent().DestroyAll(); var stone = new Tombstone(); stone.DisableDialog = true; if (InGameState.Multiplayer) { stone.HasPlayer = true; stone.Index = GetComponent().Index; stone.WasGamepad = GetComponent().GamepadEnabled; if (GetComponent().Index == 0) { var minIndex = 1024; Player pl = null; foreach (var p in Area.Tagged[Tags.Player]) { var i = p.GetComponent().Index; if (p != this && i < minIndex) { minIndex = i; pl = (Player) p; } } if (pl != null) { var c = ForceGetComponent(); c.Entity = pl; Components.Remove(typeof(ConsumablesComponent)); pl.Components[typeof(ConsumablesComponent)] = c; AddComponent(new ConsumablesComponent()); } } } var pool = new List(); foreach (var i in GetComponent().Items) { if (i.Type != ItemType.Hat && i.Id != "bk:no_lamp") { pool.Add(i.Id); } } var w = GetComponent().Item; if (w != null) { pool.Add(w.Id); } w = GetComponent().Item; if (w != null) { pool.Add(w.Id); } w = GetComponent().Item; if (w != null) { pool.Add(w.Id); } if (pool.Count == 0) { pool.Add("bk:coin"); } GlobalSave.Put("next_tomb", pool[Rnd.Int(pool.Count)]); GlobalSave.Put("tomb_depth", Run.Depth); Area.Add(stone); stone.CenterX = CenterX; stone.Bottom = Bottom; if (InGameState.EveryoneDied(this)) { Camera.Instance.Targets.Clear(); Camera.Instance.Follow(stone, 0.5f); } else { ((InGameState) Engine.Instance.State).ResetFollowing(); } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteInt32(lastDepth); } public override void Load(FileReader stream) { base.Load(stream); lastDepth = stream.ReadInt32(); } public void ModifyDrops(List drops) { if (!Dead) { return; } var inventory = GetComponent(); foreach (var i in inventory.Items) { if (i.Id != "bk:no_lamp") { drops.Add(Items.Create(i.Id)); } } foreach (var c in Components.Values) { if (c is ItemComponent i && i.Item != null && i.Item.Type != ItemType.Hat && i.Item.Id != "bk:no_lamp") { drops.Add(Items.Create(i.Item.Id)); } } } public override void Destroy() { base.Destroy(); if (!GetComponent().Dead && (Run.LastDepth == -1 || Run.LastDepth == 0)) { var index = GetComponent().Index; StartingWeapons[index] = GetComponent().Item?.Id; StartingItems[index] = GetComponent().Item?.Id; StartingLamps[index] = GetComponent().Item?.Id; } } protected override string GetHurtSfx() { return null; } protected override string GetDeadSfx() { return null; } public T ForceGetComponent() where T : Component { return base.GetComponent(); } public override T GetComponent() { var minIndex = 1024; var pl = this; if (InGameState.Multiplayer && typeof(T) == typeof(ConsumablesComponent) && base.GetComponent().Index != 0) { foreach (var p in Area.Tagged[Tags.Player]) { var i = p.GetComponent().Index; if (i == 0) { return p.GetComponent(); } if (i < minIndex) { minIndex = i; pl = (Player) p; } } } return pl.ForceGetComponent(); } } } ================================================ FILE: BurningKnight/entity/creature/player/PlayerClass.cs ================================================ namespace BurningKnight.entity.creature.player { public enum PlayerClass { Warrior, Mage, Ranger, Any } } ================================================ FILE: BurningKnight/entity/creature/player/PlayerGraphicsComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.pet; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.entity.item.util; using BurningKnight.entity.orbital; using BurningKnight.entity.projectile; using BurningKnight.entity.room.controllable.platform; using BurningKnight.entity.room.controllable.spikes; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using BurningKnight.state; using BurningKnight.util.geometry; using Lens; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.graphics.animation; using Lens.input; using Lens.util; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MonoGame.Extended; namespace BurningKnight.entity.creature.player { public class PlayerGraphicsComponent : AnimationComponent { public static Color AimLineColor = new Color(1f, 0f, 0f, 1f); private Vector2 scale = Vector2.One; private Animation head; private TextureRegion wing; public bool Hidden; public PlayerGraphicsComponent() : base("gobbo", "body") { CustomFlip = true; ShadowOffset = 8; head = Animations.Get("gobbo").CreateAnimation("head"); wing = CommonAse.Items.GetSlice("wing"); } public override void Update(float dt) { base.Update(dt); head.Update(dt); if (!(GetComponent().StateInstance is Player.SleepingState)) { Flipped = Entity.CenterX > GetComponent().Cursor.GamePosition.X; } } private float angle; protected override void CallRender(Vector2 pos, bool shadow) { if (Hidden) { return; } var region = Animation.GetCurrentTexture(); var origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height); var s = scale * Scale; var v = GetComponent().Acceleration; var target = (v.Length() > 0.1f ? 1f : 0f) * 0.25f * (Flipped ? -1 : 1); angle += (target - angle) * Engine.Delta * 3f; var state = GetComponent().StateInstance; var a = 0; // (state is Player.RollState || state is Player.DuckState || state is Player.PostRollState || state is Player.SittingState) ? 0 : angle; if (shadow) { a *= -1; } if (FlippedVerticaly) { pos.Y += region.Source.Height; } if (!shadow) { pos.Y -= GetComponent().Z; } var p = pos + origin; p.Floor(); Graphics.Render(region, p, a, origin, s, Graphics.ParseEffect(Flipped, FlippedVerticaly)); var st = GetComponent().StateInstance; if (st is Player.RollState || st is Player.SleepingState) { return; } var h = GetComponent(); var hat = h.Item; if (hat != null && !h.DoNotRender) { var r = $"{hat.Id}_{(Entity.GetComponent().StateInstance is Player.DuckState ? "b" : "a")}"; var m = shadow ? -4 : 4; region = CommonAse.Items.GetSlice(r); origin = new Vector2(region.Width / 2, region.Height + 4); var pp = new Vector2(Entity.CenterX, m + Entity.Bottom - (shadow ? 0 : GetComponent().Z) + (shadow ? -1 : 1) * (offsets[Math.Min(offsets.Length - 1, Animation.Frame + Animation.StartFrame)] - 15)); pp.Floor(); Graphics.Render(region, pp, a, origin, Scale * new Vector2(s.X, s.Y * (shadow ? -1 : 1)), Flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None); } else { region = head.GetFrame(Animation.Tag, (int) Animation.Frame); if (region == null) { return; } origin = new Vector2(region.Source.Width / 2f, FlippedVerticaly ? 0 : region.Source.Height); var pp = pos + origin; pp.Floor(); Graphics.Render(region, pp, a, origin, s, Graphics.ParseEffect(Flipped, FlippedVerticaly)); } } public void AnimateSwap() { scale.Y = 0.3f; scale.X = 2f; Tween.To(1f, scale.X, x => scale.X = x, 0.2f); Tween.To(1f, scale.Y, x => scale.Y = x, 0.2f); } public override bool HandleEvent(Event e) { if (e is WeaponSwappedEvent) { AnimateSwap(); } else if (e is InteractedEvent) { scale.Y = 0.5f; scale.X = 2f; Tween.To(1f, scale.X, x => scale.X = x, 0.2f); Tween.To(1f, scale.Y, x => scale.Y = x, 0.2f); } return base.HandleEvent(e); } private static sbyte[] offsets = { 13, 12, 12, 12, 12, 0, 0, 0, 0, 11, 11, 11, 12, 12, 12, 11, 11, 11, 10, 10, 11, 11, 10, 10, 11 }; public void SimpleRender(bool shadow) { base.Render(shadow); } private static bool RayShouldCollide(Entity entity) { return 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); } public override void Render(bool shadow) { if (Hidden) { return; } var o = (shadow ? -1 : 1) * (offsets[Math.Min(offsets.Length - 1, Animation.Frame + Animation.StartFrame)] - 11); var s = GetComponent().StateInstance; var w = !(s is Player.RollState || s is Player.SleepingState); var z = GetComponent(); // Render wings if (((Player) Entity).HasFlight) { var a = (float) (Math.Sin(Engine.Time * 5f) * 0.5f) * (shadow ? -1 : 1); if (!shadow) { z.Z = -a * 3 + 4; } a -= (float) Math.PI / 4 * (shadow ? -1 : 1); var wy = shadow ? Entity.Height : 0; wy += GetComponent().Z * (shadow ? 1 : -1); Graphics.Render(wing, Entity.Center + new Vector2(-1, wy), a, new Vector2(8), shadow ? MathUtils.InvertY : Vector2.One); Graphics.Render(wing, Entity.Center + new Vector2(1, wy), -a, new Vector2(8), shadow ? MathUtils.InvertXY : MathUtils.InvertX); } var g = shadow ? 0 : (int) z.Z; if (w) { GetComponent().Render(shadow, o - g); } if (!shadow && InGameState.Multiplayer) { var pos = Entity.Position + Offset; var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(Player.VectorTints[Entity.GetComponent().Index]); foreach (var d in MathUtils.Directions) { CallRender(pos + d, false); } Shaders.End(); } var stopShader = StartShaders(); SimpleRender(shadow); if (stopShader) { Shaders.End(); } if (!shadow) { var aim = GetComponent(); if (aim.ShowLaserLine) { var from = aim.Center; var to = aim.RealAim; var min = 1f; var closest = MathUtils.CreateVector(MathUtils.Angle(to.X - from.X, to.Y - from.Y), Display.UiWidth) + from; Physics.World.RayCast((fixture, point, normal, fraction) => { if (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) { min = fraction; closest = point; } return min; }, from, to); Graphics.Batch.FillRectangle((int) closest.X - 1, (int) closest.Y - 1,3, 3, AimLineColor); Graphics.Batch.DrawLine(from, new Vector2((int) closest.X, (int) closest.Y), AimLineColor, 1); } } if (w) { GetComponent().Render(shadow, o - g); } } } } ================================================ FILE: BurningKnight/entity/creature/player/PlayerInputComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.input; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.events; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity.component; using Lens.entity.component.logic; using Lens.input; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace BurningKnight.entity.creature.player { public class PlayerInputComponent : Component { public static bool EnableUpdates; private const float Speed = 20f; private DialogComponent dialog; private bool wasSitting; public static float TimeIdle; public bool InDialog; public DialogComponent Dialog { get => dialog; set { var old = dialog; dialog = value; if (dialog == null) { if (old != null) { ((InGameState) Engine.Instance.State).ResetFollowing(); // Tween.To(1f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 1f); } } else if (dialog != null) { Camera.Instance.Targets.Clear(); if (old == null) { // Tween.To(2f, Camera.Instance.TextureZoom, x => Camera.Instance.TextureZoom = x, 0.35f); } Camera.Instance.Follow(dialog.Entity, 1f); } } } private float holdTimer; public override void Update(float dt) { base.Update(dt); EnableUpdates = !((Player) Entity).SuperHot; if (GetComponent().Has()) { EnableUpdates = true; return; } if (DialogComponent.Talking != null || Boss.Exploding) { EnableUpdates = true; } var idle = true; var controller = GetComponent(); var data = controller.GamepadData; if (data != null && data.WasAttached && !data.Attached) { data.WasAttached = false; Engine.Instance.State.Paused = true; idle = false; } if (InDialog) { EnableUpdates = true; var dd = dialog?.Dialog; if (dd != null) { var isAnswer = dialog.Current is AnswerDialog; var a = isAnswer ? (AnswerDialog) dialog.Current : null; if (dd.DoneSaying) { if (dialog.Current is ChoiceDialog c) { if (Input.WasPressed(Controls.UiUp, controller, true)) { c.Choice -= 1; if (Settings.UiSfx) { Audio.PlaySfx("ui_moving"); } if (c.Choice < 0) { c.Choice += c.Options.Length; } } if (Input.WasPressed(Controls.UiDown, controller, true)) { c.Choice = (c.Choice + 1) % c.Options.Length; if (Settings.UiSfx) { Audio.PlaySfx("ui_moving"); } } } } if (dd.Saying && !dd.JustStarted) { if ((!isAnswer && (Input.WasPressed(Controls.Interact, controller, true) || Input.WasPressed(Controls.UiSelect, controller, true))) || (isAnswer && !a.Focused)) { if (dd.DoneSaying) { dd.Finish(); Audio.PlaySfx("ui_moving"); } else { dd.Str.FinishTyping(); Audio.PlaySfx("ui_moving"); } } } } Accelerate(Vector2.Zero, dt); /*if (Input.WasPressed(Controls.Pause)) { dd?.Close(); dialog?.OnEnd(); Audio.PlaySfx("ui_moving"); InGameState.SkipPause = true; } else {*/ return; //} } if (Run.Depth == 0 && InGameState.Multiplayer && controller.Index > 0) { if (controller.GamepadData.CurrentState.Buttons.B == ButtonState.Pressed) { if (holdTimer <= 0) { holdTimer = 0; var dialog = GetComponent(); if (dialog.Current == null) { dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice("button_b")); dialog.StartAndClose("remove_player", 2); } } holdTimer += dt; if (holdTimer >= 2f) { AnimationUtil.Poof(Entity.Center); Entity.Done = true; ((Player) Entity).Dead = true; ((InGameState) Engine.Instance.State).ResetFollowing(); Camera.Instance.Shake(10); var count = 0; foreach (var p in Entity.Area.Tagged[Tags.Player]) { if (p != Entity) { count++; } } if (count == 1) { InGameState.Multiplayer = false; } } } else { holdTimer = -1; } } if (Run.Depth > 0 && Run.Type != RunType.Daily && Input.Keyboard.WasPressed(Keys.P)) { Run.StartNew(1, Run.Type); Audio.PlaySfx("ui_moving"); return; } var state = Entity.GetComponent(); var duck = state.StateInstance is Player.DuckState; if (duck) { if (Input.WasReleased(Controls.Duck, controller)) { idle = false; if (wasSitting) { state.Become(); } else { state.Become(); } } } else if (Input.WasPressed(Controls.Duck, controller)) { idle = false; wasSitting = state.StateInstance is Player.SittingState; state.Become(); GlobalSave.Put("control_duck", true); } if (state.StateInstance is Player.PostRollState) { EnableUpdates = true; } if (state.StateInstance is Player.RollState r) { EnableUpdates = true; // Movement tech :) Direction changing if (Input.WasPressed(Controls.Swap, controller)) { idle = false; r.ChangeDirection(); } // Movement tech :) Roll cancelling if (Input.WasPressed(Controls.Roll, controller)) { idle = false; state.Become(); } } else if (!duck) { var acceleration = new Vector2(); if (Input.IsDown(Controls.Up, controller)) { idle = false; acceleration.Y -= 1; } if (Input.IsDown(Controls.Down, controller)) { idle = false; acceleration.Y += 1; } if (Input.IsDown(Controls.Left, controller)) { idle = false; acceleration.X -= 1; } if (Input.IsDown(Controls.Right, controller)) { idle = false; acceleration.X += 1; } if (controller.KeyboardEnabled && Input.Mouse.CheckMiddleButton) { idle = false; var a = Entity.AngleTo(GetComponent().Cursor.GamePosition); acceleration += new Vector2((float) Math.Cos(a), (float) Math.Sin(a)); } if (controller.GamepadEnabled && data != null && data.Attached) { acceleration += data.GetLeftStick(); } if (Input.WasPressed(Controls.Roll, controller) && !Send(new PlayerRolledEvent { Who = (Player) Entity })) { EnableUpdates = true; idle = false; GlobalSave.Put("control_roll", true); state.Become(); } else { if (acceleration.Length() > 0.1f) { EnableUpdates = true; state.Become(); } else if (!(state.StateInstance is Player.SittingState || state.StateInstance is Player.SleepingState)) { state.Become(); } if (acceleration.Length() > 0.1f) { idle = false; acceleration.Normalize(); } Accelerate(acceleration, dt); } } if (BK.StandMode && idle && !Engine.Instance.State.Paused && Run.Depth > 0) { TimeIdle += dt; if (TimeIdle >= 120f) { TimeIdle = 0; Log.Info("The game was idle for 120 seconds, restarting"); GlobalSave.ResetControlKnowldge(); Run.StartNew(0); } } else { TimeIdle = 0; } } public void Accelerate(Vector2 acceleration, float dt) { if (GetComponent().Confused) { acceleration *= -1; } var body = GetComponent(); var i = GetComponent(); var b = GetComponent(); var s = Speed; var sp = 20; if (((Player) Entity).Sliding || !b.IceImmunity && i.Touching[(int) Tile.Ice]) { sp -= 19; s *= 0.25f; } if (i.Touching[(int) Tile.Cobweb]) { s *= 0.6f; } if (i.Touching[(int) Tile.Water] || i.Touching[(int) Tile.Lava]) { s *= 0.9f; } var ac = acceleration * s; var st = (GetComponent().Speed); body.Acceleration = ac * st * 1.5f; body.Velocity -= body.Velocity * dt * sp * 1.5f - body.Acceleration; if (st > 1) { body.Position += ac * (0.5f * dt * (st - 1)); } } public override void Destroy() { base.Destroy(); if (Entity.TryGetComponent(out var body) && body.Body != null) { body.Body.LinearVelocity = Vector2.Zero; body.Acceleration = Vector2.Zero; } EnableUpdates = true; Entity.GetComponent().Become(); } } } ================================================ FILE: BurningKnight/entity/creature/player/WeaponComponent.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.level.entities; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens; using Lens.assets; using Lens.entity; using Lens.util; using Lens.util.file; namespace BurningKnight.entity.creature.player { public class WeaponComponent : ItemComponent { public bool Disabled; protected bool AtBack = true; private bool requestSwap; public void RequestSwap() { requestSwap = true; } public override void PostInit() { base.PostInit(); if (Item != null && Run.Depth < 1) { Item.Done = true; Item = null; } UpdateItem = !AtBack; } protected override void OnItemSet(Item previous) { base.OnItemSet(previous); if (Item != null && Item.Scourged) { Achievements.Unlock("bk:scourged_weapon"); } } public void Render(bool shadow, int offset) { if (!Disabled && Item != null && Item.Renderer != null) { if (!shadow) { var sh = Shaders.Item; Shaders.Begin(sh); sh.Parameters["time"].SetValue(Engine.Time * 0.1f); sh.Parameters["size"].SetValue(ItemGraphicsComponent.FlashSize); } Item.Renderer.Render(AtBack, Engine.Instance.State.Paused, Engine.Delta, shadow, offset); if (!shadow) { Shaders.End(); } } } protected override bool ShouldReplace(Item item) { return (Run.Depth > 0 || !AtBack) && item.Type == ItemType.Weapon && !Disabled; } public override void Update(float dt) { base.Update(dt); if (requestSwap) { Swap(); requestSwap = false; } } public override bool HandleEvent(Event e) { if (e is ItemAddedEvent ev) { if (!Disabled && ev.Component == this) { ev.Old?.Drop(); ev.Item?.Pickup(); if (ev.Item != null && ev.Old == null && AtBack) { if (GlobalSave.IsTrue("control_swap")) { Entity.GetComponent().requestSwap = InGameState.Ready; } else { var dialog = GetComponent(); dialog.Dialog.Str.ClearIcons(); dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Swap, false))); if (GamepadComponent.Current != null && GamepadComponent.Current.Attached) { dialog.Dialog.Str.AddIcon(CommonAse.Ui.GetSlice(Controls.FindSlice(Controls.Swap, true))); } dialog.StartAndClose("control_5", 5); } } } } return base.HandleEvent(e); } protected void Swap() { if (GlobalSave.IsFalse("control_swap")) { GlobalSave.Put("control_swap", true); Entity.GetComponent().Close(); } var component = AtBack ? Entity.GetComponent() : Entity.GetComponent(); if (!Send(new WeaponSwappedEvent { Who = (Player) Entity, Old = Item, Current = component.Item })) { // Swap the items var tmp = component.Item; component.Item = Item; Item = tmp; if (!AtBack) { component.Item?.PutAway(); Item?.TakeOut(); Audio.PlaySfx(Item == null ? "swap" : Item.Data.WeaponType.GetSwapSfx()); } else { Log.Error("Swap is called from not active weapon component"); } } } public override void Load(FileReader stream) { base.Load(stream); Disabled = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(Disabled); } } } ================================================ FILE: BurningKnight/entity/cutscene/controller/CutsceneController.cs ================================================ using System; using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens.entity; using Lens.input; namespace BurningKnight.entity.cutscene.controller { public class CutsceneController : Entity { public DialogComponent Current; public CutsceneState State; public override void Init() { base.Init(); AlwaysActive = true; } public override void Update(float dt) { base.Update(dt); if (Current == null) { return; } var dd = Current.Dialog; var controller = GamepadComponent.Current; if (dd.Saying && !dd.JustStarted) { if (Input.WasPressed(Controls.Interact, controller, true) || Input.WasPressed(Controls.UiSelect, controller, true)) { if (dd.DoneSaying) { dd.Finish(); var c = Current; c.FinishCallback?.Invoke(); c.FinishCallback = null; } else { dd.Str.FinishTyping(); } } } } public void Start(DialogComponent component, string what, Action onEnd) { Current = component; component.Start(what, null, onEnd); } } } ================================================ FILE: BurningKnight/entity/cutscene/controller/GobboCutsceneController.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.cutscene.entity; using BurningKnight.state; using BurningKnight.ui.dialog; using Lens; using Lens.assets; using Lens.graphics.gamerenderer; using Lens.util.camera; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.cutscene.controller { public class GobboCutsceneController : CutsceneController { private BabyGobbo baby; private OldGobbo dad; private Gobbo gobbo; private Vector2 dadStart; public override void PostInit() { base.PostInit(); baby = Area.Find(); dad = Area.Find(); dadStart = dad.BottomCenter; dad.GraphicsComponent.Flipped = true; Timer.Add(() => FirstPart(), 1); PixelPerfectGameRenderer.GameScale = 2; } public override void Destroy() { base.Destroy(); PixelPerfectGameRenderer.GameScale = 1; } private void FirstPart() { var dadDialog = dad.GetComponent(); var sonDialog = baby.GetComponent(); dadDialog.Dialog.AlwaysShowArrow = true; sonDialog.Dialog.AlwaysShowArrow = true; Start(dadDialog, "dad_0", () => { dadDialog.Close(); Start(sonDialog, "son_0", () => { sonDialog.Close(); Start(dadDialog, "dad_1", () => { dadDialog.Close(); dad.GraphicsComponent.Flipped = false; dad.GetComponent().Animation.Tag = "run"; dad.RunAway = true; Timer.Add(() => { State.Say(Locale.Get("20_years_later"), () => { dad.Done = true; gobbo = new Gobbo(); Area.Add(gobbo); gobbo.BottomCenter = dadStart; gobbo.GraphicsComponent.Flipped = true; Timer.Add(() => { SecondPart(); }, 1f); }); }, 2f); }); }); }); } private void SecondPart() { var gobboDialog = gobbo.GetComponent(); var sonDialog = baby.GetComponent(); gobboDialog.Dialog.AlwaysShowArrow = true; Start(gobboDialog, "gobbo_0", () => { gobboDialog.Close(); Start(sonDialog, "son_0", () => { sonDialog.Close(); Start(gobboDialog, "gobbo_1", () => { gobboDialog.Close(); gobbo.GraphicsComponent.Flipped = false; gobbo.GetComponent().Animation.Tag = "run"; gobbo.RunAway = true; Timer.Add(() => { State.Transition(() => { Run.Depth = -2; }); }, 2f); }); }); }); } } } ================================================ FILE: BurningKnight/entity/cutscene/entity/BabyGobbo.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; namespace BurningKnight.entity.cutscene.entity { public class BabyGobbo : CutsceneEntity { public override void AddComponents() { base.AddComponents(); Width = 8; Height = 8; AddComponent(new AnimationComponent("baby_gobbo")); GetComponent().Dialog.Voice = 7; } } } ================================================ FILE: BurningKnight/entity/cutscene/entity/CutsceneEntity.cs ================================================ using BurningKnight.entity.component; using BurningKnight.save; using BurningKnight.ui.dialog; using BurningKnight.ui.editor; using Lens.entity; using Lens.entity.component.logic; namespace BurningKnight.entity.cutscene.entity { public class CutsceneEntity : SaveableEntity, PlaceableEntity { public override void AddComponents() { base.AddComponents(); AddComponent(new AudioEmitterComponent()); AddComponent(new DialogComponent()); AddComponent(new StateComponent()); AddComponent(new ShadowComponent()); } } } ================================================ FILE: BurningKnight/entity/cutscene/entity/Gobbo.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.entity.cutscene.entity { public class Gobbo : CutsceneEntity { public bool RunAway; public override void AddComponents() { base.AddComponents(); Width = 11; Height = 14; AddComponent(new AnimationComponent("new_gobbo")); } public override void Update(float dt) { base.Update(dt); if (RunAway) { X += dt * 60; } } } } ================================================ FILE: BurningKnight/entity/cutscene/entity/Heinur.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.bk; using BurningKnight.util; using Lens; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework; namespace BurningKnight.entity.cutscene.entity { public class Heinur : CutsceneEntity { public bool Attract; public Action Callback; public override void AddComponents() { base.AddComponents(); Width = 42; Height = 42; AddComponent(new BkGraphicsComponent("heinur")); AddComponent(new SensorBodyComponent(0, 0, 42, 42)); GetComponent().Body.LinearDamping = 2; } public override void Update(float dt) { base.Update(dt); if (!Attract) { return; } foreach (var p in Area.Tagged[Tags.Player]) { var dx = p.DxTo(this); var dy = p.DyTo(this); var d = MathUtils.Distance(dx, dy); if (d <= 24) { AnimationUtil.Explosion(Center); Done = true; Callback(); Camera.Instance.Shake(20); Engine.Instance.Flash = 2; var ba = GetComponent(); ba.Velocity = ba.Knockback = Vector2.Zero; var bb = p.GetComponent(); bb.Velocity = bb.Knockback = Vector2.Zero; return; } var a = MathUtils.Angle(dx, dy); var force = 360 * dt; if (d <= 64) { force *= 2; } p.GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); a += (float) Math.PI; GetComponent().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } } } ================================================ FILE: BurningKnight/entity/cutscene/entity/OldGobbo.cs ================================================ using BurningKnight.entity.component; namespace BurningKnight.entity.cutscene.entity { public class OldGobbo : CutsceneEntity { public bool RunAway; public override void AddComponents() { base.AddComponents(); Width = 11; Height = 14; AddComponent(new AnimationComponent("old_gobbo")); } public override void Update(float dt) { base.Update(dt); if (RunAway) { X += dt * 60; } } } } ================================================ FILE: BurningKnight/entity/door/BossDoor.cs ================================================ using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class BossDoor : CustomDoor { public override void AddComponents() { OpenByDefault = false; base.AddComponents(); } protected override Rectangle GetHitbox() { return new Rectangle(0, 17, (int) Width, 7); } protected override void SetSize() { Width = 24; Height = 30; } protected override Vector2 GetLockOffset() { return new Vector2(0, 9); } public override Vector2 GetOffset() { return new Vector2(0, 0); } protected override string GetBar() { return "boss_door"; } protected override string GetAnimation() { return "boss_door"; } protected override Lock CreateLock() { return new BossLock(); } } } ================================================ FILE: BurningKnight/entity/door/BossLock.cs ================================================ using BurningKnight.entity.creature.bk; using BurningKnight.level.entities.decor; using BurningKnight.level.rooms; using Lens.entity; using Lens.entity.component.logic; using Lens.util; namespace BurningKnight.entity.door { public class BossLock : IronLock { private bool triggered; public override void Init() { base.Init(); Subscribe(); Subscribe(); Subscribe(); } public override bool HandleEvent(Event e) { if (e is SpawnTrigger.TriggeredEvent) { triggered = true; } else if (e is creature.bk.BurningKnight.DefeatedEvent || e is BurningStatue.BrokenEvent) { triggered = false; } return base.HandleEvent(e); } protected override void UpdateState() { var shouldLock = triggered; if (!shouldLock) { foreach (var r in rooms) { if (r.Type != RoomType.Connection && r.Tagged[Tags.Player].Count > 0 && r.Tagged[Tags.MustBeKilled].Count > 0) { shouldLock = true; break; } } } if (shouldLock && !IsLocked) { SetLocked(true, null); GetComponent().Become(); } else if (!shouldLock && IsLocked) { SetLocked(false, null); GetComponent().Become(); } } } } ================================================ FILE: BurningKnight/entity/door/CageDoor.cs ================================================ namespace BurningKnight.entity.door { public class CageDoor : LockableDoor { protected override Lock CreateLock() { return new CageLock(); } } } ================================================ FILE: BurningKnight/entity/door/CageLock.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.save; using Lens.assets; using Lens.entity; using Lens.graphics.animation; using Steamworks.Data; namespace BurningKnight.entity.door { public class CageLock : Lock { private static ColorSet palette = ColorSets.New(new[] { Palette.Default[9], Palette.Default[10], Palette.Default[11] }, new[] { Palette.Default[8], Palette.Default[9], Palette.Default[10] }); protected override ColorSet GetLockPalette() { return palette; } private void SaveNpc() { var rooms = ((Door) GetComponent().Owner).Rooms; foreach (var r in rooms) { if (r == null) { continue; } foreach (var n in r.Tagged[Tags.Npc]) { if (n is ShopNpc sn) { sn.Save(); } } } Audio.PlaySfx("item_cage_key_used"); CheckProgress(); } public static void CheckProgress() { var progress = 0; var total = 0; foreach (var id in ShopNpc.AllNpc) { if (id == ShopNpc.TrashGoblin) { continue; } total++; if (GlobalSave.IsTrue(id)) { progress++; } } Achievements.SetProgress("bk:npc_party2", progress, total); } protected override bool TryToConsumeKey(Entity entity) { if (entity.TryGetComponent(out var a) && a.Item != null && a.Item.Id == "bk:cage_key") { var i = a.Item; a.Set(null); i.Done = true; a.RequestSwap(); SaveNpc(); return true; } if (entity.TryGetComponent(out var w) && w.Item != null && w.Item.Id == "bk:cage_key") { var i = w.Item; w.Set(null); i.Done = true; SaveNpc(); return true; } return false; } } } ================================================ FILE: BurningKnight/entity/door/ChallengeDoor.cs ================================================ using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class ChallengeDoor : CustomDoor { protected override void SetSize() { Width = 40; Height = 33; } protected override Rectangle GetHitbox() { return new Rectangle(0, 19, (int) Width, 7); } protected override Vector2 GetLockOffset() { return new Vector2(0, 9); } public override Vector2 GetOffset() { return new Vector2(0, 0); } protected override Lock CreateLock() { return new IronLock(); } protected override string GetBar() { return "challenge_door"; } protected override string GetAnimation() { return "challenge_door"; } } } ================================================ FILE: BurningKnight/entity/door/ConditionDoor.cs ================================================ using System; using BurningKnight.assets.achievements; using BurningKnight.entity.creature.npc; using BurningKnight.save; using ImGuiNET; using Lens; using Lens.entity; using Lens.util.file; namespace BurningKnight.entity.door { public class ConditionDoor : LockableDoor { private static string[] conditions = { "Played Once", "Saved Hat Trader", "Saved Weapon Trader", "Saved Artifact Trader", "Saved Active Trader", "Save Boss Rush Guy", "Completed 10 Challenges", "Completed 20 Challenges", "Completed 30 Challenges", "Achievement Branch A Complete", "Achievement Branch B Complete", "Achievement Branch C Complete", "Achievement Branch D Complete" }; private bool shouldLock; private bool cached; private bool lockInDemo; private int condition; private bool DecideState() { if (lockInDemo && BK.Demo) { return false; } switch (condition) { case 0: return GlobalSave.IsTrue("played_once"); case 1: return GlobalSave.IsTrue(ShopNpc.HatTrader); case 2: return GlobalSave.IsTrue(ShopNpc.WeaponTrader); case 3: return GlobalSave.IsTrue(ShopNpc.AccessoryTrader); case 4: return GlobalSave.IsTrue(ShopNpc.ActiveTrader); case 5: return GlobalSave.IsTrue(ShopNpc.Mike); case 6: return GlobalSave.GetInt("challenges_completed") >= 10; case 7: return GlobalSave.GetInt("challenges_completed") >= 20; case 8: return GlobalSave.GetInt("challenges_completed") >= 30; case 9: return Achievements.IsGroupComplete("a"); case 10: return Achievements.IsGroupComplete("b"); case 11: return Achievements.IsGroupComplete("c"); case 12: return Achievements.IsGroupComplete("d"); } return false; } public bool ShouldLock() { if (!cached) { shouldLock = !DecideState(); cached = true; } return shouldLock; } public override void PostInit() { SkipLock = false; Replaced = false; base.PostInit(); Subscribe(); if (!Vertical) { // CenterX = (float) (Math.Round(CenterX / 16) * 16) + 8; } } protected override Lock CreateLock() { //Replaced = false; return /*Engine.EditingLevel ? null : */new ConditionLock(); } public override void RenderImDebug() { base.RenderImDebug(); ImGui.Checkbox("Lock in demo", ref lockInDemo); ImGui.Combo("Condition", ref condition, conditions, conditions.Length); } public override void Load(FileReader stream) { base.Load(stream); condition = stream.ReadByte(); lockInDemo = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte((byte) condition); stream.WriteBoolean(lockInDemo); } public override bool HandleEvent(Event e) { if (e is Achievement.UnlockedEvent) { cached = false; ShouldLock(); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/door/ConditionLock.cs ================================================ using BurningKnight.entity.component; using Lens.entity.component.logic; namespace BurningKnight.entity.door { public class ConditionLock : Lock { private bool first; public ConditionLock() { LockedByDefault = false; AlwaysActive = true; } protected override bool Disposable() { return false; } public override bool Interactable() { return false; } public override void Update(float dt) { base.Update(dt); UpdateState(); } protected virtual void UpdateState() { var shouldLock = ((ConditionDoor) GetComponent().Owner).ShouldLock(); if (shouldLock && !IsLocked) { SetLocked(true, null); if (first) { GetComponent().Become(); } else { GetComponent().Become(); } } else if (!shouldLock && IsLocked) { SetLocked(false, null); if (first) { GetComponent().Become(); } else { GetComponent().Become(); } } first = false; } } } ================================================ FILE: BurningKnight/entity/door/CustomDoor.cs ================================================ using BurningKnight.assets; using Lens.graphics; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class CustomDoor : LockableDoor { private TextureRegion bar; private TextureRegion pad; public CustomDoor() { OpenByDefault = true; } public override void PostInit() { base.PostInit(); var p = GetPad(); if (p != null) { pad = CommonAse.Props.GetSlice(p); Area.Add(new RenderTrigger(this, () => { Graphics.Render(pad, Position); }, -1)); } var b = GetBar(); if (b == null) { return; } bar = CommonAse.Props.GetSlice(b); Area.Add(new RenderTrigger(this, () => RenderFrame(false), Layers.FlyingMob)); } protected override float GetShadowOffset() { return 0; } protected virtual string GetBar() { return null; } protected virtual string GetPad() { return null; } protected override void RenderShadow() { base.RenderShadow(); if (bar != null) { RenderFrame(true); } } private void RenderFrame(bool shadow) { Graphics.Render(bar, shadow ? new Vector2(X, Bottom + Height) : Position, 0, Vector2.Zero, shadow ? MathUtils.InvertY : MathUtils.Normal); } } } ================================================ FILE: BurningKnight/entity/door/Door.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.particle; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.level.rooms.granny; using BurningKnight.level.rooms.oldman; using BurningKnight.level.rooms.shop; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; using MonoGame.Extended; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.door { public class Door : SaveableEntity, PlaceableEntity { private const float CloseTimer = 1f; public bool Vertical; protected bool OpenByDefault; public bool Open { get { var component = GetComponent(); return component.StateInstance is OpenState || component.StateInstance is OpeningState; } } protected List Colliding = new List(); private float lastCollisionTimer; private bool lit; internal Room[] Rooms; public virtual Vector2 GetOffset() { return new Vector2(0, Vertical ? -7 : -7); } public override void AddComponents() { base.AddComponents(); Depth = Layers.Door; AlwaysActive = true; AddComponent(new AudioEmitterComponent()); AddComponent(new StateComponent()); AddComponent(new ShadowComponent(RenderShadow)); // AddComponent(new ExplodableComponent()); if (OpenByDefault) { GetComponent().Become(); } else { GetComponent().Become(); } AddTag(Tags.Door); } protected virtual float GetShadowOffset() { return 8; } protected virtual void SetSize() { Width = Vertical ? 8 : 20; Height = Vertical ? 19 : 11; } public override void PostInit() { base.PostInit(); SetSize(); AddComponent(new AnimationComponent(GetAnimation()) { ShadowOffset = GetShadowOffset() }); AddComponent(new RectBodyComponent(-2, -2, Width + 4, Height + 4, BodyType.Static, true)); } protected virtual void RenderShadow() { GraphicsComponent.Render(true); } public override void Load(FileReader stream) { base.Load(stream); Vertical = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(Vertical); } protected virtual string GetAnimation() { return Vertical ? "side_door" : "regular_door"; } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent start) { if (start.Entity is Player) { Colliding.Add(start.Entity); if (Colliding.Count >= 1 && CanOpen()) { var state = GetComponent(); if (!(state.StateInstance is OpeningState || state.StateInstance is OpenState)) { HandleEvent(new DoorOpenedEvent { Who = this }); state.Become(); } } } } else if (e is CollisionEndedEvent end) { if (end.Entity is Player) { Colliding.Remove(end.Entity); if (Colliding.Count == 0 && !OpenByDefault) { lastCollisionTimer = CloseTimer; } } } return base.HandleEvent(e); } protected virtual bool CanOpen() { return true; } public override void RenderDebug() { var pad = 4; Graphics.Batch.DrawRectangle(new RectangleF((int) (X + pad), (int) Y, (int) (Width - pad * 2), (int) Height), Color.Aqua, 1); } private bool added; public override void Update(float dt) { base.Update(dt); if (!added) { added = true; var x = (int) Math.Floor(CenterX / 16); var y = (int) Math.Floor(Bottom / 16); if (Run.Level.IsInside(x, y)) { Run.Level.Passable[Run.Level.ToIndex(x, y)] = false; } } var state = GetComponent(); if (state.StateInstance is OpenState && Colliding.Count == 0 && !OpenByDefault) { lastCollisionTimer -= dt; if (lastCollisionTimer <= 0) { HandleEvent(new DoorClosedEvent { Who = this }); state.Become(); } } if (Rooms == null) { Rooms = new Room[2]; var i = 0; var pad = 4; var rc = new Rectangle((int) (X + pad), (int) Y, (int) (Width - pad * 2), (int) Height); foreach (var room in Area.Tagged[Tags.Room]) { if (room.Overlaps(rc)) { var r = (Room) room; Rooms[i] = r; r.Doors.Add(this); i++; if (i == 2) { break; } } } } if (Rooms != null && !lit) { var found = false; foreach (var rm in Rooms) { if (rm != null && rm.Tagged[Tags.Player].Count > 0) { found = true; break; } } if (found) { foreach (var rm in Rooms) { if (rm != null && (rm.Type == RoomType.OldMan || rm.Type == RoomType.Granny)) { return; } } lit = true; ExplosionMaker.LightUp(CenterX, CenterY); } } } public class ClosedState : EntityState { } public class ClosingState : EntityState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().EmitRandomizedPrefixed("level_door_close", 2); Self.GetComponent().Become(); } } } public class OpenState : EntityState { } public class OpeningState : EntityState { public override void Init() { base.Init(); Self.GetComponent().EmitRandomizedPrefixed("level_door_open", 5); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Self.GetComponent().Become(); } } } } } ================================================ FILE: BurningKnight/entity/door/GoldLock.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.assets; using Lens.entity; using Lens.graphics.animation; namespace BurningKnight.entity.door { public class GoldLock : Lock { private static ColorSet palette = ColorSets.New(new[] { Palette.Default[9], Palette.Default[10], Palette.Default[11] }, new[] { Palette.Default[31], Palette.Default[30], Palette.Default[29] }); protected override ColorSet GetLockPalette() { return palette; } protected override bool CanInteract(Entity entity) { return entity.TryGetComponent(out var component) && component.Keys > 0; } protected override bool TryToConsumeKey(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.Keys > 0) { component.Keys--; Audio.PlaySfx("item_key"); return true; } return false; } } } ================================================ FILE: BurningKnight/entity/door/HallDoor.cs ================================================ namespace BurningKnight.entity.door { public class HallDoor : LockableDoor { protected override Lock CreateLock() { return new HallLock(); } } } ================================================ FILE: BurningKnight/entity/door/HallLock.cs ================================================ using BurningKnight.entity.creature.npc; using Lens.entity.component.logic; namespace BurningKnight.entity.door { public class HallLock : IronLock { protected override void UpdateState() { var found = false; foreach (var n in Area.Tagged[Tags.Npc]) { if (n is ShopNpc sn && !sn.Hidden) { found = true; break; } } if (!found && !IsLocked) { SetLocked(true, null); GetComponent().Become(); } else if (found && IsLocked) { SetLocked(false, null); GetComponent().Become(); } } } } ================================================ FILE: BurningKnight/entity/door/HeadDoor.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.state; using BurningKnight.util; using Lens.assets; using Lens.entity; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.door { public class HeadDoor : CustomDoor { private Trigger trigger; private float last; protected override void SetSize() { Width = 30; Height = 25; } protected override Rectangle GetHitbox() { return new Rectangle(0, 5 + 8, (int) Width, 7); } protected override Vector2 GetLockOffset() { return new Vector2(0, 7); } public override Vector2 GetOffset() { return new Vector2(0, 8); } protected override Lock CreateLock() { return new IronLock(); } protected override string GetBar() { return "head_door"; } protected override string GetAnimation() { return "head_door"; } public override void PostInit() { base.PostInit(); Area.Add(trigger = new Trigger { Callback = (e) => { if (e is Player p) { if (p.GetComponent().Velocity.Y >= 0 || p.Y > trigger.Y + 4) { return; } // fixme: played multiple time if (Run.Scourge > 0 || p.GetComponent().Coins >= 30) { if (last <= 0) { Audio.PlaySfx("level_door_head_success"); last = 0.3f; } return; } if (last <= 0) { Audio.PlaySfx("level_door_head_fail"); last = 0.3f; } p.GetComponent().ModifyHealth(-1, this); AnimationUtil.Poof(p.Center); p.TopCenter = BottomCenter + new Vector2(0, 2); AnimationUtil.Poof(p.Center); var b = p.GetComponent(); b.Acceleration = Vector2.Zero; b.Velocity = Vector2.Zero; p.GetComponent().Add(new FrozenBuff() { Duration = 1f }); } } }); trigger.TopCenter = TopCenter; } public override void Update(float dt) { base.Update(dt); if (last > 0) { last -= dt; } trigger.TopCenter = TopCenter; } private class Trigger : Entity { public Action Callback; public override void AddComponents() { base.AddComponents(); AddComponent(new RectBodyComponent(0, 0, 16, 2, BodyType.Static, true)); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { Callback(cse.Entity); } return base.HandleEvent(e); } } } } ================================================ FILE: BurningKnight/entity/door/IronLock.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.item.stand; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.state; using Lens.assets; using Lens.entity.component.logic; namespace BurningKnight.entity.door { public class IronLock : Lock { protected List rooms = new List(); private bool first = true; public IronLock() { LockedByDefault = false; } public void CalcRooms() { rooms.Clear(); foreach (var room in Area.Tagged[Tags.Room]) { if (room.Overlaps(this)) { rooms.Add((Room) room); } } } protected override bool Disposable() { return false; } public override bool Interactable() { return false; } private bool updatedRooms; public override void Update(float dt) { base.Update(dt); if (!updatedRooms || rooms.Count == 0) { updatedRooms = true; CalcRooms(); } UpdateState(); } protected virtual void UpdateState() { var shouldLock = false; // Run.Depth >= Run.ContentEndDepth; if (!shouldLock) { foreach (var r in rooms) { if (r.Tagged[Tags.Player].Count > 0) { if (r.Type != RoomType.Connection && r.Tagged[Tags.MustBeKilled].Count > 0) { var found = false; foreach (var m in r.Tagged[Tags.MustBeKilled]) { if (!m.Done && !m.GetComponent().Has() && m.GetComponent().Health > 0.3f && (!(m is Mob mb) || mb.Target != null) && r.Contains(m.Center)) { found = true; break; } } if (found) { foreach (var p in r.Tagged[Tags.Player]) { if (!p.GetComponent().Has()) { shouldLock = true; break; } } } } if (r.Type == RoomType.Trap) { if (r.Inputs.Count > 0) { foreach (var c in r.Inputs) { if (c.On == c.DefaultState) { shouldLock = true; break; } } break; } } else if (r.Type == RoomType.Scourged) { foreach (var i in r.Tagged[Tags.Item]) { if (i is ScourgedStand st && st.Item != null) { shouldLock = true; break; } } } } } } if (shouldLock && !IsLocked) { SetLocked(true, null); if (first) { GetComponent().Become(); } else { GetComponent().Become(); } } else if (!shouldLock && IsLocked) { SetLocked(false, null); if (first) { GetComponent().Become(); } else { GetComponent().Become(); } } first = false; } } } ================================================ FILE: BurningKnight/entity/door/ItemDoor.cs ================================================ namespace BurningKnight.entity.door { public class ItemDoor : LockableDoor { protected override Lock CreateLock() { return new ItemLock(); } } } ================================================ FILE: BurningKnight/entity/door/ItemLock.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.state; using Lens.entity.component.logic; namespace BurningKnight.entity.door { public class ItemLock : Lock { protected List rooms = new List(); public void CalcRooms() { rooms.Clear(); foreach (var room in Area.Tagged[Tags.Room]) { if (room.Overlaps(this)) { rooms.Add((Room) room); } } } protected override bool Disposable() { return false; } public override bool Interactable() { return false; } private bool updatedRooms; public override void Update(float dt) { base.Update(dt); if (!updatedRooms || rooms.Count == 0) { updatedRooms = true; CalcRooms(); } UpdateState(); } protected virtual void UpdateState() { var shouldLock = false; foreach (var r in rooms) { if (r.Tagged[Tags.Player].Count == 0) { continue; } foreach (var item in r.Tagged[Tags.Item]) { if ((item is ItemStand ist && ist.Item != null)) { shouldLock = true; break; } } } if (shouldLock && !IsLocked) { SetLocked(true, null); GetComponent().Become(); } else if (!shouldLock && IsLocked) { SetLocked(false, null); GetComponent().Become(); } } } } ================================================ FILE: BurningKnight/entity/door/LevelDoor.cs ================================================ using BurningKnight.entity.component; using Lens.util.file; namespace BurningKnight.entity.door { public class LevelDoor : LockableDoor { protected override Lock CreateLock() { return new LevelLock(); } public override void Load(FileReader stream) { base.Load(stream); SkipLock = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(!TryGetComponent(out var c) || !c.Lock.IsLocked); } } } ================================================ FILE: BurningKnight/entity/door/LevelLock.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using Lens.entity; using Lens.graphics.animation; namespace BurningKnight.entity.door { public class LevelLock : Lock { private static ColorSet palette = ColorSets.New(new[] { Palette.Default[9], Palette.Default[10], Palette.Default[11] }, new[] { Palette.Default[31], Palette.Default[30], Palette.Default[29] }); protected override ColorSet GetLockPalette() { return palette; } public override void AddComponents() { Width = 20; Height = 40; base.AddComponents(); AddComponent(new RoomComponent()); } protected override AnimationComponent CreateGraphicsComponent() { return new AnimationComponent("level_lock", GetLockPalette()); } public override bool Interactable() { return false; } protected override bool TryToConsumeKey(Entity entity) { return false; } } } ================================================ FILE: BurningKnight/entity/door/Lock.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics.animation; using Lens.util.camera; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.door { public class Lock : Entity { private bool locked; protected bool LockedByDefault = true; public Entity Owner; public bool IsLocked => locked; public void SetLocked(bool value, Entity entity) { if (value == locked || Done) { return; } locked = value; if (!locked) { HandleEvent(new LockOpenedEvent { Lock = this, Who = entity }); if (Owner is Door) { Owner.GetComponent().Become(); } GetComponent().Become(); GetComponent().EmitRandomized("unlock"); } else { HandleEvent(new LockClosedEvent { Lock = this, Who = entity }); } } public bool Move; private float t; private float shake; public Lock() { Width = 10; Height = 20; locked = true; } protected virtual bool Interact(Entity entity) { if (TryToConsumeKey(entity)) { SetLocked(false, entity); return true; } Camera.Instance.Shake(3); shake = 1f; return false; } protected virtual bool TryToConsumeKey(Entity entity) { return false; } protected virtual bool CanInteract(Entity entity) { return true; } public override void AddComponents() { base.AddComponents(); if (Interactable()) { AddComponent(new InteractableComponent(Interact) { CanInteract = CanInteract }); } AddComponent(new AudioEmitterComponent { DestroySounds = false }); var state = new StateComponent(); AddComponent(state); if (LockedByDefault) { state.Become(); locked = true; } else { state.Become(); locked = false; } AddTag(Tags.Lock); } protected virtual AnimationComponent CreateGraphicsComponent() { return new AnimationComponent("lock", GetLockPalette()); } public override void Update(float dt) { base.Update(dt); if (GraphicsComponent == null) { // Set here, because of the ui thread AddComponent(CreateGraphicsComponent()); } if (!IsLocked) { return; } var offset = GetComponent().Offset; if (Move) { t += dt; offset.Y = (float) (Math.Cos(t * 3f) * 1.5f); } if (shake > 0) { shake -= dt; } else { shake = 0; } offset.X = (float) (Math.Cos(shake * 20f) * shake * 2.5f); GetComponent().Offset = offset; } public override void Render() { } public void RealRender() { if (/*!Done && */!(GetComponent().StateInstance is OpenState)) { base.Render(); } } protected virtual bool Disposable() { return true; } protected virtual ColorSet GetLockPalette() { return null; } public virtual bool Interactable() { return true; } #region Lock States public class IdleState : EntityState { } public class OpenState : EntityState { } public class OpeningState : EntityState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { if (((Lock) Self).Disposable()) { Self.Done = true; } else { Self.Done = false; Become(); } } } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } } public class ClosingState : EntityState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Update(float dt) { base.Update(dt); if (Self.GetComponent().Animation.Paused) { Become(); } } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } } #endregion } } ================================================ FILE: BurningKnight/entity/door/LockableDoor.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.physics; using Lens.entity; using Lens.entity.component.logic; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.door { public class LockableDoor : Door, CollisionFilterEntity { protected bool SkipLock; protected bool Replaced; protected virtual Rectangle GetHitbox() { return new Rectangle(0, Vertical ? 0 : 5, (int) Width, Vertical ? (int) Height + 10 : 7); } protected virtual Vector2 GetLockOffset() { return Vertical ? new Vector2(0, 1) : new Vector2(0, 2); } public override void PostInit() { base.PostInit(); if (!SkipLock) { AddLock(Replaced ? new IronLock() : CreateLock()); } } public override void Update(float dt) { base.Update(dt); if (SkipLock) { return; } var state = GetComponent(); if (TryGetComponent(out var l)) { if (l.Lock == null || l.Lock.Done) { ReplaceLock(); } else if ((state.StateInstance is OpenState || state.StateInstance is OpeningState) && l.Lock.IsLocked) { state.Become(); } else if (OpenByDefault && (state.StateInstance is ClosedState || state.StateInstance is ClosingState) && !l.Lock.IsLocked) { state.Become(); } } else { ReplaceLock(); } } private void ReplaceLock() { Replaced = true; AddLock(new IronLock()); } private void AddLock(Lock l) { if (l == null) { return; } if (HasComponent()) { RemoveComponent(); } AddComponent(new LockComponent(this, l, GetLockOffset())); if (!HasComponent()) { var box = GetHitbox(); if (this is CustomDoor && !Vertical) { box.Y += 8; } AddComponent(new DoorBodyComponent(box.X, box.Y, box.Width, box.Height, BodyType.Static, true)); } } public override void Load(FileReader stream) { base.Load(stream); SkipLock = stream.ReadBoolean(); Replaced = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(SkipLock || !TryGetComponent(out var l) || l.Lock == null || l.Lock.Done); stream.WriteBoolean(Replaced); } protected virtual Lock CreateLock() { return new IronLock(); } public bool ShouldCollide(Entity entity) { return !(entity is Door); } protected override bool CanOpen() { return !TryGetComponent(out var c) || !c.Lock.IsLocked; } public override void Render() { base.Render(); if (!SkipLock && TryGetComponent(out var l)) { l.Lock?.RealRender(); } } } } ================================================ FILE: BurningKnight/entity/door/LockedDoor.cs ================================================ namespace BurningKnight.entity.door { public class LockedDoor : LockableDoor { protected override Lock CreateLock() { return new GoldLock(); } } } ================================================ FILE: BurningKnight/entity/door/PayedDoor.cs ================================================ using BurningKnight.entity.component; using BurningKnight.ui.dialog; using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class PayedDoor : CustomDoor { public override void AddComponents() { OpenByDefault = false; base.AddComponents(); AddComponent(new DialogComponent { AnimateTyping = false }); AddComponent(new CloseDialogComponent("payed_door_0")); } protected override Rectangle GetHitbox() { return new Rectangle(0, 5 + 4, (int) Width, 7); } protected override Vector2 GetLockOffset() { return new Vector2(0, 3); } protected override void SetSize() { Width = 24; Height = 23; } public override Vector2 GetOffset() { return new Vector2(0, 0); } protected override Lock CreateLock() { return new IronLock(); } protected override string GetBar() { return "payed_door"; } protected override string GetAnimation() { return "payed_door"; } } } ================================================ FILE: BurningKnight/entity/door/RedDoor.cs ================================================ namespace BurningKnight.entity.door { public class RedDoor : SpecialDoor { protected override Lock CreateLock() { return new RedLock(); } } } ================================================ FILE: BurningKnight/entity/door/RedLock.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.creature.player; using Lens.assets; using Lens.entity; using Lens.graphics.animation; namespace BurningKnight.entity.door { public class RedLock : Lock { private static ColorSet palette = ColorSets.New(new[] { Palette.Default[9], Palette.Default[10], Palette.Default[11] }, new[] { Palette.Default[59], Palette.Default[60], Palette.Default[62] }); protected override ColorSet GetLockPalette() { return palette; } protected override bool CanInteract(Entity entity) { return entity.GetComponent().Item?.Id == "bk:treasure_key" || entity.GetComponent().Item?.Id == "bk:treasure_key"; } protected override bool TryToConsumeKey(Entity entity) { if (entity.TryGetComponent(out var a) && a.Item != null && a.Item.Id == "bk:treasure_key") { var i = a.Item; a.Set(null); i.Done = true; a.RequestSwap(); Audio.PlaySfx("item_key"); return true; } if (entity.TryGetComponent(out var w) && w.Item != null && w.Item.Id == "bk:treasure_key") { var i = w.Item; w.Set(null); i.Done = true; Audio.PlaySfx("item_key"); return true; } return false; } } } ================================================ FILE: BurningKnight/entity/door/ScourgedDoor.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.rooms; using BurningKnight.state; using Lens.entity; using Lens.util.file; using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class ScourgedDoor : CustomDoor { private List Colliding = new List(); private bool scourged; public override void PostInit() { base.PostInit(); Subscribe(); } private bool Scourge(ItemComponent component) { if (component.Item != null && !component.Item.Scourged) { Run.AddScourge(); component.Item.Scourged = true; return true; } return false; } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce && rce.Who is Player p && Colliding.Contains(p)) { if (scourged || (rce.Old != null && rce.Old.Type == RoomType.Scourged)) { return base.HandleEvent(e); } var a = Scourge(p.GetComponent()); var b = Scourge(p.GetComponent()); if (!a && !b) { Run.AddScourge(); } scourged = true; } else if (e is CollisionStartedEvent cse) { if (cse.Entity is Player p2) { Colliding.Add(p2); } } else if (e is CollisionEndedEvent cee) { if (cee.Entity is Player p2) { Colliding.Remove(p2); } } return base.HandleEvent(e); } protected override Rectangle GetHitbox() { return new Rectangle(0, 5 + 4, (int) Width, 7); } protected override Vector2 GetLockOffset() { return new Vector2(0, 3); } protected override void SetSize() { Width = 24; Height = 23; } public override Vector2 GetOffset() { return new Vector2(0, 0); } protected override Lock CreateLock() { return new IronLock(); } protected override string GetBar() { return "scourged_door"; } protected override string GetAnimation() { return "scourged_door"; } public override void Load(FileReader stream) { base.Load(stream); scourged = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(scourged); } } } ================================================ FILE: BurningKnight/entity/door/ShopDoor.cs ================================================ using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class ShopDoor : CustomDoor { protected override void SetSize() { Width = Vertical ? 14 : 24; Height = Vertical ? 17 : 31; OpenByDefault = !Vertical; } public override Vector2 GetOffset() { return new Vector2(0, Vertical ? -6 : 0); } protected override Vector2 GetLockOffset() { return Vertical ? new Vector2(0, -1) : new Vector2(0, 9); } protected override Rectangle GetHitbox() { return Vertical ? new Rectangle(0, 0, (int) Width, (int) Height + 5) : new Rectangle(0, 14, (int) Width, 16); } protected override Lock CreateLock() { return new GoldLock(); } protected override string GetBar() { return Vertical ? null : "shop_door"; } protected override string GetAnimation() { return Vertical ? "vertical_shop_door" : "shop_door"; } protected override string GetPad() { return null; } } } ================================================ FILE: BurningKnight/entity/door/SpecialDoor.cs ================================================ namespace BurningKnight.entity.door { public class SpecialDoor : LockableDoor { protected override Lock CreateLock() { return new GoldLock(); } } } ================================================ FILE: BurningKnight/entity/door/SpikedDoor.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using Lens.entity; using Lens.entity.component.logic; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class SpikedDoor : CustomDoor { protected override Rectangle GetHitbox() { return new Rectangle(0, 5 + 4, (int) Width, 7); } protected List Colliding = new List(); public override void PostInit() { base.PostInit(); Subscribe(); } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce && rce.Who is Player p && Colliding.Contains(p)) { var rolling = p.GetComponent().StateInstance is Player.RollState; var h = p.GetComponent(); if (rolling && Rnd.Chance(95)) { h.Unhittable = false; } h.ModifyHealth(-1, this); if (rolling) { h.Unhittable = true; } } else if (e is CollisionStartedEvent cse) { if (cse.Entity is Player p2 && cse.Body is DoorBodyComponent) { Colliding.Add(p2); } } else if (e is CollisionEndedEvent cee) { if (cee.Entity is Player p2 && cee.Body is DoorBodyComponent) { Colliding.Remove(p2); } } return base.HandleEvent(e); } protected override Vector2 GetLockOffset() { return new Vector2(0, 3); } protected override void SetSize() { Width = 24; Height = 23; } public override Vector2 GetOffset() { return new Vector2(0, 0); } protected override Lock CreateLock() { return new IronLock(); } protected override string GetBar() { return "spiked_door"; } protected override string GetAnimation() { return "spiked_door"; } } } ================================================ FILE: BurningKnight/entity/door/TeleportTrigger.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using ImGuiNET; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework; using MonoGame.Extended; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.door { public class TeleportTrigger : SaveableEntity, PlaceableEntity { private sbyte depth; private string id; private string toId; private bool ignoreCollision; private bool toTop; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; AddTag(Tags.TeleportTrigger); AddComponent(new SensorBodyComponent(0, 0, Width, Height, BodyType.Static)); } public override bool HandleEvent(Event e) { if (e is CollisionEndedEvent cee) { if (cee.Entity is Player) { ignoreCollision = false; } } else if (e is CollisionStartedEvent cse && cse.Entity is Player p) { if (ignoreCollision) { return base.HandleEvent(e); } if (depth != 0) { Run.Depth = depth; } else { foreach (var t in Area.Tagged[Tags.TeleportTrigger]) { var tr = (TeleportTrigger) t; if (tr.id == toId) { if (tr.toTop) { p.TopCenter = tr.TopCenter - new Vector2(0, 1); } else { tr.ignoreCollision = true; p.BottomCenter = tr.BottomCenter + new Vector2(0, 1); } return base.HandleEvent(e); } } Log.Error($"Failed to teleport to {toId}"); } } return base.HandleEvent(e); } public override void RenderImDebug() { var v = (int) depth; if (id == null) { id = ""; } ImGui.InputText("Id", ref id, 128); if (ImGui.InputInt("To depth", ref v)) { depth = (sbyte) v; } if (v == 0) { if (toId == null) { toId = ""; } ImGui.InputText("To Id", ref toId, 128); } ImGui.Separator(); var x = (int) X; var y = (int) Y; if (ImGui.InputInt("X", ref x)) { X = x; } if (ImGui.InputInt("Y", ref y)) { Y = y; } ImGui.InputFloat("Width", ref Width); ImGui.InputFloat("Height", ref Height); } public override void Load(FileReader stream) { base.Load(stream); Width = stream.ReadFloat(); Height = stream.ReadFloat(); depth = stream.ReadSbyte(); id = stream.ReadString(); if (depth == 0) { toId = stream.ReadString(); } toTop = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteFloat(Width); stream.WriteFloat(Height); stream.WriteSbyte(depth); stream.WriteString(id); if (depth == 0) { stream.WriteString(toId); } stream.WriteBoolean(toTop); } public override void Render() { if (Engine.EditingLevel) { Graphics.Batch.FillRectangle(X, Y, Width, Height, ColorUtils.WhiteColor); } } } } ================================================ FILE: BurningKnight/entity/door/TreasureDoor.cs ================================================ using BurningKnight.state; using Microsoft.Xna.Framework; namespace BurningKnight.entity.door { public class TreasureDoor : CustomDoor { protected override void SetSize() { Width = Vertical ? 10 : 24; Height = Vertical ? 22 : 26; OpenByDefault = !Vertical; } public override Vector2 GetOffset() { return new Vector2(0, Vertical ? -5 : 0); } protected override Vector2 GetLockOffset() { return Vertical ? new Vector2(0, 0) : new Vector2(0, 6); } protected override Rectangle GetHitbox() { return Vertical ? new Rectangle(0, 0, (int) Width, (int) Height + 3) : new Rectangle(0, 12, (int) Width, 7); } protected override Lock CreateLock() { return Run.Depth == 1 || Run.Type == RunType.BossRush ? (Lock) new IronLock() : (Lock) new GoldLock(); } protected override string GetBar() { return Vertical ? "vertical_treasure_door" : "treasure_door"; } protected override string GetAnimation() { return Vertical ? "vertical_treasure_door" : "treasure_door"; } protected override string GetPad() { return Vertical ? "vertical_treasure_door_pad" : null; } } } ================================================ FILE: BurningKnight/entity/door/VerticalConditionDoor.cs ================================================ namespace BurningKnight.entity.door { public class VerticalConditionDoor : ConditionDoor { public VerticalConditionDoor() { Vertical = true; } } } ================================================ FILE: BurningKnight/entity/door/VerticalDoor.cs ================================================ namespace BurningKnight.entity.door { public class VerticalDoor : Door { public VerticalDoor() { Vertical = true; } } } ================================================ FILE: BurningKnight/entity/door/VerticalHallDoor.cs ================================================ namespace BurningKnight.entity.door { public class VerticalHallDoor : HallDoor { public VerticalHallDoor() { Vertical = true; } } } ================================================ FILE: BurningKnight/entity/door/VerticalShopDoor.cs ================================================ namespace BurningKnight.entity.door { public class VerticalShopDoor : ShopDoor { public VerticalShopDoor() { Vertical = true; } } } ================================================ FILE: BurningKnight/entity/events/BombPlacedEvent.cs ================================================ using BurningKnight.entity.bomb; using Lens.entity; namespace BurningKnight.entity.events { public class BombPlacedEvent : Event { public Bomb Bomb; public Entity Owner; } } ================================================ FILE: BurningKnight/entity/events/BuffAddedEvent.cs ================================================ using BurningKnight.entity.buff; using Lens.entity; namespace BurningKnight.entity.events { public class BuffAddedEvent : Event { public Buff Buff; } } ================================================ FILE: BurningKnight/entity/events/BuffRemovedEvent.cs ================================================ using BurningKnight.entity.buff; using Lens.entity; namespace BurningKnight.entity.events { public class BuffRemovedEvent : Event { public Buff Buff; } } ================================================ FILE: BurningKnight/entity/events/BurningKnightDefeatedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class BurningKnightDefeatedEvent : Event { } } ================================================ FILE: BurningKnight/entity/events/CollisionEndedEvent.cs ================================================ using BurningKnight.entity.component; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.events { public class CollisionEndedEvent : Event { public Entity Entity; public BodyComponent Body; } } ================================================ FILE: BurningKnight/entity/events/CollisionStartedEvent.cs ================================================ using BurningKnight.entity.component; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.events { public class CollisionStartedEvent : Event { public Entity Entity; public BodyComponent Body; } } ================================================ FILE: BurningKnight/entity/events/ConsumableAddedEvent.cs ================================================ using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ConsumableAddedEvent : Event { public int Amount; public int TotalNow; public ItemType Type; } } ================================================ FILE: BurningKnight/entity/events/ConsumableRemovedEvent.cs ================================================ using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ConsumableRemovedEvent : Event { public int Amount; public int TotalNow; public ItemType Type; } } ================================================ FILE: BurningKnight/entity/events/DealChanceCalculateEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class DealChanceCalculateEvent : Event { public float GrannyStartChance; public float GrannyChance; public float DmStartChance; public float DmChance; public bool OpenBoth; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/DiedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class DiedEvent : Event { public Entity From; public Entity Who; public bool BlockClear; public DamageType DamageType; } } ================================================ FILE: BurningKnight/entity/events/DoorClosedEvent.cs ================================================ using BurningKnight.entity.door; using Lens.entity; namespace BurningKnight.entity.events { public class DoorClosedEvent : Event { public Door Who; } } ================================================ FILE: BurningKnight/entity/events/DoorOpenedEvent.cs ================================================ using BurningKnight.entity.door; using Lens.entity; namespace BurningKnight.entity.events { public class DoorOpenedEvent : Event { public Door Who; } } ================================================ FILE: BurningKnight/entity/events/ExplodedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class ExplodedEvent : Event { public Entity Who; public Entity Origin; public float Damage; } } ================================================ FILE: BurningKnight/entity/events/FlagCollisionEndEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class FlagCollisionEndEvent : Event { public int Flag; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/FlagCollisionStartEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class FlagCollisionStartEvent : Event { public int Flag; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/GramophoneBrokenEvent.cs ================================================ using BurningKnight.level.entities; using Lens.entity; namespace BurningKnight.entity.events { public class GramophoneBrokenEvent : Event { public Gramophone Gramophone; } } ================================================ FILE: BurningKnight/entity/events/HealthModifiedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class HealthModifiedEvent : Event { public float Amount; public Entity From; public Entity Who; public bool Default = true; public DamageType Type = DamageType.Regular; public HealthType HealthType; public bool PressedForBomb; } } ================================================ FILE: BurningKnight/entity/events/InteractedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class InteractedEvent : Event { public Entity Who; public Entity With; } } ================================================ FILE: BurningKnight/entity/events/ItemAddedEvent.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ItemAddedEvent : Event { public Item Item; public Item Old; public ItemComponent Component; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/ItemBoughtEvent.cs ================================================ using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; namespace BurningKnight.entity.events { public class ItemBoughtEvent : Event { public Item Item; public Entity Who; public ItemStand Stand; } } ================================================ FILE: BurningKnight/entity/events/ItemCheckEvent.cs ================================================ using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ItemCheckEvent : Event { public Item Item; public bool Animate; public bool Blocked; } } ================================================ FILE: BurningKnight/entity/events/ItemPlacedEvent.cs ================================================ using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; namespace BurningKnight.entity.events { public class ItemPlacedEvent : Event { public Item Item; public Entity Who; public ItemStand Stand; } } ================================================ FILE: BurningKnight/entity/events/ItemPriceCalculationEvent.cs ================================================ using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; namespace BurningKnight.entity.events { public class ItemPriceCalculationEvent : Event { public Item Item; public ShopStand Stand; public float Percent; } } ================================================ FILE: BurningKnight/entity/events/ItemRemovedEvent.cs ================================================ using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ItemRemovedEvent : Event { public Item Item; public Entity Owner; } } ================================================ FILE: BurningKnight/entity/events/ItemTakenEvent.cs ================================================ using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens.entity; namespace BurningKnight.entity.events { public class ItemTakenEvent : Event { public Item Item; public Entity Who; public ItemStand Stand; } } ================================================ FILE: BurningKnight/entity/events/ItemUsedEvent.cs ================================================ using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class ItemUsedEvent : Event { public Item Item; public Entity Who; public bool Fake; } } ================================================ FILE: BurningKnight/entity/events/KilledEvent.cs ================================================ using BurningKnight.entity.creature; using Lens.entity; namespace BurningKnight.entity.events { public class KilledEvent : Event { public Creature Who; public Creature KilledBy; } } ================================================ FILE: BurningKnight/entity/events/LockClosedEvent.cs ================================================ using BurningKnight.entity.door; using Lens.entity; namespace BurningKnight.entity.events { public class LockClosedEvent : Event { public Lock Lock; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/LockOpenedEvent.cs ================================================ using BurningKnight.entity.door; using Lens.entity; namespace BurningKnight.entity.events { public class LockOpenedEvent : Event { public Lock Lock; public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/LostSupportEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class LostSupportEvent : Event { public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/MaxHealthModifiedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class MaxHealthModifiedEvent : Event { public Entity Who; public int Amount; } } ================================================ FILE: BurningKnight/entity/events/MobTargetChange.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class MobTargetChange : Event { public Entity Mob; public Entity Old; public Entity New; } } ================================================ FILE: BurningKnight/entity/events/NewFloorEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class NewFloorEvent : Event { } } ================================================ FILE: BurningKnight/entity/events/NewLevelStartedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class NewLevelStartedEvent : Event { } } ================================================ FILE: BurningKnight/entity/events/PlayerHurtEvent.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.events { public class PlayerHurtEvent : Event { public Player Player; } } ================================================ FILE: BurningKnight/entity/events/PlayerRolledEvent.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.events { public class PlayerRolledEvent : Event { public Player Who; } } ================================================ FILE: BurningKnight/entity/events/PlayerShootEvent.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.events { public class PlayerShootEvent : Event { public Player Player; public int Times = 1; public bool Accurate; } } ================================================ FILE: BurningKnight/entity/events/PostHealthModifiedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class PostHealthModifiedEvent : Event { public float Amount; public Entity From; public Entity Who; public bool Default = true; public DamageType Type = DamageType.Regular; public HealthType HealthType; public bool PressedForBomb; } } ================================================ FILE: BurningKnight/entity/events/ProjectileCreatedEvent.cs ================================================ using BurningKnight.entity.item; using BurningKnight.entity.projectile; using Lens.entity; namespace BurningKnight.entity.events { public class ProjectileCreatedEvent : Event { public Projectile Projectile; public Entity Owner; public Item Item; } } ================================================ FILE: BurningKnight/entity/events/QuackEvent.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.events { public class QuackEvent : Event { public Player Player; } } ================================================ FILE: BurningKnight/entity/events/RemoveFromPoolUse.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.entity.item; using BurningKnight.entity.item.use; using BurningKnight.save; using BurningKnight.state; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.events { public class RemoveFromPoolUse : ItemUse { private List items = new List(); public override void Use(Entity entity, Item item) { if (item.Used) { return; } foreach (var i in items) { Run.Statistics.Banned.Add(i); } } public override void Setup(JsonValue settings) { base.Setup(settings); items.Clear(); foreach (var i in settings["items"].AsJsonArray) { items.Add(i.String("")); } } public static void RenderDebug(JsonValue root) { if (!root["items"].IsJsonArray) { root["items"] = new JsonArray(); } var items = root["items"].AsJsonArray; var toRemove = -1; for (var i = 0; i < items.Count; i++) { var item = items[i].AsString; if (ImGui.InputText($"##item{i}", ref item, 128)) { items[i] = item; } ImGui.SameLine(); if (ImGui.Button("-")) { toRemove = i; } if (!Items.Has(item)) { ImGui.BulletText("Unknown item!"); } } if (toRemove > -1) { items.Remove(toRemove); } if (ImGui.Button("+")) { items.Add(""); } } } } ================================================ FILE: BurningKnight/entity/events/RevivedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class RevivedEvent : Event { public Entity Who; public Entity WhoDamaged; } } ================================================ FILE: BurningKnight/entity/events/RoomChangedEvent.cs ================================================ using BurningKnight.entity.room; using BurningKnight.level.rooms; using Lens.entity; namespace BurningKnight.entity.events { public class RoomChangedEvent : Event { public Entity Who; public Room Old; public Room New; public bool WasDiscovered; public bool JustDiscovered; } } ================================================ FILE: BurningKnight/entity/events/RoomClearedEvent.cs ================================================ using BurningKnight.entity.room; using BurningKnight.level.rooms; using Lens.entity; namespace BurningKnight.entity.events { public class RoomClearedEvent : Event { public Room Room; } } ================================================ FILE: BurningKnight/entity/events/SaveEndedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class SaveEndedEvent : Event { } } ================================================ FILE: BurningKnight/entity/events/SaveStartedEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class SaveStartedEvent : Event { } } ================================================ FILE: BurningKnight/entity/events/SecretRoomFoundEvent.cs ================================================ using Lens.entity; namespace BurningKnight.entity.events { public class SecretRoomFoundEvent : Event { public Entity Who; } } ================================================ FILE: BurningKnight/entity/events/TileCollisionEndEvent.cs ================================================ using BurningKnight.level.tile; using Lens.entity; namespace BurningKnight.entity.events { public class TileCollisionEndEvent : Event { public Entity Who; public Tile Tile; } } ================================================ FILE: BurningKnight/entity/events/TileCollisionStartEvent.cs ================================================ using BurningKnight.level.tile; using Lens.entity; namespace BurningKnight.entity.events { public class TileCollisionStartEvent : Event { public Entity Who; public Tile Tile; } } ================================================ FILE: BurningKnight/entity/events/WeaponSwappedEvent.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.item; using Lens.entity; namespace BurningKnight.entity.events { public class WeaponSwappedEvent : Event { public Player Who; public Item Current; public Item Old; } } ================================================ FILE: BurningKnight/entity/fx/ChasmFx.cs ================================================ using System; using BurningKnight.assets; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class ChasmFx : Entity { private static TextureRegion region; private Vector2 scale; private Color color; private float vx; private float vy; private float t; private float life; private byte targetAlpha; public override void Init() { base.Init(); if (region == null) { region = CommonAse.Particles.GetSlice("wall"); } AlwaysActive = true; var v = Rnd.Float(0.5f, 1f); color = new Color(v, v, v, 0); scale = new Vector2(Rnd.Float(0.15f, 0.3f)); targetAlpha = (byte) Rnd.Int(120, 255); life = Rnd.Float(2f, 3f); vx = Rnd.Float(-1f, 1f) * 2; vy = Rnd.Float(0.5f, 2f) * -2; } public override void Update(float dt) { base.Update(dt); t += dt; X += vx * dt; Y += vy * dt; if (t < life - 0.5f) { if (color.A < targetAlpha) { color.A = (byte) Math.Min(targetAlpha, dt * 5 * targetAlpha + color.A); } } else { color.A = (byte) Math.Max(0, color.A - dt * 2 * targetAlpha); if (color.A <= 0) { Done = true; } } } public override void Render() { Graphics.Color = color; Graphics.Render(region, Position, 0, region.Center, scale); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/fx/ExplosionLeftOver.cs ================================================ using BurningKnight.entity.component; using Lens.entity; using Lens.entity.component.graphics; namespace BurningKnight.entity.fx { public class ExplosionLeftOver : Entity { public ExplosionLeftOver() { Width = 38; Height = 38; Depth = Layers.FloorParticles; } public override void AddComponents() { base.AddComponents(); AddComponent(new SliceComponent("props", "explosion_leftover")); } } } ================================================ FILE: BurningKnight/entity/fx/Firefly.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.lighting; using BurningKnight.save; using BurningKnight.ui.editor; using Lens.graphics; using Lens.util; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class Firefly : SaveableEntity, PlaceableEntity { private static TextureRegion region; private Vector2 size; private Vector2 lightSize; private Color color; private Color lightColor; private Vector2 start; private float t; public override void Save(FileWriter stream) { Position = start; base.Save(stream); } public override void PostInit() { base.PostInit(); start = Position; Width = 192; Height = 192; Centered = true; if (region == null) { region = CommonAse.Particles.GetSlice("circ"); } color = new Color(Rnd.Float(0, 0.5f), Rnd.Float(0.5f, 1f), Rnd.Float(0, 0.5f), 1f); lightColor = new Color(color.R, color.G, color.B, (byte) 128); AddComponent(new LightComponent(this, 1f, color)); size = new Vector2(Rnd.Float(0.1f, 0.2f)); lightSize = new Vector2(size.X * 3f); Depth = Layers.WallDecor; t = Rnd.Float(20f); } public override void Update(float dt) { base.Update(dt); t += dt; lightSize.X += ((t % 20 <= 16f ? size.X * 3f : size.X) - lightSize.X) * dt * 3; lightSize.Y = lightSize.X; X = (float) (start.X + Math.Cos(t / 8) * Math.Sin(t / 9) * 32); Y = (float) (start.Y + Math.Sin(t / 7) * Math.Cos(t / 10) * 32); var light = GetComponent().Light; light.Radius += ((t % 20 <= 16f ? 96f : 0) - light.Radius) * dt * 3; } public override void Render() { Graphics.Color = lightColor; Graphics.Render(region, Position, 0.1f, region.Center, lightSize); Graphics.Color = color; Graphics.Render(region, Position, 0.1f, region.Center, size); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/fx/InteractFx.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using Lens; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class InteractFx : Entity { private bool tweened; private string text; private Entity entity; private float y; private TweenTask task; private TextureRegion region; private float offset; public InteractFx(Entity e, string str, TextureRegion sprite = null, float of = 0) { entity = e; text = str; region = sprite; AlwaysActive = true; AlwaysVisible = true; offset = of; } public override void AddComponents() { base.AddComponents(); if (region != null) { Width = region.Width; Height = region.Height; var component = new ScalableSliceComponent(region); AddComponent(component); component.Scale = Vector2.Zero; component.Origin = new Vector2(Width / 2, Height / 2); task = Tween.To(1f, component.Scale.X, x => component.Scale = new Vector2(x), 0.25f, Ease.BackOut); } else { var size = Font.Medium.MeasureString(text); Width = size.Width; Height = size.Height; var component = new TextGraphicsComponent(text); AddComponent(component); component.Scale = 0; task = Tween.To(component, new {Scale = 1.3f}, 0.25f, Ease.BackOut); } Depth = Layers.InGameUi; CenterX = entity.CenterX + offset; Y = entity.Y - Height; y = 12; Tween.To(0, y, x => y = x, 0.2f); UpdatePosition(); } private void UpdatePosition() { if (entity == null) { Done = true; return; } Center = Camera.Instance.CameraToUi(new Vector2(entity.CenterX + offset, entity.Y - 8 + y)); if (region == null) { GetComponent().Angle = (float) (Math.Cos(Engine.Instance.State.Time) * 0.05f); } } public override void Render() { if (!Engine.Instance.State.Paused) { base.Render(); } } public override void Update(float dt) { base.Update(dt); UpdatePosition(); if (!tweened) { var d = entity.Done; if (d || !entity.TryGetComponent(out var component) || component.CurrentlyInteracting == null) { if (!d && entity.TryGetComponent(out var owner) && owner.Owner is ItemStand stand && stand.GetComponent().CurrentlyInteracting != null) { return; } Close(); } } } public void Close() { task.Ended = true; if (region != null) { var c = GetComponent(); Tween.To(0, c.Scale.X, x => c.Scale = new Vector2(x), 0.25f, Ease.BackOut).OnEnd = () => Done = true; } else { Tween.To(GetComponent(), new {Scale = 0}, 0.2f).OnEnd = () => Done = true; } Tween.To(12, y, x => y = x, 0.5f); tweened = true; } } } ================================================ FILE: BurningKnight/entity/fx/SplashFx.cs ================================================ using System; using System.Linq; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class SplashFx : Entity { private TextureRegion region; private float angle; private Vector2 scale; private float targetScale; public Color Color; public override void PostInit() { base.PostInit(); X -= 16; Y -= 16; Width = 32; Height = 32; angle = Rnd.Angle(); targetScale = Rnd.Float(0.7f, 1.2f); AlwaysActive = true; AddTag(Tags.Mess); var list = Animations.Get("splash_fx").Layers.First().Value; region = list[Rnd.Int(list.Count)].Texture; } public override void Update(float dt) { base.Update(dt); scale.X = Math.Min(targetScale, scale.X + dt * 5); scale.Y = scale.X; } public void RenderInSurface() { Graphics.Color = Color; Graphics.Render(region, Center, angle, region.Center, scale); if (scale.X >= targetScale) { Done = true; } } } } ================================================ FILE: BurningKnight/entity/fx/SplashParticle.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using Lens.entity; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class SplashParticle : Entity, CollisionFilterEntity { public Color Color; private float zv; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Width = 5; Height = 5; AddComponent(new RandomFrameComponent("splash_particle") { Tint = new Color(Color.R, Color.G, Color.B, 0.8f) }); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new ZComponent()); var body = new CircleBodyComponent(0, 0, 4); AddComponent(body); var f = Rnd.Float(60, 90); var a = Rnd.AnglePI(); body.Body.LinearVelocity = new Vector2((float) Math.Cos(a) * f, (float) Math.Sin(a) * f); zv = Rnd.Float(1, 3); } public override void Update(float dt) { base.Update(dt); var c = GetComponent(); c.Z += zv * dt * 60; zv -= dt * 10; if (c.Z <= 0) { Remove(); } } private void RenderShadow() { GraphicsComponent.Render(true); } public bool ShouldCollide(Entity entity) { return (entity is Door || (entity is SolidProp && !(entity is Tombstone)) || entity is Level); } private void Remove() { Done = true; Area.Add(new SplashFx { Position = Center, Color = Color }); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev && ShouldCollide(ev.Entity)) { Remove(); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/fx/TileFx.cs ================================================ using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util.math; namespace BurningKnight.entity.fx { public class TileFx : Entity { private TextureRegion region; private float t; public override void Init() { base.Init(); Depth = Layers.WallDecor; AlwaysActive = true; t = Rnd.Float(0.5f); region = Animations.Get("particles").GetSlice("wall"); } public override void Update(float dt) { base.Update(dt); t += dt * 4f; if (t >= 1f) { Done = true; } } public override void Render() { Graphics.Render(region, Position); } } } ================================================ FILE: BurningKnight/entity/fx/WaterfallFx.cs ================================================ using System; using BurningKnight.assets; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class WaterfallFx : Entity { private static TextureRegion region; private float angle; private float angleSpeed; private float vy; private Vector2 scale; private Color color; private bool grow; public bool Lava; public override void Init() { base.Init(); if (region == null) { region = CommonAse.Particles.GetSlice("wall"); } color = new Color(255, 255, 255, 255); angleSpeed = Rnd.Float(-1, 1) * 4; scale = new Vector2(0); AlwaysActive = true; grow = true; vy = Rnd.Float(4, 8); Depth = 4; } public override void Update(float dt) { base.Update(dt); if (grow) { scale.Y += dt; scale.X = scale.Y; if (scale.X >= 0.5f) { grow = false; } else { return; } } Y += vy * dt; vy += dt * 5; angle += angleSpeed * dt; if (Lava) { if (color.R > 200) { color.R -= (byte) (dt * 140f); color.B -= (byte) (dt * 400f); color.G -= (byte) (dt * 360f); } } else { if (color.B > 150) { color.R -= (byte) (dt * 400f); color.B -= (byte) (dt * 240f); color.G -= (byte) (dt * 300f); } } color.A = (byte) Math.Max(0, color.A - dt * 55f); scale.Y -= dt * 0.3f; scale.X = scale.Y; if (color.A == 0 || scale.X <= 0) { Done = true; } } public override void Render() { Graphics.Color = color; Graphics.Color.A /= 2; Graphics.Render(region, Position, angle, region.Center, scale); Graphics.Color = color; Graphics.Render(region, Position, angle, region.Center, scale / 2); Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/fx/WindFx.cs ================================================ using System; using System.Threading; using BurningKnight.assets; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.fx { public class WindFx : Entity { private static TextureRegion region; private const float MaxSpeed = 0.5f; private float angle; private float angleSpeed; private float speed; private float t; private Vector2 scale; private Color color; private float delay; private bool overlapped; private Vector2 velocity; public override void Init() { base.Init(); if (region == null) { region = CommonAse.Particles.GetSlice("wall"); } AlwaysActive = true; Depth = Layers.WindFx; Reset(); } private void Reset() { delay = Rnd.Float(0, 5f); speed = Rnd.Float(1f, 3f) * 20; angle = Rnd.AnglePI(); angleSpeed = Rnd.Float(1f, 8f); scale = new Vector2(Rnd.Float(0.05f, 0.3f)); t = 0; float v = Rnd.Float(0.5f, 1f); color = new Color(v, v, v, Rnd.Float(0.4f, 0.9f)); var wind = CalculateWind(); var a = wind.ToAngle() - Math.PI / 2; var w = Display.Width * -0.75f; var d = Rnd.Float(-w / 2, w / 2); Position = Camera.Instance.Position + wind * w; X += (float) Math.Cos(a) * d; Y += (float) Math.Sin(a) * d; overlapped = false; velocity = wind; } public override void Update(float dt) { base.Update(dt); var overlaps = Camera.Instance.Overlaps(this); if (delay > 0) { if (overlaps) { delay = 0; } else { delay -= dt; return; } } t += dt; var w = CalculateWindSpeed(); if (overlapped) { Position += CalculateWind() * (dt * speed * w); } else { Position += velocity * (dt * speed); } Position += Camera.Instance.PositionDelta * (speed * 0.01f); angle += angleSpeed * dt * w; if (overlaps) { overlapped = true; } else if (overlapped) { Reset(); } else if (t > 3f) { Reset(); } } public override void Render() { Graphics.Color = color; Graphics.Render(region, Position, angle, region.Center, scale); Graphics.Color = ColorUtils.WhiteColor; } public static Vector2 CalculateWind() { float t = Engine.Time * 0.1f; double a = Math.Cos(t) * Math.Sin(t * 1.3f) + Math.Cos(t * 1.5f); return new Vector2(MathUtils.Clamp(-MaxSpeed, MaxSpeed, (float) Math.Cos(a)), MathUtils.Clamp(-MaxSpeed, MaxSpeed, (float) Math.Sin(a))); } public static float CalculateWindSpeed() { float t = Engine.Time * 0.1f; return (float) (1 + Math.Cos(t) * Math.Sin(t * 0.9f) * 0.5f) * 2.5f; } } } ================================================ FILE: BurningKnight/entity/item/AnimatedItemGraphicsComponent.cs ================================================ using BurningKnight.entity.component; using Lens.assets; using Lens.entity.component.graphics; using Lens.graphics; using Lens.graphics.animation; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item { public class AnimatedItemGraphicsComponent : GraphicsComponent { public Animation Animation; public float T; public AnimatedItemGraphicsComponent(string animation) { Animation = Animations.Create(animation); Animation.Randomize(); T = Rnd.Float(32f); } public override void Update(float dt) { base.Update(dt); T += dt; Animation.Update(dt); } public override void Render(bool shadow) { if (!Entity.HasComponent()) { if (shadow) { var region = Animation.GetCurrentTexture(); Graphics.Render(region, Entity.Position, 0, new Vector2(0, -region.Height), Vector2.One, Graphics.ParseEffect(Flipped, !FlippedVerticaly)); return; } Animation.Render(Entity.Position/* + new Vector2(0, ItemGraphicsComponent.CalculateMove(T * 1.2f))*/); } } } } ================================================ FILE: BurningKnight/entity/item/BossStand.cs ================================================ using BurningKnight.entity.item.stand; namespace BurningKnight.entity.item { public class BossStand : ItemStand { protected override string GetSprite() { return "boss_stand"; } public override ItemPool GetPool() { return ItemPool.Boss; } } } ================================================ FILE: BurningKnight/entity/item/Chance.cs ================================================ using System; using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item { public class Chance { public const double OtherClasses = 0.1f; public double Any; public double Melee; public double Magic; public double Range; public Chance(double all, double warrior, double mage, double ranged) { Any = all; Melee = warrior; Magic = mage; Range = ranged; } public double Calculate(PlayerClass c) { switch (c) { case PlayerClass.Warrior: return Melee * Any; case PlayerClass.Mage: return Magic * Any; case PlayerClass.Ranger: return Range * Any; default: return Any; } } public static Chance All(double all = 1) { return new Chance(all, 1, 1, 1); } public static Chance Warrior(double all) { return new Chance(all, 1, OtherClasses, OtherClasses); } public static Chance Mage(double all) { return new Chance(all, OtherClasses, 1, OtherClasses); } public static Chance Ranger(double all) { return new Chance(all, OtherClasses, OtherClasses, 1); } public static Chance Parse(JsonValue value) { if (value.IsJsonArray) { var array = value.AsJsonArray; if (array.Count != 4) { Log.Error("Invalid chance declaration, must be [ all, melee, ranged, mage ] (3 numbers)"); return All(); } return new Chance(array[0], array[1], array[2], array[3]); } return All(value.Number(1f)); } public JsonValue ToJson() { return Any; /*new JsonArray { Any, Melee, Magic, Range };*/ } private static bool simplify = true; public void RenderDebug() { /*ImGui.Checkbox("Show simplified", ref simplify); if (simplify) { var vl = Math.Pow(Any, -1); ImGui.Text("1 in"); ImGui.SameLine(); if (ImGui.InputDouble("Chance", ref vl)) { Any = Math.Pow(vl, -1); } ImGui.Separator(); vl = Math.Pow(Melee, -1); ImGui.Text("1 in"); ImGui.SameLine(); if (ImGui.InputDouble("Melee", ref Melee)) { Melee = Math.Pow(vl, -1); } vl = Math.Pow(Magic, -1); ImGui.Text("1 in"); ImGui.SameLine(); if (ImGui.InputDouble("Magic", ref Magic)) { Magic = Math.Pow(vl, -1); } vl = Math.Pow(Range, -1); ImGui.Text("1 in"); ImGui.SameLine(); if (ImGui.InputDouble("Range", ref Range)) { Range = Math.Pow(vl, -1); } return; }*/ ImGui.InputDouble("Chance", ref Any); /*ImGui.Separator(); ImGui.InputDouble("Melee", ref Melee); ImGui.InputDouble("Magic", ref Magic); ImGui.InputDouble("Range", ref Range);*/ } } } ================================================ FILE: BurningKnight/entity/item/EmeraldStand.cs ================================================ using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.save; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item { public class EmeraldStand : ItemStand { public static List AlreadyOnStand = new List(); private TextureRegion emerald; private int price; private float priceWidth; private string priceString; private float priceX; public EmeraldStand() { dontSaveItem = true; emerald = CommonAse.Ui.GetSlice("emerald"); } public override void Init() { base.Init(); var item = PickItem(); if (item != null) { SetItem(item, null); } } public override void Destroy() { base.Destroy(); if (Item != null) { AlreadyOnStand.Remove(Item.Id); } } protected override string GetSprite() { return "shop_stand"; } protected override bool CanTake(Entity entity) { if (!base.CanTake(entity)) { return false; } if (GlobalSave.Emeralds < price) { AnimationUtil.ActionFailed(); var npc = Area.FindClosest(Center, Tags.Npc, n => n is ShopNpc); if (npc != null && npc.TryGetComponent(out var c)) { c.StartAndClose($"shopkeeper_{Rnd.Int(15, 18)}", 3); } return false; } GlobalSave.Emeralds -= price; Items.Unlock(Item.Id); AlreadyOnStand.Remove(Item.Id); if (!ShowUnlocked) { Item.Done = true; /*var item = PickItem(); SetItem(item, entity, false);*/ AnimationUtil.Poof(Center, 1); } Audio.PlaySfx("item_purchase"); Achievements.Unlock("bk:unlock"); entity.HandleEvent(new ItemBoughtEvent { Item = item, Who = entity, Stand = this }); foreach (var i in Area.Tagged[Tags.Item]) { if (i is Item it) { it.CheckMasked(); } else if (i is ItemStand its) { its.Item?.CheckMasked(); } } DoStuff(); return ShowUnlocked; } protected virtual void DoStuff() { } protected virtual bool ApproveItem(ItemData item) { return true; } protected bool ShowUnlocked; private Item PickItem() { var items = new List(); foreach (var i in Items.Datas.Values) { if (i.Lockable && i.UnlockPrice > 0 && ApproveItem(i) && !AlreadyOnStand.Contains(i.Id) && (ShowUnlocked || GlobalSave.IsFalse(i.Id))) { items.Add(i); } } if (items.Count == 0) { return null; } items.Sort((a, b) => a.UnlockPrice.CompareTo(b.UnlockPrice)); var id = items[0].Id; AlreadyOnStand.Add(id); return Items.CreateAndAdd(id, Area); } protected override bool CanInteract(Entity e) { return Item != null; } public override void Render() { base.Render(); if (Item != null && price > 0) { Graphics.Print(priceString, Font.Small, Position + new Vector2(priceX, 14)); Graphics.Render(emerald, Position + new Vector2(priceX + priceWidth + 2, 17)); } } public override void SetItem(Item i, Entity entity, bool remove = true) { base.SetItem(i, entity, remove); RecalculatePrice(); } public void RecalculatePrice() { if (Item == null) { return; } if (GlobalSave.IsTrue(Item.Id)) { price = 0; } else { price = Item.Data.UnlockPrice; var player = LocalPlayer.Locate(Area); if (player != null && player.GetComponent().Item?.Id == "bk:dunce_hat") { price++; } priceString = $"{price}"; priceWidth = Font.Small.MeasureString(priceString).Width; priceX = (Width - priceWidth - 2 - emerald.Width) / 2f; } } } } ================================================ FILE: BurningKnight/entity/item/Item.cs ================================================ using System; using System.Linq; using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.assets.particle; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.renderer; using BurningKnight.entity.item.stand; using BurningKnight.entity.item.use; using BurningKnight.entity.item.useCheck; using BurningKnight.level; using BurningKnight.level.rooms; using BurningKnight.physics; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.item { public class Item : SaveableEntity, CollisionFilterEntity, PlaceableEntity { public static TextureRegion UnknownRegion; public static bool Attact; public ItemType Type; public string Id; public string LastId; public string IdUnderScourge => Type != ItemType.Scourge && Scourge.IsEnabled(Scourge.OfEgg) ? Items.Datas.Values.ElementAt(Rnd.Int(Items.Datas.Count)).Id : Id; public string Name => Masked ? "???" : Locale.Get(IdUnderScourge); public string Description => Locale.Get($"{IdUnderScourge}_desc"); public float UseTime = 0.3f; public float Delay; public string Animation; public bool AutoPickup; public bool LoadedSelf; public bool Used; public bool Touched; public bool Automatic; public bool SingleUse; public bool Scourged; public bool Hide; public ItemUse[] Uses; public ItemUseCheck UseCheck = ItemUseChecks.Default; public ItemRenderer Renderer; public bool Hidden => (Type != ItemType.Mana && Type != ItemType.Coin && Type != ItemType.Heart && Type != ItemType.Key && Type != ItemType.Bomb && (!TryGetComponent(out var o) || !(o.Owner is Player)) && Scourge.IsEnabled(Scourge.OfUnknown)); public TextureRegion Region => (Hidden) ? UnknownRegion : (Animation != null ? GetComponent().Animation.GetCurrentTexture() : GetComponent().Sprite); public Entity Owner => TryGetComponent(out var o) ? o.Owner : null; public ItemData Data => Items.Datas[Id]; private bool updateLight; private float t; public override void Init() { base.Init(); if (Run.Depth > 0 && (Type != ItemType.Scourge && Type != ItemType.Coin && Type != ItemType.Key && Type != ItemType.Bomb && Type != ItemType.Heart) && Rnd.Chance(Scourge.IsEnabled(Scourge.OfScourged) ? 0.66f : (Run.Scourge * 10 + 0.5f))) { Scourged = true; } } public override void Destroy() { base.Destroy(); if (Uses == null) { return; } foreach (var u in Uses) { u.Destroy(); } } public bool Use(Entity entity, bool avoidCheck = false) { if (!avoidCheck && (Type == ItemType.Weapon || Type == ItemType.Active) && !UseCheck.CanUse(entity, this)) { return false; } foreach (var use in Uses) { if (use.SingleUse && Used) { continue; } try { use.Use(entity, this); } catch (Exception e) { Log.Error(e); } } Delay = Math.Abs(UseTime); entity.HandleEvent(new ItemUsedEvent { Item = this, Who = entity, Fake = avoidCheck }); Used = true; Renderer?.OnUse(); if (Type == ItemType.Active) { ((Player) entity).AnimateItemPickup(this, null, false, false); } return true; } public void Pickup() { var entity = Owner; foreach (var use in Uses) { try { use.Pickup(entity, this); } catch (Exception e) { Log.Error(e); } } } public void Drop() { var entity = Owner; foreach (var use in Uses) { try { use.Drop(entity, this); } catch (Exception e) { Log.Error(e); } } } public void TakeOut() { var entity = Owner; foreach (var use in Uses) { try { use.TakeOut(entity, this); } catch (Exception e) { Log.Error(e); } } } public void PutAway() { var entity = Owner; foreach (var use in Uses) { try { use.PutAway(entity, this); } catch (Exception e) { Log.Error(e); } } } public override void PostInit() { base.PostInit(); if (Animation != null) { AddComponent(new AnimatedItemGraphicsComponent(Animation)); } else { AddComponent(new ItemGraphicsComponent(Id)); } if (LoadedSelf) { AddDroppedComponents(); } CheckMasked(); if (Id.Contains("mana")) { AlwaysActive = true; } } private bool Interact(Entity entity) { if (Masked && Run.Depth < 1) { return false; } if (entity.TryGetComponent(out var inventory)) { inventory.Pickup(this); return true; } return false; } protected virtual bool ShouldInteract(Entity entity) { return !(entity is Player c && ((Type == ItemType.Mana && (!c.GetComponent().CanPickup(this) || t < 1f)) || (Type == ItemType.Heart && !c.GetComponent().CanPickup(this)) || (Type == ItemType.Battery && c.GetComponent().IsFullOrEmpty()) || (Type == ItemType.Coin && Id != "bk:emerald" && c.GetComponent().Coins >= c.GetComponent().MaxCoins) || (Type == ItemType.Bomb && c.GetComponent().Bombs == 99 && c.TryGetComponent(out var b) && b.BombsMax > b.Bombs) || (Type == ItemType.Key && c.GetComponent().Keys == 99) )); } public void OnInteractionStart(Entity entity) { if (!Scourged && AutoPickup && entity.TryGetComponent(out var inventory)) { if (ShouldInteract(entity)) { inventory.Pickup(this); entity.GetComponent().EndInteraction(); } } else if (!HasComponent() && Run.Depth != -2) { Engine.Instance.State.Ui.Add(new ItemPickupFx(this)); } } protected virtual BodyComponent CreateBody() { var slice = Region; return new RectBodyComponent(0, 0, slice.Source.Width, slice.Source.Height); } public virtual void AddDroppedComponents() { var body = CreateBody(); t = 0; AddComponent(body); body.Body.LinearDamping = Type == ItemType.Mana ? 1 : 4; body.Body.Friction = 0; body.Body.Mass = 0.1f; AddComponent(new InteractableComponent(Interact) { OnStart = OnInteractionStart, CanInteract = ShouldInteract }); AddComponent(new ShadowComponent(RenderShadow)); AddTag(Tags.LevelSave); AddTag(Tags.Item); AddComponent(new RoomComponent()); AddComponent(new ExplodableComponent()); AddComponent(new SupportableComponent()); CheckMasked(); } public void RandomizeVelocity(float force) { var component = GetBody(); if (component == null) { return; } force *= 60f; var angle = Rnd.AnglePI(); component.Velocity += new Vector2((float) Math.Cos(angle) * force, (float) Math.Sin(angle) * force); } protected virtual void RemoveBody() { RemoveComponent(); } public virtual void RemoveDroppedComponents() { RemoveComponent(); RemoveComponent(); RemoveComponent(); RemoveBody(); RemoveTag(Tags.LevelSave); RemoveTag(Tags.Item); RemoveComponent(); RemoveComponent(); RemoveComponent(); CheckMasked(); } private void RenderShadow() { GraphicsComponent.Render(true); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteString(Id); stream.WriteBoolean(Used); stream.WriteBoolean(Touched); stream.WriteFloat(Delay); stream.WriteBoolean(Unknown); stream.WriteBoolean(Scourged); stream.WriteBoolean(Hide); } public void ConvertTo(string id) { var item = Items.Create(id); if (item == null) { Log.Error($"Failed to convert item {Id}, such id does not exist!"); return; } if (HasComponent()) { RemoveComponent(); } else if (HasComponent()) { RemoveComponent(); } Uses = Items.ParseUses(Items.Datas[id].Uses); foreach (var u in Uses) { u.Item = this; u.Init(); } UseTime = item.UseTime; Renderer = item.Renderer; Animation = item.Animation; AutoPickup = item.AutoPickup; Automatic = item.Automatic; SingleUse = item.SingleUse; Type = item.Type; Id = id; Used = false; Scourged = Scourged || item.Scourged; if (Renderer != null) { Renderer.Item = this; } if (Animation != null) { AddComponent(new AnimatedItemGraphicsComponent(Animation)); } else { AddComponent(new ItemGraphicsComponent(Id)); } if (HasBody()) { RemoveDroppedComponents(); AddDroppedComponents(); } } protected virtual bool HasBody() { return HasComponent(); } public override void Load(FileReader stream) { base.Load(stream); try { LoadedSelf = true; Id = stream.ReadString(); Scourged = false; if (!Items.Has(Id)) { Id = "bk:revolver"; } ConvertTo(Id); Used = stream.ReadBoolean(); Touched = stream.ReadBoolean(); Delay = stream.ReadFloat(); Unknown = stream.ReadBoolean(); var v = stream.ReadBoolean(); Scourged = Scourged || v; Hide = stream.ReadBoolean(); } catch (Exception e) { Log.Error(e); } } private float lastParticle; public override void Update(float dt) { base.Update(dt); t += dt; if (Type != ItemType.Active || UseTime < 0) { var s = dt; if (Type == ItemType.Weapon && Owner != null && Owner.TryGetComponent(out var stats)) { s *= stats.FireRate; if (Data.WeaponType == WeaponType.Ranged) { s *= stats.RangedRate; } } Delay = Math.Max(0, Delay - s); } var hasOwner = HasComponent(); if (Scourged) { lastParticle -= dt; if (lastParticle <= 0) { lastParticle = Rnd.Float(0.05f, 0.3f); for (var i = 0; i < Rnd.Int(0, 3); i++) { var part = new ParticleEntity(Particles.Scourge()); part.Position = (hasOwner ? GetComponent().Owner.Center : Center) + Rnd.Vector(-4, 4); part.Particle.Scale = Rnd.Float(0.5f, 1.2f); Area.Add(part); part.Depth = hasOwner ? 1 : -1; } } } if (hasOwner) { var o = Owner; foreach (var u in Uses) { u.Update(o, this, dt); } } else { if (Attact) { var room = GetComponent().Room; if (room.Tagged[Tags.Player].Count > 0) { var force = 360 * dt; var a = AngleTo(room.Tagged[Tags.Player][0]); GetBody().Velocity += new Vector2((float) Math.Cos(a) * force, (float) Math.Sin(a) * force); } } if (updateLight) { updateLight = false; var room = GetComponent().Room; if (room == null || HasComponent()) { if (room == null || room.Type == RoomType.Secret) { RemoveComponent(); } } else if (room.Type != RoomType.Secret) { if (Type == ItemType.Mana || Type == ItemType.Coin || Type == ItemType.Heart || Type == ItemType.Battery || Type == ItemType.Key) { Color color; if (Type == ItemType.Coin || Type == ItemType.Key) { color = new Color(1f, 1f, 0.5f, 1f); } else if (Type == ItemType.Heart) { color = new Color(1f, 0.2f, 0.2f, 1f); } else if (Type == ItemType.Mana) { color = new Color(0.2f, 1f, 0.2f, 1f); } else { color = new Color(1f, 1f, 1f, 1f); } AddComponent(new LightComponent(this, 32f, color)); } } } } if (Type == ItemType.Mana && t >= 0.1f) { var p = LocalPlayer.Locate(Area); if (p == null) { return; } if (p.GetComponent().IsFull() || t < 1f) { return; } var room = GetComponent().Room; var limitRange = room != null && room.Tagged[Tags.MustBeKilled].Count > 0; var d = DistanceTo(p); if (d < 4) { return; } if (limitRange && d > 64) { return; } var b = GetBody().Body; var dx = DxTo(p); var dy = DyTo(p); var s = dt * 4; b.LinearVelocity -= new Vector2(dx / d * s, dy / d * s); var a = b.LinearVelocity.ToAngle(); d = Math.Min(b.LinearVelocity.Length() + dt * 300, 1000); a = (float) MathUtils.LerpAngle(a, AngleTo(p), dt * 10); b.LinearVelocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); } } protected virtual BodyComponent GetBody() { return TryGetComponent(out var b) ? b : null; } public virtual bool ShouldCollide(Entity entity) { if (Type == ItemType.Mana) { if (entity is ProjectileLevelBody || entity is HalfProjectileLevel || entity is Chasm) { return false; } var room = GetComponent().Room; if (room == null || room.Tagged[Tags.MustBeKilled].Count == 0) { return false; } } return !(entity is Creature) || !ShouldInteract(entity); } public override bool HandleEvent(Event e) { if (e is LostSupportEvent) { Done = true; return true; } else if (e is RoomChangedEvent rce && !HasComponent()) { updateLight = true; } return base.HandleEvent(e); } public bool Masked { get; protected set; } private bool unknown; public bool Unknown { get => unknown; set { unknown = value; CheckMasked(); } } public void CheckMasked() { Masked = Unknown || (Run.Depth == 0 && Data.Lockable && Type != ItemType.Lamp && (Data.UnlockPrice == 0 || (TryGetComponent(out var o) && o.Owner is PermanentStand)) && !Unlocked(Id)); } public static bool Unlocked(string id) { return GlobalSave.IsTrue(id) || id == "bk:sword" || id == "bk:no_lamp" || id == "bk:revolver" || id == "bk:no_hat"; } public bool HandleOwnerEvent(Event e) { if (Uses == null) { return false; } foreach (var use in Uses) { if (use.HandleEvent(e)) { return true; } } return false; } #if DEBUG private string debugItem = ""; public override void RenderImDebug() { if (ImGui.InputText("Item", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) { ConvertTo(debugItem); } ImGui.Checkbox("Scourged", ref Scourged); ImGui.Checkbox("Touched", ref Touched); } #endif public class UnlockedEvent : Event { public ItemData Data; } } } ================================================ FILE: BurningKnight/entity/item/ItemGraphicsComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.ui.imgui; using Lens.graphics; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item { public class ItemGraphicsComponent : SliceComponent { public const float FlashSize = 0.025f; public const int ScourgedColorId = 48; public static Color MaskedColor = new Color(0f, 0f, 0f, 0.75f); public static Vector4 ScourgedColor = Palette.Default[ScourgedColorId].ToVector4(); public float T; public ItemGraphicsComponent(string slice) : base(CommonAse.Items, slice) { T = Rnd.Float(32f); } public override void Init() { base.Init(); Entity.Width = Sprite.Source.Width; Entity.Height = Sprite.Source.Height; } public override void Update(float dt) { base.Update(dt); T += dt; } public static float CalculateMove(float t) { return (float) (Math.Sin(t * 3f) * 0.5f + 0.5f) * -5.5f; } public virtual Vector2 CalculatePosition(bool shadow = false) { return Entity.Position + Sprite.Center + new Vector2(0, shadow ? 8 : CalculateMove(T)); } public override void Render(bool shadow) { if (Entity.HasComponent()) { return; } var item = (Item) Entity; var s = item.Hidden ? Item.UnknownRegion : Sprite; var origin = s.Center; var position = CalculatePosition(shadow); var angle = (float) Math.Cos(T * 1.8f) * 0.4f; var cursed = item.Scourged; if (!shadow) { var interact = Entity.TryGetComponent(out var component) && component.OutlineAlpha > 0.05f; if (cursed || interact) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(cursed ? 1f : component.OutlineAlpha); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(!cursed ? ColorUtils.White : ColorUtils.Mix(ScourgedColor, ColorUtils.White, component.OutlineAlpha)); foreach (var d in MathUtils.Directions) { Graphics.Render(s, position + d, angle, origin); } Shaders.End(); } } if (item.Masked) { Graphics.Color = MaskedColor; Graphics.Render(s, position, angle, origin); Graphics.Color = ColorUtils.WhiteColor; } else { if (!shadow && DebugWindow.ItemShader && !Settings.LowQuality) { var shader = Shaders.Item; Shaders.Begin(shader); shader.Parameters["time"].SetValue(T * 0.1f); shader.Parameters["size"].SetValue(FlashSize); } Graphics.Render(s, position, angle, origin); if (!shadow && DebugWindow.ItemShader && !Settings.LowQuality) { Shaders.End(); } } } } } ================================================ FILE: BurningKnight/entity/item/ItemInfo.cs ================================================ using System; namespace BurningKnight.entity.item { public class ItemInfo { public Chance Chance; public string Id; public Func Create; public float Warrior; public ItemType Type; public ItemInfo(string id, Func create, ItemType type = ItemType.Artifact, Chance chance = null) { Id = id; Create = create; Chance = chance ?? Chance.All(); Type = type; } public bool Unlocked(string Key) { return true; } } } ================================================ FILE: BurningKnight/entity/item/ItemPair.cs ================================================ namespace BurningKnight.entity.item { public class ItemPair { public string Id; public int Count = 1; } } ================================================ FILE: BurningKnight/entity/item/ItemPickupFx.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using Lens; using Lens.assets; using Lens.entity; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item { public class ItemPickupFx : Entity { private Item item; private bool tweened; private float y; private TweenTask task; public ItemPickupFx(Item it) { item = it; AlwaysActive = true; AlwaysVisible = true; } public override void AddComponents() { base.AddComponents(); string text; if (Locale.Current == "de" || Locale.Current == "it") { text = item.Hidden ? "???" : (item.Scourged ? $"{item.Name} ({Locale.Get("scourged")})" : item.Name); } else { text = item.Hidden ? "???" : (item.Scourged ? $"{Locale.Get("scourged")} {item.Name}" : item.Name); } var size = Font.Medium.MeasureString(text); Width = size.Width; Height = size.Height; var component = new TextGraphicsComponent(text); AddComponent(component); component.Scale = 0; task = Tween.To(component, new {Scale = 1.3f}, 0.25f, Ease.BackOut); y = 12; Tween.To(0, y, x => y = x, 0.2f); UpdatePosition(); if (item.Scourged) { component.Color = Palette.Default[ItemGraphicsComponent.ScourgedColorId]; } } private void UpdatePosition() { var yy = 0f; if (item.Animation == null) { var c = item.GetComponent(); yy = ItemGraphicsComponent.CalculateMove(c.T) * Display.UiScale; } Center = Camera.Instance.CameraToUi(new Vector2(item.CenterX, item.Y - 8 + y + yy)); GetComponent().Angle = (float) (Math.Cos(Engine.Instance.State.Time) * 0.05f); } public override void Render() { if (!Engine.Instance.State.Paused) { base.Render(); } } public override void Update(float dt) { base.Update(dt); UpdatePosition(); if (!tweened) { if (!item.TryGetComponent(out var component) || component.CurrentlyInteracting == null) { if (item.TryGetComponent(out var owner) && owner.Owner is ItemStand stand && stand.GetComponent().CurrentlyInteracting != null) { return; } task.Ended = true; Tween.To(GetComponent(), new {Scale = 0}, 0.2f).OnEnd = () => Done = true; Tween.To(12, y, x => y = x, 0.5f); tweened = true; } } } } } ================================================ FILE: BurningKnight/entity/item/ItemPool.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.util; using Lens.util; namespace BurningKnight.entity.item { public class ItemPool { public static Dictionary ByName = new Dictionary(); public static ItemPool[] ById = new ItemPool[32]; public static string[] Names = new string[32]; static ItemPool() { // So that imgui doesnt crash for (var i = 0; i < 32; i++) { if (Names[i] == null) { Names[i] = ""; } } } public static readonly ItemPool Consumable = new ItemPool("consumable"); public static readonly ItemPool Treasure = new ItemPool("treasure"); public static readonly ItemPool Secret = new ItemPool("secret"); public static readonly ItemPool Snek = new ItemPool("snek"); public static readonly ItemPool Boxy = new ItemPool("boxy"); public static readonly ItemPool StartingWeapon = new ItemPool("starting_weapon"); public static readonly ItemPool Shop = new ItemPool("shop"); public static readonly ItemPool Boss = new ItemPool("boss"); public static readonly ItemPool ShopConsumable = new ItemPool("shop_consumable"); public static readonly ItemPool Safe = new ItemPool("safe"); public static readonly ItemPool Charger = new ItemPool("charger"); public static readonly ItemPool WoodenChest = new ItemPool("wooden_chest"); public static readonly ItemPool GoldChest = new ItemPool("gold_chest"); public static readonly ItemPool ScourgedChest = new ItemPool("scourged_chest"); public static readonly ItemPool DoubleChest = new ItemPool("double_chest"); public static readonly ItemPool TripleChest = new ItemPool("triple_chest"); public static readonly ItemPool RedChest = new ItemPool("red_chest"); public static readonly ItemPool Pet = new ItemPool("pet"); public static readonly ItemPool Orbital = new ItemPool("orbital"); public static readonly ItemPool StoneChest = new ItemPool("stone_chest"); public static readonly ItemPool Granny = new ItemPool("granny"); public static readonly ItemPool OldMan = new ItemPool("old_man"); public static readonly ItemPool Vampire = new ItemPool("vampire"); public static readonly ItemPool Roger = new ItemPool("roger"); public static readonly ItemPool Weapon = new ItemPool("weapon"); public static readonly ItemPool SpikedRoom = new ItemPool("spiked_room"); public static readonly ItemPool DuckChest = new ItemPool("duck_chest"); public static readonly ItemPool Gobetta = new ItemPool("gobetta"); public static readonly ItemPool BossRush = new ItemPool("boss_rush"); private static int count; public static int Count => count; public readonly string Name; public readonly int Id; public ItemPool(string name) { if (count >= 32) { Log.Error($"Can not define item pool {name}, 32 pools were already defined"); return; } Name = name; Id = count; ById[Id] = this; ByName[name] = this; Names[Id] = name; count++; } public int Apply(int pools, bool add = true) { return BitHelper.SetBit(pools, Id, add); } public bool Contains(int pools) { return BitHelper.IsBitSet(pools, Id); } } } ================================================ FILE: BurningKnight/entity/item/ItemQuality.cs ================================================ namespace BurningKnight.entity.item { // Keep in sync with ItemEditor::Quality!! public enum ItemQuality { Wooden, Iron, Golden, Trash } } ================================================ FILE: BurningKnight/entity/item/ItemType.cs ================================================ namespace BurningKnight.entity.item { // Keep in sync with item editor defenition!!! // (in the same order) public enum ItemType { Artifact, Active, Coin, Bomb, Key, Heart, ConsumableArtifact, Weapon, Battery, Hat, Pouch, Scourge, Mana, Lamp } } ================================================ FILE: BurningKnight/entity/item/PriceCalculator.cs ================================================ using System; using BurningKnight.state; namespace BurningKnight.entity.item { public static class PriceCalculator { public static int BasePrice(ItemType type) { switch (type) { case ItemType.Lamp: case ItemType.Artifact: return 15; case ItemType.Active: case ItemType.Coin: return 10; case ItemType.Bomb: case ItemType.Key: case ItemType.Battery: case ItemType.Heart: return 3; case ItemType.Hat: return 1; default: return 15; } } public static float GetPriceModifier(this ItemQuality quality) { switch (quality) { case ItemQuality.Wooden: default: return 1; case ItemQuality.Iron: return 1.333f; case ItemQuality.Golden: return 2f; case ItemQuality.Trash: return 0.5f; } } public static float GetModifier(Item item) { return Math.Max(1, Math.Min(99, (Run.Loop > 0 ? 7 : 1) * (Scourge.IsEnabled(Scourge.OfGreed) ? 2 : 1) * item.Data.Quality.GetPriceModifier())); } public static int Calculate(Item item) { return (int) Math.Round(BasePrice(item.Type) * GetModifier(item)); } } } ================================================ FILE: BurningKnight/entity/item/RandomItem.cs ================================================ using BurningKnight.assets.items; using BurningKnight.ui.editor; using Lens.util.file; namespace BurningKnight.entity.item { public class RandomItem : RoundItem { public bool Prevent; private static string GenerateId() { return Items.Generate(ItemPool.Treasure); } private void TryToOverrideId() { if (Prevent) { return; } ConvertTo(GenerateId()); } public override void PostInit() { TryToOverrideId(); base.PostInit(); } } } ================================================ FILE: BurningKnight/entity/item/Reroller.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.entity.room; using Lens.assets; using Lens.entity; namespace BurningKnight.entity.item { public static class Reroller { private static bool CanReroll(Item i) { return !(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); } public static void Reroll(Area area, Room room, bool rerollStands, bool spawnNewItems, bool ignore, ItemType[] types, Action processItem = null, bool d2 = false) { var items = room.Tagged[Tags.Item].ToArray(); var pool = Items.GeneratePool(Items.GetPool(room.GetPool() ?? ItemPool.Shop)); foreach (var e in items) { Item item = null; if (e is ItemStand s) { if (rerollStands) { if (s.Item == null) { if (spawnNewItems) { var id = s is ShopStand std ? Items.Generate(std.GetPool()) : Items.GenerateAndRemove(pool); s.SetItem(Items.CreateAndAdd(id, area), null); TextParticle.Add(s, Locale.Get("rerolled")).Stacks = false; } continue; } var i = s.Item; if (!CanReroll(i)) { continue; } item = i; } } else if (e is Item i) { if (!CanReroll(i)) { continue; } if (types != null) { var found = false; foreach (var t in types) { if (t == i.Type) { found = true; } } if (found == ignore) { continue; } } item = i; } if (item == null || (item.TryGetComponent(out var o) && !(o.Owner is ItemStand))) { continue; } if (Reroll(item, pool, null, d2)) { processItem?.Invoke(item); } if (e is ShopStand st) { st.Recalculate(); } } Audio.PlaySfx("item_reroll"); } public static bool Reroll(Item item, ItemPool pool, Func filter = null) { var id = Items.Generate(pool, i => i.Id != item.Id && Items.ShouldAppear(i) && (filter == null || filter(i))); if (id != null) { item.LastId = item.Id; item.ConvertTo(id); item.AutoPickup = false; TextParticle.Add(item, Locale.Get("rerolled")).Stacks = false; return true; } return false; } public static bool Reroll(Item item, List pool, Func filter = null, bool d2 = false) { var id = d2 ? item.LastId : null; if (id == null) { id = Items.GenerateAndRemove(pool, i => i.Id != item.Id && (filter == null || filter(i))); } if (id != null) { item.LastId = item.Id; item.ConvertTo(id); item.AutoPickup = false; TextParticle.Add(item, Locale.Get("rerolled")).Stacks = false; return true; } return false; } } } ================================================ FILE: BurningKnight/entity/item/RoundItem.cs ================================================ using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item { public class RoundItem : Item { public bool Transparent; public bool Won; protected override BodyComponent GetBody() { return GetComponent(); } protected override bool HasBody() { return HasComponent(); } protected override void RemoveBody() { RemoveComponent(); } protected override BodyComponent CreateBody() { return new CircleBodyComponent(0, 0, 8); } public override bool ShouldCollide(Entity entity) { return !Transparent && base.ShouldCollide(entity); } protected override bool ShouldInteract(Entity entity) { return !Transparent && Won && base.ShouldInteract(entity); } } } ================================================ FILE: BurningKnight/entity/item/Scourge.cs ================================================ using System.Collections.Generic; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item { public static class Scourge { private static Dictionary enabled = new Dictionary(); public static List Defined = new List(); public const string OfUnknown = "bk:of_unknown"; public const string OfRisk = "bk:of_risk"; public const string OfScourged = "bk:of_scourged"; public const string OfBlood = "bk:of_blood"; public const string OfLost = "bk:of_lost"; public const string OfKeys = "bk:of_keys"; public const string OfEgg = "bk:of_egg"; public const string OfIllness = "bk:of_illness"; public const string OfGreed = "bk:of_greed"; public const string OfDeath = "bk:of_death"; public static void Define(string curse) { Defined.Add(curse); } static Scourge() { Define(OfUnknown); Define(OfRisk); Define(OfScourged); Define(OfBlood); Define(OfLost); Define(OfKeys); Define(OfEgg); Define(OfIllness); Define(OfGreed); Define(OfDeath); } public static void Clear() { enabled.Clear(); } public static void Enable(string curse) { if (IsEnabled(curse)) { return; } enabled[curse] = true; Log.Info($"Scourge {curse} was activated!"); } public static void Disable(string curse) { if (!IsEnabled(curse)) { return; } enabled[curse] = false; Log.Info($"Scourge {curse} was deactivated!"); } public static bool IsEnabled(string curse) { if (!enabled.ContainsKey(curse)) { return false; } return enabled[curse]; } public static bool ShouldAppear(string id) { if (id == OfDeath) { foreach (var s in Defined) { if (s != OfDeath && !IsEnabled(s)) { return false; } } } else if (id == OfScourged) { var found = false; foreach (var s in Defined) { if (IsEnabled(s)) { found = true; break; } } if (!found) { return false; } } return !IsEnabled(id); } public static string Generate() { var list = GenerateList(); return list.Count == 0 ? null : list[Rnd.Int(list.Count)]; } public static string GenerateItemId() { var id = Generate(); if (id == null) { return null; } return $"bk:scourge_{id.Replace("bk:", "")}"; } public static List GenerateList() { var list = new List(); foreach (var s in Defined) { if (ShouldAppear(s)) { list.Add(s); } } return list; } } } ================================================ FILE: BurningKnight/entity/item/SingleChoiceStand.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.save; using BurningKnight.util; using Lens.entity; using Lens.util.camera; namespace BurningKnight.entity.item { public class SingleChoiceStand : ItemStand { public override void Init() { base.Init(); AlwaysActive = true; Subscribe(); } protected override string GetSprite() { return "single_stand"; } protected override bool CanInteract(Entity e) { return Item != null && base.CanInteract(e); } protected virtual void RemoveStands() { var rm = GetComponent().Room; if (rm == null) { return; } GlobalSave.Put("item_stolen", true); var it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it foreach (var s in it) { if (s is SingleChoiceStand ist) { if (s is HealChoiceStand) { AnimationUtil.Poof(ist.Center); ist.Done = true; } else if (ist.Item != null) { var i = ist.Item; ist.SetItem(null, this); i.Done = true; AnimationUtil.Poof(ist.Center); } } } Camera.Instance.Shake(10); } public override bool HandleEvent(Event e) { if (e is ItemTakenEvent ite && !(ite.Who is SingleChoiceStand || !(ite.Stand is SingleChoiceStand))) { var rm = GetComponent().Room; if (rm == null) { return false; } if (ite.Stand != this && ite.Stand.GetComponent().Room == rm) { RemoveStands(); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/SpawnMobsUse.cs ================================================ using System; using BurningKnight.assets.particle; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.item.use; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item { public class SpawnMobsUse : ItemUse { public int Count; private static Func CheckDistance(Entity entity) { return (x, y) => entity.DistanceTo(new Vector2(x * 16, y * 16)) > 32; } public override void Use(Entity entity, Item item) { if (!entity.TryGetComponent(out var r) || r.Room == null) { return; } var filter = CheckDistance(entity); MobRegistry.SetupForBiome(Run.Level.Biome.Id); for (var i = 0; i < Count; i++) { Timer.Add(() => { var mob = MobRegistry.Generate(); entity.Area.Add(mob); if (MobRegistry.FindFor(mob.GetType())?.NearWall ?? false) { mob.Center = r.Room.GetRandomFreeTileNearWall(filter) * 16; } else { mob.Center = r.Room.GetRandomFreeTile(filter) * 16; } var where = mob.Center; for (var j = 0; j < 8; j++) { var part = new ParticleEntity(Particles.Dust()); part.Position = where + Rnd.Vector(-8, 8); part.Particle.Scale = Rnd.Float(1f, 1.3f); part.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 40); Run.Level.Area.Add(part); part.Depth = 1; } Audio.PlaySfx("scroll"); }, (i - 1) * 0.2f); } } public override void Setup(JsonValue settings) { base.Setup(settings); Count = settings["count"].Int(1); } public static void RenderDebug(JsonValue root) { var v = root["count"].Int(1); if (ImGui.InputInt("Count", ref v)) { root["count"] = v; } } } } ================================================ FILE: BurningKnight/entity/item/Weapon.cs ================================================ namespace BurningKnight.entity.item { public class Weapon : Item { } } ================================================ FILE: BurningKnight/entity/item/WeaponType.cs ================================================ namespace BurningKnight.entity.item { // Keep in sync with the ItemEditor's names!! // Don't forget to update WeaponTypeHelper's switch blocks after changing this public enum WeaponType { Melee, Ranged, Magic, None } } ================================================ FILE: BurningKnight/entity/item/WeaponTypeHelper.cs ================================================ using System; namespace BurningKnight.entity.item { public static class WeaponTypeHelper { public static string GetPickupSfx(this WeaponType type) { switch (type) { case WeaponType.Melee: default: return "item_sword_pickup"; case WeaponType.Ranged: return "item_gun_pickup"; case WeaponType.Magic: return "item_magic_pickup"; } } public static string GetSwapSfx(this WeaponType type) { switch (type) { case WeaponType.Melee: default: return "item_sword_switch"; case WeaponType.Ranged: return "item_gun_switch"; case WeaponType.Magic: return "item_magic_switch"; } } } } ================================================ FILE: BurningKnight/entity/item/renderer/AngledRenderer.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.graphics; using Lens.input; using Lens.lightJson; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.item.renderer { public class AngledRenderer : ItemRenderer { public float Angle; public bool InvertBack; public float AddedAngle; public float SwingAngle; private double lastAngle; private float sx = 1; private float sy = 1; private float oy; private float ox; public override void Render(bool atBack, bool paused, float dt, bool shadow, int offset) { if (Hidden) { return; } var s = dt * 10f; sx += (1 - sx) * s; sy += (1 - sy) * s; ox += (-ox) * s; oy += (-oy) * s; var region = Item.Region; var owner = Item.Owner; var of = owner.GraphicsComponent.Flipped; var flipped = false; var angle = MathUtils.Mod((of ? -Angle : Angle) + (atBack ? ((InvertBack ? -1 : 1) * (of ? -Math.PI / 4 : Math.PI / 4)) : lastAngle), Math.PI * 2); var vf = angle > Math.PI * 0.5f && angle < Math.PI * 1.5f; if (!atBack && !paused && !shadow) { var to = owner.GetComponent().Aim; /*var dx = Nozzle.X - Origin.X; var dy = Nozzle.Y - Origin.Y; if (vf) { dy *= -1; } *var a = MathUtils.Angle(dx, dy) + lastAngle - AddedAngle - SwingAngle; var d = MathUtils.Distance(dx, dy); to -= MathUtils.CreateVector(a, d); owner.GetComponent().Aim = to;*/ lastAngle = MathUtils.LerpAngle(lastAngle, owner.AngleTo(to), dt * 24f); } if (atBack) { flipped = !flipped; } else { angle += (SwingAngle + AddedAngle) * (of ? -1 : 1); } var pos = new Vector2(owner.CenterX + (of ? -5 : 5), owner.CenterY + offset + (shadow ? owner.Height : 0)); var or = Origin + new Vector2(ox, oy); var sc = new Vector2(flipped ? -sx : sx, (shadow ^ vf) ? -sy : sy); var fangle = (float) angle * (shadow ? -1 : 1); if (!shadow && !atBack) { var dx = Nozzle.X - or.X; var dy = Nozzle.Y - or.Y; if (vf) { dy *= -1; } var a = MathUtils.Angle(dx, dy) + angle; var d = MathUtils.Distance(dx, dy); var aim = owner.GetComponent(); aim.Center = pos + MathUtils.CreateVector(a, d); d = (aim.Aim - pos).Length(); aim.RealAim = aim.Center + MathUtils.CreateVector(angle - AddedAngle - SwingAngle, d); } if (Item.Scourged) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ItemGraphicsComponent.ScourgedColor); foreach (var d in MathUtils.Directions) { Graphics.Render(region, pos + d, fangle, or, sc); } Shaders.End(); } Graphics.Render(region, pos, fangle, or, sc); } public override void OnUse() { base.OnUse(); sx = 0.3f; sy = 2f; ox = 8; } public override void Setup(JsonValue settings) { base.Setup(settings); InvertBack = settings["invert_back"].Bool(true); AddedAngle = settings["aa"].Number(0).ToRadians(); } public static void RenderDebug(string id, JsonValue parent, JsonValue root) { ItemRenderer.RenderDebug(id, parent, root); var invert = root["invert_back"].AsBoolean; if (ImGui.Checkbox("Invert back?", ref invert)) { root["invert_back"] = invert; } var min = (float) root["aa"].Number(0); if (ImGui.InputFloat("Added Angle", ref min)) { root["aa"] = min; } } } } ================================================ FILE: BurningKnight/entity/item/renderer/ItemRenderer.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.state; using ImGuiNET; using Lens.graphics; using Lens.lightJson; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.renderer { public class ItemRenderer { public Item Item; public Vector2 Origin; public Vector2 Nozzle; public bool Hidden; public virtual void Render(bool atBack, bool paused, float dt, bool shadow, int offset) { } public virtual void Setup(JsonValue settings) { Origin.X = settings["ox"].Number(0); Origin.Y = settings["oy"].Number(0); Nozzle.X = settings["nx"].Number(0); Nozzle.Y = settings["ny"].Number(0); } public virtual void OnUse() { } private static bool snapGrid = true; public static unsafe void RenderDebug(string id, JsonValue parent, JsonValue root) { if (ImGui.TreeNode("Origin")) { var v = new System.Numerics.Vector2((float) root["ox"].AsNumber * 3, (float) root["oy"].AsNumber * 3); var region = CommonAse.Items.GetSlice(id); var m = ImGui.GetScrollY(); var pos = ImGui.GetWindowPos() + ImGui.GetCursorPos() - new System.Numerics.Vector2(0, m); if (ImGui.IsMouseDown(1)) { v = ImGui.GetMousePos() - pos; if (!(v.X < 0) && !(v.Y < 0) && !(v.X > region.Width * 3) && !(v.Y > region.Height * 3)) { if (snapGrid) { v.X = (float) (Math.Floor(v.X / 3) * 3); v.Y = (float) (Math.Floor(v.Y / 3) * 3); } v.X = VelcroPhysics.Utilities.MathUtils.Clamp(v.X, 0, region.Width * 3); v.Y = VelcroPhysics.Utilities.MathUtils.Clamp(v.Y, 0, region.Height * 3); root["ox"] = v.X / 3f; root["oy"] = v.Y / 3f; } } ImGuiNative.ImDrawList_AddRect(ImGui.GetWindowDrawList(), pos - new System.Numerics.Vector2(1, 1), pos + new System.Numerics.Vector2(region.Width * 3 + 1, region.Height * 3 + 1), ColorUtils.WhiteColor.PackedValue, 0, 0, 1); ItemEditor.DrawItem(region); ImGuiNative.ImDrawList_AddCircleFilled(ImGui.GetWindowDrawList(), pos + v, 3, ColorUtils.WhiteColor.PackedValue, 8); v /= 3f; ImGui.Checkbox("Snap to grid", ref snapGrid); if (ImGui.InputFloat2("Origin", ref v)) { root["ox"] = v.X; root["oy"] = v.Y; } if (ImGui.Button("tx")) { root["ox"] = 0; } ImGui.SameLine(); if (ImGui.Button("ty")) { root["oy"] = 0; } if (ImGui.Button("cx")) { root["ox"] = region.Width / 2f; } ImGui.SameLine(); if (ImGui.Button("cy")) { root["oy"] = region.Height / 2f; } if (ImGui.Button("bx")) { root["ox"] = region.Width; } ImGui.SameLine(); if (ImGui.Button("by")) { root["oy"] = region.Height; } ImGui.TreePop(); } if (ImGui.TreeNode("Nozzle")) { var v = new System.Numerics.Vector2((float) root["nx"].AsNumber * 3, (float) root["ny"].AsNumber * 3); var region = CommonAse.Items.GetSlice(id); var m = ImGui.GetScrollY(); var pos = ImGui.GetWindowPos() + ImGui.GetCursorPos() - new System.Numerics.Vector2(0, m); if (ImGui.IsMouseDown(1)) { v = ImGui.GetMousePos() - pos; if (!(v.X < 0) && !(v.Y < 0) && !(v.X > region.Width * 3) && !(v.Y > region.Height * 3)) { if (snapGrid) { v.X = (float) (Math.Floor(v.X / 3) * 3); v.Y = (float) (Math.Floor(v.Y / 3) * 3); } v.X = VelcroPhysics.Utilities.MathUtils.Clamp(v.X, 0, region.Width * 3); v.Y = VelcroPhysics.Utilities.MathUtils.Clamp(v.Y, 0, region.Height * 3); root["nx"] = v.X / 3f; root["ny"] = v.Y / 3f; } } ImGuiNative.ImDrawList_AddRect(ImGui.GetWindowDrawList(), pos - new System.Numerics.Vector2(1, 1), pos + new System.Numerics.Vector2(region.Width * 3 + 1, region.Height * 3 + 1), ColorUtils.WhiteColor.PackedValue, 0, 0, 1); ItemEditor.DrawItem(region); ImGuiNative.ImDrawList_AddCircleFilled(ImGui.GetWindowDrawList(), pos + v, 3, ColorUtils.WhiteColor.PackedValue, 8); v /= 3f; ImGui.Checkbox("Snap to grid", ref snapGrid); if (ImGui.InputFloat2("Nozzle", ref v)) { root["nx"] = v.X; root["ny"] = v.Y; } if (ImGui.Button("tx")) { root["nx"] = 0; } ImGui.SameLine(); if (ImGui.Button("ty")) { root["ny"] = 0; } if (ImGui.Button("cx")) { root["nx"] = region.Width / 2f; } ImGui.SameLine(); if (ImGui.Button("cy")) { root["ny"] = region.Height / 2f; } if (ImGui.Button("bx")) { root["nx"] = region.Width; } ImGui.SameLine(); if (ImGui.Button("by")) { root["oy"] = region.Height; } ImGui.TreePop(); } } } } ================================================ FILE: BurningKnight/entity/item/renderer/MovingAngledRenderer.cs ================================================ using ImGuiNET; using Lens.lightJson; using Lens.util; using Lens.util.tween; namespace BurningKnight.entity.item.renderer { public class MovingAngledRenderer : AngledRenderer { public float MaxAngle; public float MinAngle; public bool Stay; public float SwingTime; public float ReturnTime; private bool stayed; public override void OnUse() { var task = Tween.To(stayed ? MinAngle : MaxAngle, SwingAngle, x => SwingAngle = x, SwingTime); if (!Stay) { task.OnEnd = () => { Tween.To(stayed ? MinAngle : MaxAngle, SwingAngle, x => SwingAngle = x, ReturnTime); }; } else { stayed = !stayed; } } public override void Setup(JsonValue settings) { base.Setup(settings); Stay = settings["stay"].Bool(false); MaxAngle = settings["max_angle"].Number(180).ToRadians(); MinAngle = settings["min_angle"].Number(0).ToRadians(); SwingTime = settings["st"].Number(0.1f); ReturnTime = settings["rt"].Number(0.2f); SwingAngle = MinAngle; } public static void RenderDebug(string id, JsonValue parent, JsonValue root) { AngledRenderer.RenderDebug(id, parent, root); var min = (float) root["min_angle"].Number(0); if (ImGui.InputFloat("Min Angle", ref min)) { root["min_angle"] = min; } var max = (float) root["max_angle"].Number(180); if (ImGui.InputFloat("Max Angle", ref max)) { root["max_angle"] = max; } var stay = root["stay"].AsBoolean; if (ImGui.Checkbox("Stay?", ref stay)) { root["stay"] = stay; } var st = (float) root["st"].Number(0.1f); if (ImGui.InputFloat("Swing Time", ref st)) { root["st"] = st; } if (!stay) { var rt = (float) root["rt"].Number(0.2f); if (ImGui.InputFloat("Return Time", ref rt)) { root["rt"] = rt; } } } } } ================================================ FILE: BurningKnight/entity/item/renderer/RendererRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.mod; using Lens.lightJson; namespace BurningKnight.entity.item.renderer { public static class RendererRegistry { public static Dictionary> DebugRenderers = new Dictionary>(); public static Dictionary Renderers = new Dictionary(); public static ItemRenderer Create(string id) { if (!Renderers.TryGetValue(id, out var renderer)) { return null; } return (ItemRenderer) Activator.CreateInstance(renderer); } public static void Register(Mod mod, Action renderer = null) where T : ItemRenderer { var type = typeof(T); var name = type.Name; var id = $"{mod?.Prefix ?? Mods.BurningKnight}:{(name.EndsWith("Renderer") ? name.Substring(0, name.Length - 8) : name)}"; Renderers[id] = type; if (renderer != null) { DebugRenderers[id] = renderer; } } private static void Register(Action renderer = null) where T : ItemRenderer { Register(null, renderer); } static RendererRegistry() { Register(AngledRenderer.RenderDebug); Register(MovingAngledRenderer.RenderDebug); Register(StickRenderer.RenderDebug); } } } ================================================ FILE: BurningKnight/entity/item/renderer/StickRenderer.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.component; using ImGuiNET; using Lens.graphics; using Lens.input; using Lens.lightJson; using Lens.util; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.item.renderer { public class StickRenderer : ItemRenderer { private double lastAngle; private Vector2 scale = Vector2.One; private bool horizontal; private float move; private float currentMove; private float moveTime; private float returnTime; public override void OnUse() { if (move > 0.1f) { Tween.To(move, currentMove, x => currentMove = x, moveTime).OnEnd = () => { Tween.To(0, currentMove, x => currentMove = x, returnTime); }; } else { scale.X = 1.4f; scale.Y = 0.3f; Tween.To(1, scale.X, x => scale.X = x, 0.2f); Tween.To(1, scale.Y, x => scale.Y = x, 0.2f); } } public override void Render(bool atBack, bool paused, float dt, bool shadow, int offset) { if (Hidden) { return; } var region = Item.Region; var owner = Item.Owner; if (!atBack && !paused && !shadow) { var to = owner.GetComponent().Aim; /*var dx = Nozzle.X - Origin.X; var dy = Nozzle.Y - Origin.Y; var a = MathUtils.Angle(dx, dy) + lastAngle; var d = MathUtils.Distance(dx, dy); to -= MathUtils.CreateVector(a, d);*/ lastAngle = MathUtils.LerpAngle(lastAngle, owner.AngleTo(to) + Math.PI * 0.5f, dt * 24f); } var angle = atBack ? (float) Math.PI * (owner.GraphicsComponent.Flipped ? 0.25f : -0.25f) : (float) lastAngle; if (horizontal) { angle -= (float) Math.PI * 0.5f; } var pos = new Vector2( owner.CenterX + (owner.GraphicsComponent.Flipped ? -5 : 5) + (horizontal ? 0 : (region.Width / 2f) * (owner.GraphicsComponent.Flipped ? -1 : 1)), owner.CenterY + offset + (shadow ? owner.Height : 0) ); var or = Origin + new Vector2(0, currentMove); var fangle = shadow ? -angle : angle; var sc = new Vector2(scale.X, shadow ? -scale.Y : scale.Y); if (!shadow && !atBack) { var dx = Nozzle.X - or.X; var dy = Nozzle.Y - or.Y; var a = MathUtils.Angle(dx, dy) + angle; var d = MathUtils.Distance(dx, dy); var aim = owner.GetComponent(); aim.Center = pos + MathUtils.CreateVector(a, d); d = (aim.Aim - pos).Length(); aim.RealAim = aim.Center + MathUtils.CreateVector(angle - (horizontal ? 0 : Math.PI / 2), d); } if (Item.Scourged) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ItemGraphicsComponent.ScourgedColor); foreach (var d in MathUtils.Directions) { Graphics.Render(region, pos + d, fangle, or, sc); } Shaders.End(); } Graphics.Render(region, pos, fangle, or, sc); } public override void Setup(JsonValue settings) { base.Setup(settings); horizontal = settings["h"]; move = settings["mv"].Number(0); moveTime = settings["mt"].Number(0.1f); returnTime = settings["rt"].Number(0.2f); } public static void RenderDebug(string id, JsonValue parent, JsonValue root) { ItemRenderer.RenderDebug(id, parent, root); var h = root["h"].Bool(false); if (ImGui.Checkbox("Horizontal", ref h)) { root["h"] = h; } var mv = (float) root["mv"].Number(0); if (ImGui.InputFloat("Move", ref mv)) { root["mv"] = mv; } var mt = (float) root["mt"].Number(0.1f); if (ImGui.InputFloat("Move Time", ref mt)) { root["mt"] = mt; } var rt = (float) root["rt"].Number(0.2f); if (ImGui.InputFloat("Return Time", ref rt)) { root["rt"] = rt; } } } } ================================================ FILE: BurningKnight/entity/item/stand/ActiveStand.cs ================================================ using BurningKnight.assets.items; namespace BurningKnight.entity.item.stand { public class ActiveStand : EmeraldStand { protected override bool ApproveItem(ItemData item) { return item.Type == ItemType.Active; } } } ================================================ FILE: BurningKnight/entity/item/stand/ArtifactStand.cs ================================================ using BurningKnight.assets.items; namespace BurningKnight.entity.item.stand { public class ArtifactStand : EmeraldStand { protected override bool ApproveItem(ItemData item) { return item.Type == ItemType.Artifact; } } } ================================================ FILE: BurningKnight/entity/item/stand/BkStand.cs ================================================ using System; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.bk; using BurningKnight.entity.events; using BurningKnight.entity.fx; using BurningKnight.level; using BurningKnight.level.entities.decor; using BurningKnight.level.tile; using BurningKnight.state; using Lens; using Lens.entity; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.stand { public class BkStand : ItemStand { private bool triggered; private bool did; private float t; public override void AddComponents() { base.AddComponents(); AlwaysActive = true; } public override void Update(float dt) { base.Update(dt); if (!did && triggered) { Camera.Instance.Shake(0.5f); t += dt; if (t >= 1f) { did = true; /*var torches = GetComponent().Room.Tagged[Tags.Torch]; var target = new Vector2(CenterX, Y - 16); foreach (var t in torches) { var tr = (Torch) t; tr.XSpread = 1; tr.On = true; tr.Target = target; } Timer.Add(() => { foreach (var t in torches) { t.Done = true; } }, 1f); Timer.Add(() => { var bk = new entity.creature.bk.BurningKnight(); Area.Add(bk); bk.Center = target; Camera.Instance.Shake(10); foreach (var t in torches) { t.Done = true; } Done = true; }, 2f);*/ } } } public override bool HandleEvent(Event e) { if (e is ItemTakenEvent && !triggered) { Timer.Add(() => { triggered = true; }, 1f); Camera.Instance.Shake(12); var xx = (int) Math.Floor(CenterX / 16) * 16; var xy = (int) Math.Floor(CenterY / 16) * 16; var p = 32; /*var torches = GetComponent().Room.Tagged[Tags.Torch]; foreach (var t in torches) { ((Torch) t).On = false; } Timer.Add(() => { foreach (var t in torches) { var tr = (Torch) t; tr.On = true; tr.XSpread = 0.1f; } }, 3f);*/ for (var x = xx - p; x < xx + Width + p; x += 16) { for (var i = 0; i < Rnd.Int(3, 9); i++) { Area.Add(new FireParticle { Position = new Vector2(x + Rnd.Float(-2, 18), xy - p + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new FireParticle { Position = new Vector2(x + Rnd.Float(-2, 18), xy + Height + p - 16 + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); } } for (var y = xy; y < xy + Height; y += 16) { for (var i = 0; i < Rnd.Int(3, 9); i++) { Area.Add(new FireParticle { Position = new Vector2(xx + Rnd.Float(-2, 18) - p, y + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); Area.Add(new FireParticle { Position = new Vector2(xx + Width + p - 16 + Rnd.Float(-2, 18), y + Rnd.Float(-2, 18)), Delay = Rnd.Float(0.5f), XChange = 0.1f, Scale = 0.3f, Vy = 8, T = 0.5f, B = 0 }); } } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/stand/BoxyStand.cs ================================================ using System; using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.item.stand { public class BoxyStand : CustomStand { protected override string GetIcon() { return "deal_key"; } protected override string GetSprite() { return "boxy_stand"; } public override ItemPool GetPool() { return ItemPool.Roger; } protected override int CalculatePrice() { return (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 2); } protected override bool TryPay(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.Keys < Price) { return false; } component.Keys -= Price; return true; } protected override bool HasEnoughToPay(Entity p) { return p.GetComponent().Keys >= Price; } } } ================================================ FILE: BurningKnight/entity/item/stand/CustomStand.cs ================================================ using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.entity; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.stand { public class CustomStand : ShopStand { private TextureRegion icon; private float priceWidth; private float iconY; protected virtual string GetIcon() { return "deal_heart"; } protected override void CalculatePriceSize() { base.CalculatePriceSize(); PriceString = $"{Price}"; priceWidth = Font.Small.MeasureString(PriceString).Width; PriceX = (Width - priceWidth - icon.Width - 2) / 2f; iconY = (7 - icon.Height) / 2; } public override void Init() { base.Init(); icon = CommonAse.Ui.GetSlice(GetIcon()); } protected override void RenderPrice() { if (HasSale) { Graphics.Color = Palette.Default[35]; } var r = GetComponent().Room; foreach (var p in r.Tagged[Tags.Player]) { if (!HasEnoughToPay(p)) { Graphics.Color *= 0.6f; break; } } Graphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14)); Graphics.Color = ColorUtils.WhiteColor; Graphics.Render(icon, Position + new Vector2(PriceX + priceWidth + 2, 17 + iconY)); } protected virtual bool HasEnoughToPay(Entity p) { return p.GetComponent().Bombs >= Price; } } } ================================================ FILE: BurningKnight/entity/item/stand/DarkMageStand.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.stand { public class DarkMageStand : ShopStand { private TextureRegion heart; private float priceWidth; private Entity payer; private Item takenItem; private int lastPrice; protected override int CalculatePrice() { return (int) Math.Max(1, PriceCalculator.GetModifier(Item)); } protected override string GetSprite() { return "dm_stand"; } public override void Init() { base.Init(); OnSale = false; heart = CommonAse.Ui.GetSlice("deal_heart"); Subscribe(); Subscribe(); } protected override void CalculatePriceSize() { PriceString = $"{Price}"; priceWidth = Font.Small.MeasureString(PriceString).Width; PriceX = (Width - priceWidth - heart.Width - 2) / 2f; } protected override void RenderPrice() { if (HasSale) { Graphics.Color = Palette.Default[35]; } var r = GetComponent().Room; foreach (var p in r.Tagged[Tags.Player]) { if (p.GetComponent().MaxHealth + p.GetComponent().Total < Price * 2) { Graphics.Color *= 0.6f; break; } } Graphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14)); Graphics.Color = ColorUtils.WhiteColor; Graphics.Render(heart, Position + new Vector2(PriceX + priceWidth + 2, 17)); } protected override bool TryPay(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.MaxHealth + entity.GetComponent().Total < Price * 2) { return false; } payer = entity; lastPrice = Price * 2; takenItem = Item; var stats = entity.GetComponent(); stats.TookDeal = true; stats.HeartsPayed += Price; Achievements.Unlock("bk:deal"); return true; } public override bool HandleEvent(Event e) { if ((e is ItemUsedEvent ite && ite.Who == payer && ite.Item == takenItem) || (e is ItemAddedEvent iae && iae.Who == payer && iae.Item == takenItem)) { var component = payer.GetComponent(); var hearts = payer.GetComponent(); var a = Math.Min(component.MaxHealth, lastPrice); if (a > 0) { component.ModifyHealth(-a, this, DamageType.Custom); if (!component.LastModifiedHearts) { component.MaxHealth -= a; } } var d = lastPrice - a; if (d > 0) { hearts.Hurt(-d, this, DamageType.Custom); } TextParticle.Add(payer, Locale.Get("max_hp"), lastPrice, true, true); payer = null; takenItem = null; } return base.HandleEvent(e); } public override ItemPool GetPool() { return ItemPool.OldMan; } } } ================================================ FILE: BurningKnight/entity/item/stand/GarderobeStand.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.save; using BurningKnight.util; using Lens.entity; namespace BurningKnight.entity.item.stand { public class GarderobeStand : ItemStand { public static List AlreadyOnStand = new List(); public GarderobeStand() { dontSaveItem = true; } public override void Destroy() { base.Destroy(); if (Item != null) { AlreadyOnStand.Remove(Item.Id); } } protected override string GetSprite() { return "gobetta_stand"; } public override void Init() { base.Init(); var item = PickItem(); if (item != null) { SetItem(item, null); } } public void UpdateItem() { if (Item != null) { return; } var item = PickItem(); if (item != null) { SetItem(item, null); } } protected override bool CanInteract(Entity e) { return item != null && base.CanInteract(e); } protected override bool CanTake(Entity entity) { if (!base.CanTake(entity)) { return false; } var ht = entity.GetComponent(); var old = ht.Item; ht.Set(item, true); item = null; SetItem(old, entity); return false; } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); Achievements.Unlock("bk:fancy_hat"); } private Item PickItem() { var items = new List(); foreach (var i in Items.Datas.Values) { if (i.Type == ItemType.Hat && GlobalSave.GetString("hat") != i.Id && (i.Id == "bk:no_hat" || GlobalSave.IsTrue(i.Id)) && !AlreadyOnStand.Contains(i.Id)) { items.Add(i); } } if (items.Count == 0) { return null; } items.Sort((a, b) => a.UnlockPrice.CompareTo(b.UnlockPrice)); var id = items[0].Id; AlreadyOnStand.Add(id); return Items.CreateAndAdd(id, Area); } } } ================================================ FILE: BurningKnight/entity/item/stand/GobettaStand.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.state; using Lens.entity; using Lens.util.timer; namespace BurningKnight.entity.item.stand { public class GobettaStand : ShopStand { protected override string GetSprite() { return "gobetta_stand"; } public override ItemPool GetPool() { return ItemPool.Gobetta; } protected override int CalculatePrice() { return (int) Math.Max(1, (base.CalculatePrice() * 0.5f)); } protected override bool TryPay(Entity entity) { if (base.TryPay(entity)) { var scourge = Scourge.GenerateItemId(); if (scourge != null) { Timer.Add(() => { entity.GetComponent().Pickup(Items.CreateAndAdd(scourge, entity.Area)); }, 2f); } return true; } return false; } } } ================================================ FILE: BurningKnight/entity/item/stand/GrannyStand.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.util; using Lens.entity; using Lens.util.camera; namespace BurningKnight.entity.item.stand { public class GrannyStand : ItemStand { protected override string GetSprite() { return "granny_stand"; } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); var rm = GetComponent().Room; if (rm == null) { return; } var it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it foreach (var s in it) { if (s != this && s is GrannyStand ist && ist.Item != null) { ist.Item.Done = true; ist.Done = true; AnimationUtil.Poof(ist.Center); } } Done = true; Camera.Instance.Shake(10); Achievements.Unlock("bk:grannys_gift"); } public override ItemPool GetPool() { return ItemPool.Granny; } } } ================================================ FILE: BurningKnight/entity/item/stand/HatStand.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.save; using Lens.entity; using Lens.util; namespace BurningKnight.entity.item.stand { public class HatStand : EmeraldStand { protected override bool ApproveItem(ItemData item) { return item.Type == ItemType.Hat; } protected override void DoStuff() { base.DoStuff(); foreach (var i in Area.Tagged[Tags.Item].ToArray()) { if (i is GarderobeStand gs) { gs.UpdateItem(); } } CheckHats(); } public static void CheckHats() { if (Achievements.Get("bk:fashion_matters2").Unlocked) { return; } var total = 0; var progress = 0; foreach (var i in Items.Datas.Values) { if (i.Type == ItemType.Hat && i.Id != "bk:no_hat") { total++; if (GlobalSave.IsTrue(i.Id)) { progress++; } } } if (progress > 0) { Achievements.Unlock("bk:fancy_hat"); } Log.Info($"Fashion matters progress: {progress}/{total}"); Achievements.SetProgress("bk:fashion_matters2", progress, total); } } } ================================================ FILE: BurningKnight/entity/item/stand/HealChoiceStand.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using Lens.assets; using Lens.entity; namespace BurningKnight.entity.item.stand { public class HealChoiceStand : SingleChoiceStand { protected override string GetSprite() { return "health_stand"; } protected virtual string GetSfx() { return "item_heart"; } protected override bool CanInteract(Entity e) { return true; } protected virtual void Heal(Entity entity) { var h = entity.GetComponent(); h.ModifyHealth(h.MaxHealth, this); } protected override bool Interact(Entity entity) { Heal(entity); RemoveStands(); Done = true; AnimationUtil.Poof(Center); Audio.PlaySfx(GetSfx()); return true; } } } ================================================ FILE: BurningKnight/entity/item/stand/HealthStand.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.stand { public class HealthStand : ItemStand { protected override string GetSprite() { return "health_stand"; } protected override bool CanInteract(Entity e) { if (Item == null) { return false; } return base.CanInteract(e); } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); var h = who.GetComponent(); h.ModifyHealth(h.MaxHealth, this); TextParticle.Add(who, "HP", h.MaxHealth, true); } } } ================================================ FILE: BurningKnight/entity/item/stand/ItemStand.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.item.stand { public class ItemStand : Prop, CollisionFilterEntity { private static TextureRegion itemShadow; private static TextureRegion standShadow; private static Vector2 shadowOffset = new Vector2(3, 3); protected Item item; public Item Item => item; public bool Hidden; public bool ShouldCollide(Entity entity) { return !Hidden; } public override void Init() { base.Init(); if (itemShadow == null) { itemShadow = CommonAse.Props.GetSlice("item_shadow"); standShadow = CommonAse.Props.GetSlice("stand_shadow"); } } protected virtual void OnTake(Item item, Entity who) { } public virtual void SetItem(Item i, Entity entity, bool remove = true) { if (item == i) { return; } if (item != null) { if (remove) { item.AddDroppedComponents(); item.RemoveComponent(); } HandleEvent(new ItemTakenEvent { Item = item, Who = entity, Stand = this }); OnTake(item, entity); } item = i; if (item != null) { item.RemoveDroppedComponents(); if (item.HasComponent()) { item.RemoveComponent(); } item.AddComponent(new OwnerComponent(this)); item.CenterX = CenterX; item.Bottom = Y + 6; item.AutoPickup = false; HandleEvent(new ItemPlacedEvent { Item = item, Who = entity, Stand = this }); } } public ItemStand() { Width = 14; Height = 14; } public override void Update(float dt) { base.Update(dt); if (item != null) { item.Center = Center; if (item.Done) { item = null; } } } public override void AddComponents() { base.AddComponents(); var g = new SliceComponent("props", GetSprite()); AddComponent(g); g.SetOwnerSize(); AddTag(Tags.Item); var body = new RectBodyComponent(0, 4, 14, 10); AddComponent(body); body.Body.Mass = 100000000f; AddComponent(new SensorBodyComponent(-2, -2, Width + 4, Height + 4, BodyType.Static)); AddComponent(new InteractableComponent(Interact) { CanInteract = CanInteract, OnStart = OnInteractionStart }); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new RoomComponent()); } protected virtual string GetSprite() { return "slab_a"; } private void RenderShadow() { if (!Hidden) { Graphics.Render(standShadow, Position + new Vector2(0, Height)); } } protected virtual bool CanTake(Entity entity) { return true; } protected virtual bool Interact(Entity entity) { if (Item != null && Item.Masked && Run.Depth < 1) { return false; } if (entity.TryGetComponent(out var inventory)) { if (item != null) { if (CanTake(entity)) { var i = item; var remove = false; if (this is GarderobeStand) { return true; } else if (this is PermanentStand && Item != null && Item.Type == ItemType.Weapon) { var c = entity.GetComponent(); var item = c.Item; c.Set(Items.CreateAndAdd(Item.Id, Area), false); Audio.PlaySfx("item_pickup"); if (item != null) { item.Done = true; } return true; } else if (this is PermanentStand && Item != null && Item.Type == ItemType.Active) { var c = entity.GetComponent(); var item = c.Item; c.Set(Items.CreateAndAdd(Item.Id, Area), false); Audio.PlaySfx("item_pickup"); if (item != null) { item.Done = true; } return true; } else if (this is LampStand && Item != null && Item.Type == ItemType.Lamp) { var c = entity.GetComponent(); var item = c.Item; c.Set(Items.CreateAndAdd(Item.Id, Area), false); Audio.PlaySfx("item_pickup"); if (item != null) { item.Done = true; } return true; } else { SetItem(null, entity, false); remove = true; } if (!inventory.Pickup(i) && remove) { SetItem(i, null, false); } } return this is HatStand || this is ShopStand || Run.Depth == -2; } else if (!(this is ShopStand) && entity.TryGetComponent(out var weapon) && weapon.Item != null) { if (weapon.Item.Scourged) { AnimationUtil.ActionFailed(); } else { SetItem(weapon.Drop(), entity); weapon.RequestSwap(); } return true; } } return true; } private void OnInteractionStart(Entity entity) { if (item != null && entity is LocalPlayer) { if (item.AutoPickup) { item.OnInteractionStart(entity); item = null; } else if (Run.Depth != -2) { Engine.Instance.State.Ui.Add(new ItemPickupFx(item)); } } } protected virtual bool CanInteract(Entity e) { return !Hidden && (Item != null || Run.Depth != -2); } public override void Render() { if (Hidden || !TryGetComponent(out var component)) { return; } var cursed = item != null && item.Scourged; var interact = component.OutlineAlpha > 0.05f; var renderOutline = interact || cursed; if (item == null && renderOutline) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(component.OutlineAlpha); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); foreach (var d in MathUtils.Directions) { Graphics.Render(((SliceComponent) GraphicsComponent).Sprite, Position + d); } Shaders.End(); } GraphicsComponent.Render(false); if (item == null) { return; } Graphics.Color = Level.ShadowColor; Graphics.Render(itemShadow, Position + shadowOffset); Graphics.Color = ColorUtils.WhiteColor; var t = item.Animation == null ? item.GetComponent().T : 0; var angle = (float) Math.Cos(t * 3f) * 0.4f; var region = item.Region; var animated = item.Animation != null; var pos = item.Center + new Vector2(0, (animated ? 0 : (float) (Math.Sin(t * 3f) * 0.5f + 0.5f) * -5.5f - 3) - 5.5f); if (renderOutline) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(cursed ? 1f : component.OutlineAlpha); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(!cursed ? ColorUtils.White : ColorUtils.Mix(ItemGraphicsComponent.ScourgedColor, ColorUtils.White, component.OutlineAlpha)); foreach (var d in MathUtils.Directions) { Graphics.Render(region, pos + d, animated ? 0 : angle, region.Center); } Shaders.End(); } if (animated) { Graphics.Render(region, pos, 0, region.Center); } else { if (item.Masked) { Graphics.Color = ItemGraphicsComponent.MaskedColor; Graphics.Render(region, pos, angle, region.Center); Graphics.Color = ColorUtils.WhiteColor; } else { var shader = Shaders.Item; Shaders.Begin(shader); shader.Parameters["time"].SetValue(t * 0.1f); shader.Parameters["size"].SetValue(ItemGraphicsComponent.FlashSize); Graphics.Render(region, pos, angle, region.Center); Shaders.End(); } } } protected bool dontSaveItem; public override void Load(FileReader stream) { base.Load(stream); if (dontSaveItem) { return; } if (stream.ReadBoolean()) { var item = new Item(); Area.Add(item, false); item.Load(stream); item.LoadedSelf = false; item.PostInit(); SetItem(item, null); } } public override void Save(FileWriter stream) { base.Save(stream); if (!dontSaveItem) { stream.WriteBoolean(item != null); item?.Save(stream); } } protected string debugItem = ""; public override void RenderImDebug() { if (ImGui.InputText("Item", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) { var item = Item; SetItem(Items.CreateAndAdd(debugItem, Area), null); if (item != null) { item.Done = true; } } } public virtual ItemPool GetPool() { return ItemPool.Treasure; } } } ================================================ FILE: BurningKnight/entity/item/stand/LampStand.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.entity.creature.npc; using BurningKnight.entity.events; using BurningKnight.save; using BurningKnight.ui.dialog; using BurningKnight.util; using Lens; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.stand { public class LampStand : ItemStand { public static List AlreadyOnStand = new List(); public LampStand() { ShowUnlocked = true; dontSaveItem = true; } public override void AddComponents() { base.AddComponents(); t = Rnd.Float(6); AddComponent(new LightComponent(this, 32f, new Color(1f, 0.8f, 0.3f, 1f))); } public override void PostInit() { base.PostInit(); Check(); Subscribe(); } private void Check() { if (Item != null) { return; } var item = PickItem(); if (item != null) { SetItem(item, null); Hidden = false; } else if (!Engine.EditingLevel) { Hidden = true; } } public override void Destroy() { base.Destroy(); if (Item != null) { AlreadyOnStand.Remove(Item.Id); } } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); AlreadyOnStand.Remove(item.Id); } protected override string GetSprite() { return "lamp_stand"; } protected virtual bool ApproveItem(ItemData item) { return item.Type == ItemType.Lamp && item.Id != "bk:no_lamp"; } protected bool ShowUnlocked = true; private Item PickItem() { var items = new List(); foreach (var i in Items.Datas.Values) { if (ApproveItem(i) && !AlreadyOnStand.Contains(i.Id) && GlobalSave.IsTrue(i.Id)) { items.Add(i); } } if (items.Count == 0) { return null; } var id = items[0].Id; AlreadyOnStand.Add(id); return Items.CreateAndAdd(id, Area); } protected override bool CanInteract(Entity e) { return Item != null; } private float t; public override void Update(float dt) { base.Update(dt); t += dt; GetComponent().Light.Radius = 32f + (float) Math.Cos(t) * 6; } public override bool HandleEvent(Event e) { if (e is Item.UnlockedEvent) { Check(); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/stand/LampUnlockStand.cs ================================================ using BurningKnight.assets.items; using BurningKnight.save; using BurningKnight.util; using Lens; using Lens.entity; namespace BurningKnight.entity.item.stand { public class LampUnlockStand : ItemStand { public override void PostInit() { base.PostInit(); CheckHidden(); } protected override string GetSprite() { return "single_stand"; } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); Items.Unlock(item.Id); CheckHidden(); } public void CheckHidden() { if (!Engine.EditingLevel && (Item == null || GlobalSave.IsTrue(Item.Id))) { Hidden = true; AnimationUtil.Poof(Center); } else { Hidden = false; } } } } ================================================ FILE: BurningKnight/entity/item/stand/PermanentStand.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.events; using ImGuiNET; using Lens.entity; using Lens.util; using Lens.util.file; namespace BurningKnight.entity.item.stand { public class PermanentStand : ItemStand { protected string SavedItem; public override void PostInit() { base.PostInit(); if (SavedItem == null) { return; } if (Item != null) { if (Item.Id == SavedItem) { return; } Item.Done = true; } debugItem = SavedItem; SetItem(Items.CreateAndAdd(SavedItem, Area), null); } public override void SetItem(Item i, Entity entity, bool remove = true) { base.SetItem(i, entity, remove); Item?.CheckMasked(); } public override void RenderImDebug() { if (ImGui.InputText("Item", ref debugItem, 128, ImGuiInputTextFlags.EnterReturnsTrue)) { if (Item != null) { Item.Done = true; } SetItem(Items.CreateAndAdd(debugItem, Area), null); SavedItem = debugItem; } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteString(SavedItem); } public override void Load(FileReader stream) { base.Load(stream); SavedItem = stream.ReadString(); } } } ================================================ FILE: BurningKnight/entity/item/stand/RogerStand.cs ================================================ using System; using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.item.stand { public class RogerStand : CustomStand { protected override string GetIcon() { return "deal_bomb"; } protected override string GetSprite() { return "roger_stand"; } public override ItemPool GetPool() { return ItemPool.Roger; } protected override int CalculatePrice() { return (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 2); } protected override bool TryPay(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.Bombs < Price) { return false; } component.Bombs -= Price; return true; } } } ================================================ FILE: BurningKnight/entity/item/stand/ScourgedStand.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.util; using Lens.entity; using Lens.util.camera; namespace BurningKnight.entity.item.stand { public class ScourgedStand : ItemStand { protected override string GetSprite() { return "scourge_stand"; } public override void Init() { base.Init(); AlwaysActive = true; Subscribe(); } protected override bool CanInteract(Entity e) { return Item != null && base.CanInteract(e); } public override bool HandleEvent(Event e) { if (e is ItemTakenEvent ite && !(ite.Who is ScourgedStand || !(ite.Stand is ScourgedStand))) { var rm = GetComponent().Room; if (ite.Stand != this && ite.Stand.GetComponent().Room == rm) { var it = rm.Tagged[Tags.Item].ToArray(); // Copy it to prevent exceptions while modifying it foreach (var s in it) { if (s is ScourgedStand ist && ist.Item != null) { var i = ist.Item; ist.SetItem(null, this); i.Done = true; AnimationUtil.Poof(ist.Center); } } Camera.Instance.Shake(10); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/stand/ShieldChoiceStand.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.stand { public class ShieldChoiceStand : HealChoiceStand { protected override string GetSprite() { return "shield_stand"; } protected override string GetSfx() { return "item_shield"; } protected override void Heal(Entity entity) { for (var i = 0; i < 3; i++) { entity.GetComponent().Pickup(Items.CreateAndAdd("bk:shield", entity.Area)); } } } } ================================================ FILE: BurningKnight/entity/item/stand/ShopStand.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.achievements; using BurningKnight.entity.component; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.state; using BurningKnight.ui.dialog; using BurningKnight.util; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.graphics; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.stand { public class ShopStand : ItemStand { public bool Sells = true; public bool Free; protected int Price; protected string PriceString; protected float PriceX; protected bool OnSale; protected bool HasSale; public override void Init() { base.Init(); OnSale = Rnd.Chance(10 + Run.Luck * 2); } public override ItemPool GetPool() { return ItemPool.Shop; } protected override string GetSprite() { return "shop_stand"; } protected override bool CanInteract(Entity e) { return Item != null && base.CanInteract(e); } protected virtual bool TryPay(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.Coins < Price) { return false; } component.Coins -= Price; Achievements.Unlock("bk:shopper"); return true; } private bool OkToBuy(Entity entity) { if (Item.Type == ItemType.Active) { var item = entity.GetComponent().Item; if (item != null && item.Scourged) { return false; } } else if (Item.Type == ItemType.Weapon) { var item = entity.GetComponent().Item; if (item != null && item.Scourged) { item = entity.GetComponent().Item; if (item != null && item.Scourged) { return false; } } } return true; } protected override bool CanTake(Entity entity) { if (!base.CanTake(entity)) { return false; } if (!Sells || Free) { return true; } if (!OkToBuy(entity)) { AnimationUtil.ActionFailed(); entity.GetComponent().StartAndClose($"~~{Locale.Get("scourged")}~~", 2); return false; } else if (!TryPay(entity)) { AnimationUtil.ActionFailed(); foreach (var n in GetComponent().Room.Tagged[Tags.Npc]) { if (n is ShopNpc s) { n.GetComponent().StartAndClose(s.GetFailDialog(), 3); break; } else if (n is ShopKeeper) { n.GetComponent().StartAndClose($"shopkeeper_{Rnd.Int(15, 18)}", 3); break; } } return false; } Sells = false; Audio.PlaySfx("item_purchase"); return true; } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); if (!Free) { who.HandleEvent(new ItemBoughtEvent { Item = item, Who = who, Stand = this }); } } public override void Render() { base.Render(); if (Item != null && Sells && !Free) { RenderPrice(); } } protected virtual void RenderPrice() { if (HasSale) { Graphics.Color = Palette.Default[35]; if (Price == 0) { HasSale = false; OnSale = false; Price = 1; } } var r = GetComponent().Room; foreach (var p in r.Tagged[Tags.Player]) { if (p.GetComponent().Coins < Price) { Graphics.Color *= 0.6f; break; } } Graphics.Print(PriceString, Font.Small, Position + new Vector2(PriceX, 14)); Graphics.Color = ColorUtils.WhiteColor; } protected virtual int CalculatePrice() { return PriceCalculator.Calculate(Item); } public void Recalculate() { if (Free) { Price = 0; return; } if (Item == null) { Price = 0; Sells = false; return; } Sells = true; Price = CalculatePrice(); if (OnSale) { Price = (int) Math.Floor(Price * 0.5f); HasSale = true; } var r = GetComponent().Room; if (r != null) { var e = new ItemPriceCalculationEvent { Stand = this, Item = Item }; foreach (var p in r.Tagged[Tags.Player]) { p.HandleEvent(e); } if (e.Percent > 0.001f) { Price = (int) Math.Floor(Price * Math.Max(0f, (1f - e.Percent * 0.01f))); HasSale = true; } if (r.Tagged[Tags.ShopKeeper].Count > 0) { var min = sbyte.MaxValue; foreach (var s in r.Tagged[Tags.ShopKeeper]) { min = Math.Min(min, ((ShopKeeper) s).Mood); } Price = Math.Max(Price, Price - (min - 3)); } } CalculatePriceSize(); } public override bool HandleEvent(Event e) { if (e is ItemPlacedEvent || (e is RoomChangedEvent rce && rce.Who is Player && rce.New == GetComponent().Room)) { Recalculate(); } return base.HandleEvent(e); } protected virtual void CalculatePriceSize() { PriceString = $"{Price}"; PriceX = (Width - Font.Small.MeasureString(PriceString).Width) / 2f; } public override void RenderImDebug() { base.RenderImDebug(); if (ImGui.InputInt("Price", ref Price)) { CalculatePriceSize(); } } public override void Load(FileReader stream) { base.Load(stream); OnSale = stream.ReadBoolean(); Free = stream.ReadBoolean(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(OnSale); stream.WriteBoolean(Free); } } } ================================================ FILE: BurningKnight/entity/item/stand/SnekStand.cs ================================================ namespace BurningKnight.entity.item.stand { public class SnekStand : ShopStand { protected override string GetSprite() { return "snek_stand"; } public override ItemPool GetPool() { return ItemPool.Snek; } } } ================================================ FILE: BurningKnight/entity/item/stand/TrashGoblinStand.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.npc.dungeon; using BurningKnight.util; using Lens.entity; namespace BurningKnight.entity.item.stand { public class TrashGoblinStand : ItemStand { protected override string GetSprite() { return "scourge_stand"; } protected override void OnTake(Item item, Entity who) { base.OnTake(item, who); foreach (var n in GetComponent().Room.Tagged[Tags.Npc]) { if (n is TrashGoblin g) { g.Free(); AnimationUtil.Poof(Center); Done = true; return; } } } } } ================================================ FILE: BurningKnight/entity/item/stand/VampireStand.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.item.stand { public class VampireStand : CustomStand { private Entity payer; private Item takenItem; private int lastPrice; public override void Init() { base.Init(); Subscribe(); Subscribe(); } protected override string GetIcon() { return "deal_hp"; } protected override string GetSprite() { return "vampire_stand"; } public override ItemPool GetPool() { return ItemPool.Vampire; } protected override int CalculatePrice() { return (int) Math.Max(1, PriceCalculator.GetModifier(Item) * 1.5f); } protected override bool TryPay(Entity entity) { if (!entity.TryGetComponent(out var component)) { return false; } if (component.Health < Price * 2) { return false; } payer = entity; lastPrice = Price * 2; takenItem = Item; return true; } public override bool HandleEvent(Event e) { if ((e is ItemUsedEvent ite && ite.Who == payer && ite.Item == takenItem) || (e is ItemAddedEvent iae && iae.Who == payer && iae.Item == takenItem)) { var component = payer.GetComponent(); component.ModifyHealth(-lastPrice, this, DamageType.Custom); payer = null; takenItem = null; } return base.HandleEvent(e); } protected override bool HasEnoughToPay(Entity p) { return p.GetComponent().Health >= Price * 2; } } } ================================================ FILE: BurningKnight/entity/item/stand/WeaponStand.cs ================================================ using BurningKnight.assets.items; namespace BurningKnight.entity.item.stand { public class WeaponStand : EmeraldStand { protected override bool ApproveItem(ItemData item) { return item.Type == ItemType.Weapon; } } } ================================================ FILE: BurningKnight/entity/item/use/AddHitboxUse.cs ================================================ using BurningKnight.physics; using Lens.entity; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; using VelcroPhysics.Factories; using VelcroPhysics.Shared; namespace BurningKnight.entity.item.use { public class AddHitboxUse : ItemUse { private Body body; public override void Use(Entity entity, Item item) { base.Use(entity, item); body = BodyFactory.CreateBody(Physics.World, Vector2.Zero, 0, BodyType.Dynamic); body.FixedRotation = true; body.UserData = this; body.LinearDamping = 0; var r = Item.Region; var w = r.Width; var h = r.Height; var x = -r.Width / 2; var y = 0; FixtureFactory.AttachPolygon(new Vertices(4) { new Vector2(x, y), new Vector2(x + w, y), new Vector2(x + w, y + h), new Vector2(x, y + h) }, 1f, body).IsSensor = true; body.Position = entity.Center; } public override void Destroy() { base.Destroy(); if (body != null) { Physics.RemoveBody(body); body = null; } } } } ================================================ FILE: BurningKnight/entity/item/use/AddTorchUse.cs ================================================ using BurningKnight.assets.lighting; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using Lens.entity; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class AddTorchUse : ItemUse { private bool isOut; private float lastFlame; public override void Pickup(Entity entity, Item item) { isOut = true; // new Color(1f, 0.8f, 0.4f, 1f)) item.AddComponent(new LightComponent(item, 192f, new Color(1f, 0, 0, 1f))); Log.Error("Add light"); } public override void Drop(Entity entity, Item item) { isOut = false; item.RemoveComponent(); Log.Error("Remove light"); } public override void Update(Entity entity, Item item, float dt) { base.Update(entity, item, dt); if (isOut) { lastFlame += dt; if (lastFlame >= 0.3f) { lastFlame = 0; entity.Area.Add(new FireParticle { Position = entity.Center + MathUtils.CreateVector(entity.AngleTo(entity.GetComponent().Aim), 13), Depth = Layers.Wall + 1 }); } } } } } ================================================ FILE: BurningKnight/entity/item/use/AffectDealChanceUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class AffectDealChanceUse : ItemUse { private float granny; private bool addGranny; private float dm; private bool addDm; private bool both; public override bool HandleEvent(Event e) { if (e is DealChanceCalculateEvent d) { if (addGranny) { d.GrannyChance += granny; } else { d.GrannyChance *= granny; } if (addDm) { d.DmChance += dm; } else { d.DmChance *= dm; } if (both) { d.OpenBoth = true; } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); both = settings["bt"].Bool(false); granny = settings["gr"].Number(0); addGranny = settings["agr"].Bool(true); dm = settings["dm"].Number(0); addDm = settings["adm"].Bool(true); } public static void RenderDebug(JsonValue root) { root.Checkbox("Open Both if one is present", "bt", false); ImGui.Separator(); root.InputFloat("Granny", "gr", 0); root.Checkbox("Add Granny", "agr", true); ImGui.Separator(); root.InputFloat("Dm", "dm", 0); root.Checkbox("Add Dm", "adm", true); } } } ================================================ FILE: BurningKnight/entity/item/use/BlankUse.cs ================================================ using Lens.entity; namespace BurningKnight.entity.item.use { public class BlankUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); BlankMaker.Make(entity.Center, entity.Area); } } } ================================================ FILE: BurningKnight/entity/item/use/BlindFoldUse.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.item.use { public class BlindFoldUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); if (entity.TryGetComponent(out var w)) { w.Disabled = true; } if (entity.TryGetComponent(out var aw)) { aw.Disabled = true; } } } } ================================================ FILE: BurningKnight/entity/item/use/BlockDamageUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.events; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class BlockDamageUse : ItemUse { private float chance; public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent hme) { if (hme.Amount < 0 && hme.Who == Item.Owner && Rnd.Chance(chance)) { hme.Amount = 0; if (Item.Id == "bk:cats_ear") { TextParticle.Add(Item.Owner, "Sick dodge!"); } return true; } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); chance = settings["chance"].Number(10); } public static void RenderDebug(JsonValue root) { root.InputFloat("Chance", "chance", 10); } } } ================================================ FILE: BurningKnight/entity/item/use/BreakPiggyBankUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.creature.player; using BurningKnight.state; using Lens.assets; using Lens.entity; namespace BurningKnight.entity.item.use { public class BreakPiggyBankUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var amount = Run.Depth * 5; entity.GetComponent().Coins += amount; TextParticle.Add(entity, Locale.Get("coins"), amount, true); } } } ================================================ FILE: BurningKnight/entity/item/use/BucketUse.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.player; using BurningKnight.level.biome; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class BucketUse : ItemUse { private bool water; private bool snow; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (water) { var r = entity.GetComponent().Room; if (r != null) { foreach (var b in r.Tagged[Tags.Boss]) { if (b is BkHead h && h.CanBeSaved) { h.Save(); Audio.Stop(); ReplaceItem(entity, "bk:bucket"); } } } } else if (snow) { } else if (Run.Level.Biome is IceBiome) { var x = (int) Math.Floor(entity.CenterX / 16); var y = (int) Math.Floor(entity.CenterY / 16); for (var xx = -1; xx <= 1; xx++) { for (var yy = -1; yy <= 1; yy++) { var d = Math.Sqrt(xx * xx + yy * yy); if (d <= 1 && Run.Level.IsInside(x + xx, y + yy) && Run.Level.Get(x + xx, y + yy) == Tile.WallA) { ReplaceItem(entity, "bk:snow_bucket"); break; } } } } } private void ReplaceItem(Entity entity, string id) { var c = entity.GetComponent(); var i = c.Item; c.Drop(); i.Done = true; entity.GetComponent().Pickup(Items.CreateAndAdd(id, entity.Area)); } public override void Setup(JsonValue settings) { base.Setup(settings); water = settings["wt"].Bool(false); snow = settings["snw"].Bool(true); } public static void RenderDebug(JsonValue root) { root.Checkbox("Water Bucket", "wt", false); root.Checkbox("Snow Bucket", "snw", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ChanceToUseWeaponUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class ChanceToUseWeaponUse : ItemUse { private bool back; private bool up; private bool down; private float chance; public override bool HandleEvent(Event e) { if (e is ItemUsedEvent ite && !ite.Fake && ite.Item != Item) { if (Rnd.Chance(chance + Run.Luck * 10)) { var weapon = Item.Owner.GetComponent().Item; if (weapon == null) { return base.HandleEvent(e); } var aim = Item.Owner.GetComponent(); var a = (aim.RealAim - aim.Center).ToAngle(); if (up) { aim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI * 0.5f, 48) + aim.Center; weapon.Use(Item.Owner, true); } if (down) { aim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI * 1.5f, 48) + aim.Center; weapon.Use(Item.Owner, true); } if (back) { aim.RealAim = aim.Aim = MathUtils.CreateVector(a + Math.PI, 48) + aim.Center; weapon.Use(Item.Owner, true); } } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); back = settings["back"].Bool(false); up = settings["up"].Bool(false); down = settings["down"].Bool(false); chance = settings["chance"].Number(10f); } public static void RenderDebug(JsonValue root) { root.Checkbox("Back", "back", false); root.Checkbox("Up", "up", false); root.Checkbox("Down", "down", false); root.InputFloat("Chance", "chance", 10); } } } ================================================ FILE: BurningKnight/entity/item/use/ConsumeUse.cs ================================================ using Lens.entity; namespace BurningKnight.entity.item.use { public class ConsumeUse : ItemUse { public override void Use(Entity entity, Item item) { item.Done = true; } } } ================================================ FILE: BurningKnight/entity/item/use/DetonateBombsUse.cs ================================================ using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.level.entities; using Lens.entity; namespace BurningKnight.entity.item.use { public class DetonateBombsUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); if (!entity.TryGetComponent(out var r)) { return; } var bombs = r.Room.Tagged[Tags.Bomb].ToArray(); foreach (var b in bombs) { if (b is Bomb bm) { bm.Explode(); } else if (b is ExplodingBarrel br) { br.Explode(); } } } } } ================================================ FILE: BurningKnight/entity/item/use/DigUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.level.tile; using BurningKnight.state; using Lens.entity; using Lens.input; namespace BurningKnight.entity.item.use { public class DigUse : ItemUse { public override void Use(Entity entity, Item item) { var cursor = entity.GetComponent().Cursor.GamePosition; var x = (int) Math.Floor(cursor.X / 16f); var y = (int) Math.Floor((cursor.Y) / 16f); var level = Run.Level; if (!level.IsInside(x, y)) { return; } var index = level.ToIndex(x, y); var tile = level.Tiles[index]; var t = (Tile) tile; if (!t.IsWall()) { if (t == Tile.Chasm) { return; } if (level.Liquid[index] != 0) { level.Liquid[index] = 0; } else { level.Liquid[index] = 0; level.Set(index, Tile.Chasm); } } else { level.Set(index, Tile.FloorA); } level.UpdateTile(x, y); level.CreateBody(); level.CreateDestroyableBody(); level.LoadPassable(); } } } ================================================ FILE: BurningKnight/entity/item/use/DiscoverSecretRoomsUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.level.tile; using BurningKnight.state; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class DiscoverSecretRoomsUse : ItemUse { private float chance; public override void Use(Entity entity, Item item) { ExplosionMaker.CheckForCracks(Run.Level, entity.GetComponent().Room, entity); } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce) { if (!Rnd.Chance(chance)) { return base.HandleEvent(e); } ExplosionMaker.CheckForCracks(Run.Level, rce.New, rce.Who); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); chance = settings["chance"].Number(100); } public static void RenderDebug(JsonValue root) { var chance = root["chance"].Number(100); if (ImGui.InputFloat("Chance", ref chance)) { root["chance"] = chance; } } } } ================================================ FILE: BurningKnight/entity/item/use/DiscoverSideRoomsUse.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.events; using BurningKnight.entity.room; using BurningKnight.level.rooms; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class DiscoverSideRoomsUse : ItemUse { public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce) { if (rce.New == null) { return base.HandleEvent(e); } var discovered = new List() { rce.Old }; foreach (var d in rce.New.Doors) { if (d.Rooms[0] != null && d.Rooms[1] != null) { Room room; if (d.Rooms[0] == rce.New) { room = d.Rooms[1]; } else { room = d.Rooms[0]; } if (room.Type == RoomType.Secret || room.Type == RoomType.DarkMarket || room.Type == RoomType.Hidden || Rnd.Chance(20)) { continue; } if (!discovered.Contains(room)) { discovered.Add(room); room.Discover(); } } } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/DoOnEnemyCollisionUse.cs ================================================ using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.entity.item.use.parent; using Lens.entity; namespace BurningKnight.entity.item.use { public class DoOnEnemyCollisionUse : DoUsesUse { protected override void DoAction(Entity entity, Item item, ItemUse use) { } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev && ev.Entity is Creature c && !c.IsFriendly()) { foreach (var u in Uses) { u.Use(c, Item); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/DoOnHurtUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.item.use.parent; using Lens.entity; namespace BurningKnight.entity.item.use { public class DoOnHurtUse : DoUsesUse { protected override void DoAction(Entity entity, Item item, ItemUse use) { } public override bool HandleEvent(Event e) { if (e is PostHealthModifiedEvent ev && ev.Amount < 0) { foreach (var u in Uses) { u.Use(ev.Who, Item); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/DoOnNewFloorUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.item.use.parent; using Lens.entity; namespace BurningKnight.entity.item.use { public class DoOnNewFloorUse : DoUsesUse { private Entity e; protected override void DoAction(Entity entity, Item item, ItemUse use) { e = entity; } public override bool HandleEvent(Event ev) { if (ev is NewFloorEvent) { foreach (var u in Uses) { u.Use(e, Item); } } return base.HandleEvent(ev); } } } ================================================ FILE: BurningKnight/entity/item/use/DoOnTimerUse.cs ================================================ using BurningKnight.entity.item.use.parent; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.timer; namespace BurningKnight.entity.item.use { public class DoOnTimerUse : DoUsesUse { private float time; public override void Use(Entity entity, Item item) { base.Use(entity, item); Timer.Add(() => { foreach (var u in Uses) { u.Item = item; u.Use(entity, item); } }, time); } protected override void DoAction(Entity entity, Item item, ItemUse use) { } public override void Setup(JsonValue settings) { base.Setup(settings); time = settings["time"].Number(1f); } public static void RenderDebug(JsonValue root) { root.InputFloat("Time", "time", 1f); ImGui.Separator(); DoUsesUse.RenderDebug(root); } } } ================================================ FILE: BurningKnight/entity/item/use/DoUsesIfUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.item.use.parent; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class DoUsesIfUse : DoUsesUse { private static string[] options = { "full_hp", "min_hp", "not_full_hp" }; private int option; public override void Use(Entity entity, Item item) { if (IsTrue(entity)) { foreach (var u in Uses) { u.Use(entity, Item); } } } private bool IsTrue(Entity entity) { switch (option) { case 0: { return entity.GetComponent().IsFull(); } case 1: { return Math.Abs(entity.GetComponent().Health) < 1.1f; } case 2: { return !entity.GetComponent().IsFull(); } default: { return true; } } } protected override void DoAction(Entity entity, Item item, ItemUse use) { } public override void Setup(JsonValue settings) { base.Setup(settings); option = settings["opt"].Int(0); } public static void RenderDebug(JsonValue root) { DoUsesUse.RenderDebug(root); ImGui.Separator(); var option = root["opt"].Int(0); if (ImGui.Combo("If", ref option, options, options.Length)) { root["opt"] = option; } } } } ================================================ FILE: BurningKnight/entity/item/use/DoWithUse.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.entity.item.use.parent; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class DoWithUse : DoWithTagUse { protected ItemUse[] Uses; protected float chance; protected override void DoAction(Entity entity, Item item, List entities) { foreach (var e in entities) { if (chance < 100f && !Rnd.Chance(chance)) { continue; } foreach (var u in Uses) { u.Use(e, item); } } } public override void Setup(JsonValue settings) { base.Setup(settings); if (!settings["uses"].IsJsonArray) { settings["uses"] = new JsonArray(); } Uses = Items.ParseUses(settings["uses"]); chance = settings["chance"].Number(100); } public static void RenderDebug(JsonValue root) { root.InputFloat("Chance", "chance", 100f); if (ImGui.TreeNode("With who")) { DoWithTagUse.RenderDebug(root); ImGui.TreePop(); } ImGui.Separator(); if (!root["uses"].IsJsonArray) { root["uses"] = new JsonArray(); } ItemEditor.DisplayUse(root, root["uses"]); } } } ================================================ FILE: BurningKnight/entity/item/use/DuplicateItemsUse.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using Lens.entity; using Lens.util; namespace BurningKnight.entity.item.use { public class DuplicateItemsUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var room = entity.GetComponent().Room; if (room == null) { return; } // Copy to array, because we are going to change the list in the loop var items = room.Tagged[Tags.Item].ToArray(); foreach (var it in items) { if (it is ItemStand ist) { if (ist.Item == null) { continue; } var st = new ItemStand(); entity.Area.Add(st); ist.X -= ist.Width / 2f + 1; st.X = ist.X + ist.Width + 2; st.Y = ist.Y; st.SetItem(Items.CreateAndAdd(ist.Item.Id, entity.Area), item); } else if (it is Item i) { var st = Items.CreateAndAdd(i.Id, entity.Area); i.X -= i.Width / 2f + 1; st.X = i.X + i.Width + 2; st.Y = i.Y; } } var chests = room.Tagged[Tags.Chest].ToArray(); foreach (var i in chests) { try { var st = (Entity) Activator.CreateInstance(i.GetType()); i.X -= i.Width / 2f + 1; st.X = i.X + i.Width + 2; st.Y = i.Y; } catch (Exception e) { Log.Error(e); } } } } } ================================================ FILE: BurningKnight/entity/item/use/DuplicateMobsAndHealUse.cs ================================================ using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.use { public class DuplicateMobsAndHealUse : DuplicateMobsUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var room = entity.GetComponent().Room; if (room == null || room.Tagged[Tags.Mob].Count == 0) { return; } entity.GetComponent().ModifyHealth(2, item); } } } ================================================ FILE: BurningKnight/entity/item/use/DuplicateMobsUse.cs ================================================ using System; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class DuplicateMobsUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var room = entity.GetComponent().Room; if (room == null) { return; } // Copy to array, because we are going to change the list in the loop var mobs = room.Tagged[Tags.Mob].ToArray(); foreach (var mob in mobs) { try { var m = (Mob) Activator.CreateInstance(mob.GetType()); entity.Area.Add(m); m.Center = mob.Center; if (!(MobRegistry.FindFor(m.GetType())?.NearWall ?? false)) { m.Center += Rnd.Vector(-8, 8); } } catch (Exception e) { Log.Error(e); } } } } } ================================================ FILE: BurningKnight/entity/item/use/EnableScourgeUse.cs ================================================ using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class EnableScourgeUse : ItemUse { private string scourge; public override void Use(Entity entity, Item item) { base.Use(entity, item); Scourge.Enable(scourge); if (Run.Scourge == 0) { Run.AddScourge(); } } public override void Setup(JsonValue settings) { base.Setup(settings); scourge = settings["scourge"].String(Scourge.OfUnknown); } public static void RenderDebug(JsonValue root) { root.InputText("Scourge", "scourge"); } } } ================================================ FILE: BurningKnight/entity/item/use/ExplodeUse.cs ================================================ using Lens.entity; namespace BurningKnight.entity.item.use { public class ExplodeUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); ExplosionMaker.Make(entity); } } } ================================================ FILE: BurningKnight/entity/item/use/FireInAllDirsUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.entity; using Lens.util; namespace BurningKnight.entity.item.use { public class FireInAllDirsUse : ItemUse { public override void Use(Entity entity, Item item) { var weapon = entity.GetComponent().Item; if (weapon == null) { return; } var aim = entity.GetComponent(); for (var i = 0; i < 8; i++) { var angle = i / 4f * (float) Math.PI; aim.RealAim = aim.Aim = MathUtils.CreateVector(angle, 48) + aim.Center; weapon.Use(entity, true); } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveBombUse.cs ================================================ using System; using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveBombUse: ItemUse { public int Amount; public override void Use(Entity entity, Item item) { var h = entity.GetComponent(); var a = Amount; if (h.Bombs < h.BombsMax) { var t = Math.Min(Amount, h.BombsMax - h.Bombs); h.ModifyBombs(t, null); a -= t; } if (a > 0) { entity.GetComponent().Bombs += a; } } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveBuffImmunityUse.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveBuffImmunityUse : GiveBuffUse { public bool IceImmunity; public bool PitImmunity; public override void Use(Entity entity, Item item) { if (IceImmunity) { entity.GetComponent().IceImmunity = true; } if (PitImmunity) { entity.GetComponent().PitImmunity = true; } } public override void Setup(JsonValue settings) { base.Setup(settings); IceImmunity = settings["ice"].Bool(false); PitImmunity = settings["pit"].Bool(false); } public override bool HandleEvent(Event e) { if (e is BuffCheckEvent ev && ev.Buff.Type == Buff) { return true; } return base.HandleEvent(e); } public static void RenderDebug(JsonValue root) { GiveBuffUse.RenderDebug(root); ImGui.Separator(); root.Checkbox("Give ice immunity", "ice", false); root.Checkbox("Pit immunity", "pit", false); } } } ================================================ FILE: BurningKnight/entity/item/use/GiveBuffUse.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class GiveBuffUse : ItemUse { protected string Buff; protected float Time; public override void Use(Entity entity, Item item) { var b = BuffRegistry.Create(Buff); if (b == null) { Log.Error($"Unknown buff {Buff}"); return; } if (Time < 0) { b.Infinite = true; } else { b.TimeLeft = b.Duration = Time; } if (entity.TryGetComponent(out var buffs)) { buffs.Add(b); } } public override void Setup(JsonValue settings) { base.Setup(settings); Time = settings["time"].Number(1); Buff = settings["buff"].AsString ?? ""; } public static void RenderDebug(JsonValue root) { var time = root["time"].Number(1); var buff = root["buff"].AsString ?? ""; if (ImGui.InputText("Buff", ref buff, 128)) { root["buff"] = buff; } if (!BuffRegistry.All.ContainsKey(buff)) { ImGui.BulletText("Unknown buff!"); } var infinite = time < 0; if (ImGui.Checkbox("Infinite?", ref infinite)) { time = infinite ? -1 : 1; } if (!infinite) { if (ImGui.InputFloat("Duration", ref time)) { root["time"] = time; } } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveEmeraldsUse.cs ================================================ using BurningKnight.save; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveEmeraldsUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { GlobalSave.Emeralds += Amount; entity.Area.EventListener.Handle(new GaveEvent { Amount = Amount }); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } } public class GaveEvent : Event { public int Amount; } } } ================================================ FILE: BurningKnight/entity/item/use/GiveFlightUse.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.item.use { public class GiveFlightUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); if (entity is Player p) { p.HasFlight = true; } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveGoldUse.cs ================================================ using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveGoldUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { entity.GetComponent().Coins += Amount; } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); ImGui.InputInt("Amount", ref val); root["amount"] = val; } } } ================================================ FILE: BurningKnight/entity/item/use/GiveHeartContainersUse.cs ================================================ using BurningKnight.entity.component; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveHeartContainersUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { var component = entity.GetComponent(); component.MaxHealth += Amount; if (!item.Used && Amount > 0) { component.ModifyHealth(Amount, entity); } } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } } } ================================================ FILE: BurningKnight/entity/item/use/GiveItemUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class GiveItemUse : ItemUse { public int Amount; public string Item; public bool OnStand; public bool Random; public bool Animate; public bool Hide; public override void Use(Entity entity, Item item) { var id = Random ? Items.Generate(i => i.Type == ItemType.Active || i.Type == ItemType.Weapon || i.Type == ItemType.Artifact) : Item; if (OnStand) { var i = Items.CreateAndAdd(id, entity.Area); if (i == null) { Log.Error($"Invalid item {id}"); return; } var stand = new ItemStand(); entity.Area.Add(stand); stand.Center = entity.Center - new Vector2(0, 8); stand.SetItem(i, null); return; } for (var j = 0; j < Amount; j++) { var i = Items.CreateAndAdd(id, entity.Area); if (i == null) { Log.Error($"Invalid item {id}"); return; } // i.Hide = Hide; entity.GetComponent().Pickup(i, Animate); } } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); Item = settings["item"].AsString ?? ""; OnStand = settings["on_stand"].Bool(false); Random = settings["random"].Bool(false); Animate = settings["animate"].Bool(true); Hide = settings["hide"].Bool(false); } public static void RenderDebug(JsonValue root) { var stand = root["on_stand"].Bool(false); var random = root["random"].Bool(false); if (ImGui.Checkbox("Spawn on stand?", ref stand)) { root["on_stand"] = stand; } if (ImGui.Checkbox("Random item?", ref random)) { root["random"] = random; } if (stand) { return; } var val = root["amount"].Int(1); if (!random) { var item = root["item"].AsString ?? ""; if (ImGui.InputText("Item", ref item, 128)) { root["item"] = item; } if (!Items.Datas.ContainsKey(item)) { ImGui.BulletText("Unknown item!"); } } if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } root.Checkbox("Animate?", "animate", true); root.Checkbox("Hide?", "hide", false); } } } ================================================ FILE: BurningKnight/entity/item/use/GiveKeyUse.cs ================================================ using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class GiveKeyUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { entity.GetComponent().Keys += Amount; } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveLaserAimUse.cs ================================================ using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.use { public class GiveLaserAimUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); entity.GetComponent().ShowLaserLine = true; } } } ================================================ FILE: BurningKnight/entity/item/use/GivePhaseUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class GivePhaseUse : ItemUse { public int Amount; public bool Broken; public override void Use(Entity entity, Item item) { if (!item.Used && (!Broken || Rnd.Chance())) { entity.GetComponent().Phases += (byte) Amount; } } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); Broken = settings["broken"].Bool(false); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } root.Checkbox("Broken", "broken", false); } } } ================================================ FILE: BurningKnight/entity/item/use/GiveRandomPickupUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.use { public class GiveRandomPickupUse : ItemUse { public override void Use(Entity entity, Item item) { entity.GetComponent().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Consumable), entity.Area)); } } } ================================================ FILE: BurningKnight/entity/item/use/GiveScourgeImmunityUse.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.state; using Lens.entity; namespace BurningKnight.entity.item.use { public class GiveScourgeImmunityUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var sc = Run.Scourge; for (var i = 0; i < sc; i++) { Run.RemoveScourge(); } var inventory = entity.GetComponent(); var toRemove = new List(); foreach (var i in inventory.Items) { if (i.Scourged) { i.Scourged = false; } if (i.Type == ItemType.Scourge) { toRemove.Add(i); } } Cleanse(entity.GetComponent()); Cleanse(entity.GetComponent()); Cleanse(entity.GetComponent()); // fixme: doesnt do anything to ui inventory foreach (var i in toRemove) { inventory.Remove(i, true); } foreach (var s in Scourge.Defined) { Scourge.Disable(s); } } private void Cleanse(ItemComponent component) { if (component.Item != null) { component.Item.Scourged = false; } } } } ================================================ FILE: BurningKnight/entity/item/use/GiveWeaponUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class GiveWeaponUse : ItemUse { public string Item; public override void Use(Entity entity, Item item) { var i = Items.CreateAndAdd(Item, entity.Area); if (i == null) { Log.Error($"Invalid item {item}"); return; } var o = entity.GetComponent(); var c = (WeaponComponent) entity.GetComponent(); if (o.Item == item) { c = o; } var old = c.Item; c.Set(i, false); old.Done = true; } public override void Setup(JsonValue settings) { base.Setup(settings); Item = settings["item"].AsString ?? ""; } public static void RenderDebug(JsonValue root) { var item = root["item"].AsString ?? ""; if (ImGui.InputText("Item", ref item, 128)) { root["item"] = item; } if (!Items.Datas.ContainsKey(item)) { ImGui.BulletText("Unknown item!"); } } } } ================================================ FILE: BurningKnight/entity/item/use/GoThonkUse.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.ui.dialog; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class GoThonkUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var room = entity.GetComponent().Room; if (room == null) { return; } var enemies = room.Tagged[Tags.Mob]; if (enemies.Count == 0) { return; } var attempt = 0; var count = 0; do { var enemy = enemies[Rnd.Int(enemies.Count)]; if (enemy.GetComponent().Add(new FrozenBuff { Duration = 50 }) != null) { if (!enemy.HasComponent()) { enemy.AddComponent(new DialogComponent()); } enemy.GetComponent().Start("mob_0"); count++; if (count >= 3) { break; } } } while (attempt++ < 99); } } } ================================================ FILE: BurningKnight/entity/item/use/InvokeItemsUse.cs ================================================ using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class InvokeItemsUse : ItemUse { private bool pets; private bool orbitals; private bool any; public override void Use(Entity entity, Item item) { base.Use(entity, item); var inventory = entity.GetComponent(); var items = new List(); foreach (var i in inventory.Items) { var use = any; if (!use) { var data = i.Data; use = (pets && ItemPool.Pet.Contains(data.Pools)) || (orbitals && ItemPool.Orbital.Contains(data.Pools)); } if (use) { items.Add(i.Id); } } foreach (var i in items) { inventory.Pickup(Items.CreateAndAdd(i, entity.Area), false); } } public override void Setup(JsonValue settings) { base.Setup(settings); pets = settings["pets"].Bool(true); orbitals = settings["orbitals"].Bool(false); any = settings["any"].Bool(false); } public static void RenderDebug(JsonValue root) { root.Checkbox("Pets", "pets", true); root.Checkbox("Orbitals", "orbitals", false); root.Checkbox("Any", "any", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ItemUse.cs ================================================ using Lens.entity; using Lens.lightJson; using Lens.util.file; namespace BurningKnight.entity.item.use { public class ItemUse { public Item Item; public bool SingleUse; public virtual void Use(Entity entity, Item item) { } public virtual void Update(Entity entity, Item item, float dt) { } public virtual void Pickup(Entity entity, Item item) { } public virtual void Drop(Entity entity, Item item) { } public virtual void TakeOut(Entity entity, Item item) { } public virtual void PutAway(Entity entity, Item item) { } public virtual void Setup(JsonValue settings) { SingleUse = settings["single"].Bool(false); } public virtual void Init() { } public virtual void Destroy() { } public virtual bool HandleEvent(Event e) { return false; } } } ================================================ FILE: BurningKnight/entity/item/use/KillMobUse.cs ================================================ using System.Linq; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class KillMobUse : ItemUse { private bool all; private bool half; private int count; public override void Use(Entity entity, Item item) { base.Use(entity, item); var room = entity.GetComponent().Room; if (room == null) { return; } var mobs = room.Tagged[Tags.Mob].ToList(); if (all) { foreach (var m in mobs) { ((Mob) m).Kill(entity); } return; } if (half) { var c = mobs.Count / 2; for (var g = 0; g < c; g++) { ((Mob) mobs[g]).Kill(entity); } return; } var i = 0; do { var index = Rnd.Int(mobs.Count); var mob = mobs[index]; mobs.RemoveAt(index); ((Mob) mob).Kill(entity); i++; } while (mobs.Count > 0 && i < count); } public override void Setup(JsonValue settings) { base.Setup(settings); all = settings["all"].Bool(false); half = settings["half"].Bool(false); count = settings["count"].Int(1); } public static void RenderDebug(JsonValue root) { var all = root["all"].Bool(false); if (ImGui.Checkbox("All?", ref all)) { root["all"] = all; } if (all || root.Checkbox("Half", "half", false)) { return; } var count = root["count"].Int(1); if (ImGui.InputInt("Count", ref count)) { root["count"] = count; } } } } ================================================ FILE: BurningKnight/entity/item/use/LeaveLegoUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using Lens.entity; namespace BurningKnight.entity.item.use { public class LeaveLegoUse : ItemUse { private float t; public override void Update(Entity entity, Item item, float dt) { base.Update(entity, item, dt); var r = entity.GetComponent().Room; if (r == null || r.Tagged[Tags.MustBeKilled].Count == 0) { t = 0; return; } t += dt; if (t >= 5f) { t = 0; var lego = new Lego(); entity.Area.Add(lego); lego.BottomCenter = entity.BottomCenter; AnimationUtil.Ash(lego.Center); } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeBombsBlankUse.cs ================================================ using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.item.use { public class MakeBombsBlankUse : ItemUse { public override bool HandleEvent(Event e) { if (e is BombPlacedEvent bpe) { bpe.Bomb.OnDeath += (b) => BlankMaker.Make(b.Center, b.Area); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeBombsExplodeOnTouchUse.cs ================================================ using BurningKnight.entity.bomb.controller; using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.item.use { public class MakeBombsExplodeOnTouchUse : ItemUse { public override bool HandleEvent(Event e) { if (e is BombPlacedEvent bce) { bce.Bomb.ExplodeOnTouch = true; } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeBombsHomeUse.cs ================================================ using BurningKnight.entity.bomb.controller; using BurningKnight.entity.events; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeBombsHomeUse : ItemUse { private float speed; public override bool HandleEvent(Event e) { if (e is BombPlacedEvent bce) { bce.Bomb.ExplodeOnTouch = true; bce.Bomb.Controller += TargetBombController.Make(null, speed); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Number(1); } public static void RenderDebug(JsonValue root) { var speed = root["speed"].Number(1); if (ImGui.InputFloat("Speed", ref speed)) { root["speed"] = speed; } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeItemsAttactUse.cs ================================================ using Lens.entity; namespace BurningKnight.entity.item.use { public class MakeItemsAttactUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); Item.Attact = true; } } } ================================================ FILE: BurningKnight/entity/item/use/MakeLayerPassableUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeLayerPassableUse : ItemUse { private bool forProjectiles; private bool forPlayer; private bool chasms; private bool props; private bool walls; private bool mobs; private bool stones; private bool projectiles; private bool breakProjectiles; public override void Use(Entity entity, Item item) { if (forPlayer) { if (props) { CollisionFilterComponent.Add(entity, (o, e) => e is Prop ? CollisionResult.Disable : CollisionResult.Default); } if (chasms) { ((Creature) entity).Flying = true; } if (walls) { CollisionFilterComponent.Add(entity, (o, en) => en is Level || en is ProjectileLevelBody || en is HalfProjectileLevel || en is HalfWall ? CollisionResult.Disable : CollisionResult.Default); } if (stones) { CollisionFilterComponent.Add(entity, (o, en) => en is HalfWall || en is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default); } } } public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { if (forProjectiles) { if (props) { CollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Prop ? CollisionResult.Disable : CollisionResult.Default); } if (walls) { pce.Projectile.AddFlags(ProjectileFlags.FlyOverStones); CollisionFilterComponent.Add(pce.Projectile, (o, en) => (en is Level || en is ProjectileLevelBody || en is Door) ? CollisionResult.Disable : CollisionResult.Default); } if (mobs) { CollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Creature ? CollisionResult.Disable : CollisionResult.Default); } if (stones) { CollisionFilterComponent.Add(pce.Projectile, (o, en) => en is HalfWall || en is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default); } if (projectiles) { CollisionFilterComponent.Add(pce.Projectile, (o, en) => en is Projectile ? CollisionResult.Enable : CollisionResult.Default); } if (breakProjectiles) { pce.Projectile.AddFlags(ProjectileFlags.BreakOtherProjectiles); } } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); forProjectiles = settings["fp"].Bool(false); forPlayer = settings["fpl"].Bool(false); chasms = settings["ic"].Bool(false); props = settings["ip"].Bool(false); walls = settings["iw"].Bool(false); mobs = settings["im"].Bool(false); stones = settings["st"].Bool(false); projectiles = settings["p"].Bool(false); breakProjectiles = settings["bp"].Bool(false); } public static void RenderDebug(JsonValue root) { var v = root["fp"].Bool(false); if (ImGui.Checkbox("For projectiles", ref v)) { root["fp"] = v; } v = root["fpl"].Bool(false); if (ImGui.Checkbox("For player", ref v)) { root["fpl"] = v; } ImGui.Separator(); root.Checkbox("Projectiles", "p", false); v = root["ic"].Bool(false); if (ImGui.Checkbox("Ignore chasms", ref v)) { root["ic"] = v; } v = root["ip"].Bool(false); if (ImGui.Checkbox("Ignore props", ref v)) { root["ip"] = v; } v = root["iw"].Bool(false); if (ImGui.Checkbox("Ignore walls", ref v)) { root["iw"] = v; } v = root["im"].Bool(false); if (ImGui.Checkbox("Ignore mobs", ref v)) { root["im"] = v; } root.Checkbox("Ignore stones", "st", false); root.Checkbox("Break Projectiles", "bp", false); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectileExpandUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectileExpandUse : ItemUse { private float speed; public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { ProjectileCallbacks.AttachUpdateCallback(pce.Projectile, ExpandProjectileController.Make(speed)); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Number(1); } public static void RenderDebug(JsonValue root) { var speed = root["speed"].Number(1); if (ImGui.InputFloat("Speed", ref speed)) { root["speed"] = speed; } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectileReshootUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class MakeProjectileReshootUse : ItemUse { public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce && !pce.Projectile.HasFlag(ProjectileFlags.Artificial)) { ProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, en) => { var room = p.Owner.GetComponent().Room; if (room == null || room.Tagged[Tags.MustBeKilled].Count == 0 || Rnd.Chance(20)) { return; } var target = room.FindClosest(p.Center, Tags.MustBeKilled, ent => ent != en); if (target != null) { var c = p.HasComponent(); var builder = new ProjectileBuilder(pce.Owner, p.Slice) { RectHitbox = !c, Parent = p, Scale = p.Scale, }; var pr = builder.Shoot(p.AngleTo(target), 10).Build(); pr.EntitiesHurt.AddRange(p.EntitiesHurt); pr.Center = p.Center; } }); } return false; } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectileShrinkUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectileShrinkUse : ItemUse { private float speed; public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { ProjectileCallbacks.AttachUpdateCallback(pce.Projectile, ShrinkProjectileController.Make(speed)); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Number(1); } public static void RenderDebug(JsonValue root) { var speed = root["speed"].Number(1); if (ImGui.InputFloat("Speed", ref speed)) { root["speed"] = speed; } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesBlankOnDeathUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class MakeProjectilesBlankOnDeathUse : ItemUse { public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { ProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => { if (Rnd.Chance(20 + Run.Luck * 10)) { BlankMaker.Make(p.Center, p.Area, 18f); } }); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesBoomerangUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using Lens.entity; namespace BurningKnight.entity.item.use { public class MakeProjectilesBoomerangUse : ItemUse { public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { var projectile = pce.Projectile; ProjectileCallbacks.AttachUpdateCallback(projectile, BoomerangProjectileController.Make(pce.Owner)); if (projectile.T > 0) { projectile.T *= 2; } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesBounceUse.cs ================================================ using BurningKnight.entity.events; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectilesBounceUse : ItemUse { private int count; public override void Setup(JsonValue settings) { base.Setup(settings); count = settings["count"].Int(1); } public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { pce.Projectile.Bounce += count; } return base.HandleEvent(e); } public static void RenderDebug(JsonValue root) { var count = root["count"].Int(1); if (ImGui.InputInt("Count", ref count)) { root["count"] = count; } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesHomeInUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectilesHomeInUse : ItemUse { private float speed; private bool better; public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { /* if (pce.Projectile is Laser l) { Timer.Add(() => { var room = pce.Owner.GetComponent().Room; var ent = room?.FindClosest(l.Position, Tags.MustBeKilled); if (ent == null) { return; } Log.Debug(ent.GetType().FullName); var ac = better ? 0.05f : 0.15f; l.PlayerRotated = false; l.BodyComponent.Body.Rotation = MathUtils.Angle(ent.Center.Y - l.Position.Y, ent.Center.X - l.Position.X); }, 0.05f); } else { */ if (better) { ProjectileCallbacks.AttachUpdateCallback(pce.Projectile, TargetProjectileController.MakeBetter(speed)); } else { ProjectileCallbacks.AttachUpdateCallback(pce.Projectile, TargetProjectileController.Make(null, speed)); } // } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Number(1); better = settings["better"].Bool(false); } public static void RenderDebug(JsonValue root) { var speed = root["speed"].Number(1); if (ImGui.InputFloat("Speed", ref speed)) { root["speed"] = speed; } root.Checkbox("Better?", "better", false); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesHurtOnMissUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.state; using Lens.entity; namespace BurningKnight.entity.item.use { public class MakeProjectilesHurtOnMissUse : ItemUse { public override bool HandleEvent(Event e) { if (Run.Depth == 0) { return base.HandleEvent(e); } if (e is ProjectileCreatedEvent pce) { if (!(pce.Projectile.Owner is Player)) { return false; } var hurt = false; ProjectileCallbacks.AttachCollisionCallback(pce.Projectile, (p, en) => { if (en.HasComponent() || (en is ProjectileLevelBody && Run.Level.Biome is IceBiome)) { hurt = true; } return false; }); ProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => { if (!hurt) { Item.Owner.GetComponent().ModifyHealth(-1, Item); } }); } else if (e is MeleeArc.CreatedEvent mac) { if (!(mac.Arc.Owner is Player)) { return false; } var hurt = false; mac.Arc.OnHurt += (m, en) => { if (en.HasComponent() || (en is ProjectileLevelBody && Run.Level.Biome is IceBiome)) { hurt = true; } }; mac.Arc.OnDeath += (m) => { if (!hurt) { Item.Owner.GetComponent().ModifyHealth(-1, Item); } }; } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesKillWithBuffUse.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectilesKillWithBuffUse : ItemUse { private Type buff; public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { ProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, w) => { if (w is Mob m && w.GetComponent().Buffs.ContainsKey(buff)) { m.Kill(Item); } }); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); var b = settings["buff"].String("bk:frozen"); if (BuffRegistry.All.TryGetValue(b, out var i)) { buff = i.Buff; } } public static void RenderDebug(JsonValue root) { root.InputText("Buff", "buff", "bk:frozen"); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesShatternOnDeathUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class MakeProjectilesShatternOnDeathUse : ItemUse { public override bool HandleEvent(Event e) { // Make sure that this is a new projectile, not created by this event if (e is ProjectileCreatedEvent pce && pce.Projectile.Parent == null) { ProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => { if (Rnd.Chance(30) || p.Parent != null) { return; } var cnt = Rnd.Int(3, 5); if (p is Laser l) { var a = l.BodyComponent.Body.Rotation - (float) Math.PI; var end = l.End + MathUtils.CreateVector(a, 5); for (var i = 0; i < cnt; i++) { var 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)); laser.Position = end; laser.Recalculate(); } } else { var v = p.GetAnyComponent().Velocity; var a = v.ToAngle() - (float) Math.PI; var s = v.Length(); var c = p.HasComponent(); var builder = new ProjectileBuilder(pce.Owner, p.Slice) { Parent = p, Scale = p.Scale * Rnd.Float(0.4f, 0.8f), RectHitbox = !c }; for (var i = 0; i < cnt; i++) { builder.Shoot(a + Rnd.Float(-1.4f, 1.4f), s * Rnd.Float(0.3f, 0.7f)).Build().Center = p.Center; } } }); } return false; } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesSlowDown.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.entity.projectile.controller; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MakeProjectilesSlowDown : ItemUse { private float amount; private float time; public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { ProjectileCallbacks.AttachUpdateCallback(pce.Projectile, SlowdownProjectileController.Make(amount, time)); } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); amount = settings["amount"].Number(1); time = settings["time"].Number(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Number(1); if (ImGui.InputFloat("Speed", ref val)) { root["amount"] = val; } val = root["time"].Number(1); if (ImGui.InputFloat("Time", ref val)) { root["time"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesSplitOnDeathUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class MakeProjectilesSplitOnDeathUse : ItemUse { public override bool HandleEvent(Event e) { // Make sure that this is a new projectile, not created by this event if (e is ProjectileCreatedEvent pce && pce.Projectile.Parent == null) { ProjectileCallbacks.AttachDeathCallback(pce.Projectile, (p, en, t) => { if (Rnd.Chance(20)) { return; } var v = p.GetAnyComponent().Velocity; if (p is Laser l) { var a = l.BodyComponent.Body.Rotation; var end = l.End - MathUtils.CreateVector(a, 5); for (var i = 0; i < 2; i++) { var laser = Laser.Make(p.Owner, a + (i == 0 ? -1 : 1) * (float) Math.PI * 0.5f, 0f, null, p.Damage, parent: l); laser.Position = end; laser.Recalculate(); } } else { var c = p.HasComponent(); var s = v.Length(); var a = v.ToAngle() - Math.PI; var builder = new ProjectileBuilder(pce.Owner, p.Slice) { Parent = p, Scale = p.Scale, RectHitbox = !c }; builder.Shoot(a - (float) Math.PI * 0.5f, s).Build().Center = p.Center; builder.Shoot(a + (float) Math.PI * 0.5f, s).Build().Center = p.Center; } }); } return false; } } } ================================================ FILE: BurningKnight/entity/item/use/MakeProjectilesSplitUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.entity; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class MakeProjectilesSplitUse : ItemUse { public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { if (pce.Projectile.Parent?.Parent != null || Rnd.Chance(20)) { return false; } ProjectileCallbacks.AttachHurtCallback(pce.Projectile, (p, en) => { var v = p.GetAnyComponent(); var a = v.Velocity.ToAngle(); var s = v.Velocity.Length(); var c = p.HasComponent(); var builder = new ProjectileBuilder(pce.Owner, p.Slice) { Scale = p.Scale, RectHitbox = !c, Parent = p }; for (var i = 0; i < 2; i++) { var pr = builder.Shoot( a + 0.2f * (i == 0 ? -1 : 1), s).Build(); pr.EntitiesHurt.AddRange(p.EntitiesHurt); pr.Center = p.Center; } p.Break(); }); } return false; } } } ================================================ FILE: BurningKnight/entity/item/use/MakeRollKickProjectilesUse.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using BurningKnight.entity.projectile; using Lens.entity; using Lens.entity.component.logic; using Lens.util; using Lens.util.camera; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class MakeRollKickProjectilesUse : ItemUse { public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (!(Item.Owner is Player pl) || !(pl.GetComponent().StateInstance is Player.RollState)) { return base.HandleEvent(e); } if (cse.Entity is Projectile p && !(p.Owner is Player) && p.HasFlag(ProjectileFlags.Reflectable)) { var owner = Item.Owner; var a = owner.AngleTo(p.Owner); p.Owner = owner; p.Damage *= 2f; // Lethal? // p.Pattern?.Remove(p); var b = p.GetAnyComponent(); var d = Math.Max(400, b.Velocity.Length() * 1.8f); b.Velocity = MathUtils.CreateVector(a, d); if (p.TryGetComponent(out var l)) { l.Light.Color = MeleeArc.ReflectedColor; } p.Color = ProjectileColor.Yellow; Camera.Instance.ShakeMax(4f); owner.GetComponent().EmitRandomizedPrefixed("projectile_reflected", 2); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MakeShopRestockUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using Lens.entity; using Lens.util.timer; namespace BurningKnight.entity.item.use { public class MakeShopRestockUse : ItemUse { public override bool HandleEvent(Event e) { if (e is ItemBoughtEvent ibe) { Timer.Add(() => { ibe.Stand.SetItem(Items.CreateAndAdd(Items.Generate(ibe.Stand.GetPool(), i => i.Id != ibe.Item.Id && Items.ShouldAppear(i)), ibe.Stand.Area), null); }, 0.5f); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/MeleeArcUse.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.item.util; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.input; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class MeleeArcUse : ItemUse { protected float Damage; protected float LifeTime; protected int W; protected int H; protected float Angle; protected string AttackSound = "item_sword_attack"; protected string HitSound = "item_sword_hit"; protected float Knockback; public override void Use(Entity entity, Item item) { entity.GetComponent().EmitRandomizedPrefixed(AttackSound, 4); var arc = new MeleeArc { Owner = entity, LifeTime = LifeTime, Damage = Damage * (item.Scourged ? 1.5f : 1), Width = W, Height = H, Sound = HitSound, Position = entity.Center, Knockback = Knockback, Angle = entity.AngleTo(entity.GetComponent().RealAim) + Angle }; entity.HandleEvent(new MeleeArc.CreatedEvent { Arc = arc, Owner = entity, By = item }); entity.Area.Add(arc); } public override void Setup(JsonValue settings) { base.Setup(settings); Damage = settings["damage"].Number(1); W = settings["w"].Int(8); H = settings["h"].Int(24); LifeTime = settings["time"].Number(0.2f); Angle = settings["angle"].Number(0) * (float) Math.PI * 2; HitSound = settings["hs"].String("item_sword_hit"); AttackSound = settings["as"].String("item_sword_attack"); Knockback = settings["knockback"].Number(0f); } public static void RenderDebug(JsonValue root) { root.InputFloat("Damage", "damage", 1); root.InputInt("Width", "w", 8); root.InputInt("Height", "h", 24); root.InputFloat("Life time", "time", 0.2f); root.InputFloat("Angle", "angle", 0); root.InputFloat("Knockback", "knockback", 0); ImGui.Separator(); root.InputText("Hit Sound", "hs", "item_sword_hit"); root.InputText("Attack Sound", "as", "item_sword_attack"); } } } ================================================ FILE: BurningKnight/entity/item/use/ModEachAttackUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.item.util; using Lens.entity; namespace BurningKnight.entity.item.use { public class ModEachAttackUse : ItemUse { private int count; public override bool HandleEvent(Event e) { if (e is ItemUsedEvent iue && iue.Item.Type == ItemType.Weapon) { count = (count + 1) % 5; } else if (count == 0) { if (e is ProjectileCreatedEvent pce) { pce.Projectile.Scale += 1; } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyActiveChargeUse.cs ================================================ using System; using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class ModifyActiveChargeUse : ItemUse { private bool percent; private float amount; public override void Use(Entity entity, Item item) { var i = entity.GetComponent().Item; if (i == null) { return; } if (percent) { i.Delay = Math.Max(0, i.Delay - i.UseTime * amount * 0.01f); } else { i.Delay = Math.Max(0, i.Delay - amount); } if (i.Delay <= 0.001f) { i.Delay = 0; } } public override void Setup(JsonValue settings) { base.Setup(settings); percent = settings["percent"].Bool(false); amount = settings["amount"].Number(1f); } public static void RenderDebug(JsonValue root) { var percent = root["percent"].Bool(false); if (ImGui.Checkbox("Percent?", ref percent)) { root["percent"] = percent; } var amount = root["amount"].Number(1f); if (ImGui.InputFloat(percent ? "Amount (%)" : "Amount (charge)", ref amount)) { root["amount"] = amount; } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyArcUse.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class ModifyArcUse : ItemUse { public float Damage; public float Chance; public bool ToAny; public bool EventCreated = true; public string BuffToApply; public bool InfiniteBuff; public float BuffDuration; public bool RandomEffect; public float EffectChangeSpeed; public bool Mine; public float Scale; private float lastEffectTime; private int lastEffect = -1; private static string[] effects = { BurningBuff.Id, FrozenBuff.Id, PoisonBuff.Id, CharmedBuff.Id, SlowBuff.Id, BrokenArmorBuff.Id }; public override void Use(Entity entity, Item item) { } public override bool HandleEvent(Event e) { if (e is MeleeArc.CreatedEvent pce) { var a = Item == pce.By; if (ToAny || (EventCreated && a)) { ModifyProjectile(pce.Arc); } } return base.HandleEvent(e); } public void ModifyProjectile(MeleeArc arc) { if (Rnd.Float() > Chance + Run.Luck * 0.2f) { return; } arc.Mines = Mine; arc.Damage *= Damage; if (Math.Abs(Scale - 1) > 0.01f) { arc.Width *= Scale; arc.Height *= Scale; // arc.AdjustSize(); } if (RandomEffect) { if (lastEffect == -1 || (EffectChangeSpeed > 0 && Engine.Time - lastEffectTime >= EffectChangeSpeed)) { lastEffect = Rnd.Int(effects.Length); lastEffectTime = Engine.Time; } ApplyBuff(arc, effects[lastEffect]); return; } if (BuffToApply != null) { ApplyBuff(arc, BuffToApply); } } private void ApplyBuff(MeleeArc arc, string buff) { if (buff != null) { if (!BuffRegistry.All.TryGetValue(buff, out var info)) { Log.Error($"Unknown buff {buff}"); return; } arc.Color = info.Effect.GetColor(); arc.OnHurt += (p, e) => { if (e.TryGetComponent(out var buffs)) { var b = BuffRegistry.Create(buff); if (InfiniteBuff) { b.Infinite = true; } else { b.TimeLeft = b.Duration = BuffDuration; } buffs.Add(b); } }; } } public override void Setup(JsonValue settings) { base.Setup(settings); Chance = settings["chance"].Number(1); Damage = settings["damage"].Number(1); Scale = settings["scale"].Number(1); ToAny = settings["any"].Bool(false); Mine = settings["mine"].Bool(false); BuffToApply = settings["buff"].String(null); if (BuffToApply != null) { InfiniteBuff = settings["infinite_buff"].Bool(false); BuffDuration = settings["buff_time"].Number(10); } else { BuffDuration = 10; } RandomEffect = settings["rne"].Bool(false); if (RandomEffect) { EffectChangeSpeed = settings["ecs"].Number(3f); } } public static void RenderDebug(JsonValue root) { root.Checkbox("From Any Source", "any", false); root.InputFloat("Chance", "chance"); root.InputFloat("Damage Modifier", "damage"); root.InputFloat("Scale", "scale"); root.Checkbox("Make it mine", "mine", false); ImGui.Separator(); if (root.Checkbox("Random Effect", "rne", false)) { root.InputFloat("Effect Change Speed", "ecs", 3f); } else { if (ImGui.TreeNode("Buff")) { if (!BuffRegistry.All.ContainsKey(root.InputText("Buff", "buff", "bk:frozen"))) { ImGui.BulletText("Unknown buff!"); } if (!root.Checkbox("Infinite", "infinite_buff", false)) { root.InputFloat("Buff Duration", "buff_time"); } ImGui.TreePop(); } } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyBombsUse.cs ================================================ using System; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class ModifyBombsUse : ItemUse { public bool SpawnBullets; public bool SpawnBombs; public bool SetFuseTime; public float FuseTime; public float RadiusMod; public override void Setup(JsonValue settings) { base.Setup(settings); SpawnBullets = settings["spawn_bullets"].Bool(false); SpawnBombs = settings["spawn_bombs"].Bool(false); SetFuseTime = settings["set_fuse"].Bool(false); FuseTime = settings["fuse_time"].Number(1); RadiusMod = settings["radius"].Number(1); } public static void RenderDebug(JsonValue root) { var spawnBullets = root["spawn_bullets"].Bool(false); if (ImGui.Checkbox("Spawn Bullets?", ref spawnBullets)) { root["spawn_bullets"] = spawnBullets; } var spawnBombs = root["spawn_bombs"].Bool(false); if (ImGui.Checkbox("Spawn Bombs?", ref spawnBombs)) { root["spawn_bombs"] = spawnBombs; } root.InputFloat("Radius Modifier", "radius", 1f); var setFuseTime = root["set_fuse"].Bool(false); if (ImGui.Checkbox("Set fuse?", ref setFuseTime)) { root["set_fuse"] = setFuseTime; } if (!setFuseTime) { return; } var fuseTime = root["fuse_time"].Number(1); if (ImGui.InputFloat("Fuse time", ref fuseTime)) { root["fuse_time"] = fuseTime; } } public override bool HandleEvent(Event e) { if (e is BombPlacedEvent bpe) { var bomb = bpe.Bomb; var c = bomb.GetComponent(); c.Radius *= RadiusMod; if (SetFuseTime) { c.Timer = FuseTime + Rnd.Float(-0.1f, 1f); } if (SpawnBombs) { bomb.OnDeath += b => { if (b.Parent != null) { return; } for (var i = 0; i < 4; i++) { var bm = new Bomb(b.Owner, Bomb.ExplosionTime, b); b.Area.Add(bm); bm.Center = b.Center + Rnd.Vector(-4, 4); bm.VelocityTo(i / 2f * (float) Math.PI, 300f); } }; } if (SpawnBullets) { bomb.OnDeath += b => { var builder = new ProjectileBuilder(b.Owner, "rect") { Scale = b.Scale }; for (var i = 0; i < 8; i++) { builder.Shoot((float) i / 8 * (float) Math.PI * 2, 8).Build().Center = b.Center; } }; } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyConsumableWeightsUse.cs ================================================ using System; using BurningKnight.entity.events; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyConsumableWeightsUse : ItemUse { private bool keys; private bool bombs; private bool coins; private float amount; public override bool HandleEvent(Event e) { if (e is ConsumableAddedEvent cae) { var t = cae.Type; if ((t == ItemType.Coin && coins) || (t == ItemType.Bomb && bombs) || (t == ItemType.Key && keys)) { cae.TotalNow -= cae.Amount; cae.Amount = (int) Math.Round(cae.Amount * amount); cae.TotalNow += cae.Amount; } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); amount = settings["amount"].Int(1); keys = settings["keys"].Bool(false); bombs = settings["bombs"].Bool(false); coins = settings["coins"].Bool(true); } public static void RenderDebug(JsonValue root) { root.InputInt("Modifier", "amount"); root.Checkbox("Coins", "coins", true); root.Checkbox("Keys", "keys", false); root.Checkbox("Bombs", "bombs", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyGameSaveValueUse.cs ================================================ using BurningKnight.save; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyGameSaveValueUse : ItemUse { private string id; private float amount; private bool over; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (item.Used) { return; } GameSave.Put(id, over ? amount : GameSave.GetFloat(id) + amount); } public override void Setup(JsonValue settings) { base.Setup(settings); id = settings["idd"].String(""); amount = settings["am"].Number(0); over = settings["ov"].Bool(false); } public static void RenderDebug(JsonValue root) { var id = root["idd"].String(""); if (ImGui.InputText("Field id##gs", ref id, 128)) { root["idd"] = id; } var amount = root["am"].Number(0); if (ImGui.InputFloat("Amount##gs", ref amount)) { root["am"] = amount; } var over = root["ov"].Bool(false); if (ImGui.Checkbox("Override?", ref over)) { root["ov"] = over; } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyGenUse.cs ================================================ using BurningKnight.entity.projectile; using BurningKnight.save; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyGenUse : ItemUse { private bool xlLevel; private float chestRewardChance; private float mobDest; private float mimicChance; private bool genMarket; private bool shops; private bool treasure; private bool melee; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (xlLevel) { LevelSave.XL = true; } LevelSave.ChestRewardChance += chestRewardChance; LevelSave.MobDestructionChance += mobDest; LevelSave.MimicChance += mimicChance; LevelSave.GenerateMarket = genMarket; LevelSave.GenerateShops = shops; LevelSave.GenerateTreasure = treasure; LevelSave.MeleeOnly = melee; } public override void Setup(JsonValue settings) { base.Setup(settings); xlLevel = settings["xl"].Bool(false); chestRewardChance = settings["crc"].Number(0); mobDest = settings["md"].Number(0); mimicChance = settings["mimic"].Number(0); genMarket = settings["gm"].Bool(false); shops = settings["sp"].Bool(false); treasure = settings["tr"].Bool(false); melee = settings["ml"].Bool(false); } public static void RenderDebug(JsonValue root) { root.Checkbox("XL Level", "xl", false); root.Checkbox("Generate Market", "gm", false); root.Checkbox("Only Shops", "sp", false); root.Checkbox("Only Treasure", "tr", false); root.Checkbox("Only Generate Melee", "ml", false); root.InputFloat("Chest Reward Chance Modifier", "crc", 0); root.InputFloat("Mob Not Shoot Chance Modifier", "md", 0); root.InputFloat("Mimic Chance Modifier", "mimic", 0); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyHpUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyHpUse : ItemUse { public int Amount; public bool SetToMin; public bool SetToMax; public override void Use(Entity entity, Item item) { if (SetToMin) { entity.GetComponent().InitMaxHealth = 1; return; } if (SetToMax) { var h = entity.GetComponent(); h.ModifyHealth(h.MaxHealth, item); return; } var a = Amount; if (a > 0 && Scourge.IsEnabled(Scourge.OfIllness)) { if (a == 1) { return; } a = (int) (a / 2f); } entity.GetComponent().ModifyHealth(a, entity); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); SetToMin = settings["to_min"].Bool(false); SetToMax = settings["to_max"].Bool(false); } public static void RenderDebug(JsonValue root) { root.InputInt("Amount", "amount"); root.Checkbox("Set To Min", "to_min", false); root.Checkbox("Fully Heal", "to_max", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyLuckUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.state; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyLuckUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { Run.Luck += Amount; TextParticle.Add(entity, Locale.Get("luck"), Amount, true, Amount < 0); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyManaMaxUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyManaMaxUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { var m = entity.GetComponent(); m.ManaMax += Amount * 2; m.ModifyMana(Amount * 2); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { root.InputInt("Amount", "amount"); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyManaUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyManaUse : ItemUse { public int Amount; public bool SetToMin; public bool SetToMax; public override void Use(Entity entity, Item item) { if (SetToMin) { entity.GetComponent().SetMana(1); return; } if (SetToMax) { var h = entity.GetComponent(); h.ModifyMana(h.ManaMax); return; } entity.GetComponent().ModifyMana(Amount); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); SetToMin = settings["to_min"].Bool(false); SetToMax = settings["to_max"].Bool(false); } public static void RenderDebug(JsonValue root) { root.InputInt("Amount", "amount"); root.Checkbox("Set To Min", "to_min", false); root.Checkbox("Set To Max", "to_max", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyMaxHpUse.cs ================================================ using System; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.util; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyMaxHpUse : ItemUse { public int Amount; public bool Set; public bool GiveHp; public bool Bomb; public override void Use(Entity entity, Item item) { if (Bomb) { var component = entity.GetComponent(); if (Set) { component.BombsMax = Amount; } else { component.BombsMax += Amount; } if (GiveHp && Amount > 0) { component.ModifyBombs(Amount, entity); TextParticle.Add(entity, "HP", Amount, true); } } else { if (Amount > 0) { if (entity.GetComponent().Item?.Id == "bk:shielded_lamp") { entity.GetComponent().ModifyShields(Amount, entity); return; } else if (entity.GetComponent().Item?.Id == "bk:explosive_lamp") { var c = entity.GetComponent(); Amount = (int) Math.Ceiling(Amount / 2f); c.BombsMax += Amount; if (GiveHp) { c.ModifyBombs(Amount, entity); TextParticle.Add(entity, "HP", Amount, true); } return; } } var component = entity.GetComponent(); if (Set) { component.MaxHealth = Amount; } else { component.MaxHealth += Amount; } if (GiveHp && Amount > 0) { component.ModifyHealth(Amount, entity); TextParticle.Add(entity, "HP", Amount, true); } } TextParticle.Add(entity, Locale.Get("max_hp"), Math.Abs(Amount), true, Amount < 0); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); GiveHp = settings["give_hp"].Bool(true); Set = settings["set"].Bool(false); Bomb = settings["bomb"].Bool(false); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } var giveHp = root["give_hp"].Bool(true); if (ImGui.Checkbox("Give health", ref giveHp)) { root["give_hp"] = giveHp; } root.Checkbox("Set", "set", false); root.Checkbox("Bomb", "bomb", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyProjectileTextureUse.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyProjectileTextureUse : ItemUse { private string texture; public override void Use(Entity entity, Item item) { if (entity is Player p) { p.ProjectileTexture = texture; } } public override void Setup(JsonValue settings) { base.Setup(settings); texture = settings["texture"].String("rect"); } public static void RenderDebug(JsonValue root) { root.InputText("Texture", "texture", "rect"); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyProjectilesUse.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class ModifyProjectilesUse : ItemUse { public bool SetScale; public float Scale; public bool SetDamage; public float Damage; public bool SetRange; public float Range; public float Chance; public bool ToAny; public bool EventCreated = true; public string BuffToApply; public bool InfiniteBuff; public float BuffDuration; public bool Explosive; public bool RandomEffect; public float EffectChangeSpeed; private float lastEffectTime; private int lastEffect = -1; private static string[] effects = { BurningBuff.Id, FrozenBuff.Id, PoisonBuff.Id, CharmedBuff.Id, SlowBuff.Id, BrokenArmorBuff.Id }; public override void Use(Entity entity, Item item) { } public override bool HandleEvent(Event e) { if (e is ProjectileCreatedEvent pce) { if (ToAny || (EventCreated && Item == pce.Item)) { ModifyProjectile(pce.Projectile); } } return base.HandleEvent(e); } public void ModifyProjectile(Projectile projectile) { if (Rnd.Float() > Chance + Run.Luck * 0.2f) { return; } // This might turn out to be a disaster if (SetRange) { projectile.T = Range; } else { projectile.T *= Range; } if (SetDamage) { projectile.Damage = Damage; } else { projectile.Damage *= Damage; } if (SetScale) { projectile.Scale = Scale; } else { projectile.Scale *= Scale; } if (RandomEffect) { if (lastEffect == -1 || (EffectChangeSpeed > 0 && Engine.Time - lastEffectTime >= EffectChangeSpeed)) { lastEffect = Rnd.Int(effects.Length + 1); lastEffectTime = Engine.Time; } var e = lastEffect == effects.Length; ApplyBuff(projectile, e ? null : effects[lastEffect], e); return; } if (BuffToApply != null || Explosive) { ApplyBuff(projectile, BuffToApply, Explosive); } } private void ApplyBuff(Projectile projectile, string buff, bool explosive) { if (explosive) { projectile.Color = ProjectileColor.Brown; ProjectileCallbacks.AttachDeathCallback(projectile, (p, en, t) => { ExplosionMaker.Make(p, 32, false, damage: 4, scale: 0.5f); }); } if (buff != null) { if (!BuffRegistry.All.TryGetValue(buff, out var info)) { Log.Error($"Unknown buff {buff}"); return; } projectile.Color = info.Effect.GetColor(); ProjectileCallbacks.AttachHurtCallback(projectile, (p, e) => { if (e.TryGetComponent(out var buffs) && !e.GetComponent().Unhittable) { var b = BuffRegistry.Create(buff); if (InfiniteBuff) { b.Infinite = true; } else { b.TimeLeft = b.Duration = BuffDuration; } buffs.Add(b); } }); } } public override void Setup(JsonValue settings) { base.Setup(settings); Chance = settings["chance"].Number(1); Scale = settings["amount"].Number(1); Damage = settings["damage"].Number(1); Range = settings["range"].Number(1); SetScale = settings["samount"].Bool(false); SetDamage = settings["sdamage"].Bool(false); SetRange = settings["srange"].Bool(false); ToAny = settings["any"].Bool(false); Explosive = settings["explosive"].Bool(false); BuffToApply = settings["buff"].String(null); if (BuffToApply != null) { InfiniteBuff = settings["infinite_buff"].Bool(false); BuffDuration = settings["buff_time"].Number(10); } else { BuffDuration = 10; } RandomEffect = settings["rne"].Bool(false); if (RandomEffect) { EffectChangeSpeed = settings["ecs"].Number(3f); } } public static void RenderDebug(JsonValue root) { root.Checkbox("From Any Source", "any", false); root.InputFloat("Chance", "chance"); root.Checkbox("Set Scale", "samount"); root.InputFloat("Scale Modifier", "amount"); root.Checkbox("Set Damage", "sdamage"); root.InputFloat("Damage Modifier", "damage"); root.Checkbox("Set Range", "srange"); root.InputFloat("Range Modifier", "range"); ImGui.Separator(); if (root.Checkbox("Random Effect", "rne", false)) { root.InputFloat("Effect Change Speed", "ecs", 3f); } else { root.Checkbox("Make Explosive", "explosive", false); if (ImGui.TreeNode("Buff")) { if (!BuffRegistry.All.ContainsKey(root.InputText("Buff", "buff", "bk:frozen"))) { ImGui.BulletText("Unknown buff!"); } if (!root.Checkbox("Infinite", "infinite_buff", false)) { root.InputFloat("Buff Duration", "buff_time"); } ImGui.TreePop(); } } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyShieldHeartsUse.cs ================================================ using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyShieldHeartsUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { entity.GetComponent().ModifyShields(Amount * 2, entity); } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyShootUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyShootUse : ItemUse { private int amount; public override bool HandleEvent(Event e) { if (e is PlayerShootEvent pse) { pse.Times += amount; pse.Accurate = true; } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { root.InputInt("Amount", "amount", 1); } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyStatUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyStatUse : ItemUse { private Stat stat; private float value; public override void Use(Entity entity, Item item) { switch (stat) { case Stat.InvincibilityTime: { entity.GetComponent().InvincibilityTimerMax += value; TextParticle.Add(entity, Locale.Get("invincibility_time")); break; } } } public override void Setup(JsonValue settings) { base.Setup(settings); stat = (Stat) settings["stat"].Int(0); value = settings["val"].Number(1); } public static void RenderDebug(JsonValue root) { var stat = root["stat"].Int(0); if (ImGui.Combo("Stat", ref stat, stats, stats.Length)) { root["stat"] = stat; } var value = root["val"].Number(1); if (ImGui.InputFloat("Amount", ref value)) { root["val"] = value; } } private enum Stat { InvincibilityTime, Total } private static string[] stats; static ModifyStatUse() { stats = new string[(int) Stat.Total]; for (var i = 0; i < (int) Stat.Total; i++) { stats[i] = $"{(Stat) i}"; } } } } ================================================ FILE: BurningKnight/entity/item/use/ModifyStatsUse.cs ================================================ using System; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class ModifyStatsUse : ItemUse { public float Speed; public bool AddSpeed; public float Damage; public bool AddDamage; public float FireRate; public bool AddFireRate; public float RangedRate; public bool AddRangedRate; public float Accuracy; public bool AddAccuracy; public float Range; public bool AddRange; public float Knockback; public bool AddKnockback; public override void Use(Entity entity, Item item) { base.Use(entity, item); var stats = entity.GetComponent(); if (Math.Abs(Math.Abs(Speed) - (AddSpeed ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("speed"), Math.Abs(Speed), true, Speed < 0); if (AddSpeed) { stats.Speed += Speed; } else { stats.Speed *= Speed; } } if (Math.Abs(Math.Abs(Damage) - (AddDamage ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("damage"), Math.Abs(Damage), true, Damage < 0); if (AddDamage) { stats.Damage += Damage; } else { stats.Damage *= Damage; } } if (Math.Abs(Math.Abs(FireRate) - (AddFireRate ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("fire_rate"), Math.Abs(FireRate), true, FireRate < 0); if (AddFireRate) { stats.FireRate += FireRate; } else { stats.FireRate *= FireRate; } } if (Math.Abs(Math.Abs(RangedRate) - (AddRangedRate ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("fire_rate"), Math.Abs(RangedRate), true, RangedRate < 0); if (AddRangedRate) { stats.RangedRate += RangedRate; } else { stats.RangedRate *= RangedRate; } } if (Math.Abs(Math.Abs(Accuracy) - (AddAccuracy ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("accuracy"), Math.Abs(Accuracy), true, Accuracy < 0); if (AddAccuracy) { stats.Accuracy += Accuracy; } else { stats.Accuracy *= Accuracy; } } if (Math.Abs(Math.Abs(Range) - (AddRange ? 0 : 1)) >= 0.01f) { TextParticle.Add(entity, Locale.Get("range"), Math.Abs(Range), true, Range < 0); if (AddRange) { stats.Range += Range; } else { stats.Range *= Range; } } } public override void Setup(JsonValue settings) { base.Setup(settings); Speed = settings["speed"].Number(0); AddSpeed = settings["add_speed"].Bool(true); Damage = settings["damage"].Number(0); AddDamage = settings["add_damage"].Bool(true); FireRate = settings["fire_rate"].Number(0); AddFireRate = settings["add_fire_rate"].Bool(true); RangedRate = settings["ranged_rate"].Number(0); AddRangedRate = settings["add_ranged_rate"].Bool(true); Accuracy = settings["accuracy"].Number(0); AddAccuracy = settings["add_accuracy"].Bool(true); Range = settings["range"].Number(0); AddRange = settings["add_range"].Bool(true); Knockback = settings["knockback"].Number(0); AddKnockback = settings["add_knockback"].Bool(true); } public static void RenderDebug(JsonValue root) { root.InputFloat("Speed", "speed", 0); root.Checkbox("Add Speed", "add_speed"); root.InputFloat("Damage", "damage", 0); root.Checkbox("Add Damage", "add_damage"); root.InputFloat("Fire Rate", "fire_rate", 0); root.Checkbox("Add Fire Rate", "add_fire_rate"); root.InputFloat("Ranged Rate", "ranged_rate", 0); root.Checkbox("Add Ranged Rate", "add_ranged_rate"); root.InputFloat("Accuracy", "accuracy", 0); root.Checkbox("Add Accuracy", "add_accuracy"); root.InputFloat("Range", "range", 0); root.Checkbox("Add Range", "add_range"); root.InputFloat("Knockback", "knockback", 0); root.Checkbox("Add Knockback", "add_knockback"); } } } ================================================ FILE: BurningKnight/entity/item/use/PlaceDecoyUse.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature; using Lens.entity; namespace BurningKnight.entity.item.use { public class PlaceDecoyUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var decoy = new Decoy(); entity.Area.Add(decoy); decoy.BottomCenter = entity.BottomCenter; entity.GetComponent().Add(new InvisibleBuff { Infinite = true }); decoy.OnDeath += () => { entity.GetComponent().Remove(); }; } } } ================================================ FILE: BurningKnight/entity/item/use/PokemonUse.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.mob.prefabs; using BurningKnight.entity.events; using Lens.entity; using Lens.util; namespace BurningKnight.entity.item.use { public class PokemonUse : ItemUse { private Type type; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (type == null) { return; } try { var m = (Mob) Activator.CreateInstance(type); entity.Area.Add(m); m.GetComponent().Add(new CharmedBuff { Infinite = true }); var h = m.GetComponent(); h.InitMaxHealth = (int) (h.Health * 3); m.Center = entity.Center; } catch (Exception e) { Log.Error(e); } } public override bool HandleEvent(Event e) { if (e is KilledEvent k && k.KilledBy == Item.Owner && k.Who is Mob m && !(m is WallWalker || m is Boss)) { type = k.Who.GetType(); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/PoofUse.cs ================================================ using BurningKnight.assets.particle; using BurningKnight.state; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class PoofUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var where = entity.Center; for (var i = 0; i < 20; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = where + Rnd.Vector(-16, 16); part.Particle.Scale = Rnd.Float(1, 2f); Run.Level.Area.Add(part); } } } } ================================================ FILE: BurningKnight/entity/item/use/PreventDamageUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.room.controllable.spikes; using BurningKnight.level; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class PreventDamageUse : ItemUse { private bool spikes; private bool lava; private bool chasm; private bool bombs; private bool contact; public override bool HandleEvent(Event e) { if (e is HealthModifiedEvent ev) { if ((spikes && ev.From is Spikes) || (lava && ev.From is Level) || (chasm && ev.From is Chasm) || (bombs && ev.Type == DamageType.Explosive) || (contact && ev.Type == DamageType.Contact)) { return true; } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); lava = settings["lv"].Bool(false); spikes = settings["sp"].Bool(false); chasm = settings["cs"].Bool(false); bombs = settings["bms"].Bool(false); contact = settings["cnt"].Bool(false); } public static void RenderDebug(JsonValue root) { var v = root["lv"].Bool(false); if (ImGui.Checkbox("From lava", ref v)) { root["lv"] = v; } v = root["sp"].Bool(false); if (ImGui.Checkbox("From spikes", ref v)) { root["sp"] = v; } v = root["cs"].Bool(false); if (ImGui.Checkbox("From chasm", ref v)) { root["cs"] = v; } v = root["bms"].Bool(false); if (ImGui.Checkbox("From explosions", ref v)) { root["bms"] = v; } root.Checkbox("From Contact", "cnt", false); } } } ================================================ FILE: BurningKnight/entity/item/use/RandomActiveUse.cs ================================================ using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.entity.component; using Lens.entity; using Lens.util; using Lens.util.timer; namespace BurningKnight.entity.item.use { public class RandomActiveUse : ItemUse { public override void Use(Entity entity, Item item) { var id = Items.Generate(ItemType.Active); if (id == null) { Log.Error("Failed to chose an active item"); return; } Log.Info($"Using active item {id} with d8"); var it = Items.Create(id); item.GetComponent().Sprite = CommonAse.Items.GetSlice(id); foreach (var u in it.Uses) { u.Item = it; u.Use(entity, it); } Timer.Add(() => { item.GetComponent().Sprite = CommonAse.Items.GetSlice(item.Id); }, 2); } } } ================================================ FILE: BurningKnight/entity/item/use/RandomUse.cs ================================================ using BurningKnight.entity.item.use.parent; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class RandomUse : DoUsesUse { protected override void DoAction(Entity entity, Item item, ItemUse use) { } public override void Use(Entity entity, Item item) { base.Use(entity, item); Uses[Rnd.Int(Uses.Length)].Use(entity, item); } } } ================================================ FILE: BurningKnight/entity/item/use/RegenUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.level.entities.chest; using BurningKnight.util; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class RegenUse : ItemUse { private int speed; private int count; private bool onKills; private bool onChests; private bool onPurchase; public override void Use(Entity entity, Item item) { base.Use(entity, item); entity.Subscribe(); } public override bool HandleEvent(Event e) { if (e is KilledEvent) { if (onKills) { count++; if (count >= speed) { count = 0; Item.Owner.GetComponent().ModifyHealth(1, Item); } } } else if (e is Chest.OpenedEvent) { if (onChests) { Item.Owner.GetComponent().ModifyHealth(1, Item); } } else if (e is ItemBoughtEvent) { if (onPurchase) { Item.Owner.GetComponent().ModifyHealth(1, Item); } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Int(10); onKills = settings["kills"].Bool(true); onChests = settings["chests"].Bool(false); onPurchase = settings["purchase"].Bool(false); } public static void RenderDebug(JsonValue root) { if (root.Checkbox("On Kills", "kills", true)) { root.InputInt("Speed", "speed", 10); } root.Checkbox("On Chests", "chests", false); root.Checkbox("On Purchase", "purchase", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ReplaceHeartsWithShieldsUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.assets; using Lens.entity; namespace BurningKnight.entity.item.use { public class ReplaceHeartsWithShieldsUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var h = entity.GetComponent(); var amount = h.MaxHealth; if (amount == 0) { return; } entity.GetComponent().ModifyShields(amount, item); h.InitMaxHealth = 0; TextParticle.Add(entity, Locale.Get("max_hp"), amount, true, true); TextParticle.Add(entity, Locale.Get("shields"), amount, true); } } } ================================================ FILE: BurningKnight/entity/item/use/RerollAndHideUse.cs ================================================ namespace BurningKnight.entity.item.use { public class RerollAndHideUse : RerollItemsUse { protected override void ProcessItem(Item item) { base.ProcessItem(item); item.Unknown = true; } } } ================================================ FILE: BurningKnight/entity/item/use/RerollItemsOnPlayerUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class RerollItemsOnPlayerUse : ItemUse { private bool rerollWeapons; private bool rerollArtifacts; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (rerollArtifacts) { Reroll(entity, entity.GetComponent()); } if (rerollWeapons) { Reroll(entity.GetComponent()); Reroll(entity.GetComponent()); } entity.HandleEvent(new RerolledEvent { Entity = entity }); } private void Reroll(ItemComponent component) { if (component?.Item == null) { return; } var item = component.Item; Reroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type); } private void Reroll(Entity entity, InventoryComponent component) { if (entity is Player player) { player.InitStats(); } foreach (var item in component.Items) { Reroller.Reroll(item, ItemPool.Treasure, i => item.Type == i.Type); item.Use(entity); } } public override void Setup(JsonValue settings) { base.Setup(settings); rerollWeapons = settings["weapons"].Bool(false); rerollArtifacts = settings["artifacts"].Bool(true); } public static void RenderDebug(JsonValue root) { var rerollWeapons = root["weapons"].Bool(false); if (ImGui.Checkbox("Reroll weapons?", ref rerollWeapons)) { root["weapons"] = rerollWeapons; } var rerollArtifacts = root["artifacts"].Bool(true); if (ImGui.Checkbox("Reroll artifacts?", ref rerollArtifacts)) { root["artifacts"] = rerollArtifacts; } } public class RerolledEvent : Event { public Entity Entity; } } } ================================================ FILE: BurningKnight/entity/item/use/RerollItemsUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.item.stand; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use { public class RerollItemsUse : ItemUse { private bool rerollStands; private bool spawnNewItems; private bool ignore; private ItemType[] types; private float consumeChance; private bool d2; public override void Use(Entity entity, Item self) { var room = entity.GetComponent().Room; if (room == null) { return; } Reroller.Reroll(entity.Area, room, rerollStands, spawnNewItems, ignore, types, ProcessItem, d2); } protected virtual void ProcessItem(Item item) { if (consumeChance > 0 && Rnd.Chance(consumeChance * 100)) { item.Done = true; } } public override void Setup(JsonValue settings) { base.Setup(settings); rerollStands = settings["r_stands"].Bool(true); spawnNewItems = settings["s_new"].Bool(true); ignore = settings["ignore"].Bool(true); consumeChance = settings["cc"].Number(0); d2 = settings["d2"].Bool(false); var tps = settings["types"]; if (tps.IsJsonArray) { var tp = tps.AsJsonArray; if (tp.Count == 0) { return; } types = new ItemType[tp.Count]; for (var i = 0; i < tp.Count; i++) { types[i] = (ItemType) tp[i].Int(0); } } } public static void RenderDebug(JsonValue root) { var rerollStands = root["r_stands"].Bool(true); var spawnNew = root["s_new"].Bool(true); var ignore = root["ignore"].Bool(true); root.InputFloat("Consume Chance", "cc", 0); root.Checkbox("D2", "d2", false); if (ImGui.Checkbox("Reroll stands", ref rerollStands)) { root["r_stands"] = rerollStands; } if (ImGui.Checkbox("Spawn new", ref spawnNew)) { root["s_new"] = spawnNew; } var tps = root["types"]; if (!tps.IsJsonArray) { tps = root["types"] = new JsonArray(); } if (ImGui.TreeNode("Item types")) { if (ImGui.Checkbox("Ignore those types", ref ignore)) { root["ignore"] = ignore; } ImGui.Separator(); var tp = tps.AsJsonArray; var toRemove = -1; var toAdd = -1; for (var i = 0; i < ItemEditor.Types.Length; i++) { var v = tp.Contains(i); if (ImGui.Checkbox(ItemEditor.Types[i], ref v)) { if (v) { toAdd = i; } else { toRemove = tp.IndexOf(i); } } } if (toRemove != -1) { tp.Remove(toRemove); } else if (toAdd != -1) { tp.Add(toAdd); } ImGui.TreePop(); } } } } ================================================ FILE: BurningKnight/entity/item/use/RevealMapUse.cs ================================================ using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.state; using Lens.assets; using Lens.entity; using Lens.util.math; namespace BurningKnight.entity.item.use { public class RevealMapUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); var level = Run.Level; Audio.PlaySfx("item_map"); foreach (var e in entity.Area.Tagged[Tags.Room]) { var room = (Room) e; if (room.Type == RoomType.DarkMarket || room.Type == RoomType.Hidden) { continue; } if (Rnd.Chance(95) && room.Type != RoomType.Secret && room.Type != RoomType.Granny && room.Type != RoomType.OldMan) { for (var y = room.MapY; y < room.MapY + room.MapH; y++) { for (var x = room.MapX; x < room.MapX + room.MapW; x++) { level.Explored[level.ToIndex(x, y)] = true; } } room.Explored = true; } } } } } ================================================ FILE: BurningKnight/entity/item/use/SaleItemsUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item.stand; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class SaleItemsUse : ItemUse { private float percent; private bool onlyOnceUsed; private bool used; public override void Use(Entity entity, Item item) { used = true; foreach (var i in entity.GetComponent().Room.Tagged[Tags.Item]) { if (i is ShopStand s) { s.Recalculate(); } } used = false; } public override bool HandleEvent(Event e) { if (e is ItemPriceCalculationEvent ipce) { if (!onlyOnceUsed || used) { ipce.Percent += percent; } } return base.HandleEvent(e); } public override void Setup(JsonValue settings) { base.Setup(settings); percent = settings["prc"].Number(50f); onlyOnceUsed = settings["wu"].Bool(false); } public static void RenderDebug(JsonValue root) { var v = root["prc"].Number(50f); if (ImGui.InputFloat("% sale", ref v)) { root["prc"] = v; } root.Checkbox("Only when used", "wu", false); } } } ================================================ FILE: BurningKnight/entity/item/use/ScourgeUse.cs ================================================ using BurningKnight.assets.particle.custom; using BurningKnight.state; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class ScourgeUse : ItemUse { private int amount; public override void Use(Entity entity, Item item) { base.Use(entity, item); for (var i = 0; i < amount; i++) { Run.AddScourge(); } } public override void Setup(JsonValue settings) { base.Setup(settings); amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { root.InputInt("Amount", "amount"); } } } ================================================ FILE: BurningKnight/entity/item/use/SetKnockbackModifierUse.cs ================================================ using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class SetKnockbackModifierUse : ItemUse { private float mod; public override void Use(Entity entity, Item item) { entity.GetAnyComponent().KnockbackModifier = mod; } public override void Setup(JsonValue settings) { base.Setup(settings); mod = settings["mod"].Number(0); } public static void RenderDebug(JsonValue root) { var val = root["mod"].Number(0); if (ImGui.InputFloat("Modifier", ref val)) { root["mod"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/SetMaxHpUse.cs ================================================ using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use { public class SetMaxHpUse : ItemUse { public int Amount; public override void Use(Entity entity, Item item) { var component = entity.GetComponent(); component.InitMaxHealth = Amount + 1; // 1 is hidden } public override void Setup(JsonValue settings) { base.Setup(settings); Amount = settings["amount"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } } } } ================================================ FILE: BurningKnight/entity/item/use/SetMusicSpeed.cs ================================================ using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.lightJson; using Lens.util.tween; namespace BurningKnight.entity.item.use { public class SetMusicSpeed : ItemUse { private float speed; public override void Use(Entity entity, Item item) { Tween.To(speed, Audio.Speed, x => Audio.Speed = x, 0.4f); } public override void Setup(JsonValue settings) { base.Setup(settings); speed = settings["speed"].Number(1f); } public static void RenderDebug(JsonValue root) { root.InputFloat("Speed", "speed", 1f); } } } ================================================ FILE: BurningKnight/entity/item/use/ShootLaserUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class ShootLaserUse : ShootUse { public override void Setup(JsonValue settings) { base.Setup(settings); var ac = 0.1f; SpawnProjectile = (entity, item) => { var aim = entity.GetComponent(); var from = aim.Center; var am = aim.RealAim; var a = MathUtils.Angle(am.X - from.X, am.Y - from.Y); entity.GetComponent().EmitRandomized("item_laser_player"); var cnt = 1; var accurate = false; if (entity is Player pl) { var e = new PlayerShootEvent { Player = pl }; entity.HandleEvent(e); cnt += e.Times - 1; accurate = e.Accurate; } for (var i = 0; i < cnt; i++) { var addition = 0f; if (accurate) { addition = (i - (int) (cnt * 0.5f)) * 0.2f + Rnd.Float(-ac / 2f, ac / 2f); } else if (cnt == 1 || i > 0) { addition = Rnd.Float(-ac / 2f, ac / 2f); } var laser = Laser.Make(entity, a, addition, item, damage: (item.Scourged ? 1.5f : 1f)); laser.Position = from; laser.PlayerRotated = true; laser.Damage *= 1.2f; laser.Recalculate(); } }; } } } ================================================ FILE: BurningKnight/entity/item/use/ShootQueueUse.cs ================================================ using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.camera; using Lens.util.timer; namespace BurningKnight.entity.item.use { public class ShootQueueUse : SimpleShootUse { private int amount; private float delay; public override void Use(Entity entity, Item item) { if (wait && !ProjectileDied) { return; } for (var i = 0; i < amount; i++) { if (i == 0) { SpawnProjectile(entity, item); } else { Timer.Add(() => SpawnProjectile(entity, item), i * delay); } } Camera.Instance.ShakeMax(1.5f); } public override void Setup(JsonValue settings) { base.Setup(settings); amount = settings["amn"].Int(3); delay = settings["dl"].Number(0.1f); } public static void RenderDebug(JsonValue root) { SimpleShootUse.RenderDebug(root); var amount = root["amn"].Int(3); if (ImGui.InputInt("Projectile Count", ref amount)) { root["amn"] = amount; } var delay = root["dl"].Number(0.1f); if (ImGui.InputFloat("Projectile Delay", ref delay)) { root["dl"] = delay; } } } } ================================================ FILE: BurningKnight/entity/item/use/ShootUse.cs ================================================ using System; using Lens.entity; using Lens.util.camera; namespace BurningKnight.entity.item.use { public class ShootUse : ItemUse { public Action SpawnProjectile; public override void Use(Entity entity, Item item) { SpawnProjectile(entity, item); Camera.Instance.ShakeMax(3); } } } ================================================ FILE: BurningKnight/entity/item/use/SimpleShootUse.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.items; using BurningKnight.assets.particle; using BurningKnight.assets.particle.controller; using BurningKnight.assets.particle.custom; using BurningKnight.assets.particle.renderer; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens.assets; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.camera; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; using Num = System.Numerics; namespace BurningKnight.entity.item.use { public class SimpleShootUse : ShootUse { private static string[] manaDropNames = { "Where it lands", "Where it starts", "Where it starts, after death" }; private float damage; private float speed; private float speedMax; private float range; private float scaleMin; private float scaleMax; private string slice; private float accuracy; private int count; private string prefab; private bool light; private float knockback; private bool rect; private string sfx; private int sfxNumber; private int manaUsage; protected bool wait; private bool toCursor; private bool toEnemy; private string color; public bool ReloadSfx; private bool shells; private int manaDrop; private float angleAdd; private bool emeralds; public bool ProjectileDied = true; private ItemUse[] modifiers; public override void Setup(JsonValue settings) { base.Setup(settings); #region Json parsing modifiers = Items.ParseUses(settings["modifiers"]); if (modifiers != null) { foreach (var m in modifiers) { m.Item = Item; } } damage = settings["damage"].Number(1); speed = settings["speed"].Number(6); speedMax = settings["speedm"].Number(10); range = settings["range"].Number(0) * 0.5f; scaleMin = settings["scale"].Number(1); scaleMax = settings["scalem"].Number(1); slice = settings["texture"].String("rect"); toCursor = settings["cursor"].Bool(false); toEnemy = settings["tomb"].Bool(false); sfx = settings["sfx"].String("item_gun_fire"); sfxNumber = settings["sfxn"].Int(0); ReloadSfx = settings["rsfx"].Bool(false); manaUsage = settings["mana"].Int(0); color = settings["color"].String(""); angleAdd = settings["ang"].Number(0); if (manaUsage > 0) { manaDrop = settings["mdr"].Int(0); } if (slice == "default") { slice = "rect"; } accuracy = settings["accuracy"].Number(0).ToRadians(); count = settings["amount"].Int(1); prefab = settings["prefab"].String(""); light = settings["light"].Bool(true); knockback = settings["knockback"].Number(1); rect = settings["rect"].Bool(false); wait = settings["wait"].Bool(false); shells = settings["shells"].Bool(true); emeralds = settings["emeralds"].Bool(false); #endregion SpawnProjectile = (entity, item) => { if (manaUsage > 0) { var mana = entity.GetComponent(); if (mana.Mana < manaUsage) { AnimationUtil.ActionFailed(); return; } mana.ModifyMana(-manaUsage); } if (emeralds) { if (GlobalSave.Emeralds == 0) { AnimationUtil.ActionFailed(); TextParticle.Add(entity, Locale.Get("no_emeralds")); return; } GlobalSave.Emeralds--; } var bad = entity is Creature c && !c.IsFriendly(); var sl = slice; if (bad) { sl = "small"; } if (sfx == "item_gun_fire") { entity.GetComponent().EmitRandomizedPrefixed(sfx, 2, 0.5f, sz: 0.2f); } else { if (sfxNumber == 0) { entity.GetComponent().EmitRandomized(sfx, 0.5f, sz: 0.25f); } else { entity.GetComponent().EmitRandomizedPrefixed(sfx, sfxNumber, 0.5f, sz: 0.25f); } } var aim = entity.GetComponent(); var from = toCursor ? entity.Center : aim.Center; var am = toCursor ? entity.GetComponent().Cursor.GamePosition : aim.RealAim; if (toEnemy) { var target = entity.Area.FindClosest(from, Tags.MustBeKilled, e => true); if (target != null) { am = target.Center; } } var a = MathUtils.Angle(am.X - from.X, am.Y - from.Y); var pr = prefab.Length == 0 ? null : ProjectileRegistry.Get(prefab); var ac = accuracy; entity.TryGetComponent(out var stats); if (stats != null) { ac /= stats.Accuracy; } var cnt = count; var accurate = false; if (entity is Player pl) { var e = new PlayerShootEvent { Player = (Player) entity }; entity.HandleEvent(e); cnt += e.Times - 1; accurate = e.Accurate; if (sl == "rect") { sl = pl.ProjectileTexture; } } for (var i = 0; i < cnt; i++) { var angle = a; if (accurate) { angle += (i - (int) (cnt * 0.5f)) * 0.2f + Rnd.Float(-ac / 2f, ac / 2f); } else if (cnt == 1 || i > 0) { angle += Rnd.Float(-ac / 2f, ac / 2f); } angle += angleAdd * (float) Math.PI * 2; var antiAngle = angle - (float) Math.PI; var builder = new ProjectileBuilder(Item, sl); builder.Shoot(angle, Rnd.Float(speed, speedMax)); builder.Scale = Rnd.Float(scaleMin, scaleMax); builder.Damage = damage * (item.Scourged ? 1.5f : 1f); builder.RectHitbox = rect; builder.Range = range; if (Item.Owner is ShopKeeper) { builder.Range *= 3; } Camera.Instance.Push(antiAngle, 4f); entity.GetComponent()?.KnockbackFrom(antiAngle, 0.4f * knockback); if (!string.IsNullOrEmpty(color) && ProjectileColor.Colors.TryGetValue(color, out var clr)) { builder.Color = clr; } if (light) { builder.LightRadius = Rnd.Float(24f, 48f); } // R.I.P flash frame 2018-2021 // projectile.FlashTimer = 0.05f; var projectile = builder.Build(); projectile.Center = from; if (modifiers != null) { foreach (var m in modifiers) { if (m is ModifyProjectilesUse mpu) { mpu.ModifyProjectile(projectile); } } } pr?.Invoke(projectile); if (wait && i == 0) { ProjectileDied = false; if (prefab == "bk:axe") { ProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => { ProjectileCallbacks.AttachDeathCallback(prj, (prj2, e2, t2) => ProjectileDied = true); }); } else { ProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => ProjectileDied = true); } } if (manaUsage > 0) { if (manaDrop == 0) { ProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => { PlaceMana(entity.Area, prj.Center); }); } else if (manaDrop == 1) { PlaceMana(entity.Area, entity.Center); } else { var where = entity.Center; ProjectileCallbacks.AttachDeathCallback(projectile, (prj, e, t) => { PlaceMana(entity.Area, where); }); } } } if (shells) { Timer.Add(() => { var p = new ShellParticle(new Particle(Controllers.Destroy, new TexturedParticleRenderer { Region = CommonAse.Particles.GetSlice("shell") })); p.Position = entity.Center; p.Y += Rnd.Float(-4, 10); entity.Area.Add(p); var f = (entity.CenterX > entity.GetComponent().Cursor.GamePosition.X ? 1 : -1); p.Particle.Velocity = new Vector2(f * Rnd.Float(40, 60), 0) + entity.GetAnyComponent().Velocity; p.Particle.Angle = 0; p.Particle.Zv = Rnd.Float(1.5f, 2.5f); p.Particle.AngleVelocity = f * Rnd.Float(40, 70); p.AddShadow(); }, 0.2f); } }; } private class ShellParticle : ParticleEntity { private bool played; public ShellParticle(Particle particle) : base(particle) { } public override void Update(float dt) { base.Update(dt); if (!played && Particle.Z <= 0) { played = true; AddComponent(new AudioEmitterComponent()); GetComponent().EmitRandomizedPrefixed("projectile_shell", 3); } } } public static void RenderDebug(JsonValue root) { if (root.InputInt("Mana Usage", "mana", 0) > 0) { var b = root["mdr"].Int(0); if (ImGui.Combo("Place Mana", ref b, manaDropNames, manaDropNames.Length)) { root["mdr"] = b; } } if (ImGui.TreeNode("Stats")) { root.Checkbox("To Cursor", "cursor", false); root.Checkbox("To Cloest Target", "tomb", false); root.InputFloat("Damage", "damage"); root.InputInt("Projectile Count", "amount"); root.InputText("Sound", "sfx", "item_gun_fire"); root.InputInt("Sound Prefix Number", "sfxn", 0); root.Checkbox("Reload Sound", "rsfx", false); root.Checkbox("Drop Shells", "shells", true); root.Checkbox("Uses Emeralds", "emeralds", false); var c = root.InputText("Color", "color"); if (!string.IsNullOrEmpty(c) && !ProjectileColor.Colors.ContainsKey(c)) { ImGui.BulletText("Unknown color"); } ImGui.Separator(); root.InputFloat("Min Speed", "speed", 10); root.InputFloat("Max Speed", "speedm", 10); root.Checkbox("Disable Boost", "dsb", false); ImGui.Separator(); root.InputFloat("Min Scale", "scale"); root.InputFloat("Max Scale", "scalem"); ImGui.Separator(); var range = (float) root["range"].Number(0); if (ImGui.InputFloat("Range", ref range)) { root["range"] = range; } var knockback = (float) root["knockback"].Number(1); if (ImGui.InputFloat("Knockback", ref knockback)) { root["knockback"] = knockback; } root.InputFloat("Additional Angle", "ang", 0); var accuracy = (float) root["accuracy"].Number(0); if (ImGui.InputFloat("Accuracy", ref accuracy)) { root["accuracy"] = accuracy; } var light = root["light"].Bool(true); if (ImGui.Checkbox("Light", ref light)) { root["light"] = light; } var rect = root["rect"].Bool(false); if (ImGui.Checkbox("Rect body", ref rect)) { root["rect"] = rect; } var wait = root["wait"].Bool(false); if (ImGui.Checkbox("Wait for projectile death", ref wait)) { root["wait"] = wait; } var prefab = root["prefab"].String(""); if (ImGui.InputText("Prefab", ref prefab, 128)) { root["prefab"] = prefab; } if (prefab.Length > 0 && ProjectileRegistry.Get(prefab) == null) { ImGui.BulletText("Unknown prefab"); } var slice = root["texture"].String("rect"); if (slice == "default") { slice = "rect"; } var region = CommonAse.Projectiles.GetSlice(slice, false); if (region != null) { ImGui.Image(ImGuiHelper.ProjectilesTexture, new Num.Vector2(region.Width * 3, region.Height * 3), new Num.Vector2(region.X / region.Texture.Width, region.Y / region.Texture.Height), new Num.Vector2((region.X + region.Width) / region.Texture.Width, (region.Y + region.Height) / region.Texture.Height)); } if (ImGui.InputText("Texture", ref slice, 128)) { root["texture"] = slice; } ImGui.TreePop(); } if (ImGui.TreeNode("Modifiers")) { if (!root["modifiers"].IsJsonArray) { root["modifiers"] = new JsonArray(); } ItemEditor.DisplayUse(root, root["modifiers"], "bk:ModifyProjectiles"); ImGui.TreePop(); } } public override void Use(Entity entity, Item item) { if (wait && !ProjectileDied) { return; } base.Use(entity, item); } private void PlaceMana(Area area, Vector2 where) { for (var j = 0; j < Math.Floor(manaUsage / 2f); j++) { Items.CreateAndAdd("bk:mana", area).Center = where; } if (manaUsage % 2 == 1) { Items.CreateAndAdd("bk:half_mana", area).Center = where; } AnimationUtil.Poof(where); } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnBombUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class SpawnBombUse : ConsumeUse { public float Timer; public int Amount; public bool Randomly; public override void Use(Entity entity, Item item) { Items.Unlock("bk:grenade_launcher"); var room = entity.GetComponent().Room; if (room == null) { return; } for (var i = 0; i < Amount; i++) { if (Randomly) { Lens.util.timer.Timer.Add(() => { if (entity?.Area == null || room == null) { return; } var bomb = new Bomb(entity, Timer); entity.Area.Add(bomb); bomb.Center = room == null ? entity.Center + Rnd.Vector(-4, 4) : room.GetRandomFreeTile() * 16 + new Vector2(8); }, i * 0.1f); } else { if (entity?.Area == null) { return; } var bomb = new Bomb(entity, Timer); entity.Area.Add(bomb); bomb.Center = entity.Center; bomb.MoveToMouse(); } } } public override void Setup(JsonValue settings) { base.Setup(settings); Timer = settings["timer"].Number(2); Amount = settings["amount"].Int(1); Randomly = settings["randomly"].Bool(false); } public static void RenderDebug(JsonValue root) { var val = root["timer"].Number(2); if (ImGui.InputFloat("Timer", ref val)) { root["timer"] = val; } var am = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref am)) { root["amount"] = am; } var randomly = root["randomly"].Bool(false); if (ImGui.Checkbox("Randomly", ref randomly)) { root["randomly"] = randomly; } } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnDropUse.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.creature.drop; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class SpawnDropUse : ItemUse { private static string drop; public override void Use(Entity entity, Item item) { base.Use(entity, item); if (!assets.loot.Drops.Defined.TryGetValue(drop, out var d)) { Log.Error($"Unknown drop {drop}"); return; } creature.drop.Drop.Create(new List { d }, entity); } public override void Setup(JsonValue settings) { base.Setup(settings); drop = settings["drop"].String("missing"); } public static void RenderDebug(JsonValue root) { root.InputText("Drop", "drop"); if (!assets.loot.Drops.Defined.ContainsKey(drop)) { ImGui.Text($"Unknown drop {drop}"); } } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnItemsUse.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class SpawnItemsUse : ItemUse { public const int Distance = 24; public List ToSpawn = new List(); public override void Use(Entity entity, Item item) { var count = 0; var center = entity.Center; var room = entity.GetComponent().Room; if (room != null) { center = room.Center; } foreach (var i in ToSpawn) { count += i.Count; } var j = 0f; for (var i = 0; i < ToSpawn.Count; i++) { var it = ToSpawn[i]; for (var m = 0; m < it.Count; m++) { var itm = Items.CreateAndAdd(it.Id, entity.Area); var angle = j / count * Math.PI * 2; itm.Center = center + new Vector2((float) Math.Cos(angle) * Distance, (float) Math.Sin(angle) * Distance); j++; } } } public override void Setup(JsonValue settings) { base.Setup(settings); ToSpawn.Clear(); var v = settings["items"]; if (!v.IsJsonArray) { return; } foreach (var i in v.AsJsonArray) { ToSpawn.Add(new ItemPair { Count = i[0], Id = i[1] }); } } public static void RenderDebug(JsonValue root) { var toRemove = -1; if (!root["items"].IsJsonArray) { root["items"] = new JsonArray(); } var toSpawn = root["items"].AsJsonArray; for (var i = 0; i < toSpawn.Count; i++) { var item = toSpawn[i]; var v = item[0].Int(1); var n = item[1].String(""); if (ImGui.InputText($"##ss{i}", ref n, 128)) { item[1] = n; } ImGui.SameLine(); if (ImGui.InputInt($"##sl{i}", ref v)) { item[0] = v; } ImGui.SameLine(); if (ImGui.Button("-")) { toRemove = i; } } if (ImGui.Button("+")) { toSpawn.Add(new JsonArray { 1, "bk:copper_coin" }); } if (toRemove > -1) { toSpawn.Remove(toRemove); } } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnOrbitalUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.orbital; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class SpawnOrbitalUse : ItemUse { private string orbital; private bool random; private bool onlyIfHasNone; public override void Use(Entity entity, Item item) { if (onlyIfHasNone) { var inventory = entity.GetComponent(); foreach (var i in inventory.Items) { if (ItemPool.Orbital.Contains(i.Data.Pools)) { return; } } } if (random) { entity.GetComponent().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Orbital), entity.Area, true)); return; } var o = OrbitalRegistry.Create(orbital, entity); if (o == null) { Log.Error($"Failed to create orbital with id {orbital}"); return; } entity.GetComponent().AddOrbiter(o); } public override void Setup(JsonValue settings) { base.Setup(settings); random = settings["random"].Bool(false); orbital = settings["orbital"].String(""); onlyIfHasNone = settings["oin"].Bool(false); } public static void RenderDebug(JsonValue root) { root.Checkbox("Only if has none", "oin", false); if (root.Checkbox("Random", "random", false)) { return; } if (!OrbitalRegistry.Has(root.InputText("Orbital", "orbital", "", 128))) { ImGui.BulletText("Unknown orbital!"); } } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnPetUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.entity.component; using BurningKnight.entity.creature.pet; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.item.use { public class SpawnPetUse : ItemUse { private string pet; private bool random; private bool onlyIfHasNone; public override void Use(Entity entity, Item item) { if (onlyIfHasNone) { var inventory = entity.GetComponent(); foreach (var i in inventory.Items) { if (ItemPool.Pet.Contains(i.Data.Pools)) { return; } } } if (random) { entity.GetComponent().Pickup(Items.CreateAndAdd(Items.Generate(ItemPool.Pet), entity.Area)); return; } var o = PetRegistry.Create(pet, entity); if (o == null) { Log.Error($"Failed to create pet with id {pet}"); return; } o.Center = entity.Center + Rnd.Offset(24); AnimationUtil.Poof(o.Center, entity.Depth + 1); } public override void Setup(JsonValue settings) { base.Setup(settings); pet = settings["pet"].String(""); random = settings["random"].Bool(false); onlyIfHasNone = settings["oin"].Bool(false); } public static void RenderDebug(JsonValue root) { root.Checkbox("Only if has none", "oin", false); if (root.Checkbox("Random", "random", false)) { return; } if (!PetRegistry.Has(root.InputText("Pet", "pet", "", 128))) { ImGui.BulletText("Unknown pet!"); } } } } ================================================ FILE: BurningKnight/entity/item/use/SpawnProjectilesUse.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.entity.projectile; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Microsoft.Xna.Framework; using Num = System.Numerics; namespace BurningKnight.entity.item.use { public class SpawnProjectilesUse : ItemUse { private int damage; private float speed; private float range; private string slice; private int amount; public override void Use(Entity entity, Item item) { var s = range * 0.5f / speed; var builder = new ProjectileBuilder(entity, slice) { LightRadius = 32f, Color = ProjectileColor.Yellow, Damage = damage }; if (range > 0.01f) { builder.Range = s; } for (var i = 0; i < amount; i++) { var angle = (float) i / amount * Math.PI * 2; builder.Shoot(angle, speed).Build(); } } public override void Setup(JsonValue settings) { base.Setup(settings); damage = settings["damage"].Int(1); amount = settings["amount"].Int(1); speed = settings["speed"].Number(60); range = settings["range"].Number(0); slice = settings["texture"].AsString; } public static void RenderDebug(JsonValue root) { var val = root["amount"].Int(1); if (ImGui.InputInt("Amount", ref val)) { root["amount"] = val; } val = root["damage"].Int(1); if (ImGui.InputInt("Damage", ref val)) { root["damage"] = val; } var spd = (float) root["speed"].Number(60); if (ImGui.InputFloat("Speed", ref spd)) { root["speed"] = spd; } var range = (float) root["range"].Number(0); if (ImGui.InputFloat("Range", ref range)) { root["range"] = range; } var slice = root["texture"].String(""); var region = CommonAse.Projectiles.GetSlice(slice); ImGui.Image(ImGuiHelper.ProjectilesTexture, new Num.Vector2(region.Width * 3, region.Height * 3), new Num.Vector2(region.X / region.Texture.Width, region.Y / region.Texture.Height), new Num.Vector2((region.X + region.Width) / region.Texture.Width, (region.Y + region.Height) / region.Texture.Height)); if (ImGui.InputText("Texture", ref slice, 128)) { root["texture"] = slice; } } } } ================================================ FILE: BurningKnight/entity/item/use/SpeedUpOrbitalsUse.cs ================================================ using BurningKnight.entity.component; using Lens.entity; namespace BurningKnight.entity.item.use { public class SpeedUpOrbitalsUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); entity.GetComponent().Speed *= 2; } } } ================================================ FILE: BurningKnight/entity/item/use/SuperHotUse.cs ================================================ using BurningKnight.entity.creature.player; using Lens.entity; namespace BurningKnight.entity.item.use { public class SuperHotUse : ItemUse { public override void Use(Entity entity, Item item) { base.Use(entity, item); if (entity is Player p) { p.SuperHot = true; } } } } ================================================ FILE: BurningKnight/entity/item/use/TeleportToCursorUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.level.tile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.input; namespace BurningKnight.entity.item.use { public class TeleportToCursorUse : ItemUse { public override void Use(Entity entity, Item item) { var position = entity.GetComponent().Cursor.GamePosition; var tileX = (int) (position.X / 16); var tileY = (int) (position.Y / 16); var level = Run.Level; if (!level.IsInside(tileX, tileY)) { return; } if (!level.Get(tileX, tileY).Matches(TileFlags.Passable)) { return; } AnimationUtil.Poof(entity.Center); entity.Center = position; AnimationUtil.Poof(entity.Center); } } } ================================================ FILE: BurningKnight/entity/item/use/TeleportToPrevRoomUse.cs ================================================ using BurningKnight.entity.events; using BurningKnight.entity.room; using BurningKnight.util; using Lens.entity; using Lens.util.camera; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class TeleportToPrevRoomUse : ItemUse { private Room previous; public override void Use(Entity e, Item item) { base.Use(e, item); if (previous == null) { return; } AnimationUtil.TeleportAway(e, () => { e.Center = previous.GetRandomFreeTile() * 16 + new Vector2(8); Camera.Instance.Jump(); AnimationUtil.TeleportIn(e); previous = null; }); } public override bool HandleEvent(Event e) { if (e is RoomChangedEvent rce && rce.Who == Item.Owner) { previous = rce.Old; } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/item/use/TeleportToShopUse.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.util; using Lens.entity; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class TeleportToShopUse : ItemUse { public override void Use(Entity e, Item item) { base.Use(e, item); var rooms = e.Area.Tagged[Tags.Room]; if (rooms.Count < 2) { return; } var room = e.GetComponent().Room; var newRoom = (Room) Rnd.Element(rooms, r => r != room && r is Room rm && rm.Type == RoomType.Shop); if (newRoom != null) { AnimationUtil.TeleportAway(e, () => { e.Center = newRoom.GetRandomFreeTile() * 16 + new Vector2(8); Camera.Instance.Jump(); AnimationUtil.TeleportIn(e); }); } } } } ================================================ FILE: BurningKnight/entity/item/use/TeleportUse.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.item.use.parent; using BurningKnight.entity.room; using BurningKnight.level.rooms; using BurningKnight.util; using Lens.entity; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.item.use { public class TeleportUse : DoWithTagUse { protected override void DoAction(Entity entity, Item item, List entities) { var rooms = entity.Area.Tagged[Tags.Room]; if (rooms.Count < 2) { return; } foreach (var e in entities) { var room = e.GetComponent().Room; var newRoom = (Room) Rnd.Element(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); if (newRoom != null) { AnimationUtil.TeleportAway(e, () => { e.Center = newRoom.GetRandomFreeTile() * 16 + new Vector2(8); Camera.Instance.Jump(); AnimationUtil.TeleportIn(e); e.GetComponent().Unhittable = false; }); entity.GetComponent().EmitRandomized("quck"); } } } } } ================================================ FILE: BurningKnight/entity/item/use/TriggerHurtEventUse.cs ================================================ using BurningKnight.entity.events; using Lens.entity; namespace BurningKnight.entity.item.use { public class TriggerHurtEventUse : ItemUse { public override void Use(Entity entity, Item item) { entity.HandleEvent(new HealthModifiedEvent { Amount = -1, Who = entity, From = item }); entity.HandleEvent(new PostHealthModifiedEvent { Amount = -1, Who = entity, From = item }); } } } ================================================ FILE: BurningKnight/entity/item/use/UseOnEventUse.cs ================================================ using System; using BurningKnight.state; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public class UseOnEventUse : ItemUse { private string type; private Type typeInstance; private string use; private JsonValue options; public override void Setup(JsonValue settings) { base.Setup(settings); type = settings["tp"].String(""); use = settings["use"].String(""); options = settings["us"]; if (options == JsonValue.Null) { options = new JsonObject(); } try { typeInstance = Type.GetType(type, true, false); } catch (Exception e) { Log.Error(e); } } public override bool HandleEvent(Event e) { if (e.GetType() == typeInstance) { var u = UseRegistry.Create(use); if (u == null) { Log.Error($"{use} is invalid item use id"); } else { u.Item = Item; u.Setup(options); u.Use(Item.Owner, Item); } } return base.HandleEvent(e); } public static void RenderDebug(JsonValue root) { var type = root["tp"].String(""); var use = root["use"].String(""); if (ImGui.InputText("Use", ref use, 128)) { root["use"] = use; } var c = !UseRegistry.Uses.ContainsKey(use); if (c) { ImGui.BulletText("Unknown use"); } if (ImGui.InputText("Event type", ref type, 256)) { root["tp"] = type; } try { Type.GetType(type, true, false); } catch (Exception e) { ImGui.BulletText("Unknown type"); } if (c) { return; } var us = root["us"]; if (us == JsonValue.Null) { us = root["us"] = new JsonObject(); } us["id"] = use; ItemEditor.DisplayUse(root, us); } } } ================================================ FILE: BurningKnight/entity/item/use/UseRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.item.use.parent; using Lens.lightJson; using Lens.util; namespace BurningKnight.entity.item.use { public static class UseRegistry { public static Dictionary Uses = new Dictionary(); public static Dictionary> Renderers = new Dictionary>(); public static void Register(Mod mod, Action renderer = null) where T : ItemUse { var type = typeof(T); var name = type.Name; var id = $"{mod?.Prefix ?? Mods.BurningKnight}:{(name.EndsWith("Use") ? name.Substring(0, name.Length - 3) : name)}"; Uses[id] = type; if (renderer != null) { Renderers[id] = renderer; } } private static void Register(Action renderer = null) where T : ItemUse { Register(null, renderer); } public static ItemUse Create(string id) { if (!Uses.TryGetValue(id, out var use)) { return null; } return (ItemUse) Activator.CreateInstance(use); } static UseRegistry() { Register(); Register(SpawnBombUse.RenderDebug); Register(); Register(MeleeArcUse.RenderDebug); Register(ModifyHpUse.RenderDebug); Register(ModifyHpUse.RenderDebug); Register(ModifyManaUse.RenderDebug); Register(ModifyMaxHpUse.RenderDebug); Register(ModifyHpUse.RenderDebug); Register(SimpleShootUse.RenderDebug); Register(ShootQueueUse.RenderDebug); Register(RandomUse.RenderDebug); Register(GiveGoldUse.RenderDebug); Register(GiveKeyUse.RenderDebug); Register(GiveBombUse.RenderDebug); Register(GiveItemUse.RenderDebug); Register(SetMaxHpUse.RenderDebug); Register(SpawnItemsUse.RenderDebug); Register(SpawnMobsUse.RenderDebug); Register(DiscoverSecretRoomsUse.RenderDebug); Register(ModifyStatUse.RenderDebug); Register(); Register(); Register(MakeProjectilesBounceUse.RenderDebug); Register(MakeProjectilesHomeInUse.RenderDebug); Register(MakeProjectilesSlowDown.RenderDebug); Register(); Register(MakeLayerPassableUse.RenderDebug); Register(SpawnOrbitalUse.RenderDebug); Register(SpawnPetUse.RenderDebug); Register(RerollItemsUse.RenderDebug); Register(RerollItemsUse.RenderDebug); Register(SpawnProjectilesUse.RenderDebug); Register(UseOnEventUse.RenderDebug); Register(); Register(SaleItemsUse.RenderDebug); Register(ModifyActiveChargeUse.RenderDebug); Register(PreventDamageUse.RenderDebug); Register(RemoveFromPoolUse.RenderDebug); Register(ModifyGameSaveValueUse.RenderDebug); Register(GiveWeaponUse.RenderDebug); Register(); Register(GiveEmeraldsUse.RenderDebug); Register(ModifyProjectilesUse.RenderDebug); Register(TeleportUse.RenderDebug); Register(DoOnEnemyCollisionUse.RenderDebug); Register(DoOnHurtUse.RenderDebug); Register(GiveBuffUse.RenderDebug); Register(GiveBuffImmunityUse.RenderDebug); Register(DoWithUse.RenderDebug); Register(); Register(SetKnockbackModifierUse.RenderDebug); Register(); Register(ScourgeUse.RenderDebug); Register(ModifyLuckUse.RenderDebug); Register(RerollItemsOnPlayerUse.RenderDebug); Register(); Register(); Register(); Register(ModifyBombsUse.RenderDebug); Register(); Register(); Register(); Register(); Register(KillMobUse.RenderDebug); Register(); Register(SpawnDropUse.RenderDebug); Register(ModifyStatsUse.RenderDebug); Register(); Register(EnableScourgeUse.RenderDebug); Register(SetMusicSpeed.RenderDebug); Register(DoOnTimerUse.RenderDebug); Register(MakeBombsHomeUse.RenderDebug); Register(); Register(RegenUse.RenderDebug); Register(); Register(GivePhaseUse.RenderDebug); Register(); Register(); Register(); Register(); Register(); Register(); Register(); Register(AffectDealChanceUse.RenderDebug); Register(); Register(DoUsesUse.RenderDebug); Register(DoUsesIfUse.RenderDebug); Register(ModifyArcUse.RenderDebug); Register(); Register(MakeProjectileShrinkUse.RenderDebug); Register(MakeProjectileExpandUse.RenderDebug); Register(); Register(ModifyManaMaxUse.RenderDebug); Register(ModifyConsumableWeightsUse.RenderDebug); Register(); Register(); Register(); Register(InvokeItemsUse.RenderDebug); Register(); Register(); Register(); Register(MakeProjectilesKillWithBuffUse.RenderDebug); Register(ModifyShootUse.RenderDebug); Register(ModifyGenUse.RenderDebug); Register(); Register(); Register(); Register(); Register(BlockDamageUse.RenderDebug); Register(ModifyProjectileTextureUse.RenderDebug); Register(); Register(); Register(BucketUse.RenderDebug); Register(); Register(); Register(); Register(ChanceToUseWeaponUse.RenderDebug); Register(); } } } ================================================ FILE: BurningKnight/entity/item/use/parent/DoUsesUse.cs ================================================ using BurningKnight.assets.items; using BurningKnight.state; using Lens.entity; using Lens.lightJson; namespace BurningKnight.entity.item.use.parent { public abstract class DoUsesUse : ItemUse { protected ItemUse[] Uses; public override void Use(Entity entity, Item item) { base.Use(entity, item); foreach (var u in Uses) { DoAction(entity, item, u); } } protected abstract void DoAction(Entity entity, Item item, ItemUse use); public override void Setup(JsonValue settings) { base.Setup(settings); if (!settings["uses"].IsJsonArray) { settings["uses"] = new JsonArray(); } Uses = Items.ParseUses(settings["uses"]); } public static void RenderDebug(JsonValue root) { if (!root["uses"].IsJsonArray) { root["uses"] = new JsonArray(); } ItemEditor.DisplayUse(root, root["uses"]); } } } ================================================ FILE: BurningKnight/entity/item/use/parent/DoWithTagUse.cs ================================================ using System.Collections.Generic; using BurningKnight.entity.component; using ImGuiNET; using Lens.entity; using Lens.lightJson; using Lens.util.math; namespace BurningKnight.entity.item.use.parent { public abstract class DoWithTagUse : ItemUse { private bool self; private bool sameRoom; private bool all; private int tag; public override void Use(Entity entity, Item item) { var list = new List(); if (self) { list.Add(entity); } var tags = (sameRoom ? entity.GetComponent().Room.Tagged : entity.Area.Tagged); for (var i = 0; i < BitTag.Total; i++) { if ((tag & 1 << i) != 0) { var l = tags[i]; if (all) { list.AddRange(l); } else if (l.Count > 0) { list.Add(l[Rnd.Int(l.Count)]); } } } DoAction(entity, item, list); } protected abstract void DoAction(Entity entity, Item item, List entities); public override void Setup(JsonValue settings) { base.Setup(settings); self = settings["self"].Bool(false); sameRoom = settings["same_room"].Bool(true); all = settings["all"].Bool(true); tag = settings["tag"].Int(1); } public static void RenderDebug(JsonValue root) { var val = root["self"].Bool(false); if (ImGui.Checkbox("Self", ref val)) { root["self"] = val; } ImGui.Separator(); val = root["same_room"].Bool(false); if (ImGui.Checkbox("Same room?", ref val)) { root["same_room"] = val; } val = root["all"].Bool(false); if (ImGui.Checkbox("All?", ref val)) { root["all"] = val; } var tag = root["tag"].Int(0); ImGui.Text($"Tags: {tag}"); for (var i = 0; i < BitTag.Total; i++) { var t = BitTag.Tags[i]; var on = (tag & 1 << i) != 0; if (ImGui.Checkbox(t.Name, ref on)) { if (on) { tag |= 1 << i; } else { tag &= ~(1 << i); } root["tag"] = tag; } } } } } ================================================ FILE: BurningKnight/entity/item/useCheck/ItemUseCheck.cs ================================================ using BurningKnight.entity.buff; using BurningKnight.entity.component; using Lens.entity; using Lens.util.file; namespace BurningKnight.entity.item.useCheck { public class ItemUseCheck { public virtual bool CanUse(Entity entity, Item item) { return item.Delay < 0.05f && (item.Type != ItemType.Weapon || !entity.GetComponent().Has()); } } } ================================================ FILE: BurningKnight/entity/item/useCheck/ItemUseChecks.cs ================================================ namespace BurningKnight.entity.item.useCheck { public static class ItemUseChecks { public static ItemUseCheck Default = new ItemUseCheck(); } } ================================================ FILE: BurningKnight/entity/item/util/MeleeArc.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.lighting; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.physics; using BurningKnight.state; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.item.util { public delegate void ArcHurtCallback(MeleeArc p, Entity e); public delegate void ArcDeathCallback(MeleeArc p); public class MeleeArc : Entity { public static Color ReflectedColor = new Color(0.5f, 1f, 0.5f, 1f); public float LifeTime = 0.1f; public float Damage; public Entity Owner; public float Angle; public string Sound = "item_sword_hit"; public Color Color = ColorUtils.WhiteColor; public bool Mines; public float Knockback; public ArcHurtCallback OnHurt; public ArcDeathCallback OnDeath; private float t; private Vector2 velocity; private List hurt = new List(); public override void AddComponents() { base.AddComponents(); const float force = 40f; velocity = new Vector2((float) Math.Cos(Angle) * force, (float) Math.Sin(Angle) * force); AddComponent(new RectBodyComponent(0, -Height / 2f, Width, Height, BodyType.Dynamic, true) { Angle = Angle }); AddComponent(new AnimationComponent("sword_trail", null, "idle") { Offset = new Vector2(4, 12), Scale = new Vector2(Width / 8, Height / 24) }); AddComponent(new LightComponent(this, 32f, Color.White)); GetComponent().OriginY = 12; Camera.Instance.Push(Angle - (float) Math.PI, 4f); } public void AdjustSize() { GetComponent().Resize(0, -Height / 2f, Width, Height); } public override void Render() { var component = GetComponent(); var region = component.Animation.GetCurrentTexture(); Graphics.Color = Color; Graphics.Render(region, Position, Angle, component.Offset, component.Scale); Graphics.Color = ColorUtils.WhiteColor; } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is HalfProjectileLevel bdd) { if (Mines) { Physics.Fixture.GetAABB(out var hitbox, 0); ProjectileLevelBody.Mine(Run.Level, hitbox.Center.X, hitbox.Center.Y); } } else if (ev.Entity is ProjectileLevelBody bd) { if (Mines) { Physics.Fixture.GetAABB(out var hitbox, 0); ProjectileLevelBody.Mine(Run.Level, hitbox.Center.X, hitbox.Center.Y); } if (Run.Level.Biome is IceBiome) { Physics.Fixture.GetAABB(out var hitbox, 0); if (bd.Break(hitbox.Center.X, hitbox.Center.Y)) { AudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed("level_snow_break", 3); } } } else if (ev.Entity is Bomb) { ev.Entity.GetComponent().KnockbackFrom(Owner, 1f + Knockback); } else if (ev.Entity is Projectile p) { if ((p.Owner is Mob) != (Owner is Mob) && ((p.FirstOwner is Mob) != (Owner is Mob))) { if (p.HasFlag(ProjectileFlags.Reflectable)) { p.Owner = Owner; p.Damage *= 2f; // fixme: lethal // p.Pattern?.Remove(p); var b = p.GetAnyComponent(); var d = Math.Max(400, b.Velocity.Length() * 1.8f); var a = Owner.AngleTo(p); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); if (p.TryGetComponent(out var l)) { l.Light.Color = ReflectedColor; } p.Color = ProjectileColor.Yellow; Camera.Instance.ShakeMax(4f); Owner.GetComponent().EmitRandomizedPrefixed("projectile_reflected", 2); } else if (p.HasFlag(ProjectileFlags.BreakableByMelee)) { p.Break(); } } } else if (ev.Entity != Owner && (!(ev.Entity is Player) || !(Owner is Player))) { if (ev.Entity.TryGetComponent(out var health)) { if (!hurt.Contains(ev.Entity)) { if (Knockback > 0) { ev.Entity.GetAnyComponent()?.KnockbackFrom(Owner, Knockback); } if (health.ModifyHealth(-Damage, Owner, DamageType.Melee)) { Owner.GetComponent().EmitRandomizedPrefixed(Sound, 3); OnHurt?.Invoke(this, ev.Entity); } hurt.Add(ev.Entity); } } else if (ev.Entity is ProjectileLevelBody && !HitWall) { HitWall = true; Owner.GetComponent().EmitRandomized("item_sword_hit_wall"); } } } return base.HandleEvent(e); } private bool HitWall; public override void Update(float dt) { base.Update(dt); t += dt; Position = Owner.Center + velocity * t; if (t >= LifeTime) { OnDeath?.Invoke(this); Done = true; } } public class CreatedEvent : Event { public MeleeArc Arc; public Entity Owner; public Item By; } } } ================================================ FILE: BurningKnight/entity/orbital/AnimatedOrbital.cs ================================================ using BurningKnight.entity.component; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.orbital { public class AnimatedOrbital : Orbital { private string sprite; public AnimatedOrbital(string spr) { sprite = spr; } public override void AddComponents() { base.AddComponents(); AddComponent(new AnimationComponent(sprite) { ShadowOffset = -2 }); var region = GetComponent().Animation.GetCurrentTexture(); Width = region.Width; Height = region.Height; AddComponent(new ShadowComponent()); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); GetComponent().Animate(); } } } ================================================ FILE: BurningKnight/entity/orbital/Marshmallow.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.orbital { public class Marshmallow : AnimatedOrbital { private float timer; public Marshmallow() : base("marshmallow") { timer = Rnd.Float(1); } public override void Update(float dt) { base.Update(dt); timer += dt; if (timer >= 1f) { timer = 0; if ((Owner.GetComponent().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) { return; } Owner.GetComponent().EmitRandomizedPrefixed("item_meatguy", 4, 0.5f); var a = GetComponent().CurrentAngle; var builder = new ProjectileBuilder(Owner, "small") { Color = ProjectileColor.White, LightRadius = 32f }; builder.Shoot(a, 6f); builder.Move(a, 5f); var projectile = builder.Build(); /*Owner.HandleEvent(new ProjectileCreatedEvent { Projectile = projectile, Owner = Owner });*/ projectile.Owner = this; GetComponent().Animate(); } } } } ================================================ FILE: BurningKnight/entity/orbital/Orbital.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.save; using BurningKnight.util; using Lens.entity; using Lens.util.tween; namespace BurningKnight.entity.orbital { public delegate void OrbitalCollisionHandler(Orbital o, Entity e); public class Orbital : Entity { public OrbitalCollisionHandler OnCollision; public Entity Owner => GetComponent().Orbiting; public Action Controller; public override void AddComponents() { base.AddComponents(); AddComponent(new OrbitalComponent()); } private bool animated; public override void Update(float dt) { base.Update(dt); if (!animated) { animated = true; if (TryGetComponent(out var g)) { AnimationUtil.Poof(Center, Depth + 1); g.Animate(); } } Controller?.Invoke(dt); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { OnCollision?.Invoke(this, cse.Entity); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/orbital/OrbitalRegistry.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using BurningKnight.assets; using BurningKnight.assets.lighting; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.entity.item.util; using BurningKnight.entity.projectile; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.util; using Lens.util.math; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.orbital { public static class OrbitalRegistry { private static Dictionary> defined = new Dictionary>(); public static Entity Create(string id, Entity owner) { return !defined.TryGetValue(id, out var d) ? null : d(owner); } public static void Define(string id, Func orbital, Mod mod = null) { defined[$"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}"] = orbital; } public static bool Has(string id) { return defined.ContainsKey(id); } static OrbitalRegistry() { Define("prism", o => { var orbital = new Prism(); o.Area.Add(orbital); return orbital; }); Define("goo", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:goo") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner) { p.Break(); } }; return orbital; }); Define("bullet_stone", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:bullet_stone") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner && p.Owner != orbital) { p.Break(); } }; var timer = 0f; orbital.Controller += (dt) => { timer += dt; if (timer >= 2f) { timer = 0; if ((o.GetComponent().Room?.Tagged[Tags.MustBeKilled].Count ?? 0) == 0) { return; } o.GetComponent().EmitRandomizedPrefixed("item_gun_fire", 2, 0.5f); var a = orbital.AngleTo(o.GetComponent().RealAim); var builder = new ProjectileBuilder(o, "small") { Color = ProjectileColor.Yellow, LightRadius = 32f }; builder.Shoot(a, 10f); builder.Move(a, 5f); var projectile = builder.Build(); /*Owner.HandleEvent(new ProjectileCreatedEvent { Projectile = projectile, Owner = Owner });*/ projectile.Owner = orbital; orbital.GetComponent().Animate(); } }; return orbital; }); Define("sword", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:sword_orbital") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new RectBodyComponent(0, 0, 9, 15, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Creature c && c.IsFriendly() != ((Creature) orbital.Owner).IsFriendly()) { c.GetComponent().ModifyHealth(-1, orbital); } else if (e is Projectile p && p.Owner != orbital.Owner) { p.Break(); } }; return orbital; }); Define("broken_stone", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:broken_stone") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 6, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner) { p.Break(); if (Rnd.Chance(20 - Run.Luck * 5)) { or.Done = true; AnimationUtil.Poof(or.Center); } } }; return orbital; }); Define("jelly", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:jelly") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 5, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner) { p.Owner = o; var b = p.GetAnyComponent(); var d = b.Velocity.Length(); var a = b.Velocity.ToAngle() - Math.PI + Rnd.Float(-0.3f, 0.3f); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); if (p.TryGetComponent(out var l)) { l.Light.Color = MeleeArc.ReflectedColor; } } }; return orbital; }); Define("nano_orb", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:nano_orb") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner) { p.Break(); } }; return orbital; }); Define("planet", o => { var orbital = new Orbital(); o.Area.Add(orbital); var g = new ScalableSliceComponent("items", "bk:earth") { ShadowZ = 2 }; orbital.AddComponent(g); g.AddShadow(); g.SetOwnerSize(); orbital.AddComponent(new CircleBodyComponent(0, 0, 3, BodyType.Dynamic, true)); orbital.OnCollision += (or, e) => { if (e is Projectile p && p.Owner != orbital.Owner) { p.Break(); var s = (ScalableSliceComponent) or.GraphicsComponent; if (Math.Abs(s.Scale.Y - 1) > 0.01f) { return; // Already animating } Tween.To(1, 1.5f, x => s.Scale.X = x, 0.3f); Tween.To(0, 1, x => s.Scale.Y = x, 0.2f).OnEnd = () => { s.Sprite = CommonAse.Items.GetSlice(planets[Rnd.Int(planets.Length)]); s.SetOwnerSize(); orbital.RemoveComponent(); orbital.AddComponent(new CircleBodyComponent(0, 0, Math.Min(orbital.Width, orbital.Height) / 2f, BodyType.Dynamic, true)); Tween.To(1, 1.5f, x => s.Scale.X = x, 0.4f, Ease.ElasticOut); Tween.To(1, 0, x => s.Scale.Y = x, 0.5f, Ease.ElasticOut); }; } }; return orbital; }); Define("marshmallow", o => { var orbital = new Marshmallow(); o.Area.Add(orbital); return orbital; }); } private static string[] planets = { "bk:mercury", "bk:venus", "bk:earth", "bk:moon", "bk:mars", "bk:jupiter", "bk:saturn", "bk:uranus", "bk:neptune" }; } } ================================================ FILE: BurningKnight/entity/orbital/Prism.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.util; using Lens.entity; using Lens.util.math; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.orbital { public class Prism : Orbital { public override void AddComponents() { base.AddComponents(); Width = 12; Height = 14; AddComponent(new AnimationComponent("prism") { ShadowOffset = -2 }); AddComponent(new ShadowComponent()); AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Dynamic, true)); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse && cse.Entity is Projectile p && !p.HasFlag(ProjectileFlags.Artificial) && p.Owner == Owner && p.Parent == null) { var tt = Rnd.Int(4, 8); var body = p.GetAnyComponent(); var builder = new ProjectileBuilder(Owner, p.Slice) { LightRadius = 32f, Parent = p }; builder.AddFlags(ProjectileFlags.Artificial); for (var i = 0; i < tt; i++) { builder.Shoot(body.Angle + (i - tt * 0.5f) * 0.1f, body.Velocity.Length() * 0.05f); var pr = builder.Build(); pr.Color = ProjectileColor.Rainbow[i]; pr.Position = p.Position; } AnimationUtil.Poof(Center, Depth + 1); p.Done = true; } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/pc/Controller.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using Lens.entity; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.pc { public class Controller : Entity { public Pico Pico; public override void AddComponents() { base.AddComponents(); Height = 9; AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, false)); AddComponent(new SensorBodyComponent(-10, -10, Width + 20, Height + 20, BodyType.Static, true)); AddComponent(new InteractableComponent(Interact)); AddComponent(new InteractableSliceComponent("props", "controller")); AddComponent(new ShadowComponent()); } private bool Interact(Entity e) { Pico.TurnOn(); Pico.Entity = e; e.RemoveComponent(); return true; } } } ================================================ FILE: BurningKnight/entity/pc/Pico.cs ================================================ using BurningKnight.assets.input; using BurningKnight.entity.component; using BurningKnight.entity.creature.player; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using ImGuiNET; using Lens; using Lens.entity; using Lens.graphics; using Lens.input; using Lens.util.camera; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.pc { public class Pico : SaveableEntity, PlaceableEntity { private bool on; private Controller controller; // private Emulator emulator; // private MonoGameGraphicsBackend backend; private const float UpdateTime30 = 1 / 30f; private const float UpdateTime60 = 1 / 60f; private float deltaUpdate30, deltaUpdate60, deltaDraw; private string cart = "ma_puzzle"; public Entity Entity; public override void PostInit() { base.PostInit(); controller = new Controller(); Area.Add(controller); controller.Y = Bottom + 16; controller.X = X + 16; controller.Pico = this; Area.Add(new RenderTrigger(this, RenderDisplay, Layers.Console)); } public override void AddComponents() { base.AddComponents(); Width = 138; Height = 150 + 5; AddComponent(new RectBodyComponent(0, 0, Width, Height, BodyType.Static, false)); AddComponent(new SliceComponent("props", "pico")); AddComponent(new ShadowComponent()); } public void TurnOn() { if (on) { return; } /*if (emulator == null) { backend = new MonoGameGraphicsBackend(Engine.GraphicsDevice); emulator = new Emulator(backend, new MonoGameAudioBackend(), new MonoGameInputBackend()); }*/ on = true; Camera.Instance.Targets.Clear(); Camera.Instance.Position = Position + new Vector2(Display.Width * 0.25f, 0);// + new Vector2(5 + 64, 16 + 64); LoadCart(); } private void LoadCart() { /*if (!emulator.CartridgeLoader.Load($"Content/Carts/{cart}.p8")) { Log.Error($"Failed to load the cart {cart}"); }*/ } public void TurnOff() { if (!on) { return; } Entity.AddComponent(new PlayerInputComponent()); Entity = null; Camera.Instance.Targets.Clear(); ((InGameState) Engine.Instance.State).ResetFollowing(); on = false; } public override void Update(float dt) { base.Update(dt); if (!on) { return; } if (Input.WasPressed(Controls.Pause, GamepadComponent.Current, true)) { TurnOff(); return; } deltaUpdate60 += dt; deltaUpdate30 += dt; /* while (deltaUpdate30 >= UpdateTime30) { deltaUpdate30 -= UpdateTime30; emulator.Update30(); } while (deltaUpdate60 >= UpdateTime60) { deltaUpdate60 -= UpdateTime60; emulator.Update60(); }*/ } public void RenderDisplay() { /*if (!on) { return; } var u = emulator.CartridgeLoader.HighFps ? UpdateTime60 : UpdateTime30; deltaDraw += Engine.Delta; while (deltaDraw >= u) { deltaDraw -= u; emulator.Graphics.drawCalls = 0; emulator.Draw(); } emulator.Graphics.Flip(); Graphics.Render(backend.Surface, Position + new Vector2(5, 16));*/ } public override void RenderImDebug() { base.RenderImDebug(); ImGui.InputText("Cart", ref cart, 64); ImGui.SameLine(); if (ImGui.Button("Load")) { LoadCart(); } } } } ================================================ FILE: BurningKnight/entity/pool/Pool.cs ================================================ using System; using System.Collections.Generic; using Lens.util; using Lens.util.math; namespace BurningKnight.entity.pool { public class Pool { protected List Chances = new List(); protected List Classes = new List(); public int Size => Classes.Count; public virtual T Generate() { var I = Rnd.Chances(Chances); if (I == -1) { Log.Error("-1 as pool result!"); return default(T); } return Classes[I]; } public void Add(T Type, float Chance) { Classes.Add(Type); Chances.Add(Chance); } public void Clear() { Classes.Clear(); Chances.Clear(); } public void AddFrom(Pool Pool) { Classes.AddRange(Pool.Classes); Chances.AddRange(Pool.Chances); } public T Get(int i) { return Classes[i]; } } } ================================================ FILE: BurningKnight/entity/projectile/BasicProjectileGraphicsComponent.cs ================================================ using BurningKnight.entity.component; using Lens.graphics; using Lens.graphics.animation; namespace BurningKnight.entity.projectile { public class BasicProjectileGraphicsComponent : SliceComponent { public BasicProjectileGraphicsComponent(string image, string slice) : base(image, slice) { } public virtual void RenderLight() { } } } ================================================ FILE: BurningKnight/entity/projectile/Laser.cs ================================================ using System; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.player; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.level; using BurningKnight.physics; using BurningKnight.state; using Lens.entity; using Lens.util; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; using VelcroPhysics.Dynamics.Solver; namespace BurningKnight.entity.projectile { public class Laser : Projectile { public float LifeTime = 1.5f; public bool Dynamic = true; public float AdditionalAngle; public float Range = 15f; public Vector2 End; public bool PlayerRotated; private float angle; public float Angle { get => angle; set { angle = value; if (BodyComponent?.Body != null) { BodyComponent.Body.Rotation = angle + AdditionalAngle; } } } public static Laser Make(Entity owner, float a, float additional, Item item = null, float damage = 1, float scale = 1f, float range = -1, Laser parent = null) { if (owner is Item i) { item = i; owner = i.Owner; } var projectile = new Laser { Owner = owner, FirstOwner = owner, Damage = damage, Flags = 0, Slice = "laser", Bounce = 0, Scale = scale, Color = ProjectileColor.Red, Parent = parent, Item = item }; owner.Area.Add(projectile); var graphics = new LaserGraphicsComponent("projectiles", "laser"); projectile.AddComponent(graphics); if (range > 0) { projectile.Range = range; } if (parent != null) { projectile.Scale *= 0.7f; projectile.Range *= 0.5f; } projectile.Position = owner.Center; owner.HandleEvent(new ProjectileCreatedEvent { Owner = owner, Item = item, Projectile = projectile }); projectile.Width = 32; projectile.Height = 9 * projectile.Scale; projectile.CreateBody(); projectile.AdditionalAngle = additional; projectile.Angle = a; return projectile; } public override void AddComponents() { base.AddComponents(); AddTag(Tags.Laser); } private void CreateBody() { AddComponent(new RectBodyComponent(0, -Height * 0.5f, Width, Height)); } private static bool RayShouldCollide(Entity entity) { return entity is ProjectileLevelBody || entity is Level || entity is Door; } public override bool BreaksFrom(Entity entity, BodyComponent body) { return false; } public void Recalculate() { var min = 1f; Vector2 closest; var aim = Owner.GetComponent(); Position = aim.Center; var from = Position; if (PlayerRotated) { BodyComponent.Body.Rotation = angle = (aim.RealAim - from).ToAngle(); } closest = Position + MathUtils.CreateVector(BodyComponent.Body.Rotation, Range * 5); Physics.World.RayCast((fixture, point, normal, fraction) => { if (min > fraction && fixture.Body.UserData is BodyComponent b && RayShouldCollide(b.Entity)) { min = fraction; closest = point; } return min; }, from, closest); var v = (from - closest); var len = v.Length(); if (Math.Abs(len - Width) > 1) { Width = len; BodyComponent.Resize(0, -Height * 0.5f, Width, Height); } BodyComponent.Body.Rotation = angle + AdditionalAngle; End = Position + MathUtils.CreateVector(BodyComponent.Body.Rotation, Width); } private float lastClear; public override void Update(float dt) { base.Update(dt); lastClear += dt; if (lastClear >= 0.05f) { lastClear = 0; EntitiesHurt.Clear(); } if (LifeTime > 0) { LifeTime -= dt; if (LifeTime <= 0) { Break(); Done = true; LifeTime = 0; return; } } if (Dynamic) { Recalculate(); } } public override void Resize(float newScale) { Scale = newScale; Height = 9 * Scale; GetComponent().Resize(0, 0, Width, Height, true); } } } ================================================ FILE: BurningKnight/entity/projectile/LaserGraphicsComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using Lens.assets; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public class LaserGraphicsComponent : BasicProjectileGraphicsComponent { private TextureRegion aura; private TextureRegion light; private TextureRegion end; private TextureRegion endAura; private TextureRegion endLight; private Vector2 origin; private Vector2 centerOrigin; private Vector2 lightOrigin; public float Rotation => ((Projectile) Entity).GetAnyComponent().Body.Rotation; public LaserGraphicsComponent(string image, string slice) : base(image, slice) { var a = Animations.Get(image); aura = a.GetSlice($"{slice}_aura", false); light = a.GetSlice($"{slice}_light", false); end = a.GetSlice("end_aura", false); endAura = a.GetSlice("end", false); endLight = a.GetSlice("end_light", false); origin = new Vector2(0, aura.Height * 0.5f); centerOrigin = new Vector2(0, Sprite.Height * 0.5f); lightOrigin = new Vector2(0, light.Height * 0.5f); } public override void Render(bool shadow) { var scale = new Vector2(Entity.Width / aura.Width, Entity.Height / aura.Height); var p = (Laser) Entity; var a = Rotation; Graphics.Color = p.Color; Graphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * 255); if (shadow) { Graphics.Render(Sprite, Entity.Position + new Vector2(0, 6), a, centerOrigin, scale); } else { Graphics.Render(Sprite, Entity.Position, a, centerOrigin, scale); var sc = new Vector2(p.Scale); var aa = a + (float) Math.PI * 0.25f; Graphics.Render(endAura, Entity.Position, aa, endAura.Center, sc); Graphics.Render(endAura, p.End, aa, endAura.Center, sc); } Graphics.Color.A = 255; Graphics.Color = ColorUtils.WhiteColor; } public void RenderTopLight() { var p = (Laser) Entity; var s = p.Scale; var a = Rotation; Graphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * 255); var sc = new Vector2(p.Scale); var aa = a + (float) Math.PI * 0.25f; Graphics.Render(endLight, Entity.Position, aa, endLight.Center, sc); Graphics.Render(endLight, p.End, aa, endLight.Center, sc); Graphics.Render(light, Entity.Position, a, lightOrigin, new Vector2(Entity.Width, s)); Graphics.Color.A = 255; } public override void RenderLight() { var p = (Laser) Entity; var a = Rotation; var sc = new Vector2(p.Scale); Graphics.Color = p.Color; Graphics.Color.A = (byte) (Math.Min(1f, ((Laser) Entity).LifeTime * 3f) * Lights.AuraAlpha); var aa = a + (float) Math.PI * 0.25f; Graphics.Render(end, Entity.Position, aa, end.Center, sc); Graphics.Render(end, p.End, aa, end.Center, sc); Graphics.Render(aura, Entity.Position, a, origin, new Vector2(Entity.Width / aura.Width, Entity.Height / aura.Height)); Graphics.Color.A = 255; Graphics.Color = ColorUtils.WhiteColor; } } } ================================================ FILE: BurningKnight/entity/projectile/LetterTemplateData.cs ================================================ using System.Collections.Generic; namespace BurningKnight.entity.projectile { public static class LetterTemplateData { public static Dictionary Data = new Dictionary(); static LetterTemplateData() { Data['a'] = new[] { "xxx", "x x", "xxx", "x x", "x x", }; Data['b'] = new[] { "xxx", "x x", "xx ", "x x", "xxx", }; Data['c'] = new[] { " xx", "x ", "x ", "x ", " xx", }; Data['d'] = new[] { "xx ", "x x", "x x", "x x", "xxx", }; Data['e'] = new[] { "xxx", "x ", "xx ", "x ", "xxx", }; Data['f'] = new[] { "xxx", "x ", "xx ", "x ", "x ", }; Data['g'] = new[] { " xx", "x ", "x ", "x x", "xxx", }; Data['h'] = new[] { "x x", "x x", "xxx", "x x", "x x", }; Data['i'] = new[] { "xxx", " x ", " x ", " x ", "xxx", }; Data['j'] = new[] { "xxx", " x ", " x ", " x ", "xx ", }; Data['k'] = new[] { "x x", "x x", "xx ", "x x", "x x", }; Data['l'] = new[] { "x ", "x ", "x ", "x ", "xxx", }; Data['m'] = new[] { "xxx", "xxx", "x x", "x x", "x x", }; Data['n'] = new[] { "xx ", "x x", "x x", "x x", "x x", }; Data['o'] = new[] { " xx", "x x", "x x", "x x", "xx ", }; Data['p'] = new[] { "xxx", "x x", "xxx", "x ", "x ", }; Data['q'] = new[] { " x ", "x x", "x x", "xx ", " xx", }; Data['r'] = new[] { "xxx", "x x", "xx ", "x x", "x x", }; Data['s'] = new[] { " xx", "x ", "xxx", " x", "xx ", }; Data['t'] = new[] { "xxx", " x ", " x ", " x ", " x ", }; Data['u'] = new[] { "x x", "x x", "x x", "x x", " xx", }; Data['v'] = new[] { "x x", "x x", "x x", "xxx", " x ", }; Data['w'] = new[] { "x x", "x x", "x x", "xxx", "xxx", }; Data['x'] = new[] { "x x", "x x", " x ", "x x", "x x", }; Data['y'] = new[] { "x x", "x x", "xxx", " x", "xxx", }; Data['z'] = new[] { "xxx", " x", " x ", "x ", "xxx", }; } } } ================================================ FILE: BurningKnight/entity/projectile/Missile.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using Lens.entity; using Lens.graphics; using Lens.util.camera; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.projectile { public class Missile : Projectile { private const float MinUpTime = 2f; private Entity target; private bool goingDown; private float toY; private float shadowSize; private bool exploded; public bool HurtOwner = true; public Missile(Entity owner, Entity tar) { target = tar; Owner = owner; } public override void AddComponents() { Slice = "missile"; base.AddComponents(); AlwaysVisible = true; AlwaysActive = true; var graphics = new ProjectileGraphicsComponent("projectiles", Slice); AddComponent(graphics); AddTag(Tags.MobProjectile); var w = graphics.Sprite.Source.Width; var h = graphics.Sprite.Source.Height; Width = w; Height = h; Center = Owner.Center; T = MinUpTime + 1; RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); AddComponent(new RectBodyComponent(0, 0, w, h)); BodyComponent.Body.IsBullet = true; BodyComponent.Body.LinearVelocity = new Vector2(0, -100f); Owner.HandleEvent(new ProjectileCreatedEvent { Owner = Owner, Projectile = this }); Depth = Layers.TileLights; CollisionFilterComponent.Add(this, (p, e) => { if (e is Level || e is Prop) { return CollisionResult.Disable; } return CollisionResult.Default; }); } public override void Render() { base.Render(); } public override void PostInit() { base.PostInit(); ProjectileCallbacks.AttachDeathCallback(this, (p, e, t) => { ExplosionMaker.Make(this, damageOwner: HurtOwner); exploded = true; }); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent) { return false; // Ignore all collision } return base.HandleEvent(e); } public override bool BreaksFrom(Entity entity, BodyComponent body) { return false; } public override bool ShouldCollide(Entity entity) { return false; } public override void Update(float dt) { base.Update(dt); Position += BodyComponent.Velocity * dt; if (goingDown) { if (Bottom >= toY && !exploded) { Break(); } } else if (T <= 1f && Bottom < Camera.Instance.Y) { T = MinUpTime + 1; goingDown = true; CenterX = target.CenterX; toY = target.Bottom; GraphicsComponent.FlippedVerticaly = true; BodyComponent.Body.LinearVelocity = new Vector2(0, 100f); Tween.To(16, 0, x => shadowSize = x, 1f); } } protected override void RenderShadow() { if (goingDown) { Graphics.Batch.DrawCircle(CenterX, toY, shadowSize, 16, ColorUtils.WhiteColor, 2f); Graphics.Batch.DrawCircle(CenterX, toY, shadowSize * 0.5f, 16, ColorUtils.WhiteColor, 2f); } } } } ================================================ FILE: BurningKnight/entity/projectile/OldProjectile.cs ================================================ using Lens.entity; /* * Ancient projectile class, reworked a tiny bit to look less messy * Still is a huge mess, and has way too much data per bullet and pretty much no caps */ namespace BurningKnight.entity.projectile { /*public class OldProjectile : Entity, CollisionFilterEntity { public ProjectileDeathCallback OnDeath; public ProjectileCallbacks.UpdateCallback Controller; public ProjectileHurtCallback OnHurt; public ProjectileNearingDeathCallback NearDeath; public ProjectileCollisionCallback OnCollision; public Projectile Parent; public Color Color = ProjectileColor.Red; public ProjectilePattern Pattern; public BodyComponent BodyComponent; public Entity Owner; public Entity FirstOwner; public Item Item; public List EntitiesHurt = new List(); public string Slice; // can be in collision callback public bool BreakOther; // melee public bool CanBeReflected = true; public bool CanBeBroken = true; // Collision public bool Spectral; public bool DieOffscreen; public bool HurtsEveryone; public bool PreventSpectralBreak; public bool BreaksFromWalls = true; public int BounceLeft; public bool Artificial; public bool Dying; public bool Rotates; public bool ManualRotation; public bool Scourged; public bool Boost = true; public bool PreventDespawn; public bool IndicateDeath; public bool NearingDeath => T >= Range - 0.9f && (Range - T) % 0.6f >= 0.3f; public float Damage = 1; public float Range = -1; public float T; public float FlashTimer; public float Scale = 1; public static Projectile Make(Entity owner, string slice, double angle = 0, float speed = 0, bool circle = true, int bounce = 0, Projectile parent = null, float scale = 1, float damage = 1, Item item = null, float range = -1) { if (slice == "default") { slice = "rect"; } var projectile = new Projectile(); owner.Area.Add(projectile); if (owner is Mob && Rnd.Chance(LevelSave.MobDestructionChance)) { projectile.Done = true; return projectile; } projectile.Range = range; if (parent != null) { projectile.Color = parent.Color; } else if (owner is Player) { projectile.Color = ProjectileColor.Yellow; } projectile.Boost = owner is Player; projectile.Damage = damage; projectile.Scale = scale; projectile.Slice = slice; projectile.Parent = parent; projectile.Owner = owner; projectile.FirstOwner = owner; projectile.BounceLeft = bounce; var graphics = new ProjectileGraphicsComponent("projectiles", slice); projectile.AddComponent(graphics); if (graphics.Sprite == null) { Log.Error($"Not found projectile slice {slice}"); projectile.Done = true; return projectile; } owner.HandleEvent(new ProjectileCreatedEvent { Owner = owner, Item = item, Projectile = projectile }); scale = projectile.Scale; var w = graphics.Sprite.Source.Width * scale; var h = graphics.Sprite.Source.Height * scale; projectile.Width = w; projectile.Height = h; projectile.Center = owner.Center; if (owner is Mob m && m.HasPrefix) { projectile.Scourged = true; projectile.Color = ProjectileColor.Black; projectile.AddLight(64, ProjectileColor.Black); } if (circle) { projectile.AddComponent(projectile.BodyComponent = new CircleBodyComponent(0, 0, w / 2f, BodyType.Dynamic, false, true)); } else { projectile.AddComponent(projectile.BodyComponent = new RectBodyComponent(0, 0, w, h, BodyType.Dynamic, false, true)); } projectile.BodyComponent.Body.Restitution = 1; projectile.BodyComponent.Body.Friction = 0; projectile.BodyComponent.Body.IsBullet = true; projectile.BodyComponent.Body.Rotation = (float) angle; if (owner.TryGetComponent(out var buffs) && buffs.Has()) { speed *= 0.5f; } speed *= 10f; if (Math.Abs(speed) > 0.01f) { projectile.BodyComponent.Velocity = new Vector2((float) (Math.Cos(angle) * speed), (float) (Math.Sin(angle) * speed)); } if (parent != null && parent.TryGetComponent(out var l)) { projectile.AddLight(l.Light.Radius, l.Light.Color); } return projectile; } public override void AddComponents() { base.AddComponents(); AddTag(Tags.Projectile); AddComponent(new ShadowComponent(RenderShadow)); AlwaysActive = true; } protected virtual void RenderShadow() { GraphicsComponent.Render(true); } public void AddLight(float radius, Color color) { if (HasComponent() || Area.Tagged[Tags.Projectile].Count > 40) { return; } AddComponent(new LightComponent(this, radius * Scale, color)); } public override void Update(float dt) { base.Update(dt); T += dt; if (NearDeath != null && NearingDeath) { NearDeath(this); NearDeath = null; } if (FlashTimer > 0) { FlashTimer -= dt; } if (Dying) { Scale -= dt * 10; if (Scale <= 0) { Scale = 0; Done = true; } return; } if ((Range > -1 && T >= Range) || (!BreaksFromWalls && Spectral && !OnScreen && !PreventSpectralBreak)) { AnimateDeath(null, true); return; } Controller?.Invoke(this, dt); if (Rotates) { BodyComponent.Body.Rotation += dt * 10; } else if (!ManualRotation) { BodyComponent.Body.Rotation = BodyComponent.Body.LinearVelocity.ToAngle(); } if (!OnScreen && DieOffscreen) { Break(null); } if (Boost) { Position += BodyComponent.Body.LinearVelocity * (dt); } if (!PreventDespawn && Pattern == null && BodyComponent.Velocity.Length() < 0.1f) { Break(null); } } public virtual bool BreaksFrom(Entity entity, BodyComponent body) { if (entity is Projectile p && p.BreakOther && p.Owner != Owner) { p.Break(this); return true; } var r = false; if (TryGetComponent(out var c)) { var rs = c.Invoke(entity); if (rs == CollisionResult.Disable) { return false; } if (rs == CollisionResult.Enable) { r = true; } } if ((entity == Owner || (Owner is Pet pt && entity == pt.Owner) || (Owner is Orbital o && entity == o.Owner)) && (!HurtsEveryone || T < 1f)) { return false; } if (entity is Turret) { return true; } if (!r && entity is creature.bk.BurningKnight) { return false; } if (entity is PlatformBorder || entity is MovingPlatform || entity is Spikes || entity is ShopStand || entity is Statue) { return false; } if (Owner is RoomControllable && entity is Mob) { return false; } if (!BreaksFromWalls && entity is RoomControllable && entity != Owner) { return true; } if (CanHitOwner && entity == Owner) { return true; } if (entity is Creature && !HurtsEveryone && Owner is Mob == entity is Mob) { return false; } return (!(entity is Creature || entity is Level || entity is Tree)) && (BreaksFromWalls && IsWall(entity, body)) || entity.HasComponent(); } private bool IsWall(Entity entity, BodyComponent body) { return (entity is ProjectileLevelBody || (!Spectral && entity is HalfProjectileLevel) || entity is Prop || (entity is Door d && !d.Open && !(body is DoorBodyComponent || d is CustomDoor))); } public bool CanHitOwner; public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (Dying) { return false; } if (ev.Entity is Creature c && c.IgnoresProjectiles()) { return false; } if (EntitiesHurt.Contains(ev.Entity)) { return false; } if (OnCollision != null && OnCollision(this, ev.Entity)) { return false; } if (((HurtsEveryone && (ev.Entity != Owner) || T > 1f) || ( (CanHitOwner && ev.Entity == Owner && T > 0.3f) || (ev.Entity != Owner && (!(Owner is Pet pt) || pt.Owner != ev.Entity) && (!(Owner is Orbital or) || or.Owner != ev.Entity) && !(Owner is RoomControllable && ev.Entity is Mob) && ( !(Owner is Creature ac) || !(ev.Entity is Creature bc) || (ac.IsFriendly() != bc.IsFriendly() || (bc.TryGetComponent(out var bf) && bf.Has())) || bc is ShopKeeper || ac is Player ) ) )) && ev.Entity.TryGetComponent(out var health) && (HurtsEveryone || CanHitOwner || !(ev.Entity is Player) || !(Owner is Player)) && !(Owner is Pet ppt && ppt.Owner == ev.Entity)) { var h = health.ModifyHealth(-Damage, Owner); if (FirstOwner is Mob && FirstOwner == ev.Entity && Owner is Player && health.Dead && T >= 0.2f) { Achievements.Unlock("bk:return_to_sender"); } EntitiesHurt.Add(ev.Entity); if (h) { OnHurt?.Invoke(this, ev.Entity); } } if (((HurtsEveryone && (ev.Entity != Owner) || T > 1f) || ( (CanHitOwner && ev.Entity == Owner && T > 0.3f) || (ev.Entity != Owner && (!(Owner is Pet pt) || pt.Owner != ev.Entity) && (!(Owner is Orbital or) || or.Owner != ev.Entity) && !(Owner is RoomControllable && ev.Entity is Mob) && ( !(Owner is Creature ac) || !(ev.Entity is Creature bc) || (ac.IsFriendly() != bc.IsFriendly() || (bc.TryGetComponent(out var bf) && bf.Has())) || bc is ShopKeeper || ac is Player ) ) )) && ev.Entity.TryGetComponent(out var health) && (HurtsEveryone || CanHitOwner || !(ev.Entity is Player) || !(Owner is Player)) && !(Owner is Pet ppt && ppt.Owner == ev.Entity)) { var h = health.ModifyHealth(-Damage, Owner); if (FirstOwner is Mob && FirstOwner == ev.Entity && Owner is Player && health.Dead && T >= 0.2f) { Achievements.Unlock("bk:return_to_sender"); } EntitiesHurt.Add(ev.Entity); if (h) { OnHurt?.Invoke(this, ev.Entity); } } var mute = false; if (Run.Level.Biome is IceBiome && !(Owner is creature.bk.BurningKnight) && ev.Entity is ProjectileLevelBody lvl) { if (lvl.Break(CenterX, CenterY)) { mute = true; AudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed("level_snow_break", 3); } } if (BreaksFrom(ev.Entity, ev.Body)) { if (BounceLeft > 0) { BounceLeft -= 1; } else { if (!mute && IsWall(ev.Entity, ev.Body)) { if (Owner is Player) { AudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed("projectile_wall", 2, 0.5f); } else { AudioEmitterComponent.Dummy(Area, Center).EmitRandomized("projectile_wall_enemy", 0.5f); } } AnimateDeath(ev.Entity); } } } return base.HandleEvent(e); } public virtual bool ShouldCollide(Entity entity) { if (entity == Owner) { return false; } if (entity is Tombstone && !(Owner is Player)) { return false; } return !(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); } public void Break(Entity from = null) { AnimateDeath(from); } protected virtual void AnimateDeath(Entity from, bool timeout = false) { if (Dying) { return; } Dying = true; try { var l = Math.Min(15, BodyComponent.Velocity.Length()); if (l > 1f) { var a = VectorExtension.ToAngle(BodyComponent.Velocity); for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()); part.Position = Center; Run.Level.Area.Add(part); part.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.4f, 0.4f), l); part.Depth = Layers.WindFx; part.Particle.Scale = 0.7f; } } Camera.Instance.ShakeMax(4); OnDeath?.Invoke(this, from, timeout); BodyComponent.Velocity = Vector2.Zero; } catch (Exception e) { Log.Error(e); } } public virtual void Resize(float newScale) { Scale = newScale; var graphics = GetComponent(); var w = graphics.Sprite.Source.Width * Scale; var h = graphics.Sprite.Source.Height * Scale; var center = Center; Width = w; Height = h; Center = center; if (HasComponent()) { GetComponent().Resize(0, 0, w / 2f, w / 2, true); } else { GetComponent().Resize(0, 0, w, h, true); } } }*/ } ================================================ FILE: BurningKnight/entity/projectile/Projectile.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.particle; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.ice; using BurningKnight.entity.creature.mob.jungle; using BurningKnight.entity.creature.npc; using BurningKnight.entity.creature.pet; using BurningKnight.entity.creature.player; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.item.stand; using BurningKnight.entity.item.util; using BurningKnight.entity.orbital; using BurningKnight.entity.room.controllable; using BurningKnight.entity.room.controllable.platform; using BurningKnight.entity.room.controllable.spikes; using BurningKnight.entity.room.controllable.turret; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.entities; using BurningKnight.level.entities.decor; using BurningKnight.level.entities.statue; using BurningKnight.physics; using BurningKnight.state; using Lens.entity; using Lens.util; using Lens.util.camera; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public class Projectile : Entity, CollisionFilterEntity { public const ProjectileFlags DefaultFlags = ProjectileFlags.Reflectable | ProjectileFlags.BreakableByMelee | ProjectileFlags.Fresh; public Projectile Parent; // Potentially not needed public Entity Owner; public Entity FirstOwner; // Potentially not needed public Item Item; public Color Color = ProjectileColor.Red; public ProjectileFlags Flags = DefaultFlags; public ProjectileCallbacks Callbacks; public string Slice; public List EntitiesHurt = new List(); // can we get rid of it? public float Damage = 1; public float T = -1; public float Scale = 1; public int Bounce; public bool Dying { get => T < -128; private set => T = value ? -129 : -1; } public bool NearingDeath => T < 0.9f && T % 0.6f >= 0.3f; public BodyComponent BodyComponent => GetAnyComponent(); public override void Init() { base.Init(); AlwaysActive = true; } public override void AddComponents() { base.AddComponents(); AddTag(Tags.Projectile); AddComponent(new ShadowComponent(RenderShadow)); AlwaysActive = true; } protected virtual void RenderShadow() { GraphicsComponent.Render(true); } public override void Update(float dt) { base.Update(dt); if (Dying) { Scale -= dt * 10; if (Scale <= 0) { Scale = 0; Done = true; } return; } if (T > 0) { T -= dt; if (T <= 0) { Break(null, true); return; } } else { T -= dt; if (T <= -8) { Break(null, true); return; } } Flags &= ~ProjectileFlags.Fresh; Callbacks?.OnUpdate?.Invoke(this, dt); var bodyComponent = GetAnyComponent(); if (!Dying && (Owner is Player || Owner is Sniper)) { Position += bodyComponent.Body.LinearVelocity * dt; } if (!HasFlag(ProjectileFlags.ManualRotation)) { if (HasFlag(ProjectileFlags.AutomaticRotation)) { bodyComponent.Body.Rotation += dt * 10; } else { bodyComponent.Body.Rotation = VectorExtension.ToAngle(bodyComponent.Body.LinearVelocity); } } if (Owner is Mob) { if (Area.Tagged[Tags.Player].Count == 0) { Break(); // Future proofing return, do not remove return; } } else if (Owner is Player) { if (Area.Tagged[Tags.PlayerProjectile].Count >= 69 && HasTag(Tags.PlayerProjectile)) { RemoveTag(Tags.PlayerProjectile); Break(); // Future proofing return, do not remove return; } } } public bool HasFlag(ProjectileFlags flag) { return (Flags & flag) != 0; } // Aka should bounce from the object or no public virtual bool ShouldCollide(Entity entity) { if (entity == Owner) { return false; } if (entity is Tombstone && !(Owner is Player)) { return false; } if (entity is Chasm || entity is MovingPlatform || entity is PlatformBorder || entity is Creature || entity is Item || entity is Projectile || entity is ShopStand || entity is Bomb) { return false; } return !(entity is Level || entity is HalfWall) && !(entity is Door d && d.Open) && !( ( HasFlag(ProjectileFlags.FlyOverStones) || HasFlag(ProjectileFlags.FlyOverWalls) ) && (entity is Prop || entity is Door || entity is HalfProjectileLevel || entity is ProjectileLevelBody) ); } // Aka should break on collision with it or no public virtual bool BreaksFrom(Entity entity, BodyComponent body) { if (TryGetComponent(out var c)) { var rs = c.Invoke(entity); if (rs == CollisionResult.Disable) { return false; } else if (rs == CollisionResult.Enable) { return true; } } if ((entity == Owner || (Owner is Pet pt && entity == pt.Owner) || (Owner is Orbital o && entity == o.Owner)) && (!HasFlag(ProjectileFlags.HurtsEveryone) || T < 1f)) { return false; } if (entity is Turret) { return true; } if ((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) { return false; } if (HasFlag(ProjectileFlags.FlyOverWalls) && entity is RoomControllable && entity != Owner) { return true; } if (HasFlag(ProjectileFlags.HitsOwner) && entity == Owner) { return true; } if (entity is Creature && !HasFlag(ProjectileFlags.HurtsEveryone) && Owner is Mob == entity is Mob) { return false; } if (IsWall(entity, body)) { return !HasFlag(ProjectileFlags.FlyOverWalls); } return (!(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(); } private bool IsWall(Entity entity, BodyComponent body) { return ((entity is ProjectileLevelBody || (!(HasFlag(ProjectileFlags.FlyOverStones) || HasFlag(ProjectileFlags.FlyOverWalls)) && entity is HalfProjectileLevel)) || entity is Prop || (entity is Door d && !d.Open && !(body is DoorBodyComponent || d is CustomDoor))); } private bool IgnoreHurtRules(Entity e) { return e is ShopKeeper; } private bool ShouldHurt(Entity entity) { var e = HasFlag(ProjectileFlags.HurtsEveryone); if (entity == Owner && !(HasFlag(ProjectileFlags.HitsOwner) || e)) { return false; } if (!e && Owner is Creature oc && entity is Creature ec && !IgnoreHurtRules(oc) && !IgnoreHurtRules(ec)) { var ownerFriendly = oc.IsFriendly(); var entityFriendly = ec.IsFriendly(); if (ownerFriendly == entityFriendly) { return false; } } return true; } public override bool HandleEvent(Event e) { if (!Dying && !HasFlag(ProjectileFlags.Fresh) && e is CollisionStartedEvent cse) { var entity = cse.Entity; if (entity is Creature creature) { if (creature.IgnoresProjectiles()) { return false; } } else if (entity is Projectile projectile) { if (HasFlag(ProjectileFlags.BreakOtherProjectiles)) { projectile.Break(this); return false; } } if (EntitiesHurt.Contains(entity)) { return false; } if (entity.TryGetComponent(out var hp) && ShouldHurt(entity)) { hp.ModifyHealth(-Damage, Owner, !(Owner is Snowman) ? DamageType.Custom : DamageType.Regular); Callbacks?.OnHurt?.Invoke(this, entity); EntitiesHurt.Add(entity); } if (Callbacks?.OnCollision != null && Callbacks.OnCollision(this, entity)) { return false; } var mute = false; if (Run.Level.Biome is IceBiome && !(Owner is creature.bk.BurningKnight) && cse.Entity is ProjectileLevelBody lvl) { if (lvl.Break(CenterX, CenterY)) { mute = true; AudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed("level_snow_break", 3); } } if (BreaksFrom(entity, cse.Body)) { if (IsWall(entity, cse.Body)) { if (!mute) { if (Owner is Player) { AudioEmitterComponent.Dummy(Area, Center).EmitRandomizedPrefixed("projectile_wall", 2, 0.5f); } else { AudioEmitterComponent.Dummy(Area, Center).EmitRandomized("projectile_wall_enemy", 0.5f); } } } if (Bounce <= 0) { Break(entity); } else { Bounce--; } } } return base.HandleEvent(e); } public virtual void Resize(float scale) { var graphics = GetComponent(); var w = graphics.Sprite.Source.Width * scale; var h = graphics.Sprite.Source.Height * scale; var center = Center; Width = w; Height = h; Center = center; if (HasComponent()) { GetComponent().Resize(0, 0, w / 2f, w / 2, true); } else { GetComponent().Resize(0, 0, w, h, true); } } public void Break(Entity from = null, bool timeout = false) { if (Dying) { return; } Dying = true; try { var bodyComponent = GetAnyComponent(); var l = Math.Min(15, bodyComponent.Velocity.Length()); if (l > 1f && Area.Tagged[Tags.Projectile].Count < 99) { var a = VectorExtension.ToAngle(bodyComponent.Velocity); for (var i = 0; i < 4; i++) { var part = new ParticleEntity(Particles.Dust()) { Position = Center }; Run.Level.Area.Add(part); part.Particle.Velocity = MathUtils.CreateVector(a + Rnd.Float(-0.4f, 0.4f), l); part.Depth = Layers.WindFx; part.Particle.Scale = 0.7f; } } Camera.Instance.ShakeMax(4); Callbacks?.OnDeath?.Invoke(this, from, timeout); bodyComponent.Velocity = Vector2.Zero; } catch (Exception e) { Log.Error(e); } } public void AddFlags(params ProjectileFlags[] projectileFlags) { foreach (var flag in projectileFlags) { Flags |= flag; } } public void RemoveFlags(params ProjectileFlags[] projectileFlags) { foreach (var flag in projectileFlags) { Flags &= ~flag; } } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileBuilder.cs ================================================ using System; using BurningKnight.assets.lighting; using BurningKnight.entity.buff; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.creature.mob.boss; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.save; using BurningKnight.state; using BurningKnight.util; using Lens.entity; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.projectile { public class ProjectileBuilder { public Entity Owner; private Projectile parent; public Projectile Parent { get => parent; set { if (value != null) { Color = value.Color; } parent = value; } } public ProjectileFlags Flags = Projectile.DefaultFlags; public string Slice; public Vector2 Velocity; public Vector2 Offset; public float Scale = 1f; public float Damage = 1f; public float Range = -1f; public bool RectHitbox; public bool Poof; public Color Color = ProjectileColor.Red; public float LightRadius; public int Bounce; private bool empty; public ProjectileBuilder(Entity projectileOwner, string projectileSlice) { if (projectileSlice == "default") { projectileSlice = "rect"; } Slice = projectileSlice; Owner = projectileOwner; if (Owner is Mob mob) { if (Rnd.Chance(LevelSave.MobDestructionChance)) { empty = true; return; } if (mob.HasPrefix) { LightRadius = 64; Color = Color.Black; AddFlags(ProjectileFlags.Scourged); } } else if (Owner is Player || (Owner is Item item && item.Owner is Player)) { Color = ProjectileColor.Yellow; } } public ProjectileBuilder Shoot(double angle, float speed) { Velocity = MathUtils.CreateVector(angle, speed); return this; } public ProjectileBuilder Move(double angle, float distance) { Offset = MathUtils.CreateVector(angle, distance); return this; } public ProjectileBuilder AddFlags(params ProjectileFlags[] projectileFlags) { foreach (var flag in projectileFlags) { Flags |= flag; } return this; } public ProjectileBuilder RemoveFlags(params ProjectileFlags[] projectileFlags) { foreach (var flag in projectileFlags) { Flags &= ~flag; } return this; } public Projectile Build() { if (empty || ((Owner is Mob && !(Owner is creature.bk.BurningKnight)) && Owner.Area.Tagged[Tags.MobProjectile].Count >= 199)) { return null; } Item item = null; if (Owner is Item i) { item = i; Owner = i.Owner; } var projectile = new Projectile { Owner = Owner, FirstOwner = Owner, Damage = Damage, Flags = Flags, Slice = Slice, Bounce = Math.Min(8, Bounce), Scale = Scale, Color = Color, Parent = parent, Item = item }; Owner.Area.Add(projectile); if (Owner is Mob) { projectile.AddTag(Tags.MobProjectile); if ((Owner is Boss && Run.Loop > 0) || Run.Loop > 1) { projectile.AddFlags(ProjectileFlags.Scourged); } } else if (Owner is Player) { projectile.AddTag(Tags.PlayerProjectile); } var graphics = new ProjectileGraphicsComponent("projectiles", Slice); if (graphics.Sprite == null) { Log.Error($"Not found projectile slice {Slice}"); empty = true; return null; } projectile.AddComponent(graphics); var w = graphics.Sprite.Source.Width * Scale; var h = graphics.Sprite.Source.Height * Scale; projectile.Width = w; projectile.Height = h; projectile.Center = Owner.Center + Offset; BodyComponent bodyComponent; if (RectHitbox) { projectile.AddComponent(bodyComponent = new RectBodyComponent(0, 0, w, h, BodyType.Dynamic, false, true)); } else { projectile.AddComponent(bodyComponent = new CircleBodyComponent(0, 0, w / 2f, BodyType.Dynamic, false, true)); } var body = bodyComponent.Body; body.Restitution = 1; body.Friction = 0; body.IsBullet = true; body.Rotation = Velocity.ToAngle(); if (Owner.TryGetComponent(out var buffs) && buffs.Has()) { Velocity *= 0.5f; } if (Range > 0) { // / Velocity.Length() projectile.T = Range; } Velocity *= 10f; body.LinearVelocity = Velocity; var count = Owner.Area.Tagged[Tags.Projectile].Count; if (count < 99) { if (LightRadius > 0) { projectile.AddComponent(new LightComponent(projectile, LightRadius * Scale, Color)); } if (Poof) { AnimationUtil.Poof(projectile.Center); } } Owner.HandleEvent(new ProjectileCreatedEvent { Owner = Owner, Item = item, Projectile = projectile }); return projectile; } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileCallbacks.cs ================================================ using Lens.entity; namespace BurningKnight.entity.projectile { public class ProjectileCallbacks { public delegate void UpdateCallback(Projectile p, float dt); public delegate void DeathCallback(Projectile p, Entity from, bool t); public delegate void HurtCallback(Projectile p, Entity e); public delegate bool CollisionCallback(Projectile p, Entity e); public UpdateCallback OnUpdate; public DeathCallback OnDeath; public HurtCallback OnHurt; public CollisionCallback OnCollision; public static void AttachUpdateCallback(Projectile p, UpdateCallback callback) { if (p.Callbacks == null) { p.Callbacks = new ProjectileCallbacks(); } p.Callbacks.OnUpdate += callback; } public static void AttachDeathCallback(Projectile p, DeathCallback callback) { if (p.Callbacks == null) { p.Callbacks = new ProjectileCallbacks(); } p.Callbacks.OnDeath += callback; } public static void AttachHurtCallback(Projectile p, HurtCallback callback) { if (p.Callbacks == null) { p.Callbacks = new ProjectileCallbacks(); } p.Callbacks.OnHurt += callback; } public static void AttachCollisionCallback(Projectile p, CollisionCallback callback) { if (p.Callbacks == null) { p.Callbacks = new ProjectileCallbacks(); } p.Callbacks.OnCollision += callback; } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileColor.cs ================================================ using System.Collections.Generic; using BurningKnight.assets; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public static class ProjectileColor { public static Color Yellow = Palette.Default[30]; public static Color BkRed = new Color(1f, 0f, 0f); public static Color Red = Palette.Default[0]; public static Color Green = Palette.Default[35]; public static Color DarkGreen = Palette.Default[37]; public static Color Blue = Palette.Default[40]; public static Color Cyan = Palette.Default[42]; public static Color Purple = Palette.Default[54]; public static Color Orange = Palette.Default[28]; public static Color Pink = Palette.Default[59]; public static Color Brown = Palette.Default[19]; public static Color Gray = Palette.Default[6]; public static Color Black = Color.Black; public static Color White = Color.White; public static Color[] Rainbow = { Red, Orange, Yellow, Green, Cyan, Blue, Purple }; public static Color[] DesertRainbow = { Red, Orange, Yellow }; public static Dictionary Colors = new Dictionary { { "yellow", Yellow }, { "red", Red }, { "green", Green }, { "blue", Blue }, { "cyan", Cyan }, { "purple", Purple }, { "orange", Orange }, { "pink", Pink }, { "brown", Brown }, { "black", Black }, { "white", White }, }; } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileFlags.cs ================================================ using System; namespace BurningKnight.entity.projectile { [Flags] public enum ProjectileFlags { Scourged = 1 << 1, Reflectable = 1 << 2, ManualRotation = 1 << 3, AutomaticRotation = 1 << 4, BreakableByMelee = 1 << 5, FlyOverStones = 1 << 6, Artificial = 1 << 7, BreakOtherProjectiles = 1 << 8, DieOffScreen = 1 << 9, FlyOverWalls = 1 << 10, Fresh = 1 << 11, HitsOwner = 1 << 12, HurtsEveryone = 1 << 13 } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileGraphicsComponent.cs ================================================ using System; using BurningKnight.assets; using BurningKnight.assets.lighting; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob.boss; using Lens; using Lens.assets; using Lens.graphics; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public class ProjectileGraphicsComponent : BasicProjectileGraphicsComponent { public static TextureRegion Flash; public bool IgnoreRotation; public float Rotation => IgnoreRotation ? 0 : ((Projectile) Entity).GetAnyComponent().Body.Rotation; public TextureRegion Aura; public TextureRegion Light; public ProjectileGraphicsComponent(string image, string slice) : base(image, slice) { if (Flash == null) { Flash = CommonAse.Particles.GetSlice("flash"); } var a = Animations.Get(image); Aura = a.GetSlice($"{slice}_aura", false); Light = a.GetSlice($"{slice}_light", false); } public override void Init() { base.Init(); if (Light == null) { ((Projectile) Entity).Color = ColorUtils.WhiteColor; } } private bool ShouldIndicateProjectileDeath(Projectile projectile) { return projectile.Owner is OldKing; } public override void Render(bool shadow) { var p = (Projectile) Entity; var scale = new Vector2(p.Scale); var a = Rotation; var 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 var spr = b ? Flash : Sprite; var or = spr.Center; if (shadow) { Graphics.Render(spr, Entity.Center + new Vector2(0, 6), a, or, scale); return; } var d = p.Dying || (ShouldIndicateProjectileDeath(p) && p.NearingDeath); var started = false; bool scourged = p.HasFlag(ProjectileFlags.Scourged); if (!d) { // fixme: p.Effect.GetColor() Graphics.Color = scourged ? ColorUtils.BlackColor : p.Color; } else if (Light == null) { var shader = Shaders.Entity; Shaders.Begin(shader); shader.Parameters["flash"].SetValue(1f); shader.Parameters["flashReplace"].SetValue(1f); shader.Parameters["flashColor"].SetValue(ColorUtils.White); started = true; } Graphics.Render(spr, Entity.Center, a, or, scale); Graphics.Color = ColorUtils.WhiteColor; if (started) { Shaders.End(); } if (!b && Light != null) { if (scourged) { Graphics.Color = p.Color; } Graphics.Render(Light, Entity.Center, a, or, scale); if (scourged) { Graphics.Color = ColorUtils.WhiteColor; } } } public override void RenderLight() { if (Aura != null) { var p = (Projectile) Entity; if (!(p.Dying || (ShouldIndicateProjectileDeath(p) && p.NearingDeath))) { Graphics.Color = p.Color; } var a = !p.HasFlag(ProjectileFlags.BreakableByMelee) && !p.HasFlag(ProjectileFlags.Reflectable); Graphics.Color.A = (byte) Math.Round(Lights.AuraAlpha * (a ? ((Math.Sin(Engine.Time * 4f * Math.PI) * 0.5f + 0.5f) * 2) : 1)); Graphics.Render(Aura, Entity.Center, Rotation, Aura.Center, new Vector2(((Projectile) Entity).Scale)); Graphics.Color.A = 255; Graphics.Color = ColorUtils.WhiteColor; } } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileGraphicsEffect.cs ================================================ namespace BurningKnight.entity.projectile { public enum ProjectileGraphicsEffect { Normal, Poison, Charming, Freezing, Slowing, Burning, BrokenArmor } } ================================================ FILE: BurningKnight/entity/projectile/ProjectilePattern.cs ================================================ using System; using System.Collections.Generic; using Lens.entity; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public delegate void ProjectilePatternController(Projectile p, ProjectilePattern.ProjectileData data, ProjectilePattern pt, int i, float dt); public class ProjectilePattern : Entity { public List Projectiles = new List(); private int maxProjectiles; public ProjectilePatternController Controller; public Vector2 Velocity; public int Count => maxProjectiles; public float T; private bool launched; public ProjectilePattern(ProjectilePatternController c) { Controller = c; AlwaysActive = true; Width = 0; Height = 0; } public void Launch(float angle, float speed) { Velocity = new Vector2((float) Math.Cos(angle) * speed, (float) Math.Sin(angle) * speed); launched = true; } public override void Update(float dt) { base.Update(dt); if (launched) { T += dt; Position += Velocity * dt; if (Controller != null) { foreach (var p in Projectiles) { Controller(p.Projectile, p, this, p.Id, dt); } } } for (var i = Projectiles.Count - 1; i >= 0; i--) { if (Projectiles[i].Projectile.Done) { Projectiles.RemoveAt(i); } } if (launched) { if (Projectiles.Count == 0) { Done = true; } } } public void Kill() { Done = true; foreach (var p in Projectiles) { p.Projectile.Done = true; } } public void Add(Projectile p) { if (!p.Done) { Projectiles.Add(new ProjectileData { Projectile = p, Id = maxProjectiles, Distance = DistanceTo(p), Angle = AngleTo(p) }); p.AddFlags(ProjectileFlags.ManualRotation); } maxProjectiles++; } public void Remove(Projectile p) { for (var i = 0; i < Projectiles.Count; i++) { if (Projectiles[i].Projectile == p) { Projectiles.RemoveAt(i); p.RemoveFlags(ProjectileFlags.ManualRotation); return; } } } public class ProjectileData { public Projectile Projectile; public int Id; public float Angle; public float Distance; } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileRegistry.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.mod; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.mob; using BurningKnight.entity.item; using BurningKnight.entity.item.use; using BurningKnight.entity.projectile.controller; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.entities; using BurningKnight.level.paintings; using BurningKnight.level.tile; using BurningKnight.physics; using BurningKnight.state; using Lens.assets; using Lens.entity; using Lens.input; using Lens.util.math; using Lens.util.timer; namespace BurningKnight.entity.projectile { public static class ProjectileRegistry { private static Dictionary> registry = new Dictionary>(); public static void Add(string id, Action fn, Mod mod = null) { registry[$"{mod?.Prefix ?? Mods.BurningKnight}:{id}"] = fn; } public static Action Get(string id) { return registry.TryGetValue(id, out var f) ? f : null; } static ProjectileRegistry() { Add("skull", skull => { ProjectileCallbacks.AttachDeathCallback(skull, (p, e, t) => { var b = new ProjectileBuilder(p.Owner, "small"); b.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); for (var i = 0; i < 8; i++) { var bullet = b.Shoot(((float) i) / 4 * (float) Math.PI, (i % 2 == 0 ? 2 : 1) * 4 + 3).Build(); bullet.Center = p.Center; } }); ProjectileCallbacks.AttachUpdateCallback(skull, TargetProjectileController.Make(null, 0.5f)); skull.T = 5f; skull.RemoveFlags(ProjectileFlags.BreakableByMelee, ProjectileFlags.Reflectable); skull.GetComponent().IgnoreRotation = true; }); Add("disk", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is HalfProjectileLevel ? CollisionResult.Disable : CollisionResult.Default); p.Bounce += 10; p.AddFlags(ProjectileFlags.HitsOwner); p.GetComponent().Body.AngularVelocity = 10f; }); Add("what", p => { ProjectileCallbacks.AttachUpdateCallback(p, WhatController.Make()); p.GetComponent().Body.AngularVelocity = 10f; }); Add("soap", p => { ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(2)); }); Add("grenade", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.Bounce = 0; return CollisionResult.Enable; } return CollisionResult.Default; }); ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(1)); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { ExplosionMaker.Make(pr, 16, damage: 8); }); ProjectileCallbacks.AttachUpdateCallback(p, (pr, dt) => { if (pr.T >= 3f) { pr.Break(); } }); }); Add("missile", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.Bounce = 0; return CollisionResult.Enable; } if (with is Prop) { return CollisionResult.Disable; } return CollisionResult.Default; }); ProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.Make(null, 0.5f)); ProjectileCallbacks.AttachUpdateCallback(p, SmokeProjectileController.Make()); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { ExplosionMaker.Make(pr, 32); }); }); Add("shotgun", p => { ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(1)); p.Bounce += 1; }); Add("follower", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.Bounce = 0; return CollisionResult.Enable; } if (with is Prop) { return CollisionResult.Disable; } return CollisionResult.Default; }); ProjectileCallbacks.AttachUpdateCallback(p, TargetProjectileController.MakeCursor()); ProjectileCallbacks.AttachUpdateCallback(p, SmokeProjectileController.Make()); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { ExplosionMaker.Make(pr, 32); }); }); Add("flak", p => { CollisionFilterComponent.Add(p, (entity, with) => { if (with is Mob) { p.Bounce = 0; return CollisionResult.Enable; } return CollisionResult.Default; }); ProjectileCallbacks.AttachUpdateCallback(p, SlowdownProjectileController.Make(0.5f)); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { var b = new ProjectileBuilder(pr.Owner, "shot"); for (var i = 0; i < 8; i++) { var pr2 = b.Shoot((float) i / 8 * (float) Math.PI * 2, 8).Build(); pr2.Center = pr.Center; ProjectileCallbacks.AttachUpdateCallback(pr2, SlowdownProjectileController.Make(1)); } }); ProjectileCallbacks.AttachUpdateCallback(p, (pr, dt) => { if (pr.T >= 1f) { pr.Break(); } }); }); Add("duck", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default); }); Add("portal", p => { p.Center = p.Owner.GetComponent().Cursor.GamePosition; p.GetAnyComponent().Velocity *= -1; }); Add("axe", p => { CollisionFilterComponent.Add(p, (entity, with) => ((with is Creature && with != p.Owner) || ((Projectile) entity).Bounce == 0) ? CollisionResult.Disable : CollisionResult.Default); var ts = Timer.Add(() => { p.Item.Renderer.Hidden = false; foreach (var u in p.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } }, 3f); p.T = 5; ProjectileCallbacks.AttachCollisionCallback(p, (projectile, e) => { if (Run.Level.Biome is IceBiome && e is ProjectileLevelBody lvl) { if (lvl.Break(projectile.CenterX, projectile.CenterY)) { AudioEmitterComponent.Dummy(projectile.Area, projectile.Center).EmitRandomizedPrefixed("level_snow_break", 3); } } if (projectile.Bounce == 0) { if (e == projectile.Owner) { projectile.Item.Renderer.Hidden = false; projectile.Break(); foreach (var u in projectile.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } } else if (!(e is Mob)) { return true; } } else if (projectile.BreaksFrom(e, null)) { if (e is Painting || e is BreakableProp || e is ExplodingBarrel || e.HasComponent()) { projectile.Bounce++; } else { var b = projectile.GetComponent().Body; b.LinearVelocity *= -1; projectile.Bounce = 0; projectile.EntitiesHurt.Clear(); ProjectileCallbacks.AttachUpdateCallback(projectile, ReturnProjectileController.Make(projectile.Owner)); var pi = projectile.Callbacks?.OnDeath; ProjectileCallbacks.AttachDeathCallback(projectile, (pr, ee, t) => { pr.Item.Renderer.Hidden = false; foreach (var u in pr.Item.Uses) { if (u is SimpleShootUse ss) { ss.ProjectileDied = true; break; } } ts.Cancel(); pr.Owner.GetComponent().EmitRandomized("item_axe_catch"); }); pi?.Invoke(projectile, e, false); return true; } } return false; }); p.Bounce = 1; p.AddFlags(ProjectileFlags.AutomaticRotation); p.Item.Renderer.Hidden = true; }); Add("lava_wand", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default); p.AddFlags(ProjectileFlags.AutomaticRotation); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { AudioEmitterComponent.Dummy(pr.Area, pr.Center).EmitRandomized("item_magic_lava_appear"); var x = (int) Math.Round(pr.CenterX / 16f); var y = (int) Math.Round(pr.CenterY / 16f); const float r = 2.3f; for (var xx = -r; xx <= r; xx++) { for (var yy = -r; yy <= r; yy++) { var zx = (int) xx + x; var zy = (int) yy + y; if (Math.Sqrt(xx * xx + yy * yy) <= r && Run.Level.Get(zx, zy).IsPassable()) { Run.Level.Set(zx, zy, Tile.Lava); Timer.Add(() => { Run.Level.Set(zx, zy, Tile.Ember); Run.Level.UpdateTile(zx, zy); }, Rnd.Float(5f, 15f)); } } } Run.Level.TileUp(); }); }); Add("discord_rod", p => { CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default); p.AddFlags(ProjectileFlags.AutomaticRotation); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { pr.Owner.Center = pr.Center; Audio.PlaySfx("item_discord"); }); }); Add("web_wand", p => { // CollisionFilterComponent.Add(p, (entity, with) => with is Mob || with is Prop ? CollisionResult.Disable : CollisionResult.Default); p.AddFlags(ProjectileFlags.AutomaticRotation); ProjectileCallbacks.AttachDeathCallback(p, (pr, e, t) => { AudioEmitterComponent.Dummy(pr.Area, pr.Center).EmitRandomized("item_magic_web_appear"); var x = (int) Math.Round(pr.CenterX / 16f); var y = (int) Math.Round(pr.CenterY / 16f); const float r = 2.3f; for (var xx = -r; xx <= r; xx++) { for (var yy = -r; yy <= r; yy++) { var zx = (int) xx + x; var zy = (int) yy + y; if (Math.Sqrt(xx * xx + yy * yy) <= r && Run.Level.Get(zx, zy).IsPassable()) { Run.Level.Set(zx, zy, Tile.Cobweb); } } } Run.Level.TileUp(); }); }); } } } ================================================ FILE: BurningKnight/entity/projectile/ProjectileTemplate.cs ================================================ using System; using Lens.entity; using Lens.util; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile { public static class ProjectileTemplate { public static void Make(Entity owner, string texture, Vector2 center, float angle, float speed, int bounce, int start, Action modifier, params string[] data) { var height = data.Length; var width = 0; for (var i = 0; i < height; i++) { width = Math.Max(width, data[i].Length); } var c = new Vector2(); var d = 0.2f; var builder = new ProjectileBuilder(owner, texture); builder.Shoot(angle, speed); builder.Bounce = bounce; for (var x = 0; x < width; x++) { var x1 = x; Timer.Add(() => { for (var y = 0; y < height; y++) { if (data[y][x1] != ' ') { var p = builder.Build(); p.Center = center + MathUtils.RotateAround(new Vector2(0, (y - height / 2f) * 10), angle, c); modifier?.Invoke(p); } } }, (width - x + start) * d); } } public static void MakeFast(Entity owner, string texture, Vector2 center, float angle, Action modifier, string[] data, Action end) { var height = data.Length; var width = 0; for (var i = 0; i < height; i++) { width = Math.Max(width, data[i].Length); } var c = new Vector2(); var first = true; var builder = new ProjectileBuilder(owner, texture); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { if (data[y][x] != ' ') { var first1 = first; var x2 = x; var y1 = y; Timer.Add(() => { var p = builder.Build(); p.Center = center + MathUtils.RotateAround(new Vector2(x2 * 10, (y1 - height / 2f) * 10), angle, c); modifier?.Invoke(p); if (first1) { end(); } }, first ? 0.5f : Rnd.Float(0, 0.4f)); first = false; } } } } public static void Write(string what, Entity owner, string texture, Vector2 center, float angle, float speed, int bounce) { what = what.ToLower(); for (var i = 0; i < what.Length; i++) { var c = what[i]; if (c == ' ') { continue; } if (!LetterTemplateData.Data.TryGetValue(c, out var data)) { continue; } Make(owner, texture, center, angle, speed, bounce, (what.Length - i) * 4, null, data); } } } } ================================================ FILE: BurningKnight/entity/projectile/controller/BoomerangProjectileController.cs ================================================ using BurningKnight.entity.component; using Lens.entity; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.controller { public static class BoomerangProjectileController { public static ProjectileCallbacks.UpdateCallback Make(Entity owner, float speed = 1f) { return (p, dt) => { if (p.T < 0.2f) { return; } var b = p.GetAnyComponent(); var dx = p.DxTo(owner); var dy = p.DyTo(owner); var d = MathUtils.Distance(dx, dy); var s = dt * 250 * speed; if (d <= 8f) { p.Break(); return; } b.Velocity += new Vector2(dx / d * s, dy / d * s); b.Angle = b.Velocity.ToAngle(); }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/ExpandProjectileController.cs ================================================ using System; namespace BurningKnight.entity.projectile.controller { public class ExpandProjectileController { public static ProjectileCallbacks.UpdateCallback Make(float speed = 1f) { var t = 0f; var z = 0f; var dmg = -1f; return (p, dt) => { t += dt * speed; z += dt; if (dmg < 0) { dmg = p.Damage; } if (z >= 0.05f) { var s = Math.Min(1, t * 5f); // (p.Scale > 1 ? 1f / p.Scale : p.Scale); z -= 0.05f; p.Resize(s); p.Damage = dmg * p.Scale; } }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/HsvProjectileController.cs ================================================ using Lens.graphics; namespace BurningKnight.entity.projectile.controller { public class HsvProjectileController { public static ProjectileCallbacks.UpdateCallback Make(float speed = 1f, float start = 0) { return (p, dt) => { p.Color = ColorUtils.FromHSV((p.T + start) * speed * 120 % 360, 100, 100); }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/ReturnProjectileController.cs ================================================ using System; using BurningKnight.entity.component; using Lens.entity; using Lens.util; namespace BurningKnight.entity.projectile.controller { public static class ReturnProjectileController { public static ProjectileCallbacks.UpdateCallback Make(Entity owner, float speed = 1f) { return (p, dt) => { var b = p.GetAnyComponent(); var dx = p.DxTo(owner); var dy = p.DyTo(owner); var d = MathUtils.Distance(dx, dy); if (d <= 8f) { p.Break(); return; } b.Velocity = MathUtils.CreateVector(MathUtils.LerpAngle(b.Velocity.ToAngle(), Math.Atan2(dy, dx), dt * 50 * speed), b.Velocity.Length()); }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/ShrinkProjectileController.cs ================================================ using System; namespace BurningKnight.entity.projectile.controller { public static class ShrinkProjectileController { public static ProjectileCallbacks.UpdateCallback Make(float speed = 1f) { var t = 0f; var z = 0.05f; var dmg = -1f; var sc = 2f; return (p, dt) => { if (dmg < 0) { // sc = p.Scale; dmg = p.Damage; } t += dt * speed; z += dt; if (z >= 0.05f) { var s = sc - t * 4f / Math.Max(1, p.Scale); // (p.Scale > 1 ? 1f / p.Scale : p.Scale); z = 0; p.Resize(s); p.Damage = dmg * p.Scale; if (p.Width <= 0 || p.Height <= 0) { p.Break(); } } }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/SlowdownProjectileController.cs ================================================ using BurningKnight.entity.component; using Lens.util.timer; namespace BurningKnight.entity.projectile.controller { public static class SlowdownProjectileController { public static ProjectileCallbacks.UpdateCallback Make(float speed = 1, float time = 1f, float vmin = 0.1f) { var stopped = false; return (p, dt) => { if (stopped) { return; } var b = p.GetAnyComponent(); var v = b.Velocity; b.Velocity -= v * (speed * dt * 2); if (b.Velocity.Length() < vmin) { stopped = true; Timer.Add(() => { p.Break(); }, time); } }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/SmokeProjectileController.cs ================================================ using BurningKnight.assets.particle; using BurningKnight.entity.component; using Lens.util.math; namespace BurningKnight.entity.projectile.controller { public static class SmokeProjectileController { public static ProjectileCallbacks.UpdateCallback Make() { var t = 0f; return (p, dt) => { t += dt; if (t >= 0.1f) { t = 0; var part = new ParticleEntity(Particles.Dust()); p.Area.Add(part); part.Particle.Position = p.Center; part.Particle.Velocity = p.GetAnyComponent().Velocity * -0.2f; part.Particle.Scale = Rnd.Float(0.6f, 0.8f); part.Depth = Layers.Creature; } }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/TargetProjectileController.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using Lens.entity; using Lens.input; using Lens.util; using Lens.util.math; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.controller { public static class TargetProjectileController { public static ProjectileCallbacks.UpdateCallback Make(Entity target, float speed = 1f) { return (p, dt) => { var b = p.GetAnyComponent(); var d = b.Velocity.Length(); var a = b.Velocity.ToAngle(); var from = p.Center; if (p.Owner.TryGetComponent(out var aim)) { from = aim.RealAim; } if (target == null) { var md = 320000f; foreach (var m in (p.Owner.TryGetComponent(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) { if (m.GetComponent().Unhittable) { continue; } var dd = m.DistanceTo(from); if (dd < md) { md = dd; target = m; } } if (target == null) { b.Angle = b.Velocity.ToAngle(); return; } } if (target.Done) { target = null; b.Angle = b.Velocity.ToAngle(); return; } a = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 16 * Math.Max(0.2f, 1 - Math.Min(1, p.DistanceTo(target) / 96))); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); b.Angle = a; }; } public static ProjectileCallbacks.UpdateCallback MakeCursor(float speed = 1f) { return (p, dt) => { var b = p.GetAnyComponent(); var d = b.Velocity.Length(); var a = b.Velocity.ToAngle(); a = (float) MathUtils.LerpAngle(a, p.AngleTo(p.Owner.GetComponent().Cursor.GamePosition) + Rnd.Float(-2, 2), dt * speed * 4); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); b.Angle = a; }; } public static ProjectileCallbacks.UpdateCallback MakeBetter(float speed = 1f) { return (p, dt) => { var b = p.GetAnyComponent(); var d = b.Velocity.Length(); var a = b.Velocity.ToAngle(); Entity target = null; var md = 320000f; var from = p.Center; if (p.Owner.TryGetComponent(out var aim)) { from = aim.RealAim; } foreach (var m in (p.Owner.TryGetComponent(out var c) ? c.Room.Tagged[Tags.Mob] : p.Area.Tagged[Tags.Mob])) { if (m.Done || m.GetComponent().Unhittable) { continue; } var dd = m.DistanceTo(from); if (dd < md) { md = dd; target = m; } } if (target == null) { b.Angle = b.Velocity.ToAngle(); return; } a = (float) MathUtils.LerpAngle(a, p.AngleTo(target), dt * speed * 16 * Math.Max(0.3f, 1 - Math.Min(1, md / 96))); b.Velocity = new Vector2((float) Math.Cos(a) * d, (float) Math.Sin(a) * d); b.Angle = a; }; } } } ================================================ FILE: BurningKnight/entity/projectile/controller/TimedProjectileController.cs ================================================ using System; using BurningKnight.assets.particle.custom; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.controller { public static class TimedProjectileController { public static ProjectileCallbacks.UpdateCallback Make(float time, Action action) { var t = 0f; return (p, dt) => { t += dt; if (t >= time) { t = 0; action(p); } }; } public static ProjectileCallbacks.UpdateCallback MakeFadingParticles(float time, Color tint) { return Make(time, p => { var pr = new FadingParticle(p.GetComponent().Sprite, tint); p.Area.Add(pr); pr.Center = p.Center; }); } } } ================================================ FILE: BurningKnight/entity/projectile/controller/WhatController.cs ================================================ using System; using BurningKnight.entity.component; using Lens.util; namespace BurningKnight.entity.projectile.controller { public static class WhatController { public static ProjectileCallbacks.UpdateCallback Make() { var time = 0f; var i = 0; return (p, dt) => { time += dt; if (time >= 0.3f) { time = 0; i++; var builder = new ProjectileBuilder(p.Owner, "circle"); builder.Shoot(p.GetAnyComponent().Velocity.ToAngle() + i / 4f * (float) Math.PI, 8f); builder.Range = 1f; var projectile = builder.Build(); projectile.Center = p.Center; } }; } } } ================================================ FILE: BurningKnight/entity/projectile/pattern/CircleProjectilePattern.cs ================================================ using System; using BurningKnight.entity.component; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.pattern { public static class CircleProjectilePattern { public static ProjectilePatternController Make(float radius, float speed) { return (p, data, pt, i, dt) => { var angle = pt.T * speed + ((float) i) / pt.Count * Math.PI * 2; p.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius); var body = p.GetAnyComponent()?.Body; if (body != null) { body.Rotation = (float) angle; } }; } } } ================================================ FILE: BurningKnight/entity/projectile/pattern/CircleWithCenterProjectilePattern.cs ================================================ using System; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.pattern { public static class CircleWithCenterProjectilePattern { public static ProjectilePatternController Make(float radius, float speed) { return (p, data, pt, i, dt) => { if (i == 0) { p.Center = pt.Center; return; } var angle = pt.T * speed + ((float) i) / (pt.Count - 1) * Math.PI * 2; p.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius); }; } } } ================================================ FILE: BurningKnight/entity/projectile/pattern/ExpandingCirclePattern.cs ================================================ using System; using Microsoft.Xna.Framework; namespace BurningKnight.entity.projectile.pattern { public static class ExpandingCirclePattern { public static ProjectilePatternController Make(int total, float radius, float speed, float delay, float expansionSpeed, float rotationDelay) { return (p, data, pt, i, dt) => { if (pt.T > delay) { radius += Math.Max(0, Math.Min(1, (pt.T - delay) / delay)) * expansionSpeed * dt; } var angle = Math.Max(0, Math.Min(1, (pt.T) / rotationDelay)) * pt.T * speed + ((float) i) / (total) * Math.PI * 2; p.Center = pt.Center + new Vector2((float) Math.Cos(angle) * radius, (float) Math.Sin(angle) * radius); }; } } } ================================================ FILE: BurningKnight/entity/projectile/pattern/KeepShapePattern.cs ================================================ using Lens.util; namespace BurningKnight.entity.projectile.pattern { public static class KeepShapePattern { public static ProjectilePatternController Make(float speed) { return (p, data, pt, i, dt) => { var angle = pt.T * speed; p.Center = pt.Center + MathUtils.CreateVector(angle + data.Angle, data.Distance); }; } } } ================================================ FILE: BurningKnight/entity/room/Room.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets.items; using BurningKnight.assets.lighting; using BurningKnight.assets.particle.custom; using BurningKnight.entity.bomb; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.door; using BurningKnight.entity.events; using BurningKnight.entity.item; using BurningKnight.entity.projectile; using BurningKnight.entity.room.controllable; using BurningKnight.entity.room.controllable.platform; using BurningKnight.entity.room.controller; using BurningKnight.entity.room.input; using BurningKnight.level; using BurningKnight.level.biome; using BurningKnight.level.entities.chest; using BurningKnight.level.rooms; using BurningKnight.level.rooms.granny; using BurningKnight.level.rooms.oldman; using BurningKnight.level.tile; using BurningKnight.save; using BurningKnight.state; using BurningKnight.ui.editor; using BurningKnight.util; using BurningKnight.util.geometry; using ImGuiNET; using Lens; using Lens.entity; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Lens.util.tween; using Microsoft.Xna.Framework; using MonoGame.Extended; namespace BurningKnight.entity.room { public class Room : SaveableEntity, PlaceableEntity { public int MapX; public int MapY; public int MapW = 4; public int MapH = 4; public TagLists Tagged = new TagLists(); public RoomType Type; public bool Explored; public bool Cleared; public string Id; public RoomDef Parent; public Rect Rect; public List Controllable = new List(); public List Inputs = new List(); public List Pistons = new List(); public List Controllers = new List(); public List Doors = new List(); private bool checkCleared; private Entity cleared; private float t; public void CheckCleared(Entity entity) { if (!Cleared) { Timer.Add(() => { checkCleared = true; cleared = entity; }, 0.1f); } } public override void AddComponents() { base.AddComponents(); AddTag(Tags.Room); } public ItemPool GetPool() { switch (Type) { case RoomType.Shop: return ItemPool.Shop; case RoomType.Secret: return ItemPool.Secret; case RoomType.Boss: return ItemPool.Boss; case RoomType.Treasure: return ItemPool.Treasure; } return null; } public override void PostInit() { base.PostInit(); UpdateSize(); AlwaysActive = true; if (Type == RoomType.Shop || Type == RoomType.Treasure || Type == RoomType.Boss) { AddComponent(new LightComponent(this, 128f, new Color(1f, 0.9f, 0.5f, 0.8f))); } } public void UpdateSize() { X = MapX * 16 + 4; Y = MapY * 16 - 4; Width = MapW * 16 - 8; Height = MapH * 16 - 8; Rect = new Rect().Setup(MapX, MapY, MapW, MapH); } public override void Update(float dt) { base.Update(dt); t += dt; if (!settedUp && t >= 0.1f) { settedUp = true; Setup(); if (!Engine.EditingLevel && Type == RoomType.Hidden) { Hide(true); } } foreach (var c in Controllers) { c.Update(dt); } if (checkCleared) { var found = false; foreach (var m in Tagged[Tags.MustBeKilled]) { if (m.GetComponent().Health > 0) { found = true; break; } } if (!found) { if (!Cleared) { SpawnReward(); Cleared = true; cleared.HandleEvent(new RoomClearedEvent { Room = this }); } } checkCleared = false; } } private static string[] rewards = { // "bk:copper_coin", "bk:key", "bk:key", "bk:bomb", "bk:bomb", "bk:troll_bomb", // "bk:heart", // "bk:heart", "bk:pouch", "bk:copper_coin" }; private Entity CreateReward() { if (Rnd.Chance(LevelSave.ChestRewardChance)) { return ChestRegistry.PlaceRandom(Vector2.Zero, Area); } var id = rewards[Rnd.Int(rewards.Length)]; if (id == "bk:troll_bomb") { var bomb = new Bomb(null); Area.Add(bomb); return bomb; } return Items.CreateAndAdd(id, Area); } private void SpawnReward() { if (Run.Depth < 1 || Type != RoomType.Regular || Rnd.Chance(40 - Run.Luck)) { return; } foreach (var e in Tagged[Tags.LevelSave]) { if (e is MovingPlatform) { // To avoid it getting stuck return; } } var where = new Dot(MapX + MapW / 2, MapY + MapH / 2); for (var x = -1; x < 2; x++) { for (var y = -1; y < 2; y++) { var x1 = x; var y1 = y; Timer.Add(() => { var part = new TileParticle(); part.Top = Run.Level.Tileset.FloorD[0]; part.TopTarget = Run.Level.Tileset.WallTopADecor; part.Side = Run.Level.Tileset.FloorSidesD[0]; part.Sides = Run.Level.Tileset.WallSidesA[2]; part.Tile = Tile.FloorD; part.X = (where.X + x1) * 16; part.Y = (where.Y + y1) * 16 + 8; part.Target.X = (where.X + x1) * 16; part.Target.Y = (where.Y + y1) * 16 + 8; part.TargetZ = -8f; Area.Add(part); }, Rnd.Float(1f)); } } Timer.Add(() => { var reward = CreateReward(); reward.BottomCenter = where * 16 + new Vector2(8, 24); AnimationUtil.Poof(reward.Center); }, 1.5f); } private bool settedUp; private void Setup() { var level = Run.Level; Explored = level.Explored[level.ToIndex(MapX + 1, MapY + 1)]; ApplyToEachTile((x, y) => { var tile = level.Get(x, y); if (tile.Matches(Tile.Piston, Tile.PistonDown)) { Pistons.Add(new Piston(x, y)); } }); foreach (var c in Controllers) { c.Init(); } } public override void Destroy() { base.Destroy(); foreach (var c in Controllers) { c.Destroy(); } Pistons.Clear(); Controllable.Clear(); Inputs.Clear(); } public void Discover() { Explored = true; ApplyToEachTile((x, y) => { Run.Level.Explored[Run.Level.ToIndex(x, y)] = true; }); } public void Hide(bool fast = false) { Explored = false; ApplyToEachTile((x, y) => { var i = Run.Level.ToIndex(x, y); if (!Run.Level.Get(i).IsWall() || !Run.Level.Get(i + Run.Level.Width).IsWall()) { Run.Level.Explored[i] = false; if (fast) { Run.Level.Light[i] = 0; } else { Tween.To(0, 1f, xx => Run.Level.Light[i] = xx, 0.5f); } } }, Type == RoomType.DarkMarket || Type == RoomType.Hidden ? 1 : 0); } public void ApplyToEachTile(Action callback, int offset = 0) { var level = Run.Level; for (int y = MapY + offset; y < MapY + MapH - 1 - offset; y++) { for (int x = MapX + offset; x < MapX + MapW - offset; x++) { if (level.IsInside(x, y)) { callback(x, y); } } } } public void Generate() { foreach (var c in Controllers) { c.Generate(); } } public override void Load(FileReader stream) { base.Load(stream); MapX = stream.ReadInt16(); MapY = stream.ReadInt16(); MapW = stream.ReadInt16(); MapH = stream.ReadInt16(); Type = RoomRegistry.FromIndex(stream.ReadByte()); var count = stream.ReadByte(); for (var i = 0; i < count; i++) { var c = RoomControllerRegistery.Get(stream.ReadString()); if (c != null) { Controllers.Add(c); c.Room = this; c.Load(stream); } } Id = stream.ReadString(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteInt16((short) MapX); stream.WriteInt16((short) MapY); stream.WriteInt16((short) MapW); stream.WriteInt16((short) MapH); stream.WriteByte((byte) RoomRegistry.FromType(Type)); stream.WriteByte((byte) Controllers.Count); foreach (var c in Controllers) { stream.WriteString(c.Id); c.Save(stream); } stream.WriteString(Id); } protected int GetRenderLeft(Camera camera, Level level) { return (int) MathUtils.Clamp(0, level.Width - 1, Math.Max((int) Math.Floor(camera.X / 16 - 1f), MapX)); } protected int GetRenderTop(Camera camera, Level level) { return (int) MathUtils.Clamp(0, level.Height - 1, Math.Max((int) Math.Floor(camera.Y / 16 - 1f), MapY)); } protected int GetRenderRight(Camera camera, Level level) { return (int) MathUtils.Clamp(0, level.Width - 1, Math.Min((int) Math.Ceiling(camera.Right / 16 + 1f), MapX + MapW)); } protected int GetRenderBottom(Camera camera, Level level) { return (int) MathUtils.Clamp(0, level.Height - 1, Math.Min((int) Math.Ceiling(camera.Bottom / 16 + 1f), MapY + MapH)); } public override void RenderDebug() { Graphics.Batch.DrawRectangle(new RectangleF(X, Y, Width, Height), Color.Red); } public override void RenderImDebug() { var v = (int) Type; if (ImGui.Combo("Type", ref v, RoomRegistry.Names, RoomRegistry.Names.Length)) { Type = (RoomType) v; } if (Id == null) { Id = ""; } ImGui.InputText("Id", ref Id, 128); ImGui.Separator(); ImGui.InputInt("Map X", ref MapX); ImGui.InputInt("Map Y", ref MapY); ImGui.InputInt("Map W", ref MapW); ImGui.InputInt("Map H", ref MapH); if (Id == null) { Id = ""; } ImGui.Text($"Doors: {Doors.Count}"); X = MapX * 16 + 4; Y = MapY * 16 - 4; Width = MapW * 16 - 8; Height = MapH * 16 - 8; /*if (ImGui.Button("Sync")) { MapX = (int) Math.Floor(X / 16); MapY = (int) Math.Floor(Y / 16); MapW = (int) Math.Floor(Width / 16); MapH = (int) Math.Floor(Height / 16); }*/ } public List GetFreeTiles(Func filter = null) { var list = new List(); for (var x = MapX + 1; x < MapX + MapW - 1; x++) { for (var y = MapY + 1; y < MapY + MapH - 1; y++) { if (Run.Level.IsPassable(x, y) && (filter == null || filter(x, y))) { list.Add(new Point(x, y)); } } } return list; } public Vector2 GetRandomFreeTile(Func filter = null) { var tiles = GetFreeTiles(filter); if (tiles.Count == 0) { return Center; } var tile = tiles[Rnd.Int(tiles.Count)]; return new Vector2(tile.X, tile.Y); } public Vector2 GetRandomFreeTileNearWall(Func filter = null) { return GetRandomFreeTile((x, y) => { if (Run.Level.CheckFor(x - 1, y, TileFlags.Passable) && Run.Level.CheckFor(x + 1, y, TileFlags.Passable) && Run.Level.CheckFor(x, y - 1, TileFlags.Passable) && Run.Level.CheckFor(x, y + 1, TileFlags.Passable)) { // No wall here :/ return false; } return filter == null || filter(x, y); }); } public Vector2 GetRandomWallFreeTile(Func filter = null) { return GetRandomFreeTile((x, y) => { if (!Run.Level.CheckFor(x - 1, y, TileFlags.Passable) || !Run.Level.CheckFor(x + 1, y, TileFlags.Passable) || !Run.Level.CheckFor(x, y - 1, TileFlags.Passable) || !Run.Level.CheckFor(x, y + 1, TileFlags.Passable)) { // Wall here :/ return false; } return filter == null || filter(x, y); }); } public void AddController(string id) { var c = RoomControllerRegistery.Get(id); if (c != null) { Controllers.Add(c); c.Room = this; c.Init(); } } public void HandleInputChange(RoomInput.ChangedEvent e) { foreach (var c in Controllers) { c.HandleInputChange(e); } } public Entity FindClosest(Vector2 to, int tag, Func filter = null) { var min = float.MaxValue; Entity en = null; foreach (var e in Tagged[tag]) { if (filter?.Invoke(e) ?? true) { var d = e.DistanceTo(to); if (d < min) { min = d; en = e; } } } return en; } public void OpenHiddenDoors() { var level = Run.Level; foreach (var door in Doors) { var x = (int) Math.Floor(door.CenterX / 16); var y = (int) Math.Floor(door.CenterY / 16); var t = level.Get(x, y); if (t == Tile.WallA || t == Tile.WallB) { var index = level.ToIndex(x, y); level.Set(index, Type == RoomType.OldMan ? Tile.EvilFloor : Tile.GrannyFloor); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); level.LoadPassable(); ExplosionMaker.LightUp(x * 16 + 8, y * 16 + 8); Level.Animate(Area, x, y); } } } public void CloseHiddenDoors() { var level = Run.Level; foreach (var door in Doors) { var x = (int) Math.Floor(door.CenterX / 16); var y = (int) Math.Floor(door.Bottom / 16); var t = level.Get(x, y); if (level.Get(x, y).Matches(TileFlags.Passable)) { var index = level.ToIndex(x, y); level.Set(index, level.Biome is IceBiome ? Tile.WallB : Tile.WallA); level.UpdateTile(x, y); level.ReCreateBodyChunk(x, y); level.LoadPassable(); Hide(); Camera.Instance.Shake(10); } } } public void PaintTunnel(List Doors, Tile Floor, Rect space = null, bool Bold = false, bool shift = true, bool randomRect = true) { if (Doors.Count == 0) { return; } var Level = Run.Level; var C = space; if (C == null) { var c = new Dot(MapX + MapW /2, MapY + MapH / 2); C = new Rect(c.X, c.Y, c.X, c.Y); } var minLeft = C.Left; var maxRight = C.Right; var minTop = C.Top; var maxBottom = C.Bottom; var Right = MapX + MapW - 1; var Bottom = MapY + MapH - 1; Painter.Clip = new Rect(MapX, MapY, MapX + MapW - 1, MapY + MapH - 1); foreach (var Door in Doors) { var dx = (int) Math.Floor(Door.CenterX / 16f); var dy = (int) Math.Floor(Door.CenterY / 16f); var Start = new Dot(dx, dy); Dot Mid; Dot End; if (shift) { if ((int) Start.X == MapX) { Start.X++; } else if ((int) Start.Y == MapY) { Start.Y++; } else if ((int) Start.X == Right) { Start.X--; } else if ((int) Start.Y == Bottom) { Start.Y--; } } int RightShift; int DownShift; if (Start.X < C.Left) { RightShift = (int) (C.Left - Start.X); } else if (Start.X > C.Right) { RightShift = (int) (C.Right - Start.X); } else { RightShift = 0; } if (Start.Y < C.Top) { DownShift = (int) (C.Top - Start.Y); } else if (Start.Y > C.Bottom) { DownShift = (int) (C.Bottom - Start.Y); } else { DownShift = 0; } if (dx == MapX || dx == Right) { Mid = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Start.X + RightShift), MathUtils.Clamp(MapY + 1, Bottom - 1, Start.Y)); End = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Mid.X), MathUtils.Clamp(MapY + 1, Bottom - 1, Mid.Y + DownShift)); } else { Mid = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Start.X), MathUtils.Clamp(MapY + 1, Bottom - 1, Start.Y + DownShift)); End = new Dot(MathUtils.Clamp(MapX + 1, Right - 1, Mid.X + RightShift), MathUtils.Clamp(MapY + 1, Bottom - 1, Mid.Y)); } Painter.DrawLine(Level, Start, Mid, Floor, Bold); Painter.DrawLine(Level, Mid, End, Floor, Bold); if (Rnd.Chance(10)) { Painter.Set(Level, End, Tiles.RandomFloor()); } minLeft = Math.Min(minLeft, End.X); minTop = Math.Min(minTop, End.Y); maxRight = Math.Max(maxRight, End.X); maxBottom = Math.Max(maxBottom, End.Y); } if (randomRect && Rnd.Chance(20)) { if (Rnd.Chance()) { minLeft--; } if (Rnd.Chance()) { minTop--; } if (Rnd.Chance()) { maxRight++; } if (Rnd.Chance()) { maxBottom++; } } minLeft = MathUtils.Clamp(MapX + 1, Right - 1, minLeft); minTop = MathUtils.Clamp(MapY + 1, Bottom - 1, minTop); maxRight = MathUtils.Clamp(MapX + 1, Right - 1, maxRight); maxBottom = MathUtils.Clamp(MapY + 1, Bottom - 1, maxBottom); if (Rnd.Chance()) { Painter.Fill(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloor()); } else { Painter.Rect(Level, minLeft, minTop, maxRight - minLeft + 1, maxBottom - minTop + 1, Rnd.Chance() ? Floor : Tiles.RandomFloor()); } Painter.Clip = null; } public bool ContainsTile(int x, int y, int d = 0) { return x >= MapX + d && x < MapX + MapW - d && y >= MapY + d - 1 && y < MapY + MapH - d; } } } ================================================ FILE: BurningKnight/entity/room/controllable/AlwaysOnSpikes.cs ================================================ using BurningKnight.entity.room.controllable.spikes; using Lens.entity.component.logic; namespace BurningKnight.entity.room.controllable { public class AlwaysOnSpikes : Spikes { protected override void InitState() { On = true; GetComponent().Become(); } } } ================================================ FILE: BurningKnight/entity/room/controllable/FireTrap.cs ================================================ using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.particle.custom; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.level.entities; using Lens.entity; using Lens.graphics; using Lens.util.math; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable { public class FireTrap : RoomControllable { private static TextureRegion tile; private float timer; private bool flaming; private float lastParticle; protected List Colliding = new List(); public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Depth = Layers.Entrance; if (tile == null) { tile = CommonAse.Props.GetSlice("firetrap"); } AddComponent(new RectBodyComponent(1, 1, 11, 14, BodyType.Static, true)); } public override void PostInit() { base.PostInit(); ResetTimer(); } private void ResetTimer() { timer = X / 256f * 5f % 5f; } public override void Update(float dt) { base.Update(dt); if (!On) { ResetTimer(); return; } else { var room = GetComponent().Room; if (room.Tagged[Tags.Player].Count == 0 || room.Tagged[Tags.MustBeKilled].Count == 0) { ResetTimer(); return; } } timer += dt; if (flaming) { if (timer <= 0.3f) { lastParticle -= dt; if (lastParticle <= 0) { lastParticle = 0.1f; Area.Add(new FireParticle { Position = new Vector2(CenterX, CenterY), XChange = 0.1f, Scale = 0.3f, Vy = 8, Mod = 2 }); } } else if (timer >= 1.5f) { lastParticle -= dt; Hurt(); if (lastParticle <= 0) { lastParticle = 0.15f; Area.Add(new FireParticle { Position = new Vector2(CenterX, CenterY), XChange = 0.1f, Scale = 0.3f, Vy = 8, Mod = 4 }); } if (timer >= 5f) { timer = 0; flaming = false; } } } else { if (timer >= 5f) { timer = 0; flaming = true; lastParticle = 0; } } } public override void Render() { Graphics.Render(tile, Position); } protected virtual bool ShouldHurt(Entity e) { return e is Player; } protected void Hurt() { foreach (var c in Colliding) { c.GetComponent().ModifyHealth(-1, this); } } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (ShouldHurt(cse.Entity)) { Colliding.Add(cse.Entity); } } else if (e is CollisionEndedEvent cee) { Colliding.Remove(cee.Entity); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/room/controllable/Piston.cs ================================================ using BurningKnight.level.tile; using BurningKnight.state; namespace BurningKnight.entity.room.controllable { public class Piston { public readonly int X; public readonly int Y; public Piston(int x, int y) { X = x; Y = y; } public bool IsOn() { return Run.Level.Get(X, Y) == Tile.Piston; } public void Set(bool value) { if (IsOn() != value) { Run.Level.Set(X, Y, value ? Tile.Piston : Tile.PistonDown); Run.Level.ReCreateBodyChunk(X, Y); Run.Level.UpdateTile(X, Y); } } public void Toggle() { Set(!IsOn()); } } } ================================================ FILE: BurningKnight/entity/room/controllable/RollingSpike.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using Lens.entity; using Lens.util; using Lens.util.file; using Microsoft.Xna.Framework; namespace BurningKnight.entity.room.controllable { public class RollingSpike : RoomControllable, CollisionFilterEntity { public Vector2 StartVelocity = new Vector2(32, 0); private List colliding = new List(); public override void AddComponents() { base.AddComponents(); var b = new CircleBodyComponent(0, 0, 8); AddComponent(b); b.Body.Restitution = 1; b.Body.Friction = 0; b.Body.Mass = 100000f; var a = new AnimationComponent("rolling_spike"); AddComponent(a); AlwaysActive = true; a.OriginY *= 0.5f; AddComponent(new ShadowComponent()); } public override void Save(FileWriter stream) { base.Save(stream); var v = GetComponent().Velocity; stream.WriteFloat(v.X); stream.WriteFloat(v.Y); } public override void Load(FileReader stream) { base.Load(stream); StartVelocity = GetComponent().Velocity = new Vector2(stream.ReadFloat(), stream.ReadFloat()); } public override void PostInit() { base.PostInit(); GetComponent().Velocity = StartVelocity; } public override void Update(float dt) { base.Update(dt); foreach (var p in colliding) { p.GetComponent().ModifyHealth(-1, this); p.GetAnyComponent()?.KnockbackFrom(this, 4); } var velocity = GetComponent().Velocity; var a = velocity.ToAngle(); var l = velocity.Length(); if (Math.Abs(a % (Math.PI * 0.5f)) >= 0.1f || l < 20) { a = (float) (Math.Floor(a / (Math.PI * 0.5f)) * (Math.PI * 0.5f)); GetComponent().Velocity = MathUtils.CreateVector(a, Math.Max(l, 32)); } GetComponent().Angle += Math.Sign(Math.Abs(velocity.X) > 0.1f ? velocity.X : velocity.Y) * dt * 10; } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { var n = ev.Entity; if (!(n is Prop) && !(n is Level) && !(n is Chasm) && !(n is RollingSpike)) { if (n is Player p) { colliding.Add(p); } } } else if (e is CollisionEndedEvent cee && cee.Entity is Player p) { colliding.Remove(p); } return base.HandleEvent(e); } public bool ShouldCollide(Entity entity) { // fixme: do not hurt return !(entity is Projectile || entity is RollingSpike || (entity is Creature)); } } } ================================================ FILE: BurningKnight/entity/room/controllable/RoomControllable.cs ================================================ using BurningKnight.entity.component; using BurningKnight.save; using BurningKnight.ui.editor; using ImGuiNET; namespace BurningKnight.entity.room.controllable { public class RoomControllable : SaveableEntity, PlaceableEntity { public override void AddComponents() { base.AddComponents(); AddComponent(new RoomComponent()); AddComponent(new SupportableComponent()); } public bool On { get; protected set; } = true; public virtual void TurnOn() { On = true; } public virtual void TurnOff() { On = false; } public void SetState(bool on) { if (on != On) { Toggle(); } } public void Toggle() { if (On) { TurnOff(); } else { TurnOn(); } } private bool added; public override void Update(float dt) { base.Update(dt); if (!added) { var room = GetComponent().Room; if (room == null) { return; } added = true; room.Controllable.Add(this); } } protected void RemoveFromRoom() { GetComponent().Room?.Controllable.Remove(this); } public override void RenderImDebug() { base.RenderImDebug(); var on = On; if (ImGui.Checkbox("On", ref on)) { if (on) { TurnOn(); } else { TurnOff(); } } } } } ================================================ FILE: BurningKnight/entity/room/controllable/Support.cs ================================================ using System.Collections.Generic; using Lens.entity; namespace BurningKnight.entity.room.controllable { public class Support : RoomControllable { public List Supporting = new List(); public virtual void Apply(Entity e, float dt) { } public class StartedSupportingEvent : Event { public Support Support; public Entity Entity; } public class EndedSupportingEvent : Event { public Support Support; public Entity Entity; } } } ================================================ FILE: BurningKnight/entity/room/controllable/platform/MovingPlatform.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.level.tile; using BurningKnight.physics; using BurningKnight.state; using BurningKnight.util.geometry; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Lens.util; using Lens.util.camera; using Lens.util.file; using Lens.util.math; using Microsoft.Xna.Framework; using MonoGame.Extended; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable.platform { public class MovingPlatform : Platform, CollisionFilterEntity { protected byte tw = 2; protected byte th = 2; public PlatformController Controller = PlatformController.LeftRight; public int StartingStep; private int step; private Vector2 velocity; private PlatformBorder left; private PlatformBorder right; private PlatformBorder up; private PlatformBorder down; protected virtual string GetAnimation() { return "moving_platform"; } public override void AddComponents() { base.AddComponents(); Width = tw * 16; Height = th * 16 + 6; On = true; AddComponent(new StateComponent()); AddComponent(new AnimationComponent(GetAnimation())); var w = tw * 16; var h = th * 16; var b = new RectBodyComponent(0.5f, 0.5f - 1, w - 1, h + 3); AddComponent(b); b.Body.Friction = 0; Area.Add(left = new PlatformBorder()); left.Setup(this, -12, 0, 8, th * 16); Area.Add(right = new PlatformBorder()); right.Setup(this, tw * 16 + 4, 0, 8, th * 16); Area.Add(up = new PlatformBorder()); up.Setup(this, 0, -8, tw * 16, 8); Area.Add(down = new PlatformBorder()); down.Setup(this, 0, th * 16 + 1, tw * 16, 8); } public override void PostInit() { base.PostInit(); step = StartingStep; Stop(); } protected override bool ShouldMove(Entity e) { return base.ShouldMove(e) && e.Bottom < Bottom - 4; } protected void ResetBorders() { left.On = true; right.On = true; up.On = true; down.On = true; } protected void RoundUp() { var x = ((int) Math.Round(X / 16)) * 16; var y = ((int) Math.Round(Y / 16)) * 16; if (MathUtils.Distance(X - x, Y - y) < 3) { X = x; Y = y; } } #region Platform States protected class IdleState : SmartState { private const float Delay = 1f; public override void Update(float dt) { base.Update(dt); Self.GetComponent().Velocity = Vector2.Zero; if (Self.On && T >= Delay) { Become(); } } } protected class MovingState : SmartState { private const float Speed = 48; private bool first = true; public override void Init() { base.Init(); Self.ResetBorders(); Self.Center -= Self.velocity * 0.1f; } public override void Update(float dt) { base.Update(dt); if (Math.Abs(Self.velocity.X) + Math.Abs(Self.velocity.Y) < 0.1f) { Self.velocity = directions[Rnd.Int(2) + 2]; } if (Math.Abs(Self.velocity.X) > 0.1f && Math.Abs(Self.velocity.Y) > 0.1f) { Self.velocity.Y = 0; } Self.GetComponent().Velocity = Self.velocity * Speed; if (Math.Abs(Self.velocity.X) > 0.1f) { var s = (int) Math.Round(Self.Y / 16); var x = (int) (Self.velocity.X > 0 ? (Math.Ceiling(Self.X / 16) + Self.tw - 1) : (Math.Floor(Self.X / 16))); for (var y = s; y < s + Self.th; y++) { var t = Run.Level.Get(x, y); if (t != Tile.Chasm) { Self.RoundUp(); Self.ResetBorders(); if (Self.velocity.X > 0) { Self.right.On = false; } else { Self.left.On = false; } Self.Stop(); if (first) { Become(); } break; } } } else { var s = (int) Math.Round(Self.X / 16); var y = (int) (Self.velocity.Y > 0 ? (Math.Ceiling(Self.Y / 16) + Self.th - 1) : (Math.Floor(Self.Y / 16))); for (var x = s; x < s + Self.tw; x++) { var t = Run.Level.Get(x, y); if (t != Tile.Chasm) { Self.RoundUp(); Self.ResetBorders(); if (Self.velocity.Y > 0) { Self.down.On = false; } else { Self.up.On = false; } Self.Stop(); if (first) { Become(); } break; } } } first = false; } public override void Destroy() { base.Destroy(); Self.GetComponent().Velocity = Vector2.Zero; } } #endregion private static Vector2[] directions = { new Vector2(1, 0), new Vector2(0, 1), new Vector2(-1, 0), new Vector2(0, -1) }; protected virtual void Stop() { GetComponent().Become(); step++; switch (Controller) { case PlatformController.LeftRight: default: { step %= 2; if (Math.Abs(velocity.X) < 0.1f) { velocity = directions[0]; } velocity.X *= -1; break; } case PlatformController.UpDown: { step %= 2; if (Math.Abs(velocity.Y) < 0.1f) { velocity = directions[1]; } velocity.Y *= -1; break; } case PlatformController.ClockWise: { step %= 4; velocity = directions[step]; break; } case PlatformController.CounterClockWise: { step %= 4; velocity = directions[3 - step]; break; } } if (OnScreen) { Camera.Instance.ShakeMax(4); } } public override void TurnOn() { base.TurnOn(); GetComponent().Become(); } public override void TurnOff() { base.TurnOff(); GetComponent().Become(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte((byte) Controller); stream.WriteByte((byte) StartingStep); } public override void Load(FileReader stream) { base.Load(stream); Controller = (PlatformController) stream.ReadByte(); StartingStep = stream.ReadByte(); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent ev) { if (ev.Entity is MovingPlatform m) { var rect = new Rectangle((int) X, (int) Y, (int) Width, (int) Height - 6); rect.X += (int) (velocity.X * Width); rect.Y += (int) (velocity.Y * (Height - 6)); if (new Rectangle((int) m.X, (int) m.Y, (int) m.Width, (int) m.Height - 6).Intersects(rect)) { Stop(); } } } return base.HandleEvent(e); } bool CollisionFilterEntity.ShouldCollide(Entity entity) { return entity is MovingPlatform; } } } ================================================ FILE: BurningKnight/entity/room/controllable/platform/Platform.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.save; using Lens.entity; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable.platform { public class Platform : Support { private Vector2 startingPoint; public override void PostInit() { base.PostInit(); Depth = -11; AlwaysActive = true; startingPoint = Position; } public override void AddComponents() { base.AddComponents(); RemoveComponent(); } public override void Load(FileReader stream) { base.Load(stream); startingPoint = new Vector2(stream.ReadInt32(), stream.ReadInt32()); Position = startingPoint; } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteInt32((int) startingPoint.X); stream.WriteInt32((int) startingPoint.Y); } public override void Apply(Entity e, float dt) { var b = e.GetAnyComponent(); if (b == null || !ShouldMove(e)) { return; } base.Apply(e, dt); b.Position += GetComponent().Velocity * dt; } protected virtual bool ShouldMove(Entity e) { return !(e is Creature c && c.InAir()); } } } ================================================ FILE: BurningKnight/entity/room/controllable/platform/PlatformBorder.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.entities; using BurningKnight.physics; using Lens.entity; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable.platform { public class PlatformBorder : Entity, CollisionFilterEntity { public Support Super; public Vector2 Offset; private bool on = true; public bool On { set { on = value; GetComponent().Body.IsSensor = !value; } } public void Setup(Support super, int x, int y, int w, int h) { Super = super; Offset = new Vector2(x, y); AlwaysActive = true; AddComponent(new RectBodyComponent(0, 0, w, h, BodyType.Static)); } public override void Update(float dt) { base.Update(dt); if (Super == null) { return; } if (Super.Done) { Done = true; return; } Position = Offset + Super.Position; } public bool ShouldCollide(Entity entity) { if (!on) { return false; } return !( entity is Prop || entity is Projectile || entity is Level || entity is Chasm || (entity is Creature c && c.InAir()) || (entity.TryGetComponent(out var t) && (!t.HasNoTileSupport)) || (entity.TryGetComponent(out var s) && s.HasAnotherSupportBesides(Super)) ); } } } ================================================ FILE: BurningKnight/entity/room/controllable/platform/PlatformController.cs ================================================ namespace BurningKnight.entity.room.controllable.platform { public enum PlatformController { LeftRight, UpDown, ClockWise, CounterClockWise } } ================================================ FILE: BurningKnight/entity/room/controllable/platform/SteppingPlatform.cs ================================================ using Lens.entity; namespace BurningKnight.entity.room.controllable.platform { public class SteppingPlatform : MovingPlatform { public override void Init() { base.Init(); On = false; } protected override string GetAnimation() { return "stepping_platform"; } public override bool HandleEvent(Event e) { if (e is StartedSupportingEvent) { if (!On) { TurnOn(); } } else if (e is EndedSupportingEvent) { if (On && Supporting.Count == 0) { TurnOff(); } } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/room/controllable/spikes/SensingSpikes.cs ================================================ using BurningKnight.assets.achievements; using BurningKnight.entity.creature.player; using BurningKnight.state; namespace BurningKnight.entity.room.controllable.spikes { public class SensingSpikes : Spikes { private float timer; private bool wasTriggered; public override void Update(float dt) { base.Update(dt); if (timer > 0) { timer -= dt; if (timer <= 0) { TurnOff(); } } else if (!On && Colliding.Count > 0) { foreach (var c in Colliding) { if (c is Player) { timer = 1.5f; TurnOnSlowly(); if (!wasTriggered) { wasTriggered = true; if (Run.Statistics != null) { Run.Statistics.SpikesTriggered++; if (Run.Statistics.SpikesTriggered >= 100) { Achievements.Unlock("bk:spikes"); } } } break; } } } } } } ================================================ FILE: BurningKnight/entity/room/controllable/spikes/Spikes.cs ================================================ using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.events; using BurningKnight.level.entities; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.graphics; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable.spikes { public class Spikes : RoomControllable { private static TextureRegion tile; private static Vector2 offset = new Vector2(0, 5); protected List Colliding = new List(); public override void Init() { base.Init(); InitState(); Y -= offset.Y; } protected virtual void InitState() { On = false; } public override void AddComponents() { base.AddComponents(); AlwaysActive = true; Height = 21; if (tile == null) { tile = CommonAse.Props.GetSlice("spikes_base"); } Area.Add(new RenderTrigger(this, RenderBase, Layers.Entrance)); AddComponent(new StateComponent()); AddComponent(new AnimationComponent("spikes")); AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new AudioEmitterComponent()); AddComponent(new RectBodyComponent(3, 5, 10, 10, BodyType.Static, true)); GetComponent().Become(); } private void RenderBase() { Graphics.Render(tile, Position + offset); } private void RenderShadow() { GraphicsComponent.Offset.Y -= 7; GraphicsComponent.Render(true); GraphicsComponent.Offset.Y += 7; } public override void TurnOn() { base.TurnOn(); var s = GetComponent(); if (s.StateInstance is HiddenState || s.StateInstance is HidingState) { s.Become(); } } public void TurnOnSlowly() { if (On) { return; } On = true; var s = GetComponent(); if (s.StateInstance is HiddenState || s.StateInstance is HidingState) { s.Become(); } } public override void TurnOff() { base.TurnOff(); var s = GetComponent(); if (s.StateInstance is IdleState || s.StateInstance is ShowingState || s.StateInstance is FshowingState) { s.Become(); } } protected void Hurt() { foreach (var c in Colliding) { if (!(c is Creature cc && cc.InAir()) || c is ExplodingBarrel) { c.GetComponent().ModifyHealth(-1, this); } } } #region Spike States protected class IdleState : SmartState { public override void Update(float dt) { base.Update(dt); Self.Hurt(); } } protected class HiddenState : SmartState { } protected class ShowingState : SmartState { public override void Init() { base.Init(); if (Self.OnScreen) { Self.GetComponent().Emit("level_spike", 1f - Audio.Db3); } Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); var a = Self.GetComponent().Animation; if (a.Frame > 3) { Self.Hurt(); } if (a.Paused) { Self.GetComponent().Become(); } } } protected class FshowingState : SmartState { private bool playedSfx; public override void Init() { base.Init(); Self.GetComponent().Emit("level_spike_peaking"); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); var a = Self.GetComponent().Animation; if (a.Frame > 2) { Self.Hurt(); if (!playedSfx) { playedSfx = true; if (Self.OnScreen) { Self.GetComponent().EmitRandomized("level_spike"); } } } if (a.Paused) { Self.GetComponent().Become(); } } } protected class HidingState : SmartState { public override void Init() { base.Init(); Self.GetComponent().SetAutoStop(true); } public override void Destroy() { base.Destroy(); Self.GetComponent().SetAutoStop(false); } public override void Update(float dt) { base.Update(dt); var a = Self.GetComponent().Animation; if (a.Frame < 2) { Self.Hurt(); } if (a.Paused) { Self.GetComponent().Become(); } } } #endregion protected virtual bool ShouldHurt(Entity e) { return e.HasComponent(); } public override bool HandleEvent(Event e) { if (e is CollisionStartedEvent cse) { if (ShouldHurt(cse.Entity)) { Colliding.Add(cse.Entity); } } else if (e is CollisionEndedEvent cee) { Colliding.Remove(cee.Entity); } return base.HandleEvent(e); } } } ================================================ FILE: BurningKnight/entity/room/controllable/turret/QuadRotatingTurret.cs ================================================ namespace BurningKnight.entity.room.controllable.turret { public class QuadRotatingTurret : QuadTurret { public override void Init() { base.Init(); Rotates = true; } } } ================================================ FILE: BurningKnight/entity/room/controllable/turret/QuadTurret.cs ================================================ using System; using BurningKnight.entity.component; namespace BurningKnight.entity.room.controllable.turret { public class QuadTurret : Turret { public override void AddComponents() { base.AddComponents(); var a = GetComponent(); a.Animation.Tag = "four"; a.Animation.Paused = true; } protected override void Fire(double angle) { for (var i = 0; i < 4; i++) { SendProjectile(angle + i * Math.PI / 2f); } } } } ================================================ FILE: BurningKnight/entity/room/controllable/turret/RotatingTurret.cs ================================================ namespace BurningKnight.entity.room.controllable.turret { public class RotatingTurret : Turret { public override void Init() { base.Init(); Rotates = true; } } } ================================================ FILE: BurningKnight/entity/room/controllable/turret/Turret.cs ================================================ using System; using BurningKnight.entity.component; using BurningKnight.entity.events; using BurningKnight.entity.projectile; using BurningKnight.level; using BurningKnight.level.rooms; using BurningKnight.physics; using BurningKnight.state; using BurningKnight.util; using ImGuiNET; using Lens.entity; using Lens.util; using Lens.util.file; using Lens.util.tween; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.controllable.turret { public class Turret : RoomControllable, CollisionFilterEntity { private float beforeNextBullet; protected bool Rotates; protected uint Angle { get => GetComponent().Animation.Frame; set => GetComponent().Animation.Frame = value; } public uint StartingAngle; public bool ReverseDirection; public float TimingOffset; public float Speed = 1f; public override void Init() { Y -= 4; base.Init(); } public override void AddComponents() { base.AddComponents(); AddComponent(new RectBodyComponent(3, 4, 10, 11, BodyType.Static)); var a = new AnimationComponent("turret", "on"); AddComponent(a); a.Animation.Tag = "single"; a.Animation.Paused = true; a.ShadowOffset = 4; AddComponent(new ShadowComponent(RenderShadow)); AddComponent(new ExplodableComponent()); AddComponent(new AudioEmitterComponent()); AlwaysActive = true; if (Run.Depth == -2) { On = false; } } public override bool HandleEvent(Event e) { if (e is ExplodedEvent) { Done = true; RemoveFromRoom(); } return base.HandleEvent(e); } public override void Load(FileReader stream) { base.Load(stream); StartingAngle = stream.ReadByte(); ReverseDirection = stream.ReadBoolean(); TimingOffset = stream.ReadFloat(); Speed = stream.ReadFloat(); if (Math.Abs(Speed) < 0.01f) { Speed = 1f; } if (Run.Depth == -2 || Run.Depth == Run.ContentEndDepth) { TimingOffset = 0; beforeNextBullet = 0; } } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte((byte) StartingAngle); stream.WriteBoolean(ReverseDirection); stream.WriteFloat(TimingOffset); stream.WriteFloat(Speed); } public override void PostInit() { base.PostInit(); Angle = StartingAngle; if (Run.Depth == Run.ContentEndDepth) { Speed = 2.5f; TimingOffset = 0; } } public override void TurnOn() { base.TurnOn(); beforeNextBullet = 0.2f + TimingOffset % 3; var a = GetComponent(); a.Scale.X = 2f; a.Scale.Y = 0.4f; a.Animation.Layer = "on"; Tween.To(1f, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1f, a.Scale.Y, x => a.Scale.Y = x, 0.3f); } public override void TurnOff() { base.TurnOff(); var a = GetComponent(); a.Scale.X = 2f; a.Scale.Y = 0.4f; a.Animation.Layer = "off"; Tween.To(1f, a.Scale.X, x => a.Scale.X = x, 0.3f); Tween.To(1f, a.Scale.Y, x => a.Scale.Y = x, 0.3f); } public override void Update(float dt) { base.Update(dt); // Always enabled in tutorial if (Run.Depth != -2 && On) { var room = GetComponent().Room; if (room != null && room.Type == RoomType.Regular) { if (room.Tagged[Tags.MustBeKilled].Count == 0) { TurnOff(); return; } } } if (!On) { return; } beforeNextBullet -= dt * Speed; if (beforeNextBullet <= 0) { beforeNextBullet = 3; var a = GetComponent(); Tween.To(0.6f, a.Scale.X, x => a.Scale.X = x, 0.2f); Tween.To(1.6f, a.Scale.Y, x => a.Scale.Y = x, 0.2f).OnEnd = () => { Tween.To(1.8f, a.Scale.X, x => a.Scale.X = x, 0.1f); Tween.To(0.2f, a.Scale.Y, x => a.Scale.Y = x, 0.1f).OnEnd = () => { Tween.To(1, a.Scale.X, x => a.Scale.X = x, 0.4f); var t = Tween.To(1, a.Scale.Y, x => a.Scale.Y = x, 0.4f); if (Rotates) { t.OnEnd = () => { a.Animate(); GetComponent().EmitRandomized("level_turret_rotating"); Angle = (uint) ((Angle + (ReverseDirection ? -1 : 1)) % 8); }; } var r = GetComponent(); if (r.Room != null && r.Room.Tagged[Tags.Player].Count > 0) { Fire(Angle / 4f * Math.PI); if (OnScreen) { GetComponent().EmitRandomized("level_turret_fire"); } } }; }; } } protected virtual void Fire(double angle) { SendProjectile(angle); } protected void SendProjectile(double angle) { var builder = new ProjectileBuilder(this, "small") { LightRadius = 32f, Color = ProjectileColor.Red, Poof = true, }; builder.Move(angle, 8f); builder.Shoot(angle, 6f); builder.RemoveFlags(ProjectileFlags.Reflectable, ProjectileFlags.BreakableByMelee); builder.Build(); } public override void Render() { if (Run.Depth != -2 || On) { base.Render(); } } public void RenderShadow() { if (Run.Depth != -2 || On) { GraphicsComponent.Render(true); } } public override void RenderImDebug() { base.RenderImDebug(); var u = (int) StartingAngle; if (ImGui.InputInt("Starting angle", ref u)) { Angle = StartingAngle = (uint) u % 8; } ImGui.InputFloat("Before next", ref beforeNextBullet); ImGui.InputFloat("Speed", ref Speed); } public bool ShouldCollide(Entity entity) { return !(entity is Chasm); } } } ================================================ FILE: BurningKnight/entity/room/controller/BossRoomController.cs ================================================ using BurningKnight.entity.room.controllable.turret; namespace BurningKnight.entity.room.controller { public class BossRoomController : RoomController { public override void Init() { base.Init(); foreach (var c in Room.Controllable) { if (c is Turret t) { t.TurnOn(); t.TimingOffset = 0; } } } } } ================================================ FILE: BurningKnight/entity/room/controller/ChallengeRoomController.cs ================================================ using System; using BurningKnight.assets.particle; using BurningKnight.entity.component; using BurningKnight.entity.creature.mob; using BurningKnight.entity.events; using BurningKnight.level.entities.chest; using BurningKnight.state; using BurningKnight.util; using Lens.assets; using Lens.entity; using Lens.util; using Lens.util.file; using Lens.util.math; using Lens.util.timer; using Microsoft.Xna.Framework; namespace BurningKnight.entity.room.controller { public class ChallengeRoomController : RoomController, Subscriber { private bool spawned; private byte wave; public override void Init() { base.Init(); var e = Room.Area.EventListener; e.Subscribe(this); e.Subscribe(this); e.Subscribe(this); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(spawned); stream.WriteByte(wave); } public override void Load(FileReader stream) { base.Load(stream); spawned = stream.ReadBoolean(); wave = stream.ReadByte(); } private static Func CheckDistance(Entity entity) { return (x, y) => entity == null || entity.DistanceTo(new Vector2(x * 16, y * 16)) > 32; } private void Spawn(Entity entity) { spawned = true; SpawnWave(entity); } private void SpawnWave(Entity entity) { var filter = CheckDistance(entity); MobRegistry.SetupForBiome(Run.Level.Biome.Id); var c = Rnd.Int(5, 11); for (var i = 0; i < c; i++) { Timer.Add(() => { var mob = MobRegistry.Generate(); entity.Area.Add(mob); var v = MobRegistry.FindFor(mob.GetType()); if (v?.NearWall ?? false) { mob.Center = Room.GetRandomFreeTileNearWall(filter) * 16; } else if (v?.AwayFromWall ?? false) { mob.Center = Room.GetRandomWallFreeTile(filter) * 16; } else { mob.Center = Room.GetRandomFreeTile(filter) * 16; } if (mob.TryGetComponent(out var z)) { z.Animate(); } else if (mob.TryGetComponent(out var m)) { m.Animate(); } var where = mob.Center; for (var j = 0; j < 8; j++) { var part = new ParticleEntity(Particles.Dust()); part.Position = where + Rnd.Vector(-8, 8); part.Particle.Scale = Rnd.Float(1f, 1.3f); part.Particle.Velocity = MathUtils.CreateVector(Rnd.AnglePI(), 40); Run.Level.Area.Add(part); part.Depth = 1; } Audio.PlaySfx("scroll"); }, (i) * 0.2f); } wave++; } public bool HandleEvent(Event e) { if (wave == 4) { return false; } if (e is DiedEvent de && de.Who.GetComponent().Room == Room) { foreach (var m in Room.Tagged[Tags.MustBeKilled]) { var mob = (Mob) m; if (!mob.GetComponent().HasNoHealth) { return false; } } SpawnWave(de.From); de.BlockClear = true; } if (spawned) { return false; } if (e is ItemTakenEvent ite) { if (ite.Stand.GetComponent().Room == Room) { Spawn(ite.Who); } } else if (e is Chest.OpenedEvent coe) { if (coe.Chest.GetComponent().Room == Room) { Spawn(coe.Who); } } return false; } } } ================================================ FILE: BurningKnight/entity/room/controller/FollowingSpikeBallController.cs ================================================ using System; using BurningKnight.entity.room.controllable.spikes; using Lens.util; using Microsoft.Xna.Framework; namespace BurningKnight.entity.room.controller { public class FollowingSpikeBallController : RoomController { private Vector2 ball; public override void Init() { base.Init(); ball = Room.Center; } public override void Update(float dt) { var target = Room.Center; if (Room.Tagged[Tags.Player].Count > 0) { target = Room.Tagged[Tags.Player][0].Center; } var dx = target.X - ball.X; var dy = target.Y - ball.Y; var d = MathUtils.Distance(dx, dy); if (d > 1f) { var s = dt * 32; ball.X += dx / d * s; ball.Y += dy / d * s; } foreach (var c in Room.Controllable) { if (c is Spikes) { c.SetState(MathUtils.Distance(ball.X - c.CenterX, ball.Y - c.CenterY) < 28); } } } } } ================================================ FILE: BurningKnight/entity/room/controller/PistonActivatorController.cs ================================================ using System; using BurningKnight.entity.room.input; using Lens.util; namespace BurningKnight.entity.room.controller { public class PistonActivatorController : RoomController { private int value; public override void HandleInputChange(RoomInput.ChangedEvent e) { base.HandleInputChange(e); var old = value; value += e.Input.On ? 1 : -1; value = Math.Max(0, value); if (old > 0 && value == 0) { foreach (var p in Room.Pistons) { p.Set(false); } } else if (old == 0 && value > 0) { foreach (var p in Room.Pistons) { p.Set(true); } } } } } ================================================ FILE: BurningKnight/entity/room/controller/RoomController.cs ================================================ using BurningKnight.entity.room.input; using Lens.entity; using Lens.util.file; namespace BurningKnight.entity.room.controller { public class RoomController { public Room Room; public float T; public string Id; public virtual void Init() { } public virtual void Destroy() { } public virtual void Update(float dt) { T += dt; } public virtual void HandleInputChange(RoomInput.ChangedEvent e) { } public virtual void Save(FileWriter stream) { } public virtual void Load(FileReader stream) { } public virtual void Generate() { } } } ================================================ FILE: BurningKnight/entity/room/controller/RoomControllerRegistery.cs ================================================ using System; using System.Collections.Generic; using BurningKnight.assets; using BurningKnight.assets.mod; using BurningKnight.entity.room.controllable; using Lens.util; namespace BurningKnight.entity.room.controller { public static class RoomControllerRegistery { private static Dictionary> defined = new Dictionary>(); static RoomControllerRegistery() { Add("timed_piston_switch"); Add("spike_field"); Add("following_spike_ball"); Add("piston_activator"); Add("trap"); Add("challenge"); Add("boss_room"); } public static void Add(string id, Func maker, Mod mod = null) { defined[$"{(mod == null ? Mods.BurningKnight : mod.Prefix)}:{id}"] = maker; } public static void Add(string id, Mod mod = null) where T : RoomController { Add(id, () => { try { return Activator.CreateInstance(); } catch (Exception e) { Log.Error(e); return null; } }, mod); } public static RoomController Get(string id) { if (defined.TryGetValue(id, out var c)) { var d = c(); d.Id = id; return d; } return null; } public static bool Has(string id) { return defined.ContainsKey(id); } } } ================================================ FILE: BurningKnight/entity/room/controller/SpikeFieldController.cs ================================================ using BurningKnight.entity.room.controllable.spikes; using BurningKnight.entity.room.input; using Lens.util.file; using Lens.util.math; namespace BurningKnight.entity.room.controller { public class SpikeFieldController : RoomController { private byte variant; private bool on = true; public override void Generate() { base.Generate(); variant = (byte) Rnd.Int(8); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteByte(variant); } public override void Load(FileReader stream) { base.Load(stream); variant = stream.ReadByte(); } public override void HandleInputChange(RoomInput.ChangedEvent e) { base.HandleInputChange(e); on = !on; } public override void Update(float dt) { base.Update(dt); foreach (var c in Room.Controllable) { if (c is Spikes) { if (on) { float x = (int) (c.X / 16); float y = (int) (c.Y / 16); var f = 0f; if (variant < 2) { f = (x + y) / 2; } else if (variant < 4) { f = (x - y) / 2; } else if (variant < 6) { f = x / 2; } else { f = y / 2; } c.SetState(((int) (f + T * 0.5f * (variant % 2 == 0 ? 1 : -1)) % 2) == 0); } else { c.SetState(false); } } } } } } ================================================ FILE: BurningKnight/entity/room/controller/TimedPistonSwitchController.cs ================================================ namespace BurningKnight.entity.room.controller { public class TimedPistonSwitchController : RoomController { public override void Update(float dt) { base.Update(dt); if (T >= 2f) { T = 0; foreach (var p in Room.Pistons) { p.Toggle(); } } } } } ================================================ FILE: BurningKnight/entity/room/controller/TrapRoomController.cs ================================================ using BurningKnight.entity.creature.player; using BurningKnight.entity.room.input; namespace BurningKnight.entity.room.controller { public class TrapRoomController : RoomController { public override void Init() { base.Init(); CheckState(); } public override void HandleInputChange(RoomInput.ChangedEvent e) { base.HandleInputChange(e); CheckState(); } private void CheckState() { var on = Room.Inputs.Count == 0; foreach (var c in Room.Inputs) { if (c.On == c.DefaultState) { on = true; break; } } foreach (var c in Room.Controllable) { if (on) { c.TurnOn(); } else { c.TurnOff(); } } if (!on) { Room.CheckCleared(LocalPlayer.Locate(Room.Area)); } } } } ================================================ FILE: BurningKnight/entity/room/input/Button.cs ================================================ using BurningKnight.entity.component; using BurningKnight.entity.creature; using BurningKnight.entity.creature.player; using BurningKnight.entity.events; using Lens.assets; using Lens.entity; using Lens.entity.component.logic; using Lens.util.camera; using Lens.util.file; using Microsoft.Xna.Framework; using VelcroPhysics.Dynamics; namespace BurningKnight.entity.room.input { public class Button : RoomInput { public override void AddComponents() { base.AddComponents(); AddComponent(new AnimationComponent("button")); AddComponent(new RectBodyComponent(2, 2, 10, 9, BodyType.Static, true)); AddComponent(new StateComponent()); ApplyState(); Depth = Layers.Entrance; // DefaultState = true; } private void ApplyState() { var s = GetComponent(); if (On) { s.Become(); } else { s.Become(); } } public override bool HandleEvent(Event e) { if (On) { return base.HandleEvent(e); } if (e is CollisionStartedEvent cse && cse.Entity is Player) { TurnOn(); Audio.PlaySfx("level_lever"); } return base.HandleEvent(e); } protected override void UpdateState() { base.UpdateState(); ApplyState(); Camera.Instance.ShakeMax(6); } public override void Load(FileReader stream) { base.Load(stream); On = stream.ReadBoolean(); ApplyState(); } public override void Save(FileWriter stream) { base.Save(stream); stream.WriteBoolean(On); } #region Button States private class OnState : SmartState