From 2f37923db622ed66c63282aa562d8913100c895f Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Sat, 28 Jun 2025 15:34:15 -0400 Subject: [PATCH 001/105] Cleanup prototype instantiation in `ExplosionSystem` (#38642) Cleanup prototype instantiation in ExplosionSystem --- .../Explosion/EntitySystems/ExplosionSystem.Processing.cs | 4 ++-- Content.Server/Explosion/EntitySystems/ExplosionSystem.cs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 3f08532e37..b61f78e909 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -913,10 +913,10 @@ sealed class Explosion /// /// Data needed to spawn an explosion with . /// -public sealed class QueuedExplosion +public sealed class QueuedExplosion(ExplosionPrototype proto) { public MapCoordinates Epicenter; - public ExplosionPrototype Proto = new(); + public ExplosionPrototype Proto = proto; public float TotalIntensity, Slope, MaxTileIntensity, TileBreakScale; public int MaxTileBreak; public bool CanCreateVacuum; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index ffdc90f9d6..0cdc6d6b23 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -306,10 +306,9 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem return; } - var boom = new QueuedExplosion() + var boom = new QueuedExplosion(type) { Epicenter = epicenter, - Proto = type, TotalIntensity = totalIntensity, Slope = slope, MaxTileIntensity = maxTileIntensity, From 90915075fb2f5c26f9a77afbfc1ec72b5aa795ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Jun 2025 03:00:28 +0200 Subject: [PATCH 002/105] Update Credits (#38646) Co-authored-by: PJBot --- Resources/Credits/GitHub.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 08b0911101..8f68e79e82 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0leshe, 0tito, 0x6273, 12rabbits, 1337dakota, 13spacemen, 154942, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 3nderall, 4310v343k, 4dplanner, 612git, 778b, aaron, abadaba695, Ablankmann, abregado, Absolute-Potato, Absotively, achookh, Acruid, ActiveMammmoth, actually-reb, ada-please, adamsong, Adeinitas, Admiral-Obvious-001, adrian, Adrian16199, Ady4ik, Aerocrux, Aeshus, Aexolott, Aexxie, africalimedrop, afrokada, AftrLite, AgentSmithRadio, Agoichi, Ahion, aiden, Aidenkrz, Aisu9, ajcm, AJCM-git, AjexRose, Alekshhh, alexkar598, AlexMorgan3817, alexum418, alexumandxgabriel08x, Alice4267, Alithsko, alliephante, ALMv1, Alpaccalypse, Alpha-Two, AlphaQwerty, Altoids1, amatwiedle, amylizzle, Andre19926, AndrewEyeke, AndreyCamper, Anzarot121, ApolloVector, Appiah, ar4ill, archee1, ArchPigeon, ArchRBX, areitpog, Arendian, arimah, Arkanic, ArkiveDev, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, ArZarLordOfMango, as334, AsikKEsel, AsnDen, asperger-sind, aspiringLich, astriloqua, august-sun, AutoOtter, AverageNotDoingAnythingEnjoyer, avghdev, Awlod, azzyisnothere, AzzyIsNotHere, B-Kirill, B3CKDOOR, baa14453, BackeTako, Bakke, BananaFlambe, Baptr0b0t, BarryNorfolk, BasedUser, beck-thompson, bellwetherlogic, ben, benbryant0, benev0, benjamin-burges, BGare, bhespiritu, bibbly, BigfootBravo, BIGZi0348, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, BlitzTheSquishy, bloodrizer, Bloody2372, blueDev2, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, Bokser815, bolantej, Booblesnoot42, Boolean-Buckeye, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, BriBrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, buntobaggins, bvelliquette, BWTCK, byondfuckery, c0rigin, c4llv07e, CaasGit, Caconym27, Calecute, Callmore, Camdot, capnsockless, CaptainMaru, captainsqrbeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, catdotjs, catlord, Catofquestionableethics, CatTheSystem, Centronias, Chaboricks, chairbender, Chaoticaa, Charlese2, charlie, chartman, ChaseFlorom, chavonadelal, Cheackraze, CheddaCheez, cheesePizza2, CheesePlated, Chief-Engineer, chillyconmor, christhirtle, chromiumboy, Chronophylos, Chubbicous, Chubbygummibear, Ciac32, ciaran, citrea, civilCornball, claustro305, Clement-O, clyf, Clyybber, CMDR-Piboy314, cnv41, coco, cohanna, Cohnway, Cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, Compilatron144, CookieMasterT, coolboy911, coolmankid12345, Coolsurf6, cooperwallace, corentt, CormosLemming, CrafterKolyan, crazybrain23, Crazydave91920, creadth, CrigCrag, croilbird, Crotalus, CrudeWax, cryals, CrzyPotato, cubixthree, cutemoongod, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, dan, dangerrevolution, daniel-cr, DanSAussieITS, Daracke, Darkenson, DawBla, Daxxi3, dch-GH, de0rix, Deahaka, dean, DEATHB4DEFEAT, Deatherd, deathride58, DebugOk, Decappi, Decortex, Deeeeja, deepdarkdepths, DeepwaterCreations, Deerstop, degradka, Delete69, deltanedas, DenisShvalov, DerbyX, derek, dersheppard, Deserty0, Detintinto, DevilishMilk, dexlerxd, dffdff2423, DieselMohawk, digitalic, Dimastra, DinnerCalzone, DinoWattz, Disp-Dev, DisposableCrewmember42, dissidentbullet, DjfjdfofdjfjD, doc-michael, docnite, Doctor-Cpu, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, DR-DOCTOR-EVIL-EVIL, dragonryan06, drakewill-CRL, Drayff, dreamlyjack, DrEnzyme, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, DuckManZach, Duddino, dukevanity, duskyjay, Dutch-VanDerLinde, dvir001, dylanstrategie, dylanwhittingham, Dynexust, Easypoller, echo, eclips_e, eden077, EEASAS, Efruit, efzapa, Ekkosangen, ElectroSR, elsie, elthundercloud, Elysium206, Emisse, emmafornash, EmoGarbage404, Endecc, Entvari, eoineoineoin, ephememory, eris, erohrs2, ERORR404V1, Errant-4, ertanic, esguard, estacaoespacialpirata, eugene, ewokswagger, exincore, exp111, f0x-n3rd, FacePluslll, Fahasor, FairlySadPanda, farrellka-dev, FATFSAAM2, Feluk6174, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, firenamefn, Firewars763, FirinMaLazors, Fishfish458, fl-oz, Flareguy, flashgnash, FluffiestFloof, FluffMe, FluidRock, flymo5678, foboscheshir, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, foxhorn, freeman2651, freeze2222, frobnic8, Froffy025, Fromoriss, froozigiusz, FrostMando, FrostRibbon, Funce, FungiFellow, FunTust, Futuristic-OK, GalacticChimp, gamer3107, Gamewar360, gansulalan, GaussiArson, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, Gentleman-Bird, geraeumig, Ghagliiarghii, Git-Nivrak, githubuser508, gituhabu, GlassEclipse, GnarpGnarp, GNF54, godisdeadLOL, goet, GoldenCan, Goldminermac, Golinth, golubgik, GoodWheatley, Gorox221, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, GreyMario, GrownSamoyedDog, GTRsound, gusxyz, Gyrandola, h3half, hamurlik, Hanzdegloker, HappyRoach, Hardly3D, harikattar, he1acdvv, Hebi, Helix-ctrl, helm4142, Henry, HerCoyote23, HighTechPuddle, Hitlinemoss, hiucko, hivehum, Hmeister-fake, Hmeister-real, Hobbitmax, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, Hoshizora, Hreno, Hrosts, htmlsystem, hubismal, Hugal31, Huxellberger, Hyenh, hyperb1, hyperDelegate, hyphenationc, i-justuser-i, iaada, iacore, IamVelcroboy, Ian321, icekot8, icesickleone, iczero, iglov, IgorAnt028, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, imatsoup, IMCB, impubbi, imrenq, imweax, indeano, Injazz, Insineer, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, itsmethom, Itzbenz, iztokbajcar, Jackal298, Jackrost, jacksonzck, Jacktastic09, Jackw2As, jacob, jamessimo, janekvap, Jark255, Jarmer123, Jaskanbe, JasperJRoth, jbox144, JCGWE30, jerryimmouse, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, jkwookee, jmcb, JohnGinnane, johnku1, Jophire, joshepvodka, JpegOfAFrog, jproads, JrInventor05, Jrpl, jukereise, juliangiebel, JustArt1m, JustCone14, justdie12, justin, justintether, JustinTrotter, JustinWinningham, justtne, K-Dynamic, k3yw, Kadeo64, Kaga-404, kaiserbirch, KaiShibaa, kalane15, kalanosh, KamTheSythe, Kanashi-Panda, katzenminer, kbailey-git, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, KieueCaprie, Killerqu00, Kimpes, KingFroozy, kira-er, kiri-yoshikage, Kirillcas, Kirus59, Kistras, Kit0vras, KittenColony, Kittygyat, klaypexx, Kmc2000, Ko4ergaPunk, kognise, kokoc9n, komunre, KonstantinAngelov, kosticia, koteq, KrasnoshchekovPavel, Krunklehorn, Kupie, kxvvv, kyupolaris, kzhanik, LaCumbiaDelCoronavirus, lajolico, Lamrr, lanedon, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leander-0, leonardo-dabepis, leonidussaks, leonsfriedrich, LeoSantich, lettern, LetterN, Level10Cybermancer, LEVELcat, lever1209, LevitatingTree, Lgibb18, lgruthes, LightVillet, liltenhead, linkbro1, LinkUyx, Litraxx, little-meow-meow, LittleBuilderJane, LittleNorthStar, LittleNyanCat, lizelive, ljm862, lmsnoise, localcc, lokachop, Lomcastar, LordCarve, LordEclipse, lucas, LucasTheDrgn, luckyshotpictures, LudwigVonChesterfield, luizwritescode, Lukasz825700516, luminight, lunarcomets, Lusatia, lvvova1, Lyndomen, lyroth001, lzimann, lzk228, M1tht1c, M3739, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, MagnusCrowe, malchanceux, MaloTV, ManelNavola, manelnavola, Mangohydra, marboww, Markek1, matt, Matz05, max, MaxNox7, maylokana, MehimoNemo, MeltedPixel, memeproof, MendaxxDev, Menshin, Mephisto72, MerrytheManokit, Mervill, metalgearsloth, MetalSage, MFMessage, mhamsterr, michaelcu, micheel665, mifia, MilenVolf, MilonPL, Minemoder5000, Minty642, minus1over12, Mirino97, mirrorcult, misandrie, MishaUnity, MissKay1994, MisterImp, MisterMecky, Mith-randalf, Mixelz, mjarduk, MjrLandWhale, mkanke-real, MLGTASTICa, moderatelyaware, modern-nm, mokiros, momo, Moneyl, monotheonist, Moomoobeef, moony, Morb0, MossyGreySlope, mr-bo-jangles, Mr0maks, MrFippik, mrrobdemo, muburu, MureixloI, murolem, musicmanvr, MWKane, Myakot, Myctai, N3X15, nabegator, nails-n-tape, Nairodian, Naive817, NakataRin, namespace-Memory, Nannek, NazrinNya, neutrino-laser, NickPowers43, nikitosych, nikthechampiongr, Nimfar11, ninruB, Nirnael, NIXC, nkokic, NkoKirkto, nmajask, noctyrnal, noelkathegod, noirogen, nok-ko, NonchalantNoob, NoobyLegion, Nopey, not-gavnaed, notafet, notquitehadouken, NotSoDana, noudoit, noverd, Nox38, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, Nyxilath, och-och, OctoRocket, OldDanceJacket, OliverOtter, onesch, OneZerooo0, OnyxTheBrave, Orange-Winds, OrangeMoronage9622, Orsoniks, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, packmore, paige404, paigemaeforrest, pali6, Palladinium, Pangogie, panzer-iv1, partyaddict, patrikturi, PaulRitter, peccneck, Peptide90, peptron1, perryprog, PeterFuto, PetMudstone, pewter-wiz, Pgriha, Phantom-Lily, pheenty, philingham, Phill101, Phooooooooooooooooooooooooooooooosphate, phunnyguy, PicklOH, PilgrimViis, Pill-U, pinkbat5, Piras314, Pireax, Pissachu, pissdemon, PixeltheAertistContrib, PixelTheKermit, PJB3005, Plasmaguy, plinyvic, Plykiya, poeMota, pofitlo, pointer-to-null, pok27, poklj, PolterTzi, PoorMansDreams, PopGamer45, portfiend, potato1234x, PotentiallyTom, PotRoastPiggy, Princess-Cheeseballs, ProfanedBane, PROG-MohamedDwidar, Prole0, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykana, psykzz, PuceTint, pumkin69, PuroSlavKing, PursuitInAshes, Putnam3145, py01, qrtDaniil, qrwas, Quantum-cross, quatre, QueerNB, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, Rainbeon, Rainfey, Raitononai, Ramlik, RamZ, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, RedBookcase, Redfire1331, Redict, RedlineTriad, redmushie, RednoWCirabrab, ReeZer2, RemberBM, RemieRichards, RemTim, rene-descartes2021, Renlou, retequizzle, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, rinary1, Rinkashikachi, riolume, RobbyTheFish, robinthedragon, Rockdtben, Rohesie, rok-povsic, rokudara-sen, rolfero, RomanNovo, rosieposieeee, Roudenn, router, ruddygreat, RumiTiger, Ruzihm, S1rFl0, S1ss3l, Saakra, Sadie-silly, saga3152, saintmuntzer, Salex08, sam, samgithubaccount, Samuka-C, SaphireLattice, SapphicOverload, sarahon, sativaleanne, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, schrodinger71, scrato, Scribbles0, scrivoy, scruq445, scuffedjays, ScumbagDog, SeamLesss, Segonist, semensponge, sephtasm, Serkket, sewerpig, SG6732, sh18rw, Shaddap1, ShadeAware, ShadowCommander, shadowtheprotogen546, shaeone, shampunj, shariathotpatrol, SharkSnake98, shibechef, SignalWalker, siigiil, silicon14wastaken, Simyon264, sirdragooon, Sirionaut, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, sleepyyapril, slimmslamm, Slyfox333, snebl, snicket, sniperchance, Snowni, snowsignal, SolidusSnek, solstar2, SonicHDC, SoulFN, SoulSloth, Soundwavesghost, soupkilove, southbridge-fur, sowelipililimute, Soydium, spacelizard, SpaceLizardSky, SpaceManiac, SpaceRox1244, SpaceyLady, Spangs04, spanky-spanky, Sparlight, spartak, SpartanKadence, spderman3333, SpeltIncorrectyl, Spessmann, SphiraI, SplinterGP, spoogemonster, sporekto, sporkyz, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, starbuckss14, Stealthbomber16, stellar-novas, stewie523, stomf, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, strO0pwafel, Strol20, StStevens, Subversionary, sunbear-dev, supergdpwyl, superjj18, Supernorn, SweptWasTaken, SyaoranFox, Sybil, SYNCHRONIC, Szunti, t, Tainakov, takemysoult, tap, TaralGit, Taran, taurie, Tayrtahn, tday93, teamaki, TeenSarlacc, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, Tezzaide, TGODiamond, TGRCdev, tgrkzus, ThatGuyUSA, ThatOneGoblin25, thatrandomcanadianguy, TheArturZh, TheBlueYowie, thecopbennet, TheCze, TheDarkElites, thedraccx, TheEmber, TheFlyingSentry, TheIntoxicatedCat, thekilk, themias, theomund, TheProNoob678, TherapyGoth, ThereDrD0, TheShuEd, thetolbean, thevinter, TheWaffleJesus, thinbug0, ThunderBear2006, timothyteakettle, TimrodDX, timurjavid, tin-man-tim, TiniestShark, Titian3, tk-a369, tkdrg, tmtmtl30, ToastEnjoyer, Toby222, TokenStyle, Tollhouse, Toly65, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, TornadoTechnology, tosatur, TotallyLemon, ToxicSonicFan04, Tr1bute, trixxedbit, TrixxedHeart, tropicalhibi, truepaintgit, Truoizys, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, tyashley, Tyler-IN, TytosB, Tyzemol, UbaserB, ubis1, UBlueberry, uhbg, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unisol, unusualcrow, Uriende, UristMcDorf, user424242420, Utmanarn, Vaaankas, valentfingerov, valquaint, Varen, Vasilis, VasilisThePikachu, veliebm, Velken, VelonacepsCalyxEggs, veprolet, VerinSenpai, veritable-calamity, Veritius, Vermidia, vero5123, Verslebas, vexerot, viceemargo, VigersRay, violet754, Visne, vitusveit, vlad, vlados1408, VMSolidus, vmzd, voidnull000, volotomite, volundr-, Voomra, Vordenburg, vorkathbruh, Vortebo, vulppine, wafehling, walksanatora, Warentan, WarMechanic, Watermelon914, weaversam8, wertanchik, whateverusername0, whatston3, widgetbeck, Will-Oliver-Br, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, Wolfkey-SomeoneElseTookMyUsername, wrexbe, wtcwr68, xeri7, xkreksx, xprospero, xRiriq, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, YoungThugSS14, Yousifb26, youtissoum, yunii, yuriykiss, YuriyKiss, zach-hill, Zadeon, Zalycon, zamp, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zero, ZeroDiamond, ZeWaka, zHonys, zionnBE, ZNixian, Zokkie, ZoldorfTheWizard, zonespace27, Zylofan, Zymem, zzylex +0leshe, 0tito, 0x6273, 12rabbits, 1337dakota, 13spacemen, 154942, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 3nderall, 4310v343k, 4dplanner, 612git, 778b, 96flo, aaron, abadaba695, Ablankmann, abregado, Absolute-Potato, Absotively, achookh, Acruid, ActiveMammmoth, actually-reb, ada-please, adamsong, Adeinitas, Admiral-Obvious-001, adrian, Adrian16199, Ady4ik, Aerocrux, Aeshus, Aexolott, Aexxie, africalimedrop, afrokada, AftrLite, AgentSmithRadio, Agoichi, Ahion, aiden, Aidenkrz, Aisu9, ajcm, AJCM-git, AjexRose, Alekshhh, alexkar598, AlexMorgan3817, alexum418, alexumandxgabriel08x, Alice4267, Alithsko, alliephante, ALMv1, Alpaccalypse, Alpha-Two, AlphaQwerty, Altoids1, amatwiedle, amylizzle, Andre19926, AndrewEyeke, AndreyCamper, Anzarot121, ApolloVector, Appiah, ar4ill, archee1, ArchPigeon, ArchRBX, areitpog, Arendian, areyouconfused, arimah, Arkanic, ArkiveDev, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, ArZarLordOfMango, as334, AsikKEsel, AsnDen, asperger-sind, aspiringLich, astriloqua, august-sun, AutoOtter, AverageNotDoingAnythingEnjoyer, avghdev, Awlod, azzyisnothere, AzzyIsNotHere, B-Kirill, B3CKDOOR, baa14453, BackeTako, Bakke, BananaFlambe, Baptr0b0t, BarryNorfolk, BasedUser, beck-thompson, beesterman, bellwetherlogic, ben, benbryant0, benev0, benjamin-burges, BGare, bhespiritu, bibbly, BigfootBravo, BIGZi0348, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blitzthesquishy, bloodrizer, Bloody2372, blueDev2, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, Bokser815, bolantej, Booblesnoot42, Boolean-Buckeye, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, BriBrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, buntobaggins, bvelliquette, BWTCK, byondfuckery, c0rigin, c4llv07e, CaasGit, Caconym27, Calecute, Callmore, Camdot, capnsockless, CaptainMaru, captainsqrbeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, catdotjs, catlord, Catofquestionableethics, CatTheSystem, Centronias, Chaboricks, chairbender, Chaoticaa, Charlese2, charlie, chartman, ChaseFlorom, chavonadelal, Cheackraze, CheddaCheez, cheesePizza2, CheesePlated, Chief-Engineer, chillyconmor, christhirtle, chromiumboy, Chronophylos, Chubbicous, Chubbygummibear, Ciac32, ciaran, citrea, civilCornball, claustro305, Clement-O, clyf, Clyybber, CMDR-Piboy314, cnv41, coco, cohanna, Cohnway, Cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, Compilatron144, CookieMasterT, coolboy911, coolmankid12345, Coolsurf6, cooperwallace, corentt, CormosLemming, CrafterKolyan, crazybrain23, Crazydave91920, creadth, CrigCrag, croilbird, Crotalus, CrudeWax, cryals, CrzyPotato, cubixthree, cutemoongod, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, dan, dangerrevolution, daniel-cr, DanSAussieITS, Daracke, Darkenson, DawBla, Daxxi3, dch-GH, de0rix, Deahaka, dean, DEATHB4DEFEAT, Deatherd, deathride58, DebugOk, Decappi, Decortex, Deeeeja, deepdarkdepths, DeepwaterCreations, Deerstop, degradka, Delete69, deltanedas, DenisShvalov, DerbyX, derek, dersheppard, Deserty0, Detintinto, DevilishMilk, dexlerxd, dffdff2423, DieselMohawk, digitalic, Dimastra, DinnerCalzone, DinoWattz, Disp-Dev, DisposableCrewmember42, dissidentbullet, DjfjdfofdjfjD, doc-michael, docnite, Doctor-Cpu, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, Doru991, DoubleRiceEddiedd, DoutorWhite, DR-DOCTOR-EVIL-EVIL, Dragonjspider, dragonryan06, drakewill-CRL, Drayff, dreamlyjack, DrEnzyme, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, DuckManZach, Duddino, dukevanity, duskyjay, Dutch-VanDerLinde, dvir001, dylanstrategie, dylanwhittingham, Dynexust, Easypoller, echo, eclips_e, eden077, EEASAS, Efruit, efzapa, Ekkosangen, ElectroSR, elsie, elthundercloud, Elysium206, Emisse, emmafornash, EmoGarbage404, Endecc, Entvari, eoineoineoin, ephememory, eris, erohrs2, ERORR404V1, Errant-4, ertanic, esguard, estacaoespacialpirata, eugene, ewokswagger, exincore, exp111, f0x-n3rd, FacePluslll, Fahasor, FairlySadPanda, farrellka-dev, FATFSAAM2, Feluk6174, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, firenamefn, Firewars763, FirinMaLazors, Fishfish458, fl-oz, Flareguy, flashgnash, FluffiestFloof, FluffMe, FluidRock, flymo5678, foboscheshir, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, foxhorn, freeman2651, freeze2222, frobnic8, Froffy025, Fromoriss, froozigiusz, FrostMando, FrostRibbon, Funce, FungiFellow, FunTust, Futuristic-OK, GalacticChimp, gamer3107, Gamewar360, gansulalan, GaussiArson, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, Gentleman-Bird, geraeumig, Ghagliiarghii, Git-Nivrak, githubuser508, gituhabu, GlassEclipse, GnarpGnarp, GNF54, godisdeadLOL, goet, GoldenCan, Goldminermac, Golinth, golubgik, GoodWheatley, Gorox221, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, GreyMario, GrownSamoyedDog, GTRsound, gusxyz, Gyrandola, h3half, hamurlik, Hanzdegloker, HappyRoach, Hardly3D, harikattar, he1acdvv, Hebi, Helix-ctrl, helm4142, Henry, HerCoyote23, HighTechPuddle, Hitlinemoss, hiucko, hivehum, Hmeister-fake, Hmeister-real, Hobbitmax, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, Hoshizora, Hreno, Hrosts, htmlsystem, hubismal, Hugal31, Huxellberger, Hyenh, hyperb1, hyperDelegate, hyphenationc, i-justuser-i, iaada, iacore, IamVelcroboy, Ian321, icekot8, icesickleone, iczero, iglov, IgorAnt028, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, imatsoup, IMCB, impubbi, imrenq, imweax, indeano, Injazz, Insineer, insoPL, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, itsmethom, Itzbenz, iztokbajcar, Jackal298, Jackrost, jacksonzck, Jacktastic09, Jackw2As, jacob, jamessimo, janekvap, Jark255, Jarmer123, Jaskanbe, JasperJRoth, jbox144, JCGWE30, jerryimmouse, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, jkwookee, jmcb, JohnGinnane, johnku1, Jophire, joshepvodka, JpegOfAFrog, jproads, JrInventor05, Jrpl, jukereise, juliangiebel, JustArt1m, JustCone14, justdie12, justin, justintether, JustinTrotter, JustinWinningham, justtne, K-Dynamic, k3yw, Kadeo64, Kaga-404, kaiserbirch, KaiShibaa, kalane15, kalanosh, KamTheSythe, Kanashi-Panda, katzenminer, kbailey-git, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, KieueCaprie, Killerqu00, Kimpes, KingFroozy, kira-er, kiri-yoshikage, Kirillcas, Kirus59, Kistras, Kit0vras, KittenColony, Kittygyat, klaypexx, Kmc2000, Ko4ergaPunk, kognise, kokoc9n, komunre, KonstantinAngelov, kosticia, koteq, KrasnoshchekovPavel, Krunklehorn, Kupie, kxvvv, kyupolaris, kzhanik, LaCumbiaDelCoronavirus, lajolico, Lamrr, lanedon, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leander-0, leonardo-dabepis, leonidussaks, leonsfriedrich, LeoSantich, lettern, LetterN, Level10Cybermancer, LEVELcat, lever1209, LevitatingTree, Lgibb18, lgruthes, LightVillet, liltenhead, linkbro1, linkuyx, Litraxx, little-meow-meow, LittleBuilderJane, LittleNorthStar, LittleNyanCat, lizelive, ljm862, lmsnoise, localcc, lokachop, Lomcastar, LordCarve, LordEclipse, lucas, LucasTheDrgn, luckyshotpictures, LudwigVonChesterfield, luizwritescode, Lukasz825700516, luminight, lunarcomets, Lusatia, lvvova1, Lyndomen, lyroth001, lzimann, lzk228, M1tht1c, M3739, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, MagnusCrowe, maland1, malchanceux, MaloTV, ManelNavola, manelnavola, Mangohydra, marboww, Markek1, matt, Matz05, max, MaxNox7, maylokana, MehimoNemo, MeltedPixel, memeproof, MendaxxDev, Menshin, Mephisto72, MerrytheManokit, Mervill, metalgearsloth, MetalSage, MFMessage, mhamsterr, michaelcu, micheel665, mifia, MilenVolf, MilonPL, Minemoder5000, Minty642, minus1over12, Mirino97, mirrorcult, misandrie, MishaUnity, MissKay1994, MisterImp, MisterMecky, Mith-randalf, Mixelz, mjarduk, MjrLandWhale, mkanke-real, MLGTASTICa, moderatelyaware, modern-nm, mokiros, momo, Moneyl, monotheonist, Moomoobeef, moony, Morb0, MossyGreySlope, mr-bo-jangles, Mr0maks, MrFippik, mrrobdemo, muburu, MureixloI, murolem, musicmanvr, MWKane, Myakot, Myctai, N3X15, nabegator, nails-n-tape, Nairodian, Naive817, NakataRin, namespace-Memory, Nannek, NazrinNya, neutrino-laser, NickPowers43, nikitosych, nikthechampiongr, Nimfar11, ninruB, Nirnael, NIXC, nkokic, NkoKirkto, nmajask, noctyrnal, noelkathegod, noirogen, nok-ko, NonchalantNoob, NoobyLegion, Nopey, not-gavnaed, notafet, notquitehadouken, NotSoDana, noudoit, noverd, Nox38, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, Nyxilath, och-och, OctoRocket, OldDanceJacket, OliverOtter, onesch, OneZerooo0, OnyxTheBrave, Orange-Winds, OrangeMoronage9622, Orsoniks, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, packmore, paige404, paigemaeforrest, pali6, Palladinium, Pangogie, panzer-iv1, partyaddict, patrikturi, PaulRitter, peccneck, Peptide90, peptron1, perryprog, PeterFuto, PetMudstone, pewter-wiz, Pgriha, Phantom-Lily, pheenty, philingham, Phill101, Phooooooooooooooooooooooooooooooosphate, phunnyguy, PicklOH, PilgrimViis, Pill-U, pinkbat5, Piras314, Pireax, Pissachu, pissdemon, PixeltheAertistContrib, PixelTheKermit, PJB3005, Plasmaguy, plinyvic, Plykiya, poeMota, pofitlo, pointer-to-null, pok27, poklj, PolterTzi, PoorMansDreams, PopGamer45, portfiend, potato1234x, PotentiallyTom, PotRoastPiggy, Princess-Cheeseballs, ProfanedBane, PROG-MohamedDwidar, Prole0, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykana, psykzz, PuceTint, pumkin69, PuroSlavKing, PursuitInAshes, Putnam3145, py01, qrtDaniil, qrwas, Quantum-cross, quatre, QueerNB, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, Rainbeon, Rainfey, Raitononai, Ramlik, RamZ, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, RedBookcase, Redfire1331, Redict, RedlineTriad, redmushie, RednoWCirabrab, ReeZer2, RemberBM, RemieRichards, RemTim, rene-descartes2021, Renlou, retequizzle, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, rinary1, Rinkashikachi, riolume, RobbyTheFish, robinthedragon, Rockdtben, Rohesie, rok-povsic, rokudara-sen, rolfero, RomanNovo, rosieposieeee, Roudenn, router, ruddygreat, rumaks, RumiTiger, Ruzihm, S1rFl0, S1ss3l, Saakra, Sadie-silly, saga3152, saintmuntzer, Salex08, sam, samgithubaccount, Samuka-C, SaphireLattice, SapphicOverload, sarahon, sativaleanne, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, schrodinger71, scrato, Scribbles0, scrivoy, scruq445, scuffedjays, ScumbagDog, SeamLesss, Segonist, semensponge, sephtasm, Serkket, sewerpig, SG6732, sh18rw, Shaddap1, ShadeAware, ShadowCommander, shadowtheprotogen546, shaeone, shampunj, shariathotpatrol, SharkSnake98, shibechef, SignalWalker, siigiil, silicon14wastaken, Simyon264, sirdragooon, Sirionaut, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skybailey-dev, Skyedra, SlamBamActionman, slarticodefast, Slava0135, sleepyyapril, slimmslamm, Slyfox333, snebl, snicket, sniperchance, Snowni, snowsignal, SolidusSnek, solstar2, SonicHDC, SoulFN, SoulSloth, Soundwavesghost, soupkilove, southbridge-fur, sowelipililimute, Soydium, spacelizard, SpaceLizardSky, SpaceManiac, SpaceRox1244, SpaceyLady, Spangs04, spanky-spanky, Sparlight, spartak, SpartanKadence, spderman3333, SpeltIncorrectyl, Spessmann, SphiraI, SplinterGP, spoogemonster, sporekto, sporkyz, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, starbuckss14, Stealthbomber16, stellar-novas, stewie523, stomf, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, strO0pwafel, Strol20, StStevens, Subversionary, sunbear-dev, supergdpwyl, superjj18, Supernorn, SweptWasTaken, SyaoranFox, Sybil, SYNCHRONIC, Szunti, t, Tainakov, takemysoult, tap, TaralGit, Taran, taurie, Tayrtahn, tday93, teamaki, TeenSarlacc, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, Tezzaide, TGODiamond, TGRCdev, tgrkzus, ThatGuyUSA, ThatOneGoblin25, thatrandomcanadianguy, TheArturZh, TheBlueYowie, thecopbennet, TheCze, TheDarkElites, thedraccx, TheEmber, TheFlyingSentry, TheIntoxicatedCat, thekilk, themias, theomund, TheProNoob678, TherapyGoth, ThereDrD0, TheShuEd, thetolbean, thevinter, TheWaffleJesus, thinbug0, ThunderBear2006, timothyteakettle, TimrodDX, timurjavid, tin-man-tim, TiniestShark, Titian3, tk-a369, tkdrg, tmtmtl30, ToastEnjoyer, Toby222, TokenStyle, Tollhouse, Toly65, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, tornado-technology, TornadoTechnology, tosatur, TotallyLemon, ToxicSonicFan04, Tr1bute, trixxedbit, TrixxedHeart, tropicalhibi, truepaintgit, Truoizys, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, tyashley, Tyler-IN, TytosB, Tyzemol, UbaserB, ubis1, UBlueberry, uhbg, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unisol, unusualcrow, Uriende, UristMcDorf, user424242420, Utmanarn, Vaaankas, valentfingerov, valquaint, Varen, Vasilis, VasilisThePikachu, veliebm, Velken, VelonacepsCalyxEggs, veprolet, VerinSenpai, veritable-calamity, Veritius, Vermidia, vero5123, Verslebas, vexerot, viceemargo, VigersRay, violet754, Visne, vitusveit, vlad, vlados1408, VMSolidus, vmzd, voidnull000, volotomite, volundr-, Voomra, Vordenburg, vorkathbruh, Vortebo, vulppine, wafehling, walksanatora, Warentan, WarMechanic, Watermelon914, weaversam8, wertanchik, whateverusername0, whatston3, widgetbeck, Will-Oliver-Br, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, Wolfkey-SomeoneElseTookMyUsername, wrexbe, wtcwr68, xeri7, xkreksx, xprospero, xRiriq, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, YoungThugSS14, Yousifb26, youtissoum, yunii, yuriykiss, YuriyKiss, zach-hill, Zadeon, Zalycon, zamp, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zero, ZeroDiamond, ZeWaka, zHonys, zionnBE, ZNixian, Zokkie, ZoldorfTheWizard, zonespace27, Zylofan, Zymem, zzylex From 4bd437272f9c69e8ce9fe830ae55a95b1021eebf Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:33:58 +0200 Subject: [PATCH 003/105] fix ItemSlotsSystem debug assert (#38655) --- Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index b3eb4b23c2..88e6ca44dc 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -395,7 +395,7 @@ namespace Content.Shared.Containers.ItemSlots if (!Resolve(user, ref hands, false)) return false; - if (!_handsSystem.TryGetActiveItem((uid, hands), out var held)) + if (!_handsSystem.TryGetActiveItem((user, hands), out var held)) return false; if (!CanInsert(uid, held.Value, user, slot)) From 5d191d7b872f00b3e3c185e134372e5a88efd9fa Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 29 Jun 2025 14:35:08 +0000 Subject: [PATCH 004/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c80ca684a3..195ca58079 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Errant - changes: - - message: Handheld geiger counters can now by heard by everyone nearby. - type: Tweak - id: 8213 - time: '2025-04-17T11:24:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/30463 - author: Centronias changes: - message: Tank harnesses can be made at lathes, similar to utility belts. @@ -3886,3 +3879,11 @@ id: 8725 time: '2025-06-28T14:01:29.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38479 +- author: slarticodefast + changes: + - message: Fixed smart equip not being able to insert items into item slots (for + example for the sabre sheath). + type: Fix + id: 8726 + time: '2025-06-29T14:33:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38655 From 7951db15ca0977302fe34d21533b728a222dadf8 Mon Sep 17 00:00:00 2001 From: BramvanZijp <56019239+BramvanZijp@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:21:14 +0200 Subject: [PATCH 005/105] Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536) --- Content.Server/Remotes/DoorRemoteSystem.cs | 16 +++++++++++---- .../Remotes/Components/DoorRemoteComponent.cs | 7 +++++++ .../Catalog/Fills/Lockers/heads.yml | 2 +- .../Entities/Objects/Devices/door_remote.yml | 20 +++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index 27df5ef34d..c3425f347a 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -51,11 +51,19 @@ namespace Content.Shared.Remotes return; } + var accessTarget = args.Used; + // This covers the accesses the REMOTE has, and is not effected by the user's ID card. + if (entity.Comp.IncludeUserAccess) // Allows some door remotes to inherit the user's access. + { + accessTarget = args.User; + // This covers the accesses the USER has, which always includes the remote's access since holding a remote acts like holding an ID card. + } + if (TryComp(args.Target, out var accessComponent) - && !_doorSystem.HasAccess(args.Target.Value, args.Used, doorComp, accessComponent)) + && !_doorSystem.HasAccess(args.Target.Value, accessTarget, doorComp, accessComponent)) { if (isAirlock) - _doorSystem.Deny(args.Target.Value, doorComp, args.User); + _doorSystem.Deny(args.Target.Value, doorComp, accessTarget); Popup.PopupEntity(Loc.GetString("door-remote-denied"), args.User, args.User); return; } @@ -63,7 +71,7 @@ namespace Content.Shared.Remotes switch (entity.Comp.Mode) { case OperatingMode.OpenClose: - if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, args.Used)) + if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, accessTarget)) _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)}: {doorComp.State}"); @@ -73,7 +81,7 @@ namespace Content.Shared.Remotes { if (!boltsComp.BoltWireCut) { - _doorSystem.SetBoltsDown((args.Target.Value, boltsComp), !boltsComp.BoltsDown, args.Used); + _doorSystem.SetBoltsDown((args.Target.Value, boltsComp), !boltsComp.BoltsDown, accessTarget); _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to {(boltsComp.BoltsDown ? "" : "un")}bolt it"); diff --git a/Content.Shared/Remotes/Components/DoorRemoteComponent.cs b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs index b157596e3b..64977596c2 100644 --- a/Content.Shared/Remotes/Components/DoorRemoteComponent.cs +++ b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs @@ -8,6 +8,13 @@ public sealed partial class DoorRemoteComponent : Component [AutoNetworkedField] [DataField] public OperatingMode Mode = OperatingMode.OpenClose; + + /// + /// Does the remote allow the user to manipulate doors that they have access to, even if the remote itself does not? + /// + [AutoNetworkedField] + [DataField] + public bool IncludeUserAccess = false; } public enum OperatingMode : byte diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index 2a15014ce2..6b1efddad1 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -43,7 +43,7 @@ - id: ClothingHeadsetAltCommand - id: ClothingOuterArmorCaptainCarapace - id: CommsComputerCircuitboard - - id: DoorRemoteCommand + - id: DoorRemoteCustom - id: MedalCase - id: NukeDisk - id: PinpointerNuclear diff --git a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml index 45689958cf..8f7f6957b2 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml @@ -29,6 +29,24 @@ - type: Access groups: - Command + - type: DoorRemote + +- type: entity + parent: [DoorRemoteDefault, BaseCommandContraband] + id: DoorRemoteCustom + name: custom door remote + description: A gadget which can open and bolt doors remotely. This advanced variant does not have built-in access, instead inheriting the ID access of the user. + components: + - type: Sprite + layers: + - state: door_remotebase + - state: door_remotelightscolour + color: "#0077FF" + - state: door_remotescreencolour + color: "#0033EE" + - type: Access + - type: DoorRemote + includeUserAccess: true - type: entity parent: [DoorRemoteDefault, BaseCommandContraband] @@ -155,6 +173,8 @@ color: "#2eba22" - state: door_remotescreencolour color: "#22871a" + - type: DoorRemote + includeUserAccess: true - type: Access groups: - AllAccess From ec2d4ddd5ea7a4f04453ceaff2faa2ebbbb277a5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 29 Jun 2025 16:22:22 +0000 Subject: [PATCH 006/105] Automatic changelog update --- Resources/Changelog/Admin.yml | 8 ++++++++ Resources/Changelog/Changelog.yml | 21 +++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index 67fc878264..b10997e927 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -1225,5 +1225,13 @@ Entries: id: 148 time: '2025-06-28T11:11:08.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38612 +- author: BramvanZijp + changes: + - message: The Super Door Remote can now effect doors that the user's ID card has + access to, even if the remote itself somehow cannot access them. + type: Tweak + id: 149 + time: '2025-06-29T16:21:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35536 Name: Admin Order: 2 diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 195ca58079..8c9af293ff 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: Centronias - changes: - - message: Tank harnesses can be made at lathes, similar to utility belts. - type: Add - - message: Tank harnesses take up a 1x2 space in inventories, half of their previous - 2x2. - type: Tweak - id: 8214 - time: '2025-04-17T12:33:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35590 - author: Jacktastic09 changes: - message: Added the Solid Headband, available via hacked ClothesMate vending machines @@ -3887,3 +3877,14 @@ id: 8726 time: '2025-06-29T14:33:58.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38655 +- author: BramvanZijp + changes: + - message: Added the custom door remote, it does not have any built-in access, instead + inheriting the ID access that the user has. + type: Add + - message: The captain's locker now comes with a custom door remote instead of a + command door remote. + type: Tweak + id: 8727 + time: '2025-06-29T16:21:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35536 From cd2ce56aefae03a80ddc92d5280afe4834473a57 Mon Sep 17 00:00:00 2001 From: Nox Date: Sun, 29 Jun 2025 15:14:12 -0700 Subject: [PATCH 007/105] Added directional beacons (#38284) * Added directional beacons Signed-off-by: Nox38 * Fixed names Signed-off-by: Nox38 --------- Signed-off-by: Nox38 --- .../en-US/navmap-beacons/station-beacons.ftl | 16 +++ .../Objects/Devices/station_beacon.yml | 128 ++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl b/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl index 89b4266ddc..2d5deb8bb6 100644 --- a/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl +++ b/Resources/Locale/en-US/navmap-beacons/station-beacons.ftl @@ -47,6 +47,14 @@ station-beacon-engineering = Engineering station-beacon-ce = CE station-beacon-ame = AME station-beacon-solars = Solars +station-beacon-solars-N = Solars N +station-beacon-solars-NE = Solars NE +station-beacon-solars-E = Solars E +station-beacon-solars-SE = Solars SE +station-beacon-solars-S = Solars S +station-beacon-solars-SW = Solars SW +station-beacon-solars-W = Solars W +station-beacon-solars-NW = Solars NW station-beacon-gravgen = Grav station-beacon-pa = PA Control station-beacon-smes = SMES @@ -81,4 +89,12 @@ station-beacon-tools = Tools station-beacon-disposals = Disposals station-beacon-cryosleep = Cryosleep station-beacon-escape-pod = Escape Pod +station-beacon-escape-pod-N = Escape Pod N +station-beacon-escape-pod-NE = Escape Pod NE +station-beacon-escape-pod-E = Escape Pod E +station-beacon-escape-pod-SE = Escape Pod SE +station-beacon-escape-pod-S = Escape Pod S +station-beacon-escape-pod-SW = Escape Pod SW +station-beacon-escape-pod-W = Escape Pod W +station-beacon-escape-pod-NW = Escape Pod NW station-beacon-vox = Vox Break Room diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml index 569fd47d00..870e66654f 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml @@ -456,6 +456,70 @@ - type: NavMapBeacon defaultText: station-beacon-solars +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsN + suffix: Solars, North + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-N + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsNE + suffix: Solars, Northeast + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-NE + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsE + suffix: Solars, East + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-E + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsSE + suffix: Solars, Southeast + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-SE + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsS + suffix: Solars, South + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-S + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsSW + suffix: Solars, Southwest + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-SW + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsW + suffix: Solars, West + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-W + +- type: entity + parent: DefaultStationBeaconEngineering + id: DefaultStationBeaconSolarsNW + suffix: Solars, Northwest + components: + - type: NavMapBeacon + defaultText: station-beacon-solars-NW + - type: entity parent: DefaultStationBeaconEngineering id: DefaultStationBeaconGravGen @@ -706,6 +770,70 @@ - type: NavMapBeacon defaultText: station-beacon-escape-pod +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodN + suffix: Escape Pod, North + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-N + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodNE + suffix: Escape Pod, Northeast + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-NE + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodE + suffix: Escape Pod, East + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-E + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodSE + suffix: Escape Pod, Southeast + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-SE + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodS + suffix: Escape Pod, South + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-S + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodSW + suffix: Escape Pod, Southwest + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-SW + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodW + suffix: Escape Pod, West + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-W + +- type: entity + parent: DefaultStationBeacon + id: DefaultStationBeaconEscapePodNW + suffix: Escape Pod, Northwest + components: + - type: NavMapBeacon + defaultText: station-beacon-escape-pod-NW + - type: entity parent: DefaultStationBeacon id: DefaultStationBeaconVox From 34825464dcbeb71e0de6f9029a0a11f13aebc26f Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Sun, 29 Jun 2025 21:41:55 -0400 Subject: [PATCH 008/105] Power stat and nuke codes commands get some LEC love. (#38585) * commit * requested changes. --- .../Nuke/Commands/SendNukeCodesCommand.cs | 75 +++++++++---------- .../Power/Commands/PowerStatCommand.cs | 33 ++++---- .../en-US/commands/nukecodes-command.ftl | 2 + .../en-US/commands/powerstat-command.ftl | 6 ++ 4 files changed, 57 insertions(+), 59 deletions(-) create mode 100644 Resources/Locale/en-US/commands/nukecodes-command.ftl create mode 100644 Resources/Locale/en-US/commands/powerstat-command.ftl diff --git a/Content.Server/Nuke/Commands/SendNukeCodesCommand.cs b/Content.Server/Nuke/Commands/SendNukeCodesCommand.cs index d0e83e4f75..8ac4f95a97 100644 --- a/Content.Server/Nuke/Commands/SendNukeCodesCommand.cs +++ b/Content.Server/Nuke/Commands/SendNukeCodesCommand.cs @@ -1,55 +1,48 @@ using Content.Server.Administration; using Content.Server.Station.Components; using Content.Shared.Administration; -using JetBrains.Annotations; using Robust.Shared.Console; -namespace Content.Server.Nuke.Commands +namespace Content.Server.Nuke.Commands; + +[AdminCommand(AdminFlags.Fun)] +public sealed class SendNukeCodesCommand : LocalizedEntityCommands { - [UsedImplicitly] - [AdminCommand(AdminFlags.Fun)] - public sealed class SendNukeCodesCommand : IConsoleCommand + [Dependency] private readonly NukeCodePaperSystem _nukeCodeSystem = default!; + + public override string Command => "nukecodes"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - public string Command => "nukecodes"; - public string Description => "Send nuke codes to a station's communication consoles"; - public string Help => "nukecodes [station EntityUid]"; - - [Dependency] private readonly IEntityManager _entityManager = default!; - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (args.Length != 1) { - if (args.Length != 1) - { - shell.WriteError(Loc.GetString("shell-need-exactly-one-argument")); - return; - } - - if (!NetEntity.TryParse(args[0], out var uidNet) || !_entityManager.TryGetEntity(uidNet, out var uid)) - { - shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number")); - return; - } - - _entityManager.System().SendNukeCodes(uid.Value); + shell.WriteError(Loc.GetString("shell-need-exactly-one-argument")); + return; } - public CompletionResult GetCompletion(IConsoleShell shell, string[] args) + if (!NetEntity.TryParse(args[0], out var uidNet) || !EntityManager.TryGetEntity(uidNet, out var uid)) { - if (args.Length != 1) - { - return CompletionResult.Empty; - } - - var stations = new List(); - var query = _entityManager.EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var stationData)) - { - var meta = _entityManager.GetComponent(uid); - - stations.Add(new CompletionOption(uid.ToString(), meta.EntityName)); - } - - return CompletionResult.FromHintOptions(stations, null); + shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number")); + return; } + + _nukeCodeSystem.SendNukeCodes(uid.Value); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + if (args.Length != 1) + return CompletionResult.Empty; + + var stations = new List(); + var query = EntityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _)) + { + var meta = EntityManager.GetComponent(uid); + + stations.Add(new CompletionOption(uid.ToString(), meta.EntityName)); + } + + return CompletionResult.FromHintOptions(stations, null); } } diff --git a/Content.Server/Power/Commands/PowerStatCommand.cs b/Content.Server/Power/Commands/PowerStatCommand.cs index 127050393a..b9d71ee9bc 100644 --- a/Content.Server/Power/Commands/PowerStatCommand.cs +++ b/Content.Server/Power/Commands/PowerStatCommand.cs @@ -3,25 +3,22 @@ using Content.Server.Power.EntitySystems; using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.Power.Commands +namespace Content.Server.Power.Commands; + +[AdminCommand(AdminFlags.Debug)] +public sealed class PowerStatCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Debug)] - public sealed class PowerStatCommand : IConsoleCommand + [Dependency] private readonly PowerNetSystem _powerNet = default!; + + public override string Command => "powerstat"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "powerstat"; - public string Description => "Shows statistics for pow3r"; - public string Help => "Usage: powerstat"; - - public void Execute(IConsoleShell shell, string argStr, string[] args) - { - var stats = _e.System().GetStatistics(); - - shell.WriteLine($"networks: {stats.CountNetworks}"); - shell.WriteLine($"loads: {stats.CountLoads}"); - shell.WriteLine($"supplies: {stats.CountSupplies}"); - shell.WriteLine($"batteries: {stats.CountBatteries}"); - } + var stats = _powerNet.GetStatistics(); + shell.WriteLine(Loc.GetString("cmd-powerstat-output", + ("networks", stats.CountNetworks), + ("loads", stats.CountLoads), + ("supplies", stats.CountSupplies), + ("batteries", stats.CountBatteries))); } } diff --git a/Resources/Locale/en-US/commands/nukecodes-command.ftl b/Resources/Locale/en-US/commands/nukecodes-command.ftl new file mode 100644 index 0000000000..50e324c524 --- /dev/null +++ b/Resources/Locale/en-US/commands/nukecodes-command.ftl @@ -0,0 +1,2 @@ +cmd-nukecodes-desc = Send nuke codes to a station's communication consoles. +cmd-nukecodes-help = Usage: nukecodes diff --git a/Resources/Locale/en-US/commands/powerstat-command.ftl b/Resources/Locale/en-US/commands/powerstat-command.ftl new file mode 100644 index 0000000000..c22cd5e22a --- /dev/null +++ b/Resources/Locale/en-US/commands/powerstat-command.ftl @@ -0,0 +1,6 @@ +cmd-powerstat-desc = Shows statistics for pow3r. +cmd-powerstat-help = Usage: powerstat +cmd-powerstat-output = Networks: {$networks} + Loads: {$loads} + Supplies: {$supplies} + Batteries: {$batteries} From 32f5551e2a43193cecaec747943a28c5a8033430 Mon Sep 17 00:00:00 2001 From: Kowlin <10947836+Kowlin@users.noreply.github.com> Date: Mon, 30 Jun 2025 23:09:16 +0200 Subject: [PATCH 009/105] Tweaks to admin CSV exporting (#38531) --- .../Administration/UI/Logs/AdminLogsEui.cs | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs index 2c64b82d20..1544b827ae 100644 --- a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs +++ b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs @@ -20,6 +20,10 @@ public sealed class AdminLogsEui : BaseEui [Dependency] private readonly IFileDialogManager _dialogManager = default!; [Dependency] private readonly ILogManager _log = default!; + private const char CsvSeparator = ','; + private const string CsvQuote = "\""; + private const string CsvHeader = "Date,ID,PlayerID,Severity,Type,Message"; + private ISawmill _sawmill; private bool _currentlyExportingLogs = false; @@ -100,7 +104,9 @@ public sealed class AdminLogsEui : BaseEui try { - await using var writer = new StreamWriter(file.Value.fileStream); + // Buffer is set to 4KB for performance reasons. As the average export of 1000 logs is ~200KB + await using var writer = new StreamWriter(file.Value.fileStream, bufferSize: 4096); + await writer.WriteLineAsync(CsvHeader); foreach (var child in LogsControl.LogsContainer.Children) { if (child is not AdminLogLabel logLabel || !child.Visible) @@ -108,28 +114,31 @@ public sealed class AdminLogsEui : BaseEui var log = logLabel.Log; + // Date // I swear to god if someone adds ,s or "s to the other fields... await writer.WriteAsync(log.Date.ToString("s", System.Globalization.CultureInfo.InvariantCulture)); - await writer.WriteAsync(','); + await writer.WriteAsync(CsvSeparator); + // ID await writer.WriteAsync(log.Id.ToString()); - await writer.WriteAsync(','); - await writer.WriteAsync(log.Impact.ToString()); - await writer.WriteAsync(','); - // Message - await writer.WriteAsync('"'); - await writer.WriteAsync(log.Message.Replace("\"", "\"\"")); - await writer.WriteAsync('"'); - // End of message - await writer.WriteAsync(','); - + await writer.WriteAsync(CsvSeparator); + // PlayerID var players = log.Players; for (var i = 0; i < players.Length; i++) { await writer.WriteAsync(players[i] + (i == players.Length - 1 ? "" : " ")); } - - await writer.WriteAsync(','); + await writer.WriteAsync(CsvSeparator); + // Severity + await writer.WriteAsync(log.Impact.ToString()); + await writer.WriteAsync(CsvSeparator); + // Type await writer.WriteAsync(log.Type.ToString()); + await writer.WriteAsync(CsvSeparator); + // Message + await writer.WriteAsync(CsvQuote); + await writer.WriteAsync(log.Message.Replace(CsvQuote, CsvQuote + CsvQuote)); + await writer.WriteAsync(CsvQuote); + await writer.WriteLineAsync(); } } From bfefb915749ccd3ba93dc0bf9dd2fb382be77540 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 30 Jun 2025 21:10:26 +0000 Subject: [PATCH 010/105] Automatic changelog update --- Resources/Changelog/Admin.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index b10997e927..62c8d88d0d 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -1233,5 +1233,12 @@ Entries: id: 149 time: '2025-06-29T16:21:15.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/35536 +- author: Kowlin + changes: + - message: Changed the way CSVs are exported + type: Tweak + id: 150 + time: '2025-06-30T21:09:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38531 Name: Admin Order: 2 From 0009ad32ab90395c1eab01e282f7c1f450c638e4 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Mon, 30 Jun 2025 19:33:59 -0400 Subject: [PATCH 011/105] Dsay Dirty and Follow commands converted to LEC and localized. (#38666) * commit * whoopwhoopwhoop --- .../Administration/Commands/DSay.cs | 57 +++++++++---------- .../Administration/Commands/DirtyCommand.cs | 22 +++---- .../Administration/Commands/FollowCommand.cs | 17 ++---- .../administration/commands/dsay-command.ftl | 2 - .../commands/follow-command.ftl | 2 - .../Locale/en-US/commands/dirty-command.ftl | 2 + .../Locale/en-US/commands/dsay-command.ftl | 2 + .../Locale/en-US/commands/follow-command.ftl | 2 + 8 files changed, 48 insertions(+), 58 deletions(-) delete mode 100644 Resources/Locale/en-US/administration/commands/dsay-command.ftl delete mode 100644 Resources/Locale/en-US/administration/commands/follow-command.ftl create mode 100644 Resources/Locale/en-US/commands/dirty-command.ftl create mode 100644 Resources/Locale/en-US/commands/dsay-command.ftl create mode 100644 Resources/Locale/en-US/commands/follow-command.ftl diff --git a/Content.Server/Administration/Commands/DSay.cs b/Content.Server/Administration/Commands/DSay.cs index 8e7f0f4bf0..f5e0b32793 100644 --- a/Content.Server/Administration/Commands/DSay.cs +++ b/Content.Server/Administration/Commands/DSay.cs @@ -2,39 +2,36 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.Administration.Commands +namespace Content.Server.Administration.Commands; + +[AdminCommand(AdminFlags.Moderator)] +public sealed class DsayCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Moderator)] - sealed class DSay : IConsoleCommand + [Dependency] private readonly ChatSystem _chatSystem = default!; + + public override string Command => "dsay"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "dsay"; - - public string Description => Loc.GetString("dsay-command-description"); - - public string Help => Loc.GetString("dsay-command-help-text", ("command", Command)); - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (shell.Player is not { } player) { - if (shell.Player is not { } player) - { - shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server")); - return; - } - - if (player.AttachedEntity is not { Valid: true } entity) - return; - - if (args.Length < 1) - return; - - var message = string.Join(" ", args).Trim(); - if (string.IsNullOrEmpty(message)) - return; - - var chat = _e.System(); - chat.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player); + shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server")); + return; } + + if (player.AttachedEntity is not { Valid: true } entity) + { + shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity")); + return; + } + + if (args.Length < 1) + return; + + var message = string.Join(" ", args).Trim(); + if (string.IsNullOrEmpty(message)) + return; + + _chatSystem.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player); } } diff --git a/Content.Server/Administration/Commands/DirtyCommand.cs b/Content.Server/Administration/Commands/DirtyCommand.cs index cc0b0fcec6..dd0b79291c 100644 --- a/Content.Server/Administration/Commands/DirtyCommand.cs +++ b/Content.Server/Administration/Commands/DirtyCommand.cs @@ -4,22 +4,18 @@ using Robust.Shared.Console; namespace Content.Server.Administration.Commands; [AdminCommand(AdminFlags.Debug)] -public sealed class DirtyCommand : IConsoleCommand +public sealed class DirtyCommand : LocalizedEntityCommands { - [Dependency] private readonly IEntityManager _entManager = default!; + public override string Command => "dirty"; - public string Command => "dirty"; - public string Description => "Marks all components on an entity as dirty, if not specified, dirties everything"; - public string Help => $"Usage: {Command} [entityUid]"; - - public async void Execute(IConsoleShell shell, string argStr, string[] args) + public override async void Execute(IConsoleShell shell, string argStr, string[] args) { switch (args.Length) { case 0: - foreach (var entity in _entManager.GetEntities()) + foreach (var entity in EntityManager.GetEntities()) { - DirtyAll(_entManager, entity); + DirtyAll(entity); } break; case 1: @@ -28,7 +24,7 @@ public sealed class DirtyCommand : IConsoleCommand shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number")); return; } - DirtyAll(_entManager, _entManager.GetEntity(parsedTarget)); + DirtyAll(EntityManager.GetEntity(parsedTarget)); break; default: shell.WriteLine(Loc.GetString("shell-wrong-arguments-number")); @@ -36,11 +32,11 @@ public sealed class DirtyCommand : IConsoleCommand } } - private static void DirtyAll(IEntityManager manager, EntityUid entityUid) + private void DirtyAll(EntityUid entityUid) { - foreach (var component in manager.GetNetComponents(entityUid)) + foreach (var component in EntityManager.GetNetComponents(entityUid)) { - manager.Dirty(entityUid, component.component); + EntityManager.Dirty(entityUid, component.component); } } } diff --git a/Content.Server/Administration/Commands/FollowCommand.cs b/Content.Server/Administration/Commands/FollowCommand.cs index b59a99b8b4..27ecbb99cf 100644 --- a/Content.Server/Administration/Commands/FollowCommand.cs +++ b/Content.Server/Administration/Commands/FollowCommand.cs @@ -6,15 +6,13 @@ using Robust.Shared.Enums; namespace Content.Server.Administration.Commands; [AdminCommand(AdminFlags.Admin)] -public sealed class FollowCommand : IConsoleCommand +public sealed class FollowCommand : LocalizedEntityCommands { - [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly FollowerSystem _followerSystem = default!; - public string Command => "follow"; - public string Description => Loc.GetString("follow-command-description"); - public string Help => Loc.GetString("follow-command-help"); + public override string Command => "follow"; - public void Execute(IConsoleShell shell, string argStr, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (shell.Player is not { } player) { @@ -34,10 +32,7 @@ public sealed class FollowCommand : IConsoleCommand return; } - var entity = args[0]; - if (NetEntity.TryParse(entity, out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid)) - { - _entManager.System().StartFollowingEntity(playerEntity, uid.Value); - } + if (NetEntity.TryParse(args[0], out var uidNet) && EntityManager.TryGetEntity(uidNet, out var uid)) + _followerSystem.StartFollowingEntity(playerEntity, uid.Value); } } diff --git a/Resources/Locale/en-US/administration/commands/dsay-command.ftl b/Resources/Locale/en-US/administration/commands/dsay-command.ftl deleted file mode 100644 index 4f9a7cc221..0000000000 --- a/Resources/Locale/en-US/administration/commands/dsay-command.ftl +++ /dev/null @@ -1,2 +0,0 @@ -dsay-command-description = Sends a message to deadchat as an admin -dsay-command-help-text = Usage: {$command} \ No newline at end of file diff --git a/Resources/Locale/en-US/administration/commands/follow-command.ftl b/Resources/Locale/en-US/administration/commands/follow-command.ftl deleted file mode 100644 index 3ef5fde075..0000000000 --- a/Resources/Locale/en-US/administration/commands/follow-command.ftl +++ /dev/null @@ -1,2 +0,0 @@ -follow-command-description = Makes you begin following an entity -follow-command-help = Usage: follow [netEntity] \ No newline at end of file diff --git a/Resources/Locale/en-US/commands/dirty-command.ftl b/Resources/Locale/en-US/commands/dirty-command.ftl new file mode 100644 index 0000000000..c3e7bc1c39 --- /dev/null +++ b/Resources/Locale/en-US/commands/dirty-command.ftl @@ -0,0 +1,2 @@ +cmd-dirty-desc = Marks all components on an entity as dirty. If not specified, dirties everything. +cmd-dirty-help = Usage: dirty [entityUid] diff --git a/Resources/Locale/en-US/commands/dsay-command.ftl b/Resources/Locale/en-US/commands/dsay-command.ftl new file mode 100644 index 0000000000..eef9747f86 --- /dev/null +++ b/Resources/Locale/en-US/commands/dsay-command.ftl @@ -0,0 +1,2 @@ +cmd-dsay-desc = Sends a message to deadchat as an admin. +cmd-dsay-help = Usage: dsay diff --git a/Resources/Locale/en-US/commands/follow-command.ftl b/Resources/Locale/en-US/commands/follow-command.ftl new file mode 100644 index 0000000000..04c805bc50 --- /dev/null +++ b/Resources/Locale/en-US/commands/follow-command.ftl @@ -0,0 +1,2 @@ +cmd-follow-desc = Makes you begin following an entity. +cmd-follow-help = Usage: follow [netEntity] From 89f982fe1c24dd66d6d29d7766db668f2eba73ad Mon Sep 17 00:00:00 2001 From: Nox Date: Mon, 30 Jun 2025 16:49:44 -0700 Subject: [PATCH 012/105] Retro laser sprite fix (#38676) * Fixed everything except the icon Signed-off-by: Nox38 * fixed icon Signed-off-by: Nox38 --------- Signed-off-by: Nox38 --- .../Guns/Battery/laser_retro.rsi/base.png | Bin 2204 -> 518 bytes .../Guns/Battery/laser_retro.rsi/icon.png | Bin 2316 -> 912 bytes .../Battery/laser_retro.rsi/mag-unshaded-0.png | Bin 2201 -> 142 bytes .../Battery/laser_retro.rsi/mag-unshaded-1.png | Bin 2246 -> 168 bytes .../Battery/laser_retro.rsi/mag-unshaded-2.png | Bin 2277 -> 171 bytes .../Battery/laser_retro.rsi/mag-unshaded-3.png | Bin 2280 -> 171 bytes .../Battery/laser_retro.rsi/mag-unshaded-4.png | Bin 2323 -> 182 bytes 7 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/base.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/base.png index 5833e7876af99ec98d19db31dbbc9e9e6cbb5701..8a94ea7a87dd716fe6106b92a82971d5b59f0071 100644 GIT binary patch delta 493 zcmVa zz)2d%i1p9VCA`F~pdgfDm#%`JK!k$r=V=|?I+O}_tW%}n;B4~{I^~goqErlYeI06o znwK}!E#qZl~VP9gip{QwrL&t^z+p^GT zG(uywEej@N_*yQv>a|*p13<6W+cM%MpePDv^SN)}?d1T^A9WNp4P(QA$yk^^L@&an zU(IYL<2&ma(0_GZIBYQ20ZfI1|AU*v-`^l4U$~yLdPO-mdH3Ioq~j+qSR&&y99DFPHgQE+-UM(rEyI z<2b$qO~z2j=keO_2Y&@o_+G6-#Ydx&FhNSGL@5oN8)hj1LI}UARxz7SJ#mvU@7hYG z65lZqnMgmCF!6l}9dc;#Py@#h4>WKr@lXT1wL^%<#Kgn^zz^yr(*`t37C-<101jnX jNoGw=04e|g00;m8000000Mb*F00000NkvXXu0mjf*c#Q! delta 2193 zcmV;C2yXX=1e_6&BYyaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|KlH@iF zyz>=)0tpaYo&#Jmu^!jcI>YB&G+d%3@G5c%Yyg3~Dv@*?NU4LwB^=<-aD5f$;-KOPVG ztu@M8^TVK%lbS8C6WzV4404MLq63&dDV4n9`aTc$>gSCNFoAV8e8VHE55W@%> zR+xM2p(DgdlQKr44#Z7XI8&t#G6F|C!=miC^56m{I+$aK>53(6zt#M~S%K#fph*G7 z!143xUIm|?PlndAG7rI*3oFD$R$mCin6oRiKuB08rhl^W4el8H>tVz)7?cfjL4xYr zVWLU6*A{P{*^7f}^v8Y)d7K6S5qt}R2@D2&3M?T7pNVn^z_EZIMdZYh8W;%Tga)Fd zi0TJ9h0Hge$zkh~&>=>90TF^Nl0i*n1z9mlOxSM)C8SPRqKG8PQlyF|PBBSJDJSbw znmNZTIe+DxORiZ9msq5vl1nMIXr;<%W8!M6xt3b1Dx7Lm*iz^#1dSTE*rcVFTWPgv zNBQ*FrKg^I>9y;i!2>P8jWqHoqYj;6qLgNwGSken%sO?U))ue0WTll?S#{~f+R5rO zYp=}xH*4W!jW$uHm+!1Wob$~@uy!KG85pA&z<+o)22jvsocR)BBxBAv^Oe{!3n5A| zaz-%5z+jw#WQB{nJ9A(1=78?c@<#8Nb4J~FFz1ZA2j+g{?G0-~ce~|HknKWXiVn%x zeo&Z2si?h|J{sMp5B@Rq+Zbvn(LI}Unrwx32*+@?4dA6K(7Uo#n)ak2$Qtg62x7AyGCEfxC=1Y5Ok{0^+pq1G^&ZYJyWNm<8Z%B}Ogxjg1hH%GEX@6{G004NL zeUUv#!$2IxUt3E>TO7wjIGXL+Cdb3~M)$pD{7Jj-;$B3>t+-n4Yi`@{mPNDA>e z@t8puB!1+&?D8AuvcrC!DHyrT9I-$wmb+N)VpcI!;wj>oqH2`y&%3N}-r}s*>a2ZF z{=#rkTh4Nw<}i|2L<(t$kWoh!HCTw#s*z$ML;DF2f7J1($t9Dk3V%k9d2B$1!6%3MYWzi*0|50HIx=)v)dFW7}?>0D))VO6&MHn!wB_>5YySI|2r_fs5;o zChq~4JHXJBE*X*|1!($9CE)#xzNr8V-U5BAZg1^T2l*I5-4G%apz5@$TO4 z-u^w)?(YXhrE-;Vl7CGf00006VoOIv0RI600RN!9r;`8x010qNS#tmYE+YT{E+YYW zr9XB6000McNliru+ZbMbi42J9`CR3 z=Y8Jic{vCaC{Q2|sj4beRTZmRFL^EA&gB5OyT4~Mne=7aF$@3{MFBwG*Z|<-^3vuP za@*wW^iqcRO_;fL5y|xdIf6MN7Ee-rvpdLOw6ziNs8R zmtGHmOe!^Nntusm14zVT^!j~-WIb#qmEx({G{ZYf6Z4~Vne*En+qf*t42Q$t2z+iy z;v{q6dt<-4ebq>(oyRNy;kJ-yUjd+Ln)q+!jK*V2>y)6AJg{9sqtO5$9*>)SyOlE9 z2OJ+BG8&J~__n5t ToECim015yANkvXXu0mjfXa*$l diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/icon.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/icon.png index f3cba12470477e5b65672232cb5e400424c88f93..bbd544a39468ecfa19bcc51a0514ce392899bdf2 100644 GIT binary patch delta 890 zcmV-=1BLvI5|9UwBYy#YX+uL$Nkc;*aB^>EX>4Tx04R}tkv&L4Q5c4wd(DbS9CC48E7?hfBXaQRqj<<9D~-Np`RtIp{2RjhSnem`hjR_Y$|GrxN%fa zBKwx}@SgAeINy6fuI6>q=@n|9zaf~;q4TB zN$9(Qp4ED8jeAb+Azp#SYuG=4;SBiK+U(ukn%loUjeq=p07y)7mRH+{(*OVgvq?lj zR9J=WlRs<1Kp4iKfPz?bYsC78(j`3=7eS#=M2F5oKY~!O{XE5QP^eh2V;u@oaFCAH zL+DUE3@A#)K!+~ZK@*J0X{hLw-;(6L_ul8ZH}?WAE-o$t2qByh!uP%3V;8(BmpK58 zr&B13!hieyJ^&ydi#ZY>Fow&E3;mN*N+m}IbjNS)wr%q1YZGbT;yvv(ubmt%o?)Ma zjQ8BMc2}wJ`)bwJglAPal}HFr)$R50RlLG)Bmw|<7v!nKA;1{EXERg0R4Q=*Xfzro zBSr^gS;lxWu@t<`w^0AMMkc*0Gg&*Iyhhq@mLHm&8Bz?obWTB zZ*vsybUL;jq?AgOQej<39Uz48VxfTXXk>^F7&CrbHk;*ZCLFVM!#43<*;r)X;u{Sd zLR@IzP~sa6tjG2t?&9L&0swz(-_W)Rrhha5000hUSV?A0O#mtY000O800000007cc QlK=n!07*qoM6N<$g0G;NGynhq delta 2305 zcmV+c3I6tw2aFPsBYy=tdQ@0+Qek%>aB^>EX>4U6ba`-PAZ2)IW&i+q+U-|clH@21 z{O1&V1SAlG4u9cdt~F%QT3RU) zS8lnn;ibmwx>}0)JkQ1VC-mRQ!{Y-(l+dQDTh^^_kjry`=6_q>-^zoI+fKa=-5*{I zCZE}7o41pj?vy)3J|!|9fje2(8i>9t41kD2+kM^mH5 z*Vk+O_N;raYkzf?O8{KuUewD{&Knc~X-;QY!L9fS-u2uKca0VYSesaC53!@uh=KT~ zOp}Z@tMg78d6I$Rj@L^T!NS%zR;Ps`FxnHV&+NE zWP&kp{Pqs-1>e2j7~0#zoG8`@R`82GzTk#4=TB&X5P#Y?rgHG5a5eG$<-{g1C z1zPNvi7xbvt#o)!Q36zRyz+%~-Ua{><`y_Z2@J%7@TNjhnUx4QR`6r+oKxlw21tVN zgqNICDj=t_&y6ukN0)^!G0F>wkW`Q)6$BZ`%2{$jzEy;f1xb=cq=-tDCRS3(MM^1J zyiS=W&3`IdRJCeTtEuKHwN$OOwrY)ALK&0LO4C+bYi5|#vcZ-?-yrDRQ_o#`>Dp^= z-3G#EdCM+acinB9W}xt=~*gIM*&1bI0T=M0Q-CVw!l&Hw_MowHaeXLjbCv)DKVR4Im+ z;^a(n#=u}+#IotZ-IKX5c?&@IS9#;lmG-yQhJ(Er9zM~I%cwU)~^^-DNs@NR18VkfKL==5kcrdGmb5i#uD zGk>Yt%#Yb-<30*LMmw&3*@o!a`8Yq#c0y8QI&F++0b`rj`eDf1DI?FarlJP!*tS%p zVCl5_Ld|YncTr?iZ(|PV^)hX*j6U+;FpZ!9Y*d4-edAD2Sq&-Gv+kL^V79&&Dr7|! z!7L3^f@XhL2R-1f|FvXA4`a=pHXx)wSphg}Qs z?iNa$C>(tmY8C(yMcF|)>(OnA+oDl%`oQ``GtPYP-eq)AGYKw-58cP*iE@kjEd*8D z7p8=X-M03&MggR75w#JJ?$JjttLa?8sC0my&&cY=P(ByfDLk(y&VN%B1gYT!hkq7+ zxH}ku%4SOtFo=^H5Ix!M4h}wcugJap`u#Q)2L>X{WpxSG2f)MTh0f?}i%mV=&Q;3J zUa7e+U)aN#tV(0O!zw&G?mo}ANYS&UH3b2PzoT86ES<2Kyv;GtaoB;MF{NQ}br*y- zdEHNJ0}cY#z2L&;*=>5{G+qN#V1ENu5ATIsJ3M0r$g?eDVeb(@R_#hZ-nT#FQ3R~Q z4+j~Lc6e9l_#0lmKVRLrN5sbkeq1o@R*@0EX>4Tx0C=2zkv&MmKpe$i zTWdvHI@m$PAw%nAK~%(1s()An3#F~ls)Na;U(lo>NpW!$Tni3^-MA$~P%l+J+BP16M26zPGIi~3*@dokCrm1n>Cyua+D1Q^56OZe3LE=ZQ zOAfzrF5B$onGrpgnJ11A3*{b`dYDyog?O4cDl01Gd-D#sElHTlU(IX(d4P0DzHE9pH+yRE4 zG*K6A$w$*$Dgp0j^i2g|=oT1Ub9(FSe@vRQBW;2 z5`*3#d!H6Tj}W!3AeA6UY!jgjNDC*EEGU#BXmMMlljF?jShkzr<_!1W`OdlLTn0RO z^5kiVR80;EzYQ@UPWUybjLnH9p3 z$iV0y>UGd{60z8zWd?`^AQB2uZ!{2+Ia`TXjN5YANPq7jb)Bc zGVnetiS5L?>x12@@SG(cx1Tcs_^U#qdJI4|n-zcUoL0MSvUUa9tpm#ylu9K4!r`zn zmd<1-WVU!pZ_;YFjp9-ig~>p`(TSaU3vgf?uC1<$nyy<~ucqq+I!>F9kG2qZ_xD_1 zT}f`T<$BnLC#R=UZ^iaUkW40p91Nmqng!y$)pC7ZzF`acQ`U73P%IWDfC;}}Oh=;z z#PZS-fUw&;(n~n%liLd+2ZNmFatwnQ8^CWN#tQHoh_M5V3gPJvg diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-0.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-0.png index 36ef0cea023526f2ce5a199cf707f582dd0f9c94..9c47712c1bb7ae6d5c1f7723359138157c9bdcf7 100644 GIT binary patch delta 114 zcmbO!*vB|QIh%pAz$3Dlfk96hgc&QA+LtjfFsOODIEF;DzCFjt%b>u+yn%B^?H4{t z{w1LoSQvf;PM+tvU7q29wBET;=J{RsBTfKy@TEq0ruq6ZXaU(AKnwzxf+vG0Pgg&e IbxsLQ03-aB^>EX>4U6ba`-PAZ2)IW&i+q+U-|alH@21 z{pS>O1V9MEal{reH<;tk6Lvb6&YFqNuAh!*yV8IxYk5z|E;s-Ad%3@G#OSk2EG5^R zJ&sgUjfzR}$8n6or+wW=Ja1wBBzM=12oYhVW0~ivuaNWo0e?xSygkdE^wUl`4F&(? zn#{A!#~I{lh~gm+=i1ft0nHEToWIylv$wQf)=2=yVA!MR;-o-+U*qA4j-TSkxCSCq z#Hd7+kL!>4xeK~C0A8~f{QNC4y2Ei8x}}w0a609IU*vSTiBA!QczKSG5f%30ACCw8 z)*5B4d1R*vb$?V-K9jnovS(0ifRpxP8K>aKn9DvZ&f?W~ur`otbG~6wLj>Y0q%eYp z73Lm$=m;^z83kjE9f+H(ki;50$Ox3|3@eJGN`nem>0pi^j#n&U`>o~=&I&w_0L>U+ z3>-h7?p5&V`DAD_uQqIUb~JsXrKkSk%x>j>d+Y`N@=FaGf$ai)~O4%wrHirD=%4P)uk6}C#%n_ zy)yUTtc8=cxQQ}7xw8hb$jwBscEZLP7>g-@aepxeP|(ph^ChGdjXC4Y*GP_tBcfy@ zX9Qym45k?(uW)g9XYNbh9MJt)-r_svoKg23%sHd(fw>=fd&An$-EL_UWV;ZUqC*n4 z9~5TMSk&H2AC2zQ2mcuQZ45P(=$_3vO}0Wigkv~cQpFN)vhu;Ac`cr5c85jOur0S! z(SMOHZ==T6Gj4j_p?x_zZ`x@GKU5cCQ>3s*?{@-ysrCA2gGGM@$ zN&qC`oR`UFOgG_Q&hdggGE+2XKnY`ubuiiyHFOw8whKJwwk+7Zhy)E6Z1S?iE@KWP z`6$mN)RsU4NWsd7t}pM3kb*0G~)a%XGscUMHU3v~7jtCxGCKZGVgap-aaCz|1GL_glBfiB2^J}K3dVG24?)z)jtNGGZXR9#PlupCA?Rv{ zD1sodTQ~;M!MQ{c^7qvay49L>d$jzluK5a7cw0FcvZPgqq|odC)0ZH#7pJmS&~~de7vjCq;N|(**J-)h(9Lq@4zk%S!qyg=ra2(S{l4#Xt$7XTbUL=n z3=UAKTU6-wdPE`-VzC&}XmnbvvdnNew8sAlV4e)az?k{ng!~CH8jXBItg#|33$ZeQ vWg%7yuna`_KR)5Vy-uwb{MQ5u6v$Oy5uwWi8)`c900000NkvXXu0mjf-xM5V diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-1.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-1.png index c456d45dcb4aa35c9dd9a7b9b6fe70c0c03912df..2b59b5aa0ab6630734e89527344f7b92145dafff 100644 GIT binary patch delta 141 zcmX>mxPozlayaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|cmgFW3 z{bvM z!wPe^J#@I3;*5ee#ty_yR!Cxv9b^Omk29<&jw%f*V5NgOf;irN3EOTpdoWgDc?8Ui z0m{Jf^XXm%Up=1`tz~H*f-iTh;8(Q#f*Z!1-7yP$1>b`?HXVg6~_akrbur_orx3meeDg>rj zAqnM&3A1P{YWvccTKCl#e=GXmC~8R2-J5foY=w3S$8a{JiXnEg@`XY3T0GV4E{(`x z8-H%2q9fg{jT&3ec<6Pz_F?P1%}(3-p}Gh~k-~1h-vRWcw$^uLEDwx|%5!+^r!yB_ zIhYdaqV8$*Ho%er=LT-2O_en!4SX|p*p+3k_M^tDkGsn1Dm#$ zQPJ7FRSPgt^^*-`-5|g88x|Y4IH}1Euz!OW>j@n-uai2@2*aj(360Vf-w<%lPr-tK z1t?3F=nlX->vew*K0T{N4s7tTlZ0MFDQg+8E~jdj7>Hd^mvmI26Ec3^j9Z9rRpz{))VXKn+cXQUpIg?|uY z3mLx+^FWR*h0ff%Tb7vHVITxJvQ&nvvk*@i+__NCG9YeaG%hPiSj8^||Y_^v*-o#h~cttmF%U=9yx5Pvs_UU&mF;cm$QOze>&0Wylptg-!N`PtU}EX>4Tx0C=2zkv&MmKpe$iTT4Y-9LylaAwzYtAS&W0 zRV;#q(pG5I!Q|2}XktiGTpR`0f`cE6RRs_2@d7t}p zM3kb*0G~)a%XGscUMHU3v~7jtCxGCKZGVgap-aaCz|1GJ-<_?0m)zJ>6gLlw+AKrluf|nq;>L7|BSn49u5GW#z$6_g1`y+03&_-ht z8*1J1LP&DXch2{m?}r2e1qu{sj8s)cRn>o6FO6Hgwz>+yf5qh`ON)!XoHk4o07X#% zkmu(C*grUM*oM6}*)EkhJv+0F9iNdfv$8NTyP*0M*ZEJ_-S*iIz@}jg+qIPJmP*foL`vO7`q%=`^>snibyPG;&_Z z9I|)5?wFTlf01$M$+*wi0A}h#s2>4PE|>q@Io)2*c6Te# zQ5`r^P_0%0NG6lkSfN-P7Ardx@0X=+uV)pPqA1M8411Y_^$~RD3GV#0ZWU{W_&x-#Q*>R07*qoM6N<$f`f=9qW}N^ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-2.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_retro.rsi/mag-unshaded-2.png index 216d3e5cad85e3910ad41450ae44bc1c2cc98743..e6caa1505fdf0e7b35c425ba790e889adc6cb8f1 100644 GIT binary patch delta 144 zcmaDVxSDZ-ay8LHo p&q&(^uYkt!rABzB`T8aB^>EX>4U6ba`-PAZ2)IW&i+q+U-|clI$i7 z{bvi*oS*lhzc7ScJAaEJZZpBDbWLBu6w(OOz5 z5l3#hQAel7>$ut!^SPgc?nf9u$;0CTLBweJ8kT*}?~u#;3xAq#`FNHGowuHPD@yTc zY4(-9ziuOMMNF4G-Q&>i7kc^N&VA9m)xNp)GR_JxmOvjdlqY!^8nNFEk2H#U<$LIUCLzdz@fx!PODsz@Q}p;+Aq+ zsV7VOv@=bZm}!%uC7M9oWtEj0O^}f|`>`gZnBmO%9kW14vVR*>Irye=9(NP3SgK0I@jfT=lN`I2uD%q5{qjPe2^1Sz7Rrf~;ZIZH0cw~7$zL0Gbg6j7@Y1(RQt#>TibBC^u`5l5mgGU}R%Ft0q z8+{^tW}Y(3)LCbnebM5D5)f8dy6S4H@3aw0J8#)#>#n=)ZiqEw%O+M#ty;7GVC`o0 znYCBu{++dSvqpy~pQrDvL9F_wB6&Fx=M0QdPJdurodEJP0zX>=m(}?ozvz zW-+YHM>FHuOxi z&DS)fYadC*Kz)&gD%A{SN_dWm`ZX3#)PIHQ;P(LI7ZhVBaD2wG?WMn^k0mskLx+LC zR|YE8P36)(YOthrU}0CjrWGc@p*En}V4G|ing^UT7JL!W1JjMFq+DQf8Mud3uq-;$ zmBr#M1jif)xdP%Q02$vw34o`&U$-2OPB?i#d>nk}U!HZ8eh>v^CVdHt9S_tmfq%D# zC@I6-*ka5YP|p!8V(!?xGRtx6m$1 z(h}pkv<7XoRZxa?+TQSi*60i14#SgKnvjz|1SogB!AbVU9<};PGDS4Q`g8*Ff+7ok z{w17CH%AzNp74w(w?6MW5_0vze}Ck>LGPru=|1{QU*9VzzD!|>mL)9-5W%1zkO2sF z&tPo!>oONfG!xwJP73~60O!Qjr?IQX4vd1BReKaSk;j!vFvQglR)VP)S2WAaHVTW@&6? z004NLeUUv#!$2IxUt3E>TO7t+-n4Yi`@{mP zNDA>e@t8puB!1+&?D8AuvcrC!DHyrT9I-$wmb+N)VpcI!;wj>oqJL_X@6WreaNgpq z*6OT%PyWJiQCrS(o#rr-SVRhGh>%f76*X9h)2fkTB18KL4}aA0r^zLgs|rSrd2B$1 z!6%3MYWzi*0|50HIx=)v)dFW7}?>0D))VO6&MHn!wB_>5YySI|2r_ zfs5;oChq~4JHXJBE=(DcBL!&sOC{j_jJ~M=4Bi5Lt8Q=YeVjf3IqGWZ1~@nbM$44F z=JD>{?%w`A)9&vFMWu3;agt3R00006VoOIv0RI600RN!9r<0K(7=H(JNliruy48tEFm&-ZEFO7!%yq?XHNG2Wg2S1|tCt2?v4N`7K?xGoMx-#xO)|7zYbg}D3{9sBoYbxU0&CFy1s>; z-;|oImR($mqA(qg`#SNflI-Yfg~q`r>mdKI;Vst05v}_ZvX%Q delta 2248 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 Date: Tue, 1 Jul 2025 12:25:52 +0200 Subject: [PATCH 013/105] fix water coolers (#38681) --- Content.Shared/Storage/EntitySystems/BinSystem.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Storage/EntitySystems/BinSystem.cs b/Content.Shared/Storage/EntitySystems/BinSystem.cs index 3b57dd8fea..9009df3753 100644 --- a/Content.Shared/Storage/EntitySystems/BinSystem.cs +++ b/Content.Shared/Storage/EntitySystems/BinSystem.cs @@ -67,12 +67,18 @@ public sealed class BinSystem : EntitySystem private void OnEntInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { + if (args.Container.ID != ent.Comp.ContainerId) + return; + ent.Comp.Items.Add(args.Entity); } - private void OnEntRemoved(EntityUid uid, BinComponent component, EntRemovedFromContainerMessage args) + private void OnEntRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { - component.Items.Remove(args.Entity); + if (args.Container.ID != ent.Comp.ContainerId) + return; + + ent.Comp.Items.Remove(args.Entity); } private void OnInteractHand(EntityUid uid, BinComponent component, InteractHandEvent args) From bbf6f6b69c1cd85d3363a6089268899c10f05b47 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 1 Jul 2025 10:27:00 +0000 Subject: [PATCH 014/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8c9af293ff..3d67cec87c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Jacktastic09 - changes: - - message: Added the Solid Headband, available via hacked ClothesMate vending machines - type: Add - id: 8215 - time: '2025-04-17T13:43:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36650 - author: Hoodie42 changes: - message: The banjo can now be worn on the back or suit storage slots. @@ -3888,3 +3881,10 @@ id: 8727 time: '2025-06-29T16:21:15.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/35536 +- author: slarticodefast + changes: + - message: Fixed water cups not being able to be picked up from water coolers. + type: Fix + id: 8728 + time: '2025-07-01T10:25:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38681 From 9a87d3fce25a860bddacd2f2bfec2674c999d716 Mon Sep 17 00:00:00 2001 From: imatsoup <93290208+imatsoup@users.noreply.github.com> Date: Tue, 1 Jul 2025 18:49:15 +0000 Subject: [PATCH 015/105] Monochromacy typo fix (#38686) * fixes the typo * Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504 * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Locale/en-US/traits/traits.ftl | 4 ++-- Resources/Prototypes/Entities/Mobs/Player/clone.yml | 2 +- Resources/Prototypes/Traits/disabilities.yml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 44bfd9d923..d7ab6ca76a 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -15,8 +15,8 @@ permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($targ trait-lightweight-name = Lightweight drunk trait-lightweight-desc = Alcohol has a stronger effect on you. -trait-monochromancy-name = Monochromancy -trait-monochromancy-desc = You are fully colorblind, everything you perceive ranges from blacks to whites. +trait-monochromacy-name = Monochromacy +trait-monochromacy-desc = You are fully colorblind, everything you perceive ranges from blacks to whites. trait-muted-name = Muted trait-muted-desc = You can't speak. diff --git a/Resources/Prototypes/Entities/Mobs/Player/clone.yml b/Resources/Prototypes/Entities/Mobs/Player/clone.yml index 80db45bf00..9ca2bfaf6d 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/clone.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/clone.yml @@ -16,8 +16,8 @@ - NpcFactionMember # traits # - LegsParalyzed (you get healed) + - BlackAndWhiteOverlay - LightweightDrunk - - Monochromacy - Muted - Narcolepsy - Pacified diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml index b435379dbf..a5c1f54d6b 100644 --- a/Resources/Prototypes/Traits/disabilities.yml +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -45,9 +45,9 @@ cloneable: true - type: trait - id: Monochromancy - name: trait-monochromancy-name - description: trait-monochromancy-desc + id: Monochromacy + name: trait-monochromacy-name + description: trait-monochromacy-desc category: Disabilities components: - type: BlackAndWhiteOverlay From 49370410ad839442957cecb41cb003cbc27b37e1 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Tue, 1 Jul 2025 20:31:39 -0400 Subject: [PATCH 016/105] Validate `CloningSettingsPrototype`s (#38688) * Validate CloningSettingsPrototypes * Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Check EventComponents too --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Cloning/CloningSettingsPrototypeTest.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs diff --git a/Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs b/Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs new file mode 100644 index 0000000000..9edc115eee --- /dev/null +++ b/Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs @@ -0,0 +1,46 @@ +using Content.Shared.Cloning; + +namespace Content.IntegrationTests.Tests.Cloning; + +public sealed class CloningSettingsPrototypeTest +{ + /// + /// Checks that the components named in every are valid components known to the server. + /// This is used instead of because we only care if the components are registered with the server, + /// and instead of a because we only need component names. + /// + [Test] + public async Task ValidatePrototypes() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + var protoMan = server.ProtoMan; + var compFactory = server.EntMan.ComponentFactory; + + await server.WaitAssertion(() => + { + Assert.Multiple(() => + { + var protos = protoMan.EnumeratePrototypes(); + foreach (var proto in protos) + { + foreach (var compName in proto.Components) + { + Assert.That(compFactory.TryGetRegistration(compName, out _), + $"Failed to find a component named {compName} for {nameof(CloningSettingsPrototype)} \"{proto.ID}\"" + ); + } + + foreach (var eventCompName in proto.EventComponents) + { + Assert.That(compFactory.TryGetRegistration(eventCompName, out _), + $"Failed to find a component named {eventCompName} for {nameof(CloningSettingsPrototype)} \"{proto.ID}\"" + ); + } + } + }); + }); + + await pair.CleanReturnAsync(); + } +} From e63905ce5fda2041d724c6a39277c30870b24f77 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Tue, 1 Jul 2025 20:57:57 -0400 Subject: [PATCH 017/105] Add test of objective-related console commands (#36400) * Add test of objective add/list/remove commands * Not sure why we're validating test prototypes, but sure * We don't need a map --- .../Tests/Commands/ObjectiveCommandsTest.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Content.IntegrationTests/Tests/Commands/ObjectiveCommandsTest.cs diff --git a/Content.IntegrationTests/Tests/Commands/ObjectiveCommandsTest.cs b/Content.IntegrationTests/Tests/Commands/ObjectiveCommandsTest.cs new file mode 100644 index 0000000000..a77761a7d1 --- /dev/null +++ b/Content.IntegrationTests/Tests/Commands/ObjectiveCommandsTest.cs @@ -0,0 +1,72 @@ +#nullable enable +using System.Linq; +using Content.Server.Objectives; +using Content.Shared.Mind; +using Robust.Shared.GameObjects; +using Robust.Shared.Player; + +namespace Content.IntegrationTests.Tests.Commands; + +public sealed class ObjectiveCommandsTest +{ + + private const string ObjectiveProtoId = "MindCommandsTestObjective"; + private const string DummyUsername = "MindCommandsTestUser"; + + [TestPrototypes] + private const string Prototypes = $""" +- type: entity + id: {ObjectiveProtoId} + components: + - type: Objective + difficulty: 1 + issuer: objective-issuer-syndicate + icon: + sprite: error.rsi + state: error + - type: DieCondition +"""; + + /// + /// Creates a dummy session, and assigns it a mind, then + /// tests using addobjective, lsobjectives, + /// and rmobjective on it. + /// + [Test] + public async Task AddListRemoveObjectiveTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + var entMan = server.EntMan; + var playerMan = server.ResolveDependency(); + var mindSys = server.System(); + var objectivesSystem = server.System(); + + await server.AddDummySession(DummyUsername); + await server.WaitRunTicks(5); + + var playerSession = playerMan.Sessions.Single(); + + Entity? mindEnt = null; + await server.WaitPost(() => + { + mindEnt = mindSys.CreateMind(playerSession.UserId); + }); + + Assert.That(mindEnt, Is.Not.Null); + var mindComp = mindEnt.Value.Comp; + Assert.That(mindComp.Objectives, Is.Empty, "Dummy player started with objectives."); + + await pair.WaitCommand($"addobjective {playerSession.Name} {ObjectiveProtoId}"); + + Assert.That(mindComp.Objectives, Has.Count.EqualTo(1), "addobjective failed to increase Objectives count."); + + await pair.WaitCommand($"lsobjectives {playerSession.Name}"); + + await pair.WaitCommand($"rmobjective {playerSession.Name} 0"); + + Assert.That(mindComp.Objectives, Is.Empty, "rmobjective failed to remove objective"); + + await pair.CleanReturnAsync(); + } +} From 32a019c6b6d98291a5c33af18570507c40156a45 Mon Sep 17 00:00:00 2001 From: UpAndLeaves <92269094+Alpha-Two@users.noreply.github.com> Date: Wed, 2 Jul 2025 04:14:37 +0100 Subject: [PATCH 018/105] CC Genpop and other misc fixes (#37494) * First commit: genpop and AI satellite * Revert AI satellite, add representative locker. --- Resources/Maps/centcomm.yml | 3796 ++++++++++++++++++++++------------- 1 file changed, 2440 insertions(+), 1356 deletions(-) diff --git a/Resources/Maps/centcomm.yml b/Resources/Maps/centcomm.yml index 6405c65923..c5dd3ac46b 100644 --- a/Resources/Maps/centcomm.yml +++ b/Resources/Maps/centcomm.yml @@ -1,11 +1,11 @@ meta: format: 7 category: Grid - engineVersion: 250.0.0 + engineVersion: 259.0.0 forkId: "" forkVersion: "" - time: 04/24/2025 00:06:42 - entityCount: 9680 + time: 06/02/2025 19:48:10 + entityCount: 9753 maps: [] grids: - 1668 @@ -59,156 +59,156 @@ entities: chunks: -1,-1: ind: -1,-1 - tiles: eQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAWQAAAAADWQAAAAADHQAAAAABHQAAAAAAHQAAAAABHQAAAAABHQAAAAACHQAAAAACHQAAAAABHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAABHQAAAAAAHQAAAAACHQAAAAACWQAAAAACWQAAAAAAHQAAAAADHQAAAAABHQAAAAACHQAAAAABHQAAAAABHQAAAAADHQAAAAACHQAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAADHQAAAAACHQAAAAABWQAAAAAAWQAAAAABHQAAAAAAHQAAAAACHQAAAAADHQAAAAADHQAAAAABHQAAAAABHQAAAAADHQAAAAADHQAAAAADHQAAAAACHQAAAAAAHQAAAAAAHQAAAAABHQAAAAABWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABWQAAAAADWQAAAAAAHQAAAAADHQAAAAAAHQAAAAAAHQAAAAADHQAAAAADHQAAAAACHQAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAADeQAAAAAAHQAAAAACWQAAAAADWQAAAAACCwAAAAAACwAAAAAAHQAAAAADEQAAAAAAEQAAAAAAHQAAAAABHQAAAAABeQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAWQAAAAADHQAAAAABHQAAAAADWQAAAAABWQAAAAADHQAAAAACHQAAAAABHQAAAAADHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADeQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAADeQAAAAAAHQAAAAABWQAAAAAAWQAAAAADNgAAAAAANgAAAAAAHQAAAAADEQAAAAAAEQAAAAAAHQAAAAABHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAHQAAAAACHQAAAAABHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAABHQAAAAAAeQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAADWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAABAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABHQAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAABHQAAAAAAeQAAAAAAWQAAAAADWQAAAAADWQAAAAABeQAAAAAAHQAAAAABdgAAAAAAHQAAAAAAHQAAAAAAWQAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAACWQAAAAABHQAAAAADWQAAAAACWQAAAAABWQAAAAABeQAAAAAAHQAAAAADdgAAAAABPgAAAAAAPgAAAAAAWQAAAAACWQAAAAAAWQAAAAABWQAAAAADWQAAAAABWQAAAAAAWQAAAAADHQAAAAADWQAAAAAAWQAAAAABWQAAAAADeQAAAAAAHQAAAAADdgAAAAAAPgAAAAAAPgAAAAAA - version: 6 + tiles: eQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAABZAAAAAAMAWQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAIAHQAAAAACAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAEAHQAAAAAAAB0AAAAAAgAdAAAAAAIAWQAAAAACAFkAAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAgAdAAAAAAEAHQAAAAABAB0AAAAAAwAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAABAB0AAAAAAwAdAAAAAAIAHQAAAAABAFkAAAAAAABZAAAAAAEAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAADAB0AAAAAAwAdAAAAAAMAHQAAAAACAB0AAAAAAAAdAAAAAAAAHQAAAAABAB0AAAAAAQBZAAAAAAAAWQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAEAWQAAAAADAFkAAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAADAB0AAAAAAgAdAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAwB5AAAAAAAAHQAAAAACAFkAAAAAAwBZAAAAAAIACwAAAAAAAAsAAAAAAAAdAAAAAAMAEQAAAAAAABEAAAAAAAAdAAAAAAEAHQAAAAABAHkAAAAAAABZAAAAAAAAWQAAAAAAAHkAAAAAAABZAAAAAAMAHQAAAAABAB0AAAAAAwBZAAAAAAEAWQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAwB5AAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAADAHkAAAAAAAAdAAAAAAEAWQAAAAAAAFkAAAAAAwA2AAAAAAAANgAAAAAAAB0AAAAAAwARAAAAAAAAEQAAAAAAAB0AAAAAAQAdAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAABAB0AAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAgAdAAAAAAEAHQAAAAAAAHkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAQBZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAQAdAAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAABAB0AAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAEAeQAAAAAAAB0AAAAAAQB2AAAAAAAAHQAAAAAAAB0AAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAgBZAAAAAAEAHQAAAAADAFkAAAAAAgBZAAAAAAEAWQAAAAABAHkAAAAAAAAdAAAAAAMAdgAAAAABAD4AAAAAAAA+AAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAADAB0AAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAwB5AAAAAAAAHQAAAAADAHYAAAAAAAA+AAAAAAAAPgAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: WQAAAAAAHQAAAAADAQAAAAAAHQAAAAACAgAAAAAAAgAAAAAAHQAAAAABHQAAAAABAgAAAAAAAgAAAAAAHQAAAAACeQAAAAAAHQAAAAABHQAAAAACHQAAAAABHQAAAAABWQAAAAADHQAAAAADAQAAAAAAHQAAAAADHQAAAAAAHQAAAAABHQAAAAABHQAAAAADHQAAAAADAgAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAADWQAAAAAAHQAAAAAAeQAAAAAAHQAAAAABHQAAAAADWQAAAAAAWQAAAAABWQAAAAADWQAAAAADWQAAAAABWQAAAAACeQAAAAAAbAAAAAADbAAAAAAAWQAAAAABWQAAAAABWQAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAADbAAAAAABbAAAAAACbAAAAAADbAAAAAADbAAAAAACWQAAAAAAHQAAAAADbAAAAAADbAAAAAAAWQAAAAABWQAAAAABWQAAAAABHQAAAAABHQAAAAAAHQAAAAACHQAAAAACbAAAAAAAbAAAAAAAbAAAAAADbAAAAAAAbAAAAAACWQAAAAACHQAAAAABbAAAAAADbAAAAAADWQAAAAADWQAAAAACWQAAAAABHQAAAAACHQAAAAAAHQAAAAAAHQAAAAACbAAAAAACbAAAAAADbAAAAAAAbAAAAAAAbAAAAAACWQAAAAAAHQAAAAABbAAAAAAAbAAAAAAAWQAAAAACWQAAAAABWQAAAAACHQAAAAABeQAAAAAAHQAAAAADHQAAAAACWQAAAAADWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAACeQAAAAAAbAAAAAAAbAAAAAAAWQAAAAAAWQAAAAABHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADeQAAAAAAeQAAAAAAbAAAAAADbAAAAAADWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAACWQAAAAABeQAAAAAAWQAAAAABbAAAAAABbAAAAAABbAAAAAABbAAAAAABbAAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAABWQAAAAABWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAeQAAAAAAWQAAAAAAbAAAAAACbAAAAAADbAAAAAAAbAAAAAABbAAAAAADbAAAAAACbAAAAAAAWQAAAAADWQAAAAADWQAAAAADWQAAAAABWQAAAAABWQAAAAACWQAAAAADeQAAAAAAWQAAAAADbAAAAAACbAAAAAADbAAAAAADbAAAAAAAbAAAAAACbAAAAAACbAAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAbAAAAAADbAAAAAABeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAHQAAAAACHQAAAAAAdgAAAAACHQAAAAAAeQAAAAAAWQAAAAADWQAAAAADWQAAAAABeQAAAAAAHQAAAAADWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAABWQAAAAABPgAAAAAAdgAAAAACHQAAAAAATQAAAAAAWQAAAAADWQAAAAACWQAAAAADHQAAAAACHQAAAAACWQAAAAABWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAACPgAAAAAAdgAAAAACHQAAAAABeQAAAAAAWQAAAAACWQAAAAABWQAAAAABHQAAAAAAHQAAAAACWQAAAAABWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABWQAAAAAD - version: 6 + tiles: WQAAAAAAAB0AAAAAAwABAAAAAAAAHQAAAAACAAIAAAAAAAACAAAAAAAAHQAAAAABAB0AAAAAAQACAAAAAAAAAgAAAAAAAB0AAAAAAgB5AAAAAAAAHQAAAAABAB0AAAAAAgAdAAAAAAEAHQAAAAABAFkAAAAAAwAdAAAAAAMAAQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAMAHQAAAAADAAIAAAAAAAAdAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAMAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAEAeQAAAAAAAHkAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAMAWQAAAAAAAB0AAAAAAAB5AAAAAAAAHQAAAAABAB0AAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAMAWQAAAAABAFkAAAAAAgB5AAAAAAAAbAAAAAADAGwAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAMAbAAAAAABAGwAAAAAAgBsAAAAAAMAbAAAAAADAGwAAAAAAgBZAAAAAAAAHQAAAAADAGwAAAAAAwBsAAAAAAAAWQAAAAABAFkAAAAAAQBZAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAACAGwAAAAAAABsAAAAAAAAbAAAAAADAGwAAAAAAABsAAAAAAIAWQAAAAACAB0AAAAAAQBsAAAAAAMAbAAAAAADAFkAAAAAAwBZAAAAAAIAWQAAAAABAB0AAAAAAgAdAAAAAAAAHQAAAAAAAB0AAAAAAgBsAAAAAAIAbAAAAAADAGwAAAAAAABsAAAAAAAAbAAAAAACAFkAAAAAAAAdAAAAAAEAbAAAAAAAAGwAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAgAdAAAAAAEAeQAAAAAAAB0AAAAAAwAdAAAAAAIAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAIAeQAAAAAAAGwAAAAAAABsAAAAAAAAWQAAAAAAAFkAAAAAAQAdAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAMAeQAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAADAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAgBZAAAAAAIAWQAAAAABAHkAAAAAAABZAAAAAAEAbAAAAAABAGwAAAAAAQBsAAAAAAEAbAAAAAABAGwAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAAB5AAAAAAAAWQAAAAAAAGwAAAAAAgBsAAAAAAMAbAAAAAAAAGwAAAAAAQBsAAAAAAMAbAAAAAACAGwAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAMAeQAAAAAAAFkAAAAAAwBsAAAAAAIAbAAAAAADAGwAAAAAAwBsAAAAAAAAbAAAAAACAGwAAAAAAgBsAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAAAAHkAAAAAAAB5AAAAAAAAbAAAAAADAGwAAAAAAQB5AAAAAAAAeQAAAAAAAB0AAAAAAgB5AAAAAAAAHQAAAAACAB0AAAAAAAB2AAAAAAIAHQAAAAAAAHkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAQB5AAAAAAAAHQAAAAADAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAABAFkAAAAAAQA+AAAAAAAAdgAAAAACAB0AAAAAAABNAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAHQAAAAACAB0AAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAQBZAAAAAAIAPgAAAAAAAHYAAAAAAgAdAAAAAAEAeQAAAAAAAFkAAAAAAgBZAAAAAAEAWQAAAAABAB0AAAAAAAAdAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAADAA== + version: 7 -1,0: ind: -1,0 - tiles: WQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAACWQAAAAADWQAAAAADHQAAAAACWQAAAAACWQAAAAABWQAAAAAAHQAAAAACHQAAAAAAdgAAAAABdgAAAAAAdgAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAADHQAAAAAAHQAAAAAAHQAAAAACeQAAAAAAWQAAAAAAWQAAAAACWQAAAAADeQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAAAWQAAAAABWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAACWQAAAAABWQAAAAACWQAAAAACWQAAAAADPgAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAABHQAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAADWQAAAAADPgAAAAAAHQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAACHQAAAAADeQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABHQAAAAABPgAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAAAHQAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAACeQAAAAAAHQAAAAACWQAAAAABWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACHQAAAAABHQAAAAABHQAAAAADAQAAAAAAHQAAAAABWQAAAAADWQAAAAACHQAAAAABeQAAAAAAHQAAAAABHQAAAAADHQAAAAACeQAAAAAAHQAAAAABHQAAAAACHQAAAAACHQAAAAACHQAAAAACHQAAAAADAQAAAAAAHQAAAAABWQAAAAAAWQAAAAABPgAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAADeQAAAAAAHQAAAAADWQAAAAABWQAAAAAAPgAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAABHQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAACAQAAAAAAHQAAAAAAWQAAAAADWQAAAAABPgAAAAAAHQAAAAACPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAAAHQAAAAABHQAAAAABAQAAAAAAHQAAAAAAWQAAAAADWQAAAAABHQAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAHQAAAAADHQAAAAABeQAAAAAAeQAAAAAAWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACHQAAAAADeQAAAAAAWQAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABCgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAABHQAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAADWQAAAAACWQAAAAAA - version: 6 + tiles: WQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAADAB0AAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAAAdAAAAAAIAHQAAAAAAAHYAAAAAAQB2AAAAAAAAdgAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAwAdAAAAAAAAHQAAAAAAAB0AAAAAAgB5AAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAMAeQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAACAFkAAAAAAwA+AAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAwBZAAAAAAMAPgAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAgAdAAAAAAIAHQAAAAADAHkAAAAAAAB5AAAAAAAAAQAAAAAAAAEAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAABAD4AAAAAAAB5AAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAACAHkAAAAAAAAdAAAAAAIAWQAAAAABAFkAAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAEAHQAAAAABAB0AAAAAAwABAAAAAAAAHQAAAAABAFkAAAAAAwBZAAAAAAIAHQAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAgB5AAAAAAAAHQAAAAABAB0AAAAAAgAdAAAAAAIAHQAAAAACAB0AAAAAAgAdAAAAAAMAAQAAAAAAAB0AAAAAAQBZAAAAAAAAWQAAAAABAD4AAAAAAAB5AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAwAdAAAAAAMAHQAAAAADAHkAAAAAAAAdAAAAAAMAWQAAAAABAFkAAAAAAAA+AAAAAAAAeQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAADAB0AAAAAAgABAAAAAAAAHQAAAAAAAFkAAAAAAwBZAAAAAAEAPgAAAAAAAB0AAAAAAgA+AAAAAAAAPgAAAAAAAD4AAAAAAAB5AAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAEAHQAAAAAAAB0AAAAAAQAdAAAAAAEAAQAAAAAAAB0AAAAAAABZAAAAAAMAWQAAAAABAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAEAeQAAAAAAAHkAAAAAAABZAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAADAHkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAEACgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAHQAAAAABAB0AAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAAAAA== + version: 7 0,0: ind: 0,0 - tiles: dgAAAAABdgAAAAACHQAAAAADHQAAAAAAWQAAAAACWQAAAAADWQAAAAAAHQAAAAAAHQAAAAADWQAAAAAAWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADHQAAAAAAHQAAAAADHQAAAAADeQAAAAAAWQAAAAACWQAAAAABWQAAAAACeQAAAAAAHQAAAAAAWQAAAAADWQAAAAABWQAAAAABWQAAAAADWQAAAAAAWQAAAAACWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAADeQAAAAAAeQAAAAAAHQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAHQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAACeQAAAAAAHQAAAAADHQAAAAAAHQAAAAAAHQAAAAABHQAAAAAAHQAAAAABHQAAAAADHQAAAAABWQAAAAACWQAAAAACWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADeQAAAAAAHQAAAAABHQAAAAAAHQAAAAADHQAAAAABHQAAAAAAHQAAAAACHQAAAAACHQAAAAACWQAAAAADWQAAAAABWQAAAAADWQAAAAAAWQAAAAADWQAAAAADWQAAAAABeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAABHQAAAAADHQAAAAACHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAHQAAAAABeQAAAAAAHQAAAAACHQAAAAADHQAAAAAAHQAAAAABWQAAAAACHQAAAAADeQAAAAAAAwAAAAAAAwAAAAAJAwAAAAAAAwAAAAALAwAAAAAAHQAAAAADHQAAAAAAHQAAAAAAHQAAAAADHQAAAAACHQAAAAADHQAAAAADHQAAAAACWQAAAAABHQAAAAABeQAAAAAAAwAAAAAAAwAAAAAAAwAAAAADAwAAAAAAAwAAAAADHQAAAAAAHQAAAAABHQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAABHQAAAAABWQAAAAABHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAACHQAAAAADHQAAAAABHQAAAAABHQAAAAACHQAAAAAAWQAAAAACHQAAAAAAeQAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAABHQAAAAACWQAAAAAAHQAAAAACeQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAADeQAAAAAAHQAAAAACHQAAAAABHQAAAAAAHQAAAAADHQAAAAACHQAAAAAAHQAAAAADWQAAAAADHQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAACWQAAAAADWQAAAAACHQAAAAACHQAAAAACHQAAAAAAHQAAAAACHQAAAAACHQAAAAADHQAAAAADHQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAHQAAAAABHQAAAAACHQAAAAACeQAAAAAAWQAAAAACWQAAAAADWQAAAAADWQAAAAABWQAAAAAAWQAAAAABWQAAAAABWQAAAAABWQAAAAABWQAAAAADWQAAAAACWQAAAAACWQAAAAADWQAAAAADWQAAAAAAWQAAAAACWQAAAAACWQAAAAADWQAAAAAAWQAAAAABWQAAAAACWQAAAAADWQAAAAAAWQAAAAABWQAAAAABWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAC - version: 6 + tiles: dgAAAAABAHYAAAAAAgAdAAAAAAMAHQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAAAAB0AAAAAAAAdAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAADAHkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAgB5AAAAAAAAHQAAAAAAAFkAAAAAAwBZAAAAAAEAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAMAeQAAAAAAAHkAAAAAAAAdAAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAHQAAAAADAHkAAAAAAAAdAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAwBZAAAAAAEAWQAAAAACAHkAAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAAAdAAAAAAEAHQAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAwB5AAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAACAB0AAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAEAeQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAIAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAQB5AAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAABAFkAAAAAAgAdAAAAAAMAeQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAAB5AAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAADAB0AAAAAAgBZAAAAAAEAHQAAAAABAHkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAAAAB0AAAAAAAAdAAAAAAEAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAEAWQAAAAABAB0AAAAAAwB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAAAAHkAAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAQAdAAAAAAIAHQAAAAAAAFkAAAAAAgAdAAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAEAWQAAAAABAFkAAAAAAgB5AAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAIAHQAAAAABAB0AAAAAAgBZAAAAAAAAHQAAAAACAHkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAgBZAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAAAdAAAAAAMAWQAAAAADAB0AAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAADAHkAAAAAAAAdAAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAIAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAAAAFkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAEAeQAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAACAHkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAIAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAA== + version: 7 1,-1: ind: 1,-1 - tiles: HQAAAAACHQAAAAAAeQAAAAAAHQAAAAAAHQAAAAADHQAAAAADHQAAAAABHQAAAAADHQAAAAACHQAAAAACHQAAAAADHQAAAAACHQAAAAACHQAAAAABHQAAAAABHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAABHQAAAAAAHQAAAAACHQAAAAACeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAHQAAAAACHQAAAAACHQAAAAABWQAAAAAAWQAAAAACWQAAAAADbAAAAAACbAAAAAAAbAAAAAAAbAAAAAAAbAAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACHQAAAAACHQAAAAABWQAAAAADWQAAAAABWQAAAAABbAAAAAACbAAAAAACbAAAAAADbAAAAAABbAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABHQAAAAADHQAAAAADWQAAAAADWQAAAAADWQAAAAADbAAAAAADbAAAAAACbAAAAAABbAAAAAADbAAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAHQAAAAABHQAAAAABWQAAAAACWQAAAAADWQAAAAAAbAAAAAAAbAAAAAADbAAAAAAAbAAAAAABbAAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAACWQAAAAAAWQAAAAAAWQAAAAABHQAAAAACHQAAAAADHQAAAAADHQAAAAADHQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAADWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAWQAAAAABWQAAAAADeQAAAAAAHQAAAAAAHQAAAAACHQAAAAABHQAAAAACHQAAAAABHQAAAAAAHQAAAAABHQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAADHQAAAAADbAAAAAACbAAAAAADHQAAAAACHQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAADWQAAAAADWQAAAAACWQAAAAABWQAAAAAAWQAAAAADWQAAAAABWQAAAAACWQAAAAABbAAAAAAAWQAAAAACeQAAAAAAHQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAACWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADWQAAAAADWQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAACWQAAAAABWQAAAAACHQAAAAACeQAAAAAAHQAAAAACWQAAAAADWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAACWQAAAAADHQAAAAADHQAAAAACHQAAAAAAWQAAAAABWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAADWQAAAAADWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAADHQAAAAAAHQAAAAAAHQAAAAADWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAADWQAAAAADWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAADWQAAAAAC - version: 6 + tiles: HQAAAAACAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAABAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAQAdAAAAAAEAHQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAHkAAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAwAdAAAAAAMAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAACAHkAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB5AAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAMAbAAAAAACAGwAAAAAAABsAAAAAAAAbAAAAAAAAGwAAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAIAHQAAAAABAFkAAAAAAwBZAAAAAAEAWQAAAAABAGwAAAAAAgBsAAAAAAIAbAAAAAADAGwAAAAAAQBsAAAAAAAAeQAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAwBsAAAAAAMAbAAAAAACAGwAAAAAAQBsAAAAAAMAbAAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAWQAAAAACAFkAAAAAAwBZAAAAAAAAbAAAAAAAAGwAAAAAAwBsAAAAAAAAbAAAAAABAGwAAAAAAgB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAABAB0AAAAAAgAdAAAAAAMAHQAAAAADAB0AAAAAAwAdAAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAHkAAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwBZAAAAAAAAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAQB5AAAAAAAAWQAAAAABAFkAAAAAAwB5AAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAEAHQAAAAACAB0AAAAAAQAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAADAGwAAAAAAgBsAAAAAAMAHQAAAAACAB0AAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAADAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAEAWQAAAAACAFkAAAAAAQBsAAAAAAAAWQAAAAACAHkAAAAAAAAdAAAAAAMAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAFkAAAAAAwBZAAAAAAMAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAgAdAAAAAAIAeQAAAAAAAB0AAAAAAgBZAAAAAAMAWQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAQBZAAAAAAIAWQAAAAAAAFkAAAAAAgBZAAAAAAMAHQAAAAADAB0AAAAAAgAdAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAADAFkAAAAAAgBZAAAAAAIAWQAAAAACAFkAAAAAAQBZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAACAA== + version: 7 1,0: ind: 1,0 - tiles: WQAAAAACHQAAAAADHQAAAAABHQAAAAABWQAAAAAAWQAAAAACWQAAAAABWQAAAAADWQAAAAADWQAAAAACWQAAAAACWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAADHQAAAAACeQAAAAAAHQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAACWQAAAAADWQAAAAACWQAAAAABWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAWQAAAAACWQAAAAACWQAAAAADWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAHQAAAAADWQAAAAADWQAAAAABWQAAAAABWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAABWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAHQAAAAADHQAAAAAAHQAAAAAAHQAAAAACWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABHQAAAAAAHQAAAAACeQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAABHQAAAAABHQAAAAABHQAAAAABHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAABHQAAAAACHQAAAAACHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAADeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAHQAAAAADHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACHQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADeQAAAAAAHQAAAAABPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAAAWQAAAAADWQAAAAABeQAAAAAAHQAAAAACdgAAAAACdgAAAAADdgAAAAACdgAAAAABdgAAAAABdgAAAAACHQAAAAADHQAAAAADHQAAAAABWQAAAAADWQAAAAAAWQAAAAAAWQAAAAADWQAAAAABeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAADdgAAAAADdgAAAAACdgAAAAABHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAWQAAAAACWQAAAAACHQAAAAADHQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAABHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAADHQAAAAACHQAAAAAAHQAAAAABWQAAAAACWQAAAAACHQAAAAADHQAAAAACHQAAAAACHQAAAAADPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAAD - version: 6 + tiles: WQAAAAACAB0AAAAAAwAdAAAAAAEAHQAAAAABAFkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAwBZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAwAdAAAAAAIAeQAAAAAAAB0AAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAwBZAAAAAAIAWQAAAAABAFkAAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAMAWQAAAAACAFkAAAAAAQBZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAHQAAAAAAAB0AAAAAAAB5AAAAAAAAHQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAABAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAIAWQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAAAAB0AAAAAAgBZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAQAdAAAAAAAAHQAAAAACAHkAAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAACAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAMAeQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAeQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAHkAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAdAAAAAAAAHQAAAAAAAHkAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAHkAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAB5AAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAHQAAAAADAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAAAWQAAAAABAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAHkAAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAAAHQAAAAAAAFkAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAB5AAAAAAAAdgAAAAACAHYAAAAAAwB2AAAAAAIAdgAAAAABAHYAAAAAAQB2AAAAAAIAHQAAAAADAB0AAAAAAwBZAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAeQAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAADAHYAAAAAAwB2AAAAAAIAdgAAAAABAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAEAeQAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAgAdAAAAAAEAHQAAAAACAB0AAAAAAgAdAAAAAAMAHQAAAAACAB0AAAAAAAAdAAAAAAEAWQAAAAACAFkAAAAAAgAdAAAAAAMAHQAAAAACAB0AAAAAAgAdAAAAAAMAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAADAA== + version: 7 2,0: ind: 2,0 - tiles: WQAAAAADeQAAAAAATQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAHQAAAAADTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABHQAAAAACTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAHQAAAAABTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAADHQAAAAAATQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAACTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAPgAAAAAAHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAADdgAAAAAAHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAADdgAAAAAAHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAADHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAABHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: WQAAAAADAHkAAAAAAABNAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAAAdAAAAAAMATQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAEAHQAAAAACAE0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAB0AAAAAAQBNAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAwAdAAAAAAAATQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAAAHQAAAAACAE0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2AAAAAAMAdgAAAAAAAB0AAAAAAgB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAADAHYAAAAAAAAdAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAIAHQAAAAADAB0AAAAAAQB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,-1: ind: 2,-1 - tiles: HQAAAAABHQAAAAACHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAADHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAACHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADHQAAAAADHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAACHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAADTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAHQAAAAACTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABHQAAAAAATQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAHQAAAAACTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAHQAAAAACTQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACeQAAAAAATQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACeQAAAAAATQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: HQAAAAABAB0AAAAAAgAdAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAEAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAACAB0AAAAAAQB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAADAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAMAHQAAAAADAB0AAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAAAHQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACAB0AAAAAAwBNAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAAAdAAAAAAIATQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAEAHQAAAAAAAE0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAB0AAAAAAgBNAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAAAdAAAAAAIATQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAIAeQAAAAAAAE0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACAHkAAAAAAABNAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 1,-2: ind: 1,-2 - tiles: bAAAAAABbAAAAAABeQAAAAAAHQAAAAAAHQAAAAABHQAAAAABHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAABbAAAAAADeQAAAAAAHQAAAAABHQAAAAABHQAAAAABHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAACbAAAAAABeQAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAHQAAAAABHQAAAAABHQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAACWQAAAAACHQAAAAADHQAAAAADHQAAAAABHQAAAAADHQAAAAABHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADBgAAAAAABgAAAAABBgAAAAAAHQAAAAADHQAAAAADWQAAAAADHQAAAAADHQAAAAADHQAAAAADHQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAAABgAAAAAABgAAAAAABgAAAAABBgAAAAABBgAAAAAABgAAAAADHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAABBgAAAAABBgAAAAACBgAAAAAAHQAAAAAAHQAAAAACHQAAAAADHQAAAAAAeQAAAAAABAAAAAAABAAAAAAAeQAAAAAAHQAAAAABHQAAAAADHQAAAAACHQAAAAAABgAAAAABBgAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAACeQAAAAAABAAAAAAABAAAAAAAeQAAAAAAdgAAAAADdgAAAAACHQAAAAABBgAAAAAABgAAAAACHQAAAAAAHQAAAAABHQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAAAeQAAAAAABAAAAAAABAAAAAAAeQAAAAAAdgAAAAAAdgAAAAADHQAAAAABBgAAAAACBgAAAAABHQAAAAADHQAAAAABHQAAAAABHQAAAAACHQAAAAADHQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAdgAAAAADdgAAAAADHQAAAAAABgAAAAAABgAAAAAAHQAAAAABHQAAAAACHQAAAAADHQAAAAACHQAAAAADHQAAAAABHQAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAABHQAAAAADBgAAAAADBgAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAADHQAAAAABBQAAAAACBQAAAAAAHQAAAAABHQAAAAABHQAAAAABHQAAAAABHQAAAAADHQAAAAAABgAAAAAABgAAAAADBgAAAAAAHQAAAAACHQAAAAADHQAAAAADHQAAAAABeQAAAAAABQAAAAACBQAAAAACHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAAAHQAAAAADHQAAAAABBgAAAAADBgAAAAABBgAAAAADBgAAAAABBgAAAAADBgAAAAABHQAAAAADBQAAAAACBQAAAAABeQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAAAHQAAAAACHQAAAAAABgAAAAACBgAAAAABBgAAAAACHQAAAAAAHQAAAAAC - version: 6 + tiles: bAAAAAABAGwAAAAAAQB5AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAAAAAAQBsAAAAAAMAeQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAAAIAbAAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAgBZAAAAAAIAHQAAAAADAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAADAAYAAAAAAAAGAAAAAAEABgAAAAAAAB0AAAAAAwAdAAAAAAMAWQAAAAADAB0AAAAAAwAdAAAAAAMAHQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAQAdAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAEABgAAAAABAAYAAAAAAAAGAAAAAAMAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAwAdAAAAAAEABgAAAAABAAYAAAAAAgAGAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAAAAHkAAAAAAAAEAAAAAAAABAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAABgAAAAABAAYAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAMAHQAAAAADAB0AAAAAAgB5AAAAAAAABAAAAAAAAAQAAAAAAAB5AAAAAAAAdgAAAAADAHYAAAAAAgAdAAAAAAEABgAAAAAAAAYAAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAAAeQAAAAAAAAQAAAAAAAAEAAAAAAAAeQAAAAAAAHYAAAAAAAB2AAAAAAMAHQAAAAABAAYAAAAAAgAGAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB2AAAAAAMAdgAAAAADAB0AAAAAAAAGAAAAAAAABgAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAAYAAAAAAwAGAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAMAHQAAAAABAAUAAAAAAgAFAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAwAdAAAAAAAABgAAAAAAAAYAAAAAAwAGAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAABAHkAAAAAAAAFAAAAAAIABQAAAAACAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAQAGAAAAAAMABgAAAAABAAYAAAAAAwAGAAAAAAEABgAAAAADAAYAAAAAAQAdAAAAAAMABQAAAAACAAUAAAAAAQB5AAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAAAGAAAAAAIABgAAAAABAAYAAAAAAgAdAAAAAAAAHQAAAAACAA== + version: 7 0,-2: ind: 0,-2 - tiles: HQAAAAABeQAAAAAAHQAAAAAAeQAAAAAAAQAAAAAAeQAAAAAAdgAAAAACdgAAAAABdgAAAAACdgAAAAABHQAAAAAAeQAAAAAAWQAAAAACWQAAAAAAeQAAAAAAWQAAAAACHQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAAQAAAAAAeQAAAAAAdgAAAAADdgAAAAACdgAAAAAAdgAAAAACHQAAAAAAHQAAAAADWQAAAAADWQAAAAABeQAAAAAAWQAAAAADHQAAAAACeQAAAAAAHQAAAAABeQAAAAAAAQAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAABHQAAAAABeQAAAAAAWQAAAAACWQAAAAACeQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAABeQAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAACWQAAAAABWQAAAAADWQAAAAABWQAAAAACWQAAAAABWQAAAAADWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADWQAAAAABWQAAAAACWQAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAABWQAAAAACWQAAAAADWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAADWQAAAAABWQAAAAACWQAAAAACWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAABHQAAAAADHQAAAAADAgAAAAAAAgAAAAAAHQAAAAAAHQAAAAAAHQAAAAABHQAAAAAAHQAAAAADHQAAAAACeQAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAAWQAAAAADHQAAAAABAQAAAAAAHQAAAAACAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAADeQAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAAWQAAAAABHQAAAAADAQAAAAAAHQAAAAAAAgAAAAAAHQAAAAAAHQAAAAAAHQAAAAABHQAAAAAAAgAAAAAAHQAAAAABeQAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAAWQAAAAACHQAAAAABAQAAAAAAHQAAAAADAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADeQAAAAAAWQAAAAAAHQAAAAADHQAAAAADAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAACHQAAAAADAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAADBQAAAAACBQAAAAACBQAAAAADHQAAAAABWQAAAAAAHQAAAAADHQAAAAACAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAAAHQAAAAADAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAABBQAAAAAABQAAAAAABQAAAAADBQAAAAACWQAAAAABHQAAAAABHQAAAAADAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAACHQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAACBQAAAAABBQAAAAADBQAAAAADBQAAAAADWQAAAAADHQAAAAADAQAAAAAAHQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAHQAAAAABeQAAAAAABQAAAAABBQAAAAACBQAAAAACBQAAAAAA - version: 6 + tiles: HQAAAAABAHkAAAAAAAAdAAAAAAAAeQAAAAAAAAEAAAAAAAB5AAAAAAAAdgAAAAACAHYAAAAAAQB2AAAAAAIAdgAAAAABAB0AAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAAB5AAAAAAAAWQAAAAACAB0AAAAAAAB5AAAAAAAAHQAAAAACAHkAAAAAAAABAAAAAAAAeQAAAAAAAHYAAAAAAwB2AAAAAAIAdgAAAAAAAHYAAAAAAgAdAAAAAAAAHQAAAAADAFkAAAAAAwBZAAAAAAEAeQAAAAAAAFkAAAAAAwAdAAAAAAIAeQAAAAAAAB0AAAAAAQB5AAAAAAAAAQAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAHkAAAAAAABZAAAAAAIAWQAAAAACAHkAAAAAAABZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAQB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAwBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAAAAFkAAAAAAwBZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAEAHQAAAAADAB0AAAAAAwACAAAAAAAAAgAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAACAHkAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAWQAAAAADAB0AAAAAAQABAAAAAAAAHQAAAAACAAIAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAB0AAAAAAwB5AAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAFkAAAAAAQAdAAAAAAMAAQAAAAAAAB0AAAAAAAACAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAEAHQAAAAAAAAIAAAAAAAAdAAAAAAEAeQAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAABZAAAAAAIAHQAAAAABAAEAAAAAAAAdAAAAAAMAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAwB5AAAAAAAAWQAAAAAAAB0AAAAAAwAdAAAAAAMAAgAAAAAAAAIAAAAAAAACAAAAAAAAHQAAAAACAB0AAAAAAwACAAAAAAAAAgAAAAAAAAIAAAAAAAAdAAAAAAMABQAAAAACAAUAAAAAAgAFAAAAAAMAHQAAAAABAFkAAAAAAAAdAAAAAAMAHQAAAAACAAIAAAAAAAACAAAAAAAAAgAAAAAAAB0AAAAAAAAdAAAAAAMAAgAAAAAAAAIAAAAAAAACAAAAAAAAHQAAAAABAAUAAAAAAAAFAAAAAAAABQAAAAADAAUAAAAAAgBZAAAAAAEAHQAAAAABAB0AAAAAAwACAAAAAAAAAgAAAAAAAAIAAAAAAAAdAAAAAAIAHQAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAB0AAAAAAgAFAAAAAAEABQAAAAADAAUAAAAAAwAFAAAAAAMAWQAAAAADAB0AAAAAAwABAAAAAAAAHQAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAB0AAAAAAQB5AAAAAAAABQAAAAABAAUAAAAAAgAFAAAAAAIABQAAAAAAAA== + version: 7 -1,-2: ind: -1,-2 - tiles: eQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAHQAAAAACDAAAAAABDAAAAAADDAAAAAACDAAAAAABeQAAAAAAAQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAHQAAAAABHQAAAAADeQAAAAAAWQAAAAADWQAAAAABHQAAAAADHQAAAAABDAAAAAAADAAAAAAADAAAAAADDAAAAAABeQAAAAAAAQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAHQAAAAABHQAAAAADeQAAAAAAWQAAAAACWQAAAAABeQAAAAAAHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAAAeQAAAAAAAQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAHQAAAAACHQAAAAABeQAAAAAAWQAAAAACWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAADWQAAAAACWQAAAAABWQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAACWQAAAAADWQAAAAACWQAAAAABWQAAAAABWQAAAAABWQAAAAACWQAAAAACWQAAAAADWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABWQAAAAADWQAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAHQAAAAACWQAAAAACWQAAAAADAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAHQAAAAACWQAAAAAAWQAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAHQAAAAADWQAAAAACWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADWQAAAAABWQAAAAAAeQAAAAAAPAAAAAAAPAAAAAAAeQAAAAAANgAAAAAANgAAAAAAeQAAAAAAEQAAAAAAEQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAACWQAAAAADWQAAAAABeQAAAAAAPAAAAAAAPAAAAAAAeQAAAAAANgAAAAAANgAAAAAAeQAAAAAAEQAAAAAAEQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAHQAAAAAAWQAAAAADWQAAAAAC - version: 6 + tiles: eQAAAAAAAFkAAAAAAABZAAAAAAAAeQAAAAAAAB0AAAAAAgAMAAAAAAEADAAAAAADAAwAAAAAAgAMAAAAAAEAeQAAAAAAAAEAAAAAAAB5AAAAAAAAHQAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAADAHkAAAAAAABZAAAAAAMAWQAAAAABAB0AAAAAAwAdAAAAAAEADAAAAAAAAAwAAAAAAAAMAAAAAAMADAAAAAABAHkAAAAAAAABAAAAAAAAeQAAAAAAAB0AAAAAAgB5AAAAAAAAHQAAAAABAB0AAAAAAwB5AAAAAAAAWQAAAAACAFkAAAAAAQB5AAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAMAHQAAAAACAB0AAAAAAAB5AAAAAAAAAQAAAAAAAHkAAAAAAAAdAAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAEAeQAAAAAAAFkAAAAAAgBZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAABAFkAAAAAAQBZAAAAAAIAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAQBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAIAWQAAAAACAFkAAAAAAwBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAgBZAAAAAAMAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAABAFkAAAAAAwBZAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAB0AAAAAAgBZAAAAAAIAWQAAAAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAdAAAAAAIAWQAAAAAAAFkAAAAAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAHQAAAAADAFkAAAAAAgBZAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAwBZAAAAAAAAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAMAWQAAAAABAFkAAAAAAAB5AAAAAAAAPAAAAAAAADwAAAAAAAB5AAAAAAAANgAAAAAAADYAAAAAAAB5AAAAAAAAEQAAAAAAABEAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAHQAAAAACAFkAAAAAAwBZAAAAAAEAeQAAAAAAADwAAAAAAAA8AAAAAAAAeQAAAAAAADYAAAAAAAA2AAAAAAAAeQAAAAAAABEAAAAAAAARAAAAAAAAeQAAAAAAAHkAAAAAAABoAAAAAAAAeQAAAAAAAB0AAAAAAABZAAAAAAMAWQAAAAACAA== + version: 7 2,-2: ind: 2,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAADHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAABHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAADHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAABCAAAAAAACAAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAAAdgAAAAADdgAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAACdgAAAAADdgAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAADdgAAAAACdgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAADCAAAAAABCAAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADHQAAAAACHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAACHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAABAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAEACAAAAAAAAAgAAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdgAAAAAAAHYAAAAAAwB2AAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHYAAAAAAgB2AAAAAAMAdgAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2AAAAAAMAdgAAAAACAHYAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAADAAgAAAAAAQAIAAAAAAIAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABAB0AAAAAAgAdAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 1,1: ind: 1,1 - tiles: WQAAAAABWQAAAAAAHQAAAAADHQAAAAACHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAADeQAAAAAAHQAAAAACHQAAAAABeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACeQAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAdgAAAAACdgAAAAAAdgAAAAABdgAAAAABdgAAAAAAdgAAAAAAdgAAAAACdgAAAAADdgAAAAABdgAAAAABdgAAAAADHQAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAHQAAAAAAdgAAAAABdgAAAAABPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAdgAAAAACeQAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAHQAAAAABdgAAAAABdgAAAAACPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAdgAAAAAATQAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAHQAAAAADdgAAAAAAdgAAAAADdgAAAAADdgAAAAADdgAAAAACdgAAAAACdgAAAAABdgAAAAACdgAAAAADdgAAAAABdgAAAAADTQAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAdgAAAAABeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAdgAAAAABTQAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAHQAAAAADHQAAAAADPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAABHQAAAAAATQAAAAAAeQAAAAAAHQAAAAABHQAAAAABHQAAAAACHQAAAAABHQAAAAAAHQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAABHQAAAAADHQAAAAAAHQAAAAADHQAAAAADTQAAAAAAeQAAAAAAHQAAAAADHQAAAAACeQAAAAAAHQAAAAADHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAAAHQAAAAADHQAAAAABHQAAAAAAHQAAAAABHQAAAAACTQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAeQAAAAAAHQAAAAACHQAAAAABHQAAAAACHQAAAAADHQAAAAABHQAAAAAAHQAAAAADHQAAAAABHQAAAAADHQAAAAAAHQAAAAABTQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAeQAAAAAAeQAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: WQAAAAABAFkAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAgB5AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAMAeQAAAAAAAB0AAAAAAgAdAAAAAAEAeQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAACAHkAAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAB2AAAAAAIAdgAAAAAAAHYAAAAAAQB2AAAAAAEAdgAAAAAAAHYAAAAAAAB2AAAAAAIAdgAAAAADAHYAAAAAAQB2AAAAAAEAdgAAAAADAB0AAAAAAAB5AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAAAdgAAAAABAHYAAAAAAQA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAdgAAAAAAAHYAAAAAAgB5AAAAAAAAeQAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAABAHYAAAAAAQB2AAAAAAIAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHYAAAAAAAB2AAAAAAAATQAAAAAAAHkAAAAAAAA+AAAAAAAAPgAAAAAAAB0AAAAAAwB2AAAAAAAAdgAAAAADAHYAAAAAAwB2AAAAAAMAdgAAAAACAHYAAAAAAgB2AAAAAAEAdgAAAAACAHYAAAAAAwB2AAAAAAEAdgAAAAADAE0AAAAAAAB5AAAAAAAAPgAAAAAAAD4AAAAAAAB5AAAAAAAAdgAAAAABAHkAAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAeQAAAAAAAHYAAAAAAQBNAAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAMAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAB0AAAAAAQAdAAAAAAAATQAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAgAdAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAADAE0AAAAAAAB5AAAAAAAAHQAAAAADAB0AAAAAAgB5AAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAABAB0AAAAAAgBNAAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAEAHQAAAAACAB0AAAAAAwAdAAAAAAEAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAAAdAAAAAAEATQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAE0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAHkAAAAAAAB5AAAAAAAATQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,1: ind: 2,1 - tiles: HQAAAAABHQAAAAACHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABPgAAAAAAPgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADPgAAAAAAPgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAABHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAADHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAADHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADHQAAAAACHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: HQAAAAABAB0AAAAAAgAdAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAABAB0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAD4AAAAAAAA+AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAQA+AAAAAAAAPgAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAAAPgAAAAAAAD4AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADAD4AAAAAAAA+AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAAAHQAAAAABAB0AAAAAAQB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,1: ind: 0,1 - tiles: WQAAAAADWQAAAAADWQAAAAADWQAAAAADWQAAAAADWQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAADWQAAAAABWQAAAAAAWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAADWQAAAAABWQAAAAADWQAAAAADeQAAAAAAWQAAAAADWQAAAAAAWQAAAAADeQAAAAAAHQAAAAAAHQAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAADHQAAAAABHQAAAAADHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAACeQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAACHQAAAAABHQAAAAADHQAAAAADeQAAAAAAWQAAAAACWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAHQAAAAACHQAAAAADeQAAAAAAeQAAAAAAWQAAAAADWQAAAAADWQAAAAACeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAACHQAAAAADHQAAAAADHQAAAAABHQAAAAADeQAAAAAAeQAAAAAAWQAAAAADWQAAAAACeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAAAWQAAAAADWQAAAAACWQAAAAAAeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAADWQAAAAADeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAADWQAAAAACWQAAAAAAWQAAAAABeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAADWQAAAAABWQAAAAADWQAAAAADeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADeQAAAAAAeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAACTQAAAAAATQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACeQAAAAAAeQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAeQAAAAAAeQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAA - version: 6 + tiles: WQAAAAADAFkAAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAIAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAADAHkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwB5AAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAMAHQAAAAABAB0AAAAAAwAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAACAHkAAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAACAB0AAAAAAQAdAAAAAAMAHQAAAAADAHkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAHQAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAADAHkAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAIAeQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAADAB0AAAAAAQAdAAAAAAMAeQAAAAAAAHkAAAAAAABZAAAAAAMAWQAAAAACAHkAAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAAB5AAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAAWQAAAAADAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAACAFkAAAAAAwBZAAAAAAMAeQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAAAWQAAAAABAHkAAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAADAFkAAAAAAwB5AAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAwB5AAAAAAAAeQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAEAeQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAAAdAAAAAAIATQAAAAAAAE0AAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAMAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAACAHkAAAAAAAB5AAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAAB5AAAAAAAAeQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAA== + version: 7 -1,1: ind: -1,1 - tiles: CgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAAAHQAAAAADeQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAABWQAAAAABWQAAAAAAWQAAAAADCgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAADCgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAADHQAAAAABHQAAAAABDQAAAAABeQAAAAAAWQAAAAABWQAAAAACCgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAABHQAAAAABHQAAAAACDQAAAAACDQAAAAAADQAAAAACDQAAAAACAQAAAAAAWQAAAAADWQAAAAABCgAAAAAACgAAAAAACgAAAAAACgAAAAAACgAAAAAACgAAAAAAHQAAAAABHQAAAAADHQAAAAAADQAAAAABDQAAAAABDQAAAAAADQAAAAABeQAAAAAAWQAAAAADWQAAAAADHQAAAAABHQAAAAACHQAAAAACHQAAAAABHQAAAAADHQAAAAABHQAAAAABHQAAAAADHQAAAAACDQAAAAABDQAAAAADDQAAAAACDQAAAAAAAQAAAAAAWQAAAAACHQAAAAAAHQAAAAABHQAAAAABHQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAABHQAAAAAAHQAAAAADHQAAAAADHQAAAAAAHQAAAAACDQAAAAADeQAAAAAAWQAAAAADeQAAAAAADQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADHQAAAAADDQAAAAACeQAAAAAAHQAAAAAAHQAAAAABHQAAAAADHQAAAAADHQAAAAAAeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAWQAAAAABWQAAAAACDQAAAAACeQAAAAAAHQAAAAACHQAAAAABHQAAAAADHQAAAAADHQAAAAACeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAWQAAAAABWQAAAAAADQAAAAACeQAAAAAAHQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAADeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAWQAAAAADWQAAAAACDQAAAAAAeQAAAAAAHQAAAAACHQAAAAACHQAAAAABHQAAAAADHQAAAAACeQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAWQAAAAABWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADWQAAAAAAWQAAAAABWQAAAAAC - version: 6 + tiles: CgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAHQAAAAAAAB0AAAAAAwB5AAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAQBZAAAAAAAAWQAAAAADAAoAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAACgAAAAAAAB0AAAAAAAAdAAAAAAMAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAwAKAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAoAAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAABAB0AAAAAAQANAAAAAAEAeQAAAAAAAFkAAAAAAQBZAAAAAAIACgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAIADQAAAAACAA0AAAAAAAANAAAAAAIADQAAAAACAAEAAAAAAABZAAAAAAMAWQAAAAABAAoAAAAAAAAKAAAAAAAACgAAAAAAAAoAAAAAAAAKAAAAAAAACgAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAAAAA0AAAAAAQANAAAAAAEADQAAAAAAAA0AAAAAAQB5AAAAAAAAWQAAAAADAFkAAAAAAwAdAAAAAAEAHQAAAAACAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAADAB0AAAAAAgANAAAAAAEADQAAAAADAA0AAAAAAgANAAAAAAAAAQAAAAAAAFkAAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAADAB0AAAAAAAAdAAAAAAIADQAAAAADAHkAAAAAAABZAAAAAAMAeQAAAAAAAA0AAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAADAB0AAAAAAwANAAAAAAIAeQAAAAAAAB0AAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAwAdAAAAAAAAeQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAIADQAAAAACAHkAAAAAAAAdAAAAAAIAHQAAAAABAB0AAAAAAwAdAAAAAAMAHQAAAAACAHkAAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAABZAAAAAAEAWQAAAAAAAA0AAAAAAgB5AAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAwB5AAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAgANAAAAAAAAeQAAAAAAAB0AAAAAAgAdAAAAAAIAHQAAAAABAB0AAAAAAwAdAAAAAAIAeQAAAAAAAE0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAA== + version: 7 1,2: ind: 1,2 - tiles: CQAAAAAAeQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAeQAAAAAAeQAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: CQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAB5AAAAAAAAeQAAAAAAAE0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,2: ind: 0,2 - tiles: HQAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAACHQAAAAADHQAAAAABHQAAAAACeQAAAAAAeQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAAeQAAAAAACgAAAAAACgAAAAAAeQAAAAAACgAAAAAACgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAeQAAAAAACgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: HQAAAAAAAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAgB5AAAAAAAAeQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAHkAAAAAAAAKAAAAAAAACgAAAAAAAHkAAAAAAAAKAAAAAAAACgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAACgAAAAAAAHkAAAAAAAAKAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -2,0: ind: -2,0 - tiles: WQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAADWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAABWQAAAAABHQAAAAAAHQAAAAAAHQAAAAACHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAACHQAAAAADHQAAAAABHQAAAAABHQAAAAABHQAAAAABHQAAAAABHQAAAAABHQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAdgAAAAAAHQAAAAAAeQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAeQAAAAAAEAAAAAAAdgAAAAAAdgAAAAADdgAAAAABdgAAAAADHQAAAAAAHQAAAAAAHQAAAAAAdgAAAAAAHQAAAAAAeQAAAAAADwAAAAACDwAAAAABDwAAAAADDwAAAAACeQAAAAAAHQAAAAACdgAAAAAAdgAAAAABdgAAAAACdgAAAAADPgAAAAAAPgAAAAAAeQAAAAAAdgAAAAAAHQAAAAAAHQAAAAADAwAAAAABAwAAAAAAAwAAAAAAAwAAAAAAHQAAAAADHQAAAAABdgAAAAAAdgAAAAADdgAAAAADdgAAAAADPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAHQAAAAAAHQAAAAACAwAAAAAAAwAAAAAAAwAAAAACAwAAAAAAHQAAAAACHQAAAAADdgAAAAAAdgAAAAADdgAAAAACdgAAAAACPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAHQAAAAAAeQAAAAAADwAAAAACDwAAAAADDwAAAAABDwAAAAADeQAAAAAAHQAAAAADdgAAAAAAdgAAAAABdgAAAAADdgAAAAABPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABdgAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABHQAAAAADHQAAAAAAHQAAAAABHQAAAAABHQAAAAADHQAAAAADHQAAAAAAdgAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAADdgAAAAAAdgAAAAADdgAAAAACPgAAAAAAPgAAAAAAdgAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACdgAAAAABPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAADPgAAAAAAPgAAAAAAdgAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADdgAAAAADPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAABPgAAAAAAPgAAAAAAdgAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAAAHQAAAAADHQAAAAABHQAAAAADHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAABbAAAAAADeQAAAAAA - version: 6 + tiles: WQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAABAB0AAAAAAAAdAAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAAAAB0AAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAdgAAAAAAAB0AAAAAAAB5AAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAHkAAAAAAAAQAAAAAAAAdgAAAAAAAHYAAAAAAwB2AAAAAAEAdgAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAAAAHYAAAAAAAAdAAAAAAAAeQAAAAAAAA8AAAAAAgAPAAAAAAEADwAAAAADAA8AAAAAAgB5AAAAAAAAHQAAAAACAHYAAAAAAAB2AAAAAAEAdgAAAAACAHYAAAAAAwA+AAAAAAAAPgAAAAAAAHkAAAAAAAB2AAAAAAAAHQAAAAAAAB0AAAAAAwADAAAAAAEAAwAAAAAAAAMAAAAAAAADAAAAAAAAHQAAAAADAB0AAAAAAQB2AAAAAAAAdgAAAAADAHYAAAAAAwB2AAAAAAMAPgAAAAAAAD4AAAAAAAA+AAAAAAAAdgAAAAAAAB0AAAAAAAAdAAAAAAIAAwAAAAAAAAMAAAAAAAADAAAAAAIAAwAAAAAAAB0AAAAAAgAdAAAAAAMAdgAAAAAAAHYAAAAAAwB2AAAAAAIAdgAAAAACAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHYAAAAAAAAdAAAAAAAAeQAAAAAAAA8AAAAAAgAPAAAAAAMADwAAAAABAA8AAAAAAwB5AAAAAAAAHQAAAAADAHYAAAAAAAB2AAAAAAEAdgAAAAADAHYAAAAAAQA+AAAAAAAAPgAAAAAAAD4AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAEAdgAAAAAAAB0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAwAdAAAAAAMAHQAAAAAAAHYAAAAAAAAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAAAAHYAAAAAAAB2AAAAAAMAdgAAAAAAAHYAAAAAAwB2AAAAAAIAPgAAAAAAAD4AAAAAAAB2AAAAAAAAHQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAgB2AAAAAAEAPgAAAAAAAD4AAAAAAAA+AAAAAAAAdgAAAAADAD4AAAAAAAA+AAAAAAAAdgAAAAAAAB0AAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAMAdgAAAAADAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHYAAAAAAQA+AAAAAAAAPgAAAAAAAHYAAAAAAAAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAQBsAAAAAAMAeQAAAAAAAA== + version: 7 -2,-1: ind: -2,-1 - tiles: TQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAACHQAAAAADHQAAAAABHQAAAAABHQAAAAAAHQAAAAADHQAAAAACHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAAAHQAAAAABHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAACHQAAAAACHQAAAAAAHQAAAAACHQAAAAACHQAAAAAAHQAAAAABHQAAAAADHQAAAAAAHQAAAAADHQAAAAADHQAAAAACHQAAAAAAHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAACHQAAAAACHQAAAAAAHQAAAAAAHQAAAAACHQAAAAACHQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAADwAAAAACDwAAAAADDwAAAAADDwAAAAAADwAAAAAAdgAAAAACDwAAAAABDwAAAAAADwAAAAACDwAAAAABeQAAAAAAHQAAAAABHQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAADwAAAAACdgAAAAADdgAAAAABdgAAAAADdgAAAAAAdgAAAAABdgAAAAADdgAAAAABdgAAAAAADwAAAAACeQAAAAAAHQAAAAAAHQAAAAABHQAAAAABHQAAAAACeQAAAAAADwAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAdgAAAAABeQAAAAAAeQAAAAAAeQAAAAAADwAAAAABeQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAAAeQAAAAAADwAAAAABeQAAAAAAdgAAAAABdgAAAAADdgAAAAADdgAAAAAAdgAAAAAAdgAAAAACeQAAAAAADwAAAAABeQAAAAAAHQAAAAABHQAAAAACHQAAAAABHQAAAAADeQAAAAAADwAAAAAAeQAAAAAAdgAAAAACdgAAAAACdgAAAAABdgAAAAADdgAAAAAAdgAAAAAAeQAAAAAADwAAAAADeQAAAAAAHQAAAAACHQAAAAADHQAAAAABHQAAAAADeQAAAAAADwAAAAAAeQAAAAAAdgAAAAACdgAAAAADHQAAAAACHQAAAAADHQAAAAABdgAAAAACeQAAAAAADwAAAAAAeQAAAAAAHQAAAAAAHQAAAAACHQAAAAABHQAAAAADeQAAAAAADwAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAADwAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAAAeQAAAAAADwAAAAABDwAAAAABAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAGAwAAAAAIDwAAAAAADwAAAAABDwAAAAABHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAADHQAAAAADHQAAAAACHQAAAAABHQAAAAAAHQAAAAAAHQAAAAACHQAAAAADHQAAAAADWQAAAAAAWQAAAAADWQAAAAACWQAAAAACWQAAAAADWQAAAAAAWQAAAAACWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAACWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAADWQAAAAAAWQAAAAACWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADWQAAAAAA - version: 6 + tiles: TQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAABNAAAAAAAATQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAQAdAAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAwAdAAAAAAMAHQAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAABAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAAAHQAAAAADAB0AAAAAAwAdAAAAAAIAHQAAAAAAAB0AAAAAAgAdAAAAAAEAHQAAAAACAB0AAAAAAgAdAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAADwAAAAACAA8AAAAAAwAPAAAAAAMADwAAAAAAAA8AAAAAAAB2AAAAAAIADwAAAAABAA8AAAAAAAAPAAAAAAIADwAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAAAeQAAAAAAAA8AAAAAAgB2AAAAAAMAdgAAAAABAHYAAAAAAwB2AAAAAAAAdgAAAAABAHYAAAAAAwB2AAAAAAEAdgAAAAAAAA8AAAAAAgB5AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAACAHkAAAAAAAAPAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHYAAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAAPAAAAAAEAeQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAAB5AAAAAAAADwAAAAABAHkAAAAAAAB2AAAAAAEAdgAAAAADAHYAAAAAAwB2AAAAAAAAdgAAAAAAAHYAAAAAAgB5AAAAAAAADwAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAACAB0AAAAAAQAdAAAAAAMAeQAAAAAAAA8AAAAAAAB5AAAAAAAAdgAAAAACAHYAAAAAAgB2AAAAAAEAdgAAAAADAHYAAAAAAAB2AAAAAAAAeQAAAAAAAA8AAAAAAwB5AAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAEAHQAAAAADAHkAAAAAAAAPAAAAAAAAeQAAAAAAAHYAAAAAAgB2AAAAAAMAHQAAAAACAB0AAAAAAwAdAAAAAAEAdgAAAAACAHkAAAAAAAAPAAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAABAB0AAAAAAwB5AAAAAAAADwAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAADwAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAAAeQAAAAAAAA8AAAAAAQAPAAAAAAEAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAGAAMAAAAACAAPAAAAAAAADwAAAAABAA8AAAAAAQAdAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAADAB0AAAAAAwBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAAAAA== + version: 7 -2,1: ind: -2,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAAAbAAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAADQAAAAACDQAAAAABDQAAAAADTQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAABHQAAAAADHQAAAAACTQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAAAHQAAAAADHQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAACHQAAAAABHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAABHQAAAAAAHQAAAAACeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAABHQAAAAABHQAAAAAATQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAADHQAAAAAAHQAAAAABTQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAABHQAAAAABHQAAAAACTQAAAAAATQAAAAAATQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAHQAAAAAAHQAAAAACHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAABsAAAAAAAAeQAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAADQAAAAACAA0AAAAAAQANAAAAAAMATQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAaAAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAACAE0AAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAGgAAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAABNAAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABoAAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAMAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAaAAAAAAAAB0AAAAAAQAdAAAAAAAAHQAAAAACAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAGgAAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABoAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAAATQAAAAAAAE0AAAAAAABNAAAAAAAAeQAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAaAAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAABAE0AAAAAAABNAAAAAAAATQAAAAAAAHkAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAGgAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAgBNAAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABoAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,2: ind: -1,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADHQAAAAADHQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -3,1: ind: -3,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-3: ind: 0,-3 - tiles: HQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAAAeQAAAAAAHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAABWQAAAAADHQAAAAACHQAAAAADHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAWQAAAAABeQAAAAAAHQAAAAACHQAAAAACWQAAAAACWQAAAAADWQAAAAADWQAAAAADWQAAAAADWQAAAAACWQAAAAACeQAAAAAAWQAAAAADWQAAAAACWQAAAAABWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAABWQAAAAACeQAAAAAAWQAAAAABeQAAAAAAWQAAAAABWQAAAAADWQAAAAABWQAAAAAAWQAAAAADWQAAAAABWQAAAAACWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAeQAAAAAAWQAAAAADWQAAAAAANgAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAAAWQAAAAACWQAAAAADeQAAAAAAWQAAAAABWQAAAAAANgAAAAAAWQAAAAAAWQAAAAAAWQAAAAADWQAAAAADWQAAAAADWQAAAAAAWQAAAAACWQAAAAADWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAABWQAAAAADWQAAAAABWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAABeQAAAAAAWQAAAAACWQAAAAAAWQAAAAABWQAAAAADWQAAAAABWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADWQAAAAADeQAAAAAAWQAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAADWQAAAAABWQAAAAABWQAAAAACWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABHQAAAAACHQAAAAACeQAAAAAAWQAAAAADWQAAAAACWQAAAAAAWQAAAAABHQAAAAACHQAAAAAAHQAAAAADHQAAAAAAHQAAAAABHQAAAAADDgAAAAADHQAAAAADdgAAAAADdgAAAAACHQAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAAADgAAAAABDgAAAAAADgAAAAAADgAAAAACDgAAAAAADgAAAAABDgAAAAACHQAAAAACdgAAAAADdgAAAAACHQAAAAADeQAAAAAAWQAAAAACWQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAADHQAAAAADHQAAAAABdgAAAAACdgAAAAAAHQAAAAACeQAAAAAAWQAAAAADWQAAAAABeQAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAdgAAAAABdgAAAAACHQAAAAACeQAAAAAAWQAAAAACWQAAAAACeQAAAAAAWQAAAAAD - version: 6 + tiles: HQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAABAB0AAAAAAgAdAAAAAAIAHQAAAAABAFkAAAAAAwAdAAAAAAIAHQAAAAADAB0AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAEAeQAAAAAAAB0AAAAAAgAdAAAAAAIAWQAAAAACAFkAAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAwBZAAAAAAIAWQAAAAACAHkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAQBZAAAAAAAAWQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgB5AAAAAAAAWQAAAAABAHkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAAANgAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAADAHkAAAAAAABZAAAAAAEAWQAAAAAAADYAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAQB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAgBZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAEAeQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAADAHkAAAAAAABZAAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAADAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAACAHkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAHQAAAAACAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAQAdAAAAAAMADgAAAAADAB0AAAAAAwB2AAAAAAMAdgAAAAACAB0AAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAABZAAAAAAAAWQAAAAAAAA4AAAAAAQAOAAAAAAAADgAAAAAAAA4AAAAAAgAOAAAAAAAADgAAAAABAA4AAAAAAgAdAAAAAAIAdgAAAAADAHYAAAAAAgAdAAAAAAMAeQAAAAAAAFkAAAAAAgBZAAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAABAHYAAAAAAgB2AAAAAAAAHQAAAAACAHkAAAAAAABZAAAAAAMAWQAAAAABAHkAAAAAAABZAAAAAAMAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAHkAAAAAAAB2AAAAAAEAdgAAAAACAB0AAAAAAgB5AAAAAAAAWQAAAAACAFkAAAAAAgB5AAAAAAAAWQAAAAADAA== + version: 7 -1,-3: ind: -1,-3 - tiles: HQAAAAADWQAAAAABHQAAAAACHQAAAAADHQAAAAADHQAAAAACHQAAAAABeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAADHQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACHQAAAAADHQAAAAAAeQAAAAAAWQAAAAABWQAAAAADWQAAAAABWQAAAAABWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAAAeQAAAAAAWQAAAAACWQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAADWQAAAAACWQAAAAAAeQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAAAWQAAAAABWQAAAAABWQAAAAABWQAAAAACeQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAABWQAAAAACeQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAACWQAAAAABWQAAAAADWQAAAAADWQAAAAABWQAAAAABNgAAAAAANgAAAAAAWQAAAAABeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAACWQAAAAADWQAAAAADWQAAAAABWQAAAAACWQAAAAABWQAAAAADWQAAAAACNgAAAAAANgAAAAAAWQAAAAABeQAAAAAAWQAAAAACWQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAADWQAAAAADeQAAAAAAWQAAAAACWQAAAAADWQAAAAACWQAAAAADWQAAAAABWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAAAeQAAAAAAHQAAAAABHQAAAAADHQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABeQAAAAAAHQAAAAADDAAAAAABDAAAAAABHQAAAAACDgAAAAABHQAAAAACHQAAAAADHQAAAAABHQAAAAAAHQAAAAACHQAAAAAAHQAAAAADeQAAAAAAWQAAAAAAWQAAAAADeQAAAAAAHQAAAAABDAAAAAADDAAAAAABHQAAAAADDgAAAAADDgAAAAABDgAAAAAADgAAAAADDgAAAAACDgAAAAAADgAAAAACDgAAAAADeQAAAAAAWQAAAAACWQAAAAACeQAAAAAAHQAAAAACDAAAAAABDAAAAAAAHQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAADHQAAAAADHQAAAAABHQAAAAABHQAAAAABeQAAAAAAWQAAAAACWQAAAAAAeQAAAAAAHQAAAAADDAAAAAABDAAAAAACeQAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAB - version: 6 + tiles: HQAAAAADAFkAAAAAAQAdAAAAAAIAHQAAAAADAB0AAAAAAwAdAAAAAAIAHQAAAAABAHkAAAAAAAAdAAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAADAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAABAFkAAAAAAQBZAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAQBZAAAAAAIAeQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAAAAFkAAAAAAwBZAAAAAAEAWQAAAAACAHkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAwBZAAAAAAMAWQAAAAABAFkAAAAAAQA2AAAAAAAANgAAAAAAAFkAAAAAAQB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAADAFkAAAAAAQBZAAAAAAIAWQAAAAABAFkAAAAAAwBZAAAAAAIANgAAAAAAADYAAAAAAABZAAAAAAEAeQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAMAWQAAAAADAHkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAwBZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAAB5AAAAAAAAHQAAAAABAB0AAAAAAwAdAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAEAeQAAAAAAAB0AAAAAAwAMAAAAAAEADAAAAAABAB0AAAAAAgAOAAAAAAEAHQAAAAACAB0AAAAAAwAdAAAAAAEAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAADAHkAAAAAAABZAAAAAAAAWQAAAAADAHkAAAAAAAAdAAAAAAEADAAAAAADAAwAAAAAAQAdAAAAAAMADgAAAAADAA4AAAAAAQAOAAAAAAAADgAAAAADAA4AAAAAAgAOAAAAAAAADgAAAAACAA4AAAAAAwB5AAAAAAAAWQAAAAACAFkAAAAAAgB5AAAAAAAAHQAAAAACAAwAAAAAAQAMAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAABAB0AAAAAAQAdAAAAAAEAeQAAAAAAAFkAAAAAAgBZAAAAAAAAeQAAAAAAAB0AAAAAAwAMAAAAAAEADAAAAAACAHkAAAAAAAAdAAAAAAMAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAA== + version: 7 -2,-2: ind: -2,-2 - tiles: AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAADbAAAAAABWQAAAAADAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAADbAAAAAABWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAABbAAAAAADWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAAAWQAAAAABWQAAAAAAWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAADWQAAAAABWQAAAAADWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAAAWQAAAAABWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAEAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAbAAAAAAAbAAAAAAAeQAAAAAACwAAAAAACwAAAAAAeQAAAAAAbAAAAAACbAAAAAADeQAAAAAAHQAAAAADHQAAAAACEAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAbAAAAAAAbAAAAAAAeQAAAAAACwAAAAAACwAAAAAAeQAAAAAAbAAAAAADbAAAAAAAeQAAAAAAHQAAAAABHQAAAAAD - version: 6 + tiles: AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAwBsAAAAAAEAWQAAAAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAABAFkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAbAAAAAABAGwAAAAAAwBZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAQAAAAAAAAeQAAAAAAABAAAAAAAAAQAAAAAAAAeQAAAAAAAGwAAAAAAABsAAAAAAAAeQAAAAAAAAsAAAAAAAALAAAAAAAAeQAAAAAAAGwAAAAAAgBsAAAAAAMAeQAAAAAAAB0AAAAAAwAdAAAAAAIAEAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAABsAAAAAAAAbAAAAAAAAHkAAAAAAAALAAAAAAAACwAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAA== + version: 7 -2,-3: ind: -2,-3 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAACeQAAAAAAHQAAAAABHQAAAAABHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAHQAAAAACHQAAAAABHQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAABWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAADWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAACWQAAAAAAWQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAWQAAAAACWQAAAAAAWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAACbAAAAAADWQAAAAACAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAbAAAAAACbAAAAAACWQAAAAAD - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAwAAAAACAHkAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAMAAAAAAAB5AAAAAAAAHQAAAAACAB0AAAAAAQAdAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAwAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAADAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAwAAAAAAAHkAAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAQBZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAADAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAMAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAADAAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAbAAAAAACAGwAAAAAAwBZAAAAAAIAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAgBsAAAAAAIAWQAAAAADAA== + version: 7 1,-3: ind: 1,-3 - tiles: eQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAABeQAAAAAAAwAAAAAFeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAABeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAADWQAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABWQAAAAABeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAACeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAAAeQAAAAAAAwAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAAAeQAAAAAAAwAAAAAKeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAABbAAAAAACeQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAAAbAAAAAADeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: eQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAAAdAAAAAAEAeQAAAAAAAAMAAAAABQB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAEAHQAAAAABAHkAAAAAAAADAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACAFkAAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAwBZAAAAAAAAeQAAAAAAAAMAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAIAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABAFkAAAAAAQB5AAAAAAAAAwAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAABZAAAAAAIAeQAAAAAAAAMAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAAAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAFkAAAAAAAB5AAAAAAAAAwAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAABZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAIAWQAAAAAAAHkAAAAAAAADAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACAFkAAAAAAAB5AAAAAAAAAwAAAAAKAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAAAEAbAAAAAACAHkAAAAAAAAdAAAAAAMAHQAAAAADAB0AAAAAAwAdAAAAAAAAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAGwAAAAAAwB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAABAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 1,-4: ind: 1,-4 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-4: ind: 0,-4 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAADHQAAAAACHQAAAAACHQAAAAADHQAAAAAAHQAAAAADHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACHQAAAAADHQAAAAADHQAAAAAAHQAAAAACHQAAAAAAHQAAAAABWQAAAAACHQAAAAADHQAAAAAC - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAgAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAMAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAABAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAABAFkAAAAAAgAdAAAAAAMAHQAAAAACAA== + version: 7 -1,-4: ind: -1,-4 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAAAHQAAAAABHQAAAAAAWQAAAAABHQAAAAAAHQAAAAADHQAAAAABHQAAAAACHQAAAAACHQAAAAAAHQAAAAABPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACHQAAAAAB - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAAAAFkAAAAAAQAdAAAAAAAAHQAAAAADAB0AAAAAAQAdAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAEAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAIAHQAAAAABAA== + version: 7 -2,-4: ind: -2,-4 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAHQAAAAAC - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAHQAAAAACAA== + version: 7 -3,0: ind: -3,0 - tiles: WQAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAABWQAAAAAAWQAAAAADHQAAAAABHQAAAAAAHQAAAAAAHQAAAAABHQAAAAABHQAAAAABHQAAAAACHQAAAAACHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAACHQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAdgAAAAABeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAACeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAABeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAADeQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAANgAAAAAACAAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: WQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAAAWQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAgAdAAAAAAIAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAIAHQAAAAACAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAdgAAAAABAHkAAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAAdAAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAgB5AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAB5AAAAAAAAHQAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAEAeQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAeQAAAAAAAB0AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAADAHkAAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHkAAAAAAAAdAAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAD4AAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAA2AAAAAAAACAAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAB2AAAAAAAAdgAAAAAAAHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -3,-1: ind: -3,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAATQAAAAAAeQAAAAAATQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAABHQAAAAACHQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAHQAAAAADHQAAAAADHQAAAAAAHQAAAAAAHQAAAAACHQAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAeQAAAAAAHQAAAAADHQAAAAABHQAAAAAAHQAAAAAAHQAAAAACHQAAAAACHQAAAAAAHQAAAAABHQAAAAADHQAAAAACHQAAAAAAeQAAAAAAHQAAAAADHQAAAAACAAAAAAAAeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAADHQAAAAABHQAAAAAAHQAAAAACeQAAAAAAHQAAAAACHQAAAAADeQAAAAAAeQAAAAAAHQAAAAADPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAAAHQAAAAACHQAAAAAAHQAAAAACHQAAAAADHQAAAAABHQAAAAACEgAAAAAAeQAAAAAAHQAAAAACPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAACHQAAAAAANgAAAAAANgAAAAAAHQAAAAACHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAAAHQAAAAADEgAAAAAAeQAAAAAAHQAAAAADPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAAAHQAAAAABHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAABHQAAAAAAHQAAAAACHQAAAAACEgAAAAAAeQAAAAAAHQAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAHQAAAAABHQAAAAADHQAAAAACHQAAAAABHQAAAAABHQAAAAADHQAAAAAAeQAAAAAAHQAAAAAAHQAAAAAAEgAAAAAAeQAAAAAAHQAAAAABHQAAAAAAHQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAADHQAAAAAAHQAAAAAAHQAAAAADHQAAAAABeQAAAAAAHQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAHQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAACHQAAAAABHQAAAAABHQAAAAABHQAAAAADHQAAAAACHQAAAAAAHQAAAAADHQAAAAABWQAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAACWQAAAAACWQAAAAABWQAAAAADWQAAAAADWQAAAAACWQAAAAADWQAAAAACWQAAAAADWQAAAAACWQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAWQAAAAAB - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAATQAAAAAAAE0AAAAAAAB5AAAAAAAATQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAABAB0AAAAAAgAdAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAAAAB0AAAAAAAAdAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAIAAAAAAAAAAHkAAAAAAAAdAAAAAAAAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAACAHkAAAAAAAAdAAAAAAIAHQAAAAADAHkAAAAAAAB5AAAAAAAAHQAAAAADAD4AAAAAAAA+AAAAAAAAPgAAAAAAAB0AAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAgASAAAAAAAAeQAAAAAAAB0AAAAAAgA+AAAAAAAAPgAAAAAAAD4AAAAAAAAdAAAAAAIAHQAAAAAAADYAAAAAAAA2AAAAAAAAHQAAAAACAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAEgAAAAAAAHkAAAAAAAAdAAAAAAMAPgAAAAAAAD4AAAAAAAA+AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAACABIAAAAAAAB5AAAAAAAAHQAAAAAAAD4AAAAAAAA+AAAAAAAAPgAAAAAAAB0AAAAAAQAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAEAHQAAAAADAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAASAAAAAAAAeQAAAAAAAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAAAAB0AAAAAAwAdAAAAAAEAeQAAAAAAAB0AAAAAAAAdAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAgB5AAAAAAAAHQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAADAB0AAAAAAwAdAAAAAAIAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAwBZAAAAAAEAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAADAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAAAAFkAAAAAAQBZAAAAAAAAWQAAAAABAA== + version: 7 -3,-2: ind: -3,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAAAWQAAAAAAWQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAACgAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAACWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAEAAAAAAAEAAAAAAAeQAAAAAAEAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAACgAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAEAAAAAAAAA== + version: 7 -4,-1: ind: -4,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADHQAAAAADHQAAAAABHQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAWQAAAAADWQAAAAAAWQAAAAADWQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAWQAAAAACWQAAAAABWQAAAAACWQAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAABIAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAdAAAAAAIAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAMAHQAAAAABAB0AAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAoAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAwBZAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAAAAA== + version: 7 -4,0: ind: -4,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAACgAAAAAAWQAAAAADWQAAAAADWQAAAAACWQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAABHQAAAAABHQAAAAABHQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAdgAAAAADdgAAAAAAdgAAAAACdgAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAdgAAAAADdgAAAAADdgAAAAABdgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAdgAAAAABdgAAAAADdgAAAAABdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAdgAAAAABdgAAAAACdgAAAAACdgAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAKAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAIAWQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAdgAAAAADAHYAAAAAAAB2AAAAAAIAdgAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHYAAAAAAwB2AAAAAAMAdgAAAAABAHYAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB2AAAAAAEAdgAAAAADAHYAAAAAAQB2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAdgAAAAABAHYAAAAAAgB2AAAAAAIAdgAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -3,-3: ind: -3,-3 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -365,7 +365,6 @@ entities: 1108: -13,26 1109: -12,27 1110: -11,26 - 1130: 13,9 1167: 3,31 2839: -6,-10 - node: @@ -394,11 +393,57 @@ entities: 1448: -16,24 1449: -16,25 2840: -6,-11 + - node: + color: '#CC8000FF' + id: BrickCornerOverlayNE + decals: + 3355: 6,12 + - node: + color: '#CC8000FF' + id: BrickCornerOverlayNW + decals: + 3352: 3,12 + - node: + color: '#CC8000FF' + id: BrickCornerOverlaySE + decals: + 3344: 6,7 + - node: + color: '#CC8000FF' + id: BrickCornerOverlaySW + decals: + 3347: 3,7 + - node: + color: '#CC8000FF' + id: BrickLineOverlayE + decals: + 3342: 6,10 + 3343: 6,9 + - node: + color: '#CC8000FF' + id: BrickLineOverlayN + decals: + 3353: 4,12 + 3354: 5,12 - node: color: '#FFFFFFFF' id: BrickLineOverlayN decals: 2958: -27.001663,-17.373186 + - node: + color: '#CC8000FF' + id: BrickLineOverlayS + decals: + 3345: 5,7 + 3346: 4,7 + - node: + color: '#CC8000FF' + id: BrickLineOverlayW + decals: + 3348: 3,8 + 3349: 3,9 + 3350: 3,10 + 3351: 3,11 - node: color: '#FFFFFFFF' id: BrickLineOverlayW @@ -569,11 +614,6 @@ entities: 619: 34,-16 695: 34,-26 2689: -43,-6 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerNe - decals: - 832: 23,12 - node: color: '#79150096' id: BrickTileWhiteCornerNe @@ -589,12 +629,10 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteCornerNe decals: - 821: 7,12 - 870: 17,12 986: 16,20 - 1494: 11,12 1763: -10,-39 1874: -18,-40 + 3312: 10,12 - node: color: '#EFD2415D' id: BrickTileWhiteCornerNe @@ -618,7 +656,6 @@ entities: id: BrickTileWhiteCornerNw decals: 735: 9,-5 - 831: 19,12 - node: color: '#79150096' id: BrickTileWhiteCornerNw @@ -634,12 +671,12 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteCornerNw decals: - 820: 3,12 - 859: 9,12 985: 10,20 - 1495: 15,12 1764: -14,-39 1875: -19,-40 + 3232: 15,12 + 3300: 12,11 + 3313: 8,12 - node: color: '#334E6DC8' id: BrickTileWhiteCornerSe @@ -647,11 +684,6 @@ entities: 621: 34,-18 693: 34,-28 2691: -43,-10 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerSe - decals: - 834: 23,10 - node: color: '#79150096' id: BrickTileWhiteCornerSe @@ -667,7 +699,6 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteCornerSe decals: - 823: 7,10 843: 17,3 982: 16,18 1766: -10,-44 @@ -699,7 +730,6 @@ entities: id: BrickTileWhiteCornerSw decals: 733: 9,-7 - 833: 19,10 - node: color: '#79150096' id: BrickTileWhiteCornerSw @@ -715,11 +745,11 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteCornerSw decals: - 822: 3,10 848: 12,3 981: 10,18 1765: -14,-44 1872: -19,-43 + 3316: 8,7 - node: color: '#EFCC4163' id: BrickTileWhiteCornerSw @@ -746,8 +776,8 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteInnerNe decals: - 864: 11,11 865: 13,11 + 3304: 10,8 - node: color: '#EFD2415D' id: BrickTileWhiteInnerNe @@ -773,8 +803,10 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteInnerNw decals: - 863: 15,11 866: 13,11 + 3233: 15,11 + 3239: 17,12 + 3303: 12,8 - node: color: '#FFFFFFFF' id: BrickTileWhiteInnerNw @@ -789,7 +821,7 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteInnerSe decals: - 881: 10,7 + 3305: 10,7 - node: color: '#EFD2415D' id: BrickTileWhiteInnerSe @@ -815,7 +847,8 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteInnerSw decals: - 852: 12,7 + 3306: 12,7 + 3318: 9,7 - node: color: '#EFD2415D' id: BrickTileWhiteInnerSw @@ -870,11 +903,6 @@ entities: 554: 31,-12 555: 31,-11 556: 31,-10 - - node: - color: '#52B4E996' - id: BrickTileWhiteLineE - decals: - 830: 23,11 - node: color: '#79150096' id: BrickTileWhiteLineE @@ -896,8 +924,6 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteLineE decals: - 827: 7,11 - 871: 17,11 872: 17,9 873: 17,8 874: 17,7 @@ -914,6 +940,9 @@ entities: 1773: -10,-40 1870: -18,-42 1871: -18,-41 + 3309: 10,9 + 3310: 10,10 + 3311: 10,11 - node: color: '#EFCC4163' id: BrickTileWhiteLineE @@ -1058,9 +1087,6 @@ entities: 740: 14,-5 741: 15,-5 742: 16,-5 - 835: 20,12 - 836: 21,12 - 837: 22,12 - node: color: '#9FED5896' id: BrickTileWhiteLineN @@ -1072,10 +1098,6 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteLineN decals: - 817: 4,12 - 818: 5,12 - 819: 6,12 - 867: 12,11 868: 14,11 987: 15,20 988: 14,20 @@ -1084,6 +1106,7 @@ entities: 1778: -13,-39 1779: -12,-39 1780: -11,-39 + 3308: 11,8 - node: color: '#EFD2415D' id: BrickTileWhiteLineN @@ -1242,9 +1265,6 @@ entities: decals: 731: 11,-7 732: 10,-7 - 838: 20,10 - 839: 21,10 - 840: 22,10 - node: color: '#9FED5896' id: BrickTileWhiteLineS @@ -1256,14 +1276,10 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteLineS decals: - 824: 6,10 - 825: 5,10 - 826: 4,10 844: 16,3 845: 15,3 846: 14,3 847: 13,3 - 853: 11,7 976: 12,18 977: 14,18 978: 15,18 @@ -1271,6 +1287,7 @@ entities: 1767: -11,-44 1768: -12,-44 1769: -13,-44 + 3307: 11,7 - node: color: '#EFCC4163' id: BrickTileWhiteLineS @@ -1376,7 +1393,6 @@ entities: 728: 12,-9 729: 12,-8 734: 9,-6 - 829: 19,11 - node: color: '#79150096' id: BrickTileWhiteLineW @@ -1398,12 +1414,9 @@ entities: color: '#DE3A3A96' id: BrickTileWhiteLineW decals: - 828: 3,11 849: 12,4 850: 12,5 851: 12,6 - 857: 9,9 - 858: 9,11 882: 9,6 883: 9,5 884: 9,4 @@ -1415,6 +1428,10 @@ entities: 1777: -14,-40 1868: -19,-41 1869: -19,-42 + 3301: 12,10 + 3302: 12,9 + 3314: 8,10 + 3315: 8,9 - node: color: '#EFCC4163' id: BrickTileWhiteLineW @@ -1471,17 +1488,11 @@ entities: 1899: 19,-46 1904: -21,-47 2439: -15,3 - - node: - color: '#FFFFFFFF' - id: BushDThree - decals: - 1457: 6.9084163,7.696661 - 1458: 6.4396663,7.352911 + 3290: 21.088001,10.494442 - node: color: '#FFFFFFFF' id: BushDTwo decals: - 1459: 3.2052913,7.727911 2185: -24,-21 - node: color: '#FFFFFFFF' @@ -1505,6 +1516,7 @@ entities: 1894: 19,-42 2402: -28.567415,3.2062178 2437: -11,-5 + 3277: 22.989494,10.9857645 - node: color: '#FFFFFFFF' id: Bushc2 @@ -1515,6 +1527,12 @@ entities: id: Bushc3 decals: 1900: 19,-44 + - node: + color: '#FFFFFFFF' + id: Bushd1 + decals: + 3271: 20.260328,11.579927 + 3272: 19.291578,10.798135 - node: color: '#FFFFFFFF' id: Bushe1 @@ -1537,14 +1555,13 @@ entities: decals: 153: 18.801558,6.901756 154: 33.138065,6.979881 - 1456: 3.7990413,7.759161 - node: color: '#FFFFFFFF' id: Bushf1 decals: - 1455: 4.7990413,7.446661 2186: -12,-22 2187: -4,-22 + 3289: 19.926857,10.994789 - node: color: '#FFFFFFFF' id: Bushf2 @@ -1562,6 +1579,11 @@ entities: id: Bushg1 decals: 2232: 2,-22 + - node: + color: '#FFFFFFFF' + id: Bushg3 + decals: + 3288: 19.739357,11.3387785 - node: color: '#FFFFFFFF' id: Bushg4 @@ -1595,8 +1617,6 @@ entities: color: '#FFFFFFFF' id: Bushi2 decals: - 1453: 3.0802913,6.946661 - 1454: 6.2677913,7.806036 1915: 19,-41 1978: 4.0082064,-31.102646 2179: -4,-21 @@ -1636,16 +1656,20 @@ entities: 2449: -10,-5 2799: -40,-23 2800: -36,-32 + 3281: 19.458244,11.64247 + 3287: 21.043343,12.0816 - node: color: '#FFFFFFFF' id: Bushj1 decals: 2409: -29.004915,3.0343428 + 3276: 23.281162,10.78771 - node: color: '#FFFFFFFF' id: Bushj2 decals: 2411: -26.27054,4.378093 + 3283: 19.223536,9.903004 - node: color: '#FFFFFFFF' id: Bushj3 @@ -1822,30 +1846,6 @@ entities: 2540: -37,-14 2541: -36,-14 2542: -38,-14 - - node: - color: '#D381C95D' - id: CheckerNWSE - decals: - 2862: 20,-30 - 2863: 19,-30 - 2864: 19,-31 - 2865: 20,-31 - 2866: 21,-31 - 2867: 21,-30 - 2868: 22,-30 - 2869: 22,-31 - 2870: 22,-32 - 2871: 21,-32 - 2872: 20,-32 - 2873: 19,-32 - 2874: 19,-33 - 2875: 20,-33 - 2876: 21,-33 - 2877: 22,-33 - 2878: 22,-34 - 2879: 21,-34 - 2880: 20,-34 - 2881: 19,-34 - node: color: '#D4D4D428' id: CheckerNWSE @@ -2044,20 +2044,16 @@ entities: 2933: 14,-44 2934: -16,-44 2935: -16,-39 - - node: - color: '#52B4E996' - id: DeliveryGreyscale - decals: - 841: 18,10 - 1497: 15,12 - node: color: '#DE3A3A96' id: DeliveryGreyscale decals: - 842: 8,10 891: 10,13 892: 16,13 - 1496: 11,12 + 3360: 10,12 + 3361: 10,11 + 3362: 10,10 + 3363: 10,9 - node: color: '#FFFFFFFF' id: DeliveryGreyscale @@ -2243,8 +2239,9 @@ entities: color: '#52B4E996' id: FullTileOverlayGreyscale decals: - 2823: -13,-9 - 2824: -12,-9 + 3263: -11,-7 + 3264: -12,-7 + 3265: -13,-7 - node: color: '#79150096' id: FullTileOverlayGreyscale @@ -2269,8 +2266,8 @@ entities: color: '#A4610696' id: FullTileOverlayGreyscale decals: - 2821: -13,-7 - 2822: -12,-7 + 3266: -13,-9 + 3267: -12,-9 - node: color: '#D381C996' id: FullTileOverlayGreyscale @@ -2660,7 +2657,6 @@ entities: decals: 1856: 13,-35 1857: 13,-33 - 1858: 13,-31 - node: color: '#D4D4D428' id: HalfTileOverlayGreyscale270 @@ -2886,6 +2882,35 @@ entities: 1374: -2,26 1375: -2,27 1376: -2,28 + - node: + color: '#D381C996' + id: QuarterTileOverlayGreyscale + decals: + 3126: 19,-30 + 3127: 20,-30 + 3128: 21,-30 + 3129: 22,-30 + 3130: 23,-30 + 3131: 23,-31 + 3132: 22,-31 + 3133: 21,-31 + 3134: 20,-31 + 3135: 19,-31 + 3136: 23,-34 + 3137: 23,-33 + 3138: 23,-32 + 3139: 22,-32 + 3140: 22,-33 + 3141: 22,-34 + 3142: 21,-34 + 3143: 20,-34 + 3144: 20,-33 + 3145: 21,-33 + 3146: 21,-32 + 3147: 20,-32 + 3148: 19,-32 + 3149: 19,-33 + 3150: 19,-34 - node: color: '#D4D4D428' id: QuarterTileOverlayGreyscale @@ -3077,6 +3102,35 @@ entities: 1356: 2,18 1357: 3,18 1358: 4,18 + - node: + color: '#D381C996' + id: QuarterTileOverlayGreyscale180 + decals: + 3151: 19,-32 + 3152: 19,-33 + 3153: 19,-34 + 3154: 20,-34 + 3155: 20,-33 + 3156: 20,-32 + 3157: 21,-32 + 3158: 21,-33 + 3159: 21,-34 + 3160: 22,-34 + 3161: 22,-33 + 3162: 22,-32 + 3163: 23,-32 + 3164: 23,-33 + 3165: 23,-34 + 3166: 23,-31 + 3167: 23,-30 + 3168: 22,-30 + 3169: 22,-31 + 3170: 21,-31 + 3171: 21,-30 + 3172: 19,-30 + 3173: 20,-30 + 3174: 20,-31 + 3175: 19,-31 - node: color: '#D4D4D428' id: QuarterTileOverlayGreyscale180 @@ -3639,13 +3693,20 @@ entities: 1404: 4,19 1405: 4,20 1498: 7,7 - 1499: 7,8 + - node: + color: '#CC8000FF' + id: WarnLineGreyscaleE + decals: + 3358: 6,8 + 3359: 6,11 - node: color: '#DE3A3A96' id: WarnLineGreyscaleE decals: 887: 17,10 888: 17,4 + 3238: 17,12 + 3269: 17,11 - node: color: '#FFFFFFFF' id: WarnLineGreyscaleE @@ -3685,9 +3746,9 @@ entities: 480: 9,1 481: 10,1 702: 33,-16 - 889: 10,12 890: 16,12 992: 13,20 + 3339: 9,12 - node: color: '#FA750096' id: WarnLineGreyscaleN @@ -3730,9 +3791,8 @@ entities: color: '#DE3A3A96' id: WarnLineGreyscaleW decals: - 886: 9,10 - 1500: 9,7 - 1501: 9,8 + 3337: 8,8 + 3338: 8,11 - node: color: '#FFFFFFFF' id: WarnLineGreyscaleW @@ -4192,25 +4252,25 @@ entities: 0,1: 0: 45567 0,2: - 0: 47931 + 0: 48059 0,3: 0: 65307 0,4: 0: 65311 1,1: - 0: 61559 + 0: 28791 1,2: - 0: 65295 + 0: 63359 1,3: - 0: 65295 + 0: 65287 1,4: 0: 56591 2,1: 0: 63231 2,2: - 0: 61423 + 0: 30591 2,3: - 0: 65359 + 0: 65319 2,4: 0: 64783 3,1: @@ -4226,7 +4286,7 @@ entities: 4,1: 0: 46015 4,2: - 0: 48955 + 0: 65339 4,3: 0: 65311 4,-5: @@ -4247,13 +4307,14 @@ entities: 0: 15 1: 3584 6,-2: - 0: 65520 + 0: 65524 6,-1: 0: 65535 6,-5: 0: 65535 6,-3: - 1: 57344 + 1: 14 + 0: 60928 6,0: 0: 65535 7,-4: @@ -4288,10 +4349,10 @@ entities: 0: 61167 6,1: 0: 61183 - 6,3: - 0: 65294 6,2: - 0: 60942 + 0: 56590 + 6,3: + 0: 65293 6,4: 0: 65535 7,1: @@ -4342,6 +4403,8 @@ entities: 0: 65535 6,-6: 0: 65535 + 6,-8: + 0: 16384 7,-7: 0: 32767 7,-6: @@ -4731,22 +4794,20 @@ entities: 0: 4368 -5,-6: 0: 4368 - -6,-13: - 0: 57344 -6,-12: 0: 2176 -6,-11: 0: 34824 -6,-10: 0: 32896 + -6,-13: + 0: 34944 -5,-13: 0: 61440 -5,-11: 0: 26214 4,-13: - 0: 61440 - 5,-13: - 0: 12288 + 0: 63616 -12,0: 0: 53503 -12,-1: @@ -4766,11 +4827,11 @@ entities: -10,0: 0: 61695 -10,1: - 0: 61439 + 0: 65535 -10,-1: 0: 65522 -10,2: - 0: 61152 + 0: 61156 -10,3: 0: 238 -12,-2: @@ -4892,6 +4953,7 @@ entities: chunkSize: 4 - type: OccluderTree - type: Shuttle + dampingModifier: 0.25 - type: RadiationGridResistance - type: GravityShake shakeTimes: 10 @@ -4992,15 +5054,22 @@ entities: parent: 1668 - type: DeviceLinkSink invokeCounter: 1 + - uid: 1589 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,8.5 + parent: 1668 - uid: 1604 components: - type: Transform pos: 16.5,13.5 parent: 1668 - - uid: 1605 + - uid: 1615 components: - type: Transform - pos: 10.5,13.5 + rot: 3.141592653589793 rad + pos: 11.5,7.5 parent: 1668 - proto: AirlockBrigLocked entities: @@ -5289,6 +5358,11 @@ entities: parent: 1668 - proto: AirlockCommandGlassLocked entities: + - uid: 1587 + components: + - type: Transform + pos: 26.5,-28.5 + parent: 1668 - uid: 6753 components: - type: Transform @@ -5566,6 +5640,13 @@ entities: - type: Transform pos: 14.5,-20.5 parent: 1668 +- proto: AirlockGlass + entities: + - uid: 9994 + components: + - type: Transform + pos: 26.5,-7.5 + parent: 1668 - proto: AirlockGlassShuttle entities: - uid: 3642 @@ -5717,20 +5798,6 @@ entities: - type: Transform pos: -18.5,-43.5 parent: 1668 -- proto: AirlockSecurityGlassLocked - entities: - - uid: 1581 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,10.5 - parent: 1668 - - uid: 1582 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 18.5,10.5 - parent: 1668 - proto: AirlockSecurityLocked entities: - uid: 556 @@ -5755,17 +5822,15 @@ entities: parent: 1668 - proto: AirlockShuttle entities: - - uid: 4617 + - uid: 5218 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 21.5,-48.5 + pos: -20.5,-50.5 parent: 1668 - - uid: 4618 + - uid: 9118 components: - type: Transform - rot: -1.5707963267948966 rad - pos: -22.5,-48.5 + pos: 19.5,-50.5 parent: 1668 - proto: AlwaysPoweredLightSodium entities: @@ -6269,16 +6334,6 @@ entities: - type: Transform pos: -21.5,18.5 parent: 1668 - - uid: 4619 - components: - - type: Transform - pos: 21.5,-48.5 - parent: 1668 - - uid: 4620 - components: - - type: Transform - pos: -22.5,-48.5 - parent: 1668 - uid: 5646 components: - type: Transform @@ -6588,16 +6643,6 @@ entities: - type: Transform pos: 33.5,-19.5 parent: 1668 - - uid: 1623 - components: - - type: Transform - pos: 23.5,10.5 - parent: 1668 - - uid: 1624 - components: - - type: Transform - pos: 3.5,10.5 - parent: 1668 - uid: 2826 components: - type: Transform @@ -7230,6 +7275,11 @@ entities: - type: Transform pos: 29.5,-13.5 parent: 1668 + - uid: 2104 + components: + - type: Transform + pos: 9.5,13.5 + parent: 1668 - uid: 2252 components: - type: Transform @@ -7304,6 +7354,11 @@ entities: - type: Transform pos: -23.5,11.5 parent: 1668 + - uid: 2923 + components: + - type: Transform + pos: 5.5,7.5 + parent: 1668 - uid: 4446 components: - type: Transform @@ -7409,6 +7464,11 @@ entities: - type: Transform pos: -0.24795187,1.5721796 parent: 1668 + - uid: 1611 + components: + - type: Transform + pos: 33.64069,11.514202 + parent: 1668 - uid: 1986 components: - type: Transform @@ -7419,11 +7479,6 @@ entities: - type: Transform pos: 27.5,21.5 parent: 1668 - - uid: 2083 - components: - - type: Transform - pos: 32.58944,11.550044 - parent: 1668 - uid: 6767 components: - type: Transform @@ -7456,6 +7511,40 @@ entities: - type: Transform pos: -17.46816,12.582452 parent: 1668 + - uid: 4560 + components: + - type: Transform + parent: 4559 + - type: Storage + storedItems: + 4617: + position: 0,0 + _rotation: South + 4618: + position: 1,0 + _rotation: South + 4619: + position: 3,0 + _rotation: South + 4620: + position: 2,0 + _rotation: South + 4656: + position: 4,0 + _rotation: South + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: + - 4617 + - 4618 + - 4619 + - 4620 + - 4656 + - type: Physics + canCollide: False - uid: 9577 components: - type: Transform @@ -7473,6 +7562,12 @@ entities: - type: Transform pos: -3.6052928,-1.4909649 parent: 1668 + - uid: 4838 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False - uid: 5999 components: - type: Transform @@ -7529,7 +7624,7 @@ entities: - uid: 533 components: - type: Transform - pos: -0.71670187,1.5721796 + pos: -0.73396444,1.5546008 parent: 1668 - uid: 1987 components: @@ -7541,10 +7636,10 @@ entities: - type: Transform pos: 25.5,21.5 parent: 1668 - - uid: 2089 + - uid: 2088 components: - type: Transform - pos: 32.386314,11.675044 + pos: 33.411522,11.701833 parent: 1668 - uid: 6768 components: @@ -7580,7 +7675,7 @@ entities: - uid: 8815 components: - type: Transform - pos: -13.5,-6.5 + pos: -13.649994,-6.1762576 parent: 1668 - proto: BoxingBell entities: @@ -7594,7 +7689,7 @@ entities: - uid: 1093 components: - type: Transform - pos: 34.536674,-20.85105 + pos: 34.34723,-21.065468 parent: 1668 - proto: BoxMagazineLightRifle entities: @@ -7610,10 +7705,10 @@ entities: parent: 1668 - proto: BoxMagazinePistolPractice entities: - - uid: 2984 + - uid: 9962 components: - type: Transform - pos: 11.430329,8.720324 + pos: 18.81643,12.32891 parent: 1668 - proto: BoxMagazinePistolSubMachineGun entities: @@ -7639,10 +7734,10 @@ entities: parent: 1668 - proto: BoxMagazinePistolSubMachineGunPractice entities: - - uid: 1742 + - uid: 9979 components: - type: Transform - pos: 11.445954,9.423449 + pos: 18.618511,12.672898 parent: 1668 - proto: BoxMagazinePistolSubMachineGunTopMounted entities: @@ -7699,10 +7794,10 @@ entities: - type: InsideEntityStorage - proto: BoxMagazineRiflePractice entities: - - uid: 1735 + - uid: 9978 components: - type: Transform - pos: 11.430329,9.079699 + pos: 18.524761,12.381029 parent: 1668 - proto: BoxMagazineShotgun entities: @@ -7776,42 +7871,42 @@ entities: - uid: 1323 components: - type: Transform - pos: 34.536674,-21.41355 + pos: 34.325996,-21.70354 parent: 1668 - proto: BoxShotgunFlare entities: - uid: 1329 components: - type: Transform - pos: 34.567924,-22.2573 + pos: 34.711796,-22.506569 parent: 1668 - proto: BoxShotgunIncendiary entities: - uid: 1311 components: - type: Transform - pos: 34.52105,-21.1323 + pos: 34.723774,-21.334171 parent: 1668 - proto: BoxShotgunSlug entities: - uid: 1335 components: - type: Transform - pos: 34.5523,-21.72605 + pos: 34.71797,-21.851793 parent: 1668 - proto: BoxShotgunUranium entities: - uid: 1334 components: - type: Transform - pos: 34.567924,-21.97605 + pos: 34.31652,-22.311989 parent: 1668 - proto: BoxZiptie entities: - - uid: 1744 + - uid: 1570 components: - type: Transform - pos: 13.5,7.5 + pos: 14.462548,8.4831295 parent: 1668 - uid: 6811 components: @@ -7846,28 +7941,63 @@ entities: - type: Transform pos: -38.7273,13.7666025 parent: 1668 -- proto: BrigTimer +- proto: BriefcaseBrown entities: - - uid: 1601 + - uid: 4559 components: - type: Transform - pos: 18.5,9.5 - parent: 1668 - - type: DeviceLinkSource - linkedPorts: - 1582: - - Start: Close - - Timer: Open - - uid: 1602 - components: - - type: Transform - pos: 8.5,9.5 - parent: 1668 - - type: DeviceLinkSource - linkedPorts: - 1581: - - Start: Close - - Timer: Open + parent: 1610 + - type: Storage + storedItems: + 4560: + position: 0,0 + _rotation: South + 4838: + position: 1,0 + _rotation: South + 7566: + position: 2,0 + _rotation: South + 9115: + position: 2,1 + _rotation: South + 9449: + position: 3,0 + _rotation: South + 9457: + position: 3,1 + _rotation: South + 9463: + position: 4,1 + _rotation: South + 9681: + position: 4,0 + _rotation: South + 9682: + position: 0,2 + _rotation: South + 9683: + position: 5,0 + _rotation: South + - type: ContainerContainer + containers: + storagebase: !type:Container + showEnts: False + occludes: True + ents: + - 4560 + - 4838 + - 7566 + - 9115 + - 9449 + - 9457 + - 9463 + - 9681 + - 9682 + - 9683 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: Bucket entities: - uid: 1034 @@ -9231,6 +9361,41 @@ entities: - type: Transform pos: 21.5,25.5 parent: 1668 + - uid: 912 + components: + - type: Transform + pos: 7.5,7.5 + parent: 1668 + - uid: 916 + components: + - type: Transform + pos: 5.5,6.5 + parent: 1668 + - uid: 919 + components: + - type: Transform + pos: 7.5,8.5 + parent: 1668 + - uid: 921 + components: + - type: Transform + pos: 2.5,7.5 + parent: 1668 + - uid: 922 + components: + - type: Transform + pos: 4.5,6.5 + parent: 1668 + - uid: 923 + components: + - type: Transform + pos: 6.5,6.5 + parent: 1668 + - uid: 924 + components: + - type: Transform + pos: 2.5,8.5 + parent: 1668 - uid: 939 components: - type: Transform @@ -9986,16 +10151,6 @@ entities: - type: Transform pos: 4.5,10.5 parent: 1668 - - uid: 1665 - components: - - type: Transform - pos: 3.5,10.5 - parent: 1668 - - uid: 1666 - components: - - type: Transform - pos: 2.5,10.5 - parent: 1668 - uid: 1667 components: - type: Transform @@ -10036,35 +10191,15 @@ entities: - type: Transform pos: 6.5,13.5 parent: 1668 - - uid: 1676 - components: - - type: Transform - pos: 8.5,11.5 - parent: 1668 - uid: 1677 components: - type: Transform pos: 7.5,9.5 parent: 1668 - - uid: 1678 - components: - - type: Transform - pos: 6.5,9.5 - parent: 1668 - - uid: 1679 - components: - - type: Transform - pos: 5.5,9.5 - parent: 1668 - uid: 1680 components: - type: Transform - pos: 4.5,9.5 - parent: 1668 - - uid: 1681 - components: - - type: Transform - pos: 3.5,9.5 + pos: 5.5,7.5 parent: 1668 - uid: 1682 components: @@ -10276,6 +10411,11 @@ entities: - type: Transform pos: 10.5,3.5 parent: 1668 + - uid: 1738 + components: + - type: Transform + pos: -20.5,-49.5 + parent: 1668 - uid: 2679 components: - type: Transform @@ -12226,6 +12366,11 @@ entities: - type: Transform pos: -0.5,7.5 parent: 1668 + - uid: 4505 + components: + - type: Transform + pos: 19.5,-49.5 + parent: 1668 - uid: 5165 components: - type: Transform @@ -12371,11 +12516,6 @@ entities: - type: Transform pos: 19.5,-48.5 parent: 1668 - - uid: 5194 - components: - - type: Transform - pos: 20.5,-48.5 - parent: 1668 - uid: 5195 components: - type: Transform @@ -12491,11 +12631,6 @@ entities: - type: Transform pos: -20.5,-48.5 parent: 1668 - - uid: 5218 - components: - - type: Transform - pos: -21.5,-48.5 - parent: 1668 - uid: 5219 components: - type: Transform @@ -15201,6 +15336,66 @@ entities: - type: Transform pos: -0.5,-8.5 parent: 1668 + - uid: 9769 + components: + - type: Transform + pos: 5.5,8.5 + parent: 1668 + - uid: 9784 + components: + - type: Transform + pos: 5.5,9.5 + parent: 1668 + - uid: 9886 + components: + - type: Transform + pos: 23.5,-30.5 + parent: 1668 + - uid: 9984 + components: + - type: Transform + pos: 5.5,10.5 + parent: 1668 + - uid: 9985 + components: + - type: Transform + pos: 4.5,8.5 + parent: 1668 + - uid: 9986 + components: + - type: Transform + pos: 3.5,8.5 + parent: 1668 + - uid: 9987 + components: + - type: Transform + pos: 3.5,11.5 + parent: 1668 + - uid: 9995 + components: + - type: Transform + pos: 26.5,-5.5 + parent: 1668 + - uid: 9996 + components: + - type: Transform + pos: 26.5,-6.5 + parent: 1668 + - uid: 9997 + components: + - type: Transform + pos: 26.5,-7.5 + parent: 1668 + - uid: 9998 + components: + - type: Transform + pos: 26.5,-8.5 + parent: 1668 + - uid: 9999 + components: + - type: Transform + pos: 26.5,-9.5 + parent: 1668 - proto: CableApcStack entities: - uid: 6776 @@ -20029,7 +20224,7 @@ entities: - uid: 499 components: - type: Transform - pos: 1.5249417,-2.3881862 + pos: -3.5328715,-1.3873212 parent: 1668 - uid: 2812 components: @@ -20050,6 +20245,18 @@ entities: parent: 1668 - proto: Carpet entities: + - uid: 926 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 32.5,-21.5 + parent: 1668 + - uid: 929 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,-21.5 + parent: 1668 - uid: 1194 components: - type: Transform @@ -20060,16 +20267,6 @@ entities: - type: Transform pos: 32.5,-22.5 parent: 1668 - - uid: 1294 - components: - - type: Transform - pos: 32.5,-21.5 - parent: 1668 - - uid: 1295 - components: - - type: Transform - pos: 32.5,-20.5 - parent: 1668 - uid: 1976 components: - type: Transform @@ -20120,6 +20317,42 @@ entities: - type: Transform pos: -49.5,5.5 parent: 1668 + - uid: 10000 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,-22.5 + parent: 1668 + - uid: 10001 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,-22.5 + parent: 1668 + - uid: 10002 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,-21.5 + parent: 1668 + - uid: 10003 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,-20.5 + parent: 1668 + - uid: 10004 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,-20.5 + parent: 1668 + - uid: 10005 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 32.5,-20.5 + parent: 1668 - proto: CarpetBlack entities: - uid: 9650 @@ -20520,26 +20753,26 @@ entities: parent: 1668 - proto: CarpetOrange entities: + - uid: 1526 + components: + - type: Transform + pos: 31.5,12.5 + parent: 1668 + - uid: 1576 + components: + - type: Transform + pos: 33.5,12.5 + parent: 1668 + - uid: 1579 + components: + - type: Transform + pos: 33.5,11.5 + parent: 1668 - uid: 2074 components: - type: Transform pos: 31.5,11.5 parent: 1668 - - uid: 2076 - components: - - type: Transform - pos: 30.5,12.5 - parent: 1668 - - uid: 2085 - components: - - type: Transform - pos: 30.5,11.5 - parent: 1668 - - uid: 2090 - components: - - type: Transform - pos: 31.5,12.5 - parent: 1668 - uid: 2091 components: - type: Transform @@ -20696,6 +20929,11 @@ entities: parent: 1668 - proto: Catwalk entities: + - uid: 1739 + components: + - type: Transform + pos: 19.5,-49.5 + parent: 1668 - uid: 3236 components: - type: Transform @@ -20801,6 +21039,11 @@ entities: - type: Transform pos: -27.5,20.5 parent: 1668 + - uid: 4562 + components: + - type: Transform + pos: -20.5,-49.5 + parent: 1668 - uid: 4840 components: - type: Transform @@ -20816,11 +21059,6 @@ entities: - type: Transform pos: -20.5,-48.5 parent: 1668 - - uid: 4845 - components: - - type: Transform - pos: -21.5,-48.5 - parent: 1668 - uid: 4846 components: - type: Transform @@ -20836,11 +21074,6 @@ entities: - type: Transform pos: 19.5,-48.5 parent: 1668 - - uid: 4849 - components: - - type: Transform - pos: 20.5,-48.5 - parent: 1668 - uid: 6217 components: - type: Transform @@ -20966,8 +21199,10 @@ entities: - uid: 500 components: - type: Transform - pos: 1.6499417,-2.5131862 - parent: 1668 + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - uid: 2814 components: - type: Transform @@ -20980,18 +21215,18 @@ entities: - type: Transform pos: -15.5,13.5 parent: 1668 + - uid: 2437 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-2.5 + parent: 1668 - uid: 2820 components: - type: Transform rot: 1.5707963267948966 rad pos: -38.5,12.5 parent: 1668 - - uid: 2936 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -1.5,-2.5 - parent: 1668 - uid: 6006 components: - type: Transform @@ -21003,13 +21238,10 @@ entities: - uid: 22 components: - type: Transform - pos: 1.5543553,-2.2420077 - parent: 1668 - - uid: 935 - components: - - type: Transform - pos: 1.5543553,-2.2420077 - parent: 1668 + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - uid: 2817 components: - type: Transform @@ -21256,6 +21488,12 @@ entities: rot: -1.5707963267948966 rad pos: 28.5,12.5 parent: 1668 + - uid: 2121 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,7.5 + parent: 1668 - uid: 2122 components: - type: Transform @@ -21446,23 +21684,23 @@ entities: rot: -1.5707963267948966 rad pos: 33.5,-10.5 parent: 1668 + - uid: 1528 + components: + - type: Transform + pos: 33.5,12.5 + parent: 1668 + - uid: 1549 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 31.5,11.5 + parent: 1668 - uid: 1621 components: - type: Transform rot: 3.141592653589793 rad pos: 13.5,12.5 parent: 1668 - - uid: 2075 - components: - - type: Transform - pos: 32.5,12.5 - parent: 1668 - - uid: 2121 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 30.570415,11.596919 - parent: 1668 - uid: 2895 components: - type: Transform @@ -22528,6 +22766,13 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage + - uid: 9686 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: ClothingMaskGasDeathSquad entities: - uid: 2469 @@ -22674,6 +22919,15 @@ entities: - type: Transform pos: -3.5,-31.5 parent: 1668 +- proto: ClothingNeckScarfStripedCentcom + entities: + - uid: 4523 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: ClothingOuterArmorCaptainCarapace entities: - uid: 1101 @@ -22681,6 +22935,15 @@ entities: - type: Transform pos: -11.664687,7.5583878 parent: 1668 +- proto: ClothingOuterArmorCentcommCarapace + entities: + - uid: 9685 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: ClothingOuterArmorHeavyRed entities: - uid: 4640 @@ -22977,6 +23240,15 @@ entities: - type: Transform pos: -22.480219,-6.422328 parent: 1668 +- proto: ClothingUniformJumpskirtCentcomFormalDress + entities: + - uid: 1750 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: ClothingUniformJumpskirtHoSParadeMale entities: - uid: 3242 @@ -22992,6 +23264,15 @@ entities: - type: Transform pos: -8.014507,-17.209332 parent: 1668 +- proto: ClothingUniformJumpsuitCentcomFormal + entities: + - uid: 1737 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: ClothingUniformJumpsuitDeathSquad entities: - uid: 2467 @@ -23357,14 +23638,6 @@ entities: - type: Transform pos: -2.5,32.5 parent: 1668 -- proto: ComputerCargoShuttle - entities: - - uid: 3907 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,23.5 - parent: 1668 - proto: ComputerCloningConsole entities: - uid: 732 @@ -23375,9 +23648,11 @@ entities: - type: DeviceLinkSource linkedPorts: 734: - - MedicalScannerSender: MedicalScannerReceiver + - - MedicalScannerSender + - MedicalScannerReceiver 733: - - CloningPodSender: CloningPodReceiver + - - CloningPodSender + - CloningPodReceiver - proto: ComputerComms entities: - uid: 2821 @@ -23392,6 +23667,14 @@ entities: rot: 3.141592653589793 rad pos: -43.5,-8.5 parent: 1668 +- proto: ComputerCrewMonitoring + entities: + - uid: 2438 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,-2.5 + parent: 1668 - proto: ComputerCriminalRecords entities: - uid: 363 @@ -23399,9 +23682,10 @@ entities: - type: Transform pos: 14.5,4.5 parent: 1668 - - uid: 1620 + - uid: 1538 components: - type: Transform + rot: -1.5707963267948966 rad pos: 14.5,12.5 parent: 1668 - proto: ComputerId @@ -23439,6 +23723,12 @@ entities: - type: Transform pos: 3.5,32.5 parent: 1668 + - uid: 3907 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,23.5 + parent: 1668 - proto: ComputerSurveillanceCameraMonitor entities: - uid: 8816 @@ -23461,11 +23751,29 @@ entities: parent: 1668 - proto: ConveyorBelt entities: + - uid: 1600 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 23.5,10.5 + parent: 1668 + - uid: 1624 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,12.5 + parent: 1668 + - uid: 1625 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,11.5 + parent: 1668 - uid: 1626 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 23.5,12.5 + rot: 1.5707963267948966 rad + pos: 24.5,10.5 parent: 1668 - uid: 1627 components: @@ -23475,12 +23783,34 @@ entities: parent: 1668 - type: DeviceLinkSink invokeCounter: 1 + - uid: 1744 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,12.5 + parent: 1668 + - uid: 1751 + components: + - type: Transform + pos: 22.5,11.5 + parent: 1668 + - uid: 2085 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 23.5,12.5 + parent: 1668 - uid: 3264 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,30.5 parent: 1668 + - uid: 3520 + components: + - type: Transform + pos: 22.5,10.5 + parent: 1668 - uid: 3638 components: - type: Transform @@ -23644,6 +23974,20 @@ entities: - type: Transform pos: -23.5,-4.5 parent: 1668 +- proto: CrayonBox + entities: + - uid: 8183 + components: + - type: Transform + pos: 6.515189,7.596311 + parent: 1668 +- proto: CrewMonitoringServer + entities: + - uid: 8793 + components: + - type: Transform + pos: -10.5,-6.5 + parent: 1668 - proto: CrowbarGreen entities: - uid: 3173 @@ -23712,6 +24056,36 @@ entities: - type: Transform pos: -30.541765,-7.579217 parent: 1668 +- proto: CryogenicSleepUnit + entities: + - uid: 9981 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,8.5 + parent: 1668 + - uid: 9990 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,-8.5 + parent: 1668 + - uid: 9991 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,-9.5 + parent: 1668 + - uid: 9992 + components: + - type: Transform + pos: 27.5,-8.5 + parent: 1668 + - uid: 9993 + components: + - type: Transform + pos: 27.5,-9.5 + parent: 1668 - proto: CryoPod entities: - uid: 677 @@ -23904,6 +24278,15 @@ entities: - type: Transform pos: 9.760128,-23.47621 parent: 1668 +- proto: DeathRattleImplanterCentcomm + entities: + - uid: 4544 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - proto: DeathsquadPDA entities: - uid: 2470 @@ -23956,19 +24339,84 @@ entities: - type: Transform pos: -12.5,5.5 parent: 1668 -- proto: DefaultStationBeaconCentComm +- proto: DefaultStationBeaconAnchor entities: - - uid: 4656 + - uid: 9928 components: - type: Transform - pos: -0.5,3.5 + pos: -11.5,26.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconArmory + entities: + - uid: 9910 + components: + - type: Transform + pos: 13.5,22.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconArrivals + entities: + - uid: 9977 + components: + - type: Transform + pos: 26.5,-0.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconAtmospherics + entities: + - uid: 9908 + components: + - type: Transform + pos: -19.5,21.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconBar + entities: + - uid: 9914 + components: + - type: Transform + pos: 8.5,-33.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconBotany + entities: + - uid: 9918 + components: + - type: Transform + pos: 6.5,-21.5 + parent: 1668 + - type: NavMapBeacon + text: Botany + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconCargoBay + entities: + - uid: 9909 + components: + - type: Transform + pos: 3.5,27.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconCentComm + entities: + - uid: 9119 + components: + - type: Transform + pos: -0.5,-0.5 parent: 1668 - proto: DefaultStationBeaconCentCommAfterhours entities: - uid: 9452 components: - type: Transform - pos: 22.5,-21.5 + pos: 27.5,-21.5 parent: 1668 - proto: DefaultStationBeaconCentCommERT entities: @@ -23984,6 +24432,125 @@ entities: - type: Transform pos: -0.5,-41.5 parent: 1668 +- proto: DefaultStationBeaconChemistry + entities: + - uid: 9919 + components: + - type: Transform + pos: 7.5,-10.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconCourtroom + entities: + - uid: 9911 + components: + - type: Transform + pos: 26.5,17.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconEngineering + entities: + - uid: 9907 + components: + - type: Transform + pos: -6.5,10.5 + parent: 1668 + - type: NavMapBeacon + text: Engineering + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconGravGen + entities: + - uid: 9927 + components: + - type: Transform + pos: -5.5,26.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconJanitorsCloset + entities: + - uid: 9923 + components: + - type: Transform + pos: -5.5,-10.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconKitchen + entities: + - uid: 9915 + components: + - type: Transform + pos: -9.5,-33.5 + parent: 1668 + missingComponents: + - WarpPoint + - uid: 9917 + components: + - type: Transform + pos: 15.5,-17.5 + parent: 1668 + - type: NavMapBeacon + text: Kitchen + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconLawOffice + entities: + - uid: 9922 + components: + - type: Transform + pos: 29.5,11.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconMedbay + entities: + - uid: 9920 + components: + - type: Transform + pos: 18.5,-10.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconScience + entities: + - uid: 9924 + components: + - type: Transform + pos: 21.5,-30.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconSecurity + entities: + - uid: 9912 + components: + - type: Transform + pos: 13.5,9.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconSecurityCheckpoint + entities: + - uid: 9925 + components: + - type: Transform + pos: 33.5,-11.5 + parent: 1668 + missingComponents: + - WarpPoint +- proto: DefaultStationBeaconTelecoms + entities: + - uid: 9921 + components: + - type: Transform + pos: -12.5,-7.5 + parent: 1668 + missingComponents: + - WarpPoint - proto: DefibrillatorCabinetFilled entities: - uid: 511 @@ -26314,10 +26881,10 @@ entities: parent: 1668 - proto: DrinkMugMetal entities: - - uid: 2088 + - uid: 905 components: - type: Transform - pos: 31.480066,11.690669 + pos: 32.55041,11.7296295 parent: 1668 - proto: DrinkShaker entities: @@ -26489,6 +27056,36 @@ entities: - type: Transform pos: 13.91264,32.80469 parent: 1668 + - uid: 2936 + components: + - type: Transform + pos: 17.020287,35.027782 + parent: 1668 + - uid: 6390 + components: + - type: Transform + pos: 16.71473,34.59847 + parent: 1668 + - uid: 9973 + components: + - type: Transform + pos: 17.020287,34.79305 + parent: 1668 + - uid: 9974 + components: + - type: Transform + pos: 16.702385,35.043224 + parent: 1668 + - uid: 9975 + components: + - type: Transform + pos: 16.699299,34.827023 + parent: 1668 + - uid: 9976 + components: + - type: Transform + pos: 17.020287,34.57685 + parent: 1668 - proto: ERTEngineerPDA entities: - uid: 6784 @@ -26676,24 +27273,12 @@ entities: rot: -1.5707963267948966 rad pos: -22.5,-11.5 parent: 1668 -- proto: filingCabinetDrawerRandom - entities: - - uid: 498 - components: - - type: Transform - pos: 0.5,-2.5 - parent: 1668 - - uid: 2084 - components: - - type: Transform - pos: 25.5,10.5 - parent: 1668 - proto: filingCabinetRandom entities: - - uid: 2082 + - uid: 1537 components: - type: Transform - pos: 30.5,12.5 + pos: 31.5,12.5 parent: 1668 - uid: 6725 components: @@ -26897,11 +27482,6 @@ entities: parent: 1668 - proto: FlashlightSeclite entities: - - uid: 3613 - components: - - type: Transform - pos: 15.5,7.5 - parent: 1668 - uid: 6756 components: - type: Transform @@ -27222,6 +27802,18 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage +- proto: FoodPlateSmall + entities: + - uid: 1198 + components: + - type: Transform + pos: 6.4804764,10.508464 + parent: 1668 + - uid: 4186 + components: + - type: Transform + pos: 6.4908934,9.705824 + parent: 1668 - proto: FoodPoppy entities: - uid: 1709 @@ -27243,6 +27835,20 @@ entities: - type: Transform pos: 21.580595,-15.908045 parent: 1668 +- proto: ForkPlastic + entities: + - uid: 1356 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.51475,9.705824 + parent: 1668 + - uid: 2093 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5043335,10.518888 + parent: 1668 - proto: FreedomImplanter entities: - uid: 2473 @@ -28192,6 +28798,14 @@ entities: color: '#0335FCFF' - proto: GasPipeStraight entities: + - uid: 498 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,3.5 + parent: 1668 + - type: AtmosPipeColor + color: '#FF1212FF' - uid: 695 components: - type: Transform @@ -28208,6 +28822,22 @@ entities: - type: Transform pos: 15.5,-9.5 parent: 1668 + - uid: 1357 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,10.5 + parent: 1668 + - type: AtmosPipeColor + color: '#FF1212FF' + - uid: 1748 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,12.5 + parent: 1668 + - type: AtmosPipeColor + color: '#0335FCFF' - uid: 3481 components: - type: Transform @@ -28890,14 +29520,6 @@ entities: parent: 1668 - type: AtmosPipeColor color: '#FF1212FF' - - uid: 7566 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -0.5,3.5 - parent: 1668 - - type: AtmosPipeColor - color: '#FF1212FF' - uid: 7568 components: - type: Transform @@ -32074,13 +32696,6 @@ entities: parent: 1668 - type: AtmosPipeColor color: '#0335FCFF' - - uid: 8046 - components: - - type: Transform - pos: 9.5,7.5 - parent: 1668 - - type: AtmosPipeColor - color: '#0335FCFF' - uid: 8047 components: - type: Transform @@ -32286,14 +32901,6 @@ entities: parent: 1668 - type: AtmosPipeColor color: '#FF1212FF' - - uid: 8077 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,10.5 - parent: 1668 - - type: AtmosPipeColor - color: '#FF1212FF' - uid: 8078 components: - type: Transform @@ -36955,6 +37562,21 @@ entities: rot: 1.5707963267948966 rad pos: 17.5,-9.5 parent: 1668 + - uid: 1571 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 9.5,7.5 + parent: 1668 + - type: AtmosPipeColor + color: '#0335FCFF' + - uid: 1575 + components: + - type: Transform + pos: 8.5,10.5 + parent: 1668 + - type: AtmosPipeColor + color: '#FF1212FF' - uid: 1734 components: - type: Transform @@ -38093,6 +38715,8 @@ entities: - type: Transform pos: 12.5,-21.5 parent: 1668 + - type: GasThermoMachine + targetTemperature: 73.15 - proto: GasThermoMachineFreezerEnabled entities: - uid: 683 @@ -38100,8 +38724,26 @@ entities: - type: Transform pos: 18.5,-8.5 parent: 1668 + - type: GasThermoMachine + targetTemperature: 73.15 - proto: GasVentPump entities: + - uid: 3666 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,12.5 + parent: 1668 + - type: AtmosPipeColor + color: '#0335FCFF' + - uid: 4185 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,7.5 + parent: 1668 + - type: AtmosPipeColor + color: '#0335FCFF' - uid: 7547 components: - type: Transform @@ -38244,14 +38886,6 @@ entities: parent: 1668 - type: AtmosPipeColor color: '#0335FCFF' - - uid: 8186 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 21.5,12.5 - parent: 1668 - - type: AtmosPipeColor - color: '#0335FCFF' - uid: 8330 components: - type: Transform @@ -38683,6 +39317,22 @@ entities: color: '#0335FCFF' - proto: GasVentScrubber entities: + - uid: 1742 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,9.5 + parent: 1668 + - type: AtmosPipeColor + color: '#FF1212FF' + - uid: 3670 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,10.5 + parent: 1668 + - type: AtmosPipeColor + color: '#FF1212FF' - uid: 7507 components: - type: Transform @@ -38805,14 +39455,6 @@ entities: parent: 1668 - type: AtmosPipeColor color: '#FF1212FF' - - uid: 8183 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 21.5,10.5 - parent: 1668 - - type: AtmosPipeColor - color: '#FF1212FF' - uid: 8184 components: - type: Transform @@ -39475,6 +40117,11 @@ entities: - type: Transform pos: 29.5,-14.5 parent: 1668 + - uid: 94 + components: + - type: Transform + pos: 23.5,-29.5 + parent: 1668 - uid: 132 components: - type: Transform @@ -39490,6 +40137,11 @@ entities: - type: Transform pos: 28.5,7.5 parent: 1668 + - uid: 149 + components: + - type: Transform + pos: 23.5,-30.5 + parent: 1668 - uid: 154 components: - type: Transform @@ -39660,11 +40312,6 @@ entities: - type: Transform pos: 28.5,-11.5 parent: 1668 - - uid: 912 - components: - - type: Transform - pos: 28.5,-10.5 - parent: 1668 - uid: 913 components: - type: Transform @@ -39680,11 +40327,6 @@ entities: - type: Transform pos: 24.5,-11.5 parent: 1668 - - uid: 916 - components: - - type: Transform - pos: 24.5,-10.5 - parent: 1668 - uid: 917 components: - type: Transform @@ -39695,16 +40337,16 @@ entities: - type: Transform pos: 25.5,-7.5 parent: 1668 - - uid: 919 - components: - - type: Transform - pos: 26.5,-7.5 - parent: 1668 - uid: 920 components: - type: Transform pos: 27.5,-7.5 parent: 1668 + - uid: 935 + components: + - type: Transform + pos: 23.5,-33.5 + parent: 1668 - uid: 1102 components: - type: Transform @@ -39760,41 +40402,16 @@ entities: - type: Transform pos: 27.5,-28.5 parent: 1668 - - uid: 1350 - components: - - type: Transform - pos: 26.5,-28.5 - parent: 1668 - uid: 1351 components: - type: Transform pos: 25.5,-28.5 parent: 1668 - - uid: 1525 - components: - - type: Transform - pos: 3.5,9.5 - parent: 1668 - - uid: 1527 - components: - - type: Transform - pos: 6.5,9.5 - parent: 1668 - - uid: 1528 - components: - - type: Transform - pos: 5.5,9.5 - parent: 1668 - uid: 1529 components: - type: Transform pos: 2.5,7.5 parent: 1668 - - uid: 1530 - components: - - type: Transform - pos: 4.5,9.5 - parent: 1668 - uid: 1531 components: - type: Transform @@ -39830,16 +40447,6 @@ entities: - type: Transform pos: 6.5,13.5 parent: 1668 - - uid: 1549 - components: - - type: Transform - pos: 7.5,9.5 - parent: 1668 - - uid: 1551 - components: - - type: Transform - pos: 2.5,10.5 - parent: 1668 - uid: 1552 components: - type: Transform @@ -39850,6 +40457,11 @@ entities: - type: Transform pos: 2.5,12.5 parent: 1668 + - uid: 1554 + components: + - type: Transform + pos: 23.5,-32.5 + parent: 1668 - uid: 1564 components: - type: Transform @@ -39880,15 +40492,22 @@ entities: - type: Transform pos: 4.5,13.5 parent: 1668 - - uid: 1570 + - uid: 1580 components: - type: Transform - pos: 18.5,11.5 + pos: 23.5,-31.5 parent: 1668 - - uid: 1571 + - uid: 1588 components: - type: Transform - pos: 8.5,11.5 + rot: 1.5707963267948966 rad + pos: 7.5,7.5 + parent: 1668 + - uid: 1601 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,12.5 parent: 1668 - uid: 1612 components: @@ -39900,15 +40519,23 @@ entities: - type: Transform pos: 15.5,13.5 parent: 1668 - - uid: 1614 + - uid: 1684 components: - type: Transform - pos: 11.5,13.5 + rot: 1.5707963267948966 rad + pos: 7.5,12.5 parent: 1668 - - uid: 1615 + - uid: 1746 components: - type: Transform - pos: 9.5,13.5 + rot: 1.5707963267948966 rad + pos: 7.5,10.5 + parent: 1668 + - uid: 1747 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,10.5 parent: 1668 - uid: 1879 components: @@ -39970,6 +40597,18 @@ entities: - type: Transform pos: 35.5,12.5 parent: 1668 + - uid: 2071 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,13.5 + parent: 1668 + - uid: 2077 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,11.5 + parent: 1668 - uid: 2144 components: - type: Transform @@ -40250,6 +40889,12 @@ entities: - type: Transform pos: -11.5,-3.5 parent: 1668 + - uid: 2700 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,9.5 + parent: 1668 - uid: 2730 components: - type: Transform @@ -41489,31 +42134,6 @@ entities: - type: Transform pos: 23.5,-34.5 parent: 1668 - - uid: 9115 - components: - - type: Transform - pos: 23.5,-33.5 - parent: 1668 - - uid: 9116 - components: - - type: Transform - pos: 23.5,-32.5 - parent: 1668 - - uid: 9117 - components: - - type: Transform - pos: 23.5,-31.5 - parent: 1668 - - uid: 9118 - components: - - type: Transform - pos: 23.5,-30.5 - parent: 1668 - - uid: 9119 - components: - - type: Transform - pos: 23.5,-29.5 - parent: 1668 - uid: 9121 components: - type: Transform @@ -41615,6 +42235,12 @@ entities: - type: Transform pos: -22.524752,13.470394 parent: 1668 + - uid: 9683 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False - proto: HandheldCrewMonitor entities: - uid: 904 @@ -41664,16 +42290,16 @@ entities: parent: 1668 - proto: HighSecCommandLocked entities: - - uid: 94 - components: - - type: Transform - pos: 3.5,0.5 - parent: 1668 - - uid: 328 + - uid: 1583 components: - type: Transform pos: -4.5,0.5 parent: 1668 + - uid: 1584 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1668 - proto: HolofanProjector entities: - uid: 4088 @@ -41977,6 +42603,20 @@ entities: - type: Transform pos: 16.5,-21.5 parent: 1668 +- proto: KnifePlastic + entities: + - uid: 1350 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.57725,9.549465 + parent: 1668 + - uid: 9830 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5355835,10.36253 + parent: 1668 - proto: Lamp entities: - uid: 527 @@ -41984,10 +42624,10 @@ entities: - type: Transform pos: -1.4329706,1.8655163 parent: 1668 - - uid: 2081 + - uid: 2089 components: - type: Transform - pos: 31.448816,12.768794 + pos: 32.48791,12.751173 parent: 1668 - uid: 2811 components: @@ -42109,31 +42749,49 @@ entities: - type: Transform pos: -33.5,-4.5 parent: 1668 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - type: ContainerContainer containers: entity_storage: !type:Container showEnts: False occludes: True ents: - - 6780 - 6779 - - 6778 - - 6777 - - 6776 - - 6775 - - 6774 - - 6773 - - 6772 - - 6771 - - 6781 - - 6782 - - 6783 - - 6784 - - 6785 - - 6786 - - 6787 - - 6788 - 6789 + - 6788 + - 6787 + - 6786 + - 6785 + - 6784 + - 6783 + - 6782 + - 6781 + - 6771 + - 6772 + - 6773 + - 6774 + - 6775 + - 6776 + - 6777 + - 6778 + - 6780 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -42145,22 +42803,37 @@ entities: - type: Transform pos: -32.5,-4.5 parent: 1668 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - type: ContainerContainer containers: entity_storage: !type:Container showEnts: False occludes: True ents: + - 6793 - 6800 - - 6799 - 6798 - 6797 - 6796 - - 6795 - 6794 - - 6793 - 6792 - - 6791 - 6801 - 6802 - 6803 @@ -42170,6 +42843,9 @@ entities: - 6807 - 6808 - 6809 + - 6799 + - 6791 + - 6795 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -42183,30 +42859,48 @@ entities: - type: Transform pos: -33.5,-10.5 parent: 1668 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - type: ContainerContainer containers: entity_storage: !type:Container showEnts: False occludes: True ents: - - 6855 - 6854 - - 6853 - - 6852 - - 6851 - - 6850 - - 6849 - - 6848 - - 6847 - - 6856 - - 6857 - - 6858 - - 6859 - - 6860 - - 6861 - - 6862 - - 6863 - 6864 + - 6863 + - 6862 + - 6861 + - 6860 + - 6859 + - 6858 + - 6857 + - 6856 + - 6847 + - 6848 + - 6849 + - 6850 + - 6851 + - 6852 + - 6853 + - 6855 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -42260,18 +42954,6 @@ entities: - type: Transform pos: -15.5,23.5 parent: 1668 -- proto: LockerEvidence - entities: - - uid: 1356 - components: - - type: Transform - pos: 11.5,12.5 - parent: 1668 - - uid: 1357 - components: - - type: Transform - pos: 15.5,12.5 - parent: 1668 - proto: LockerFreezer entities: - uid: 1183 @@ -42470,8 +43152,79 @@ entities: showEnts: False occludes: True ent: null +- proto: LockerPrisoner + entities: + - uid: 1620 + components: + - type: Transform + pos: 10.5,12.5 + parent: 1668 +- proto: LockerPrisoner2 + entities: + - uid: 1623 + components: + - type: Transform + pos: 10.5,11.5 + parent: 1668 +- proto: LockerPrisoner3 + entities: + - uid: 1628 + components: + - type: Transform + pos: 10.5,10.5 + parent: 1668 +- proto: LockerPrisoner4 + entities: + - uid: 1730 + components: + - type: Transform + pos: 10.5,9.5 + parent: 1668 - proto: LockerRepresentative entities: + - uid: 1610 + components: + - type: Transform + pos: 1.5,-2.5 + parent: 1668 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 9685 + - 4559 + - 4544 + - 4541 + - 4523 + - 22 + - 1750 + - 1737 + - 500 + - 9686 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null - uid: 6884 components: - type: MetaData @@ -42479,30 +43232,48 @@ entities: - type: Transform pos: -28.5,-4.5 parent: 1668 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - type: ContainerContainer containers: entity_storage: !type:Container showEnts: False occludes: True ents: - - 6902 - 6901 - - 6900 - - 6899 - - 6898 - - 6897 - - 6896 - - 6895 - - 6894 - - 6893 - - 6892 - - 6891 - - 6890 - - 6889 - - 6888 - - 6887 - - 6886 - 6885 + - 6886 + - 6887 + - 6888 + - 6889 + - 6890 + - 6891 + - 6892 + - 6893 + - 6894 + - 6895 + - 6896 + - 6897 + - 6898 + - 6899 + - 6900 + - 6902 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -42985,6 +43756,11 @@ entities: - type: Transform pos: -39.5,-6.5 parent: 1668 + - uid: 9957 + components: + - type: Transform + pos: 32.31388,-22.19726 + parent: 1668 - proto: MedkitOxygenFilled entities: - uid: 774 @@ -43036,6 +43812,11 @@ entities: - type: Transform pos: 16.557764,-13.5264435 parent: 1668 + - uid: 9959 + components: + - type: Transform + pos: 32.68194,-22.523876 + parent: 1668 - proto: MetalFoamGrenade entities: - uid: 2418 @@ -43317,25 +44098,73 @@ entities: parent: 1668 - proto: Paper entities: - - uid: 1748 + - uid: 4617 components: - type: Transform - pos: 7.501362,11.6733 - parent: 1668 - - uid: 1749 + parent: 4560 + - type: Physics + canCollide: False + - uid: 4618 components: - type: Transform - pos: 7.501362,11.6733 - parent: 1668 - - uid: 1750 + parent: 4560 + - type: Physics + canCollide: False + - uid: 4619 components: - type: Transform - pos: 19.535091,11.6733 - parent: 1668 - - uid: 1751 + parent: 4560 + - type: Physics + canCollide: False + - uid: 4620 components: - type: Transform - pos: 19.535091,11.6733 + parent: 4560 + - type: Physics + canCollide: False + - uid: 4656 + components: + - type: Transform + parent: 4560 + - type: Physics + canCollide: False + - uid: 9115 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False + - uid: 9449 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False + - uid: 9457 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False + - uid: 9463 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False + - uid: 9681 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False +- proto: PaperBin20 + entities: + - uid: 8186 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,7.5 parent: 1668 - proto: PaperBin5 entities: @@ -43392,15 +44221,15 @@ entities: parent: 1668 - proto: Pen entities: - - uid: 1746 + - uid: 9982 components: - type: Transform - pos: 19.5,11.5 + pos: 3.2651894,7.4295287 parent: 1668 - - uid: 1747 + - uid: 9983 components: - type: Transform - pos: 7.5,11.5 + pos: 3.806856,7.6866517 parent: 1668 - proto: PenCentcom entities: @@ -43414,6 +44243,12 @@ entities: - type: Transform pos: -17.37441,12.973077 parent: 1668 + - uid: 7566 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False - uid: 9080 components: - type: Transform @@ -43708,6 +44543,8 @@ entities: - type: Transform pos: -0.5,-2.5 parent: 1668 + missingComponents: + - WarpPoint - proto: PlushieGhost entities: - uid: 6072 @@ -44851,6 +45688,12 @@ entities: rot: 1.5707963267948966 rad pos: 19.5,-21.5 parent: 1668 + - uid: 1665 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 34.5,-11.5 + parent: 1668 - uid: 3990 components: - type: Transform @@ -45029,6 +45872,17 @@ entities: - type: Transform pos: 17.5,-15.5 parent: 1668 + - uid: 1524 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 17.5,7.5 + parent: 1668 + - uid: 1631 + components: + - type: Transform + pos: 8.5,12.5 + parent: 1668 - uid: 1633 components: - type: Transform @@ -45045,11 +45899,11 @@ entities: rot: 1.5707963267948966 rad pos: 19.5,7.5 parent: 1668 - - uid: 1733 + - uid: 2090 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 17.5,9.5 + rot: 3.141592653589793 rad + pos: 8.5,7.5 parent: 1668 - uid: 2098 components: @@ -45115,11 +45969,6 @@ entities: rot: 3.141592653589793 rad pos: 10.5,-23.5 parent: 1668 - - uid: 2700 - components: - - type: Transform - pos: 8.5,8.5 - parent: 1668 - uid: 2737 components: - type: Transform @@ -45791,12 +46640,6 @@ entities: rot: 1.5707963267948966 rad pos: 12.5,-22.5 parent: 1668 - - uid: 1156 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 34.5,-11.5 - parent: 1668 - uid: 2441 components: - type: Transform @@ -45856,6 +46699,11 @@ entities: - type: Transform pos: -23.5,13.5 parent: 1668 + - uid: 2982 + components: + - type: Transform + pos: 19.5,-48.5 + parent: 1668 - uid: 3359 components: - type: Transform @@ -45938,15 +46786,10 @@ entities: rot: -1.5707963267948966 rad pos: -9.5,-36.5 parent: 1668 - - uid: 4838 + - uid: 5194 components: - type: Transform - pos: 18.5,-48.5 - parent: 1668 - - uid: 4839 - components: - - type: Transform - pos: -19.5,-48.5 + pos: -20.5,-48.5 parent: 1668 - uid: 7184 components: @@ -46028,23 +46871,29 @@ entities: rot: 1.5707963267948966 rad pos: 32.5,-21.5 parent: 1668 + - uid: 1294 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,-10.5 + parent: 1668 - uid: 2100 components: - type: Transform pos: 34.5,12.5 parent: 1668 - - uid: 2923 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 25.5,11.5 - parent: 1668 - uid: 2926 components: - type: Transform rot: 1.5707963267948966 rad pos: -13.5,11.5 parent: 1668 + - uid: 3613 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,11.5 + parent: 1668 - uid: 3908 components: - type: Transform @@ -46269,17 +47118,23 @@ entities: - type: InsideEntityStorage - proto: Railing entities: - - uid: 3037 + - uid: 2075 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,7.5 + rot: -1.5707963267948966 rad + pos: 19.5,10.5 parent: 1668 - - uid: 3670 + - uid: 3721 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,8.5 + rot: -1.5707963267948966 rad + pos: 19.5,12.5 + parent: 1668 + - uid: 8077 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 19.5,11.5 parent: 1668 - proto: RandomDrinkBottle entities: @@ -46507,6 +47362,11 @@ entities: - type: Transform pos: -2.5,-3.5 parent: 1668 + - uid: 82 + components: + - type: Transform + pos: 11.5,10.5 + parent: 1668 - uid: 86 components: - type: Transform @@ -46587,6 +47447,11 @@ entities: - type: Transform pos: 16.5,2.5 parent: 1668 + - uid: 328 + components: + - type: Transform + pos: 23.5,-29.5 + parent: 1668 - uid: 348 components: - type: Transform @@ -46662,36 +47527,11 @@ entities: - type: Transform pos: 20.5,-7.5 parent: 1668 - - uid: 921 - components: - - type: Transform - pos: 28.5,-12.5 - parent: 1668 - - uid: 922 - components: - - type: Transform - pos: 28.5,-11.5 - parent: 1668 - - uid: 923 - components: - - type: Transform - pos: 28.5,-10.5 - parent: 1668 - - uid: 924 - components: - - type: Transform - pos: 28.5,-9.5 - parent: 1668 - uid: 925 components: - type: Transform pos: 27.5,-7.5 parent: 1668 - - uid: 926 - components: - - type: Transform - pos: 26.5,-7.5 - parent: 1668 - uid: 927 components: - type: Transform @@ -46702,11 +47542,6 @@ entities: - type: Transform pos: 24.5,-9.5 parent: 1668 - - uid: 929 - components: - - type: Transform - pos: 24.5,-10.5 - parent: 1668 - uid: 930 components: - type: Transform @@ -46742,11 +47577,6 @@ entities: - type: Transform pos: 35.5,-16.5 parent: 1668 - - uid: 1198 - components: - - type: Transform - pos: 26.5,-28.5 - parent: 1668 - uid: 1199 components: - type: Transform @@ -46792,26 +47622,6 @@ entities: - type: Transform pos: 2.5,7.5 parent: 1668 - - uid: 1524 - components: - - type: Transform - pos: 6.5,9.5 - parent: 1668 - - uid: 1526 - components: - - type: Transform - pos: 5.5,9.5 - parent: 1668 - - uid: 1537 - components: - - type: Transform - pos: 4.5,9.5 - parent: 1668 - - uid: 1538 - components: - - type: Transform - pos: 3.5,9.5 - parent: 1668 - uid: 1539 components: - type: Transform @@ -46822,11 +47632,6 @@ entities: - type: Transform pos: 22.5,9.5 parent: 1668 - - uid: 1554 - components: - - type: Transform - pos: 2.5,10.5 - parent: 1668 - uid: 1555 components: - type: Transform @@ -46847,11 +47652,6 @@ entities: - type: Transform pos: 19.5,9.5 parent: 1668 - - uid: 1559 - components: - - type: Transform - pos: 18.5,11.5 - parent: 1668 - uid: 1560 components: - type: Transform @@ -46872,16 +47672,6 @@ entities: - type: Transform pos: 22.5,13.5 parent: 1668 - - uid: 1575 - components: - - type: Transform - pos: 7.5,9.5 - parent: 1668 - - uid: 1576 - components: - - type: Transform - pos: 8.5,11.5 - parent: 1668 - uid: 1577 components: - type: Transform @@ -46892,6 +47682,43 @@ entities: - type: Transform pos: 4.5,13.5 parent: 1668 + - uid: 1581 + components: + - type: Transform + pos: 23.5,-32.5 + parent: 1668 + - uid: 1582 + components: + - type: Transform + pos: 23.5,-30.5 + parent: 1668 + - uid: 1585 + components: + - type: Transform + pos: 23.5,-31.5 + parent: 1668 + - uid: 1586 + components: + - type: Transform + pos: 23.5,-33.5 + parent: 1668 + - uid: 1590 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,10.5 + parent: 1668 + - uid: 1593 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,13.5 + parent: 1668 + - uid: 1605 + components: + - type: Transform + pos: 11.5,12.5 + parent: 1668 - uid: 1608 components: - type: Transform @@ -46902,30 +47729,22 @@ entities: - type: Transform pos: 15.5,13.5 parent: 1668 - - uid: 1610 + - uid: 1685 components: - type: Transform - pos: 11.5,13.5 + rot: 1.5707963267948966 rad + pos: 7.5,9.5 parent: 1668 - - uid: 1611 + - uid: 1733 components: - type: Transform - pos: 9.5,13.5 + rot: 1.5707963267948966 rad + pos: 7.5,12.5 parent: 1668 - - uid: 1737 + - uid: 1749 components: - type: Transform - pos: 23.5,-30.5 - parent: 1668 - - uid: 1738 - components: - - type: Transform - pos: 23.5,-33.5 - parent: 1668 - - uid: 1739 - components: - - type: Transform - pos: 23.5,-29.5 + pos: 11.5,11.5 parent: 1668 - uid: 1769 components: @@ -47197,21 +48016,11 @@ entities: - type: Transform pos: -22.5,8.5 parent: 1668 - - uid: 2933 - components: - - type: Transform - pos: 23.5,-32.5 - parent: 1668 - uid: 2981 components: - type: Transform pos: 23.5,-34.5 parent: 1668 - - uid: 2982 - components: - - type: Transform - pos: 23.5,-31.5 - parent: 1668 - uid: 2988 components: - type: Transform @@ -47254,6 +48063,12 @@ entities: - type: Transform pos: -8.5,3.5 parent: 1668 + - uid: 3266 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,7.5 + parent: 1668 - uid: 3286 components: - type: Transform @@ -48545,7 +49360,7 @@ entities: - uid: 8822 components: - type: Transform - pos: -10.5,-6.5 + pos: -13.362957,-6.653441 parent: 1668 - proto: SecurityTechFab entities: @@ -48846,20 +49661,30 @@ entities: - type: DeviceLinkSource linkedPorts: 542: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 543: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 544: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 545: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 546: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 603 components: - type: MetaData @@ -48870,20 +49695,30 @@ entities: - type: DeviceLinkSource linkedPorts: 539: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 538: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 537: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 540: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 541: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 9388 components: - type: MetaData @@ -48895,17 +49730,25 @@ entities: - type: DeviceLinkSource linkedPorts: 9380: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9381: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9382: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9383: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 9389 components: - type: MetaData @@ -48917,17 +49760,25 @@ entities: - type: DeviceLinkSource linkedPorts: 9387: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9386: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9385: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 9384: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - proto: SignalSwitchDirectional entities: - uid: 336 @@ -48940,65 +49791,105 @@ entities: - type: DeviceLinkSource linkedPorts: 332: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 331: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 330: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 329: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 81: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 327: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 314: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 315: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 318: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 319: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 320: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 321: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 322: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 323: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 324: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 325: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 326: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 335: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 334: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 333: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 569 components: - type: MetaData @@ -49009,20 +49900,30 @@ entities: - type: DeviceLinkSource linkedPorts: 568: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 567: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 566: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 565: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 564: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 570 components: - type: MetaData @@ -49034,20 +49935,30 @@ entities: - type: DeviceLinkSource linkedPorts: 559: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 560: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 561: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 562: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 563: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 607 components: - type: MetaData @@ -49059,9 +49970,11 @@ entities: - type: DeviceLinkSource linkedPorts: 554: - - Status: Toggle + - - Status + - Toggle 555: - - Status: Toggle + - - Status + - Toggle - uid: 608 components: - type: MetaData @@ -49073,9 +49986,11 @@ entities: - type: DeviceLinkSource linkedPorts: 578: - - Status: Toggle + - - Status + - Toggle 577: - - Status: Toggle + - - Status + - Toggle - uid: 610 components: - type: MetaData @@ -49087,8 +50002,10 @@ entities: - type: DeviceLinkSource linkedPorts: 612: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 611 components: - type: MetaData @@ -49100,8 +50017,10 @@ entities: - type: DeviceLinkSource linkedPorts: 609: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 728 components: - type: MetaData @@ -49112,14 +50031,20 @@ entities: - type: DeviceLinkSource linkedPorts: 731: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 730: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 729: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 1130 components: - type: Transform @@ -49129,14 +50054,20 @@ entities: - type: DeviceLinkSource linkedPorts: 1142: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 1141: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 1140: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 1131 components: - type: Transform @@ -49146,48 +50077,72 @@ entities: - type: DeviceLinkSource linkedPorts: 1143: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 1144: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 1145: - - On: Open - - Off: Close - - uid: 1587 + - - On + - Open + - - Off + - Close + - uid: 1630 components: - type: MetaData - name: Inner Windoor Switch + name: Conveyor Toggle - type: Transform rot: -1.5707963267948966 rad - pos: 18.5,11.5 - parent: 1668 - - type: DeviceLinkSource - linkedPorts: - 1585: - - Status: Toggle - - uid: 1588 - components: - - type: MetaData - name: Inner Windoor Toggle - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,11.5 - parent: 1668 - - type: DeviceLinkSource - linkedPorts: - 1586: - - Status: Toggle - - uid: 1663 - components: - - type: Transform - pos: 23.5,13.5 + pos: 18.5,9.5 parent: 1668 - type: DeviceLinkSource linkedPorts: + 3520: + - - Off + - Off + - - On + - Reverse + 1751: + - - Off + - Off + - - On + - Reverse + 1744: + - - Off + - Off + - - On + - Reverse + 2085: + - - Off + - Off + - - On + - Reverse + 1624: + - - Off + - Off + - - On + - Reverse + 1625: + - - On + - Forward + - - Off + - Off + - - On + - Reverse 1626: - - On: Forward - - Off: Off + - - Off + - Off + - - On + - Reverse + 1600: + - - Off + - Off + - - On + - Reverse - uid: 1728 components: - type: Transform @@ -49196,8 +50151,10 @@ entities: - type: DeviceLinkSource linkedPorts: 1627: - - On: Forward - - Off: Off + - - On + - Forward + - - Off + - Off - uid: 2250 components: - type: Transform @@ -49207,17 +50164,25 @@ entities: - type: DeviceLinkSource linkedPorts: 2247: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2246: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2248: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2249: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 2254 components: - type: Transform @@ -49227,17 +50192,25 @@ entities: - type: DeviceLinkSource linkedPorts: 2257: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2256: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2253: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2252: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 2803 components: - type: Transform @@ -49246,11 +50219,15 @@ entities: - type: DeviceLinkSource linkedPorts: 2805: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 2804: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 3914 components: - type: Transform @@ -49260,11 +50237,15 @@ entities: - type: DeviceLinkSource linkedPorts: 3913: - - Off: Close - - On: Open + - - Off + - Close + - - On + - Open 3912: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 4715 components: - type: MetaData @@ -49276,20 +50257,30 @@ entities: - type: DeviceLinkSource linkedPorts: 4726: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4727: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4728: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4729: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4730: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 4716 components: - type: MetaData @@ -49301,41 +50292,65 @@ entities: - type: DeviceLinkSource linkedPorts: 4737: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4738: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4739: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4740: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4741: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4742: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4759: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4758: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4757: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4756: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4755: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4754: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 4717 components: - type: MetaData @@ -49347,20 +50362,30 @@ entities: - type: DeviceLinkSource linkedPorts: 4743: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4744: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4745: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4746: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 4747: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - uid: 9217 components: - type: MetaData @@ -49372,14 +50397,20 @@ entities: - type: DeviceLinkSource linkedPorts: 6903: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 6904: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close 6905: - - On: Open - - Off: Close + - - On + - Open + - - Off + - Close - proto: SignArmory entities: - uid: 2163 @@ -49479,6 +50510,13 @@ entities: - type: Transform pos: -15.5,-28.5 parent: 1668 +- proto: SignGenpop + entities: + - uid: 2076 + components: + - type: Transform + pos: 8.5,13.5 + parent: 1668 - proto: SignGravity entities: - uid: 4028 @@ -49647,30 +50685,11 @@ entities: parent: 1668 - proto: SignPrison entities: - - uid: 1631 - components: - - type: Transform - pos: 8.5,13.5 - parent: 1668 - uid: 1632 components: - type: Transform pos: 18.5,6.5 parent: 1668 -- proto: SignRedOne - entities: - - uid: 1589 - components: - - type: Transform - pos: 8.5,11.5 - parent: 1668 -- proto: SignRedTwo - entities: - - uid: 1590 - components: - - type: Transform - pos: 18.5,11.5 - parent: 1668 - proto: SignScience entities: - uid: 9123 @@ -50003,15 +51022,15 @@ entities: - type: Transform pos: 16.07121,34.553917 parent: 1668 - - uid: 2437 + - uid: 9722 components: - type: Transform - pos: 16.07121,34.413292 + pos: 16.067247,34.42217 parent: 1668 - - uid: 2438 + - uid: 9929 components: - type: Transform - pos: 16.07121,34.413292 + pos: 16.070206,34.493206 parent: 1668 - proto: SprayBottleSpaceCleaner entities: @@ -50127,6 +51146,12 @@ entities: parent: 1668 - proto: Stool entities: + - uid: 501 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,9.5 + parent: 1668 - uid: 1319 components: - type: Transform @@ -50145,17 +51170,11 @@ entities: rot: -1.5707963267948966 rad pos: 16.5,6.5 parent: 1668 - - uid: 1684 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 20.5,11.5 - parent: 1668 - - uid: 1685 + - uid: 1614 components: - type: Transform rot: 1.5707963267948966 rad - pos: 6.5,11.5 + pos: 5.5,10.5 parent: 1668 - uid: 3027 components: @@ -50917,16 +51936,6 @@ entities: - SurveillanceCameraGeneral nameSet: True id: Afterhours Lounge North - - uid: 9449 - components: - - type: Transform - pos: 29.5,-27.5 - parent: 1668 - - type: SurveillanceCamera - setupAvailableNetworks: - - SurveillanceCameraGeneral - nameSet: True - id: Afterhours Lounge South - uid: 9454 components: - type: Transform @@ -51015,17 +52024,6 @@ entities: - SurveillanceCameraGeneral nameSet: True id: Green Team Ready Room - - uid: 9463 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 17.5,-39.5 - parent: 1668 - - type: SurveillanceCamera - setupAvailableNetworks: - - SurveillanceCameraGeneral - nameSet: True - id: Green Team Hall - uid: 9464 components: - type: Transform @@ -51192,10 +52190,10 @@ entities: parent: 1668 - proto: SurveillanceCameraRouterMedical entities: - - uid: 8793 + - uid: 8818 components: - type: Transform - pos: -11.5,-8.5 + pos: -11.5,-6.5 parent: 1668 - proto: SurveillanceCameraRouterScience entities: @@ -51220,24 +52218,11 @@ entities: parent: 1668 - proto: SurveillanceCameraRouterSupply entities: - - uid: 8790 + - uid: 9684 components: - type: Transform - pos: -11.5,-6.5 + pos: -11.5,-8.5 parent: 1668 -- proto: SurveillanceCameraScience - entities: - - uid: 9457 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 19.5,-30.5 - parent: 1668 - - type: SurveillanceCamera - setupAvailableNetworks: - - SurveillanceCameraScience - nameSet: True - id: Afterhours Science Lounge - proto: SurveillanceCameraSecurity entities: - uid: 9413 @@ -51557,16 +52542,6 @@ entities: - type: Transform pos: 8.5,3.5 parent: 1668 - - uid: 1625 - components: - - type: Transform - pos: 7.5,11.5 - parent: 1668 - - uid: 1628 - components: - - type: Transform - pos: 19.5,11.5 - parent: 1668 - uid: 2111 components: - type: Transform @@ -51731,11 +52706,6 @@ entities: - type: Transform pos: -13.5,-6.5 parent: 1668 - - uid: 8818 - components: - - type: Transform - pos: -10.5,-6.5 - parent: 1668 - uid: 9091 components: - type: Transform @@ -51773,6 +52743,16 @@ entities: parent: 1668 - proto: TableCarpet entities: + - uid: 1527 + components: + - type: Transform + pos: 32.5,12.5 + parent: 1668 + - uid: 1530 + components: + - type: Transform + pos: 33.5,11.5 + parent: 1668 - uid: 2037 components: - type: Transform @@ -51788,16 +52768,6 @@ entities: - type: Transform pos: 33.5,27.5 parent: 1668 - - uid: 2077 - components: - - type: Transform - pos: 31.5,11.5 - parent: 1668 - - uid: 2093 - components: - - type: Transform - pos: 31.5,12.5 - parent: 1668 - uid: 2109 components: - type: Transform @@ -52148,11 +53118,6 @@ entities: - type: Transform pos: -3.5,-2.5 parent: 1668 - - uid: 149 - components: - - type: Transform - pos: 1.5,-2.5 - parent: 1668 - uid: 151 components: - type: Transform @@ -52203,12 +53168,6 @@ entities: - type: Transform pos: 3.5,-1.5 parent: 1668 - - uid: 515 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,8.5 - parent: 1668 - uid: 575 components: - type: Transform @@ -52386,12 +53345,6 @@ entities: - type: Transform pos: 16.5,-4.5 parent: 1668 - - uid: 905 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,9.5 - parent: 1668 - uid: 936 components: - type: Transform @@ -52681,16 +53634,12 @@ entities: rot: 1.5707963267948966 rad pos: 34.5,-12.5 parent: 1668 - - uid: 1579 + - uid: 1540 components: - type: Transform + rot: -1.5707963267948966 rad pos: 18.5,12.5 parent: 1668 - - uid: 1580 - components: - - type: Transform - pos: 8.5,12.5 - parent: 1668 - uid: 1591 components: - type: Transform @@ -52701,21 +53650,11 @@ entities: - type: Transform pos: 14.5,6.5 parent: 1668 - - uid: 1598 - components: - - type: Transform - pos: 15.5,7.5 - parent: 1668 - uid: 1599 components: - type: Transform pos: 14.5,7.5 parent: 1668 - - uid: 1600 - components: - - type: Transform - pos: 13.5,7.5 - parent: 1668 - uid: 1603 components: - type: Transform @@ -52736,11 +53675,10 @@ entities: - type: Transform pos: 12.5,12.5 parent: 1668 - - uid: 2103 + - uid: 2083 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,7.5 + pos: 6.5,10.5 parent: 1668 - uid: 2148 components: @@ -52995,6 +53933,11 @@ entities: - type: Transform pos: -17.5,4.5 parent: 1668 + - uid: 2984 + components: + - type: Transform + pos: 6.5,9.5 + parent: 1668 - uid: 3021 components: - type: Transform @@ -53040,17 +53983,11 @@ entities: - type: Transform pos: -3.5,22.5 parent: 1668 - - uid: 3520 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,7.5 - parent: 1668 - uid: 3671 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,8.5 + rot: -1.5707963267948966 rad + pos: 18.5,10.5 parent: 1668 - uid: 3884 components: @@ -53084,6 +54021,12 @@ entities: - type: Transform pos: -18.5,26.5 parent: 1668 + - uid: 4180 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,11.5 + parent: 1668 - uid: 4225 components: - type: Transform @@ -53448,6 +54391,12 @@ entities: - type: Transform pos: -20.5,12.5 parent: 1668 + - uid: 2985 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,7.5 + parent: 1668 - uid: 4205 components: - type: Transform @@ -53636,14 +54585,27 @@ entities: rot: 1.5707963267948966 rad pos: -42.5,5.5 parent: 1668 -- proto: TargetClown - entities: - - uid: 3100 + - uid: 9829 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,8.5 + rot: -1.5707963267948966 rad + pos: 6.5,7.5 parent: 1668 + - uid: 9960 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,-22.5 + parent: 1668 +- proto: TargetClown + entities: + - uid: 2081 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,12.5 + parent: 1668 + - type: Conveyed - proto: TargetDarts entities: - uid: 9132 @@ -53651,14 +54613,24 @@ entities: - type: Transform pos: 21.5,-29.5 parent: 1668 -- proto: TargetSyndicate +- proto: TargetHuman entities: - - uid: 3666 + - uid: 3100 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,7.5 + rot: -1.5707963267948966 rad + pos: 22.5,10.5 parent: 1668 + - type: Conveyed +- proto: TargetSyndicate + entities: + - uid: 9834 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 24.5,11.5 + parent: 1668 + - type: Conveyed - proto: TearGasGrenade entities: - uid: 3169 @@ -53686,7 +54658,7 @@ entities: - uid: 8786 components: - type: Transform - pos: -12.5,-6.5 + pos: -12.5,-8.5 parent: 1668 - proto: TelecomServerFilledCommand entities: @@ -53711,10 +54683,10 @@ entities: parent: 1668 - proto: TelecomServerFilledMedical entities: - - uid: 6390 + - uid: 8790 components: - type: Transform - pos: -12.5,-8.5 + pos: -12.5,-6.5 parent: 1668 - proto: TelecomServerFilledScience entities: @@ -53773,6 +54745,24 @@ entities: - type: Transform pos: 29.5,-14.5 parent: 1668 + - uid: 1666 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,-9.5 + parent: 1668 + - uid: 1676 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,-11.5 + parent: 1668 + - uid: 1678 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,-12.5 + parent: 1668 - uid: 2114 components: - type: Transform @@ -53896,6 +54886,14 @@ entities: - type: Transform pos: -20.5,30.5 parent: 1668 +- proto: Truncheon + entities: + - uid: 9682 + components: + - type: Transform + parent: 4559 + - type: Physics + canCollide: False - proto: TurboItemRecharger entities: - uid: 209 @@ -53903,6 +54901,28 @@ entities: - type: Transform pos: 14.5,5.5 parent: 1668 +- proto: TurnstileGenpopEnter + entities: + - uid: 4187 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,8.5 + parent: 1668 +- proto: TurnstileGenpopLeave + entities: + - uid: 1598 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,13.5 + parent: 1668 + - uid: 1735 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,11.5 + parent: 1668 - proto: TwoWayLever entities: - uid: 3648 @@ -53913,41 +54933,68 @@ entities: - type: DeviceLinkSource linkedPorts: 3644: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3645: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3663: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3651: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3646: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3649: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3638: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3654: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3662: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off - uid: 3652 components: - type: Transform @@ -53956,41 +55003,68 @@ entities: - type: DeviceLinkSource linkedPorts: 3655: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3653: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3656: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3647: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3650: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3657: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3658: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3659: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 3264: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off - uid: 9083 components: - type: Transform @@ -53999,9 +55073,12 @@ entities: - type: DeviceLinkSource linkedPorts: 8745: - - Left: Reverse - - Right: Forward - - Middle: Off + - - Left + - Reverse + - - Right + - Forward + - - Middle + - Off - proto: UraniumReinforcedWindowDirectional entities: - uid: 9601 @@ -54183,10 +55260,10 @@ entities: - type: Transform pos: 34.5,14.5 parent: 1668 - - uid: 3607 + - uid: 3037 components: - type: Transform - pos: 13.5,8.5 + pos: 12.5,10.5 parent: 1668 - uid: 9096 components: @@ -54221,6 +55298,11 @@ entities: parent: 1668 - proto: VendingMachineGames entities: + - uid: 1525 + components: + - type: Transform + pos: 3.5,9.5 + parent: 1668 - uid: 9107 components: - type: Transform @@ -54242,10 +55324,10 @@ entities: parent: 1668 - proto: VendingMachineLawDrobe entities: - - uid: 2071 + - uid: 1563 components: - type: Transform - pos: 25.5,12.5 + pos: 30.5,12.5 parent: 1668 - proto: VendingMachineMedical entities: @@ -54282,22 +55364,22 @@ entities: parent: 1668 - proto: VendingMachineSec entities: - - uid: 82 - components: - - type: Transform - pos: 13.5,5.5 - parent: 1668 - uid: 1138 components: - type: Transform pos: 34.5,-8.5 parent: 1668 -- proto: VendingMachineSecDrobe - entities: - - uid: 1593 + - uid: 2103 components: - type: Transform - pos: 13.5,6.5 + pos: 15.5,7.5 + parent: 1668 +- proto: VendingMachineSecDrobe + entities: + - uid: 3607 + components: + - type: Transform + pos: 15.5,12.5 parent: 1668 - proto: VendingMachineSeeds entities: @@ -54336,6 +55418,11 @@ entities: parent: 1668 - proto: VendingMachineSustenance entities: + - uid: 4179 + components: + - type: Transform + pos: 3.5,10.5 + parent: 1668 - uid: 9199 components: - type: Transform @@ -55029,12 +56116,6 @@ entities: - type: Transform pos: 19.5,-7.5 parent: 1668 - - uid: 409 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,11.5 - parent: 1668 - uid: 410 components: - type: Transform @@ -55050,12 +56131,6 @@ entities: - type: Transform pos: 7.5,2.5 parent: 1668 - - uid: 501 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,10.5 - parent: 1668 - uid: 502 components: - type: Transform @@ -55068,6 +56143,12 @@ entities: rot: 1.5707963267948966 rad pos: 19.5,13.5 parent: 1668 + - uid: 515 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.5,12.5 + parent: 1668 - uid: 516 components: - type: Transform @@ -55509,6 +56590,12 @@ entities: - type: Transform pos: 34.5,-14.5 parent: 1668 + - uid: 1156 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 27.5,-10.5 + parent: 1668 - uid: 1159 components: - type: Transform @@ -55637,6 +56724,12 @@ entities: - type: Transform pos: 31.5,-23.5 parent: 1668 + - uid: 1295 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,-10.5 + parent: 1668 - uid: 1522 components: - type: Transform @@ -55657,11 +56750,6 @@ entities: - type: Transform pos: 8.5,13.5 parent: 1668 - - uid: 1540 - components: - - type: Transform - pos: 8.5,9.5 - parent: 1668 - uid: 1541 components: - type: Transform @@ -55684,11 +56772,39 @@ entities: - type: Transform pos: 2.5,13.5 parent: 1668 - - uid: 1563 + - uid: 1551 + components: + - type: Transform + pos: 2.5,10.5 + parent: 1668 + - uid: 1559 components: - type: Transform rot: 1.5707963267948966 rad - pos: 24.5,12.5 + pos: 25.5,10.5 + parent: 1668 + - uid: 1602 + components: + - type: Transform + pos: 11.5,13.5 + parent: 1668 + - uid: 1663 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.5,11.5 + parent: 1668 + - uid: 1679 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,-10.5 + parent: 1668 + - uid: 1681 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,-10.5 parent: 1668 - uid: 1752 components: @@ -56042,6 +57158,11 @@ entities: - type: Transform pos: 25.5,13.5 parent: 1668 + - uid: 2084 + components: + - type: Transform + pos: 11.5,9.5 + parent: 1668 - uid: 2123 components: - type: Transform @@ -56791,6 +57912,11 @@ entities: - type: Transform pos: -14.5,4.5 parent: 1668 + - uid: 2933 + components: + - type: Transform + pos: -21.5,-50.5 + parent: 1668 - uid: 2987 components: - type: Transform @@ -57872,7 +58998,7 @@ entities: - uid: 4464 components: - type: Transform - pos: 18.5,-49.5 + pos: -21.5,-49.5 parent: 1668 - uid: 4465 components: @@ -57932,7 +59058,7 @@ entities: - uid: 4482 components: - type: Transform - pos: -20.5,-49.5 + pos: -21.5,-48.5 parent: 1668 - uid: 4483 components: @@ -58029,11 +59155,6 @@ entities: - type: Transform pos: -18.5,-49.5 parent: 1668 - - uid: 4505 - components: - - type: Transform - pos: -19.5,-49.5 - parent: 1668 - uid: 4506 components: - type: Transform @@ -58089,11 +59210,6 @@ entities: - type: Transform pos: -18.5,-34.5 parent: 1668 - - uid: 4523 - components: - - type: Transform - pos: -21.5,-49.5 - parent: 1668 - uid: 4524 components: - type: Transform @@ -58179,11 +59295,6 @@ entities: - type: Transform pos: -19.5,-33.5 parent: 1668 - - uid: 4541 - components: - - type: Transform - pos: -22.5,-49.5 - parent: 1668 - uid: 4542 components: - type: Transform @@ -58194,11 +59305,6 @@ entities: - type: Transform pos: -21.5,-47.5 parent: 1668 - - uid: 4544 - components: - - type: Transform - pos: -22.5,-47.5 - parent: 1668 - uid: 4545 components: - type: Transform @@ -58269,25 +59375,10 @@ entities: - type: Transform pos: -20.5,-34.5 parent: 1668 - - uid: 4559 - components: - - type: Transform - pos: 19.5,-49.5 - parent: 1668 - - uid: 4560 - components: - - type: Transform - pos: 20.5,-49.5 - parent: 1668 - uid: 4561 components: - type: Transform - pos: 21.5,-49.5 - parent: 1668 - - uid: 4562 - components: - - type: Transform - pos: 21.5,-47.5 + pos: 20.5,-48.5 parent: 1668 - uid: 4563 components: @@ -58379,6 +59470,21 @@ entities: - type: Transform pos: -23.5,-28.5 parent: 1668 + - uid: 4839 + components: + - type: Transform + pos: 20.5,-49.5 + parent: 1668 + - uid: 4845 + components: + - type: Transform + pos: -19.5,-50.5 + parent: 1668 + - uid: 4849 + components: + - type: Transform + pos: -19.5,-49.5 + parent: 1668 - uid: 5512 components: - type: Transform @@ -59873,11 +60979,32 @@ entities: - type: Transform pos: -8.5,-8.5 parent: 1668 + - uid: 9116 + components: + - type: Transform + pos: 20.5,-50.5 + parent: 1668 + - uid: 9117 + components: + - type: Transform + pos: 18.5,-49.5 + parent: 1668 - uid: 9280 components: - type: Transform pos: -40.5,8.5 parent: 1668 + - uid: 9699 + components: + - type: Transform + pos: 18.5,-50.5 + parent: 1668 + - uid: 9988 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.5,-10.5 + parent: 1668 - proto: WallWood entities: - uid: 6135 @@ -59982,11 +61109,6 @@ entities: - type: Transform pos: 3.5,11.5 parent: 1668 - - uid: 1630 - components: - - type: Transform - pos: 23.5,11.5 - parent: 1668 - proto: WarningN2 entities: - uid: 3375 @@ -60018,11 +61140,6 @@ entities: - type: Transform pos: 20.5,16.5 parent: 1668 - - uid: 3266 - components: - - type: Transform - pos: 13.5,9.5 - parent: 1668 - uid: 3994 components: - type: Transform @@ -60033,6 +61150,11 @@ entities: - type: Transform pos: 1.5,18.5 parent: 1668 + - uid: 8046 + components: + - type: Transform + pos: 12.5,11.5 + parent: 1668 - uid: 8763 components: - type: Transform @@ -60058,6 +61180,11 @@ entities: - type: Transform pos: -30.5,4.5 parent: 1668 + - uid: 9980 + components: + - type: Transform + pos: 6.5,12.5 + parent: 1668 - proto: WaterTankHighCapacity entities: - uid: 1031 @@ -60116,11 +61243,6 @@ entities: - type: Transform pos: -23.5,10.5 parent: 1668 - - uid: 2985 - components: - - type: Transform - pos: 11.5,7.5 - parent: 1668 - uid: 4631 components: - type: Transform @@ -60177,6 +61299,12 @@ entities: - type: Transform pos: -35.5,13.5 parent: 1668 + - uid: 9835 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,10.5 + parent: 1668 - proto: WeaponDisabler entities: - uid: 6817 @@ -60202,10 +61330,10 @@ entities: - type: InsideEntityStorage - proto: WeaponDisablerPractice entities: - - uid: 4180 + - uid: 9958 components: - type: Transform - pos: 11.414704,7.5328236 + pos: 18.50393,10.681932 parent: 1668 - proto: WeaponDisablerSMG entities: @@ -60272,10 +61400,11 @@ entities: parent: 1668 - proto: WeaponLaserCarbinePractice entities: - - uid: 4179 + - uid: 9961 components: - type: Transform - pos: 11.461579,8.095324 + rot: -1.5707963267948966 rad + pos: 18.587261,11.463725 parent: 1668 - proto: WeaponLaserGun entities: @@ -60342,6 +61471,13 @@ entities: - type: Transform pos: -11.42821,5.5092115 parent: 1668 + - uid: 4541 + components: + - type: Transform + parent: 1610 + - type: Physics + canCollide: False + - type: InsideEntityStorage - uid: 6897 components: - type: Transform @@ -60413,7 +61549,7 @@ entities: - uid: 2430 components: - type: Transform - pos: 15.508711,34.397667 + pos: 15.50552,34.388195 parent: 1668 - proto: WeaponRifleAk entities: @@ -60900,18 +62036,6 @@ entities: parent: 1668 - proto: WindoorSecureBrigLocked entities: - - uid: 1583 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,12.5 - parent: 1668 - - uid: 1584 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,12.5 - parent: 1668 - uid: 1864 components: - type: Transform @@ -61125,6 +62249,12 @@ entities: parent: 1668 - proto: WindoorSecureSecurityLocked entities: + - uid: 409 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,11.5 + parent: 1668 - uid: 557 components: - type: Transform @@ -61155,22 +62285,6 @@ entities: rot: -1.5707963267948966 rad pos: 32.5,-10.5 parent: 1668 - - uid: 1585 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 18.5,12.5 - parent: 1668 - - type: DeviceLinkSink - invokeCounter: 1 - - uid: 1586 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,12.5 - parent: 1668 - - type: DeviceLinkSink - invokeCounter: 1 - uid: 1616 components: - type: Transform @@ -61186,17 +62300,17 @@ entities: - type: Transform pos: 26.5,19.5 parent: 1668 - - uid: 2104 + - uid: 2082 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,8.5 + rot: -1.5707963267948966 rad + pos: 18.5,12.5 parent: 1668 - - uid: 3721 + - uid: 4184 components: - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,7.5 + rot: -1.5707963267948966 rad + pos: 18.5,10.5 parent: 1668 - proto: Window entities: @@ -61395,12 +62509,6 @@ entities: - type: Transform pos: 14.5,13.5 parent: 1668 - - uid: 1730 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 21.5,12.5 - parent: 1668 - uid: 1731 components: - type: Transform @@ -61703,30 +62811,6 @@ entities: rot: -1.5707963267948966 rad pos: -3.5,-20.5 parent: 1668 - - uid: 4184 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,7.5 - parent: 1668 - - uid: 4185 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,8.5 - parent: 1668 - - uid: 4186 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,9.5 - parent: 1668 - - uid: 4187 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 11.5,9.5 - parent: 1668 - uid: 4795 components: - type: Transform From 159c1879712e3d543a13f57e04d885720b03cb8f Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 2 Jul 2025 03:15:49 +0000 Subject: [PATCH 019/105] Automatic changelog update --- Resources/Changelog/Maps.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Resources/Changelog/Maps.yml b/Resources/Changelog/Maps.yml index 50080c357a..ea755b5405 100644 --- a/Resources/Changelog/Maps.yml +++ b/Resources/Changelog/Maps.yml @@ -387,4 +387,11 @@ id: 47 time: '2025-06-19T04:06:17.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38435 +- author: UpAndLeaves + changes: + - message: CentComm security now uses a genpop system. + type: Add + id: 48 + time: '2025-07-02T03:14:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37494 Order: 1 From 579b38b92b6dfc800b2d8dbfe1e2fc0c79c003b2 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Wed, 2 Jul 2025 10:46:30 -0700 Subject: [PATCH 020/105] Improvements and fixups for New Status Effect API (#38660) --- Content.Server/Drowsiness/DrowsinessSystem.cs | 4 +- .../Traits/Assorted/NarcolepsySystem.cs | 2 +- .../StatusEffects/ModifyStatusEffect.cs | 12 +- .../SSDIndicator/SSDIndicatorSystem.cs | 2 +- .../SharedStatusEffectsSystem.cs | 135 ++++++++++++---- .../StatusEffectNew/StatusEffectSystem.API.cs | 152 +++++++++++------- 6 files changed, 210 insertions(+), 97 deletions(-) diff --git a/Content.Server/Drowsiness/DrowsinessSystem.cs b/Content.Server/Drowsiness/DrowsinessSystem.cs index 0489b16f51..6de270abcc 100644 --- a/Content.Server/Drowsiness/DrowsinessSystem.cs +++ b/Content.Server/Drowsiness/DrowsinessSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.StatusEffectNew; +using Content.Server.StatusEffectNew; using Content.Shared.Bed.Sleep; using Content.Shared.Drowsiness; using Content.Shared.StatusEffectNew; @@ -47,7 +47,7 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem // Make sure the sleep time doesn't cut into the time to next incident. drowsiness.NextIncidentTime += duration; - _statusEffects.TryAddStatusEffect(statusEffect.AppliedTo.Value, SleepingSystem.StatusEffectForcedSleeping, duration); + _statusEffects.TryAddStatusEffectDuration(statusEffect.AppliedTo.Value, SleepingSystem.StatusEffectForcedSleeping, duration); } } } diff --git a/Content.Server/Traits/Assorted/NarcolepsySystem.cs b/Content.Server/Traits/Assorted/NarcolepsySystem.cs index 9d0ff9470a..b0746fa377 100644 --- a/Content.Server/Traits/Assorted/NarcolepsySystem.cs +++ b/Content.Server/Traits/Assorted/NarcolepsySystem.cs @@ -53,7 +53,7 @@ public sealed class NarcolepsySystem : EntitySystem // Make sure the sleep time doesn't cut into the time to next incident. narcolepsy.NextIncidentTime += duration; - _statusEffects.TryAddStatusEffect(uid, SleepingSystem.StatusEffectForcedSleeping, TimeSpan.FromSeconds(duration)); + _statusEffects.TryAddStatusEffectDuration(uid, SleepingSystem.StatusEffectForcedSleeping, TimeSpan.FromSeconds(duration)); } } } diff --git a/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs index 33021ecdab..5ebb8aad1b 100644 --- a/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs +++ b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs @@ -20,7 +20,7 @@ public sealed partial class ModifyStatusEffect : EntityEffect public float Time = 2.0f; /// - /// true - refresh status effect time, false - accumulate status effect time. + /// true - refresh status effect time (update to greater value), false - accumulate status effect time. /// [DataField] public bool Refresh = true; @@ -40,16 +40,20 @@ public sealed partial class ModifyStatusEffect : EntityEffect if (args is EntityEffectReagentArgs reagentArgs) time *= reagentArgs.Scale.Float(); + var duration = TimeSpan.FromSeconds(time); switch (Type) { case StatusEffectMetabolismType.Add: - statusSys.TryAddStatusEffect(args.TargetEntity, EffectProto, TimeSpan.FromSeconds(time), Refresh); + if (Refresh) + statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration); + else + statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration); break; case StatusEffectMetabolismType.Remove: - statusSys.TryAddTime(args.TargetEntity, EffectProto, -TimeSpan.FromSeconds(time)); + statusSys.TryAddTime(args.TargetEntity, EffectProto, -duration); break; case StatusEffectMetabolismType.Set: - statusSys.TrySetTime(args.TargetEntity, EffectProto, TimeSpan.FromSeconds(time)); + statusSys.TrySetStatusEffectDuration(args.TargetEntity, EffectProto, duration); break; } } diff --git a/Content.Shared/SSDIndicator/SSDIndicatorSystem.cs b/Content.Shared/SSDIndicator/SSDIndicatorSystem.cs index a13b6b915c..ca7d73ac83 100644 --- a/Content.Shared/SSDIndicator/SSDIndicatorSystem.cs +++ b/Content.Shared/SSDIndicator/SSDIndicatorSystem.cs @@ -85,7 +85,7 @@ public sealed class SSDIndicatorSystem : EntitySystem ssd.FallAsleepTime <= _timing.CurTime && !TerminatingOrDeleted(uid)) { - _statusEffects.TryAddStatusEffect(uid, StatusEffectSSDSleeping); + _statusEffects.TrySetStatusEffectDuration(uid, StatusEffectSSDSleeping, null); } } } diff --git a/Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs b/Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs index c836b8205c..9e6ed4d7ff 100644 --- a/Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs +++ b/Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.Alert; using Content.Shared.StatusEffectNew.Components; using Content.Shared.Whitelist; @@ -77,53 +78,59 @@ public abstract partial class SharedStatusEffectsSystem : EntitySystem effectComp.EndEffectTime += delta; Dirty(effect, effectComp); - if (effectComp is { AppliedTo: not null, Alert: not null }) - { - (TimeSpan Start, TimeSpan End)? cooldown = effectComp.EndEffectTime is null - ? null - : (_timing.CurTime, effectComp.EndEffectTime.Value); - _alerts.ShowAlert( - effectComp.AppliedTo.Value, - effectComp.Alert.Value, - cooldown: cooldown - ); - } + ShowAlertIfNeeded(effectComp); } - private void SetStatusEffectTime(EntityUid effect, TimeSpan duration) + private void SetStatusEffectTime(EntityUid effect, TimeSpan? duration) { if (!_effectQuery.TryComp(effect, out var effectComp)) return; - effectComp.EndEffectTime = _timing.CurTime + duration; + if (duration is null) + { + if(effectComp.EndEffectTime is null) + return; + + effectComp.EndEffectTime = null; + } + else + effectComp.EndEffectTime = _timing.CurTime + duration; + Dirty(effect, effectComp); - if (effectComp is { AppliedTo: not null, Alert: not null }) - { - (TimeSpan, TimeSpan)? cooldown = effectComp.EndEffectTime is null - ? null - : (_timing.CurTime, effectComp.EndEffectTime.Value); - _alerts.ShowAlert( - effectComp.AppliedTo.Value, - effectComp.Alert.Value, - cooldown: cooldown - ); - } + ShowAlertIfNeeded(effectComp); } + private void UpdateStatusEffectTime(EntityUid effect, TimeSpan? duration) + { + if (!_effectQuery.TryComp(effect, out var effectComp)) + return; + + // It's already infinitely long + if (effectComp.EndEffectTime is null) + return; + + if (duration is null) + effectComp.EndEffectTime = null; + else + { + var newEndTime = _timing.CurTime + duration; + if (effectComp.EndEffectTime >= newEndTime) + return; + + effectComp.EndEffectTime = newEndTime; + } + + Dirty(effect, effectComp); + + ShowAlertIfNeeded(effectComp); + } + + private void OnStatusEffectApplied(Entity ent, ref StatusEffectAppliedEvent args) { - if (ent.Comp is { AppliedTo: not null, Alert: not null }) - { - (TimeSpan, TimeSpan)? cooldown = ent.Comp.EndEffectTime is null - ? null - : (_timing.CurTime, ent.Comp.EndEffectTime.Value); - _alerts.ShowAlert( - ent.Comp.AppliedTo.Value, - ent.Comp.Alert.Value, - cooldown: cooldown - ); - } + StatusEffectComponent statusEffect = ent; + ShowAlertIfNeeded(statusEffect); } private void OnStatusEffectRemoved(Entity ent, ref StatusEffectRemovedEvent args) @@ -154,6 +161,64 @@ public abstract partial class SharedStatusEffectsSystem : EntitySystem return true; } + + /// + /// Attempts to add a status effect to the specified entity. Returns True if the effect is added, does not check if one + /// already exists as it's intended to be called after a check for an existing effect has already failed. + /// + /// The target entity to which the effect should be added. + /// ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it. + /// Duration of status effect. Leave null and the effect will be permanent until it is removed using TryRemoveStatusEffect. + /// The EntityUid of the status effect we have just created or null if we couldn't create one. + private bool TryAddStatusEffect( + EntityUid target, + EntProtoId effectProto, + [NotNullWhen(true)] out EntityUid? statusEffect, + TimeSpan? duration = null + ) + { + statusEffect = null; + if (!CanAddStatusEffect(target, effectProto)) + return false; + + var container = EnsureComp(target); + + //And only if all checks passed we spawn the effect + var effect = PredictedSpawnAttachedTo(effectProto, Transform(target).Coordinates); + _transform.SetParent(effect, target); + if (!_effectQuery.TryComp(effect, out var effectComp)) + return false; + + statusEffect = effect; + + if (duration != null) + effectComp.EndEffectTime = _timing.CurTime + duration; + + container.ActiveStatusEffects.Add(effect); + effectComp.AppliedTo = target; + Dirty(target, container); + Dirty(effect, effectComp); + + var ev = new StatusEffectAppliedEvent(target); + RaiseLocalEvent(effect, ref ev); + + return true; + } + + private void ShowAlertIfNeeded(StatusEffectComponent effectComp) + { + if (effectComp is { AppliedTo: not null, Alert: not null }) + { + (TimeSpan, TimeSpan)? cooldown = effectComp.EndEffectTime is null + ? null + : (_timing.CurTime, effectComp.EndEffectTime.Value); + _alerts.ShowAlert( + effectComp.AppliedTo.Value, + effectComp.Alert.Value, + cooldown: cooldown + ); + } + } } /// diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs index 2d1ec89c9d..5e20cea1bb 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs @@ -7,80 +7,94 @@ namespace Content.Shared.StatusEffectNew; public abstract partial class SharedStatusEffectsSystem { /// - /// Attempts to add a status effect to the specified entity. Returns True if the effect is added or it already exists - /// and has been successfully extended in time, returns False if the status effect cannot be applied to this entity, - /// or for any other reason. + /// Increments duration of status effect by . + /// Tries to add status effect if it is not yet present on entity. /// /// The target entity to which the effect should be added. /// ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it. /// Duration of status effect. Leave null and the effect will be permanent until it is removed using TryRemoveStatusEffect. - /// - /// If True, the effect duration time will be reset and reapplied. If False, the effect duration time will be overlaid with the existing one. - /// In the other case, the effect will either be added for the specified time or its time will be extended for the specified time. - /// /// The EntityUid of the status effect we have just created or null if it doesn't exist. - public bool TryAddStatusEffect( + /// True if effect exists and its duration is set properly, false in case effect cannot be applied. + public bool TryAddStatusEffectDuration( EntityUid target, EntProtoId effectProto, - out EntityUid? statusEffect, - TimeSpan? duration = null, - bool resetCooldown = false + [NotNullWhen(true)] out EntityUid? statusEffect, + TimeSpan duration ) { - statusEffect = null; - if (TryGetStatusEffect(target, effectProto, out var existingEffect)) - { - statusEffect = existingEffect; - //We don't need to add the effect if it already exists - if (duration is null) - return true; + if (!TryGetStatusEffect(target, effectProto, out statusEffect)) + return TryAddStatusEffect(target, effectProto, out statusEffect, duration); - if (resetCooldown) - SetStatusEffectTime(existingEffect.Value, duration.Value); - else - AddStatusEffectTime(existingEffect.Value, duration.Value); - - return true; - } - - if (!CanAddStatusEffect(target, effectProto)) - return false; - - var container = EnsureComp(target); - - //And only if all checks passed we spawn the effect - var effect = PredictedSpawnAttachedTo(effectProto, Transform(target).Coordinates); - statusEffect = effect; - _transform.SetParent(effect, target); - if (!_effectQuery.TryComp(effect, out var effectComp)) - return false; - - if (duration != null) - effectComp.EndEffectTime = _timing.CurTime + duration; - - container.ActiveStatusEffects.Add(effect); - effectComp.AppliedTo = target; - Dirty(target, container); - Dirty(effect, effectComp); - - var ev = new StatusEffectAppliedEvent(target); - RaiseLocalEvent(effect, ref ev); + AddStatusEffectTime(statusEffect.Value, duration); return true; } + + /// + public bool TryAddStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan duration) + { + return TryAddStatusEffectDuration(target, effectProto, out _, duration); + } + /// - /// An overload of - /// that doesn't return a status effect EntityUid. + /// Sets duration of status effect by . + /// Tries to add status effect if it is not yet present on entity. /// - public bool TryAddStatusEffect( + /// The target entity to which the effect should be added. + /// ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it. + /// Duration of status effect. Leave null and the effect will be permanent until it is removed using TryRemoveStatusEffect. + /// The EntityUid of the status effect we have just created or null if it doesn't exist. + /// True if effect exists and its duration is set properly, false in case effect cannot be applied. + public bool TrySetStatusEffectDuration( EntityUid target, EntProtoId effectProto, - TimeSpan? duration = null, - bool resetCooldown = false + [NotNullWhen(true)] out EntityUid? statusEffect, + TimeSpan? duration = null ) { - return TryAddStatusEffect(target, effectProto, out _, duration, resetCooldown); + if (!TryGetStatusEffect(target, effectProto, out statusEffect)) + return TryAddStatusEffect(target, effectProto, out statusEffect, duration); + + SetStatusEffectTime(statusEffect.Value, duration); + + return true; + } + + /// + public bool TrySetStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null) + { + return TrySetStatusEffectDuration(target, effectProto, out _, duration); + } + + /// + /// Updates duration of effect to larger value between provided and current effect duration. + /// Tries to add status effect if it is not yet present on entity. + /// + /// The target entity to which the effect should be added. + /// ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it. + /// Duration of status effect. Leave null and the effect will be permanent until it is removed using TryRemoveStatusEffect. + /// The EntityUid of the status effect we have just created or null if it doesn't exist. + /// True if effect exists and its duration is set properly, false in case effect cannot be applied. + public bool TryUpdateStatusEffectDuration( + EntityUid target, + EntProtoId effectProto, + [NotNullWhen(true)] out EntityUid? statusEffect, + TimeSpan? duration = null + ) + { + if (!TryGetStatusEffect(target, effectProto, out statusEffect)) + return TryAddStatusEffect(target, effectProto, out statusEffect, duration); + + UpdateStatusEffectTime(statusEffect.Value, duration); + + return true; + } + + /// + public bool TryUpdateStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null) + { + return TryUpdateStatusEffectDuration(target, effectProto, out _, duration); } /// @@ -190,6 +204,36 @@ public abstract partial class SharedStatusEffectsSystem return false; } + /// + /// Attempts to get the maximum time left for a given Status Effect Component, returns false if no such + /// component exists. + /// + /// The target entity on which the effect is applied. + /// Returns the EntityUid of the status effect with the most time left, and the end effect time + /// of that status effect. + /// True if a status effect entity with the given component exists + public bool TryGetMaxTime(EntityUid uid, out (EntityUid EffectEnt, TimeSpan? EndEffectTime) time) where T : IComponent + { + time = default; + if (!TryEffectsWithComp(uid, out var status)) + return false; + + time.Item2 = TimeSpan.Zero; + + foreach (var effect in status) + { + if (effect.Comp2.EndEffectTime == null) + { + time = (effect.Owner, null); + return true; + } + + if (effect.Comp2.EndEffectTime > time.Item2) + time = (effect.Owner, effect.Comp2.EndEffectTime); + } + return true; + } + /// /// Attempts to edit the remaining time for a status effect on an entity. /// From a6c58aba12945e8abb77feed556615d44d75259a Mon Sep 17 00:00:00 2001 From: little-meow-meow <204685920+little-meow-meow@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:26:03 -0700 Subject: [PATCH 021/105] ci: include pull request id in changelog link (#38504) Signed-off-by: little-meow-meow <204685920+little-meow-meow@users.noreply.github.com> --- Tools/actions_changelogs_since_last_run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/actions_changelogs_since_last_run.py b/Tools/actions_changelogs_since_last_run.py index 8df972d258..4337980c14 100755 --- a/Tools/actions_changelogs_since_last_run.py +++ b/Tools/actions_changelogs_since_last_run.py @@ -189,7 +189,8 @@ def changelog_entries_to_message_lines(entries: Iterable[ChangelogEntry]) -> lis message = message[: DISCORD_SPLIT_LIMIT - 100].rstrip() + " [...]" if url is not None: - line = f"{emoji} - {message} [PR]({url}) \n" + pr_number = url.split("/")[-1] + line = f"{emoji} - {message} ([#{pr_number}]({url}))\n" else: line = f"{emoji} - {message}\n" From 80d733a15211ca96a2668dba009965638ef490b4 Mon Sep 17 00:00:00 2001 From: Andrew Malcolm O'Neill <105134723+maland1@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:50:22 +0100 Subject: [PATCH 022/105] Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661) * Resolving Wizard Recall on Nuke disk making it impossible to disarm - Adding a DisarmBomb case to nuke status update loop - Changing a few methods and parameters to properly follow formatting standards - Updating some names to follow camelCase * Updating missed tag * Reverting DataField change Should prevent this preventative bugfix being a breaking change. --- Content.Server/Nuke/NukeComponent.cs | 2 +- Content.Server/Nuke/NukeSystem.cs | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Content.Server/Nuke/NukeComponent.cs b/Content.Server/Nuke/NukeComponent.cs index b14ad9c165..cd1c0227eb 100644 --- a/Content.Server/Nuke/NukeComponent.cs +++ b/Content.Server/Nuke/NukeComponent.cs @@ -56,7 +56,7 @@ namespace Content.Server.Nuke /// How long a user must wait to disarm the bomb. /// [DataField("disarmDoafterLength")] - public float DisarmDoafterLength = 30.0f; + public float DisarmDoAfterLength = 30.0f; [DataField("alertLevelOnActivate")] public string AlertLevelOnActivate = default!; [DataField("alertLevelOnDeactivate")] public string AlertLevelOnDeactivate = default!; diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs index 81fbf074da..f110734a60 100644 --- a/Content.Server/Nuke/NukeSystem.cs +++ b/Content.Server/Nuke/NukeSystem.cs @@ -165,7 +165,7 @@ public sealed class NukeSystem : EntitySystem { UpdateUserInterface(uid, component); - if (args.Anchored == false && component.Status == NukeStatus.ARMED && component.RemainingTime > component.DisarmDoafterLength) + if (args.Anchored == false && component.Status == NukeStatus.ARMED && component.RemainingTime > component.DisarmDoAfterLength) { // yes, this means technically if you can find a way to unanchor the nuke, you can disarm it // without the doafter. but that takes some effort, and it won't allow you to disarm a nuke that can't be disarmed by the doafter. @@ -271,7 +271,7 @@ public sealed class NukeSystem : EntitySystem else { - DisarmBombDoafter(uid, args.Actor, component); + DisarmBombDoAfter(uid, args.Actor, component); } } @@ -381,7 +381,12 @@ public sealed class NukeSystem : EntitySystem // do nothing, wait for arm button to be pressed break; case NukeStatus.ARMED: - // do nothing, wait for arm button to be unpressed + // handling case of wizard recalling disk out of armed Nuke + if (!component.DiskSlot.HasItem) + { + DisarmBomb(uid, component); + } + break; } } @@ -409,7 +414,7 @@ public sealed class NukeSystem : EntitySystem AllowArm = allowArm, EnteredCodeLength = component.EnteredCode.Length, MaxCodeLength = component.CodeLength, - CooldownTime = (int) component.CooldownTime + CooldownTime = (int) component.CooldownTime, }; _ui.SetUiState(uid, NukeUiKey.Key, state); @@ -436,7 +441,7 @@ public sealed class NukeSystem : EntitySystem 8 => 9, 9 => 10, 0 => component.LastPlayedKeypadSemitones + 12, - _ => 0 + _ => 0, }; // Don't double-dip on the octave shifting @@ -617,9 +622,9 @@ public sealed class NukeSystem : EntitySystem #endregion - private void DisarmBombDoafter(EntityUid uid, EntityUid user, NukeComponent nuke) + private void DisarmBombDoAfter(EntityUid uid, EntityUid user, NukeComponent nuke) { - var doAfter = new DoAfterArgs(EntityManager, user, nuke.DisarmDoafterLength, new NukeDisarmDoAfterEvent(), uid, target: uid) + var doAfter = new DoAfterArgs(EntityManager, user, nuke.DisarmDoAfterLength, new NukeDisarmDoAfterEvent(), uid, target: uid) { BreakOnDamage = true, BreakOnMove = true, @@ -629,8 +634,10 @@ public sealed class NukeSystem : EntitySystem if (!_doAfter.TryStartDoAfter(doAfter)) return; - _popups.PopupEntity(Loc.GetString("nuke-component-doafter-warning"), user, - user, PopupType.LargeCaution); + _popups.PopupEntity(Loc.GetString("nuke-component-doafter-warning"), + user, + user, + PopupType.LargeCaution); } private void UpdateAppearance(EntityUid uid, NukeComponent nuke) From 8597acd030bc6b3b4cb5c7b1ac0a411db25655c9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 2 Jul 2025 20:51:29 +0000 Subject: [PATCH 023/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3d67cec87c..c51b0b9058 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Hoodie42 - changes: - - message: The banjo can now be worn on the back or suit storage slots. - type: Tweak - id: 8216 - time: '2025-04-17T14:05:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34057 - author: muburu changes: - message: Space Dragons now have randomly generated names. @@ -3888,3 +3881,11 @@ id: 8728 time: '2025-07-01T10:25:52.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38681 +- author: maland1 + changes: + - message: Fixed Wizard recalling nuke disk from inside an armed nuke making it + impossible to defuse + type: Fix + id: 8729 + time: '2025-07-02T20:50:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38661 From 38232d2255206cf31bd43719769d279aaabeb4df Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Thu, 3 Jul 2025 01:20:31 +0200 Subject: [PATCH 024/105] Predict healing and bloodstream (#38690) * initial commit * reapply 38126 * fix rootable * someone missed an important minus sign here * try this * fix * fix * reenable crit hits * cleanup * fix status time dirtying * fix * camelCase --- .../Body/Systems/BloodStreamSystem.cs | 5 + .../Systems/AdminVerbSystem.Smites.cs | 2 +- Content.Server/Atmos/Rotting/RottingSystem.cs | 2 +- .../Body/Components/BloodstreamComponent.cs | 186 ------- .../Body/Components/MetabolizerComponent.cs | 1 + .../Body/Systems/BloodstreamSystem.cs | 485 +--------------- Content.Server/Body/Systems/BodySystem.cs | 1 - .../Chemistry/EntitySystems/InjectorSystem.cs | 5 +- .../SolutionInjectOnEventSystem.cs | 4 +- Content.Server/Devour/DevourSystem.cs | 2 +- .../EntityEffects/EntityEffectSystem.cs | 9 +- .../Fluids/EntitySystems/SmokeSystem.cs | 4 +- .../Forensics/Systems/ForensicsSystem.cs | 2 +- Content.Server/Implants/ImplantedSystem.cs | 2 +- .../BiomassReclaimerSystem.cs | 3 +- .../Medical/Components/HealingComponent.cs | 66 --- Content.Server/Medical/CryoPodSystem.cs | 4 +- .../Medical/HealthAnalyzerSystem.cs | 4 +- Content.Server/Medical/VomitSystem.cs | 1 - .../Mind/TransferMindOnGibSystem.cs | 2 +- .../EntitySystems/SmokingSystem.Vape.cs | 2 +- .../Nutrition/EntitySystems/SmokingSystem.cs | 6 +- Content.Server/Rootable/RootableSystem.cs | 7 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 3 +- .../Zombies/ZombieSystem.Transform.cs | 1 + .../Body/Components/BloodstreamComponent.cs | 200 +++++++ .../Events/ApplyMetabolicMultiplierEvent.cs | 2 +- .../Body/Events}/BeingGibbedEvent.cs | 2 +- .../Body/Systems/SharedBloodstreamSystem.cs | 519 ++++++++++++++++++ Content.Shared/Body/Systems/StomachSystem.cs | 1 + .../EntitySystems/HypospraySystem.cs | 4 +- Content.Shared/Damage/DamageSpecifier.cs | 6 + .../Damage/Systems/DamageableSystem.cs | 2 +- .../Medical/Healing/HealingComponent.cs | 65 +++ .../Medical/Healing}/HealingSystem.cs | 136 +++-- .../medical/components/healing-component.ftl | 8 +- .../Objects/Specific/Medical/healing.yml | 2 +- 37 files changed, 915 insertions(+), 841 deletions(-) create mode 100644 Content.Client/Body/Systems/BloodStreamSystem.cs delete mode 100644 Content.Server/Body/Components/BloodstreamComponent.cs delete mode 100644 Content.Server/Medical/Components/HealingComponent.cs create mode 100644 Content.Shared/Body/Components/BloodstreamComponent.cs rename {Content.Server/Body/Components => Content.Shared/Body/Events}/BeingGibbedEvent.cs (81%) create mode 100644 Content.Shared/Body/Systems/SharedBloodstreamSystem.cs create mode 100644 Content.Shared/Medical/Healing/HealingComponent.cs rename {Content.Server/Medical => Content.Shared/Medical/Healing}/HealingSystem.cs (54%) diff --git a/Content.Client/Body/Systems/BloodStreamSystem.cs b/Content.Client/Body/Systems/BloodStreamSystem.cs new file mode 100644 index 0000000000..85f4f6198e --- /dev/null +++ b/Content.Client/Body/Systems/BloodStreamSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.Body.Systems; + +namespace Content.Client.Body.Systems; + +public sealed class BloodstreamSystem : SharedBloodstreamSystem; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 442c768709..b764c7f68d 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -273,7 +273,7 @@ public sealed partial class AdminVerbSystem Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/tomato_splat.rsi"), "puddle-1"), Act = () => { - _bloodstreamSystem.SpillAllSolutions(args.Target, bloodstream); + _bloodstreamSystem.SpillAllSolutions((args.Target, bloodstream)); var xform = Transform(args.Target); _popupSystem.PopupEntity(Loc.GetString("admin-smite-remove-blood-self"), args.Target, args.Target, PopupType.LargeCaution); diff --git a/Content.Server/Atmos/Rotting/RottingSystem.cs b/Content.Server/Atmos/Rotting/RottingSystem.cs index 43dddce4a4..6f14debc3d 100644 --- a/Content.Server/Atmos/Rotting/RottingSystem.cs +++ b/Content.Server/Atmos/Rotting/RottingSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Body.Components; using Content.Server.Temperature.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Rotting; +using Content.Shared.Body.Events; using Content.Shared.Damage; using Robust.Server.Containers; using Robust.Shared.Physics.Components; diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs deleted file mode 100644 index 35e76403bb..0000000000 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ /dev/null @@ -1,186 +0,0 @@ -using Content.Server.Body.Systems; -using Content.Server.Chemistry.EntitySystems; -using Content.Shared.Alert; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; -using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; -using Content.Shared.FixedPoint; -using Robust.Shared.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Server.Body.Components -{ - [RegisterComponent, Access(typeof(BloodstreamSystem), typeof(ReactionMixerSystem))] - public sealed partial class BloodstreamComponent : Component - { - public static string DefaultChemicalsSolutionName = "chemicals"; - public static string DefaultBloodSolutionName = "bloodstream"; - public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary"; - - /// - /// The next time that blood level will be updated and bloodloss damage dealt. - /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] - public TimeSpan NextUpdate; - - /// - /// The interval at which this component updates. - /// - [DataField] - public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3); - - /// - /// How much is this entity currently bleeding? - /// Higher numbers mean more blood lost every tick. - /// - /// Goes down slowly over time, and items like bandages - /// or clotting reagents can lower bleeding. - /// - /// - /// This generally corresponds to an amount of damage and can't go above 100. - /// - [ViewVariables(VVAccess.ReadWrite)] - public float BleedAmount; - - /// - /// How much should bleeding be reduced every update interval? - /// - [DataField] - public float BleedReductionAmount = 0.33f; - - /// - /// How high can go? - /// - [DataField] - public float MaxBleedAmount = 10.0f; - - /// - /// What percentage of current blood is necessary to avoid dealing blood loss damage? - /// - [DataField] - public float BloodlossThreshold = 0.9f; - - /// - /// The base bloodloss damage to be incurred if below - /// The default values are defined per mob/species in YML. - /// - [DataField(required: true)] - public DamageSpecifier BloodlossDamage = new(); - - /// - /// The base bloodloss damage to be healed if above - /// The default values are defined per mob/species in YML. - /// - [DataField(required: true)] - public DamageSpecifier BloodlossHealDamage = new(); - - // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. - /// - /// How much reagent of blood should be restored each update interval? - /// - [DataField] - public FixedPoint2 BloodRefreshAmount = 1.0f; - - /// - /// How much blood needs to be in the temporary solution in order to create a puddle? - /// - [DataField] - public FixedPoint2 BleedPuddleThreshold = 1.0f; - - /// - /// A modifier set prototype ID corresponding to how damage should be modified - /// before taking it into account for bloodloss. - /// - /// - /// For example, piercing damage is increased while poison damage is nullified entirely. - /// - [DataField] - public ProtoId DamageBleedModifiers = "BloodlossHuman"; - - /// - /// The sound to be played when a weapon instantly deals blood loss damage. - /// - [DataField] - public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood"); - - /// - /// The sound to be played when some damage actually heals bleeding rather than starting it. - /// - [DataField] - public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); - - /// - /// The minimum amount damage reduction needed to play the healing sound/popup. - /// This prevents tiny amounts of heat damage from spamming the sound, e.g. spacing. - /// - [DataField] - public float BloodHealedSoundThreshold = -0.1f; - - // TODO probably damage bleed thresholds. - - /// - /// Max volume of internal chemical solution storage - /// - [DataField] - public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250); - - /// - /// Max volume of internal blood storage, - /// and starting level of blood. - /// - [DataField] - public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300); - - /// - /// Which reagent is considered this entities 'blood'? - /// - /// - /// Slime-people might use slime as their blood or something like that. - /// - [DataField] - public ProtoId BloodReagent = "Blood"; - - /// Name/Key that is indexed by. - [DataField] - public string BloodSolutionName = DefaultBloodSolutionName; - - /// Name/Key that is indexed by. - [DataField] - public string ChemicalSolutionName = DefaultChemicalsSolutionName; - - /// Name/Key that is indexed by. - [DataField] - public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName; - - /// - /// Internal solution for blood storage - /// - [ViewVariables] - public Entity? BloodSolution; - - /// - /// Internal solution for reagent storage - /// - [ViewVariables] - public Entity? ChemicalSolution; - - /// - /// Temporary blood solution. - /// When blood is lost, it goes to this solution, and when this - /// solution hits a certain cap, the blood is actually spilled as a puddle. - /// - [ViewVariables] - public Entity? TemporarySolution; - - /// - /// Variable that stores the amount of status time added by having a low blood level. - /// - [ViewVariables(VVAccess.ReadWrite)] - public TimeSpan StatusTime; - - [DataField] - public ProtoId BleedingAlert = "Bleed"; - } -} diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs index 90c99df7db..3699267ebf 100644 --- a/Content.Server/Body/Components/MetabolizerComponent.cs +++ b/Content.Server/Body/Components/MetabolizerComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Body.Components; using Content.Server.Body.Systems; using Content.Shared.Body.Prototypes; using Content.Shared.FixedPoint; diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index 6d85affad3..c2185750af 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -1,189 +1,32 @@ -using Content.Server.Body.Components; -using Content.Server.Fluids.EntitySystems; -using Content.Server.Popups; -using Content.Shared.Alert; -using Content.Shared.Body.Events; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.Chemistry.Reaction; +using Content.Shared.Body.Components; +using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Reagent; -using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; -using Content.Shared.Drunk; -using Content.Shared.EntityEffects.Effects; -using Content.Shared.FixedPoint; using Content.Shared.Forensics; -using Content.Shared.Forensics.Components; -using Content.Shared.HealthExaminable; -using Content.Shared.Mobs.Systems; -using Content.Shared.Popups; -using Content.Shared.Rejuvenate; -using Content.Shared.Speech.EntitySystems; -using Robust.Server.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Timing; namespace Content.Server.Body.Systems; -public sealed class BloodstreamSystem : EntitySystem +public sealed class BloodstreamSystem : SharedBloodstreamSystem { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _robustRandom = default!; - [Dependency] private readonly AudioSystem _audio = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly PuddleSystem _puddleSystem = default!; - [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly SharedDrunkSystem _drunkSystem = default!; - [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; - [Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!; - [Dependency] private readonly AlertsSystem _alertsSystem = default!; - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnUnpaused); - SubscribeLocalEvent(OnDamageChanged); - SubscribeLocalEvent(OnHealthBeingExamined); - SubscribeLocalEvent(OnBeingGibbed); - SubscribeLocalEvent(OnApplyMetabolicMultiplier); - SubscribeLocalEvent(OnReactionAttempt); - SubscribeLocalEvent>(OnReactionAttempt); - SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnDnaGenerated); } - private void OnMapInit(Entity ent, ref MapInitEvent args) - { - ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; - } - - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextUpdate += args.PausedTime; - } - - private void OnReactionAttempt(Entity entity, ref ReactionAttemptEvent args) - { - if (args.Cancelled) - return; - - foreach (var effect in args.Reaction.Effects) - { - switch (effect) - { - case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream - case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels. - args.Cancelled = true; - return; - } - } - - // The area-reaction effect canceling is part of avoiding smoke-fork-bombs (create two smoke bombs, that when - // ingested by mobs create more smoke). This also used to act as a rapid chemical-purge, because all the - // reagents would get carried away by the smoke/foam. This does still work for the stomach (I guess people vomit - // up the smoke or spawned entities?). - - // TODO apply organ damage instead of just blocking the reaction? - // Having cheese-clots form in your veins can't be good for you. - } - - private void OnReactionAttempt(Entity entity, ref SolutionRelayEvent args) - { - if (args.Name != entity.Comp.BloodSolutionName - && args.Name != entity.Comp.ChemicalSolutionName - && args.Name != entity.Comp.BloodTemporarySolutionName) - { - return; - } - - OnReactionAttempt(entity, ref args.Event); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var bloodstream)) - { - if (_gameTiming.CurTime < bloodstream.NextUpdate) - continue; - - bloodstream.NextUpdate += bloodstream.UpdateInterval; - - if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) - continue; - - // Adds blood to their blood level if it is below the maximum; Blood regeneration. Must be alive. - if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid)) - { - TryModifyBloodLevel(uid, bloodstream.BloodRefreshAmount, bloodstream); - } - - // Removes blood from the bloodstream based on bleed amount (bleed rate) - // as well as stop their bleeding to a certain extent. - if (bloodstream.BleedAmount > 0) - { - // Blood is removed from the bloodstream at a 1-1 rate with the bleed amount - TryModifyBloodLevel(uid, (-bloodstream.BleedAmount), bloodstream); - // Bleed rate is reduced by the bleed reduction amount in the bloodstream component. - TryModifyBleedAmount(uid, -bloodstream.BleedReductionAmount, bloodstream); - } - - // deal bloodloss damage if their blood level is below a threshold. - var bloodPercentage = GetBloodLevelPercentage(uid, bloodstream); - if (bloodPercentage < bloodstream.BloodlossThreshold && !_mobStateSystem.IsDead(uid)) - { - // bloodloss damage is based on the base value, and modified by how low your blood level is. - var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage); - - _damageableSystem.TryChangeDamage(uid, amt, - ignoreResistances: false, interruptsDoAfters: false); - - // Apply dizziness as a symptom of bloodloss. - // The effect is applied in a way that it will never be cleared without being healthy. - // Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out - _drunkSystem.TryApplyDrunkenness( - uid, - (float) bloodstream.UpdateInterval.TotalSeconds * 2, - applySlur: false); - _stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false); - - // storing the drunk and stutter time so we can remove it independently from other effects additions - bloodstream.StatusTime += bloodstream.UpdateInterval * 2; - } - else if (!_mobStateSystem.IsDead(uid)) - { - // If they're healthy, we'll try and heal some bloodloss instead. - _damageableSystem.TryChangeDamage( - uid, - bloodstream.BloodlossHealDamage * bloodPercentage, - ignoreResistances: true, interruptsDoAfters: false); - - // Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level - _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds); - _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds); - // Reset the drunk and stutter time to zero - bloodstream.StatusTime = TimeSpan.Zero; - } - } - } - + // not sure if we can move this to shared or not + // it would certainly help if SolutionContainer was documented + // but since we usually don't add the component dynamically to entities we can keep this unpredicted for now private void OnComponentInit(Entity entity, ref ComponentInit args) { - if (!_solutionContainerSystem.EnsureSolution(entity.Owner, + if (!SolutionContainer.EnsureSolution(entity.Owner, entity.Comp.ChemicalSolutionName, out var chemicalSolution) || - !_solutionContainerSystem.EnsureSolution(entity.Owner, + !SolutionContainer.EnsureSolution(entity.Owner, entity.Comp.BloodSolutionName, out var bloodSolution) || - !_solutionContainerSystem.EnsureSolution(entity.Owner, + !SolutionContainer.EnsureSolution(entity.Owner, entity.Comp.BloodTemporarySolutionName, out var tempSolution)) return; @@ -197,298 +40,10 @@ public sealed class BloodstreamSystem : EntitySystem bloodSolution.AddReagent(new ReagentId(entity.Comp.BloodReagent, GetEntityBloodData(entity.Owner)), entity.Comp.BloodMaxVolume - bloodSolution.Volume); } - private void OnDamageChanged(Entity ent, ref DamageChangedEvent args) - { - if (args.DamageDelta is null || !args.DamageIncreased) - { - return; - } - - // TODO probably cache this or something. humans get hurt a lot - if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers)) - return; - - // some reagents may deal and heal different damage types in the same tick, which means DamageIncreased will be true - // but we only want to consider the dealt damage when causing bleeding - var damage = DamageSpecifier.GetPositive(args.DamageDelta); - var bloodloss = DamageSpecifier.ApplyModifierSet(damage, modifiers); - - if (bloodloss.Empty) - return; - - // Does the calculation of how much bleed rate should be added/removed, then applies it - var oldBleedAmount = ent.Comp.BleedAmount; - var total = bloodloss.GetTotal(); - var totalFloat = total.Float(); - TryModifyBleedAmount(ent, totalFloat, ent); - - /// - /// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5 - /// The crit chance is currently the bleed rate modifier divided by 25. - /// Higher damage weapons have a higher chance to crit! - /// - var prob = Math.Clamp(totalFloat / 25, 0, 1); - if (totalFloat > 0 && _robustRandom.Prob(prob)) - { - TryModifyBloodLevel(ent, -total / 5, ent); - _audio.PlayPvs(ent.Comp.InstantBloodSound, ent); - } - - // Heat damage will cauterize, causing the bleed rate to be reduced. - else if (totalFloat <= ent.Comp.BloodHealedSoundThreshold && oldBleedAmount > 0) - { - // Magically, this damage has healed some bleeding, likely - // because it's burn damage that cauterized their wounds. - - // We'll play a special sound and popup for feedback. - _audio.PlayPvs(ent.Comp.BloodHealedSound, ent); - _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent, - ent, PopupType.Medium); - } - } - /// - /// Shows text on health examine, based on bleed rate and blood level. - /// - private void OnHealthBeingExamined(Entity ent, ref HealthBeingExaminedEvent args) - { - // Shows massively bleeding at 0.75x the max bleed rate. - if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.75f) - { - args.Message.PushNewline(); - args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-massive-bleeding", ("target", ent.Owner))); - } - // Shows bleeding message when bleeding above half the max rate, but less than massively. - else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.5f) - { - args.Message.PushNewline(); - args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-strong-bleeding", ("target", ent.Owner))); - } - // Shows bleeding message when bleeding above 0.25x the max rate, but less than half the max. - else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.25f) - { - args.Message.PushNewline(); - args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-bleeding", ("target", ent.Owner))); - } - // Shows bleeding message when bleeding below 0.25x the max cap - else if (ent.Comp.BleedAmount > 0) - { - args.Message.PushNewline(); - args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-slight-bleeding", ("target", ent.Owner))); - } - - // If the mob's blood level is below the damage threshhold, the pale message is added. - if (GetBloodLevelPercentage(ent, ent) < ent.Comp.BloodlossThreshold) - { - args.Message.PushNewline(); - args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-looks-pale", ("target", ent.Owner))); - } - } - - private void OnBeingGibbed(Entity ent, ref BeingGibbedEvent args) - { - SpillAllSolutions(ent, ent); - } - - private void OnApplyMetabolicMultiplier( - Entity ent, - ref ApplyMetabolicMultiplierEvent args) - { - // TODO REFACTOR THIS - // This will slowly drift over time due to floating point errors. - // Instead, raise an event with the base rates and allow modifiers to get applied to it. - if (args.Apply) - { - ent.Comp.UpdateInterval *= args.Multiplier; - return; - } - ent.Comp.UpdateInterval /= args.Multiplier; - } - - private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) - { - TryModifyBleedAmount(entity.Owner, -entity.Comp.BleedAmount, entity.Comp); - - if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution)) - TryModifyBloodLevel(entity.Owner, bloodSolution.AvailableVolume, entity.Comp); - - if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.ChemicalSolutionName, ref entity.Comp.ChemicalSolution)) - _solutionContainerSystem.RemoveAllSolution(entity.Comp.ChemicalSolution.Value); - } - - /// - /// Attempt to transfer provided solution to internal solution. - /// - public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null) - { - return Resolve(uid, ref component, logMissing: false) - && _solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution) - && _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution); - } - - public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component, logMissing: false) - || !_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution)) - return false; - - for (var i = chemSolution.Contents.Count - 1; i >= 0; i--) - { - var (reagentId, _) = chemSolution.Contents[i]; - if (reagentId.Prototype != excludedReagentID) - { - _solutionContainerSystem.RemoveReagent(component.ChemicalSolution.Value, reagentId, quantity); - } - } - - return true; - } - - public float GetBloodLevelPercentage(EntityUid uid, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component) - || !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) - { - return 0.0f; - } - - return bloodSolution.FillFraction; - } - - public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamComponent? comp = null) - { - if (!Resolve(uid, ref comp)) - return; - - comp.BloodlossThreshold = threshold; - } - - /// - /// Attempts to modify the blood level of this entity directly. - /// - public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component, logMissing: false) - || !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution)) - { - return false; - } - - if (amount >= 0) - return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, null, GetEntityBloodData(uid)); - - // Removal is more involved, - // since we also wanna handle moving it to the temporary solution - // and then spilling it if necessary. - var newSol = _solutionContainerSystem.SplitSolution(component.BloodSolution.Value, -amount); - - if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution)) - return true; - - tempSolution.AddSolution(newSol, _prototypeManager); - - if (tempSolution.Volume > component.BleedPuddleThreshold) - { - // Pass some of the chemstream into the spilled blood. - if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)) - { - var temp = _solutionContainerSystem.SplitSolution(component.ChemicalSolution.Value, tempSolution.Volume / 10); - tempSolution.AddSolution(temp, _prototypeManager); - } - - _puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false); - - tempSolution.RemoveAllSolution(); - } - - _solutionContainerSystem.UpdateChemicals(component.TemporarySolution.Value); - - return true; - } - - /// - /// Tries to make an entity bleed more or less - /// - public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component, logMissing: false)) - return false; - - component.BleedAmount += amount; - component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount); - - if (component.BleedAmount == 0) - _alertsSystem.ClearAlert(uid, component.BleedingAlert); - else - { - var severity = (short) Math.Clamp(Math.Round(component.BleedAmount, MidpointRounding.ToZero), 0, 10); - _alertsSystem.ShowAlert(uid, component.BleedingAlert, severity); - } - - return true; - } - - /// - /// BLOOD FOR THE BLOOD GOD - /// - public void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - var tempSol = new Solution(); - - if (_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) - { - tempSol.MaxVolume += bloodSolution.MaxVolume; - tempSol.AddSolution(bloodSolution, _prototypeManager); - _solutionContainerSystem.RemoveAllSolution(component.BloodSolution.Value); - } - - if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution)) - { - tempSol.MaxVolume += chemSolution.MaxVolume; - tempSol.AddSolution(chemSolution, _prototypeManager); - _solutionContainerSystem.RemoveAllSolution(component.ChemicalSolution.Value); - } - - if (_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution)) - { - tempSol.MaxVolume += tempSolution.MaxVolume; - tempSol.AddSolution(tempSolution, _prototypeManager); - _solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value); - } - - _puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid); - } - - /// - /// Change what someone's blood is made of, on the fly. - /// - public void ChangeBloodReagent(EntityUid uid, string reagent, BloodstreamComponent? component = null) - { - if (!Resolve(uid, ref component, logMissing: false) - || reagent == component.BloodReagent) - { - return; - } - - if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) - { - component.BloodReagent = reagent; - return; - } - - var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume, ignoreReagentData: true); - - component.BloodReagent = reagent; - - if (currentVolume > 0) - _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, null, GetEntityBloodData(uid)); - } - + // forensics is not predicted yet private void OnDnaGenerated(Entity entity, ref GenerateDnaEvent args) { - if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution)) + if (SolutionContainer.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution)) { foreach (var reagent in bloodSolution.Contents) { @@ -500,22 +55,4 @@ public sealed class BloodstreamSystem : EntitySystem else Log.Error("Unable to set bloodstream DNA, solution entity could not be resolved"); } - - /// - /// Get the reagent data for blood that a specific entity should have. - /// - public List GetEntityBloodData(EntityUid uid) - { - var bloodData = new List(); - var dnaData = new DnaData(); - - if (TryComp(uid, out var donorComp) && donorComp.DNA != null) - dnaData.DNA = donorComp.DNA; - else - dnaData.DNA = Loc.GetString("forensics-dna-unknown"); - - bloodData.Add(dnaData); - - return bloodData; - } } diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index d2fc3d6558..957dea9d41 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Content.Server.Body.Components; using Content.Server.Ghost; using Content.Server.Humanoid; using Content.Shared.Body.Components; diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs index f53688a241..7b43e7f092 100644 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs @@ -1,10 +1,9 @@ -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.Chemistry.Reagent; +using Content.Shared.Body.Components; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; @@ -237,7 +236,7 @@ public sealed class InjectorSystem : SharedInjectorSystem // Move units from attackSolution to targetSolution var removedSolution = SolutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount); - _blood.TryAddToChemicals(target, removedSolution, target.Comp); + _blood.TryAddToChemicals(target.AsNullable(), removedSolution); _reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection); diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs index 503a0ebde6..7b4deea9f4 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs @@ -1,7 +1,7 @@ -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Body.Components; using Content.Shared.Chemistry.Events; using Content.Shared.Inventory; using Content.Shared.Popups; @@ -148,7 +148,7 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem // Take our portion of the adjusted solution for this target var individualInjection = solutionToInject.SplitSolution(volumePerBloodstream); // Inject our portion into the target's bloodstream - if (_bloodstream.TryAddToChemicals(targetBloodstream.Owner, individualInjection, targetBloodstream.Comp)) + if (_bloodstream.TryAddToChemicals(targetBloodstream.AsNullable(), individualInjection)) anySuccess = true; } diff --git a/Content.Server/Devour/DevourSystem.cs b/Content.Server/Devour/DevourSystem.cs index 8ee4cf852b..88edc3ec4c 100644 --- a/Content.Server/Devour/DevourSystem.cs +++ b/Content.Server/Devour/DevourSystem.cs @@ -1,5 +1,5 @@ -using Content.Server.Body.Components; using Content.Server.Body.Systems; +using Content.Shared.Body.Events; using Content.Shared.Chemistry.Components; using Content.Shared.Devour; using Content.Shared.Devour.Components; diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs index 98853a0e61..e18b3b1470 100644 --- a/Content.Server/EntityEffects/EntityEffectSystem.cs +++ b/Content.Server/EntityEffects/EntityEffectSystem.cs @@ -22,6 +22,7 @@ using Content.Server.Temperature.Systems; using Content.Server.Traits.Assorted; using Content.Server.Zombies; using Content.Shared.Atmos; +using Content.Shared.Body.Components; using Content.Shared.Coordinates.Helpers; using Content.Shared.EntityEffects.EffectConditions; using Content.Shared.EntityEffects.Effects.PlantMetabolism; @@ -558,11 +559,11 @@ public sealed class EntityEffectSystem : EntitySystem return; cleanseRate *= reagentArgs.Scale.Float(); - _bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent.ID, cleanseRate); + _bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent, cleanseRate); } else { - _bloodstream.FlushChemicals(args.Args.TargetEntity, "", cleanseRate); + _bloodstream.FlushChemicals(args.Args.TargetEntity, null, cleanseRate); } } @@ -780,7 +781,7 @@ public sealed class EntityEffectSystem : EntitySystem amt *= reagentArgs.Scale.Float(); } - _bloodstream.TryModifyBleedAmount(args.Args.TargetEntity, amt, blood); + _bloodstream.TryModifyBleedAmount((args.Args.TargetEntity, blood), amt); } } @@ -796,7 +797,7 @@ public sealed class EntityEffectSystem : EntitySystem amt *= reagentArgs.Scale; } - _bloodstream.TryModifyBloodLevel(args.Args.TargetEntity, amt, blood); + _bloodstream.TryModifyBloodLevel((args.Args.TargetEntity, blood), amt); } } diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index dfbad1bbe9..13695caff1 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Administration.Logs; -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Shared.EntityEffects.Effects; using Content.Server.Spreader; +using Content.Shared.Body.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; @@ -288,7 +288,7 @@ public sealed class SmokeSystem : EntitySystem if (blockIngestion) return; - if (_blood.TryAddToChemicals(entity, transferSolution, bloodstream)) + if (_blood.TryAddToChemicals((entity, bloodstream), transferSolution)) { // Log solution addition by smoke _logger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity):target} ingested smoke {SharedSolutionContainerSystem.ToPrettyString(transferSolution)}"); diff --git a/Content.Server/Forensics/Systems/ForensicsSystem.cs b/Content.Server/Forensics/Systems/ForensicsSystem.cs index ec4683460b..9f94e39fb7 100644 --- a/Content.Server/Forensics/Systems/ForensicsSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicsSystem.cs @@ -1,9 +1,9 @@ -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.DoAfter; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics.Components; using Content.Server.Popups; +using Content.Shared.Body.Events; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Popups; using Content.Shared.Chemistry.Components; diff --git a/Content.Server/Implants/ImplantedSystem.cs b/Content.Server/Implants/ImplantedSystem.cs index c5048cbd8d..7851758730 100644 --- a/Content.Server/Implants/ImplantedSystem.cs +++ b/Content.Server/Implants/ImplantedSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Body.Components; +using Content.Shared.Body.Events; using Content.Shared.Implants.Components; using Content.Shared.Storage; using Robust.Shared.Containers; diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs index f6b751c398..42e455a47f 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs @@ -1,11 +1,11 @@ using System.Numerics; -using Content.Server.Body.Components; using Content.Server.Botany.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.Materials; using Content.Server.Power.Components; using Content.Shared.Administration.Logs; using Content.Shared.Audio; +using Content.Shared.Body.Components; using Content.Shared.CCVar; using Content.Shared.Chemistry.Components; using Content.Shared.Climbing.Events; @@ -30,7 +30,6 @@ using Robust.Server.Player; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Physics.Components; -using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Medical.BiomassReclaimer diff --git a/Content.Server/Medical/Components/HealingComponent.cs b/Content.Server/Medical/Components/HealingComponent.cs deleted file mode 100644 index a56bc17143..0000000000 --- a/Content.Server/Medical/Components/HealingComponent.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; -using Robust.Shared.Audio; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Server.Medical.Components -{ - /// - /// Applies a damage change to the target when used in an interaction. - /// - [RegisterComponent] - public sealed partial class HealingComponent : Component - { - [DataField("damage", required: true)] - [ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier Damage = default!; - - /// - /// This should generally be negative, - /// since you're, like, trying to heal damage. - /// - [DataField("bloodlossModifier")] - [ViewVariables(VVAccess.ReadWrite)] - public float BloodlossModifier = 0.0f; - - /// - /// Restore missing blood. - /// - [DataField("ModifyBloodLevel")] - [ViewVariables(VVAccess.ReadWrite)] - public float ModifyBloodLevel = 0.0f; - - /// - /// The supported damage types are specified using a s. For a - /// HealingComponent this filters what damage container type this component should work on. If null, - /// all damage container types are supported. - /// - [DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List? DamageContainers; - - /// - /// How long it takes to apply the damage. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("delay")] - public float Delay = 3f; - - /// - /// Delay multiplier when healing yourself. - /// - [DataField("selfHealPenaltyMultiplier")] - public float SelfHealPenaltyMultiplier = 3f; - - /// - /// Sound played on healing begin - /// - [DataField("healingBeginSound")] - public SoundSpecifier? HealingBeginSound = null; - - /// - /// Sound played on healing end - /// - [DataField("healingEndSound")] - public SoundSpecifier? HealingEndSound = null; - } -} diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index 8dd0330a27..1160f6aa17 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Administration.Logs; using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.EntitySystems; -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Medical.Components; using Content.Server.NodeContainer.EntitySystems; @@ -10,6 +9,7 @@ using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.Nodes; using Content.Server.Temperature.Components; using Content.Shared.Atmos; +using Content.Shared.Body.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; @@ -116,7 +116,7 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem } var solutionToInject = _solutionContainerSystem.SplitSolution(containerSolution.Value, cryoPod.BeakerTransferAmount); - _bloodstreamSystem.TryAddToChemicals(patient.Value, solutionToInject, bloodstream); + _bloodstreamSystem.TryAddToChemicals((patient.Value, bloodstream), solutionToInject); _reactiveSystem.DoEntityReaction(patient.Value, solutionToInject, ReactionMethod.Injection); } } diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index f2235363ad..11e4ed4fcf 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -1,8 +1,7 @@ -using Content.Server.Body.Components; using Content.Server.Medical.Components; using Content.Server.PowerCell; using Content.Server.Temperature.Components; -using Content.Shared.Traits.Assorted; +using Content.Shared.Body.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.DoAfter; @@ -14,6 +13,7 @@ using Content.Shared.Item.ItemToggle.Components; using Content.Shared.MedicalScanner; using Content.Shared.Mobs.Components; using Content.Shared.Popups; +using Content.Shared.Traits.Assorted; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index 9d27247a38..66cc9bf5f6 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics; diff --git a/Content.Server/Mind/TransferMindOnGibSystem.cs b/Content.Server/Mind/TransferMindOnGibSystem.cs index 758a23c868..ff71fa0560 100644 --- a/Content.Server/Mind/TransferMindOnGibSystem.cs +++ b/Content.Server/Mind/TransferMindOnGibSystem.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Server.Body.Components; +using Content.Shared.Body.Events; using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Tag; diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs index fa5ec0a1bf..5a269eace5 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs @@ -1,8 +1,8 @@ -using Content.Server.Body.Components; using Content.Server.DoAfter; using Content.Server.Explosion.EntitySystems; using Content.Server.Nutrition.Components; using Content.Server.Popups; +using Content.Shared.Body.Components; using Content.Shared.Atmos; using Content.Shared.Damage; using Content.Shared.DoAfter; diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index b3ef8bff69..4960ff1ba8 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -1,10 +1,9 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Shared.Chemistry.EntitySystems; using Content.Server.Forensics; +using Content.Shared.Body.Components; using Content.Shared.Chemistry; -using Content.Shared.Chemistry.Reagent; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; using Content.Shared.FixedPoint; @@ -17,7 +16,6 @@ using Content.Shared.Temperature; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using System.Linq; using Content.Shared.Atmos; namespace Content.Server.Nutrition.EntitySystems @@ -159,7 +157,7 @@ namespace Content.Server.Nutrition.EntitySystems } _reactiveSystem.DoEntityReaction(containerManager.Owner, inhaledSolution, ReactionMethod.Ingestion); - _bloodstreamSystem.TryAddToChemicals(containerManager.Owner, inhaledSolution, bloodstream); + _bloodstreamSystem.TryAddToChemicals((containerManager.Owner, bloodstream), inhaledSolution); } _timer -= UpdateTimer; diff --git a/Content.Server/Rootable/RootableSystem.cs b/Content.Server/Rootable/RootableSystem.cs index ce88f18dc3..cd18315bd0 100644 --- a/Content.Server/Rootable/RootableSystem.cs +++ b/Content.Server/Rootable/RootableSystem.cs @@ -1,6 +1,6 @@ -using Content.Server.Body.Components; -using Content.Server.Body.Systems; +using Content.Server.Body.Systems; using Content.Shared.Administration.Logs; +using Content.Shared.Body.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; @@ -12,6 +12,7 @@ using Robust.Shared.Timing; namespace Content.Server.Rootable; +// TODO: Move all of this to shared /// /// Adds an action to toggle rooting to the ground, primarily for the Diona species. /// @@ -68,7 +69,7 @@ public sealed class RootableSystem : SharedRootableSystem _reactive.DoEntityReaction(entity, transferSolution, ReactionMethod.Ingestion); - if (_blood.TryAddToChemicals(entity, transferSolution, entity.Comp2)) + if (_blood.TryAddToChemicals((entity, entity.Comp2), transferSolution)) { // Log solution addition by puddle _logger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity):target} absorbed puddle {SharedSolutionContainerSystem.ToPrettyString(transferSolution)}"); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 3957e02d2d..fd40aa8816 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -1,13 +1,12 @@ using Content.Server.Actions; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; -using Content.Server.Body.Components; +using Content.Shared.Body.Events; using Content.Server.DeviceNetwork.Systems; using Content.Server.Explosion.EntitySystems; using Content.Server.Hands.Systems; using Content.Server.PowerCell; using Content.Shared.Alert; -using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 03be40aad2..cf0dac30b2 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -13,6 +13,7 @@ using Content.Server.NPC.HTN; using Content.Server.NPC.Systems; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; +using Content.Shared.Body.Components; using Content.Shared.CombatMode; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage; diff --git a/Content.Shared/Body/Components/BloodstreamComponent.cs b/Content.Shared/Body/Components/BloodstreamComponent.cs new file mode 100644 index 0000000000..7997d92066 --- /dev/null +++ b/Content.Shared/Body/Components/BloodstreamComponent.cs @@ -0,0 +1,200 @@ +using Content.Shared.Alert; +using Content.Shared.Body.Systems; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.FixedPoint; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Body.Components; + +/// +/// Gives an entity a bloodstream. +/// +[RegisterComponent, NetworkedComponent,] +[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause] +[Access(typeof(SharedBloodstreamSystem))] +public sealed partial class BloodstreamComponent : Component +{ + public const string DefaultChemicalsSolutionName = "chemicals"; + public const string DefaultBloodSolutionName = "bloodstream"; + public const string DefaultBloodTemporarySolutionName = "bloodstreamTemporary"; + + /// + /// The next time that blood level will be updated and bloodloss damage dealt. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextUpdate; + + /// + /// The interval at which this component updates. + /// + [DataField, AutoNetworkedField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3); + + /// + /// How much is this entity currently bleeding? + /// Higher numbers mean more blood lost every tick. + /// + /// Goes down slowly over time, and items like bandages + /// or clotting reagents can lower bleeding. + /// + /// + /// This generally corresponds to an amount of damage and can't go above 100. + /// + [DataField, AutoNetworkedField] + public float BleedAmount; + + /// + /// How much should bleeding be reduced every update interval? + /// + [DataField, AutoNetworkedField] + public float BleedReductionAmount = 0.33f; + + /// + /// How high can go? + /// + [DataField, AutoNetworkedField] + public float MaxBleedAmount = 10.0f; + + /// + /// What percentage of current blood is necessary to avoid dealing blood loss damage? + /// + [DataField, AutoNetworkedField] + public float BloodlossThreshold = 0.9f; + + /// + /// The base bloodloss damage to be incurred if below + /// The default values are defined per mob/species in YML. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier BloodlossDamage = new(); + + /// + /// The base bloodloss damage to be healed if above + /// The default values are defined per mob/species in YML. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier BloodlossHealDamage = new(); + + // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. + /// + /// How much reagent of blood should be restored each update interval? + /// + [DataField, AutoNetworkedField] + public FixedPoint2 BloodRefreshAmount = 1.0f; + + /// + /// How much blood needs to be in the temporary solution in order to create a puddle? + /// + [DataField, AutoNetworkedField] + public FixedPoint2 BleedPuddleThreshold = 1.0f; + + /// + /// A modifier set prototype ID corresponding to how damage should be modified + /// before taking it into account for bloodloss. + /// + /// + /// For example, piercing damage is increased while poison damage is nullified entirely. + /// + [DataField, AutoNetworkedField] + public ProtoId DamageBleedModifiers = "BloodlossHuman"; + + /// + /// The sound to be played when a weapon instantly deals blood loss damage. + /// + [DataField, AutoNetworkedField] + public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood"); + + /// + /// The sound to be played when some damage actually heals bleeding rather than starting it. + /// + [DataField] + public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + /// + /// The minimum amount damage reduction needed to play the healing sound/popup. + /// This prevents tiny amounts of heat damage from spamming the sound, e.g. spacing. + /// + [DataField] + public float BloodHealedSoundThreshold = -0.1f; + + // TODO probably damage bleed thresholds. + + /// + /// Max volume of internal chemical solution storage + /// + [DataField] + public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250); + + /// + /// Max volume of internal blood storage, + /// and starting level of blood. + /// + [DataField] + public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300); + + /// + /// Which reagent is considered this entities 'blood'? + /// + /// + /// Slime-people might use slime as their blood or something like that. + /// + [DataField, AutoNetworkedField] + public ProtoId BloodReagent = "Blood"; + + /// + /// Name/Key that is indexed by. + /// + [DataField] + public string BloodSolutionName = DefaultBloodSolutionName; + + /// + /// Name/Key that is indexed by. + /// + [DataField] + public string ChemicalSolutionName = DefaultChemicalsSolutionName; + + /// + /// Name/Key that is indexed by. + /// + [DataField] + public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName; + + /// + /// Internal solution for blood storage + /// + [ViewVariables] + public Entity? BloodSolution; + + /// + /// Internal solution for reagent storage + /// + [ViewVariables] + public Entity? ChemicalSolution; + + /// + /// Temporary blood solution. + /// When blood is lost, it goes to this solution, and when this + /// solution hits a certain cap, the blood is actually spilled as a puddle. + /// + [ViewVariables] + public Entity? TemporarySolution; + + /// + /// Variable that stores the amount of status time added by having a low blood level. + /// + [DataField, AutoNetworkedField] + public TimeSpan StatusTime; + + /// + /// Alert to show when bleeding. + /// + [DataField] + public ProtoId BleedingAlert = "Bleed"; +} diff --git a/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs b/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs index dafc1e49de..1a7b589392 100644 --- a/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs +++ b/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Body.Events; +namespace Content.Shared.Body.Events; // TODO REFACTOR THIS // This will cause rates to slowly drift over time due to floating point errors. diff --git a/Content.Server/Body/Components/BeingGibbedEvent.cs b/Content.Shared/Body/Events/BeingGibbedEvent.cs similarity index 81% rename from Content.Server/Body/Components/BeingGibbedEvent.cs rename to Content.Shared/Body/Events/BeingGibbedEvent.cs index a010855f78..7ab34f2e18 100644 --- a/Content.Server/Body/Components/BeingGibbedEvent.cs +++ b/Content.Shared/Body/Events/BeingGibbedEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Body.Components; +namespace Content.Shared.Body.Events; /// /// Raised when a body gets gibbed, before it is deleted. diff --git a/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs new file mode 100644 index 0000000000..3b1674cf3c --- /dev/null +++ b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs @@ -0,0 +1,519 @@ +using Content.Shared.Alert; +using Content.Shared.Body.Components; +using Content.Shared.Body.Events; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage; +using Content.Shared.Drunk; +using Content.Shared.EntityEffects.Effects; +using Content.Shared.FixedPoint; +using Content.Shared.Fluids; +using Content.Shared.Forensics.Components; +using Content.Shared.HealthExaminable; +using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; +using Content.Shared.Rejuvenate; +using Content.Shared.Speech.EntitySystems; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared.Body.Systems; + +public abstract class SharedBloodstreamSystem : EntitySystem +{ + [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPuddleSystem _puddle = default!; + [Dependency] private readonly AlertsSystem _alertsSystem = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedDrunkSystem _drunkSystem = default!; + [Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnEntRemoved); + SubscribeLocalEvent(OnReactionAttempt); + SubscribeLocalEvent>(OnReactionAttempt); + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnHealthBeingExamined); + SubscribeLocalEvent(OnBeingGibbed); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); + SubscribeLocalEvent(OnRejuvenate); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var bloodstream)) + { + if (curTime < bloodstream.NextUpdate) + continue; + + bloodstream.NextUpdate += bloodstream.UpdateInterval; + DirtyField(uid, bloodstream, nameof(BloodstreamComponent.NextUpdate)); // needs to be dirtied on the client so it can be rerolled during prediction + + if (!SolutionContainer.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) + continue; + + // Adds blood to their blood level if it is below the maximum; Blood regeneration. Must be alive. + if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid)) + { + TryModifyBloodLevel((uid, bloodstream), bloodstream.BloodRefreshAmount); + } + + // Removes blood from the bloodstream based on bleed amount (bleed rate) + // as well as stop their bleeding to a certain extent. + if (bloodstream.BleedAmount > 0) + { + // Blood is removed from the bloodstream at a 1-1 rate with the bleed amount + TryModifyBloodLevel((uid, bloodstream), -bloodstream.BleedAmount); + // Bleed rate is reduced by the bleed reduction amount in the bloodstream component. + TryModifyBleedAmount((uid, bloodstream), -bloodstream.BleedReductionAmount); + } + + // deal bloodloss damage if their blood level is below a threshold. + var bloodPercentage = GetBloodLevelPercentage((uid, bloodstream)); + if (bloodPercentage < bloodstream.BloodlossThreshold && !_mobStateSystem.IsDead(uid)) + { + // bloodloss damage is based on the base value, and modified by how low your blood level is. + var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage); + + _damageableSystem.TryChangeDamage(uid, amt, + ignoreResistances: false, interruptsDoAfters: false); + + // Apply dizziness as a symptom of bloodloss. + // The effect is applied in a way that it will never be cleared without being healthy. + // Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out + _drunkSystem.TryApplyDrunkenness( + uid, + (float)bloodstream.UpdateInterval.TotalSeconds * 2, + applySlur: false); + _stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false); + + // storing the drunk and stutter time so we can remove it independently from other effects additions + bloodstream.StatusTime += bloodstream.UpdateInterval * 2; + DirtyField(uid, bloodstream, nameof(BloodstreamComponent.StatusTime)); + } + else if (!_mobStateSystem.IsDead(uid)) + { + // If they're healthy, we'll try and heal some bloodloss instead. + _damageableSystem.TryChangeDamage( + uid, + bloodstream.BloodlossHealDamage * bloodPercentage, + ignoreResistances: true, interruptsDoAfters: false); + + // Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level + _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds); + _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds); + // Reset the drunk and stutter time to zero + bloodstream.StatusTime = TimeSpan.Zero; + DirtyField(uid, bloodstream, nameof(BloodstreamComponent.StatusTime)); + } + } + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.UpdateInterval; + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.NextUpdate)); + } + + // prevent the infamous UdderSystem debug assert, see https://github.com/space-wizards/space-station-14/pull/35314 + // TODO: find a better solution than copy pasting this into every shared system that caches solution entities + private void OnEntRemoved(Entity entity, ref EntRemovedFromContainerMessage args) + { + // Make sure the removed entity was our contained solution and set it to null + if (args.Entity == entity.Comp.BloodSolution?.Owner) + entity.Comp.BloodSolution = null; + + if (args.Entity == entity.Comp.ChemicalSolution?.Owner) + entity.Comp.ChemicalSolution = null; + + if (args.Entity == entity.Comp.TemporarySolution?.Owner) + entity.Comp.TemporarySolution = null; + } + + private void OnReactionAttempt(Entity ent, ref ReactionAttemptEvent args) + { + if (args.Cancelled) + return; + + foreach (var effect in args.Reaction.Effects) + { + switch (effect) + { + case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream + case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels. + args.Cancelled = true; + return; + } + } + + // The area-reaction effect canceling is part of avoiding smoke-fork-bombs (create two smoke bombs, that when + // ingested by mobs create more smoke). This also used to act as a rapid chemical-purge, because all the + // reagents would get carried away by the smoke/foam. This does still work for the stomach (I guess people vomit + // up the smoke or spawned entities?). + + // TODO apply organ damage instead of just blocking the reaction? + // Having cheese-clots form in your veins can't be good for you. + } + + private void OnReactionAttempt(Entity ent, ref SolutionRelayEvent args) + { + if (args.Name != ent.Comp.BloodSolutionName + && args.Name != ent.Comp.ChemicalSolutionName + && args.Name != ent.Comp.BloodTemporarySolutionName) + { + return; + } + + OnReactionAttempt(ent, ref args.Event); + } + + private void OnDamageChanged(Entity ent, ref DamageChangedEvent args) + { + // The incoming state from the server raises a DamageChangedEvent as well. + // But the changes to the bloodstream have also been dirtied, + // so we prevent applying them twice. + if (_timing.ApplyingState) + return; + + if (args.DamageDelta is null || !args.DamageIncreased) + { + return; + } + + // TODO probably cache this or something. humans get hurt a lot + if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers)) + return; + + // some reagents may deal and heal different damage types in the same tick, which means DamageIncreased will be true + // but we only want to consider the dealt damage when causing bleeding + var damage = DamageSpecifier.GetPositive(args.DamageDelta); + var bloodloss = DamageSpecifier.ApplyModifierSet(damage, modifiers); + + if (bloodloss.Empty) + return; + + // Does the calculation of how much bleed rate should be added/removed, then applies it + var oldBleedAmount = ent.Comp.BleedAmount; + var total = bloodloss.GetTotal(); + var totalFloat = total.Float(); + TryModifyBleedAmount(ent.AsNullable(), totalFloat); + + /// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5 + /// The crit chance is currently the bleed rate modifier divided by 25. + /// Higher damage weapons have a higher chance to crit! + + // TODO: Replace with RandomPredicted once the engine PR is merged + // Use both the receiver and the damage causing entity for the seed so that we have different results for multiple attacks in the same tick + var seed = HashCode.Combine((int)_timing.CurTick.Value, GetNetEntity(ent).Id, GetNetEntity(args.Origin)?.Id ?? 0); + var rand = new System.Random(seed); + var prob = Math.Clamp(totalFloat / 25, 0, 1); + if (totalFloat > 0 && rand.Prob(prob)) + { + TryModifyBloodLevel(ent.AsNullable(), -total / 5); + _audio.PlayPredicted(ent.Comp.InstantBloodSound, ent, args.Origin); + } + + // Heat damage will cauterize, causing the bleed rate to be reduced. + else if (totalFloat <= ent.Comp.BloodHealedSoundThreshold && oldBleedAmount > 0) + { + // Magically, this damage has healed some bleeding, likely + // because it's burn damage that cauterized their wounds. + + // We'll play a special sound and popup for feedback. + _popup.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent, + ent, PopupType.Medium); // only the burned entity can see this + _audio.PlayPredicted(ent.Comp.BloodHealedSound, ent, args.Origin); + } + } + + /// + /// Shows text on health examine, based on bleed rate and blood level. + /// + private void OnHealthBeingExamined(Entity ent, ref HealthBeingExaminedEvent args) + { + // Shows massively bleeding at 0.75x the max bleed rate. + if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.75f) + { + args.Message.PushNewline(); + args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-massive-bleeding", ("target", ent.Owner))); + } + // Shows bleeding message when bleeding above half the max rate, but less than massively. + else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.5f) + { + args.Message.PushNewline(); + args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-strong-bleeding", ("target", ent.Owner))); + } + // Shows bleeding message when bleeding above 0.25x the max rate, but less than half the max. + else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.25f) + { + args.Message.PushNewline(); + args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-bleeding", ("target", ent.Owner))); + } + // Shows bleeding message when bleeding below 0.25x the max cap + else if (ent.Comp.BleedAmount > 0) + { + args.Message.PushNewline(); + args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-slight-bleeding", ("target", ent.Owner))); + } + + // If the mob's blood level is below the damage threshhold, the pale message is added. + if (GetBloodLevelPercentage(ent.AsNullable()) < ent.Comp.BloodlossThreshold) + { + args.Message.PushNewline(); + args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-looks-pale", ("target", ent.Owner))); + } + } + + private void OnBeingGibbed(Entity ent, ref BeingGibbedEvent args) + { + SpillAllSolutions(ent.AsNullable()); + } + + private void OnApplyMetabolicMultiplier(Entity ent, ref ApplyMetabolicMultiplierEvent args) + { + // TODO REFACTOR THIS + // This will slowly drift over time due to floating point errors. + // Instead, raise an event with the base rates and allow modifiers to get applied to it. + if (args.Apply) + ent.Comp.UpdateInterval *= args.Multiplier; + else + ent.Comp.UpdateInterval /= args.Multiplier; + + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.UpdateInterval)); + } + + private void OnRejuvenate(Entity ent, ref RejuvenateEvent args) + { + TryModifyBleedAmount(ent.AsNullable(), -ent.Comp.BleedAmount); + + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodSolutionName, ref ent.Comp.BloodSolution, out var bloodSolution)) + TryModifyBloodLevel(ent.AsNullable(), bloodSolution.AvailableVolume); + + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.ChemicalSolutionName, ref ent.Comp.ChemicalSolution)) + SolutionContainer.RemoveAllSolution(ent.Comp.ChemicalSolution.Value); + } + + /// + /// Returns the current blood level as a percentage (between 0 and 1). + /// + public float GetBloodLevelPercentage(Entity ent) + { + if (!Resolve(ent, ref ent.Comp) + || !SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodSolutionName, ref ent.Comp.BloodSolution, out var bloodSolution)) + { + return 0.0f; + } + + return bloodSolution.FillFraction; + } + + /// + /// Setter for the BloodlossThreshold datafield. + /// + public void SetBloodLossThreshold(Entity ent, float threshold) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + ent.Comp.BloodlossThreshold = threshold; + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.BloodlossThreshold)); + } + + /// + /// Attempt to transfer a provided solution to internal solution. + /// + public bool TryAddToChemicals(Entity ent, Solution solution) + { + if (!Resolve(ent, ref ent.Comp, logMissing: false) + || !SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.ChemicalSolutionName, ref ent.Comp.ChemicalSolution)) + return false; + + if (SolutionContainer.TryAddSolution(ent.Comp.ChemicalSolution.Value, solution)) + return true; + + return false; + } + + /// + /// Removes a certain amount of all reagents except of a single excluded one from the bloodstream. + /// + public bool FlushChemicals(Entity ent, ProtoId? excludedReagentID, FixedPoint2 quantity) + { + if (!Resolve(ent, ref ent.Comp, logMissing: false) + || !SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.ChemicalSolutionName, ref ent.Comp.ChemicalSolution, out var chemSolution)) + return false; + + for (var i = chemSolution.Contents.Count - 1; i >= 0; i--) + { + var (reagentId, _) = chemSolution.Contents[i]; + if (reagentId.Prototype != excludedReagentID) + { + SolutionContainer.RemoveReagent(ent.Comp.ChemicalSolution.Value, reagentId, quantity); + } + } + + return true; + } + + /// + /// Attempts to modify the blood level of this entity directly. + /// + public bool TryModifyBloodLevel(Entity ent, FixedPoint2 amount) + { + if (!Resolve(ent, ref ent.Comp, logMissing: false) + || !SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodSolutionName, ref ent.Comp.BloodSolution)) + return false; + + if (amount >= 0) + return SolutionContainer.TryAddReagent(ent.Comp.BloodSolution.Value, ent.Comp.BloodReagent, amount, null, GetEntityBloodData(ent)); + + // Removal is more involved, + // since we also wanna handle moving it to the temporary solution + // and then spilling it if necessary. + var newSol = SolutionContainer.SplitSolution(ent.Comp.BloodSolution.Value, -amount); + + if (!SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodTemporarySolutionName, ref ent.Comp.TemporarySolution, out var tempSolution)) + return true; + + tempSolution.AddSolution(newSol, _prototypeManager); + + if (tempSolution.Volume > ent.Comp.BleedPuddleThreshold) + { + // Pass some of the chemstream into the spilled blood. + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.ChemicalSolutionName, ref ent.Comp.ChemicalSolution)) + { + var temp = SolutionContainer.SplitSolution(ent.Comp.ChemicalSolution.Value, tempSolution.Volume / 10); + tempSolution.AddSolution(temp, _prototypeManager); + } + + _puddle.TrySpillAt(ent.Owner, tempSolution, out _, sound: false); + + tempSolution.RemoveAllSolution(); + } + + SolutionContainer.UpdateChemicals(ent.Comp.TemporarySolution.Value); + + return true; + } + + /// + /// Tries to make an entity bleed more or less. + /// + public bool TryModifyBleedAmount(Entity ent, float amount) + { + if (!Resolve(ent, ref ent.Comp, logMissing: false)) + return false; + + ent.Comp.BleedAmount += amount; + ent.Comp.BleedAmount = Math.Clamp(ent.Comp.BleedAmount, 0, ent.Comp.MaxBleedAmount); + + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.BleedAmount)); + + if (ent.Comp.BleedAmount == 0) + _alertsSystem.ClearAlert(ent, ent.Comp.BleedingAlert); + else + { + var severity = (short)Math.Clamp(Math.Round(ent.Comp.BleedAmount, MidpointRounding.ToZero), 0, 10); + _alertsSystem.ShowAlert(ent, ent.Comp.BleedingAlert, severity); + } + + return true; + } + + /// + /// Spill all bloodstream solutions into a puddle. + /// BLOOD FOR THE BLOOD GOD + /// + public void SpillAllSolutions(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + var tempSol = new Solution(); + + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodSolutionName, ref ent.Comp.BloodSolution, out var bloodSolution)) + { + tempSol.MaxVolume += bloodSolution.MaxVolume; + tempSol.AddSolution(bloodSolution, _prototypeManager); + SolutionContainer.RemoveAllSolution(ent.Comp.BloodSolution.Value); + } + + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.ChemicalSolutionName, ref ent.Comp.ChemicalSolution, out var chemSolution)) + { + tempSol.MaxVolume += chemSolution.MaxVolume; + tempSol.AddSolution(chemSolution, _prototypeManager); + SolutionContainer.RemoveAllSolution(ent.Comp.ChemicalSolution.Value); + } + + if (SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodTemporarySolutionName, ref ent.Comp.TemporarySolution, out var tempSolution)) + { + tempSol.MaxVolume += tempSolution.MaxVolume; + tempSol.AddSolution(tempSolution, _prototypeManager); + SolutionContainer.RemoveAllSolution(ent.Comp.TemporarySolution.Value); + } + + _puddle.TrySpillAt(ent, tempSol, out _); + } + + /// + /// Change what someone's blood is made of, on the fly. + /// + public void ChangeBloodReagent(Entity ent, ProtoId reagent) + { + if (!Resolve(ent, ref ent.Comp, logMissing: false) + || reagent == ent.Comp.BloodReagent) + { + return; + } + + if (!SolutionContainer.ResolveSolution(ent.Owner, ent.Comp.BloodSolutionName, ref ent.Comp.BloodSolution, out var bloodSolution)) + { + ent.Comp.BloodReagent = reagent; + return; + } + + var currentVolume = bloodSolution.RemoveReagent(ent.Comp.BloodReagent, bloodSolution.Volume, ignoreReagentData: true); + + ent.Comp.BloodReagent = reagent; + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.BloodReagent)); + + if (currentVolume > 0) + SolutionContainer.TryAddReagent(ent.Comp.BloodSolution.Value, ent.Comp.BloodReagent, currentVolume, null, GetEntityBloodData(ent)); + } + + /// + /// Get the reagent data for blood that a specific entity should have. + /// + public List GetEntityBloodData(EntityUid uid) + { + var bloodData = new List(); + var dnaData = new DnaData(); + + if (TryComp(uid, out var donorComp) && donorComp.DNA != null) + dnaData.DNA = donorComp.DNA; + else + dnaData.DNA = Loc.GetString("forensics-dna-unknown"); + + bloodData.Add(dnaData); + + return bloodData; + } +} diff --git a/Content.Shared/Body/Systems/StomachSystem.cs b/Content.Shared/Body/Systems/StomachSystem.cs index 8b2df453a0..d0ecb6b93b 100644 --- a/Content.Shared/Body/Systems/StomachSystem.cs +++ b/Content.Shared/Body/Systems/StomachSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Body.Components; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; +using Content.Shared.Body.Events; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; diff --git a/Content.Shared/Chemistry/EntitySystems/HypospraySystem.cs b/Content.Shared/Chemistry/EntitySystems/HypospraySystem.cs index 86f6edc903..34bc44f1cb 100644 --- a/Content.Shared/Chemistry/EntitySystems/HypospraySystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/HypospraySystem.cs @@ -1,6 +1,8 @@ using Content.Shared.Administration.Logs; -using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Body.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.Hypospray.Events; using Content.Shared.Database; using Content.Shared.FixedPoint; diff --git a/Content.Shared/Damage/DamageSpecifier.cs b/Content.Shared/Damage/DamageSpecifier.cs index 51472a56bd..00bd416e1f 100644 --- a/Content.Shared/Damage/DamageSpecifier.cs +++ b/Content.Shared/Damage/DamageSpecifier.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Text.Json.Serialization; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; @@ -77,6 +78,11 @@ namespace Content.Shared.Damage [JsonIgnore] public bool Empty => DamageDict.Count == 0; + public override string ToString() + { + return "DamageSpecifier(" + string.Join("; ", DamageDict.Select(x => x.Key + ":" + x.Value)) + ")"; + } + #region constructors /// /// Constructor that just results in an empty dictionary. diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 31426f6bd0..70fbc46806 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -353,7 +353,7 @@ namespace Content.Shared.Damage // Has the damage actually changed? DamageSpecifier newDamage = new() { DamageDict = new(state.DamageDict) }; - var delta = component.Damage - newDamage; + var delta = newDamage - component.Damage; delta.TrimZeros(); if (!delta.Empty) diff --git a/Content.Shared/Medical/Healing/HealingComponent.cs b/Content.Shared/Medical/Healing/HealingComponent.cs new file mode 100644 index 0000000000..53358fd28d --- /dev/null +++ b/Content.Shared/Medical/Healing/HealingComponent.cs @@ -0,0 +1,65 @@ +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Medical.Healing; + +/// +/// Applies a damage change to the target when used in an interaction. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class HealingComponent : Component +{ + /// + /// The amount of damage to heal per use. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// This should generally be negative, + /// since you're, like, trying to heal damage. + /// + [DataField, AutoNetworkedField] + public float BloodlossModifier = 0.0f; + + /// + /// Restore missing blood. + /// + [DataField, AutoNetworkedField] + public float ModifyBloodLevel = 0.0f; + + /// + /// The supported damage types are specified using a s. For a + /// HealingComponent this filters what damage container type this component should work on. If null, + /// all damage container types are supported. + /// + [DataField, AutoNetworkedField] + public List>? DamageContainers; + + /// + /// How long it takes to apply the damage. + /// + [DataField, AutoNetworkedField] + public float Delay = 3f; + + /// + /// Delay multiplier when healing yourself. + /// + [DataField, AutoNetworkedField] + public float SelfHealPenaltyMultiplier = 3f; + + /// + /// Sound played on healing begin. + /// + [DataField] + public SoundSpecifier? HealingBeginSound = null; + + /// + /// Sound played on healing end. + /// + [DataField] + public SoundSpecifier? HealingEndSound = null; +} diff --git a/Content.Server/Medical/HealingSystem.cs b/Content.Shared/Medical/Healing/HealingSystem.cs similarity index 54% rename from Content.Server/Medical/HealingSystem.cs rename to Content.Shared/Medical/Healing/HealingSystem.cs index c18f29d2fb..74cb8881f4 100644 --- a/Content.Server/Medical/HealingSystem.cs +++ b/Content.Shared/Medical/Healing/HealingSystem.cs @@ -1,9 +1,6 @@ -using Content.Server.Administration.Logs; -using Content.Server.Body.Components; -using Content.Server.Body.Systems; -using Content.Server.Medical.Components; -using Content.Server.Popups; -using Content.Server.Stack; +using Content.Shared.Administration.Logs; +using Content.Shared.Body.Components; +using Content.Shared.Body.Systems; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Database; @@ -12,77 +9,74 @@ using Content.Shared.FixedPoint; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; -using Content.Shared.Medical; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Stacks; using Robust.Shared.Audio.Systems; -using Robust.Shared.Random; -using Robust.Shared.Audio; -namespace Content.Server.Medical; +namespace Content.Shared.Medical.Healing; public sealed class HealingSystem : EntitySystem { [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly SharedBloodstreamSystem _bloodstreamSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; - [Dependency] private readonly StackSystem _stacks = default!; + [Dependency] private readonly SharedStackSystem _stacks = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnHealingUse); SubscribeLocalEvent(OnHealingAfterInteract); SubscribeLocalEvent(OnDoAfter); } - private void OnDoAfter(Entity entity, ref HealingDoAfterEvent args) + private void OnDoAfter(Entity target, ref HealingDoAfterEvent args) { - var dontRepeat = false; - - if (!TryComp(args.Used, out HealingComponent? healing)) - return; if (args.Handled || args.Cancelled) return; + if (!TryComp(args.Used, out HealingComponent? healing)) + return; + if (healing.DamageContainers is not null && - entity.Comp.DamageContainerID is not null && - !healing.DamageContainers.Contains(entity.Comp.DamageContainerID)) + target.Comp.DamageContainerID is not null && + !healing.DamageContainers.Contains(target.Comp.DamageContainerID.Value)) { return; } + TryComp(target, out var bloodstream); + // Heal some bloodloss damage. - if (healing.BloodlossModifier != 0) + if (healing.BloodlossModifier != 0 && bloodstream != null) { - if (!TryComp(entity, out var bloodstream)) - return; var isBleeding = bloodstream.BleedAmount > 0; - _bloodstreamSystem.TryModifyBleedAmount(entity.Owner, healing.BloodlossModifier); + _bloodstreamSystem.TryModifyBleedAmount((target.Owner, bloodstream), healing.BloodlossModifier); if (isBleeding != bloodstream.BleedAmount > 0) { - var popup = (args.User == entity.Owner) + var popup = (args.User == target.Owner) ? Loc.GetString("medical-item-stop-bleeding-self") - : Loc.GetString("medical-item-stop-bleeding", ("target", Identity.Entity(entity.Owner, EntityManager))); - _popupSystem.PopupEntity(popup, entity, args.User); + : Loc.GetString("medical-item-stop-bleeding", ("target", Identity.Entity(target.Owner, EntityManager))); + _popupSystem.PopupClient(popup, target, args.User); } } // Restores missing blood - if (healing.ModifyBloodLevel != 0) - _bloodstreamSystem.TryModifyBloodLevel(entity.Owner, healing.ModifyBloodLevel); + if (healing.ModifyBloodLevel != 0 && bloodstream != null) + _bloodstreamSystem.TryModifyBloodLevel((target.Owner, bloodstream), healing.ModifyBloodLevel); - var healed = _damageable.TryChangeDamage(entity.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, true, origin: args.Args.User); + var healed = _damageable.TryChangeDamage(target.Owner, healing.Damage * _damageable.UniversalTopicalsHealModifier, true, origin: args.Args.User); if (healed == null && healing.BloodlossModifier != 0) return; @@ -90,7 +84,7 @@ public sealed class HealingSystem : EntitySystem var total = healed?.GetTotal() ?? FixedPoint2.Zero; // Re-verify that we can heal the damage. - + var dontRepeat = false; if (TryComp(args.Used.Value, out var stackComp)) { _stacks.Use(args.Used.Value, 1, stackComp); @@ -100,13 +94,13 @@ public sealed class HealingSystem : EntitySystem } else { - QueueDel(args.Used.Value); + PredictedQueueDel(args.Used.Value); } - if (entity.Owner != args.User) + if (target.Owner != args.User) { _adminLogger.Add(LogType.Healed, - $"{ToPrettyString(args.User):user} healed {ToPrettyString(entity.Owner):target} for {total:damage} damage"); + $"{ToPrettyString(args.User):user} healed {ToPrettyString(target.Owner):target} for {total:damage} damage"); } else { @@ -114,19 +108,19 @@ public sealed class HealingSystem : EntitySystem $"{ToPrettyString(args.User):user} healed themselves for {total:damage} damage"); } - _audio.PlayPvs(healing.HealingEndSound, entity.Owner); + _audio.PlayPredicted(healing.HealingEndSound, target.Owner, args.User); // Logic to determine the whether or not to repeat the healing action - args.Repeat = (HasDamage(entity, healing) && !dontRepeat); + args.Repeat = HasDamage((args.Used.Value, healing), target) && !dontRepeat; if (!args.Repeat && !dontRepeat) - _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), entity.Owner, args.User); + _popupSystem.PopupClient(Loc.GetString("medical-item-finished-using", ("item", args.Used)), target.Owner, args.User); args.Handled = true; } - private bool HasDamage(Entity ent, HealingComponent healing) + private bool HasDamage(Entity healing, Entity target) { - var damageableDict = ent.Comp.Damage.DamageDict; - var healingDict = healing.Damage.DamageDict; + var damageableDict = target.Comp.Damage.DamageDict; + var healingDict = healing.Comp.Damage.DamageDict; foreach (var type in healingDict) { if (damageableDict[type.Key].Value > 0) @@ -135,18 +129,18 @@ public sealed class HealingSystem : EntitySystem } } - if (TryComp(ent, out var bloodstream)) + if (TryComp(target, out var bloodstream)) { // Is ent missing blood that we can restore? - if (healing.ModifyBloodLevel > 0 - && _solutionContainerSystem.ResolveSolution(ent.Owner, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) + if (healing.Comp.ModifyBloodLevel > 0 + && _solutionContainerSystem.ResolveSolution(target.Owner, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution) && bloodSolution.Volume < bloodSolution.MaxVolume) { return true; } // Is ent bleeding and can we stop it? - if (healing.BloodlossModifier < 0 && bloodstream.BleedAmount > 0) + if (healing.Comp.BloodlossModifier < 0 && bloodstream.BleedAmount > 0) { return true; } @@ -155,64 +149,64 @@ public sealed class HealingSystem : EntitySystem return false; } - private void OnHealingUse(Entity entity, ref UseInHandEvent args) + private void OnHealingUse(Entity healing, ref UseInHandEvent args) { if (args.Handled) return; - if (TryHeal(entity, args.User, args.User, entity.Comp)) + if (TryHeal(healing, args.User, args.User)) args.Handled = true; } - private void OnHealingAfterInteract(Entity entity, ref AfterInteractEvent args) + private void OnHealingAfterInteract(Entity healing, ref AfterInteractEvent args) { if (args.Handled || !args.CanReach || args.Target == null) return; - if (TryHeal(entity, args.User, args.Target.Value, entity.Comp)) + if (TryHeal(healing, args.Target.Value, args.User)) args.Handled = true; } - private bool TryHeal(EntityUid uid, EntityUid user, EntityUid target, HealingComponent component) + private bool TryHeal(Entity healing, Entity target, EntityUid user) { - if (!TryComp(target, out var targetDamage)) + if (!Resolve(target, ref target.Comp, false)) return false; - if (component.DamageContainers is not null && - targetDamage.DamageContainerID is not null && - !component.DamageContainers.Contains(targetDamage.DamageContainerID)) + if (healing.Comp.DamageContainers is not null && + target.Comp.DamageContainerID is not null && + !healing.Comp.DamageContainers.Contains(target.Comp.DamageContainerID.Value)) { return false; } - if (user != target && !_interactionSystem.InRangeUnobstructed(user, target, popup: true)) + if (user != target.Owner && !_interactionSystem.InRangeUnobstructed(user, target.Owner, popup: true)) return false; - if (TryComp(uid, out var stack) && stack.Count < 1) + if (TryComp(healing, out var stack) && stack.Count < 1) return false; - if (!HasDamage((target, targetDamage), component)) + if (!HasDamage(healing, target!)) { - _popupSystem.PopupEntity(Loc.GetString("medical-item-cant-use", ("item", uid)), uid, user); + _popupSystem.PopupClient(Loc.GetString("medical-item-cant-use", ("item", healing.Owner)), healing, user); return false; } - _audio.PlayPvs(component.HealingBeginSound, uid); + _audio.PlayPredicted(healing.Comp.HealingBeginSound, healing, user); - var isNotSelf = user != target; + var isNotSelf = user != target.Owner; if (isNotSelf) { - var msg = Loc.GetString("medical-item-popup-target", ("user", Identity.Entity(user, EntityManager)), ("item", uid)); + var msg = Loc.GetString("medical-item-popup-target", ("user", Identity.Entity(user, EntityManager)), ("item", healing.Owner)); _popupSystem.PopupEntity(msg, target, target, PopupType.Medium); } var delay = isNotSelf - ? component.Delay - : component.Delay * GetScaledHealingPenalty(user, component); + ? healing.Comp.Delay + : healing.Comp.Delay * GetScaledHealingPenalty(healing); var doAfterEventArgs = - new DoAfterArgs(EntityManager, user, delay, new HealingDoAfterEvent(), target, target: target, used: uid) + new DoAfterArgs(EntityManager, user, delay, new HealingDoAfterEvent(), target, target: target, used: healing) { // Didn't break on damage as they may be trying to prevent it and // not being able to heal your own ticking damage would be frustrating. @@ -231,18 +225,18 @@ public sealed class HealingSystem : EntitySystem /// /// /// - public float GetScaledHealingPenalty(EntityUid uid, HealingComponent component) + public float GetScaledHealingPenalty(Entity healing) { - var output = component.Delay; - if (!TryComp(uid, out var mobThreshold) || - !TryComp(uid, out var damageable)) + var output = healing.Comp.Delay; + if (!TryComp(healing, out var mobThreshold) || + !TryComp(healing, out var damageable)) return output; - if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var amount, mobThreshold)) + if (!_mobThresholdSystem.TryGetThresholdForState(healing, MobState.Critical, out var amount, mobThreshold)) return 1; - var percentDamage = (float) (damageable.TotalDamage / amount); + var percentDamage = (float)(damageable.TotalDamage / amount); //basically make it scale from 1 to the multiplier. - var modifier = percentDamage * (component.SelfHealPenaltyMultiplier - 1) + 1; + var modifier = percentDamage * (healing.Comp.SelfHealPenaltyMultiplier - 1) + 1; return Math.Max(modifier, 1); } } diff --git a/Resources/Locale/en-US/medical/components/healing-component.ftl b/Resources/Locale/en-US/medical/components/healing-component.ftl index 20ad23dcb2..d206150a0e 100644 --- a/Resources/Locale/en-US/medical/components/healing-component.ftl +++ b/Resources/Locale/en-US/medical/components/healing-component.ftl @@ -1,5 +1,5 @@ -medical-item-finished-using = You have finished healing with the {$item} -medical-item-cant-use = There is no damage you can heal with the {$item} -medical-item-stop-bleeding = {CAPITALIZE($target)} has stopped bleeding -medical-item-stop-bleeding-self = You have stopped bleeding +medical-item-finished-using = You have finished healing with the {$item}. +medical-item-cant-use = There is no damage you can heal with the {$item}. +medical-item-stop-bleeding = {CAPITALIZE($target)} has stopped bleeding. +medical-item-stop-bleeding-self = You have stopped bleeding. medical-item-popup-target = {CAPITALIZE(THE($user))} is trying to heal you with the {$item}! diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml index 98565931fd..4a05817646 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healing.yml @@ -257,7 +257,7 @@ damage: types: Bloodloss: -0.5 #lowers bloodloss damage - ModifyBloodLevel: 15 #restores about 5% blood per use on standard humanoids. + modifyBloodLevel: 15 #restores about 5% blood per use on standard humanoids. healingBeginSound: path: "/Audio/Items/Medical/brutepack_begin.ogg" params: From 70ed8835c64369f8ea7925ddbd53dd9e37c48d50 Mon Sep 17 00:00:00 2001 From: LaCumbiaDelCoronavirus <90893484+LaCumbiaDelCoronavirus@users.noreply.github.com> Date: Thu, 3 Jul 2025 08:27:56 +0800 Subject: [PATCH 025/105] make telesci wreck easier (#37569) rel --- .../Maps/Ruins/displaced_telescience.yml | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/Resources/Maps/Ruins/displaced_telescience.yml b/Resources/Maps/Ruins/displaced_telescience.yml index 47b13089d7..b5c2690275 100644 --- a/Resources/Maps/Ruins/displaced_telescience.yml +++ b/Resources/Maps/Ruins/displaced_telescience.yml @@ -1,11 +1,11 @@ meta: format: 7 category: Grid - engineVersion: 255.0.0 + engineVersion: 260.0.0 forkId: "" forkVersion: "" - time: 04/30/2025 11:12:40 - entityCount: 485 + time: 05/18/2025 11:12:07 + entityCount: 487 maps: [] grids: - 1 @@ -33,20 +33,20 @@ entities: chunks: 0,0: ind: 0,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAABAAAAAAAAAQAAAAAAAAIAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAQAAAAAAAAMAAAAAAAACAAAAAAAAAwAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: AwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAABAAAAAAABAAAAAAAAQAAAAAAAQAAAAAABAAAAAAABAAAAAAABAAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAAAgAAAAAAAgAAAAAABAAAAAAAAQAAAAAABAAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAABAAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAABAAAAAAABAAAAAAABAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAA - version: 6 + tiles: AwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAADAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAgAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAQAAAAAAAAEAAAAAAAAAQAAAAAAAAEAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAABAAAAAAAAAgAAAAAAAAIAAAAAAAABAAAAAAAABAAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAgAAAAAAAAIAAAAAAAAEAAAAAAAAAQAAAAAAAAQAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAEAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAgAAAAAAAAIAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAgAAAAAAAAEAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAEAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAIAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAQAAAAAAAgAAAAAABQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAABAAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAABAAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAA - version: 6 + tiles: AwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAEAAAAAAAACAAAAAAAABQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAQAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAIAAAAAAAABAAAAAAAAAgAAAAAAAAIAAAAAAAABAAAAAAAAAQAAAAAAAAQAAAAAAAAEAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAQAAAAAAAAIAAAAAAAACAAAAAAAAAQAAAAAAAAEAAAAAAAAEAAAAAAAABAAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAEAAAAAAAACAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAABAAAAAAAAAgAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAEAAAAAAAACAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAABQAAAAAABQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAA - version: 6 + tiles: AwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAQAAAAAAAAIAAAAAAAABAAAAAAAAAQAAAAAAAAUAAAAAAAAFAAAAAAAAAQAAAAAAAAEAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAACAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAMAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAQAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAIAAAAAAAACAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAACAAAAAAAABAAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAgAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAAMAAAAAAAADAAAAAAAAAwAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -59,6 +59,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -1756,6 +1757,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - uid: 476 mapInit: true paused: true @@ -1843,7 +1845,7 @@ entities: pos: -1.5,-7.5 parent: 1 - type: Door - secondsUntilStateChange: -5362.1104 + secondsUntilStateChange: -5774.7476 state: Opening - type: DeviceLinkSource lastSignals: @@ -4425,6 +4427,14 @@ entities: rot: 3.141592653589793 rad pos: 1.5,-8.5 parent: 1 +- proto: PoweredSmallLightEmpty + entities: + - uid: 486 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,-1.5 + parent: 1 - proto: PoweredStrobeLightEmpty entities: - uid: 178 @@ -4472,6 +4482,12 @@ entities: rot: -1.5707963267948966 rad pos: -5.5,0.5 parent: 1 + - uid: 487 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,-5.5 + parent: 1 - proto: Railing entities: - uid: 362 From aded799ae500c9e1e6fec5b4eebb3a5d401c10e2 Mon Sep 17 00:00:00 2001 From: Alzore <140123969+Blackern5000@users.noreply.github.com> Date: Wed, 2 Jul 2025 19:54:02 -0500 Subject: [PATCH 026/105] Reduce most salvage mob health, reduce most salvage weapon damage. (#38131) --- .../Entities/Mobs/NPCs/asteroid.yml | 4 +-- .../Prototypes/Entities/Mobs/NPCs/carp.yml | 6 +++- .../Prototypes/Entities/Mobs/NPCs/space.yml | 10 ++++-- .../Entities/Mobs/NPCs/spacetick.yml | 2 +- .../Weapons/Guns/Projectiles/projectiles.yml | 21 +++++++++-- .../Entities/Objects/Weapons/Melee/mining.yml | 36 ++++++++++++++----- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml b/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml index de8f15f4c0..941091335a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/asteroid.yml @@ -57,7 +57,7 @@ - type: MobThresholds thresholds: 0: Alive - 250: Dead + 150: Dead - type: MeleeWeapon soundHit: path: "/Audio/Weapons/smash.ogg" @@ -378,7 +378,7 @@ - type: MobThresholds thresholds: 0: Alive - 75: Dead + 45: Dead - type: MeleeWeapon angle: 0 animation: WeaponArcBite diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index 8db27e19c5..971f5e1dc6 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -156,6 +156,10 @@ suffix: "Salvage Ruleset" components: - type: SalvageMobRestrictions + - type: MobThresholds + thresholds: + 0: Alive + 30: Dead - type: entity name: space carp @@ -222,7 +226,7 @@ - type: MobThresholds thresholds: 0: Alive - 150: Dead + 82: Dead # Might seem random, but this brings up the hits to kill with a crusher mark to 3 - type: Stamina critThreshold: 150 - type: DamageStateVisuals diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml index 2bd0de128b..039cac3358 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml @@ -34,7 +34,7 @@ - type: MobThresholds thresholds: 0: Alive - 100: Dead + 80: Dead - type: Stamina critThreshold: 150 - type: MovementAlwaysTouching @@ -168,6 +168,10 @@ spawned: - id: FoodMeat amount: 1 + - type: MobThresholds + thresholds: + 0: Alive + 60: Dead - type: entity id: MobKangarooSpaceSalvage @@ -194,7 +198,7 @@ - type: MobThresholds thresholds: 0: Alive - 90: Dead + 45: Dead - type: Stamina critThreshold: 150 - type: DamageStateVisuals @@ -295,7 +299,7 @@ - type: MobThresholds thresholds: 0: Alive - 100: Dead + 45: Dead - type: Stamina critThreshold: 150 - type: DamageStateVisuals diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml index 92b27c7a4c..2eaf7c819f 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml @@ -41,7 +41,7 @@ - type: MobThresholds thresholds: 0: Alive - 15: Dead + 5: Dead - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index 712be28de3..7c94dd65cc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -496,7 +496,7 @@ impactEffect: BulletImpactEffectKinetic damage: types: - Blunt: 25 + Blunt: 15 Structural: 30 # Short lifespan - type: TimedDespawn @@ -553,8 +553,8 @@ - MobState damage: types: - Blunt: 20 - Slash: 5 + Blunt: 18 + Slash: 4 - type: Projectile impactEffect: BulletImpactEffectKinetic damage: @@ -564,6 +564,21 @@ - type: TimedDespawn lifetime: 0.4 + # Deals less damage, glaive has better HP recovery +- type: entity + id: BulletChargeGlaive + name: leech bolt + parent: BulletCharge + components: + - type: DamageMarkerOnCollide + whitelist: + components: + - MobState + damage: + types: + Blunt: 1 + Slash: 5 + - type: entity parent: BaseBullet id: AnomalousParticleDelta diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml index 8cbf2530ec..3ed57e0495 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/mining.yml @@ -106,6 +106,7 @@ enabled: false radius: 4 +# Very high burst damage if you land a mark, while also providing a small amount of healing. - type: entity parent: [BaseWeaponCrusher, BaseSecurityCargoContraband] id: WeaponCrusher @@ -132,7 +133,7 @@ - type: LeechOnMarker leech: groups: - Brute: -10 + Brute: -6 - type: Gun soundGunshot: /Audio/Weapons/plasma_cutter.ogg fireRate: 1 @@ -146,25 +147,26 @@ capacity: 1 count: 1 - type: MeleeWeapon - attackRate: 1.5 + attackRate: 1 wideAnimationRotation: -135 damage: types: - Blunt: 10 - Slash: 5 + Blunt: 6 + Slash: 4 soundHit: collection: MetalThud - type: Wieldable - type: IncreaseDamageOnWield damage: types: - Blunt: 2.5 - Slash: 2.5 + Blunt: 6 + Slash: 2 Structural: 30 - type: GunRequiresWield - type: DisarmMalus - type: Prying +# No mark ability in exchange for wideswing, autoattack, and being one-handed - type: entity parent: [ BaseKnife, BaseWeaponCrusher, BaseSecurityCargoContraband] id: WeaponCrusherDagger @@ -194,12 +196,12 @@ - type: ThrowingAngle angle: 225 -# Like a crusher... but better +# Less mark damage in exchange for more healing. Also has a better ratio of blunt to slash damage, but less structural. - type: entity parent: [ WeaponCrusher, BaseSecurityCargoContraband] id: WeaponCrusherGlaive name: crusher glaive - description: An early design of the proto-kinetic accelerator, in glaive form. + description: An early design of the proto-kinetic accelerator, in glaive form. Provides better healing in exchange for less charged damage. components: - type: Sprite sprite: Objects/Weapons/Melee/crusher_glaive.rsi @@ -215,11 +217,27 @@ - suitStorage - type: UseDelay delay: 1.9 + - type: BasicEntityAmmoProvider + proto: BulletChargeGlaive + capacity: 1 + count: 1 - type: LeechOnMarker leech: groups: Brute: -21 - - type: MeleeWeapon - type: Tag tags: - Pickaxe + - type: MeleeWeapon + attackRate: 1 + wideAnimationRotation: -135 + damage: + types: + Blunt: 3 + Slash: 7 + - type: IncreaseDamageOnWield + damage: + types: + Blunt: 2 + Slash: 6 + Structural: 20 From 41160063905566ac04399d3c04f4ce25e7f753ff Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Jul 2025 00:55:10 +0000 Subject: [PATCH 027/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c51b0b9058..0d6c85ffe5 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: muburu - changes: - - message: Space Dragons now have randomly generated names. - type: Add - id: 8217 - time: '2025-04-17T21:05:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36656 - author: archee1 changes: - message: Cats can walk slowly to avoid slipping on puddles. @@ -3889,3 +3882,12 @@ id: 8729 time: '2025-07-02T20:50:22.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38661 +- author: Blackern5000 + changes: + - message: Most salvage enemies have had their HP reduced + type: Tweak + - message: Most salvage weapons have had their damage reduced + type: Tweak + id: 8730 + time: '2025-07-03T00:54:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38131 From 752957a81946fb2ab1d70b0d8730e636a61f2870 Mon Sep 17 00:00:00 2001 From: Mora <46364955+TrixxedHeart@users.noreply.github.com> Date: Wed, 2 Jul 2025 20:08:06 -0500 Subject: [PATCH 028/105] Switch HSV to the default colorspace for character customization (#38434) * Made HSV default for character editor * Adds/fixes comments to HSV defaulting * Added dropbox fix, potentially cursed * Revert "Added dropbox fix, potentially cursed" This reverts commit a709883366fbee813e839742125e70844672af29. --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> --- Content.Client/Humanoid/EyeColorPicker.cs | 1 + Content.Client/Humanoid/MarkingPicker.xaml.cs | 1 + Content.Client/Humanoid/SingleMarkingPicker.xaml.cs | 3 ++- Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Content.Client/Humanoid/EyeColorPicker.cs b/Content.Client/Humanoid/EyeColorPicker.cs index 1c864b1082..8a21b5e8b3 100644 --- a/Content.Client/Humanoid/EyeColorPicker.cs +++ b/Content.Client/Humanoid/EyeColorPicker.cs @@ -27,6 +27,7 @@ public sealed class EyeColorPicker : Control AddChild(vBox); vBox.AddChild(_colorSelectors = new ColorSelectorSliders()); + _colorSelectors.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV _colorSelectors.OnColorChanged += ColorValueChanged; } diff --git a/Content.Client/Humanoid/MarkingPicker.xaml.cs b/Content.Client/Humanoid/MarkingPicker.xaml.cs index 629f379f71..5a571942b8 100644 --- a/Content.Client/Humanoid/MarkingPicker.xaml.cs +++ b/Content.Client/Humanoid/MarkingPicker.xaml.cs @@ -416,6 +416,7 @@ public sealed partial class MarkingPicker : Control CMarkingColors.AddChild(colorContainer); ColorSelectorSliders colorSelector = new ColorSelectorSliders(); + colorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV colorSliders.Add(colorSelector); colorContainer.AddChild(new Label { Text = $"{stateNames[i]} color:" }); diff --git a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs index 50a6036c8b..822768893e 100644 --- a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs +++ b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs @@ -15,7 +15,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer [Dependency] private readonly IEntityManager _entityManager = default!; private readonly SpriteSystem _sprite; - + /// /// What happens if a marking is selected. /// It will send the 'slot' (marking index) @@ -231,6 +231,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer HorizontalExpand = true }; selector.Color = marking.MarkingColors[i]; + selector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV var colorIndex = i; selector.OnColorChanged += color => diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index aa18751db0..f22d1416ca 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -240,6 +240,7 @@ namespace Content.Client.Lobby.UI }; RgbSkinColorContainer.AddChild(_rgbSkinColorSelector = new ColorSelectorSliders()); + _rgbSkinColorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV _rgbSkinColorSelector.OnColorChanged += _ => { OnSkinColorOnValueChanged(); From f432943625d19db615c892dcd7bd32e7a191e932 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Jul 2025 01:09:14 +0000 Subject: [PATCH 029/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0d6c85ffe5..107d7ef828 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: archee1 - changes: - - message: Cats can walk slowly to avoid slipping on puddles. - type: Tweak - - message: Cak's (cake cats) previously incorrect sprinting and walking speeds have - been corrected - type: Fix - id: 8218 - time: '2025-04-18T01:15:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36542 - author: Killerqu00 changes: - message: Contraband examine icon now shows whether or not you are allowed to possess @@ -3891,3 +3881,10 @@ id: 8730 time: '2025-07-03T00:54:02.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38131 +- author: TrixxedHeart + changes: + - message: Made HSV the default color selector for character customization. + type: Tweak + id: 8731 + time: '2025-07-03T01:08:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38434 From fdf3d6715e99037a8ff3a9ee6d48ac846aaa129a Mon Sep 17 00:00:00 2001 From: Emisse <99158783+Emisse@users.noreply.github.com> Date: Wed, 2 Jul 2025 20:31:19 -0600 Subject: [PATCH 030/105] Centcomm update (#38697) --- Resources/Maps/centcomm.yml | 192 ++++++++++++++++++++++++------------ 1 file changed, 127 insertions(+), 65 deletions(-) diff --git a/Resources/Maps/centcomm.yml b/Resources/Maps/centcomm.yml index c5dd3ac46b..7830a3742e 100644 --- a/Resources/Maps/centcomm.yml +++ b/Resources/Maps/centcomm.yml @@ -1,11 +1,11 @@ meta: format: 7 category: Grid - engineVersion: 259.0.0 + engineVersion: 264.0.0 forkId: "" forkVersion: "" - time: 06/02/2025 19:48:10 - entityCount: 9753 + time: 07/02/2025 19:31:54 + entityCount: 9761 maps: [] grids: - 1668 @@ -35,6 +35,7 @@ tilemap: 11: FloorRedCircuit 77: FloorReinforced 9: FloorReinforcedHardened + 19: FloorShuttleRed 89: FloorSteel 5: FloorSteelCheckerDark 12: FloorSteelCheckerLight @@ -91,7 +92,7 @@ entities: version: 7 1,-2: ind: 1,-2 - tiles: bAAAAAABAGwAAAAAAQB5AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAAAAAAQBsAAAAAAMAeQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAAAIAbAAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAgBZAAAAAAIAHQAAAAADAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAADAAYAAAAAAAAGAAAAAAEABgAAAAAAAB0AAAAAAwAdAAAAAAMAWQAAAAADAB0AAAAAAwAdAAAAAAMAHQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAQAdAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAEABgAAAAABAAYAAAAAAAAGAAAAAAMAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAwAdAAAAAAEABgAAAAABAAYAAAAAAgAGAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAAAAHkAAAAAAAAEAAAAAAAABAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAABgAAAAABAAYAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAMAHQAAAAADAB0AAAAAAgB5AAAAAAAABAAAAAAAAAQAAAAAAAB5AAAAAAAAdgAAAAADAHYAAAAAAgAdAAAAAAEABgAAAAAAAAYAAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAAAeQAAAAAAAAQAAAAAAAAEAAAAAAAAeQAAAAAAAHYAAAAAAAB2AAAAAAMAHQAAAAABAAYAAAAAAgAGAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB2AAAAAAMAdgAAAAADAB0AAAAAAAAGAAAAAAAABgAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAAYAAAAAAwAGAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAMAHQAAAAABAAUAAAAAAgAFAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAwAdAAAAAAAABgAAAAAAAAYAAAAAAwAGAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAABAHkAAAAAAAAFAAAAAAIABQAAAAACAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAQAGAAAAAAMABgAAAAABAAYAAAAAAwAGAAAAAAEABgAAAAADAAYAAAAAAQAdAAAAAAMABQAAAAACAAUAAAAAAQB5AAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAAAGAAAAAAIABgAAAAABAAYAAAAAAgAdAAAAAAAAHQAAAAACAA== + tiles: bAAAAAABAGwAAAAAAQB5AAAAAAAAHQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAAAAAAQBsAAAAAAMAeQAAAAAAAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAAAIAbAAAAAABAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAAAdAAAAAAEAHQAAAAABAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAAAHQAAAAACAB0AAAAAAgAdAAAAAAIAHQAAAAAAAB0AAAAAAwAdAAAAAAIAHQAAAAACAB0AAAAAAgBZAAAAAAIAHQAAAAADAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAADAAYAAAAAAAAGAAAAAAEABgAAAAAAAB0AAAAAAwAdAAAAAAMAWQAAAAADAB0AAAAAAwAdAAAAAAMAHQAAAAADAB0AAAAAAAAdAAAAAAAAHQAAAAADAB0AAAAAAQAdAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAEABgAAAAABAAYAAAAAAAAGAAAAAAMAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAB0AAAAAAwAdAAAAAAEABgAAAAABAAYAAAAAAgAGAAAAAAAAHQAAAAAAAB0AAAAAAgAdAAAAAAMAHQAAAAAAAHkAAAAAAAAEAAAAAAAABAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAABgAAAAABAAYAAAAAAAAdAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAMAHQAAAAADAB0AAAAAAgB5AAAAAAAABAAAAAAAAAQAAAAAAAB5AAAAAAAAdgAAAAADAHYAAAAAAgAdAAAAAAEABgAAAAAAAAYAAAAAAgAdAAAAAAAAHQAAAAABAB0AAAAAAAAdAAAAAAIAHQAAAAAAAB0AAAAAAQAdAAAAAAAAeQAAAAAAAAQAAAAAAAAEAAAAAAAAeQAAAAAAAHYAAAAAAAB2AAAAAAMAHQAAAAABAAYAAAAAAgAGAAAAAAEAHQAAAAADAB0AAAAAAQAdAAAAAAEAHQAAAAACAB0AAAAAAwAdAAAAAAAAHQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB2AAAAAAMAdgAAAAADAB0AAAAAAAAGAAAAAAAABgAAAAAAAB0AAAAAAQAdAAAAAAIAHQAAAAADAB0AAAAAAgAdAAAAAAMAHQAAAAABAB0AAAAAAAB5AAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAMAHQAAAAAAAB0AAAAAAwAdAAAAAAEAHQAAAAADAAYAAAAAAwAGAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAQAdAAAAAAMAHQAAAAABAAUAAAAAAgAFAAAAAAAAHQAAAAABAB0AAAAAAQAdAAAAAAEAHQAAAAABAB0AAAAAAwAdAAAAAAAABgAAAAAAAAYAAAAAAwAGAAAAAAAAHQAAAAACAB0AAAAAAwAdAAAAAAMAHQAAAAABAHkAAAAAAAAFAAAAAAIABQAAAAACAB0AAAAAAgAdAAAAAAEAHQAAAAADAB0AAAAAAgAdAAAAAAAAHQAAAAADAB0AAAAAAQAGAAAAAAMABgAAAAABAAYAAAAAAwAGAAAAAAEABgAAAAADAAYAAAAAAQAdAAAAAAMABQAAAAACAAUAAAAAAQB5AAAAAAAAHQAAAAADAB0AAAAAAAAdAAAAAAMAHQAAAAACAB0AAAAAAgAdAAAAAAAAHQAAAAACAB0AAAAAAAAGAAAAAAIABgAAAAABAAYAAAAAAgAdAAAAAAAAHQAAAAACAA== version: 7 0,-2: ind: 0,-2 @@ -159,7 +160,7 @@ entities: version: 7 -2,-2: ind: -2,-2 - tiles: AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAwBsAAAAAAEAWQAAAAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAABAFkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAbAAAAAABAGwAAAAAAwBZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAQAAAAAAAAeQAAAAAAABAAAAAAAAAQAAAAAAAAeQAAAAAAAGwAAAAAAABsAAAAAAAAeQAAAAAAAAsAAAAAAAALAAAAAAAAeQAAAAAAAGwAAAAAAgBsAAAAAAMAeQAAAAAAAB0AAAAAAwAdAAAAAAIAEAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAABsAAAAAAAAbAAAAAAAAHkAAAAAAAALAAAAAAAACwAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAA== + tiles: AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAGwAAAAAAwBsAAAAAAEAWQAAAAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAABAFkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAbAAAAAABAGwAAAAAAwBZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAQBZAAAAAAIAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABoAAAAAAAAeQAAAAAAABMAAAAAAAATAAAAAAAAeQAAAAAAAGwAAAAAAABsAAAAAAAAeQAAAAAAAAsAAAAAAAALAAAAAAAAeQAAAAAAAGwAAAAAAgBsAAAAAAMAeQAAAAAAAB0AAAAAAwAdAAAAAAIAeQAAAAAAAHkAAAAAAAATAAAAAAAAEwAAAAAAAHkAAAAAAABsAAAAAAAAbAAAAAAAAHkAAAAAAAALAAAAAAAACwAAAAAAAHkAAAAAAABsAAAAAAMAbAAAAAAAAHkAAAAAAAAdAAAAAAEAHQAAAAADAA== version: 7 -2,-3: ind: -2,-3 @@ -195,7 +196,7 @@ entities: version: 7 -3,-2: ind: -3,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAACgAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAEAAAAAAAAA== + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAACgAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAACAFkAAAAAAQBZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAAQAAAAAAAAEAAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAEAAAAAAAABAAAAAAAAB5AAAAAAAAeQAAAAAAAA== version: 7 -4,-1: ind: -4,-1 @@ -4961,6 +4962,7 @@ entities: - type: SpreaderGrid - type: GridPathfinding - type: NavMap + - type: ImplicitRoof - proto: AccessConfiguratorUniversal entities: - uid: 2056 @@ -5358,11 +5360,6 @@ entities: parent: 1668 - proto: AirlockCommandGlassLocked entities: - - uid: 1587 - components: - - type: Transform - pos: 26.5,-28.5 - parent: 1668 - uid: 6753 components: - type: Transform @@ -14976,6 +14973,11 @@ entities: - type: Transform pos: -31.5,-25.5 parent: 1668 + - uid: 8770 + components: + - type: Transform + pos: -31.5,-17.5 + parent: 1668 - uid: 8800 components: - type: Transform @@ -21074,6 +21076,12 @@ entities: - type: Transform pos: 19.5,-48.5 parent: 1668 + - uid: 6124 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -32.5,-16.5 + parent: 1668 - uid: 6217 components: - type: Transform @@ -21084,6 +21092,11 @@ entities: - type: Transform pos: -5.5,-17.5 parent: 1668 + - uid: 6672 + components: + - type: Transform + pos: -32.5,-17.5 + parent: 1668 - uid: 7339 components: - type: Transform @@ -22604,6 +22617,13 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage +- proto: ClothingHeadHatCatEars + entities: + - uid: 9693 + components: + - type: Transform + pos: -26.009851,-17.232796 + parent: 1668 - proto: ClothingHeadHatCentcomcap entities: - uid: 9398 @@ -24127,26 +24147,6 @@ entities: parent: 1668 - proto: CurtainsBlack entities: - - uid: 8768 - components: - - type: Transform - pos: -28.5,-15.5 - parent: 1668 - - uid: 8769 - components: - - type: Transform - pos: -29.5,-15.5 - parent: 1668 - - uid: 8770 - components: - - type: Transform - pos: -31.5,-15.5 - parent: 1668 - - uid: 8771 - components: - - type: Transform - pos: -32.5,-15.5 - parent: 1668 - uid: 8772 components: - type: Transform @@ -27614,6 +27614,13 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage +- proto: FoodCheeseSlice + entities: + - uid: 9687 + components: + - type: Transform + pos: -31.446606,-17.398685 + parent: 1668 - proto: FoodCorn entities: - uid: 5453 @@ -40497,6 +40504,11 @@ entities: - type: Transform pos: 23.5,-31.5 parent: 1668 + - uid: 1587 + components: + - type: Transform + pos: 26.5,-28.5 + parent: 1668 - uid: 1588 components: - type: Transform @@ -42547,6 +42559,13 @@ entities: - type: Transform pos: -11.5,-32.5 parent: 1668 +- proto: KitchenKnife + entities: + - uid: 9692 + components: + - type: Transform + pos: -29.015015,-17.370127 + parent: 1668 - proto: KitchenMicrowave entities: - uid: 1169 @@ -44566,6 +44585,18 @@ entities: - type: Transform pos: -36.464035,13.631715 parent: 1668 + - uid: 9690 + components: + - type: Transform + pos: -28.43419,-17.370127 + parent: 1668 +- proto: PlushieLizardInversed + entities: + - uid: 9691 + components: + - type: Transform + pos: -29.558764,-17.370127 + parent: 1668 - proto: PlushieSharkBlue entities: - uid: 9288 @@ -45705,6 +45736,12 @@ entities: - type: Transform pos: -4.5,-16.5 parent: 1668 + - uid: 6678 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -32.5,-17.5 + parent: 1668 - proto: Poweredlight entities: - uid: 126 @@ -46381,12 +46418,6 @@ entities: rot: 3.141592653589793 rad pos: -29.5,-17.5 parent: 1668 - - uid: 6678 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -32.5,-17.5 - parent: 1668 - uid: 6679 components: - type: Transform @@ -49139,6 +49170,11 @@ entities: - type: Transform pos: -36.5,-3.5 parent: 1668 + - uid: 9694 + components: + - type: Transform + pos: 26.5,-28.5 + parent: 1668 - proto: RitualDagger entities: - uid: 6114 @@ -50617,7 +50653,7 @@ entities: - uid: 4662 components: - type: MetaData - desc: Current Headmin. + desc: I'm not a cat. name: nikthechampiongr - type: Transform pos: -24.5,-15.5 @@ -50670,6 +50706,22 @@ entities: - type: Transform pos: -22.5,-9.5 parent: 1668 + - uid: 8768 + components: + - type: MetaData + desc: Current Headmin. + name: Reisama + - type: Transform + pos: -30.5,-15.5 + parent: 1668 + - uid: 8769 + components: + - type: MetaData + desc: Current Headmin. + name: AdmiralObvious + - type: Transform + pos: -27.5,-15.5 + parent: 1668 - uid: 9395 components: - type: MetaData @@ -51497,13 +51549,6 @@ entities: - type: Transform pos: -15.5,25.5 parent: 1668 -- proto: SuitStorageBasic - entities: - - uid: 2911 - components: - - type: Transform - pos: -10.5,5.5 - parent: 1668 - proto: SuitStorageEngi entities: - uid: 4035 @@ -51511,6 +51556,13 @@ entities: - type: Transform pos: -15.5,24.5 parent: 1668 +- proto: SuitStorageEVA + entities: + - uid: 2911 + components: + - type: Transform + pos: -10.5,5.5 + parent: 1668 - proto: SurveillanceCameraCommand entities: - uid: 9397 @@ -52665,6 +52717,11 @@ entities: rot: 3.141592653589793 rad pos: -31.5,-7.5 parent: 1668 + - uid: 6671 + components: + - type: Transform + pos: -31.5,-17.5 + parent: 1668 - uid: 6681 components: - type: Transform @@ -52701,6 +52758,12 @@ entities: rot: 3.141592653589793 rad pos: -31.5,-10.5 parent: 1668 + - uid: 8771 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -32.5,-17.5 + parent: 1668 - uid: 8817 components: - type: Transform @@ -52871,6 +52934,18 @@ entities: - type: Transform pos: -37.5,3.5 parent: 1668 +- proto: TableFancyCyan + entities: + - uid: 9688 + components: + - type: Transform + pos: -29.5,-17.5 + parent: 1668 + - uid: 9689 + components: + - type: Transform + pos: -28.5,-17.5 + parent: 1668 - proto: TableFancyGreen entities: - uid: 6066 @@ -52883,32 +52958,12 @@ entities: - type: Transform pos: -11.5,-17.5 parent: 1668 - - uid: 6124 - components: - - type: Transform - pos: -29.5,-17.5 - parent: 1668 - - uid: 6125 - components: - - type: Transform - pos: -28.5,-17.5 - parent: 1668 - uid: 6173 components: - type: Transform rot: 1.5707963267948966 rad pos: -24.5,-7.5 parent: 1668 - - uid: 6671 - components: - - type: Transform - pos: -31.5,-17.5 - parent: 1668 - - uid: 6672 - components: - - type: Transform - pos: -32.5,-17.5 - parent: 1668 - uid: 6673 components: - type: Transform @@ -54844,6 +54899,13 @@ entities: - type: Transform pos: -19.5,-8.5 parent: 1668 +- proto: ToyMouse + entities: + - uid: 6125 + components: + - type: Transform + pos: -32.09308,-17.190353 + parent: 1668 - proto: ToyRubberDuck entities: - uid: 2793 From fe7b96147c05afc160c33f033deca384e2886755 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:36:06 +1000 Subject: [PATCH 031/105] Biome rework (#37735) * DungeonData rework Back to fields, serializes better, just make new layers dumby. * wawawewa * Fix this * Fixes * Port the work over * wawawewa * zoom * Kinda workin * Adjust wawa * Unloading work * Ore + entitytable fixes Iterate every dungeon not just last. * Big shot * wawawewa * Fixes * true * Fixes # Conflicts: # Content.Server/Procedural/DungeonJob/DungeonJob.cs * wawawewa * Fixes * Fix * Lot of work * wawawewa * Fixing * eh? * a * Fix a heap of stuff * Better ignored check * Reserve tile changes * biome * changes * wawawewa * Fixes & snow * Shadow fixes * wawawewa * smol * Add layer API * More work * wawawewa * Preloads and running again * wawawewa * Modified * Replacements and command * Runtime support * werk * Fix expeds + dungeon alltiles * reh --------- Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> --- Content.Client/Parallax/BiomeDebugOverlay.cs | 87 -- Content.Client/Parallax/BiomeSystem.cs | 8 - .../Parallax/Commands/ShowBiomeCommand.cs | 22 - Content.Client/Parallax/ParallaxOverlay.cs | 6 +- .../Salvage/UI/OfferingWindowOption.xaml.cs | 14 - .../Components/GatewayGeneratorComponent.cs | 6 +- .../Gateway/Systems/GatewayGeneratorSystem.cs | 9 +- Content.Server/Maps/PlanetCommand.cs | 20 +- .../Pathfinding/PathfindingSystem.Simple.cs | 6 +- .../Parallax/BiomeSystem.Commands.cs | 188 --- Content.Server/Parallax/BiomeSystem.cs | 1086 ----------------- .../Procedural/BiomeSystem.Commands.cs | 105 ++ .../Procedural/BiomeSystem.Planet.cs | 65 + Content.Server/Procedural/BiomeSystem.cs | 661 ++++++++++ .../DungeonJob/DungeonJob.AutoCabling.cs | 3 +- .../Procedural/DungeonJob/DungeonJob.Biome.cs | 74 -- .../DungeonJob/DungeonJob.BiomeMarkerLayer.cs | 105 -- .../DungeonJob/DungeonJob.BoundaryWall.cs | 29 +- .../Procedural/DungeonJob/DungeonJob.Chunk.cs | 42 + .../DungeonJob/DungeonJob.Corridor.cs | 8 +- .../DungeonJob/DungeonJob.CorridorClutter.cs | 8 +- .../DungeonJob.CorridorDecalSkirting.cs | 9 +- .../DungeonJob.DunGenNoiseDistance.cs | 8 +- .../DungeonJob/DungeonJob.DunGenPrefab.cs | 13 +- .../DungeonJob.DunGenReplaceTile.cs | 1 + .../DungeonJob/DungeonJob.DungeonEntrance.cs | 7 +- .../DungeonJob.EntityTableDunGen.cs | 1 + .../DungeonJob/DungeonJob.EntranceFlank.cs | 11 +- .../DungeonJob/DungeonJob.Exterior.cs | 28 +- .../DungeonJob/DungeonJob.ExternalWindow.cs | 12 +- .../Procedural/DungeonJob/DungeonJob.Fill.cs | 32 +- .../DungeonJob/DungeonJob.Helpers.cs | 2 + .../DungeonJob/DungeonJob.InternalWindow.cs | 11 +- .../DungeonJob/DungeonJob.Junction.cs | 11 +- .../DungeonJob/DungeonJob.MiddleConnection.cs | 19 +- .../Procedural/DungeonJob/DungeonJob.Mobs.cs | 1 + .../Procedural/DungeonJob/DungeonJob.Noise.cs | 10 +- .../Procedural/DungeonJob/DungeonJob.Ore.cs | 193 +-- .../Procedural/DungeonJob/DungeonJob.Roof.cs | 38 + .../DungeonJob/DungeonJob.RoomEntrance.cs | 11 +- .../DungeonJob/DungeonJob.SampleDecal.cs | 64 + .../DungeonJob/DungeonJob.SampleEntity.cs | 62 + .../DungeonJob/DungeonJob.SampleTile.cs | 66 + .../DungeonJob.SplineDungeonConnector.cs | 8 +- .../DungeonJob/DungeonJob.WallMount.cs | 11 +- .../Procedural/DungeonJob/DungeonJob.cs | 123 +- .../Procedural/DungeonSystem.Rooms.cs | 11 +- Content.Server/Procedural/DungeonSystem.cs | 16 +- .../Salvage/SpawnSalvageMissionJob.cs | 76 +- .../Shuttles/Systems/ArrivalsSystem.cs | 10 +- .../Systems/ShuttleSystem.FasterThanLight.cs | 13 +- .../Shuttles/Systems/ShuttleSystem.cs | 3 + .../Components/StationBiomeComponent.cs | 3 +- .../Station/Systems/StationBiomeSystem.cs | 1 + Content.Server/Tabletop/TabletopSystem.cs | 2 +- Content.Shared/CCVar/CCVars.Biome.cs | 18 + .../Parallax/Biomes/BiomeComponent.cs | 87 -- .../Parallax/Biomes/BiomeTemplatePrototype.cs | 16 - .../Parallax/Biomes/Layers/BiomeDecalLayer.cs | 34 - .../Parallax/Biomes/Layers/BiomeDummyLayer.cs | 18 - .../Biomes/Layers/BiomeEntityLayer.cs | 27 - .../Parallax/Biomes/Layers/BiomeMetaLayer.cs | 27 - .../Parallax/Biomes/Layers/IBiomeLayer.cs | 22 - .../Biomes/Layers/IBiomeWorldLayer.cs | 12 - .../Markers/BiomeMarkerLayerPrototype.cs | 53 - .../Biomes/Markers/IBiomeMarkerLayer.cs | 22 - .../Parallax/Biomes/SharedBiomeSystem.cs | 386 ------ .../Procedural/Components/BiomeComponent.cs | 86 ++ .../Components/BiomeForceUnloadComponent.cs | 9 + .../Distance/DunGenDistanceSquared.cs | 7 + Content.Shared/Procedural/DungeonConfig.cs | 9 +- Content.Shared/Procedural/DungeonData.cs | 41 + .../DungeonGenerators/ChunkDunGen.cs | 24 + .../DungeonGenerators/ExteriorDunGen.cs | 6 + .../DungeonGenerators/PrototypeDunGen.cs | 19 + .../AutoCablingDunGen.cs | 0 .../BoundaryWallDunGen.cs | 0 .../CornerClutterDunGen.cs | 0 .../CorridorClutterDunGen.cs | 0 .../CorridorDecalSkirtingDunGen.cs | 0 .../CorridorDunGen.cs | 0 .../DungeonEntranceDunGen.cs | 0 .../EntranceFlankDunGen.cs | 1 + .../ExternalWindowDunGen.cs | 1 - .../DungeonLayers/FillGridDunGen.cs | 32 +- .../InternalWindowDunGen.cs | 0 .../JunctionDunGen.cs | 0 .../MiddleConnectionDunGen.cs | 0 .../Procedural/DungeonLayers/MobsDunGen.cs | 2 - .../Procedural/DungeonLayers/RoofDunGen.cs | 15 + .../RoomEntranceDunGen.cs | 1 - .../DungeonLayers/SampleDecalDunGen.cs | 36 + .../DungeonLayers/SampleEntityDunGen.cs | 31 + .../DungeonLayers/SampleTileDunGen.cs} | 16 +- .../SplineDungeonConnectorDunGen.cs | 6 +- .../WallMountDunGen.cs | 0 .../WormCorridorDunGen.cs | 0 Content.Shared/Procedural/Loot/BiomeLoot.cs | 12 + .../Procedural/Loot/BiomeMarkerLoot.cs | 15 - .../Procedural/Loot/BiomeTemplateLoot.cs | 14 - .../Procedural/PostGeneration/BiomeDunGen.cs | 21 - .../PostGeneration/BiomeMarkerLayerDunGen.cs | 19 - .../Modifiers/SalvageBiomeModPrototype.cs | 6 +- Resources/Locale/en-US/procedural/biome.ftl | 4 - Resources/Prototypes/Entities/Tiles/water.yml | 6 +- .../Prototypes/Procedural/Magnet/asteroid.yml | 20 +- .../Procedural/Magnet/space_debris.yml | 10 +- .../Magnet/space_debris_templates.yml | 16 +- .../Prototypes/Procedural/biome_markers.yml | 147 ++- .../Procedural/biome_ore_templates.yml | 219 ++-- .../Procedural/biome_ore_templates_low.yml | 219 ++-- .../Prototypes/Procedural/biome_templates.yml | 1040 +++++++++------- .../Prototypes/Procedural/dungeon_configs.yml | 3 + .../Prototypes/Procedural/salvage_loot.yml | 244 ++-- .../Prototypes/Procedural/salvage_mods.yml | 8 +- Resources/Prototypes/Procedural/vgroid.yml | 16 +- 116 files changed, 3005 insertions(+), 3537 deletions(-) delete mode 100644 Content.Client/Parallax/BiomeDebugOverlay.cs delete mode 100644 Content.Client/Parallax/BiomeSystem.cs delete mode 100644 Content.Client/Parallax/Commands/ShowBiomeCommand.cs delete mode 100644 Content.Server/Parallax/BiomeSystem.Commands.cs delete mode 100644 Content.Server/Parallax/BiomeSystem.cs create mode 100644 Content.Server/Procedural/BiomeSystem.Commands.cs create mode 100644 Content.Server/Procedural/BiomeSystem.Planet.cs create mode 100644 Content.Server/Procedural/BiomeSystem.cs delete mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs delete mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.Chunk.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.Roof.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.SampleDecal.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.SampleEntity.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.SampleTile.cs create mode 100644 Content.Shared/CCVar/CCVars.Biome.cs delete mode 100644 Content.Shared/Parallax/Biomes/BiomeComponent.cs delete mode 100644 Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs delete mode 100644 Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs delete mode 100644 Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs create mode 100644 Content.Shared/Procedural/Components/BiomeComponent.cs create mode 100644 Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs create mode 100644 Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs create mode 100644 Content.Shared/Procedural/DungeonData.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/AutoCablingDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/BoundaryWallDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/CornerClutterDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/CorridorClutterDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/CorridorDecalSkirtingDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/CorridorDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/DungeonEntranceDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/EntranceFlankDunGen.cs (93%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/ExternalWindowDunGen.cs (94%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/InternalWindowDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/JunctionDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/MiddleConnectionDunGen.cs (100%) create mode 100644 Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/RoomEntranceDunGen.cs (93%) create mode 100644 Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs rename Content.Shared/{Parallax/Biomes/Layers/BiomeTileLayer.cs => Procedural/DungeonLayers/SampleTileDunGen.cs} (66%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/SplineDungeonConnectorDunGen.cs (83%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/WallMountDunGen.cs (100%) rename Content.Shared/Procedural/{PostGeneration => DungeonLayers}/WormCorridorDunGen.cs (100%) create mode 100644 Content.Shared/Procedural/Loot/BiomeLoot.cs delete mode 100644 Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs delete mode 100644 Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs diff --git a/Content.Client/Parallax/BiomeDebugOverlay.cs b/Content.Client/Parallax/BiomeDebugOverlay.cs deleted file mode 100644 index c914cb5de7..0000000000 --- a/Content.Client/Parallax/BiomeDebugOverlay.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Numerics; -using System.Text; -using Content.Shared.Parallax.Biomes; -using Robust.Client.Graphics; -using Robust.Client.Input; -using Robust.Client.ResourceManagement; -using Robust.Shared.Enums; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; - -namespace Content.Client.Parallax; - -public sealed class BiomeDebugOverlay : Overlay -{ - public override OverlaySpace Space => OverlaySpace.ScreenSpace; - - [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IEyeManager _eyeManager = default!; - [Dependency] private readonly IInputManager _inputManager = default!; - [Dependency] private readonly IResourceCache _cache = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; - - private BiomeSystem _biomes; - private SharedMapSystem _maps; - - private Font _font; - - public BiomeDebugOverlay() - { - IoCManager.InjectDependencies(this); - - _biomes = _entManager.System(); - _maps = _entManager.System(); - - _font = new VectorFont(_cache.GetResource("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 12); - } - - protected override bool BeforeDraw(in OverlayDrawArgs args) - { - var mapUid = _maps.GetMapOrInvalid(args.MapId); - - return _entManager.HasComponent(mapUid); - } - - protected override void Draw(in OverlayDrawArgs args) - { - var mouseScreenPos = _inputManager.MouseScreenPosition; - var mousePos = _eyeManager.ScreenToMap(mouseScreenPos); - - if (mousePos.MapId == MapId.Nullspace || mousePos.MapId != args.MapId) - return; - - var mapUid = _maps.GetMapOrInvalid(args.MapId); - - if (!_entManager.TryGetComponent(mapUid, out BiomeComponent? biomeComp) || !_entManager.TryGetComponent(mapUid, out MapGridComponent? grid)) - return; - - var sb = new StringBuilder(); - var nodePos = _maps.WorldToTile(mapUid, grid, mousePos.Position); - - if (_biomes.TryGetEntity(nodePos, biomeComp, (mapUid, grid), out var ent)) - { - var text = $"Entity: {ent}"; - sb.AppendLine(text); - } - - if (_biomes.TryGetDecals(nodePos, biomeComp.Layers, biomeComp.Seed, (mapUid, grid), out var decals)) - { - var text = $"Decals: {decals.Count}"; - sb.AppendLine(text); - - foreach (var decal in decals) - { - var decalText = $"- {decal.ID}"; - sb.AppendLine(decalText); - } - } - - if (_biomes.TryGetBiomeTile(nodePos, biomeComp.Layers, biomeComp.Seed, (mapUid, grid), out var tile)) - { - var tileText = $"Tile: {_tileDefManager[tile.Value.TypeId].ID}"; - sb.AppendLine(tileText); - } - - args.ScreenHandle.DrawString(_font, mouseScreenPos.Position + new Vector2(0f, 32f), sb.ToString()); - } -} diff --git a/Content.Client/Parallax/BiomeSystem.cs b/Content.Client/Parallax/BiomeSystem.cs deleted file mode 100644 index dc326e1fa7..0000000000 --- a/Content.Client/Parallax/BiomeSystem.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Shared.Parallax.Biomes; - -namespace Content.Client.Parallax; - -public sealed class BiomeSystem : SharedBiomeSystem -{ - -} diff --git a/Content.Client/Parallax/Commands/ShowBiomeCommand.cs b/Content.Client/Parallax/Commands/ShowBiomeCommand.cs deleted file mode 100644 index 2a628dd931..0000000000 --- a/Content.Client/Parallax/Commands/ShowBiomeCommand.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Robust.Client.Graphics; -using Robust.Shared.Console; - -namespace Content.Client.Parallax.Commands; - -public sealed class ShowBiomeCommand : LocalizedCommands -{ - [Dependency] private readonly IOverlayManager _overlayMgr = default!; - - public override string Command => "showbiome"; - public override void Execute(IConsoleShell shell, string argStr, string[] args) - { - if (_overlayMgr.HasOverlay()) - { - _overlayMgr.RemoveOverlay(); - } - else - { - _overlayMgr.AddOverlay(new BiomeDebugOverlay()); - } - } -} diff --git a/Content.Client/Parallax/ParallaxOverlay.cs b/Content.Client/Parallax/ParallaxOverlay.cs index 06f830675d..8e3a1dddfe 100644 --- a/Content.Client/Parallax/ParallaxOverlay.cs +++ b/Content.Client/Parallax/ParallaxOverlay.cs @@ -1,8 +1,6 @@ using System.Numerics; using Content.Client.Parallax.Managers; using Content.Shared.CCVar; -using Content.Shared.Parallax.Biomes; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Shared.Configuration; using Robust.Shared.Enums; @@ -19,7 +17,6 @@ public sealed class ParallaxOverlay : Overlay [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly IParallaxManager _manager = default!; - private readonly SharedMapSystem _mapSystem; private readonly ParallaxSystem _parallax; public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowWorld; @@ -28,13 +25,12 @@ public sealed class ParallaxOverlay : Overlay { ZIndex = ParallaxSystem.ParallaxZIndex; IoCManager.InjectDependencies(this); - _mapSystem = _entManager.System(); _parallax = _entManager.System(); } protected override bool BeforeDraw(in OverlayDrawArgs args) { - if (args.MapId == MapId.Nullspace || _entManager.HasComponent(_mapSystem.GetMapOrInvalid(args.MapId))) + if (args.MapId == MapId.Nullspace) return false; return true; diff --git a/Content.Client/Salvage/UI/OfferingWindowOption.xaml.cs b/Content.Client/Salvage/UI/OfferingWindowOption.xaml.cs index 7855577e69..8d718f1be5 100644 --- a/Content.Client/Salvage/UI/OfferingWindowOption.xaml.cs +++ b/Content.Client/Salvage/UI/OfferingWindowOption.xaml.cs @@ -1,23 +1,9 @@ -using System.Linq; -using Content.Client.Computer; using Content.Client.Stylesheets; -using Content.Client.UserInterface.Controls; -using Content.Shared.CCVar; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Procedural; -using Content.Shared.Salvage; -using Content.Shared.Salvage.Expeditions; -using Content.Shared.Salvage.Expeditions.Modifiers; -using Content.Shared.Shuttles.BUIStates; using Robust.Client.AutoGenerated; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Configuration; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Robust.Shared.Utility; namespace Content.Client.Salvage.UI; diff --git a/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs b/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs index d65760e270..03a7ec5c4d 100644 --- a/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs +++ b/Content.Server/Gateway/Components/GatewayGeneratorComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Parallax.Biomes.Markers; +using Content.Shared.Procedural; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; @@ -42,7 +42,7 @@ public sealed partial class GatewayGeneratorComponent : Component /// Mob layers to pick from. /// [DataField] - public List> MobLayers = new() + public List> MobLayers = new() { "Carps", "Xenos", @@ -54,7 +54,7 @@ public sealed partial class GatewayGeneratorComponent : Component /// /// Loot layers to pick from. /// - public List> LootLayers = new() + public List> LootLayers = new() { "OreIron", "OreQuartz", diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 83471cdbc1..7f4bdccf2e 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -1,12 +1,11 @@ using System.Linq; using Content.Server.Gateway.Components; -using Content.Server.Parallax; using Content.Server.Procedural; using Content.Shared.CCVar; using Content.Shared.Dataset; using Content.Shared.Maps; -using Content.Shared.Parallax.Biomes; using Content.Shared.Procedural; +using Content.Shared.Procedural.Components; using Content.Shared.Salvage; using Robust.Shared.Configuration; using Robust.Shared.Map; @@ -111,7 +110,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem }; AddComp(mapUid, restricted); - _biome.EnsurePlanet(mapUid, _protoManager.Index("Continental"), seed); + _biome.EnsurePlanet(mapUid, _protoManager.Index("BiomeContinental"), seed); var grid = Comp(mapUid); @@ -199,7 +198,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem var layer = lootLayers[layerIdx]; lootLayers.RemoveSwap(layerIdx); - _biome.AddMarkerLayer(ent.Owner, biomeComp, layer.Id); + _biome.AddLayer((ent.Owner, biomeComp), $"{layer.Id}-{i}", layer.Id); } // - Mobs @@ -211,7 +210,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem var layer = mobLayers[layerIdx]; mobLayers.RemoveSwap(layerIdx); - _biome.AddMarkerLayer(ent.Owner, biomeComp, layer.Id); + _biome.AddLayer((ent.Owner, biomeComp), $"{layer.Id}-{i}", layer.Id); } } } diff --git a/Content.Server/Maps/PlanetCommand.cs b/Content.Server/Maps/PlanetCommand.cs index 8e8b5b10ed..d3b7abc171 100644 --- a/Content.Server/Maps/PlanetCommand.cs +++ b/Content.Server/Maps/PlanetCommand.cs @@ -1,20 +1,11 @@ using System.Linq; using Content.Server.Administration; -using Content.Server.Atmos; -using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Parallax; +using Content.Server.Procedural; using Content.Shared.Administration; -using Content.Shared.Atmos; -using Content.Shared.Gravity; -using Content.Shared.Movement.Components; -using Content.Shared.Parallax.Biomes; -using Robust.Shared.Audio; +using Content.Shared.Procedural.Components; using Robust.Shared.Console; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; -using Robust.Shared.Random; namespace Content.Server.Maps; @@ -52,7 +43,7 @@ public sealed class PlanetCommand : LocalizedEntityCommands return; } - if (!_protoManager.TryIndex(args[1], out var biomeTemplate)) + if (!_protoManager.TryIndex(args[1], out var biomeTemplate)) { shell.WriteError(Loc.GetString("cmd-planet-map-prototype", ("prototype", args[1]))); return; @@ -70,9 +61,12 @@ public sealed class PlanetCommand : LocalizedEntityCommands if (args.Length == 1) return CompletionResult.FromHintOptions(CompletionHelper.MapIds(_entManager), "Map Id"); + var biomeName = _entManager.ComponentFactory.GetComponentName(); + if (args.Length == 2) { - var options = _protoManager.EnumeratePrototypes() + var options = _protoManager.EnumeratePrototypes() + .Where(o => o.Components.ContainsKey(biomeName)) .Select(o => new CompletionOption(o.ID, "Biome")); return CompletionResult.FromOptions(options); } diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs index 7afd3d78df..07d6a624c8 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs @@ -65,6 +65,9 @@ public sealed partial class PathfindingSystem { for (var y = -1; y <= 1; y++) { + if (x == 0 && y == 0) + continue; + var neighbor = node + new Vector2i(x, y); var neighborCost = OctileDistance(node, neighbor) * args.TileCost?.Invoke(neighbor) ?? 1f; @@ -121,8 +124,7 @@ public sealed partial class PathfindingSystem cameFrom[neighbor] = node; costSoFar[neighbor] = gScore; - // Still use octile even for manhattan distance. - var hScore = OctileDistance(args.End, neighbor) * 1.001f; + var hScore = ManhattanDistance(args.End, neighbor); var fScore = gScore + hScore; frontier.Enqueue(neighbor, fScore); } diff --git a/Content.Server/Parallax/BiomeSystem.Commands.cs b/Content.Server/Parallax/BiomeSystem.Commands.cs deleted file mode 100644 index a915e17fcb..0000000000 --- a/Content.Server/Parallax/BiomeSystem.Commands.cs +++ /dev/null @@ -1,188 +0,0 @@ -using Content.Server.Administration; -using Content.Shared.Administration; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Parallax.Biomes.Layers; -using Content.Shared.Parallax.Biomes.Markers; -using Robust.Shared.Console; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; - -namespace Content.Server.Parallax; - -public sealed partial class BiomeSystem -{ - private void InitializeCommands() - { - _console.RegisterCommand("biome_clear", Loc.GetString("cmd-biome_clear-desc"), Loc.GetString("cmd-biome_clear-help"), BiomeClearCallback, BiomeClearCallbackHelper); - _console.RegisterCommand("biome_addlayer", Loc.GetString("cmd-biome_addlayer-desc"), Loc.GetString("cmd-biome_addlayer-help"), AddLayerCallback, AddLayerCallbackHelp); - _console.RegisterCommand("biome_addmarkerlayer", Loc.GetString("cmd-biome_addmarkerlayer-desc"), Loc.GetString("cmd-biome_addmarkerlayer-desc"), AddMarkerLayerCallback, AddMarkerLayerCallbackHelper); - } - - [AdminCommand(AdminFlags.Fun)] - private void BiomeClearCallback(IConsoleShell shell, string argstr, string[] args) - { - if (args.Length != 1) - { - return; - } - - int.TryParse(args[0], out var mapInt); - var mapId = new MapId(mapInt); - var mapUid = _mapSystem.GetMapOrInvalid(mapId); - - if (_mapSystem.MapExists(mapId) || - !TryComp(mapUid, out var biome)) - { - return; - } - - ClearTemplate(mapUid, biome); - } - - private CompletionResult BiomeClearCallbackHelper(IConsoleShell shell, string[] args) - { - if (args.Length == 1) - { - return CompletionResult.FromHintOptions(CompletionHelper.Components(args[0], EntityManager), "Biome"); - } - - return CompletionResult.Empty; - } - - [AdminCommand(AdminFlags.Fun)] - private void AddLayerCallback(IConsoleShell shell, string argstr, string[] args) - { - if (args.Length < 3 || args.Length > 4) - { - return; - } - - if (!int.TryParse(args[0], out var mapInt)) - { - return; - } - - var mapId = new MapId(mapInt); - var mapUid = _mapSystem.GetMapOrInvalid(mapId); - - if (!_mapSystem.MapExists(mapId) || !TryComp(mapUid, out var biome)) - { - return; - } - - if (!ProtoManager.TryIndex(args[1], out var template)) - { - return; - } - - var offset = 0; - - if (args.Length == 4) - { - int.TryParse(args[3], out offset); - } - - AddTemplate(mapUid, biome, args[2], template, offset); - } - - private CompletionResult AddLayerCallbackHelp(IConsoleShell shell, string[] args) - { - if (args.Length == 1) - { - return CompletionResult.FromHintOptions(CompletionHelper.MapIds(EntityManager), "Map ID"); - } - - if (args.Length == 2) - { - return CompletionResult.FromHintOptions( - CompletionHelper.PrototypeIDs(proto: ProtoManager), "Biome template"); - } - - if (args.Length == 3) - { - if (int.TryParse(args[0], out var mapInt)) - { - var mapId = new MapId(mapInt); - - if (TryComp(_mapSystem.GetMapOrInvalid(mapId), out var biome)) - { - var results = new List(); - - foreach (var layer in biome.Layers) - { - if (layer is not BiomeDummyLayer dummy) - continue; - - results.Add(dummy.ID); - } - - return CompletionResult.FromHintOptions(results, "Dummy layer ID"); - } - } - } - - if (args.Length == 4) - { - return CompletionResult.FromHint("Seed offset"); - } - - return CompletionResult.Empty; - } - - [AdminCommand(AdminFlags.Fun)] - private void AddMarkerLayerCallback(IConsoleShell shell, string argstr, string[] args) - { - if (args.Length != 2) - { - return; - } - - if (!int.TryParse(args[0], out var mapInt)) - { - return; - } - - var mapId = new MapId(mapInt); - - if (!_mapSystem.MapExists(mapId) || !TryComp(_mapSystem.GetMapOrInvalid(mapId), out var biome)) - { - return; - } - - if (!ProtoManager.HasIndex(args[1])) - { - return; - } - - if (!biome.MarkerLayers.Add(args[1])) - { - return; - } - - biome.ForcedMarkerLayers.Add(args[1]); - } - - private CompletionResult AddMarkerLayerCallbackHelper(IConsoleShell shell, string[] args) - { - if (args.Length == 1) - { - var allQuery = AllEntityQuery(); - var options = new List(); - - while (allQuery.MoveNext(out var mapComp, out _)) - { - options.Add(new CompletionOption(mapComp.MapId.ToString())); - } - - return CompletionResult.FromHintOptions(options, "Biome"); - } - - if (args.Length == 2) - { - return CompletionResult.FromHintOptions( - CompletionHelper.PrototypeIDs(proto: ProtoManager), "Marker"); - } - - return CompletionResult.Empty; - } -} diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs deleted file mode 100644 index 496cb387e8..0000000000 --- a/Content.Server/Parallax/BiomeSystem.cs +++ /dev/null @@ -1,1086 +0,0 @@ -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; -using Content.Server.Atmos; -using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Decals; -using Content.Server.Ghost.Roles.Components; -using Content.Server.Shuttles.Events; -using Content.Server.Shuttles.Systems; -using Content.Shared.Atmos; -using Content.Shared.Decals; -using Content.Shared.Ghost; -using Content.Shared.Gravity; -using Content.Shared.Light.Components; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Parallax.Biomes.Layers; -using Content.Shared.Parallax.Biomes.Markers; -using Content.Shared.Tag; -using Microsoft.Extensions.ObjectPool; -using Robust.Server.Player; -using Robust.Shared; -using Robust.Shared.Collections; -using Robust.Shared.Configuration; -using Robust.Shared.Console; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Threading; -using Robust.Shared.Utility; -using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator; - -namespace Content.Server.Parallax; - -public sealed partial class BiomeSystem : SharedBiomeSystem -{ - [Dependency] private readonly IConfigurationManager _configManager = default!; - [Dependency] private readonly IConsoleHost _console = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IParallelManager _parallel = default!; - [Dependency] private readonly IPrototypeManager _proto = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly AtmosphereSystem _atmos = default!; - [Dependency] private readonly DecalSystem _decals = default!; - [Dependency] private readonly SharedMapSystem _mapSystem = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly ShuttleSystem _shuttles = default!; - [Dependency] private readonly TagSystem _tags = default!; - - private EntityQuery _biomeQuery; - private EntityQuery _fixturesQuery; - private EntityQuery _ghostQuery; - private EntityQuery _xformQuery; - - private readonly HashSet _handledEntities = new(); - private const float DefaultLoadRange = 16f; - private float _loadRange = DefaultLoadRange; - private static readonly ProtoId AllowBiomeLoadingTag = "AllowBiomeLoading"; - - private List<(Vector2i, Tile)> _tiles = new(); - - private ObjectPool> _tilePool = - new DefaultObjectPool>(new SetPolicy(), 256); - - /// - /// Load area for chunks containing tiles, decals etc. - /// - private Box2 _loadArea = new(-DefaultLoadRange, -DefaultLoadRange, DefaultLoadRange, DefaultLoadRange); - - /// - /// Stores the chunks active for this tick temporarily. - /// - private readonly Dictionary> _activeChunks = new(); - - private readonly Dictionary>> _markerChunks = new(); - - public override void Initialize() - { - base.Initialize(); - Log.Level = LogLevel.Debug; - _biomeQuery = GetEntityQuery(); - _fixturesQuery = GetEntityQuery(); - _ghostQuery = GetEntityQuery(); - _xformQuery = GetEntityQuery(); - SubscribeLocalEvent(OnBiomeMapInit); - SubscribeLocalEvent(OnFTLStarted); - SubscribeLocalEvent(OnShuttleFlatten); - Subs.CVar(_configManager, CVars.NetMaxUpdateRange, SetLoadRange, true); - InitializeCommands(); - SubscribeLocalEvent(ProtoReload); - } - - private void ProtoReload(PrototypesReloadedEventArgs obj) - { - if (!obj.ByType.TryGetValue(typeof(BiomeTemplatePrototype), out var reloads)) - return; - - var query = AllEntityQuery(); - - while (query.MoveNext(out var uid, out var biome)) - { - if (biome.Template == null || !reloads.Modified.TryGetValue(biome.Template, out var proto)) - continue; - - SetTemplate(uid, biome, (BiomeTemplatePrototype)proto); - } - } - - private void SetLoadRange(float obj) - { - // Round it up - _loadRange = MathF.Ceiling(obj / ChunkSize) * ChunkSize; - _loadArea = new Box2(-_loadRange, -_loadRange, _loadRange, _loadRange); - } - - private void OnBiomeMapInit(EntityUid uid, BiomeComponent component, MapInitEvent args) - { - if (component.Seed == -1) - { - SetSeed(uid, component, _random.Next()); - } - - if (_proto.TryIndex(component.Template, out var biome)) - SetTemplate(uid, component, biome); - - var xform = Transform(uid); - var mapId = xform.MapID; - - if (mapId != MapId.Nullspace && HasComp(uid)) - { - var setTiles = new List<(Vector2i Index, Tile tile)>(); - - foreach (var grid in _mapManager.GetAllGrids(mapId)) - { - if (!_fixturesQuery.TryGetComponent(grid.Owner, out var fixtures)) - continue; - - // Don't want shuttles flying around now do we. - _shuttles.Disable(grid.Owner); - var pTransform = _physics.GetPhysicsTransform(grid.Owner); - - foreach (var fixture in fixtures.Fixtures.Values) - { - for (var i = 0; i < fixture.Shape.ChildCount; i++) - { - var aabb = fixture.Shape.ComputeAABB(pTransform, i); - - setTiles.Clear(); - ReserveTiles(uid, aabb, setTiles); - } - } - } - } - } - - public void SetEnabled(Entity ent, bool enabled = true) - { - if (!Resolve(ent, ref ent.Comp) || ent.Comp.Enabled == enabled) - return; - - ent.Comp.Enabled = enabled; - Dirty(ent, ent.Comp); - } - - public void SetSeed(EntityUid uid, BiomeComponent component, int seed, bool dirty = true) - { - component.Seed = seed; - - if (dirty) - Dirty(uid, component); - } - - public void ClearTemplate(EntityUid uid, BiomeComponent component, bool dirty = true) - { - component.Layers.Clear(); - component.Template = null; - - if (dirty) - Dirty(uid, component); - } - - /// - /// Sets the and refreshes layers. - /// - public void SetTemplate(EntityUid uid, BiomeComponent component, BiomeTemplatePrototype template, bool dirty = true) - { - component.Layers.Clear(); - component.Template = template.ID; - - foreach (var layer in template.Layers) - { - component.Layers.Add(layer); - } - - if (dirty) - Dirty(uid, component); - } - - /// - /// Adds the specified layer at the specified marker if it exists. - /// - public void AddLayer(EntityUid uid, BiomeComponent component, string id, IBiomeLayer addedLayer, int seedOffset = 0) - { - for (var i = 0; i < component.Layers.Count; i++) - { - var layer = component.Layers[i]; - - if (layer is not BiomeDummyLayer dummy || dummy.ID != id) - continue; - - addedLayer.Noise.SetSeed(addedLayer.Noise.GetSeed() + seedOffset); - component.Layers.Insert(i, addedLayer); - break; - } - - Dirty(uid, component); - } - - public void AddMarkerLayer(EntityUid uid, BiomeComponent component, string marker) - { - component.MarkerLayers.Add(marker); - Dirty(uid, component); - } - - /// - /// Adds the specified template at the specified marker if it exists, withour overriding every layer. - /// - public void AddTemplate(EntityUid uid, BiomeComponent component, string id, BiomeTemplatePrototype template, int seedOffset = 0) - { - for (var i = 0; i < component.Layers.Count; i++) - { - var layer = component.Layers[i]; - - if (layer is not BiomeDummyLayer dummy || dummy.ID != id) - continue; - - for (var j = template.Layers.Count - 1; j >= 0; j--) - { - var addedLayer = template.Layers[j]; - addedLayer.Noise.SetSeed(addedLayer.Noise.GetSeed() + seedOffset); - component.Layers.Insert(i, addedLayer); - } - - break; - } - - Dirty(uid, component); - } - - private void OnFTLStarted(ref FTLStartedEvent ev) - { - var targetMap = _transform.ToMapCoordinates(ev.TargetCoordinates); - var targetMapUid = _mapSystem.GetMapOrInvalid(targetMap.MapId); - - if (!TryComp(targetMapUid, out var biome)) - return; - - var preloadArea = new Vector2(32f, 32f); - var targetArea = new Box2(targetMap.Position - preloadArea, targetMap.Position + preloadArea); - Preload(targetMapUid, biome, targetArea); - } - - private void OnShuttleFlatten(ref ShuttleFlattenEvent ev) - { - if (!TryComp(ev.MapUid, out var biome) || - !TryComp(ev.MapUid, out var grid)) - { - return; - } - - var tiles = new List<(Vector2i Index, Tile Tile)>(); - - foreach (var aabb in ev.AABBs) - { - for (var x = Math.Floor(aabb.Left); x <= Math.Ceiling(aabb.Right); x++) - { - for (var y = Math.Floor(aabb.Bottom); y <= Math.Ceiling(aabb.Top); y++) - { - var index = new Vector2i((int)x, (int)y); - var chunk = SharedMapSystem.GetChunkIndices(index, ChunkSize); - - var mod = biome.ModifiedTiles.GetOrNew(chunk * ChunkSize); - - if (!mod.Add(index) || !TryGetBiomeTile(index, biome.Layers, biome.Seed, (ev.MapUid, grid), out var tile)) - continue; - - // If we flag it as modified then the tile is never set so need to do it ourselves. - tiles.Add((index, tile.Value)); - } - } - } - - _mapSystem.SetTiles(ev.MapUid, grid, tiles); - } - - /// - /// Preloads biome for the specified area. - /// - public void Preload(EntityUid uid, BiomeComponent component, Box2 area) - { - var markers = component.MarkerLayers; - var goobers = _markerChunks.GetOrNew(component); - - foreach (var layer in markers) - { - var proto = ProtoManager.Index(layer); - var enumerator = new ChunkIndicesEnumerator(area, proto.Size); - - while (enumerator.MoveNext(out var chunk)) - { - var chunkOrigin = chunk * proto.Size; - var layerChunks = goobers.GetOrNew(proto.ID); - layerChunks.Add(chunkOrigin.Value); - } - } - } - - private bool CanLoad(EntityUid uid) - { - return !_ghostQuery.HasComp(uid) || _tags.HasTag(uid, AllowBiomeLoadingTag); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - var biomes = AllEntityQuery(); - - while (biomes.MoveNext(out var biome)) - { - if (biome.LifeStage < ComponentLifeStage.Running) - continue; - - _activeChunks.Add(biome, _tilePool.Get()); - _markerChunks.GetOrNew(biome); - } - - // Get chunks in range - foreach (var pSession in Filter.GetAllPlayers(_playerManager)) - { - if (_xformQuery.TryGetComponent(pSession.AttachedEntity, out var xform) && - _handledEntities.Add(pSession.AttachedEntity.Value) && - _biomeQuery.TryGetComponent(xform.MapUid, out var biome) && - biome.Enabled && - CanLoad(pSession.AttachedEntity.Value)) - { - var worldPos = _transform.GetWorldPosition(xform); - AddChunksInRange(biome, worldPos); - - foreach (var layer in biome.MarkerLayers) - { - var layerProto = ProtoManager.Index(layer); - AddMarkerChunksInRange(biome, worldPos, layerProto); - } - } - - foreach (var viewer in pSession.ViewSubscriptions) - { - if (!_handledEntities.Add(viewer) || - !_xformQuery.TryGetComponent(viewer, out xform) || - !_biomeQuery.TryGetComponent(xform.MapUid, out biome) || - !biome.Enabled || - !CanLoad(viewer)) - { - continue; - } - - var worldPos = _transform.GetWorldPosition(xform); - AddChunksInRange(biome, worldPos); - - foreach (var layer in biome.MarkerLayers) - { - var layerProto = ProtoManager.Index(layer); - AddMarkerChunksInRange(biome, worldPos, layerProto); - } - } - } - - var loadBiomes = AllEntityQuery(); - - while (loadBiomes.MoveNext(out var gridUid, out var biome, out var grid)) - { - // If not MapInit don't run it. - if (biome.LifeStage < ComponentLifeStage.Running) - continue; - - if (!biome.Enabled) - continue; - - // Load new chunks - LoadChunks(biome, gridUid, grid, biome.Seed); - // Unload old chunks - UnloadChunks(biome, gridUid, grid, biome.Seed); - } - - _handledEntities.Clear(); - - foreach (var tiles in _activeChunks.Values) - { - _tilePool.Return(tiles); - } - - _activeChunks.Clear(); - _markerChunks.Clear(); - } - - private void AddChunksInRange(BiomeComponent biome, Vector2 worldPos) - { - var enumerator = new ChunkIndicesEnumerator(_loadArea.Translated(worldPos), ChunkSize); - - while (enumerator.MoveNext(out var chunkOrigin)) - { - _activeChunks[biome].Add(chunkOrigin.Value * ChunkSize); - } - } - - private void AddMarkerChunksInRange(BiomeComponent biome, Vector2 worldPos, IBiomeMarkerLayer layer) - { - // Offset the load area so it's centralised. - var loadArea = new Box2(0, 0, layer.Size, layer.Size); - var halfLayer = new Vector2(layer.Size / 2f); - - var enumerator = new ChunkIndicesEnumerator(loadArea.Translated(worldPos - halfLayer), layer.Size); - - while (enumerator.MoveNext(out var chunkOrigin)) - { - var lay = _markerChunks[biome].GetOrNew(layer.ID); - lay.Add(chunkOrigin.Value * layer.Size); - } - } - - #region Load - - /// - /// Loads all of the chunks for a particular biome, as well as handle any marker chunks. - /// - private void LoadChunks( - BiomeComponent component, - EntityUid gridUid, - MapGridComponent grid, - int seed) - { - BuildMarkerChunks(component, gridUid, grid, seed); - - var active = _activeChunks[component]; - - foreach (var chunk in active) - { - LoadChunkMarkers(component, gridUid, grid, chunk, seed); - - if (!component.LoadedChunks.Add(chunk)) - continue; - - // Load NOW! - LoadChunk(component, gridUid, grid, chunk, seed); - } - } - - /// - /// Goes through all marker chunks that haven't been calculated, then calculates what spawns there are and - /// allocates them to the relevant actual chunks in the biome (marker chunks may be many times larger than biome chunks). - /// - private void BuildMarkerChunks(BiomeComponent component, EntityUid gridUid, MapGridComponent grid, int seed) - { - var markers = _markerChunks[component]; - var loadedMarkers = component.LoadedMarkers; - var idx = 0; - - foreach (var (layer, chunks) in markers) - { - // I know dictionary ordering isn't guaranteed but I just need something to differentiate seeds. - idx++; - var localIdx = idx; - - Parallel.ForEach(chunks, new ParallelOptions() { MaxDegreeOfParallelism = _parallel.ParallelProcessCount }, chunk => - { - if (loadedMarkers.TryGetValue(layer, out var mobChunks) && mobChunks.Contains(chunk)) - return; - - var forced = component.ForcedMarkerLayers.Contains(layer); - - // Make a temporary version and copy back in later. - var pending = new Dictionary>>(); - - // Essentially get the seed + work out a buffer to adjacent chunks so we don't - // inadvertantly spawn too many near the edges. - var layerProto = ProtoManager.Index(layer); - var markerSeed = seed + chunk.X * ChunkSize + chunk.Y + localIdx; - var rand = new Random(markerSeed); - var buffer = (int)(layerProto.Radius / 2f); - var bounds = new Box2i(chunk + buffer, chunk + layerProto.Size - buffer); - var count = (int)(bounds.Area / (layerProto.Radius * layerProto.Radius)); - count = Math.Min(count, layerProto.MaxCount); - - GetMarkerNodes(gridUid, component, grid, layerProto, forced, bounds, count, rand, - out var spawnSet, out var existing); - - // Forcing markers to spawn so delete any that were found to be in the way. - if (forced && existing.Count > 0) - { - // Lock something so we can delete these safely. - lock (component.PendingMarkers) - { - foreach (var ent in existing) - { - Del(ent); - } - } - } - - foreach (var node in spawnSet.Keys) - { - var chunkOrigin = SharedMapSystem.GetChunkIndices(node, ChunkSize) * ChunkSize; - - if (!pending.TryGetValue(chunkOrigin, out var pendingMarkers)) - { - pendingMarkers = new Dictionary>(); - pending[chunkOrigin] = pendingMarkers; - } - - if (!pendingMarkers.TryGetValue(layer, out var layerMarkers)) - { - layerMarkers = new List(); - pendingMarkers[layer] = layerMarkers; - } - - layerMarkers.Add(node); - } - - lock (loadedMarkers) - { - if (!loadedMarkers.TryGetValue(layer, out var lockMobChunks)) - { - lockMobChunks = new HashSet(); - loadedMarkers[layer] = lockMobChunks; - } - - lockMobChunks.Add(chunk); - - foreach (var (chunkOrigin, layers) in pending) - { - if (!component.PendingMarkers.TryGetValue(chunkOrigin, out var lockMarkers)) - { - lockMarkers = new Dictionary>(); - component.PendingMarkers[chunkOrigin] = lockMarkers; - } - - foreach (var (lockLayer, nodes) in layers) - { - lockMarkers[lockLayer] = nodes; - } - } - } - }); - } - - component.ForcedMarkerLayers.Clear(); - } - - /// - /// Gets the marker nodes for the specified area. - /// - /// Should we include empty tiles when determine markers (e.g. if they are yet to be loaded) - public void GetMarkerNodes( - EntityUid gridUid, - BiomeComponent biome, - MapGridComponent grid, - BiomeMarkerLayerPrototype layerProto, - bool forced, - Box2i bounds, - int count, - Random rand, - out Dictionary spawnSet, - out HashSet existingEnts, - bool emptyTiles = true) - { - DebugTools.Assert(count > 0); - var remainingTiles = _tilePool.Get(); - var nodeEntities = new Dictionary(); - var nodeMask = new Dictionary(); - - // Okay so originally we picked a random tile and BFS outwards - // the problem is if you somehow get a cooked frontier then it might drop entire veins - // hence we'll grab all valid tiles up front and use that as possible seeds. - // It's hella more expensive but stops issues. - for (var x = bounds.Left; x < bounds.Right; x++) - { - for (var y = bounds.Bottom; y < bounds.Top; y++) - { - var node = new Vector2i(x, y); - - // Empty tile, skip if relevant. - if (!emptyTiles && (!_mapSystem.TryGetTile(grid, node, out var tile) || tile.IsEmpty)) - continue; - - // Check if it's a valid spawn, if so then use it. - var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(gridUid, grid, node); - enumerator.MoveNext(out var existing); - - if (!forced && existing != null) - continue; - - // Check if mask matches // anything blocking. - TryGetEntity(node, biome, (gridUid, grid), out var proto); - - // If there's an existing entity and it doesn't match the mask then skip. - if (layerProto.EntityMask.Count > 0 && - (proto == null || - !layerProto.EntityMask.ContainsKey(proto))) - { - continue; - } - - // If it's just a flat spawn then just check for anything blocking. - if (proto != null && layerProto.Prototype != null) - { - continue; - } - - DebugTools.Assert(layerProto.EntityMask.Count == 0 || !string.IsNullOrEmpty(proto)); - remainingTiles.Add(node); - nodeEntities.Add(node, existing); - nodeMask.Add(node, proto); - } - } - - var frontier = new ValueList(32); - // TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk - // Get the total amount of groups to spawn across the entire chunk. - // We treat a null entity mask as requiring nothing else on the tile - - spawnSet = new Dictionary(); - existingEnts = new HashSet(); - - // Iterate the group counts and pathfind out each group. - for (var i = 0; i < count; i++) - { - var groupSize = rand.Next(layerProto.MinGroupSize, layerProto.MaxGroupSize + 1); - - // While we have remaining tiles keep iterating - while (groupSize > 0 && remainingTiles.Count > 0) - { - var startNode = rand.PickAndTake(remainingTiles); - frontier.Clear(); - frontier.Add(startNode); - - // This essentially may lead to a vein being split in multiple areas but the count matters more than position. - while (frontier.Count > 0 && groupSize > 0) - { - // Need to pick a random index so we don't just get straight lines of ores. - var frontierIndex = rand.Next(frontier.Count); - var node = frontier[frontierIndex]; - frontier.RemoveSwap(frontierIndex); - remainingTiles.Remove(node); - - // Add neighbors if they're valid, worst case we add no more and pick another random seed tile. - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - var neighbor = new Vector2i(node.X + x, node.Y + y); - - if (frontier.Contains(neighbor) || !remainingTiles.Contains(neighbor)) - continue; - - frontier.Add(neighbor); - } - } - - // Tile valid salad so add it. - var mask = nodeMask[node]; - spawnSet.Add(node, mask); - groupSize--; - - if (nodeEntities.TryGetValue(node, out var existing)) - { - Del(existing); - } - } - } - - if (groupSize > 0) - { - Log.Warning($"Found remaining group size for ore veins!"); - } - } - - _tilePool.Return(remainingTiles); - } - - /// - /// Loads the pre-deteremined marker nodes for a particular chunk. - /// This is calculated in - /// - /// - /// Note that the marker chunks do not correspond to this chunk. - /// - private void LoadChunkMarkers( - BiomeComponent component, - EntityUid gridUid, - MapGridComponent grid, - Vector2i chunk, - int seed) - { - // Load any pending marker tiles first. - if (!component.PendingMarkers.TryGetValue(chunk, out var layers)) - return; - - // This needs to be done separately in case we try to add a marker layer and want to force it on existing - // loaded chunks. - component.ModifiedTiles.TryGetValue(chunk, out var modified); - modified ??= _tilePool.Get(); - - foreach (var (layer, nodes) in layers) - { - var layerProto = ProtoManager.Index(layer); - - foreach (var node in nodes) - { - if (modified.Contains(node)) - continue; - - // Need to ensure the tile under it has loaded for anchoring. - if (TryGetBiomeTile(node, component.Layers, seed, (gridUid, grid), out var tile)) - { - _mapSystem.SetTile(gridUid, grid, node, tile.Value); - } - - string? prototype; - - if (TryGetEntity(node, component, (gridUid, grid), out var proto) && - layerProto.EntityMask.TryGetValue(proto, out var maskedProto)) - { - prototype = maskedProto; - } - else - { - prototype = layerProto.Prototype; - } - - // If it is a ghost role then purge it - // TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work. - // Ideally we'd just have ghost role and non-ghost role variants for some stuff. - var uid = EntityManager.CreateEntityUninitialized(prototype, _mapSystem.GridTileToLocal(gridUid, grid, node)); - RemComp(uid); - RemComp(uid); - EntityManager.InitializeAndStartEntity(uid); - modified.Add(node); - } - } - - if (modified.Count == 0) - { - component.ModifiedTiles.Remove(chunk); - _tilePool.Return(modified); - } - - component.PendingMarkers.Remove(chunk); - } - - /// - /// Loads a particular queued chunk for a biome. - /// - private void LoadChunk( - BiomeComponent component, - EntityUid gridUid, - MapGridComponent grid, - Vector2i chunk, - int seed) - { - component.ModifiedTiles.TryGetValue(chunk, out var modified); - modified ??= _tilePool.Get(); - _tiles.Clear(); - - // Set tiles first - for (var x = 0; x < ChunkSize; x++) - { - for (var y = 0; y < ChunkSize; y++) - { - var indices = new Vector2i(x + chunk.X, y + chunk.Y); - - // Pass in null so we don't try to get the tileref. - if (modified.Contains(indices)) - continue; - - // If there's existing data then don't overwrite it. - if (_mapSystem.TryGetTileRef(gridUid, grid, indices, out var tileRef) && !tileRef.Tile.IsEmpty) - continue; - - if (!TryGetBiomeTile(indices, component.Layers, seed, (gridUid, grid), out var biomeTile)) - continue; - - _tiles.Add((indices, biomeTile.Value)); - } - } - - _mapSystem.SetTiles(gridUid, grid, _tiles); - _tiles.Clear(); - - // Now do entities - var loadedEntities = new Dictionary(); - component.LoadedEntities.Add(chunk, loadedEntities); - - for (var x = 0; x < ChunkSize; x++) - { - for (var y = 0; y < ChunkSize; y++) - { - var indices = new Vector2i(x + chunk.X, y + chunk.Y); - - if (modified.Contains(indices)) - continue; - - // Don't mess with anything that's potentially anchored. - var anchored = _mapSystem.GetAnchoredEntitiesEnumerator(gridUid, grid, indices); - - if (anchored.MoveNext(out _) || !TryGetEntity(indices, component, (gridUid, grid), out var entPrototype)) - continue; - - // TODO: Fix non-anchored ents spawning. - // Just track loaded chunks for now. - var ent = Spawn(entPrototype, _mapSystem.GridTileToLocal(gridUid, grid, indices)); - - // At least for now unless we do lookups or smth, only work with anchoring. - if (_xformQuery.TryGetComponent(ent, out var xform) && !xform.Anchored) - { - _transform.AnchorEntity((ent, xform), (gridUid, grid), indices); - } - - loadedEntities.Add(ent, indices); - } - } - - // Decals - var loadedDecals = new Dictionary(); - component.LoadedDecals.Add(chunk, loadedDecals); - - for (var x = 0; x < ChunkSize; x++) - { - for (var y = 0; y < ChunkSize; y++) - { - var indices = new Vector2i(x + chunk.X, y + chunk.Y); - - if (modified.Contains(indices)) - continue; - - // Don't mess with anything that's potentially anchored. - var anchored = _mapSystem.GetAnchoredEntitiesEnumerator(gridUid, grid, indices); - - if (anchored.MoveNext(out _) || !TryGetDecals(indices, component.Layers, seed, (gridUid, grid), out var decals)) - continue; - - foreach (var decal in decals) - { - if (!_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out var dec)) - continue; - - loadedDecals.Add(dec, indices); - } - } - } - - if (modified.Count == 0) - { - _tilePool.Return(modified); - component.ModifiedTiles.Remove(chunk); - } - else - { - component.ModifiedTiles[chunk] = modified; - } - } - - #endregion - - #region Unload - - /// - /// Handles all of the queued chunk unloads for a particular biome. - /// - private void UnloadChunks(BiomeComponent component, EntityUid gridUid, MapGridComponent grid, int seed) - { - var active = _activeChunks[component]; - List<(Vector2i, Tile)>? tiles = null; - - foreach (var chunk in component.LoadedChunks) - { - if (active.Contains(chunk) || !component.LoadedChunks.Remove(chunk)) - continue; - - // Unload NOW! - tiles ??= new List<(Vector2i, Tile)>(ChunkSize * ChunkSize); - UnloadChunk(component, gridUid, grid, chunk, seed, tiles); - } - } - - /// - /// Unloads a specific biome chunk. - /// - private void UnloadChunk(BiomeComponent component, EntityUid gridUid, MapGridComponent grid, Vector2i chunk, int seed, List<(Vector2i, Tile)> tiles) - { - // Reverse order to loading - component.ModifiedTiles.TryGetValue(chunk, out var modified); - modified ??= new HashSet(); - - // Delete decals - foreach (var (dec, indices) in component.LoadedDecals[chunk]) - { - // If we couldn't remove it then flag the tile to never be touched. - if (!_decals.RemoveDecal(gridUid, dec)) - { - modified.Add(indices); - } - } - - component.LoadedDecals.Remove(chunk); - - // Delete entities - // Ideally any entities that aren't modified just get deleted and re-generated later - // This is because if we want to save the map (e.g. persistent server) it makes the file much smaller - // and also if the map is enormous will make stuff like physics broadphase much faster - var xformQuery = GetEntityQuery(); - - foreach (var (ent, tile) in component.LoadedEntities[chunk]) - { - if (Deleted(ent) || !xformQuery.TryGetComponent(ent, out var xform)) - { - modified.Add(tile); - continue; - } - - // It's moved - var entTile = _mapSystem.LocalToTile(gridUid, grid, xform.Coordinates); - - if (!xform.Anchored || entTile != tile) - { - modified.Add(tile); - continue; - } - - if (!EntityManager.IsDefault(ent)) - { - modified.Add(tile); - continue; - } - - Del(ent); - } - - component.LoadedEntities.Remove(chunk); - - // Unset tiles (if the data is custom) - - for (var x = 0; x < ChunkSize; x++) - { - for (var y = 0; y < ChunkSize; y++) - { - var indices = new Vector2i(x + chunk.X, y + chunk.Y); - - if (modified.Contains(indices)) - continue; - - // Don't mess with anything that's potentially anchored. - var anchored = _mapSystem.GetAnchoredEntitiesEnumerator(gridUid, grid, indices); - - if (anchored.MoveNext(out _)) - { - modified.Add(indices); - continue; - } - - // If it's default data unload the tile. - if (!TryGetBiomeTile(indices, component.Layers, seed, null, out var biomeTile) || - _mapSystem.TryGetTileRef(gridUid, grid, indices, out var tileRef) && tileRef.Tile != biomeTile.Value) - { - modified.Add(indices); - continue; - } - - tiles.Add((indices, Tile.Empty)); - } - } - - _mapSystem.SetTiles(gridUid, grid, tiles); - tiles.Clear(); - component.LoadedChunks.Remove(chunk); - - if (modified.Count == 0) - { - component.ModifiedTiles.Remove(chunk); - } - else - { - component.ModifiedTiles[chunk] = modified; - } - } - - #endregion - - /// - /// Creates a simple planet setup for a map. - /// - public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, int? seed = null, MetaDataComponent? metadata = null, Color? mapLight = null) - { - if (!Resolve(mapUid, ref metadata)) - return; - - EnsureComp(mapUid); - var biome = EntityManager.ComponentFactory.GetComponent(); - seed ??= _random.Next(); - SetSeed(mapUid, biome, seed.Value, false); - SetTemplate(mapUid, biome, biomeTemplate, false); - AddComp(mapUid, biome, true); - Dirty(mapUid, biome, metadata); - - var gravity = EnsureComp(mapUid); - gravity.Enabled = true; - gravity.Inherent = true; - Dirty(mapUid, gravity, metadata); - - // Day lighting - // Daylight: #D8B059 - // Midday: #E6CB8B - // Moonlight: #2b3143 - // Lava: #A34931 - var light = EnsureComp(mapUid); - light.AmbientLightColor = mapLight ?? Color.FromHex("#D8B059"); - Dirty(mapUid, light, metadata); - - EnsureComp(mapUid); - - EnsureComp(mapUid); - - EnsureComp(mapUid); - EnsureComp(mapUid); - - var moles = new float[Atmospherics.AdjustedNumberOfGases]; - moles[(int)Gas.Oxygen] = 21.824779f; - moles[(int)Gas.Nitrogen] = 82.10312f; - - var mixture = new GasMixture(moles, Atmospherics.T20C); - - _atmos.SetMapAtmosphere(mapUid, false, mixture); - } - - /// - /// Sets the specified tiles as relevant and marks them as modified. - /// - public void ReserveTiles(EntityUid mapUid, Box2 bounds, List<(Vector2i Index, Tile Tile)> tiles, BiomeComponent? biome = null, MapGridComponent? mapGrid = null) - { - if (!Resolve(mapUid, ref biome, ref mapGrid, false)) - return; - - foreach (var tileSet in _mapSystem.GetLocalTilesIntersecting(mapUid, mapGrid, bounds, false)) - { - Vector2i chunkOrigin; - HashSet modified; - - // Existing, ignore - if (_mapSystem.TryGetTileRef(mapUid, mapGrid, tileSet.GridIndices, out var existingRef) && !existingRef.Tile.IsEmpty) - { - chunkOrigin = SharedMapSystem.GetChunkIndices(tileSet.GridIndices, ChunkSize) * ChunkSize; - modified = biome.ModifiedTiles.GetOrNew(chunkOrigin); - modified.Add(tileSet.GridIndices); - continue; - } - - if (!TryGetBiomeTile(tileSet.GridIndices, biome.Layers, biome.Seed, (mapUid, mapGrid), out var tile)) - { - continue; - } - - chunkOrigin = SharedMapSystem.GetChunkIndices(tileSet.GridIndices, ChunkSize) * ChunkSize; - modified = biome.ModifiedTiles.GetOrNew(chunkOrigin); - modified.Add(tileSet.GridIndices); - tiles.Add((tileSet.GridIndices, tile.Value)); - } - - _mapSystem.SetTiles(mapUid, mapGrid, tiles); - } -} diff --git a/Content.Server/Procedural/BiomeSystem.Commands.cs b/Content.Server/Procedural/BiomeSystem.Commands.cs new file mode 100644 index 0000000000..ef90310483 --- /dev/null +++ b/Content.Server/Procedural/BiomeSystem.Commands.cs @@ -0,0 +1,105 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Components; +using Robust.Shared.Console; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.Server.Procedural; + +public sealed partial class BiomeSystem +{ + [AdminCommand(AdminFlags.Mapping)] + public sealed class BiomeAddLayerCommand : LocalizedEntityCommands + { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + + public override string Command => "biome_addlayer"; + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 3) + { + shell.WriteError(Help); + return; + } + + if (!int.TryParse(args[0], out var entInt)) + { + return; + } + + var entId = new EntityUid(entInt); + + if (!EntityManager.TryGetComponent(entId, out BiomeComponent? biome)) + { + return; + } + + if (!_protoManager.TryIndex(args[2], out DungeonConfigPrototype? config)) + { + return; + } + + var system = EntityManager.System(); + system.AddLayer((entId, biome), args[1], config); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + switch (args.Length) + { + case 1: + return CompletionResult.FromOptions(CompletionHelper.Components(args[0])); + case 2: + return CompletionResult.FromHint("layerId"); + case 3: + return CompletionResult.FromOptions(CompletionHelper.PrototypeIDs()); + } + + return CompletionResult.Empty; + } + } + + [AdminCommand(AdminFlags.Mapping)] + public sealed class BiomeRemoveLayerCommand : LocalizedEntityCommands + { + public override string Command => "biome_removelayer"; + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 2) + { + shell.WriteError(Help); + return; + } + + if (!int.TryParse(args[0], out var entInt)) + { + return; + } + + var entId = new EntityUid(entInt); + + if (!EntityManager.TryGetComponent(entId, out BiomeComponent? biome)) + { + return; + } + + var system = EntityManager.System(); + system.RemoveLayer((entId, biome), args[1]); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + switch (args.Length) + { + case 0: + return CompletionResult.FromOptions(CompletionHelper.Components(args[0])); + case 1: + return CompletionResult.FromHint("layerId"); + } + + return CompletionResult.Empty; + } + } +} diff --git a/Content.Server/Procedural/BiomeSystem.Planet.cs b/Content.Server/Procedural/BiomeSystem.Planet.cs new file mode 100644 index 0000000000..c5138ca04e --- /dev/null +++ b/Content.Server/Procedural/BiomeSystem.Planet.cs @@ -0,0 +1,65 @@ +using Content.Shared.Atmos; +using Content.Shared.Gravity; +using Content.Shared.Light.Components; +using Content.Shared.Procedural.Components; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; + +namespace Content.Server.Procedural; + +public sealed partial class BiomeSystem +{ + /// + /// Copies the biomecomponent to the specified map. + /// + public BiomeComponent? AddBiome(Entity mapUid, EntProtoId biomeTemplate, int? seed = null) + { + if (!_protomanager.Index(biomeTemplate).Components.TryGetComponent(Factory.GetComponentName(), out var template)) + { + return null; + } + + var biome = Factory.GetComponent(); + var biomeObj = (object)biome; + _serManager.CopyTo(template, ref biomeObj, notNullableOverride: true); + seed ??= _random.Next(); + biome.Seed = seed.Value; + AddComp(mapUid, biome, true); + return biome; + } + + /// + /// Creates a simple planet setup for a map. + /// + public void EnsurePlanet(EntityUid mapUid, EntProtoId biomeTemplate, int? seed = null, MetaDataComponent? metadata = null, Color? mapLight = null) + { + if (!Resolve(mapUid, ref metadata)) + return; + + EnsureComp(mapUid); + AddBiome(mapUid, biomeTemplate, seed); + var gravity = EnsureComp(mapUid); + gravity.Enabled = true; + gravity.Inherent = true; + Dirty(mapUid, gravity, metadata); + + var light = EnsureComp(mapUid); + light.AmbientLightColor = mapLight ?? Color.FromHex("#D8B059"); + Dirty(mapUid, light, metadata); + + EnsureComp(mapUid); + + EnsureComp(mapUid); + + EnsureComp(mapUid); + EnsureComp(mapUid); + + var moles = new float[Atmospherics.AdjustedNumberOfGases]; + moles[(int)Gas.Oxygen] = 21.824779f; + moles[(int)Gas.Nitrogen] = 82.10312f; + + var mixture = new GasMixture(moles, Atmospherics.T20C); + + _atmos.SetMapAtmosphere(mapUid, false, mixture); + } +} diff --git a/Content.Server/Procedural/BiomeSystem.cs b/Content.Server/Procedural/BiomeSystem.cs new file mode 100644 index 0000000000..6d584ad3b2 --- /dev/null +++ b/Content.Server/Procedural/BiomeSystem.cs @@ -0,0 +1,661 @@ +using System.Numerics; +using System.Threading; +using System.Threading.Tasks; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Decals; +using Content.Server.Shuttles.Events; +using Content.Shared.CCVar; +using Content.Shared.Decals; +using Content.Shared.Ghost; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Components; +using Content.Shared.Procedural.DungeonGenerators; +using Content.Shared.Sprite; +using Content.Shared.Tag; +using Robust.Server.Player; +using Robust.Shared.Configuration; +using Robust.Shared.CPUJob.JobQueues; +using Robust.Shared.CPUJob.JobQueues.Queues; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Map.Enumerators; +using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural; + +public sealed partial class BiomeSystem : EntitySystem +{ + /* + * Handles loading in biomes around players. + * These are essentially chunked-areas that load in dungeons and can also be unloaded. + */ + + [Dependency] private readonly IConfigurationManager _cfgManager = default!; + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _protomanager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] private readonly AtmosphereSystem _atmos = default!; + [Dependency] private readonly SharedMapSystem _maps = default!; + [Dependency] private readonly TagSystem _tags = default!; + [Dependency] private readonly SharedTransformSystem _xforms = default!; + + /// + /// Ignored components for default checks + /// + public static readonly List IgnoredComponents = new(); + + /// + /// Jobs for biomes to load. + /// + private JobQueue _biomeQueue = default!; + + private float _loadRange = 1f; + private float _loadTime; + + private EntityQuery _ghostQuery; + private EntityQuery _biomeQuery; + + private static readonly ProtoId AllowBiomeLoadingTag = "AllowBiomeLoading"; + + public override void Initialize() + { + base.Initialize(); + _ghostQuery = GetEntityQuery(); + _biomeQuery = GetEntityQuery(); + + IgnoredComponents.Add(Factory.GetComponentName()); + + Subs.CVar(_cfgManager, CCVars.BiomeLoadRange, OnLoadRange, true); + Subs.CVar(_cfgManager, CCVars.BiomeLoadTime, OnLoadTime, true); + + SubscribeLocalEvent(OnFTLStarted); + } + + private void OnLoadTime(float obj) + { + _biomeQueue = new JobQueue(obj); + _loadTime = obj; + } + + private void OnLoadRange(float obj) + { + _loadRange = obj; + } + + private void OnFTLStarted(ref FTLStartedEvent ev) + { + var targetMap = _xforms.ToMapCoordinates(ev.TargetCoordinates); + var targetMapUid = _maps.GetMapOrInvalid(targetMap.MapId); + + if (!TryComp(targetMapUid, out var biome)) + return; + + var preloadArea = new Vector2(32f, 32f); + var targetArea = new Box2(targetMap.Position - preloadArea, targetMap.Position + preloadArea); + Preload(targetMapUid, biome, (Box2i) targetArea); + } + + /// + /// Preloads biome for the specified area. + /// + public void Preload(EntityUid uid, BiomeComponent component, Box2i area) + { + component.PreloadAreas.Add(area); + } + + private bool CanLoad(EntityUid uid) + { + return !_ghostQuery.HasComp(uid) || _tags.HasTag(uid, AllowBiomeLoadingTag); + } + + public bool RemoveLayer(Entity biome, string label) + { + if (!Resolve(biome.Owner, ref biome.Comp)) + return false; + + if (!biome.Comp.Layers.ContainsKey(label)) + { + return false; + } + + // Technically this can race-condition with adds but uhh tell people to not do that. + biome.Comp.PendingRemovals.Add(label); + return true; + } + + public void AddLayer(Entity biome, string label, BiomeMetaLayer layer) + { + if (!Resolve(biome.Owner, ref biome.Comp)) + return; + + if (!biome.Comp.Layers.TryAdd(label, layer)) + { + Log.Warning($"Tried to add layer {label} to biome {ToPrettyString(biome)} that already has it?"); + return; + } + } + + public void AddLayer(Entity biome, string label, ProtoId layer) + { + if (!Resolve(biome.Owner, ref biome.Comp)) + return; + + var metaLayer = new BiomeMetaLayer() + { + Dungeon = layer, + }; + + AddLayer(biome, label, metaLayer); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = AllEntityQuery(); + + while (query.MoveNext(out var biome)) + { + // If it's still loading then don't touch the observer bounds. + if (biome.Loading) + continue; + + biome.LoadedBounds.Clear(); + + // Make sure preloads go in. + foreach (var preload in biome.PreloadAreas) + { + biome.LoadedBounds.Add(preload); + } + } + + // Get all relevant players. + foreach (var player in _player.Sessions) + { + if (player.AttachedEntity != null) + { + TryAddBiomeBounds(player.AttachedEntity.Value); + } + + foreach (var viewer in player.ViewSubscriptions) + { + TryAddBiomeBounds(viewer); + } + } + + // Unload first in case we can't catch up. + UnloadChunks(); + + var loadQuery = AllEntityQuery(); + + // Check if any biomes are intersected and queue up loads. + while (loadQuery.MoveNext(out var uid, out var biome, out var grid)) + { + if (biome.Loading || biome.LoadedBounds.Count == 0) + continue; + + biome.Loading = true; + var job = new BiomeLoadJob(_loadTime) + { + Grid = (uid, biome, grid), + }; + _biomeQueue.EnqueueJob(job); + } + + // Process jobs. + _biomeQueue.Process(); + } + + private void UnloadChunks() + { + var query = AllEntityQuery(); + + while (query.MoveNext(out var uid, out var biome, out var grid)) + { + // Only start unloading if it's currently not loading anything. + if (biome.Loading) + continue; + + var toUnload = new Dictionary>(); + + foreach (var (layerId, loadedLayer) in biome.LoadedData) + { + var layer = biome.Layers[layerId]; + + // If it can't unload then ignore it. + if (!layer.CanUnload) + continue; + + var size = GetSize(_protomanager.Index(layer.Dungeon), layer); + + if (size == null) + continue; + + // Go through each loaded chunk and check if they can be unloaded by checking if any players are in range. + foreach (var chunk in loadedLayer.Keys) + { + var chunkBounds = new Box2i(chunk, chunk + size.Value); + var canUnload = true; + + foreach (var playerView in biome.LoadedBounds) + { + // Give a buffer range so we don't immediately unload if we wiggle, we'll just double the load area. + var enlarged = playerView.Enlarged((int) _loadRange); + + // Still relevant + if (chunkBounds.Intersects(enlarged)) + { + canUnload = false; + break; + } + } + + if (!canUnload) + continue; + + toUnload.GetOrNew(layerId).Add(chunk); + } + } + + if (biome.PendingRemovals.Count > 0) + { + foreach (var label in biome.PendingRemovals) + { + var bounds = toUnload.GetOrNew(label); + + foreach (var chunkOrigin in biome.LoadedData[label].Keys) + { + bounds.Add(chunkOrigin); + } + } + } + + if (toUnload.Count == 0) + continue; + + // Queue up unloads. + biome.Loading = true; + var job = new BiomeUnloadJob(_loadTime) + { + Biome = (uid, grid, biome), + ToUnload = toUnload, + }; + _biomeQueue.EnqueueJob(job); + } + } + + /// + /// Gets the full bounds to be loaded. Considers layer dependencies where they may have different chunk sizes. + /// + private Box2i GetFullBounds(BiomeComponent component, Box2i bounds) + { + var result = bounds; + + foreach (var layer in component.Layers.Values) + { + var layerBounds = GetLayerBounds(layer, result); + + if (layer.DependsOn != null) + { + foreach (var sub in layer.DependsOn) + { + var depLayer = component.Layers[sub]; + + layerBounds = layerBounds.Union(GetLayerBounds(depLayer, layerBounds)); + } + } + + result = result.Union(layerBounds); + } + + return result; + } + + /// + /// Tries to add the viewer bounds of this entity for loading. + /// + private void TryAddBiomeBounds(EntityUid uid) + { + if (!CanLoad(uid)) + return; + + var xform = Transform(uid); + + // No biome to load + if (!_biomeQuery.TryComp(xform.MapUid, out var biome)) + return; + + // Currently already loading. + if (biome.Loading) + return; + + var center = _xforms.GetWorldPosition(uid); + + var bounds = new Box2i((center - new Vector2(_loadRange, _loadRange)).Floored(), (center + new Vector2(_loadRange, _loadRange)).Floored()); + + // If it's moving then preload in that direction + if (TryComp(uid, out PhysicsComponent? physics)) + { + bounds = bounds.Union(bounds.Translated((physics.LinearVelocity * 2f).Floored())); + } + + var adjustedBounds = GetFullBounds(biome, bounds); + biome.LoadedBounds.Add(adjustedBounds); + } + + public int? GetSize(DungeonConfigPrototype config, BiomeMetaLayer layer) + { + var size = layer.Size; + + if (size == null && config.Layers[0] is ChunkDunGen chunkGen) + { + size = chunkGen.Size; + } + // No size + else + { + Log.Warning($"Unable to infer chunk size for biome {layer} / config {config.ID}"); + return null; + } + + return size.Value; + } + + public Box2i GetLayerBounds(BiomeMetaLayer layer, Box2i layerBounds) + { + var size = GetSize(_protomanager.Index(layer.Dungeon), layer); + + if (size == null) + return Box2i.Empty; + + var chunkSize = new Vector2(size.Value, size.Value); + + // Need to round the bounds to our chunk size to ensure we load whole chunks. + // We also need to know the minimum bounds for our dependencies to load. + var layerBL = (layerBounds.BottomLeft / chunkSize).Floored() * chunkSize; + var layerTR = (layerBounds.TopRight / chunkSize).Ceiled() * chunkSize; + + var loadBounds = new Box2i(layerBL.Floored(), layerTR.Ceiled()); + return loadBounds; + } +} + + public sealed class BiomeLoadJob : Job + { + [Dependency] private IEntityManager _entManager = default!; + [Dependency] private IPrototypeManager _protoManager = default!; + + private BiomeSystem System = default!; + private DungeonSystem DungeonSystem = default!; + + public Entity Grid; + + internal ISawmill _sawmill = default!; + + public BiomeLoadJob(double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation) + { + IoCManager.InjectDependencies(this); + System = _entManager.System(); + DungeonSystem = _entManager.System(); + } + + protected override async Task Process() + { + try + { + foreach (var bound in Grid.Comp1.LoadedBounds) + { + foreach (var (layerId, layer) in Grid.Comp1.Layers) + { + await LoadLayer(layerId, layer, bound); + } + } + } + finally + { + // Finished + DebugTools.Assert(Grid.Comp1.Loading); + Grid.Comp1.Loading = false; + } + + // If we have any preloads then mark those as modified so they persist. + foreach (var preload in Grid.Comp1.PreloadAreas) + { + for (var x = preload.Left; x <= preload.Right; x++) + { + for (var y = preload.Bottom; y <= preload.Top; y++) + { + var index = new Vector2i(x, y); + Grid.Comp1.ModifiedTiles.Add(index); + } + } + + await SuspendIfOutOfTime(); + } + + Grid.Comp1.PreloadAreas.Clear(); + + return true; + } + + private async Task LoadLayer(string layerId, BiomeMetaLayer layer, Box2i parentBounds) + { + // Nothing to do + var dungeon = _protoManager.Index(layer.Dungeon); + + if (dungeon.Layers.Count == 0) + return; + + var loadBounds = System.GetLayerBounds(layer, parentBounds); + + // Make sure our dependencies are loaded first. + if (layer.DependsOn != null) + { + foreach (var sub in layer.DependsOn) + { + var actualLayer = Grid.Comp1.Layers[sub]; + + await LoadLayer(sub, actualLayer, loadBounds); + } + } + + var size = System.GetSize(dungeon, layer); + + if (size == null) + return; + + // The reason we do this is so if we dynamically add similar layers (e.g. we add 3 mob layers at runtime) + // they don't all have the same seeds. + var layerSeed = Grid.Comp1.Seed + layerId.GetHashCode(); + + // Okay all of our dependencies loaded so we can send it. + var chunkEnumerator = new NearestChunkEnumerator(loadBounds, size.Value); + + while (chunkEnumerator.MoveNext(out var chunk)) + { + var chunkOrigin = chunk.Value; + var layerLoaded = Grid.Comp1.LoadedData.GetOrNew(layerId); + + // Layer already loaded for this chunk. + // This can potentially happen if we're moving and the player's bounds changed but some existing chunks remain. + if (layerLoaded.ContainsKey(chunkOrigin)) + { + continue; + } + + // Load dungeon here async await and all that jaz. + var (_, data) = await WaitAsyncTask(DungeonSystem + .GenerateDungeonAsync(dungeon, Grid.Owner, Grid.Comp2, chunkOrigin, layerSeed, reservedTiles: Grid.Comp1.ModifiedTiles)); + + // If we can unload it then store the data to check for later. + if (layer.CanUnload) + { + layerLoaded.Add(chunkOrigin, data); + } + } + } +} + +public sealed class BiomeUnloadJob : Job +{ + [Dependency] private EntityManager _entManager = default!; + + public Entity Biome; + public Dictionary> ToUnload = default!; + + public BiomeUnloadJob(double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation) + { + IoCManager.InjectDependencies(this); + } + + public BiomeUnloadJob(double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation) + { + } + + protected override async Task Process() + { + try + { + var grid = Biome.Comp1; + var biome = Biome.Comp2; + DebugTools.Assert(biome.Loading); + var maps = _entManager.System(); + var decals = _entManager.System(); + var lookup = _entManager.System(); + _entManager.TryGetComponent(Biome.Owner, out DecalGridComponent? decalGrid); + var forceUnload = _entManager.GetEntityQuery(); + var entities = new HashSet(); + var tiles = new List<(Vector2i, Tile)>(); + + foreach (var (layer, chunkOrigins) in ToUnload) + { + if (!biome.Layers.TryGetValue(layer, out var meta)) + continue; + + if (!biome.LoadedData.TryGetValue(layer, out var data)) + continue; + + DebugTools.Assert(meta.CanUnload); + + foreach (var chunk in chunkOrigins) + { + // Not loaded anymore? + if (!data.Remove(chunk, out var loaded)) + continue; + + tiles.Clear(); + + foreach (var (ent, pos) in loaded.Entities) + { + // Already flagged as modified so go next. + if (biome.ModifiedTiles.Contains(pos)) + { + continue; + } + + // IsDefault is actually super expensive so really need to run this check in the loop. + await SuspendIfOutOfTime(); + + if (forceUnload.HasComp(ent)) + { + _entManager.DeleteEntity(ent); + continue; + } + + // Deleted so counts as modified. + if (!_entManager.TransformQuery.TryComp(ent, out var xform)) + { + biome.ModifiedTiles.Add(pos); + continue; + } + + // If it stayed still and had no data change then keep it. + if (pos == xform.LocalPosition.Floored() && xform.GridUid == Biome.Owner && _entManager.IsDefault(ent, BiomeSystem.IgnoredComponents)) + { + _entManager.DeleteEntity(ent); + continue; + } + + // Need the entity's current tile to be flagged for unloading. + if (Biome.Owner == xform.GridUid) + { + var entTile = maps.LocalToTile(Biome.Owner, grid, xform.Coordinates); + biome.ModifiedTiles.Add(entTile); + } + } + + foreach (var (decal, pos) in loaded.Decals) + { + // Modified go NEXT + if (biome.ModifiedTiles.Contains(pos.Floored())) + continue; + + // Should just be able to remove them as you can't actually edit a decal. + if (!decals.RemoveDecal(Biome.Owner, decal, decalGrid)) + { + biome.ModifiedTiles.Add(pos.Floored()); + } + } + + await SuspendIfOutOfTime(); + + foreach (var (index, tile) in loaded.Tiles) + { + await SuspendIfOutOfTime(); + + if (Biome.Comp2.ModifiedTiles.Contains(index)) + { + continue; + } + + if (!maps.TryGetTileRef(Biome.Owner, Biome.Comp1, index, out var tileRef) || + tileRef.Tile != tile) + { + Biome.Comp2.ModifiedTiles.Add(index); + continue; + } + + entities.Clear(); + var tileBounds = lookup.GetLocalBounds(index, Biome.Comp1.TileSize).Enlarged(-0.05f); + + lookup.GetEntitiesIntersecting(Biome.Owner, + tileBounds, + entities); + + // Still entities remaining so just leave the tile. + if (entities.Count > 0) + { + Biome.Comp2.ModifiedTiles.Add(index); + continue; + } + + if (decals.GetDecalsIntersecting(Biome.Owner, tileBounds, component: decalGrid).Count > 0) + { + Biome.Comp2.ModifiedTiles.Add(index); + continue; + } + + // Clear it + tiles.Add((index, Tile.Empty)); + } + + maps.SetTiles(Biome.Owner, Biome.Comp1, tiles); + } + } + } + finally + { + Biome.Comp2.Loading = false; + } + + Biome.Comp2.PendingRemovals.Clear(); + + return true; + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs index 8c49a7d606..83ff71f8b7 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.AutoCabling.cs @@ -151,7 +151,8 @@ public sealed partial class DungeonJob if (found) continue; - _entManager.SpawnEntity(gen.Entity, _maps.GridTileToLocal(_gridUid, _grid, tile)); + var ent = _entManager.SpawnEntity(gen.Entity, _maps.GridTileToLocal(_gridUid, _grid, tile)); + AddLoadedEntity(tile, ent); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs deleted file mode 100644 index 48adb8af18..0000000000 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Biome.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Threading.Tasks; -using Content.Server.Parallax; -using Content.Shared.Maps; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Procedural; -using Content.Shared.Procedural.PostGeneration; -using Robust.Shared.Map; -using Robust.Shared.Utility; - -namespace Content.Server.Procedural.DungeonJob; - -public sealed partial class DungeonJob -{ - /// - /// - /// - private async Task PostGen(BiomeDunGen dunGen, Dungeon dungeon, HashSet reservedTiles, Random random) - { - if (!_prototype.TryIndex(dunGen.BiomeTemplate, out var indexedBiome)) - return; - - var biomeSystem = _entManager.System(); - - var seed = random.Next(); - var xformQuery = _entManager.GetEntityQuery(); - - var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); - while (tiles.MoveNext(out var tileRef)) - { - var node = tileRef.Value.GridIndices; - - if (reservedTiles.Contains(node)) - continue; - - if (dunGen.TileMask is not null) - { - if (!dunGen.TileMask.Contains(((ContentTileDefinition)_tileDefManager[tileRef.Value.Tile.TypeId]).ID)) - continue; - } - - // Need to set per-tile to override data. - if (biomeSystem.TryGetTile(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var tile)) - { - _maps.SetTile(_gridUid, _grid, node, tile.Value); - } - - if (biomeSystem.TryGetDecals(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var decals)) - { - foreach (var decal in decals) - { - _decals.TryAddDecal(decal.ID, new EntityCoordinates(_gridUid, decal.Position), out _); - } - } - - if (biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile ?? tileRef.Value.Tile, seed, (_gridUid, _grid), out var entityProto)) - { - var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector)); - var xform = xformQuery.Get(ent); - - if (!xform.Comp.Anchored) - { - _transform.AnchorEntity(ent, xform); - } - - // TODO: Engine bug with SpawnAtPosition - DebugTools.Assert(xform.Comp.Anchored); - } - - await SuspendDungeon(); - if (!ValidateResume()) - return; - } - } -} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs deleted file mode 100644 index abc74ddc4f..0000000000 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.BiomeMarkerLayer.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Threading.Tasks; -using Content.Server.Parallax; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Parallax.Biomes.Markers; -using Content.Shared.Procedural; -using Content.Shared.Procedural.PostGeneration; -using Content.Shared.Random.Helpers; -using Robust.Shared.Map; -using Robust.Shared.Utility; - -namespace Content.Server.Procedural.DungeonJob; - -public sealed partial class DungeonJob -{ - /// - /// - /// - private async Task PostGen(BiomeMarkerLayerDunGen dunGen, Dungeon dungeon, HashSet reservedTiles, Random random) - { - // If we're adding biome then disable it and just use for markers. - if (_entManager.EnsureComponent(_gridUid, out BiomeComponent biomeComp)) - { - biomeComp.Enabled = false; - } - - var biomeSystem = _entManager.System(); - var weightedRandom = _prototype.Index(dunGen.MarkerTemplate); - var xformQuery = _entManager.GetEntityQuery(); - var templates = new Dictionary(); - - for (var i = 0; i < dunGen.Count; i++) - { - var template = weightedRandom.Pick(random); - var count = templates.GetOrNew(template); - count++; - templates[template] = count; - } - - foreach (var (template, count) in templates) - { - var markerTemplate = _prototype.Index(template); - - var bounds = new Box2i(); - - foreach (var tile in dungeon.RoomTiles) - { - bounds = bounds.UnionTile(tile); - } - - await SuspendDungeon(); - if (!ValidateResume()) - return; - - biomeSystem.GetMarkerNodes(_gridUid, biomeComp, _grid, markerTemplate, true, bounds, count, - random, out var spawnSet, out var existing, false); - - await SuspendDungeon(); - if (!ValidateResume()) - return; - - var checkTile = reservedTiles.Count > 0; - - foreach (var ent in existing) - { - if (checkTile && reservedTiles.Contains(_maps.LocalToTile(_gridUid, _grid, _xformQuery.GetComponent(ent).Coordinates))) - { - continue; - } - - _entManager.DeleteEntity(ent); - - await SuspendDungeon(); - if (!ValidateResume()) - return; - } - - foreach (var (node, mask) in spawnSet) - { - if (reservedTiles.Contains(node)) - continue; - - string? proto; - - if (mask != null && markerTemplate.EntityMask.TryGetValue(mask, out var maskedProto)) - { - proto = maskedProto; - } - else - { - proto = markerTemplate.Prototype; - } - - var ent = _entManager.SpawnAtPosition(proto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector)); - var xform = xformQuery.Get(ent); - - if (!xform.Comp.Anchored) - _transform.AnchorEntity(ent, xform); - - await SuspendDungeon(); - if (!ValidateResume()) - return; - } - } - } -} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs index 1c48a84cce..7bc7527ff5 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.BoundaryWall.cs @@ -32,7 +32,10 @@ public sealed partial class DungeonJob if (!_anchorable.TileFree((_gridUid, _grid), neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) continue; - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + tiles.Add((neighbor, tile)); + AddLoadedTile(neighbor, tile); + DebugTools.Assert(dungeon.AllTiles.Contains(neighbor)); } foreach (var index in dungeon.CorridorExteriorTiles) @@ -43,7 +46,10 @@ public sealed partial class DungeonJob if (!_anchorable.TileFree((_gridUid, _grid), index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) continue; - tiles.Add((index, _tile.GetVariantTile((ContentTileDefinition)tileDef, random))); + var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + tiles.Add((index, tile)); + AddLoadedTile(index, tile); + DebugTools.Assert(dungeon.AllTiles.Contains(index)); } _maps.SetTiles(_gridUid, _grid, tiles); @@ -82,18 +88,21 @@ public sealed partial class DungeonJob } if (isCorner) - _entManager.SpawnEntity(cornerWall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); + { + var uid = _entManager.SpawnEntity(cornerWall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); + AddLoadedEntity(index.Index, uid); + } if (!isCorner) - _entManager.SpawnEntity(wall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); - - if (i % 20 == 0) { - await SuspendDungeon(); - - if (!ValidateResume()) - return; + var uid = _entManager.SpawnEntity(wall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); + AddLoadedEntity(index.Index, uid); } + + await SuspendDungeon(); + + if (!ValidateResume()) + return; } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Chunk.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Chunk.cs new file mode 100644 index 0000000000..391fb9161b --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Chunk.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonGenerators; +using Content.Shared.Procedural.PostGeneration; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(ChunkDunGen dunGen, HashSet reservedTiles, Random random) + { + var dungeon = new Dungeon(); + var tiles = new HashSet(); + var tr = _position + new Vector2i(dunGen.Size, dunGen.Size); + var oldSeed = dunGen.Noise?.GetSeed() ?? 0; + dunGen.Noise?.SetSeed(_seed + oldSeed); + + for (var x = 0; x < dunGen.Size; x++) + { + for (var y = 0; y < dunGen.Size; y++) + { + var index = new Vector2i(_position.X + x, _position.Y + y); + + if (reservedTiles.Contains(index)) + continue; + + if (dunGen.Noise?.GetNoise(x, y) < dunGen.Threshold) + continue; + + tiles.Add(index); + } + } + + dunGen.Noise?.SetSeed(oldSeed); + var room = new DungeonRoom(tiles, (tr - _position) / 2 + _position, new Box2i(_position, tr), new HashSet()); + dungeon.AddRoom(room); + return dungeon; + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs index bf9f910b94..8353d81f16 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Corridor.cs @@ -94,12 +94,14 @@ public sealed partial class DungeonJob var setTiles = new List<(Vector2i, Tile)>(); var tileDef = (ContentTileDefinition) _tileDefManager[gen.Tile]; - foreach (var tile in corridorTiles) + foreach (var node in corridorTiles) { - if (reservedTiles.Contains(tile)) + if (reservedTiles.Contains(node)) continue; - setTiles.Add((tile, _tile.GetVariantTile(tileDef, random))); + var tile = _tile.GetVariantTile(tileDef, random); + setTiles.Add((node, tile)); + AddLoadedTile(node, tile); } _maps.SetTiles(_gridUid, _grid, setTiles); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs index e0be852733..e28c6798f2 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorClutter.cs @@ -48,7 +48,13 @@ public sealed partial class DungeonJob var protos = _entTable.GetSpawns(contents, random); var coords = _maps.ToCenterCoordinates(_gridUid, tile, _grid); - _entManager.SpawnEntitiesAttachedTo(coords, protos); + var uids = _entManager.SpawnEntitiesAttachedTo(coords, protos); + + foreach (var uid in uids) + { + AddLoadedEntity(tile, uid); + } + await SuspendIfOutOfTime(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs index cd8737e6ec..48088a4718 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.CorridorDecalSkirting.cs @@ -83,7 +83,8 @@ public sealed partial class DungeonJob { // Decals not being centered biting my ass again var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); + _decals.TryAddDecal(cDir, gridPos, out var did, color: decks.Color); + AddLoadedDecal(tile, did); } } @@ -96,7 +97,8 @@ public sealed partial class DungeonJob { // Decals not being centered biting my ass again var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); + _decals.TryAddDecal(cDir, gridPos, out var did, color: decks.Color); + AddLoadedDecal(tile, did); } continue; @@ -111,7 +113,8 @@ public sealed partial class DungeonJob if (decks.CornerDecals.TryGetValue(dirFlag, out var cDir)) { var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: decks.Color); + _decals.TryAddDecal(cDir, gridPos, out var did, color: decks.Color); + AddLoadedDecal(tile, did); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs index f1808ec90c..10481c5b5f 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs @@ -28,7 +28,7 @@ public sealed partial class DungeonJob Random random) { var tiles = new List<(Vector2i, Tile)>(); - var matrix = Matrix3Helpers.CreateTranslation(position); + var matrix = Matrix3Helpers.CreateTranslation(_position + position); foreach (var layer in dungen.Layers) { @@ -76,7 +76,9 @@ public sealed partial class DungeonJob break; } - tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant))); + var tile = new Tile(tileDef.TileId, variant: variant); + tiles.Add((adjusted, tile)); + AddLoadedTile(adjusted, tile); roomTiles.Add(adjusted); break; } @@ -101,6 +103,8 @@ public sealed partial class DungeonJob { switch (distance) { + case DunGenDistanceSquared: + return dx * dx + dy * dy; case DunGenEuclideanSquaredDistance: return MathF.Min(1f, (dx * dx + dy * dy) / MathF.Sqrt(2)); case DunGenSquareBump: diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs index 8eb85e2cb8..f348ce7301 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs @@ -196,7 +196,9 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(index)) continue; - tiles.Add((index, new Tile(_tileDefManager[fallbackTile.Value].TileId))); + var tile = new Tile(_tileDefManager[fallbackTile.Value].TileId); + tiles.Add((index, tile)); + AddLoadedTile(index, tile); } } @@ -230,7 +232,14 @@ public sealed partial class DungeonJob var dungeonMatty = Matrix3x2.Multiply(matty, dungeonTransform); // The expensive bit yippy. - _dungeon.SpawnRoom(_gridUid, _grid, dungeonMatty, room, reservedTiles); + var data = _dungeon.SpawnRoom(_gridUid, _grid, dungeonMatty, room, reservedTiles); + + _data.Merge(data); + + await SuspendDungeon(); + + if (!ValidateResume()) + return dungeon; var roomCenter = (room.Offset + room.Size / 2f) * _grid.TileSize; var roomTiles = new HashSet(room.Size.X * room.Size.Y); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs index dfc0932915..4c53141bc9 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs @@ -42,6 +42,7 @@ public sealed partial class DungeonJob } replacements.Add((node, tile)); + AddLoadedTile(node, tile); break; } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs index dceeac3f12..35a35e9656 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DungeonEntrance.cs @@ -71,14 +71,17 @@ public sealed partial class DungeonJob isValid = true; // Entrance wew - _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile(tileDef, random)); + var tileVariant = _tile.GetVariantTile(tileDef, random); + _maps.SetTile(_gridUid, _grid, tile, tileVariant); + AddLoadedTile(tile, tileVariant); ClearDoor(dungeon, _grid, tile); var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile); // Need to offset the spawn to avoid spawning in the room. foreach (var ent in _entTable.GetSpawns(contents, random)) { - _entManager.SpawnAtPosition(ent, gridCoords); + var uid = _entManager.SpawnAtPosition(ent, gridCoords); + AddLoadedEntity(tile, uid); } // Clear out any biome tiles nearby to avoid blocking it diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.EntityTableDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.EntityTableDunGen.cs index 6483448240..02686f7a26 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.EntityTableDunGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.EntityTableDunGen.cs @@ -51,6 +51,7 @@ public sealed partial class DungeonJob foreach (var ent in entities) { var uid = _entManager.SpawnAtPosition(ent, _maps.GridTileToLocal(_gridUid, _grid, tile)); + AddLoadedEntity(tile, uid); _entManager.RemoveComponent(uid); _entManager.RemoveComponent(uid); npcs.SleepNPC(uid); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs index 1788c23cae..831081cdf1 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.EntranceFlank.cs @@ -35,7 +35,9 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(neighbor)) continue; - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + var tile = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + tiles.Add((neighbor, tile)); + AddLoadedTile(neighbor, tile); spawnPositions.Add(neighbor); } } @@ -45,7 +47,12 @@ public sealed partial class DungeonJob foreach (var entrance in spawnPositions) { - _entManager.SpawnEntitiesAttachedTo(_maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(_maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(entrance, uid); + } } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs index 4f2f564ded..1248ab7505 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Exterior.cs @@ -1,3 +1,4 @@ +using System.Numerics; using System.Threading.Tasks; using Content.Shared.Maps; using Content.Shared.NPC; @@ -13,15 +14,22 @@ public sealed partial class DungeonJob /// /// /// - private async Task> GenerateExteriorDungen(Vector2i position, ExteriorDunGen dungen, HashSet reservedTiles, Random random) + private async Task> GenerateExteriorDungen(int runCount, int maxRuns, Vector2i position, ExteriorDunGen dungen, HashSet reservedTiles, Random random) { DebugTools.Assert(_grid.ChunkCount > 0); var aabb = new Box2i(_grid.LocalAABB.BottomLeft.Floored(), _grid.LocalAABB.TopRight.Floored()); - var angle = random.NextAngle(); + // TODO: Cross-layer seeding. Need this because we need to be able to spread the dungeons out. + var angle = new Random(_seed).NextAngle(); + var divisors = new Angle(Angle.FromDegrees(360) / maxRuns); + + // Offset each dungeon so they don't generate on top of each other. + for (var i = 0; i < runCount; i++) + { + angle += (random.NextFloat(0.6f, 1.4f)) * divisors; + } var distance = Math.Max(aabb.Width / 2f + 1f, aabb.Height / 2f + 1f); - var startTile = new Vector2i(0, (int) distance).Rotate(angle); Vector2i? dungeonSpawn = null; @@ -47,9 +55,19 @@ public sealed partial class DungeonJob }; } - var config = _prototype.Index(dungen.Proto); + // Move it further in based on the spawn angle. + if (dungen.Penetration.Y > 0) + { + var penetration = random.Next(dungen.Penetration.X, dungen.Penetration.Y); + var diff = dungeonSpawn.Value - startTile; + var diffVec = new Vector2(diff.X, diff.Y); + dungeonSpawn = (diffVec.Normalized() * (penetration + diffVec.Length())).Floored() + startTile; + } + + var subConfig = _prototype.Index(dungen.Proto); var nextSeed = random.Next(); - var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Layers, reservedTiles, nextSeed, new Random(nextSeed)); + var (dungeons, newReserved) = await GetDungeons(dungeonSpawn.Value, subConfig, subConfig.Layers, nextSeed, new Random(nextSeed), reserved: reservedTiles); + reservedTiles.UnionWith(newReserved); return dungeons; } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs index 482cb34a56..1608e50266 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.ExternalWindow.cs @@ -105,7 +105,9 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(neighbor)) continue; - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + tiles.Add((neighbor, tileVariant)); + AddLoadedTile(neighbor, tileVariant); index++; takenTiles.Add(neighbor); } @@ -119,7 +121,13 @@ public sealed partial class DungeonJob { var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile.Item1); - _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(tile.Item1, uid); + } + await SuspendDungeon(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs index b579d4e5a1..95ec9d56e5 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Fill.cs @@ -18,21 +18,45 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(tile)) continue; + await SuspendDungeon(); + if (!ValidateResume()) + return; + if (!_maps.TryGetTileDef(_grid, tile, out var tileDef)) continue; if (fill.AllowedTiles != null && !fill.AllowedTiles.Contains(tileDef.ID)) continue; + // If noise then check it matches. + if (fill.ReservedNoise != null) + { + var value = fill.ReservedNoise.GetNoise(tile.X, tile.Y); + + if (fill.DistanceConfig != null) + { + // Need to get dx - dx in a range from -1 -> 1 + var dx = 2 * tile.X / fill.Size.X; + var dy = 2 * tile.Y / fill.Size.Y; + + var distance = GetDistance(dx, dy, fill.DistanceConfig); + + value = MathHelper.Lerp(value, 1f - distance, fill.DistanceConfig.BlendWeight); + } + + value *= (fill.Invert ? -1 : 1); + + if (value < fill.Threshold) + continue; + } + if (!_anchorable.TileFree((_gridUid, _grid), tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) continue; var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); - _entManager.SpawnEntity(fill.Entity, gridPos); + var uid = _entManager.SpawnEntity(fill.Entity, gridPos); - await SuspendDungeon(); - if (!ValidateResume()) - break; + AddLoadedEntity(tile, uid); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs index c57757b421..4ced89ba0e 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Helpers.cs @@ -52,6 +52,8 @@ public sealed partial class DungeonJob } } } + + dungeon.RefreshAllTiles(); } private void WidenCorridor(Dungeon dungeon, float width, ICollection corridorTiles) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs index f80b3face7..c736eb6070 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.InternalWindow.cs @@ -81,9 +81,16 @@ public sealed partial class DungeonJob { var tile = validTiles[j]; var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); - _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + _maps.SetTile(_gridUid, _grid, tile, tileVariant); + AddLoadedTile(tile, tileVariant); - _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(tile, uid); + } } if (validTiles.Count > 0) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs index 28cbc9b208..88db2fad42 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Junction.cs @@ -113,10 +113,17 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(weh)) continue; - _maps.SetTile(_gridUid, _grid, weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + _maps.SetTile(_gridUid, _grid, weh, tileVariant); + AddLoadedTile(weh, tileVariant); var coords = _maps.GridTileToLocal(_gridUid, _grid, weh); - _entManager.SpawnEntitiesAttachedTo(coords, _entTable.GetSpawns(contents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(coords, _entTable.GetSpawns(contents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(weh, uid); + } } break; diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs index d6e3c09d62..52edaf3433 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.MiddleConnection.cs @@ -18,6 +18,7 @@ public sealed partial class DungeonJob // Grab all of the room bounds // Then, work out connections between them var roomBorders = new Dictionary>(dungeon.Rooms.Count); + var flank = gen.Flank; foreach (var room in dungeon.Rooms) { @@ -107,18 +108,30 @@ public sealed partial class DungeonJob continue; width--; - _maps.SetTile(_gridUid, _grid, node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + _maps.SetTile(_gridUid, _grid, node, tileVariant); + AddLoadedTile(node, tileVariant); if (flankContents != null && nodeDistances.Count - i <= 2) { - _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(flankContents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(flankContents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(node, uid); + } } else { // Iterate neighbors and check for blockers, if so bulldoze ClearDoor(dungeon, _grid, node); - _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, _entTable.GetSpawns(contents, random)); + + foreach (var uid in uids) + { + AddLoadedEntity(node, uid); + } } if (width == 0) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs index caf6828e43..341dbf168a 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Mobs.cs @@ -49,6 +49,7 @@ public sealed partial class DungeonJob _entManager.RemoveComponent(uid); _entManager.RemoveComponent(uid); npcs.SleepNPC(uid); + AddLoadedEntity(tile, uid); } break; diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs index b2526ec17d..201948fc02 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Noise.cs @@ -98,7 +98,9 @@ public sealed partial class DungeonJob var variant = _tile.PickVariant((ContentTileDefinition) tileDef, random); var adjusted = Vector2.Transform(node + _grid.TileSizeHalfVector, matrix).Floored(); - tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant))); + var tileVariant = new Tile(tileDef.TileId, variant: variant); + tiles.Add((adjusted, tileVariant)); + AddLoadedTile(adjusted, tileVariant); roomTiles.Add(adjusted); tileCount++; break; @@ -127,8 +129,7 @@ public sealed partial class DungeonJob } } - await SuspendIfOutOfTime(); - ValidateResume(); + await SuspendDungeon(); } var center = Vector2.Zero; @@ -140,8 +141,7 @@ public sealed partial class DungeonJob center /= roomTiles.Count; rooms.Add(new DungeonRoom(roomTiles, center, roomArea, new HashSet())); - await SuspendIfOutOfTime(); - ValidateResume(); + await SuspendDungeon(); } _maps.SetTiles(_gridUid, _grid, tiles); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs index 78ab2b7a0d..035820fd90 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Ore.cs @@ -19,12 +19,26 @@ public sealed partial class DungeonJob HashSet reservedTiles, Random random) { + var emptyTiles = false; + var replaceEntities = new Dictionary(); + var availableTiles = new List(); + var remapName = _entManager.ComponentFactory.GetComponentName(); + var replacementRemapping = new Dictionary(); + + if (_prototype.TryIndex(gen.Replacement, out var replacementProto) && + replacementProto.Components.TryGetComponent(remapName, out var replacementComps)) + { + var remappingComp = (EntityRemapComponent) replacementComps; + replacementRemapping = remappingComp.Mask; + } + + if (gen.Replacement != null) + { + replacementRemapping[gen.Replacement.Value] = gen.Entity; + } + foreach (var dungeon in dungeons) { - var emptyTiles = false; - var replaceEntities = new Dictionary(); - var availableTiles = new List(); - foreach (var node in dungeon.AllTiles) { if (reservedTiles.Contains(node)) @@ -41,19 +55,23 @@ public sealed partial class DungeonJob // We use existing entities as a mark to spawn in place // OR // We check for any existing entities to see if we can spawn there. - while (enumerator.MoveNext(out var uid)) + // We can't replace so just stop here. + if (gen.Replacement != null) { - // We can't replace so just stop here. - if (gen.Replacement == null) - break; - - var prototype = _entManager.GetComponent(uid.Value).EntityPrototype; - - if (prototype?.ID == gen.Replacement) + while (enumerator.MoveNext(out var uid)) { - replaceEntities[node] = uid.Value; - found = true; - break; + var prototype = _entManager.GetComponent(uid.Value).EntityPrototype; + + if (string.IsNullOrEmpty(prototype?.ID)) + continue; + + // It has a valid remapping so take it over. + if (replacementRemapping.ContainsKey(prototype.ID)) + { + replaceEntities[node] = uid.Value; + found = true; + break; + } } } @@ -68,83 +86,86 @@ public sealed partial class DungeonJob if (!ValidateResume()) return; } + } - var remapping = new Dictionary(); + var remapping = new Dictionary(); - // TODO: Move this to engine - if (_prototype.TryIndex(gen.Entity, out var proto) && - proto.Components.TryGetComponent("EntityRemap", out var comps)) + // TODO: Move this to engine + if (_prototype.TryIndex(gen.Entity, out var proto) && + proto.Components.TryGetComponent(remapName, out var comps)) + { + var remappingComp = (EntityRemapComponent) comps; + remapping = remappingComp.Mask; + } + + var frontier = new ValueList(32); + + // Iterate the group counts and pathfind out each group. + for (var i = 0; i < gen.Count; i++) + { + var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1); + + // While we have remaining tiles keep iterating + while (groupSize > 0 && availableTiles.Count > 0) { - var remappingComp = (EntityRemapComponent) comps; - remapping = remappingComp.Mask; + var startNode = random.PickAndTake(availableTiles); + frontier.Clear(); + frontier.Add(startNode); + + // This essentially may lead to a vein being split in multiple areas but the count matters more than position. + while (frontier.Count > 0 && groupSize > 0) + { + // Need to pick a random index so we don't just get straight lines of ores. + var frontierIndex = random.Next(frontier.Count); + var node = frontier[frontierIndex]; + frontier.RemoveSwap(frontierIndex); + availableTiles.Remove(node); + + // Add neighbors if they're valid, worst case we add no more and pick another random seed tile. + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + var neighbor = new Vector2i(node.X + x, node.Y + y); + + if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor)) + continue; + + frontier.Add(neighbor); + } + } + + var prototype = gen.Entity; + + // May have been deleted while iteration was suspended. + if (replaceEntities.TryGetValue(node, out var existingEnt) && _entManager.TryGetComponent(existingEnt, out MetaDataComponent? metadata)) + { + var existingProto = metadata.EntityPrototype; + _entManager.DeleteEntity(existingEnt); + + if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped)) + { + prototype = remapped; + } + } + + // Tile valid salad so add it. + var uid = _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node)); + AddLoadedEntity(node, uid); + + groupSize--; + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } } - var frontier = new ValueList(32); - - // Iterate the group counts and pathfind out each group. - for (var i = 0; i < gen.Count; i++) + if (groupSize > 0) { - await SuspendDungeon(); - - if (!ValidateResume()) - return; - - var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1); - - // While we have remaining tiles keep iterating - while (groupSize > 0 && availableTiles.Count > 0) - { - var startNode = random.PickAndTake(availableTiles); - frontier.Clear(); - frontier.Add(startNode); - - // This essentially may lead to a vein being split in multiple areas but the count matters more than position. - while (frontier.Count > 0 && groupSize > 0) - { - // Need to pick a random index so we don't just get straight lines of ores. - var frontierIndex = random.Next(frontier.Count); - var node = frontier[frontierIndex]; - frontier.RemoveSwap(frontierIndex); - availableTiles.Remove(node); - - // Add neighbors if they're valid, worst case we add no more and pick another random seed tile. - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - var neighbor = new Vector2i(node.X + x, node.Y + y); - - if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor)) - continue; - - frontier.Add(neighbor); - } - } - - var prototype = gen.Entity; - - if (replaceEntities.TryGetValue(node, out var existingEnt)) - { - var existingProto = _entManager.GetComponent(existingEnt).EntityPrototype; - _entManager.DeleteEntity(existingEnt); - - if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped)) - { - prototype = remapped; - } - } - - // Tile valid salad so add it. - _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node)); - - groupSize--; - } - } - - if (groupSize > 0) - { - _sawmill.Warning($"Found remaining group size for ore veins of {gen.Replacement ?? "null"}!"); - } + // Not super worried depending on the gen it's fine. + _sawmill.Debug($"Found remaining group size for ore veins of {gen.Replacement ?? "null"} / {gen.Entity}!"); } } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.Roof.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.Roof.cs new file mode 100644 index 0000000000..2d00dbe2ab --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.Roof.cs @@ -0,0 +1,38 @@ +using System.Threading.Tasks; +using Content.Server.Light.EntitySystems; +using Content.Shared.Light.Components; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + public async Task RoofGen(RoofDunGen roof, List dungeons, HashSet reservedTiles, Random random) + { + var roofComp = _entManager.EnsureComponent(_gridUid); + + var noise = roof.Noise; + var oldSeed = noise?.GetSeed() ?? 0; + noise?.SetSeed(_seed + oldSeed); + var rooves = _entManager.System(); + + foreach (var dungeon in dungeons) + { + foreach (var tile in dungeon.AllTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + var value = noise?.GetNoise(tile.X, tile.Y) ?? 1f; + + if (value < roof.Threshold) + continue; + + rooves.SetRoof((_gridUid, _grid, roofComp), tile, true); + } + } + + noise?.SetSeed(oldSeed); + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs index a4a01b5f0b..17ad9b5e35 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.RoomEntrance.cs @@ -25,7 +25,9 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(entrance)) continue; - setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + var tileVariant = _tile.GetVariantTile((ContentTileDefinition)tileDef, random); + setTiles.Add((entrance, tileVariant)); + AddLoadedTile(entrance, tileVariant); } } @@ -38,10 +40,15 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(entrance)) continue; - _entManager.SpawnEntitiesAttachedTo( + var uids = _entManager.SpawnEntitiesAttachedTo( _maps.GridTileToLocal(_gridUid, _grid, entrance), _entTable.GetSpawns(contents, random)); + foreach (var uid in uids) + { + AddLoadedEntity(entrance, uid); + } + await SuspendDungeon(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.SampleDecal.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleDecal.cs new file mode 100644 index 0000000000..b240c0b84c --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleDecal.cs @@ -0,0 +1,64 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; +using Robust.Shared.Map; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(SampleDecalDunGen gen, + List dungeons, + HashSet reservedTiles, + Random random) + { + var oldSeed = gen.Noise.GetSeed(); + gen.Noise.SetSeed(_seed + oldSeed); + + foreach (var dungeon in dungeons) + { + foreach (var tile in dungeon.AllTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + var invert = gen.Invert; + var value = gen.Noise.GetNoise(tile.X, tile.Y); + value = invert ? value * -1 : value; + + if (value < gen.Threshold) + continue; + + // Not allowed + if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) || + !gen.AllowedTiles.Contains(_tileDefManager[tileRef.Tile.TypeId].ID)) + { + continue; + } + + // Occupied? + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + _decals.TryAddDecal(random.Pick(gen.Decals), new EntityCoordinates(_gridUid, tile), out var did); + AddLoadedDecal(tile, did); + + if (gen.ReserveTiles) + { + reservedTiles.Add(tile); + } + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + + gen.Noise.SetSeed(oldSeed); + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.SampleEntity.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleEntity.cs new file mode 100644 index 0000000000..1a9fc8b2e2 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleEntity.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; +using Robust.Shared.Map; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen( + SampleEntityDunGen gen, + List dungeons, + HashSet reservedTiles, + Random random) + { + var oldSeed = gen.Noise.GetSeed(); + gen.Noise.SetSeed(_seed + oldSeed); + + foreach (var dungeon in dungeons) + { + foreach (var tile in dungeon.AllTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + var invert = gen.Invert; + var value = gen.Noise.GetNoise(tile.X, tile.Y); + value = invert ? value * -1 : value; + + if (value < gen.Threshold) + continue; + + // Not allowed + if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) || + !gen.AllowedTiles.Contains(_tileDefManager[tileRef.Tile.TypeId].ID)) + { + continue; + } + + var gridTile = _maps.GridTileToLocal(_gridUid, _grid, tile); + var uid = _entManager.SpawnAttachedTo(random.Pick(gen.Entities), gridTile); + AddLoadedEntity(tile, uid); + + if (gen.ReserveTiles) + { + reservedTiles.Add(tile); + } + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + + gen.Noise.SetSeed(oldSeed); + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.SampleTile.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleTile.cs new file mode 100644 index 0000000000..97875b22fc --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.SampleTile.cs @@ -0,0 +1,66 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; +using Robust.Shared.Map; +using Robust.Shared.Noise; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(SampleTileDunGen gen, + List dungeons, + HashSet reservedTiles, + Random random) + { + var noise = gen.Noise; + var oldSeed = noise.GetSeed(); + noise.SetSeed(_seed + oldSeed); + var tiles = new List<(Vector2i Index, Tile Tile)>(); + var tileDef = _prototype.Index(gen.Tile); + var variants = tileDef.PlacementVariants.Length; + + foreach (var dungeon in dungeons) + { + foreach (var tile in dungeon.AllTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + var invert = gen.Invert; + var value = noise.GetNoise(tile.X, tile.Y); + value = invert ? value * -1 : value; + + if (value < gen.Threshold) + continue; + + var variantValue = (noise.GetNoise(tile.X * 8, tile.Y * 8, variants) + 1f) * 100; + var variant = _tile.PickVariant(tileDef, (int)variantValue); + var tileVariant = new Tile(tileDef.TileId, variant: variant); + + tiles.Add((tile, tileVariant)); + AddLoadedTile(tile, tileVariant); + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + + gen.Noise.SetSeed(oldSeed); + _maps.SetTiles(_gridUid, _grid, tiles); + + if (gen.ReserveTiles) + { + foreach (var tile in tiles) + { + reservedTiles.Add(tile.Index); + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs index a131efd353..8635bc0f48 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.SplineDungeonConnector.cs @@ -2,6 +2,7 @@ using System.Numerics; using System.Threading.Tasks; using Content.Server.NPC.Pathfinding; using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; using Content.Shared.Procedural.PostGeneration; using Robust.Shared.Map; using Robust.Shared.Random; @@ -11,10 +12,10 @@ namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { /// - /// + /// /// private async Task PostGen( - SplineDungeonConnectorDunGen gen, + Shared.Procedural.DungeonLayers.SplineDungeonConnectorDunGen gen, List dungeons, HashSet reservedTiles, Random random) @@ -59,6 +60,7 @@ public sealed partial class DungeonJob { Start = pair.Start, End = pair.End, + Diagonals = false, TileCost = node => { // We want these to get prioritised internally and into space if it's a space dungeon. @@ -110,6 +112,7 @@ public sealed partial class DungeonJob } tiles.Add((node, tile)); + AddLoadedTile(node, tile); } _maps.SetTiles(_gridUid, _grid, tiles); @@ -123,6 +126,7 @@ public sealed partial class DungeonJob allTiles.Add(node); tiles.Add((node, pathTile)); + AddLoadedTile(node, pathTile); } _maps.SetTiles(_gridUid, _grid, tiles); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs index e5bb32bd0c..fa2921b80a 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.WallMount.cs @@ -32,11 +32,18 @@ public sealed partial class DungeonJob if (reservedTiles.Contains(neighbor)) continue; - _maps.SetTile(_gridUid, _grid, neighbor, _tile.GetVariantTile(tileDef, random)); + var tileVariant = _tile.GetVariantTile(tileDef, random); + _maps.SetTile(_gridUid, _grid, neighbor, tileVariant); + AddLoadedTile(neighbor, tileVariant); var gridPos = _maps.GridTileToLocal(_gridUid, _grid, neighbor); var protoNames = _entTable.GetSpawns(contents, random); - _entManager.SpawnEntitiesAttachedTo(gridPos, protoNames); + var uids = _entManager.SpawnEntitiesAttachedTo(gridPos, protoNames); + + foreach (var uid in uids) + { + AddLoadedEntity(neighbor, uid); + } await SuspendDungeon(); if (!ValidateResume()) diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.cs index 77404fc963..8145492205 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.cs @@ -1,8 +1,7 @@ -using System.Linq; +using System.Numerics; using System.Threading; using System.Threading.Tasks; using Content.Server.Decals; -using Content.Server.NPC.Components; using Content.Server.NPC.HTN; using Content.Server.NPC.Systems; using Content.Server.Shuttles.Systems; @@ -23,11 +22,10 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; -using IDunGenLayer = Content.Shared.Procedural.IDunGenLayer; namespace Content.Server.Procedural.DungeonJob; -public sealed partial class DungeonJob : Job> +public sealed partial class DungeonJob : Job<(List, DungeonData)> { public bool TimeSlice = true; @@ -60,6 +58,10 @@ public sealed partial class DungeonJob : Job> private readonly ISawmill _sawmill; + private DungeonData _data = new(); + + private HashSet? _reservedTiles; + public DungeonJob( ISawmill sawmill, double maxTime, @@ -79,12 +81,14 @@ public sealed partial class DungeonJob : Job> int seed, Vector2i position, EntityCoordinates? targetCoordinates = null, - CancellationToken cancellation = default) : base(maxTime, cancellation) + CancellationToken cancellation = default, + HashSet? reservedTiles = null) : base(maxTime, cancellation) { _sawmill = sawmill; _entManager = entManager; _prototype = prototype; _tileDefManager = tileDefManager; + _reservedTiles = reservedTiles; _anchorable = anchorable; _decals = decals; @@ -111,17 +115,18 @@ public sealed partial class DungeonJob : Job> /// /// Gets the relevant dungeon, running recursively as relevant. /// - /// Should we reserve tiles even if the config doesn't specify. - private async Task> GetDungeons( + /// Should we reserve tiles even if the config doesn't specify. + private async Task<(List, HashSet)> GetDungeons( Vector2i position, DungeonConfig config, List layers, - HashSet reservedTiles, int seed, Random random, + HashSet? reserved = null, List? existing = null) { var dungeons = new List(); + var reservedTiles = reserved == null ? new HashSet() : new HashSet(reserved); // Don't pass dungeons back up the "stack". They are ref types though it's a caller problem if they start trying to mutate it. if (existing != null) @@ -137,8 +142,8 @@ public sealed partial class DungeonJob : Job> foreach (var layer in layers) { - var dungCount = dungeons.Count; - await RunLayer(dungeons, position, layer, reservedTiles, seed, random); + var dungCount = dungeons.Count; + await RunLayer(i, count, config, dungeons, position, layer, reservedTiles, seed, random); if (config.ReserveTiles) { @@ -152,24 +157,23 @@ public sealed partial class DungeonJob : Job> await SuspendDungeon(); if (!ValidateResume()) - return new List(); + return (new List(), new HashSet()); } } - return dungeons; + // Only return the new dungeons and applicable reserved tiles. + return (dungeons[(existing?.Count ?? 0)..], config.ReturnReserved ? reservedTiles : new HashSet()); } - protected override async Task?> Process() + protected override async Task<(List, DungeonData)> Process() { _sawmill.Info($"Generating dungeon {_gen} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}"); _grid.CanSplit = false; var random = new Random(_seed); + var oldTileCount = _reservedTiles?.Count ?? 0; var position = (_position + random.NextPolarVector2(_gen.MinOffset, _gen.MaxOffset)).Floored(); - // Tiles we can no longer generate on due to being reserved elsewhere. - var reservedTiles = new HashSet(); - - var dungeons = await GetDungeons(position, _gen, _gen.Layers, reservedTiles, _seed, random); + var (dungeons, _) = await GetDungeons(position, _gen, _gen.Layers, _seed, random, reserved: _reservedTiles); // To make it slightly more deterministic treat this RNG as separate ig. // Post-processing after finishing loading. @@ -181,6 +185,7 @@ public sealed partial class DungeonJob : Job> } // Defer splitting so they don't get spammed and so we don't have to worry about tracking the grid along the way. + DebugTools.Assert(oldTileCount == (_reservedTiles?.Count ?? 0)); _grid.CanSplit = true; _entManager.System().CheckSplits(_gridUid); var npcSystem = _entManager.System(); @@ -194,10 +199,13 @@ public sealed partial class DungeonJob : Job> } _sawmill.Info($"Finished generating dungeon {_gen} with seed {_seed}"); - return dungeons; + return (dungeons, _data); } private async Task RunLayer( + int runCount, + int maxRuns, + DungeonConfig config, List dungeons, Vector2i position, IDunGenLayer layer, @@ -205,7 +213,7 @@ public sealed partial class DungeonJob : Job> int seed, Random random) { - _sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen} with seed {_seed}"); + // _sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen} with seed {_seed}"); // If there's a way to just call the methods directly for the love of god tell me. // Some of these don't care about reservedtiles because they only operate on dungeon tiles (which should @@ -219,15 +227,12 @@ public sealed partial class DungeonJob : Job> case AutoCablingDunGen cabling: await PostGen(cabling, dungeons[^1], reservedTiles, random); break; - case BiomeMarkerLayerDunGen markerPost: - await PostGen(markerPost, dungeons[^1], reservedTiles, random); - break; - case BiomeDunGen biome: - await PostGen(biome, dungeons[^1], reservedTiles, random); - break; case BoundaryWallDunGen boundary: await PostGen(boundary, dungeons[^1], reservedTiles, random); break; + case ChunkDunGen chunk: + dungeons.Add(await PostGen(chunk, reservedTiles, random)); + break; case CornerClutterDunGen clutter: await PostGen(clutter, dungeons[^1], reservedTiles, random); break; @@ -244,7 +249,7 @@ public sealed partial class DungeonJob : Job> await PostGen(flank, dungeons[^1], reservedTiles, random); break; case ExteriorDunGen exterior: - dungeons.AddRange(await GenerateExteriorDungen(position, exterior, reservedTiles, random)); + dungeons.AddRange(await GenerateExteriorDungen(runCount, maxRuns, position, exterior, reservedTiles, random)); break; case FillGridDunGen fill: await GenerateFillDunGen(fill, dungeons, reservedTiles); @@ -285,27 +290,67 @@ public sealed partial class DungeonJob : Job> case PrototypeDunGen prototypo: var groupConfig = _prototype.Index(prototypo.Proto); position = (position + random.NextPolarVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored(); + List? inheritedDungeons = null; + HashSet? inheritedReserved = null; + + switch (prototypo.InheritReserved) + { + case ReservedInheritance.All: + inheritedReserved = new HashSet(reservedTiles); + break; + case ReservedInheritance.None: + break; + default: + throw new NotImplementedException(); + } switch (prototypo.InheritDungeons) { case DungeonInheritance.All: - dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random, existing: dungeons)); + inheritedDungeons = dungeons; break; case DungeonInheritance.Last: - dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random, existing: dungeons.GetRange(dungeons.Count - 1, 1))); + inheritedDungeons = dungeons.GetRange(dungeons.Count - 1, 1); break; case DungeonInheritance.None: - dungeons.AddRange(await GetDungeons(position, groupConfig, groupConfig.Layers, reservedTiles, seed, random)); break; + default: + throw new NotImplementedException(); + } + + var (newDungeons, newReserved) = await GetDungeons(position, + groupConfig, + groupConfig.Layers, + seed, + random, + reserved: inheritedReserved, + existing: inheritedDungeons); + dungeons.AddRange(newDungeons); + + if (groupConfig.ReturnReserved) + { + reservedTiles.UnionWith(newReserved); } break; case ReplaceTileDunGen replace: await GenerateTileReplacementDunGen(replace, dungeons, reservedTiles, random); break; + case RoofDunGen roof: + await RoofGen(roof, dungeons, reservedTiles, random); + break; case RoomEntranceDunGen rEntrance: await PostGen(rEntrance, dungeons[^1], reservedTiles, random); break; + case SampleDecalDunGen sdec: + await PostGen(sdec, dungeons, reservedTiles, random); + break; + case SampleEntityDunGen sent: + await PostGen(sent, dungeons, reservedTiles, random); + break; + case SampleTileDunGen stile: + await PostGen(stile, dungeons, reservedTiles, random); + break; case SplineDungeonConnectorDunGen spline: dungeons.Add(await PostGen(spline, dungeons, reservedTiles, random)); break; @@ -320,11 +365,6 @@ public sealed partial class DungeonJob : Job> } } - private void LogDataError(Type type) - { - _sawmill.Error($"Unable to find dungeon data keys for {type}"); - } - [Pure] private bool ValidateResume() { @@ -346,4 +386,19 @@ public sealed partial class DungeonJob : Job> await SuspendIfOutOfTime(); } + + private void AddLoadedEntity(Vector2i tile, EntityUid ent) + { + _data.Entities[ent] = tile; + } + + private void AddLoadedDecal(Vector2 tile, uint decal) + { + _data.Decals[decal] = tile; + } + + private void AddLoadedTile(Vector2i index, Tile tile) + { + _data.Tiles[index] = tile; + } } diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index e5b0981b3d..e5143454d3 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -113,7 +113,7 @@ public sealed partial class DungeonSystem return roomRotation; } - public void SpawnRoom( + public DungeonData SpawnRoom( EntityUid gridUid, MapGridComponent grid, Matrix3x2 roomTransform, @@ -126,6 +126,7 @@ public sealed partial class DungeonSystem var templateMapUid = _maps.GetMapOrInvalid(roomMap); var templateGrid = Comp(templateMapUid); var roomDimensions = room.Size; + var data = new DungeonData(); var finalRoomRotation = roomTransform.Rotation(); @@ -154,6 +155,7 @@ public sealed partial class DungeonSystem } _tiles.Add((rounded, tileRef.Tile)); + data.Tiles[rounded] = tileRef.Tile; if (clearExisting) { @@ -186,6 +188,7 @@ public sealed partial class DungeonSystem // TODO: Copy the templated entity as is with serv var ent = Spawn(protoId, new EntityCoordinates(gridUid, childPos)); + data.Entities.Add(ent, childPos.Floored()); var childXform = _xformQuery.GetComponent(ent); var anchored = templateXform.Anchored; @@ -256,14 +259,18 @@ public sealed partial class DungeonSystem var result = _decals.TryAddDecal( decal.Id, new EntityCoordinates(gridUid, position), - out _, + out var did, decal.Color, angle, decal.ZIndex, decal.Cleanable); + data.Decals.Add(did, position); + DebugTools.Assert(result); } } + + return data; } } diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index 3a0a7ab2cd..b758fa2d16 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -199,7 +199,8 @@ public sealed partial class DungeonSystem : SharedDungeonSystem MapGridComponent grid, Vector2i position, int seed, - EntityCoordinates? coordinates = null) + EntityCoordinates? coordinates = null, + HashSet? reservedTiles = null) { var cancelToken = new CancellationTokenSource(); var job = new DungeonJob.DungeonJob( @@ -221,18 +222,20 @@ public sealed partial class DungeonSystem : SharedDungeonSystem seed, position, coordinates, - cancelToken.Token); + cancelToken.Token, + reservedTiles); _dungeonJobs.Add(job, cancelToken); _dungeonJobQueue.EnqueueJob(job); } - public async Task> GenerateDungeonAsync( + public async Task<(List, DungeonData)> GenerateDungeonAsync( DungeonConfig gen, EntityUid gridUid, MapGridComponent grid, Vector2i position, - int seed) + int seed, + HashSet? reservedTiles = null) { var cancelToken = new CancellationTokenSource(); var job = new DungeonJob.DungeonJob( @@ -254,7 +257,8 @@ public sealed partial class DungeonSystem : SharedDungeonSystem seed, position, null, - cancelToken.Token); + cancelToken.Token, + reservedTiles); _dungeonJobs.Add(job, cancelToken); _dungeonJobQueue.EnqueueJob(job); @@ -265,7 +269,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem throw job.Exception; } - return job.Result!; + return job.Result; } public Angle GetDungeonRotation(int seed) diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index cbce4dc692..3a74a67dbf 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -1,22 +1,17 @@ -using System.Collections; using System.Linq; using System.Numerics; using System.Threading; using System.Threading.Tasks; -using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Robust.Shared.CPUJob.JobQueues; using Content.Server.Ghost.Roles.Components; -using Content.Server.Parallax; using Content.Server.Procedural; using Content.Server.Salvage.Expeditions; -using Content.Server.Salvage.Expeditions.Structure; using Content.Shared.Atmos; using Content.Shared.Construction.EntitySystems; using Content.Shared.Dataset; using Content.Shared.Gravity; -using Content.Shared.Parallax.Biomes; using Content.Shared.Physics; using Content.Shared.Procedural; using Content.Shared.Procedural.Loot; @@ -25,15 +20,14 @@ using Content.Shared.Salvage; using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Shuttles.Components; -using Content.Shared.Storage; using Robust.Shared.Collections; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; using Content.Server.Shuttles.Components; +using Content.Shared.Procedural.Components; namespace Content.Server.Salvage; @@ -120,14 +114,13 @@ public sealed class SpawnSalvageMissionJob : Job .GetMission(difficultyProto, _missionParams.Seed); var missionBiome = _prototypeManager.Index(mission.Biome); + BiomeComponent? biome = null; if (missionBiome.BiomePrototype != null) { - var biome = _entManager.AddComponent(mapUid); var biomeSystem = _entManager.System(); - biomeSystem.SetTemplate(mapUid, biome, _prototypeManager.Index(missionBiome.BiomePrototype)); - biomeSystem.SetSeed(mapUid, biome, mission.Seed); - _entManager.Dirty(mapUid, biome); + + biome = biomeSystem.AddBiome(mapUid, missionBiome.BiomePrototype.Value, mission.Seed); // Gravity var gravity = _entManager.EnsureComponent(mapUid); @@ -172,7 +165,7 @@ public sealed class SpawnSalvageMissionJob : Job dungeonOffset = dungeonRotation.RotateVec(dungeonOffset); var dungeonMod = _prototypeManager.Index(mission.Dungeon); var dungeonConfig = _prototypeManager.Index(dungeonMod.Proto); - var dungeons = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i)dungeonOffset, + var (dungeons, data) = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i)dungeonOffset, _missionParams.Seed)); var dungeon = dungeons.First(); @@ -183,18 +176,20 @@ public sealed class SpawnSalvageMissionJob : Job return false; } - expedition.DungeonLocation = dungeonOffset; - - List reservedTiles = new(); - - foreach (var tile in _map.GetTilesIntersecting(mapUid, grid, new Circle(Vector2.Zero, landingPadRadius), false)) + // Don't modify any dungeon tiles with chunk gen. + // Have to defer biome loading until the primo dungen is generated. + if (biome != null) { - if (!_biome.TryGetBiomeTile(mapUid, grid, tile.GridIndices, out _)) - continue; + foreach (var tile in dungeon.AllTiles) + { + biome.ModifiedTiles.Add(tile); + } - reservedTiles.Add(tile.GridIndices); + biome.Enabled = true; } + expedition.DungeonLocation = dungeonOffset; + var budgetEntries = new List(); /* @@ -208,13 +203,14 @@ public sealed class SpawnSalvageMissionJob : Job if (!lootProto.Guaranteed) continue; - try + foreach (var rule in lootProto.LootRules) { - await SpawnDungeonLoot(lootProto, mapUid); - } - catch (Exception e) - { - _sawmill.Error($"Failed to spawn guaranteed loot {lootProto.ID}: {e}"); + switch (rule) + { + case BiomeLoot biomeLoot: + _biome.AddLayer(mapUid, $"{rule}", biomeLoot.Proto); + break; + } } } @@ -323,32 +319,4 @@ public sealed class SpawnSalvageMissionJob : Job // oh noooooooooooo } - - private async Task SpawnDungeonLoot(SalvageLootPrototype loot, EntityUid gridUid) - { - for (var i = 0; i < loot.LootRules.Count; i++) - { - var rule = loot.LootRules[i]; - - switch (rule) - { - case BiomeMarkerLoot biomeLoot: - { - if (_entManager.TryGetComponent(gridUid, out var biome)) - { - _biome.AddMarkerLayer(gridUid, biome, biomeLoot.Prototype); - } - } - break; - case BiomeTemplateLoot biomeLoot: - { - if (_entManager.TryGetComponent(gridUid, out var biome)) - { - _biome.AddTemplate(gridUid, biome, "Loot", _prototypeManager.Index(biomeLoot.Prototype), i); - } - } - break; - } - } - } } diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index aa1c2e6dff..d2a3157232 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -6,6 +6,7 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; using Content.Server.Parallax; +using Content.Server.Procedural; using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; @@ -22,7 +23,6 @@ using Content.Shared.DeviceNetwork.Components; using Content.Shared.GameTicking; using Content.Shared.Mobs.Components; using Content.Shared.Movement.Components; -using Content.Shared.Parallax.Biomes; using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; using Content.Shared.Tiles; @@ -82,11 +82,11 @@ public sealed class ArrivalsSystem : EntitySystem /// private const float RoundStartFTLDuration = 10f; - private readonly List> _arrivalsBiomeOptions = new() + private readonly List _arrivalsBiomeOptions = new() { - "Grasslands", - "LowDesert", - "Snow", + "BiomeGrasslands", + "BiomeLowDesert", + "BiomeSnow", }; public override void Initialize() diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 13e13bf8f3..9e9bcb6c42 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -1,12 +1,14 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; +using Content.Server.Decals; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Events; using Content.Shared.Body.Components; using Content.Shared.CCVar; using Content.Shared.Database; +using Content.Shared.Decals; using Content.Shared.Ghost; using Content.Shared.Maps; using Content.Shared.Parallax; @@ -956,6 +958,7 @@ public sealed partial class ShuttleSystem var transform = _physics.GetRelativePhysicsTransform((uid, xform), xform.MapUid.Value); var aabbs = new List(manager.Fixtures.Count); var tileSet = new List<(Vector2i, Tile)>(); + TryComp(xform.MapUid.Value, out DecalGridComponent? decalGrid); foreach (var fixture in manager.Fixtures.Values) { @@ -969,9 +972,15 @@ public sealed partial class ShuttleSystem aabb = aabb.Enlarged(0.2f); aabbs.Add(aabb); - // Handle clearing biome stuff as relevant. + if (decalGrid != null) + { + foreach (var decal in _decals.GetDecalsIntersecting(xform.MapUid.Value, aabb)) + { + _decals.RemoveDecal(xform.MapUid.Value, decal.Index, decalGrid); + } + } + tileSet.Clear(); - _biomes.ReserveTiles(xform.MapUid.Value, aabb, tileSet); _lookupEnts.Clear(); _immuneEnts.Clear(); // TODO: Ideally we'd query first BEFORE moving grid but needs adjustments above. diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index cea7fbfc09..525e16ae1a 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Administration.Logs; using Content.Server.Body.Systems; using Content.Server.Buckle.Systems; +using Content.Server.Decals; using Content.Server.Parallax; using Content.Server.Procedural; using Content.Server.Shuttles.Components; @@ -41,10 +42,12 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly BiomeSystem _biomes = default!; [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly BuckleSystem _buckle = default!; [Dependency] private readonly DamageableSystem _damageSys = default!; + [Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; diff --git a/Content.Server/Station/Components/StationBiomeComponent.cs b/Content.Server/Station/Components/StationBiomeComponent.cs index 0eb64aaff8..a2105d6cef 100644 --- a/Content.Server/Station/Components/StationBiomeComponent.cs +++ b/Content.Server/Station/Components/StationBiomeComponent.cs @@ -1,5 +1,4 @@ using Content.Server.Station.Systems; -using Content.Shared.Parallax.Biomes; using Robust.Shared.Prototypes; namespace Content.Server.Station.Components; @@ -11,7 +10,7 @@ namespace Content.Server.Station.Components; public sealed partial class StationBiomeComponent : Component { [DataField(required: true)] - public ProtoId Biome = "Grasslands"; + public EntProtoId Biome = "BiomeGrasslands"; // If null, its random [DataField] diff --git a/Content.Server/Station/Systems/StationBiomeSystem.cs b/Content.Server/Station/Systems/StationBiomeSystem.cs index c12e2f47e4..c0777f6052 100644 --- a/Content.Server/Station/Systems/StationBiomeSystem.cs +++ b/Content.Server/Station/Systems/StationBiomeSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Parallax; +using Content.Server.Procedural; using Content.Server.Station.Components; using Content.Server.Station.Events; using Robust.Shared.Prototypes; diff --git a/Content.Server/Tabletop/TabletopSystem.cs b/Content.Server/Tabletop/TabletopSystem.cs index e771add0e4..3c3065c95a 100644 --- a/Content.Server/Tabletop/TabletopSystem.cs +++ b/Content.Server/Tabletop/TabletopSystem.cs @@ -191,7 +191,7 @@ namespace Content.Server.Tabletop if (!TryComp(uid, out ActorComponent? actor)) { RemComp(uid); - return; + continue; } if (actor.PlayerSession.Status != SessionStatus.InGame || !CanSeeTable(uid, gamer.Tabletop)) diff --git a/Content.Shared/CCVar/CCVars.Biome.cs b/Content.Shared/CCVar/CCVars.Biome.cs new file mode 100644 index 0000000000..13c6cd548e --- /dev/null +++ b/Content.Shared/CCVar/CCVars.Biome.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Configuration; + +namespace Content.Shared.CCVar; + +public sealed partial class CCVars +{ + /// + /// Load range for biomes. Set this higher than PVS so server can have some time to load in before the client arrives. + /// + public static readonly CVarDef BiomeLoadRange = + CVarDef.Create("biome.load_range", 20f, CVar.SERVERONLY); + + /// + /// Time allocation (ms) for how long biomes are allowed to load. + /// + public static readonly CVarDef BiomeLoadTime = + CVarDef.Create("biome.load_time", 0.03f, CVar.SERVERONLY); +} diff --git a/Content.Shared/Parallax/Biomes/BiomeComponent.cs b/Content.Shared/Parallax/Biomes/BiomeComponent.cs deleted file mode 100644 index af8eb88683..0000000000 --- a/Content.Shared/Parallax/Biomes/BiomeComponent.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Content.Shared.Parallax.Biomes.Layers; -using Content.Shared.Parallax.Biomes.Markers; -using Robust.Shared.GameStates; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Parallax.Biomes; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedBiomeSystem))] -public sealed partial class BiomeComponent : Component -{ - /// - /// Do we load / deload. - /// - [DataField, ViewVariables(VVAccess.ReadWrite), Access(Other = AccessPermissions.ReadWriteExecute)] - public bool Enabled = true; - - [ViewVariables(VVAccess.ReadWrite), DataField("seed")] - [AutoNetworkedField] - public int Seed = -1; - - /// - /// The underlying entity, decal, and tile layers for the biome. - /// - [DataField("layers")] - [AutoNetworkedField] - public List Layers = new(); - - /// - /// Templates to use for . - /// If this is set on mapinit, it will fill out layers automatically. - /// If not set, use BiomeSystem to do it. - /// Prototype reloading will also use this. - /// - [DataField] - public ProtoId? Template; - - /// - /// If we've already generated a tile and couldn't deload it then we won't ever reload it in future. - /// Stored by [Chunkorigin, Tiles] - /// - [DataField("modifiedTiles")] - public Dictionary> ModifiedTiles = new(); - - /// - /// Decals that have been loaded as a part of this biome. - /// - [DataField("decals")] - public Dictionary> LoadedDecals = new(); - - [DataField("entities")] - public Dictionary> LoadedEntities = new(); - - /// - /// Currently active chunks - /// - [DataField("loadedChunks")] - public HashSet LoadedChunks = new(); - - #region Markers - - /// - /// Work out entire marker tiles in advance but only load the entities when in range. - /// - [DataField("pendingMarkers")] - public Dictionary>> PendingMarkers = new(); - - /// - /// Track what markers we've loaded already to avoid double-loading. - /// - [DataField("loadedMarkers", customTypeSerializer:typeof(PrototypeIdDictionarySerializer, BiomeMarkerLayerPrototype>))] - public Dictionary> LoadedMarkers = new(); - - [DataField] - public HashSet> MarkerLayers = new(); - - /// - /// One-tick forcing of marker layers to bulldoze any entities in the way. - /// - [DataField] - public HashSet> ForcedMarkerLayers = new(); - - #endregion -} diff --git a/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs b/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs deleted file mode 100644 index 437ead63a7..0000000000 --- a/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Parallax.Biomes.Layers; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Parallax.Biomes; - -/// -/// A preset group of biome layers to be used for a -/// -[Prototype] -public sealed partial class BiomeTemplatePrototype : IPrototype -{ - [IdDataField] public string ID { get; private set; } = default!; - - [DataField("layers")] - public List Layers = new(); -} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs deleted file mode 100644 index 5e31e513a9..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Shared.Decals; -using Content.Shared.Maps; -using Robust.Shared.Noise; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Parallax.Biomes.Layers; - -[Serializable, NetSerializable] -public sealed partial class BiomeDecalLayer : IBiomeWorldLayer -{ - /// - [DataField("allowedTiles", customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List AllowedTiles { get; private set; } = new(); - - /// - /// Divide each tile up by this amount. - /// - [DataField("divisions")] - public float Divisions = 1f; - - [DataField("noise")] - public FastNoiseLite Noise { get; private set; } = new(0); - - /// - [DataField("threshold")] - public float Threshold { get; private set; } = 0.8f; - - /// - [DataField("invert")] public bool Invert { get; private set; } = false; - - [DataField("decals", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List Decals = new(); -} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs deleted file mode 100644 index 2beeba6e03..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.Noise; -using Robust.Shared.Serialization; - -namespace Content.Shared.Parallax.Biomes.Layers; - -/// -/// Dummy layer that specifies a marker to be replaced by external code. -/// For example if they wish to add their own layers at specific points across different templates. -/// -[Serializable, NetSerializable] -public sealed partial class BiomeDummyLayer : IBiomeLayer -{ - [DataField("id", required: true)] public string ID = string.Empty; - - public FastNoiseLite Noise { get; } = new(); - public float Threshold { get; } - public bool Invert { get; } -} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs deleted file mode 100644 index 21ffdd96e5..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Parallax.Biomes.Layers; - -[Serializable, NetSerializable] -public sealed partial class BiomeEntityLayer : IBiomeWorldLayer -{ - /// - [DataField("allowedTiles", customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List AllowedTiles { get; private set; } = new(); - - [DataField("noise")] public FastNoiseLite Noise { get; private set; } = new(0); - - /// - [DataField("threshold")] - public float Threshold { get; private set; } = 0.5f; - - /// - [DataField("invert")] public bool Invert { get; private set; } = false; - - [DataField("entities", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new(); -} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs deleted file mode 100644 index 51231405a8..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Robust.Shared.Noise; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Parallax.Biomes.Layers; - -/// -/// Contains more biome layers recursively via a biome template. -/// Can be used for sub-biomes. -/// -[Serializable, NetSerializable] -public sealed partial class BiomeMetaLayer : IBiomeLayer -{ - [DataField("noise")] - public FastNoiseLite Noise { get; private set; } = new(0); - - /// - [DataField("threshold")] - public float Threshold { get; private set; } = -1f; - - /// - [DataField("invert")] - public bool Invert { get; private set; } - - [DataField("template", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Template = string.Empty; -} diff --git a/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs b/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs deleted file mode 100644 index 3b1ad5c76c..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Robust.Shared.Noise; - -namespace Content.Shared.Parallax.Biomes.Layers; - -[ImplicitDataDefinitionForInheritors] -public partial interface IBiomeLayer -{ - /// - /// Seed is used an offset from the relevant BiomeComponent's seed. - /// - FastNoiseLite Noise { get; } - - /// - /// Threshold for this layer to be present. If set to 0 forces it for every tile. - /// - float Threshold { get; } - - /// - /// Is the thresold inverted so we need to be lower than it. - /// - public bool Invert { get; } -} diff --git a/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs b/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs deleted file mode 100644 index e04db913b7..0000000000 --- a/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Content.Shared.Parallax.Biomes.Layers; - -/// -/// Handles actual objects such as decals and entities. -/// -public partial interface IBiomeWorldLayer : IBiomeLayer -{ - /// - /// What tiles we're allowed to spawn on, real or biome. - /// - List AllowedTiles { get; } -} diff --git a/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs b/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs deleted file mode 100644 index fbc3a04eb4..0000000000 --- a/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Parallax.Biomes.Markers; - -/// -/// Spawns entities inside of the specified area with the minimum specified radius. -/// -[Prototype] -public sealed partial class BiomeMarkerLayerPrototype : IBiomeMarkerLayer -{ - [IdDataField] public string ID { get; private set; } = default!; - - /// - /// Checks for the relevant entity for the tile before spawning. Useful for substituting walls with ore veins for example. - /// - [DataField] - public Dictionary EntityMask { get; private set; } = new(); - - /// - /// Default prototype to spawn. If null will fall back to entity mask. - /// - [DataField] - public string? Prototype { get; private set; } - - /// - /// Minimum radius between 2 points - /// - [DataField("radius")] - public float Radius = 32f; - - /// - /// Maximum amount of group spawns - /// - [DataField("maxCount")] - public int MaxCount = int.MaxValue; - - /// - /// Minimum entities to spawn in one group. - /// - [DataField] - public int MinGroupSize = 1; - - /// - /// Maximum entities to spawn in one group. - /// - [DataField] - public int MaxGroupSize = 1; - - /// - [DataField("size")] - public int Size { get; private set; } = 128; -} diff --git a/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs b/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs deleted file mode 100644 index de2913bb09..0000000000 --- a/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared.Parallax.Biomes.Markers; - -/// -/// Specifies one-off marker points to be used. This could be for dungeon markers, mob markers, etc. -/// These are run outside of the tile / decal / entity layers. -/// -public interface IBiomeMarkerLayer : IPrototype -{ - /// - /// Biome template to use as a mask for this layer. - /// - public Dictionary EntityMask { get; } - - public string? Prototype { get; } - - /// - /// How large the pre-generated points area is. - /// - public int Size { get; } -} diff --git a/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs b/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs deleted file mode 100644 index a5238e8c6e..0000000000 --- a/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Numerics; -using Content.Shared.Maps; -using Content.Shared.Parallax.Biomes.Layers; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.Manager; -using Robust.Shared.Utility; - -namespace Content.Shared.Parallax.Biomes; - -public abstract class SharedBiomeSystem : EntitySystem -{ - [Dependency] protected readonly IPrototypeManager ProtoManager = default!; - [Dependency] private readonly ISerializationManager _serManager = default!; - [Dependency] protected readonly ITileDefinitionManager TileDefManager = default!; - [Dependency] private readonly TileSystem _tile = default!; - [Dependency] private readonly SharedMapSystem _map = default!; - - protected const byte ChunkSize = 8; - - private T Pick(List collection, float value) - { - // Listen I don't need this exact and I'm too lazy to finetune just for random ent picking. - value %= 1f; - value = Math.Clamp(value, 0f, 1f); - - if (collection.Count == 1) - return collection[0]; - - var randValue = value * collection.Count; - - foreach (var item in collection) - { - randValue -= 1f; - - if (randValue <= 0f) - { - return item; - } - } - - throw new ArgumentOutOfRangeException(); - } - - private int Pick(int count, float value) - { - value %= 1f; - value = Math.Clamp(value, 0f, 1f); - - if (count == 1) - return 0; - - value *= count; - - for (var i = 0; i < count; i++) - { - value -= 1f; - - if (value <= 0f) - { - return i; - } - } - - throw new ArgumentOutOfRangeException(); - } - - public bool TryGetBiomeTile(EntityUid uid, MapGridComponent grid, Vector2i indices, [NotNullWhen(true)] out Tile? tile) - { - if (_map.TryGetTileRef(uid, grid, indices, out var tileRef) && !tileRef.Tile.IsEmpty) - { - tile = tileRef.Tile; - return true; - } - - if (!TryComp(uid, out var biome)) - { - tile = null; - return false; - } - - return TryGetBiomeTile(indices, biome.Layers, biome.Seed, (uid, grid), out tile); - } - - /// - /// Tries to get the tile, real or otherwise, for the specified indices. - /// - public bool TryGetBiomeTile(Vector2i indices, List layers, int seed, Entity? grid, [NotNullWhen(true)] out Tile? tile) - { - if (grid is { } gridEnt && _map.TryGetTileRef(gridEnt, gridEnt.Comp, indices, out var tileRef) && !tileRef.Tile.IsEmpty) - { - tile = tileRef.Tile; - return true; - } - - return TryGetTile(indices, layers, seed, grid, out tile); - } - - /// - /// Tries to get the tile, real or otherwise, for the specified indices. - /// - [Obsolete("Use the Entity? overload")] - public bool TryGetBiomeTile(Vector2i indices, List layers, int seed, MapGridComponent? grid, [NotNullWhen(true)] out Tile? tile) - { - return TryGetBiomeTile(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out tile); - } - - /// - /// Gets the underlying biome tile, ignoring any existing tile that may be there. - /// - public bool TryGetTile(Vector2i indices, List layers, int seed, Entity? grid, [NotNullWhen(true)] out Tile? tile) - { - for (var i = layers.Count - 1; i >= 0; i--) - { - var layer = layers[i]; - var noiseCopy = GetNoise(layer.Noise, seed); - - var invert = layer.Invert; - var value = noiseCopy.GetNoise(indices.X, indices.Y); - value = invert ? value * -1 : value; - - if (value < layer.Threshold) - continue; - - // Check if the tile is from meta layer, otherwise fall back to default layers. - if (layer is BiomeMetaLayer meta) - { - if (TryGetBiomeTile(indices, ProtoManager.Index(meta.Template).Layers, seed, grid, out tile)) - { - return true; - } - - continue; - } - - if (layer is not BiomeTileLayer tileLayer) - continue; - - if (TryGetTile(indices, noiseCopy, tileLayer.Invert, tileLayer.Threshold, ProtoManager.Index(tileLayer.Tile), tileLayer.Variants, out tile)) - { - return true; - } - } - - tile = null; - return false; - } - - /// - /// Gets the underlying biome tile, ignoring any existing tile that may be there. - /// - [Obsolete("Use the Entity? overload")] - public bool TryGetTile(Vector2i indices, List layers, int seed, MapGridComponent? grid, [NotNullWhen(true)] out Tile? tile) - { - return TryGetTile(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out tile); - } - - /// - /// Gets the underlying biome tile, ignoring any existing tile that may be there. - /// - private bool TryGetTile(Vector2i indices, FastNoiseLite noise, bool invert, float threshold, ContentTileDefinition tileDef, List? variants, [NotNullWhen(true)] out Tile? tile) - { - var found = noise.GetNoise(indices.X, indices.Y); - found = invert ? found * -1 : found; - - if (found < threshold) - { - tile = null; - return false; - } - - byte variant = 0; - var variantCount = variants?.Count ?? tileDef.Variants; - - // Pick a variant tile if they're available as well - if (variantCount > 1) - { - var variantValue = (noise.GetNoise(indices.X * 8, indices.Y * 8, variantCount) + 1f) * 100; - variant = _tile.PickVariant(tileDef, (int)variantValue); - } - - tile = new Tile(tileDef.TileId, variant); - return true; - } - - /// - /// Tries to get the relevant entity for this tile. - /// - public bool TryGetEntity(Vector2i indices, BiomeComponent component, Entity? grid, - [NotNullWhen(true)] out string? entity) - { - if (!TryGetBiomeTile(indices, component.Layers, component.Seed, grid, out var tile)) - { - entity = null; - return false; - } - - return TryGetEntity(indices, component.Layers, tile.Value, component.Seed, grid, out entity); - } - - /// - /// Tries to get the relevant entity for this tile. - /// - [Obsolete("Use the Entity? overload")] - public bool TryGetEntity(Vector2i indices, BiomeComponent component, MapGridComponent grid, - [NotNullWhen(true)] out string? entity) - { - return TryGetEntity(indices, component, grid == null ? null : (grid.Owner, grid), out entity); - } - - public bool TryGetEntity(Vector2i indices, List layers, Tile tileRef, int seed, Entity? grid, - [NotNullWhen(true)] out string? entity) - { - var tileId = TileDefManager[tileRef.TypeId].ID; - - for (var i = layers.Count - 1; i >= 0; i--) - { - var layer = layers[i]; - - switch (layer) - { - case BiomeDummyLayer: - continue; - case IBiomeWorldLayer worldLayer: - if (!worldLayer.AllowedTiles.Contains(tileId)) - continue; - - break; - case BiomeMetaLayer: - break; - default: - continue; - } - - var noiseCopy = GetNoise(layer.Noise, seed); - - var invert = layer.Invert; - var value = noiseCopy.GetNoise(indices.X, indices.Y); - value = invert ? value * -1 : value; - - if (value < layer.Threshold) - continue; - - if (layer is BiomeMetaLayer meta) - { - if (TryGetEntity(indices, ProtoManager.Index(meta.Template).Layers, tileRef, seed, grid, out entity)) - { - return true; - } - - continue; - } - - // Decals might block entity so need to check if there's one in front of us. - if (layer is not BiomeEntityLayer biomeLayer) - { - entity = null; - return false; - } - - var noiseValue = noiseCopy.GetNoise(indices.X, indices.Y, i); - entity = Pick(biomeLayer.Entities, (noiseValue + 1f) / 2f); - return true; - } - - entity = null; - return false; - } - - [Obsolete("Use the Entity? overload")] - public bool TryGetEntity(Vector2i indices, List layers, Tile tileRef, int seed, MapGridComponent grid, - [NotNullWhen(true)] out string? entity) - { - return TryGetEntity(indices, layers, tileRef, seed, grid == null ? null : (grid.Owner, grid), out entity); - } - - /// - /// Tries to get the relevant decals for this tile. - /// - public bool TryGetDecals(Vector2i indices, List layers, int seed, Entity? grid, - [NotNullWhen(true)] out List<(string ID, Vector2 Position)>? decals) - { - if (!TryGetBiomeTile(indices, layers, seed, grid, out var tileRef)) - { - decals = null; - return false; - } - - var tileId = TileDefManager[tileRef.Value.TypeId].ID; - - for (var i = layers.Count - 1; i >= 0; i--) - { - var layer = layers[i]; - - // Entities might block decal so need to check if there's one in front of us. - switch (layer) - { - case BiomeDummyLayer: - continue; - case IBiomeWorldLayer worldLayer: - if (!worldLayer.AllowedTiles.Contains(tileId)) - continue; - - break; - case BiomeMetaLayer: - break; - default: - continue; - } - - var invert = layer.Invert; - var noiseCopy = GetNoise(layer.Noise, seed); - var value = noiseCopy.GetNoise(indices.X, indices.Y); - value = invert ? value * -1 : value; - - if (value < layer.Threshold) - continue; - - if (layer is BiomeMetaLayer meta) - { - if (TryGetDecals(indices, ProtoManager.Index(meta.Template).Layers, seed, grid, out decals)) - { - return true; - } - - continue; - } - - // Check if the other layer should even render, if not then keep going. - if (layer is not BiomeDecalLayer decalLayer) - { - decals = null; - return false; - } - - decals = new List<(string ID, Vector2 Position)>(); - - for (var x = 0; x < decalLayer.Divisions; x++) - { - for (var y = 0; y < decalLayer.Divisions; y++) - { - var index = new Vector2(indices.X + x * 1f / decalLayer.Divisions, indices.Y + y * 1f / decalLayer.Divisions); - var decalValue = noiseCopy.GetNoise(index.X, index.Y); - decalValue = invert ? decalValue * -1 : decalValue; - - if (decalValue < decalLayer.Threshold) - continue; - - decals.Add((Pick(decalLayer.Decals, (noiseCopy.GetNoise(indices.X, indices.Y, x + y * decalLayer.Divisions) + 1f) / 2f), index)); - } - } - - // Check other layers - if (decals.Count == 0) - continue; - - return true; - } - - decals = null; - return false; - } - - /// - /// Tries to get the relevant decals for this tile. - /// - [Obsolete("Use the Entity? overload")] - public bool TryGetDecals(Vector2i indices, List layers, int seed, MapGridComponent grid, - [NotNullWhen(true)] out List<(string ID, Vector2 Position)>? decals) - { - return TryGetDecals(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out decals); - } - - private FastNoiseLite GetNoise(FastNoiseLite seedNoise, int seed) - { - var noiseCopy = new FastNoiseLite(); - _serManager.CopyTo(seedNoise, ref noiseCopy, notNullableOverride: true); - noiseCopy.SetSeed(noiseCopy.GetSeed() + seed); - // Ensure re-calculate is run. - noiseCopy.SetFractalOctaves(noiseCopy.GetFractalOctaves()); - return noiseCopy; - } -} diff --git a/Content.Shared/Procedural/Components/BiomeComponent.cs b/Content.Shared/Procedural/Components/BiomeComponent.cs new file mode 100644 index 0000000000..f79a31c414 --- /dev/null +++ b/Content.Shared/Procedural/Components/BiomeComponent.cs @@ -0,0 +1,86 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.Components; + +/// +/// A layer inside of +/// +[DataRecord] +public sealed record BiomeMetaLayer +{ + /// + /// Chunk dimensions for this meta layer. Will try to infer it from the first layer of the dungeon if null. + /// + [DataField] + public int? Size; + + /// + /// Meta layers that this one requires to be loaded first. + /// Will ensure all of the chunks for our corresponding area are loaded. + /// + public List? DependsOn; + + /// + /// Can this layer be unloaded if no one is in range. + /// + public bool CanUnload = true; + + /// + /// Dungeon config to load inside the specified area. + /// + [DataField(required: true)] + public ProtoId Dungeon = new(); +} + +[RegisterComponent] +public sealed partial class BiomeComponent : Component +{ + /// + /// Can we load / unload chunks. + /// + [DataField] + public bool Enabled = true; + + /// + /// Areas queued for preloading. Will add these during and then flag as modified so they retain. + /// + [DataField] + public List PreloadAreas = new(); + + /// + /// Is there currently a job that's loading. + /// + public bool Loading = false; + + [DataField] + public int Seed; + + /// + /// Layer key and associated data. + /// + [DataField(required: true)] + public Dictionary Layers = new(); + + /// + /// Layer removals that are pending. + /// + [DataField] + public List PendingRemovals = new(); + + /// + /// Data that is currently loaded. + /// + [DataField] + public Dictionary> LoadedData = new(); + + /// + /// Flag modified tiles so we don't try and unload / reload them. + /// + [DataField] + public HashSet ModifiedTiles = new(); + + /// + /// Bounds loaded by players for this tick. + /// + public List LoadedBounds = new(); +} diff --git a/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs b/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs new file mode 100644 index 0000000000..215a8f345d --- /dev/null +++ b/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Procedural.Components; + +/// +/// Will forcibly unload an entity no matter what. Useful if you have consistent entities that will never be default or the likes. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class BiomeForceUnloadComponent : Component; diff --git a/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs b/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs new file mode 100644 index 0000000000..813f5fc1d4 --- /dev/null +++ b/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Procedural.Distance; + +public sealed partial class DunGenDistanceSquared : IDunGenDistance +{ + [DataField] + public float BlendWeight { get; set; } = 0.50f; +} diff --git a/Content.Shared/Procedural/DungeonConfig.cs b/Content.Shared/Procedural/DungeonConfig.cs index 7c84b1a6a3..56131e5b28 100644 --- a/Content.Shared/Procedural/DungeonConfig.cs +++ b/Content.Shared/Procedural/DungeonConfig.cs @@ -12,11 +12,18 @@ public partial class DungeonConfig public List Layers = new(); /// - /// Should we reserve the tiles generated by this config so no other dungeons can spawn on it within the same job? + /// Should we reserve the tiles generated by this config so no other layers at the same level can spawn on this tile? /// [DataField] public bool ReserveTiles; + /// + /// Should we return the reserved tiles to the upper level. + /// Set to false if you don't care if this dungeon has its tiles overwritten at higher levels. + /// + [DataField] + public bool ReturnReserved = true; + /// /// Minimum times to run the config. /// diff --git a/Content.Shared/Procedural/DungeonData.cs b/Content.Shared/Procedural/DungeonData.cs new file mode 100644 index 0000000000..a0209f91a6 --- /dev/null +++ b/Content.Shared/Procedural/DungeonData.cs @@ -0,0 +1,41 @@ +using System.Linq; +using System.Numerics; +using Robust.Shared.Map; + +namespace Content.Shared.Procedural; + +/// +/// Contains the loaded data for a dungeon. +/// +[DataDefinition] +public sealed partial class DungeonData +{ + [DataField] + public Dictionary Decals = new(); + + [DataField] + public Dictionary Entities = new(); + + [DataField] + public Dictionary Tiles = new(); + + public static DungeonData Empty = new(); + + public void Merge(DungeonData data) + { + foreach (var did in data.Decals) + { + Decals[did.Key] = did.Value; + } + + foreach (var ent in data.Entities) + { + Entities[ent.Key] = ent.Value; + } + + foreach (var tile in data.Tiles) + { + Tiles[tile.Key] = tile.Value; + } + } +} diff --git a/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs new file mode 100644 index 0000000000..b48a1b3fd6 --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Noise; + +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Turns a chunked area into a dungeon for layer purposes. Assumes the position is the BL origin. +/// +public sealed partial class ChunkDunGen : IDunGenLayer +{ + [DataField] + public int Size = 16; + + /// + /// Noise to apply for each tile conditionally. + /// + [DataField] + public FastNoiseLite? Noise; + + /// + /// Threshold for noise. Does nothing if is null. + /// + [DataField] + public float Threshold = -1f; +} diff --git a/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs index e9a5181f8d..2ece880851 100644 --- a/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs @@ -10,4 +10,10 @@ public sealed partial class ExteriorDunGen : IDunGenLayer { [DataField(required: true)] public ProtoId Proto; + + /// + /// Minimum and maximum penetration. + /// + [DataField] + public Vector2i Penetration = new Vector2i(5, 15); } diff --git a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs index 89a4ab216a..c3f7ae3f33 100644 --- a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs @@ -14,6 +14,12 @@ public sealed partial class PrototypeDunGen : IDunGenLayer [DataField] public DungeonInheritance InheritDungeons = DungeonInheritance.None; + /// + /// Should we pass in the current level's reserved tiles to the prototype. + /// + [DataField] + public ReservedInheritance InheritReserved = ReservedInheritance.All; + [DataField(required: true)] public ProtoId Proto; } @@ -35,3 +41,16 @@ public enum DungeonInheritance : byte /// All, } + +public enum ReservedInheritance : byte +{ + /// + /// Don't inherit any reserved tiles. + /// + None, + + /// + /// Inherit reserved tiles, + /// + All, +} diff --git a/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs b/Content.Shared/Procedural/DungeonLayers/AutoCablingDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/AutoCablingDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs b/Content.Shared/Procedural/DungeonLayers/BoundaryWallDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/BoundaryWallDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs b/Content.Shared/Procedural/DungeonLayers/CornerClutterDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/CornerClutterDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs b/Content.Shared/Procedural/DungeonLayers/CorridorClutterDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/CorridorClutterDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs b/Content.Shared/Procedural/DungeonLayers/CorridorDecalSkirtingDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/CorridorDecalSkirtingDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs b/Content.Shared/Procedural/DungeonLayers/CorridorDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/CorridorDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs b/Content.Shared/Procedural/DungeonLayers/DungeonEntranceDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/DungeonEntranceDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs b/Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs similarity index 93% rename from Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs index f9be6caf6a..cd6cf169fc 100644 --- a/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs @@ -1,5 +1,6 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; +using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs b/Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs similarity index 94% rename from Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs index fc992ea7b8..30b8302263 100644 --- a/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs @@ -1,6 +1,5 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; -using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs index 363de0a511..e2506298fd 100644 --- a/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs @@ -1,4 +1,7 @@ +using System.Numerics; using Content.Shared.Maps; +using Content.Shared.Procedural.Distance; +using Robust.Shared.Noise; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; @@ -6,10 +9,6 @@ namespace Content.Shared.Procedural.DungeonLayers; /// /// Fills unreserved tiles with the specified entity prototype. /// -/// -/// DungeonData keys are: -/// - Fill -/// public sealed partial class FillGridDunGen : IDunGenLayer { /// @@ -20,4 +19,29 @@ public sealed partial class FillGridDunGen : IDunGenLayer [DataField(required: true)] public EntProtoId Entity; + + #region Noise + + [DataField] + public bool Invert; + + /// + /// Optionally don't spawn entities if the noise value matches. + /// + [DataField] + public FastNoiseLite? ReservedNoise; + + /// + /// Noise threshold for . Does nothing without it. + /// + [DataField] + public float Threshold = -1f; + + [DataField] + public IDunGenDistance? DistanceConfig; + + [DataField] + public Vector2 Size; + + #endregion } diff --git a/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs b/Content.Shared/Procedural/DungeonLayers/InternalWindowDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/InternalWindowDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs b/Content.Shared/Procedural/DungeonLayers/JunctionDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/JunctionDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs b/Content.Shared/Procedural/DungeonLayers/MiddleConnectionDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/MiddleConnectionDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs index 5525341eb9..1b754d3778 100644 --- a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs @@ -1,10 +1,8 @@ using Content.Shared.EntityTable; -using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; - /// /// Spawns mobs inside of the dungeon randomly. /// diff --git a/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs b/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs new file mode 100644 index 0000000000..fbb174dc14 --- /dev/null +++ b/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs @@ -0,0 +1,15 @@ +using Robust.Shared.Noise; + +namespace Content.Shared.Procedural.DungeonLayers; + +/// +/// Sets tiles as rooved. +/// +public sealed partial class RoofDunGen : IDunGenLayer +{ + [DataField] + public float Threshold = -1f; + + [DataField] + public FastNoiseLite? Noise; +} diff --git a/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs b/Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs similarity index 93% rename from Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs index 1436f7473d..f0fea57588 100644 --- a/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs @@ -1,6 +1,5 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; -using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs b/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs new file mode 100644 index 0000000000..616e643b52 --- /dev/null +++ b/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs @@ -0,0 +1,36 @@ +using Content.Shared.Decals; +using Content.Shared.Maps; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Procedural.DungeonLayers; + +public sealed partial class SampleDecalDunGen : IDunGenLayer +{ + /// + /// Reserve any tiles we update. + /// + [DataField] + public bool ReserveTiles = true; + + [DataField(customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List AllowedTiles { get; private set; } = new(); + + /// + /// Divide each tile up by this amount. + /// + [DataField] + public float Divisions = 1f; + + [DataField] + public FastNoiseLite Noise { get; private set; } = new(0); + + [DataField] + public float Threshold { get; private set; } = 0.8f; + + [DataField] public bool Invert { get; private set; } = false; + + [DataField(required: true)] + public List> Decals = new(); +} diff --git a/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs b/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs new file mode 100644 index 0000000000..2daf7e7aa7 --- /dev/null +++ b/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs @@ -0,0 +1,31 @@ +using Content.Shared.Maps; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Procedural.DungeonLayers; + +/// +/// Samples noise to spawn the specified entity +/// +public sealed partial class SampleEntityDunGen : IDunGenLayer +{ + /// + /// Reserve any tiles we update. + /// + [DataField] + public bool ReserveTiles = true; + + [DataField(customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List AllowedTiles { get; private set; } = new(); + + [DataField] public FastNoiseLite Noise { get; private set; } = new(0); + + [DataField] + public float Threshold { get; private set; } = 0.5f; + + [DataField] public bool Invert { get; private set; } = false; + + [DataField] + public List Entities = new(); +} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs b/Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs similarity index 66% rename from Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs rename to Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs index 9dee35da4e..6d23d201f5 100644 --- a/Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs +++ b/Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs @@ -2,20 +2,26 @@ using Content.Shared.Maps; using Robust.Shared.Noise; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Shared.Parallax.Biomes.Layers; +namespace Content.Shared.Procedural.DungeonLayers; +/// +/// Samples noise and spawns the specified tile in the dungeon area. +/// [Serializable, NetSerializable] -public sealed partial class BiomeTileLayer : IBiomeLayer +public sealed partial class SampleTileDunGen : IDunGenLayer { + /// + /// Reserve any tiles we update. + /// + [DataField] + public bool ReserveTiles = true; + [DataField] public FastNoiseLite Noise { get; private set; } = new(0); - /// [DataField] public float Threshold { get; private set; } = 0.5f; - /// [DataField] public bool Invert { get; private set; } = false; /// diff --git a/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs b/Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs similarity index 83% rename from Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs index d2f5a2126a..4a4bc0b36a 100644 --- a/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs @@ -1,7 +1,7 @@ using Content.Shared.Maps; using Robust.Shared.Prototypes; -namespace Content.Shared.Procedural.PostGeneration; +namespace Content.Shared.Procedural.DungeonLayers; /// /// Connects dungeons via points that get subdivided. @@ -18,11 +18,11 @@ public sealed partial class SplineDungeonConnectorDunGen : IDunGenLayer /// Will divide the distance between the start and end points so that no subdivision is more than these metres away. /// [DataField] - public int DivisionDistance = 10; + public int DivisionDistance = 20; /// /// How much each subdivision can vary from the middle. /// [DataField] - public float VarianceMax = 0.35f; + public float VarianceMax = 0.15f; } diff --git a/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs b/Content.Shared/Procedural/DungeonLayers/WallMountDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/WallMountDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs b/Content.Shared/Procedural/DungeonLayers/WormCorridorDunGen.cs similarity index 100% rename from Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs rename to Content.Shared/Procedural/DungeonLayers/WormCorridorDunGen.cs diff --git a/Content.Shared/Procedural/Loot/BiomeLoot.cs b/Content.Shared/Procedural/Loot/BiomeLoot.cs new file mode 100644 index 0000000000..1330043493 --- /dev/null +++ b/Content.Shared/Procedural/Loot/BiomeLoot.cs @@ -0,0 +1,12 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.Loot; + +/// +/// Adds the prototype as a biome layer. +/// +public sealed partial class BiomeLoot : IDungeonLoot +{ + [DataField(required: true)] + public ProtoId Proto; +} diff --git a/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs b/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs deleted file mode 100644 index 2eda4b059c..0000000000 --- a/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Content.Shared.Parallax.Biomes.Markers; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; - -namespace Content.Shared.Procedural.Loot; - -/// -/// Adds a biome marker layer for dungeon loot. -/// -public sealed partial class BiomeMarkerLoot : IDungeonLoot -{ - [DataField("proto", required: true)] - public ProtoId Prototype = new(); -} diff --git a/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs b/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs deleted file mode 100644 index e4968b6e42..0000000000 --- a/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Content.Shared.Parallax.Biomes; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Procedural.Loot; - -/// -/// Adds a biome template layer for dungeon loot. -/// -public sealed partial class BiomeTemplateLoot : IDungeonLoot -{ - [DataField("proto", required: true)] - public ProtoId Prototype = string.Empty; -} diff --git a/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs deleted file mode 100644 index e21e582211..0000000000 --- a/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.Maps; -using Content.Shared.Parallax.Biomes; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Generates a biome on top of valid tiles, then removes the biome when done. -/// Only works if no existing biome is present. -/// -public sealed partial class BiomeDunGen : IDunGenLayer -{ - [DataField(required: true)] - public ProtoId BiomeTemplate; - - /// - /// creates a biome only on the specified tiles - /// - [DataField] - public HashSet>? TileMask; -} diff --git a/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs deleted file mode 100644 index af5d7c5d8f..0000000000 --- a/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Shared.Random; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Spawns the specified marker layer on top of the dungeon rooms. -/// -public sealed partial class BiomeMarkerLayerDunGen : IDunGenLayer -{ - /// - /// How many times to spawn marker layers; can duplicate. - /// - [DataField] - public int Count = 6; - - [DataField(required: true)] - public ProtoId MarkerTemplate; -} diff --git a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs index e84223ed1f..10106cd666 100644 --- a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs +++ b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs @@ -1,6 +1,4 @@ -using Content.Shared.Parallax.Biomes; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Salvage.Expeditions.Modifiers; @@ -26,6 +24,6 @@ public sealed partial class SalvageBiomeModPrototype : IPrototype, ISalvageMod [DataField("weather")] public bool Weather = true; - [DataField("biome", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string? BiomePrototype; + [DataField("biome", required: true)] + public EntProtoId? BiomePrototype; } diff --git a/Resources/Locale/en-US/procedural/biome.ftl b/Resources/Locale/en-US/procedural/biome.ftl index d24ec7d72e..7c2a88a696 100644 --- a/Resources/Locale/en-US/procedural/biome.ftl +++ b/Resources/Locale/en-US/procedural/biome.ftl @@ -1,6 +1,2 @@ -cmd-biome_clear-desc = Clears a biome entirely -cmd-biome_clear-help = biome_clear cmd-biome_addlayer-desc = Adds another biome layer cmd-biome_addlayer-help = biome_addlayer [seed offset] -cmd-biome_addmarkerlayer-desc = Adds another biome marker layer -cmd-biome_addmarkerlayer-help = biome_addmarkerlayer diff --git a/Resources/Prototypes/Entities/Tiles/water.yml b/Resources/Prototypes/Entities/Tiles/water.yml index c488df231b..357bc9f98c 100644 --- a/Resources/Prototypes/Entities/Tiles/water.yml +++ b/Resources/Prototypes/Entities/Tiles/water.yml @@ -17,10 +17,14 @@ drawdepth: BelowFloor layers: - state: shoreline_water + - type: BiomeForceUnload + #- type: ContainerContainer + # containers: + # solution@pool: !type:ContainerSlot - type: SolutionContainerManager solutions: pool: - maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable. + maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable. reagents: - ReagentId: Water Quantity: 9999999 diff --git a/Resources/Prototypes/Procedural/Magnet/asteroid.yml b/Resources/Prototypes/Procedural/Magnet/asteroid.yml index a77a6b287b..f838104f3c 100644 --- a/Resources/Prototypes/Procedural/Magnet/asteroid.yml +++ b/Resources/Prototypes/Procedural/Magnet/asteroid.yml @@ -18,8 +18,9 @@ lacunarity: 2 # Generate biome - - !type:BiomeDunGen - biomeTemplate: Asteroid + - !type:PrototypeDunGen + proto: Asteroid + inheritDungeons: All - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -47,8 +48,9 @@ lacunarity: 2 # Generate biome - - !type:BiomeDunGen - biomeTemplate: Asteroid + - !type:PrototypeDunGen + proto: Asteroid + inheritDungeons: All - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -76,8 +78,9 @@ cellularDistanceFunction: Euclidean # Generate biome - - !type:BiomeDunGen - biomeTemplate: Asteroid + - !type:PrototypeDunGen + proto: Asteroid + inheritDungeons: All - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -104,8 +107,9 @@ lacunarity: 2 # Generate biome - - !type:BiomeDunGen - biomeTemplate: Asteroid + - !type:PrototypeDunGen + proto: Asteroid + inheritDungeons: All - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite diff --git a/Resources/Prototypes/Procedural/Magnet/space_debris.yml b/Resources/Prototypes/Procedural/Magnet/space_debris.yml index 11c1afdabe..a9bd823e6b 100644 --- a/Resources/Prototypes/Procedural/Magnet/space_debris.yml +++ b/Resources/Prototypes/Procedural/Magnet/space_debris.yml @@ -36,8 +36,9 @@ gain: 0.5 # Generate biome - - !type:BiomeDunGen - biomeTemplate: SpaceDebris + - !type:PrototypeDunGen + proto: SpaceDebris + inheritDungeons: All - type: dungeonConfig id: ChunkDebrisSmall @@ -77,5 +78,6 @@ gain: 0.5 # Generate biome - - !type:BiomeDunGen - biomeTemplate: SpaceDebris + - !type:PrototypeDunGen + proto: SpaceDebris + inheritDungeons: All diff --git a/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml b/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml index 47aa47fce4..e181f89268 100644 --- a/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml +++ b/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml @@ -1,8 +1,8 @@ # Asteroid -- type: biomeTemplate +- type: dungeonConfig id: SpaceDebris layers: - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.20 noise: seed: 0 @@ -23,7 +23,7 @@ - WallReinforced - WallSolid - WallSolid - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.5 noise: seed: 0 @@ -41,7 +41,7 @@ - Grille - Grille - GrilleBroken - - !type:BiomeDecalLayer + - !type:SampleDecalDunGen allowedTiles: - FloorSteel threshold: -0.5 @@ -56,7 +56,7 @@ - DirtMedium - DirtMedium - DirtLight - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.45 noise: seed: 1 @@ -71,7 +71,7 @@ - FloorSteel entities: - SalvageSpawnerStructuresVarious - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen allowedTiles: - FloorSteel - Plating @@ -85,7 +85,7 @@ - SalvageSpawnerScrapCommon - SalvageSpawnerScrapCommon - SalvageSpawnerScrapCommon75 - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen allowedTiles: - FloorSteel - Plating @@ -97,7 +97,7 @@ - SalvageSpawnerTreasure - SalvageSpawnerTreasure - SalvageSpawnerTreasureValuable - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen allowedTiles: - FloorSteel - Plating diff --git a/Resources/Prototypes/Procedural/biome_markers.yml b/Resources/Prototypes/Procedural/biome_markers.yml index 5c4fdeb178..ef28b314ca 100644 --- a/Resources/Prototypes/Procedural/biome_markers.yml +++ b/Resources/Prototypes/Procedural/biome_markers.yml @@ -1,67 +1,122 @@ -- type: biomeMarkerLayer +- type: dungeonConfig id: Lizards - prototype: MobLizard - minGroupSize: 3 - maxGroupSize: 5 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobLizard + amount: !type:RangeNumberSelector + range: 3, 5 -- type: biomeMarkerLayer + +- type: dungeonConfig id: WatchersLavaland - prototype: MobWatcherLavaland - minGroupSize: 3 - maxGroupSize: 3 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobWatcherLavaland + amount: !type:RangeNumberSelector + range: 3, 3 -- type: biomeMarkerLayer +- type: dungeonConfig id: WatchersIcewing - prototype: MobWatcherIcewing - minGroupSize: 3 - maxGroupSize: 3 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobWatcherIcewing + amount: !type:RangeNumberSelector + range: 3, 3 -- type: biomeMarkerLayer +- type: dungeonConfig id: WatchersMagmawing - prototype: MobWatcherMagmawing - minGroupSize: 3 - maxGroupSize: 3 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobWatcherMagmawing + amount: !type:RangeNumberSelector + range: 3, 3 -- type: biomeMarkerLayer +- type: dungeonConfig id: Cows - prototype: MobCow - minGroupSize: 1 - maxGroupSize: 2 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobCow + amount: !type:RangeNumberSelector + range: 1, 2 -- type: biomeMarkerLayer +- type: dungeonConfig id: Chickens - prototype: MobChicken - minGroupSize: 1 - maxGroupSize: 2 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobChicken + amount: !type:RangeNumberSelector + range: 1, 2 -- type: biomeMarkerLayer +- type: dungeonConfig id: Pigs - prototype: MobPig - minGroupSize: 1 - maxGroupSize: 2 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobPig + amount: !type:RangeNumberSelector + range: 1, 2 -- type: biomeMarkerLayer +- type: dungeonConfig id: Foxes - prototype: MobFox - minGroupSize: 1 - maxGroupSize: 1 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobFox + amount: !type:RangeNumberSelector + range: 1, 1 -- type: biomeMarkerLayer +- type: dungeonConfig id: Goats - prototype: MobGoat - minGroupSize: 1 - maxGroupSize: 1 + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobGoat + amount: !type:RangeNumberSelector + range: 1, 1 -# TODO: Needs to be more robust -- type: biomeMarkerLayer - id: Xenos - prototype: MobXeno - -- type: biomeMarkerLayer +- type: dungeonConfig id: Carps - prototype: MobCarpDungeon + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobCarp + amount: !type:RangeNumberSelector + range: 1, 2 +- type: dungeonConfig + id: Xenos + layers: + - !type:ChunkDunGen + size: 128 + - !type:EntityTableDunGen + table: !type:EntSelector + id: MobXeno + amount: !type:RangeNumberSelector + range: 1, 2 -#- type: biomeMarkerLayer -# id: Experiment -# proto: DungeonMarkerExperiment diff --git a/Resources/Prototypes/Procedural/biome_ore_templates.yml b/Resources/Prototypes/Procedural/biome_ore_templates.yml index ae033230b6..16b2c7e64f 100644 --- a/Resources/Prototypes/Procedural/biome_ore_templates.yml +++ b/Resources/Prototypes/Procedural/biome_ore_templates.yml @@ -1,146 +1,127 @@ # Low value -- type: biomeMarkerLayer +- type: dungeonConfig id: OreIron - entityMask: - AsteroidRock: AsteroidRockTin - WallRock: WallRockTin - WallRockBasalt: WallRockBasaltTin - WallRockChromite: WallRockChromiteTin - WallRockSand: WallRockSandTin - WallRockSnow: WallRockSnowTin - maxCount: 30 - minGroupSize: 10 - maxGroupSize: 15 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockTin + count: 30 + minGroupSize: 10 + maxGroupSize: 15 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreQuartz - entityMask: - AsteroidRock: AsteroidRockQuartz - WallRock: WallRockQuartz - WallRockBasalt: WallRockBasaltQuartz - WallRockChromite: WallRockChromiteQuartz - WallRockSnow: WallRockSnowQuartz - maxCount: 30 - minGroupSize: 10 - maxGroupSize: 15 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockQuartz + count: 30 + minGroupSize: 10 + maxGroupSize: 15 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreCoal - entityMask: - AsteroidRock: AsteroidRockCoal - WallRock: WallRockCoal - WallRockBasalt: WallRockBasaltCoal - WallRockChromite: WallRockChromiteCoal - WallRockSand: WallRockSandCoal - WallRockSnow: WallRockSnowCoal - maxCount: 30 - minGroupSize: 8 - maxGroupSize: 12 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockCoal + count: 30 + minGroupSize: 8 + maxGroupSize: 12 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreSalt - entityMask: - AsteroidRock: AsteroidRockSalt - WallRock: WallRockSalt - WallRockBasalt: WallRockBasaltSalt - WallRockChromite: WallRockChromiteSalt - WallRockSand: WallRockSandSalt - WallRockSnow: WallRockSnowSalt - maxCount: 30 - minGroupSize: 8 - maxGroupSize: 12 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockSalt + count: 30 + minGroupSize: 8 + maxGroupSize: 12 # Medium value # Gold -- type: biomeMarkerLayer +- type: dungeonConfig id: OreGold - entityMask: - AsteroidRock: AsteroidRockGold - WallRock: WallRockGold - WallRockBasalt: WallRockBasaltGold - WallRockChromite: WallRockChromiteGold - WallRockSand: WallRockSandGold - WallRockSnow: WallRockSnowGold - maxCount: 20 - minGroupSize: 5 - maxGroupSize: 10 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockGold + count: 20 + minGroupSize: 5 + maxGroupSize: 10 # Silver -- type: biomeMarkerLayer +- type: dungeonConfig id: OreSilver - entityMask: - AsteroidRock: AsteroidRockSilver - WallRock: WallRockSilver - WallRockBasalt: WallRockBasaltSilver - WallRockChromite: WallRockChromiteSilver - WallRockSand: WallRockSandSilver - WallRockSnow: WallRockSnowSilver - maxCount: 20 - minGroupSize: 5 - maxGroupSize: 10 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockSilver + count: 20 + minGroupSize: 5 + maxGroupSize: 10 # High value # Plasma -- type: biomeMarkerLayer +- type: dungeonConfig id: OrePlasma - entityMask: - AsteroidRock: AsteroidRockPlasma - WallRock: WallRockPlasma - WallRockBasalt: WallRockBasaltPlasma - WallRockChromite: WallRockChromitePlasma - WallRockSand: WallRockSandPlasma - WallRockSnow: WallRockSnowPlasma - maxCount: 12 - minGroupSize: 4 - maxGroupSize: 8 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockPlasma + count: 12 + minGroupSize: 4 + maxGroupSize: 8 # Uranium -- type: biomeMarkerLayer +- type: dungeonConfig id: OreUranium - entityMask: - AsteroidRock: AsteroidRockUranium - WallRock: WallRockUranium - WallRockBasalt: WallRockBasaltUranium - WallRockChromite: WallRockChromiteUranium - WallRockSand: WallRockSandUranium - WallRockSnow: WallRockSnowUranium - maxCount: 15 - minGroupSize: 4 - maxGroupSize: 8 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockUranium + count: 15 + minGroupSize: 4 + maxGroupSize: 8 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreDiamond - entityMask: - AsteroidRock: AsteroidRockDiamond - WallRock: WallRockDiamond - WallRockBasalt: WallRockBasaltDiamond - WallRockChromite: WallRockChromiteDiamond - WallRockSand: WallRockSandDiamond - WallRockSnow: WallRockSnowDiamond - maxCount: 6 - minGroupSize: 1 - maxGroupSize: 2 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockDiamond + count: 6 + minGroupSize: 1 + maxGroupSize: 2 # Artifact Fragment -- type: biomeMarkerLayer +- type: dungeonConfig id: OreArtifactFragment - entityMask: - AsteroidRock: AsteroidRockArtifactFragment - WallRock: WallRockArtifactFragment - WallRockBasalt: WallRockBasaltArtifactFragment - WallRockChromite: WallRockChromiteArtifactFragment - WallRockSand: WallRockSandArtifactFragment - WallRockSnow: WallRockSnowArtifactFragment - maxCount: 6 - minGroupSize: 1 - maxGroupSize: 2 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockArtifactFragment + count: 6 + minGroupSize: 1 + maxGroupSize: 2 diff --git a/Resources/Prototypes/Procedural/biome_ore_templates_low.yml b/Resources/Prototypes/Procedural/biome_ore_templates_low.yml index 3b0e242446..9af10e3c2b 100644 --- a/Resources/Prototypes/Procedural/biome_ore_templates_low.yml +++ b/Resources/Prototypes/Procedural/biome_ore_templates_low.yml @@ -1,146 +1,127 @@ # Low value -- type: biomeMarkerLayer +- type: dungeonConfig id: OreIronLow - entityMask: - AsteroidRock: AsteroidRockTin - WallRock: WallRockTin - WallRockBasalt: WallRockBasaltTin - WallRockChromite: WallRockChromiteTin - WallRockSand: WallRockSandTin - WallRockSnow: WallRockSnowTin - maxCount: 20 - minGroupSize: 4 - maxGroupSize: 8 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockTin + count: 20 + minGroupSize: 4 + maxGroupSize: 8 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreQuartzLow - entityMask: - AsteroidRock: AsteroidRockQuartz - WallRock: WallRockQuartz - WallRockBasalt: WallRockBasaltQuartz - WallRockChromite: WallRockChromiteQuartz - WallRockSnow: WallRockSnowQuartz - maxCount: 20 - minGroupSize: 4 - maxGroupSize: 8 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockQuartz + count: 20 + minGroupSize: 4 + maxGroupSize: 8 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreCoalLow - entityMask: - AsteroidRock: AsteroidRockCoal - WallRock: WallRockCoal - WallRockBasalt: WallRockBasaltCoal - WallRockChromite: WallRockChromiteCoal - WallRockSand: WallRockSandCoal - WallRockSnow: WallRockSnowCoal - maxCount: 20 - minGroupSize: 4 - maxGroupSize: 6 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockCoal + count: 20 + minGroupSize: 4 + maxGroupSize: 6 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreSaltLow - entityMask: - AsteroidRock: AsteroidRockSalt - WallRock: WallRockSalt - WallRockBasalt: WallRockBasaltSalt - WallRockChromite: WallRockChromiteSalt - WallRockSand: WallRockSandSalt - WallRockSnow: WallRockSnowSalt - maxCount: 15 - minGroupSize: 4 - maxGroupSize: 6 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockSalt + count: 15 + minGroupSize: 4 + maxGroupSize: 6 # Medium value # Gold -- type: biomeMarkerLayer +- type: dungeonConfig id: OreGoldLow - entityMask: - AsteroidRock: AsteroidRockGold - WallRock: WallRockGold - WallRockBasalt: WallRockBasaltGold - WallRockChromite: WallRockChromiteGold - WallRockSand: WallRockSandGold - WallRockSnow: WallRockSnowGold - maxCount: 10 - minGroupSize: 2 - maxGroupSize: 5 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockGold + count: 12 + minGroupSize: 2 + maxGroupSize: 5 # Silver -- type: biomeMarkerLayer +- type: dungeonConfig id: OreSilverLow - entityMask: - AsteroidRock: AsteroidRockSilver - WallRock: WallRockSilver - WallRockBasalt: WallRockBasaltSilver - WallRockChromite: WallRockChromiteSilver - WallRockSand: WallRockSandSilver - WallRockSnow: WallRockSnowSilver - maxCount: 10 - minGroupSize: 2 - maxGroupSize: 5 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockSilver + count: 12 + minGroupSize: 2 + maxGroupSize: 5 # High value # Plasma -- type: biomeMarkerLayer +- type: dungeonConfig id: OrePlasmaLow - entityMask: - AsteroidRock: AsteroidRockPlasma - WallRock: WallRockPlasma - WallRockBasalt: WallRockBasaltPlasma - WallRockChromite: WallRockChromitePlasma - WallRockSand: WallRockSandPlasma - WallRockSnow: WallRockSnowPlasma - maxCount: 6 - minGroupSize: 2 - maxGroupSize: 4 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockPlasma + count: 6 + minGroupSize: 2 + maxGroupSize: 4 # Uranium -- type: biomeMarkerLayer +- type: dungeonConfig id: OreUraniumLow - entityMask: - AsteroidRock: AsteroidRockUranium - WallRock: WallRockUranium - WallRockBasalt: WallRockBasaltUranium - WallRockChromite: WallRockChromiteUranium - WallRockSand: WallRockSandUranium - WallRockSnow: WallRockSnowUranium - maxCount: 7 - minGroupSize: 2 - maxGroupSize: 4 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockUranium + count: 7 + minGroupSize: 2 + maxGroupSize: 4 -- type: biomeMarkerLayer +- type: dungeonConfig id: OreDiamondLow - entityMask: - AsteroidRock: AsteroidRockDiamond - WallRock: WallRockDiamond - WallRockBasalt: WallRockBasaltDiamond - WallRockChromite: WallRockChromiteDiamond - WallRockSand: WallRockSandDiamond - WallRockSnow: WallRockSnowDiamond - maxCount: 3 - minGroupSize: 1 - maxGroupSize: 2 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockDiamond + count: 3 + minGroupSize: 1 + maxGroupSize: 2 # Artifact Fragment -- type: biomeMarkerLayer +- type: dungeonConfig id: OreArtifactFragmentLow - entityMask: - AsteroidRock: AsteroidRockArtifactFragment - WallRock: WallRockArtifactFragment - WallRockBasalt: WallRockBasaltArtifactFragment - WallRockChromite: WallRockChromiteArtifactFragment - WallRockSand: WallRockSandArtifactFragment - WallRockSnow: WallRockSnowArtifactFragment - maxCount: 3 - minGroupSize: 1 - maxGroupSize: 2 - radius: 4 + layers: + - !type:ChunkDunGen + size: 128 + - !type:OreDunGen + replacement: WallRock + entity: WallRockArtifactFragment + count: 3 + minGroupSize: 1 + maxGroupSize: 2 diff --git a/Resources/Prototypes/Procedural/biome_templates.yml b/Resources/Prototypes/Procedural/biome_templates.yml index d630ebad48..747660dc8f 100644 --- a/Resources/Prototypes/Procedural/biome_templates.yml +++ b/Resources/Prototypes/Procedural/biome_templates.yml @@ -1,435 +1,551 @@ -# Contains several biomes -- type: biomeTemplate - id: Continental - layers: - - !type:BiomeMetaLayer - template: Lava - - !type:BiomeMetaLayer - template: Caves - threshold: -0.5 - noise: - frequency: 0.001 - noiseType: OpenSimplex2 - fractalType: FBm - octaves: 2 - lacunarity: 2 - - !type:BiomeMetaLayer - template: Grasslands - threshold: 0 - noise: - frequency: 0.001 - noiseType: OpenSimplex2 - fractalType: FBm - octaves: 2 - lacunarity: 2 - - !type:BiomeMetaLayer - template: Snow - threshold: 0.5 - noise: - frequency: 0.001 - noiseType: OpenSimplex2 - fractalType: FBm - octaves: 2 - lacunarity: 2 - # Desert -# TODO: Water in desert -- type: biomeTemplate - id: LowDesert - layers: - - !type:BiomeEntityLayer - threshold: 0.95 - noise: - seed: 0 - frequency: 2 - noiseType: OpenSimplex2 - allowedTiles: - - FloorAsteroidSand - entities: - - FloraRockSolid - # Large rock areas - - !type:BiomeEntityLayer - threshold: -0.20 - noise: - seed: 0 - frequency: 0.04 - noiseType: Cellular - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - allowedTiles: - - FloorAsteroidSand - entities: - - WallRockSand - - !type:BiomeDummyLayer - id: Loot - # Fill layer - - !type:BiomeTileLayer - threshold: -1 - tile: FloorAsteroidSand +- type: entity + id: BiomeLowDesert + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: LowDesertTerrain -# Grass -- type: biomeTemplate - id: Grasslands +- type: dungeonConfig + id: LowDesertTerrain layers: - # Sparse vegetation - - !type:BiomeDecalLayer - allowedTiles: - - FloorPlanetGrass - divisions: 2 - threshold: -0.50 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - decals: - - BushDOne - - BushDTwo - - BushDThree - - !type:BiomeDecalLayer - allowedTiles: - - FloorPlanetGrass - noise: - seed: 0 - noiseType: OpenSimplex2 - frequency: 1 - divisions: 1 - threshold: 0.8 - decals: - - FlowersBROne - - FlowersBRTwo - - FlowersBRThree - # Dense vegetation - - !type:BiomeDecalLayer - allowedTiles: - - FloorPlanetGrass - divisions: 1 - threshold: -0.35 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.2 - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - BushAOne - - BushATwo - - BushAThree - - BushCOne - - BushCTwo - - BushCThree - - !type:BiomeEntityLayer - threshold: 0.5 - noise: - seed: 0 - noiseType: OpenSimplex2 - fractalType: FBm - frequency: 2 - allowedTiles: - - FloorPlanetGrass - entities: - - FloraTree - - FloraTreeLarge - # Rock formations - - !type:BiomeEntityLayer - allowedTiles: - - FloorPlanetGrass - - FloorPlanetDirt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRock - - !type:BiomeDummyLayer - id: Loot - # Water - - !type:BiomeEntityLayer - allowedTiles: - - FloorPlanetGrass - - FloorPlanetDirt - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - entities: - - FloorWaterEntity - # Fill remainder with dirt. - - !type:BiomeTileLayer - threshold: -1.0 - tile: FloorPlanetDirt - - !type:BiomeTileLayer - threshold: -0.90 - tile: FloorPlanetGrass - noise: - seed: 0 - frequency: 0.02 - fractalType: None - # Water sand - - !type:BiomeTileLayer - tile: FloorPlanetDirt - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - # Rock formation sand - - !type:BiomeTileLayer - tile: FloorPlanetDirt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: LowDesertTiles + inheritDungeons: All + - !type:PrototypeDunGen + proto: LowDesertEntities + inheritDungeons: All + +- type: dungeonConfig + id: LowDesertTiles + returnReserved: false + layers: + - !type:SampleTileDunGen + threshold: -1 + tile: FloorAsteroidSand + +- type: dungeonConfig + id: LowDesertEntities + reserveTiles: true + layers: + - !type:SampleEntityDunGen + threshold: 0.95 + noise: + seed: 0 + frequency: 2 + noiseType: OpenSimplex2 + allowedTiles: + - FloorAsteroidSand + entities: + - FloraRockSolid + # Large rock areas + - !type:SampleEntityDunGen + threshold: -0.20 + noise: + seed: 0 + frequency: 0.04 + noiseType: Cellular + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + allowedTiles: + - FloorAsteroidSand + entities: + - WallRockSand + + +- type: entity + id: BiomeGrasslands + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: GrasslandsTerrain + +- type: dungeonConfig + id: GrasslandsTerrain + layers: + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: GrasslandsTiles + inheritDungeons: All + - !type:PrototypeDunGen + proto: GrasslandsEntities + inheritDungeons: All + - !type:PrototypeDunGen + proto: GrasslandsDecals + inheritDungeons: All + +- type: dungeonConfig + id: GrasslandsTiles + returnReserved: false + layers: + # Water sand + - !type:SampleTileDunGen + tile: FloorPlanetDirt + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + # Rock formation sand + - !type:SampleTileDunGen + tile: FloorPlanetDirt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + - !type:SampleTileDunGen + threshold: -0.80 + tile: FloorPlanetGrass + noise: + seed: 0 + noiseType: OpenSimplex2 + lacunarity: 1.50 + frequency: 0.02 + fractalType: None + octaves: 1 + # Fill remainder with dirt. + - !type:SampleTileDunGen + threshold: -1.0 + tile: FloorPlanetDirt + +- type: dungeonConfig + id: GrasslandsEntities + reserveTiles: true + layers: + # Water + - !type:SampleEntityDunGen + allowedTiles: + - FloorPlanetGrass + - FloorPlanetDirt + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + entities: + - FloorWaterEntity + # Rock formations + - !type:SampleEntityDunGen + allowedTiles: + - FloorPlanetGrass + - FloorPlanetDirt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRock + - !type:SampleEntityDunGen + threshold: 0.5 + noise: + seed: 0 + noiseType: OpenSimplex2 + fractalType: FBm + frequency: 2 + allowedTiles: + - FloorPlanetGrass + entities: + - FloraTree + - FloraTreeLarge + +- type: dungeonConfig + id: GrasslandsDecals + returnReserved: false + layers: + # Dense vegetation + - !type:SampleDecalDunGen + allowedTiles: + - FloorPlanetGrass + divisions: 1 + threshold: -0.35 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.2 + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - BushAOne + - BushATwo + - BushAThree + - BushCOne + - BushCTwo + - BushCThree + - !type:SampleDecalDunGen + allowedTiles: + - FloorPlanetGrass + noise: + seed: 0 + noiseType: OpenSimplex2 + frequency: 1 + divisions: 1 + threshold: 0.8 + decals: + - FlowersBROne + - FlowersBRTwo + - FlowersBRThree + # Sparse vegetation + - !type:SampleDecalDunGen + allowedTiles: + - FloorPlanetGrass + divisions: 2 + threshold: -0.50 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + decals: + - BushDOne + - BushDTwo + - BushDThree # Lava -- type: biomeTemplate - id: Lava +- type: entity + id: BiomeLava + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: LavaTerrain + +- type: dungeonConfig + id: LavaTerrain layers: - - !type:BiomeEntityLayer - threshold: 0.9 - noise: - frequency: 1 - seed: 2 - allowedTiles: - - FloorBasalt - entities: - - BasaltOne - - BasaltTwo - - BasaltThree - - BasaltFour - - BasaltFive - - !type:BiomeDecalLayer - allowedTiles: - - FloorBasalt - threshold: 0.9 - divisions: 1 - noise: - seed: 1 - frequency: 1 - decals: - - Basalt1 - - Basalt2 - - Basalt3 - - Basalt4 - - Basalt5 - - Basalt6 - - Basalt7 - - Basalt8 - - Basalt9 - - !type:BiomeEntityLayer - threshold: 0.95 - noise: - seed: 0 - noiseType: OpenSimplex2 - frequency: 1 - allowedTiles: - - FloorBasalt - entities: - - FloraRockSolid - - !type:BiomeEntityLayer - threshold: 0.2 - noise: - seed: 0 - frequency: 0.02 - fractalType: FBm - octaves: 5 - lacunarity: 2 - gain: 0.4 - allowedTiles: - - FloorBasalt - entities: - - FloorLavaEntity - # Rock formations - - !type:BiomeEntityLayer - allowedTiles: - - FloorBasalt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRockBasalt - - !type:BiomeDummyLayer - id: Loot - # Fill basalt - - !type:BiomeTileLayer - threshold: -1 - tile: FloorBasalt + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: LavaTiles + inheritDungeons: All + - !type:PrototypeDunGen + proto: LavaEntities + inheritDungeons: All + - !type:PrototypeDunGen + proto: LavaDecals + inheritDungeons: All + - !type:PrototypeDunGen + proto: LavaBasalt + inheritDungeons: All + +- type: dungeonConfig + id: LavaTiles + returnReserved: false + layers: + # Fill basalt + - !type:SampleTileDunGen + threshold: -1 + tile: FloorBasalt + +- type: dungeonConfig + id: LavaEntities + reserveTiles: true + layers: + - !type:SampleEntityDunGen + threshold: 0.2 + noise: + seed: 0 + frequency: 0.02 + fractalType: FBm + octaves: 5 + lacunarity: 2 + gain: 0.4 + allowedTiles: + - FloorBasalt + entities: + - FloorLavaEntity + # Rock formations + - !type:SampleEntityDunGen + allowedTiles: + - FloorBasalt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRockBasalt + - !type:SampleEntityDunGen + threshold: 0.95 + noise: + seed: 0 + noiseType: OpenSimplex2 + frequency: 1 + allowedTiles: + - FloorBasalt + entities: + - FloraRockSolid + +- type: dungeonConfig + id: LavaDecals + returnReserved: false + layers: + - !type:SampleDecalDunGen + allowedTiles: + - FloorBasalt + threshold: 0.9 + divisions: 1 + noise: + seed: 1 + frequency: 1 + decals: + - Basalt1 + - Basalt2 + - Basalt3 + - Basalt4 + - Basalt5 + - Basalt6 + - Basalt7 + - Basalt8 + - Basalt9 + +- type: dungeonConfig + id: LavaBasalt + returnReserved: false + layers: + - !type:SampleEntityDunGen + threshold: 0.9 + noise: + frequency: 1 + seed: 2 + allowedTiles: + - FloorBasalt + entities: + - BasaltOne + - BasaltTwo + - BasaltThree + - BasaltFour + - BasaltFive # Snow -- type: biomeTemplate - id: Snow # Similar to Grasslands... but snow +- type: entity + id: BiomeSnow + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: SnowTerrain + +- type: dungeonConfig + id: SnowTerrain layers: - # Sparse vegetation - - !type:BiomeDecalLayer - allowedTiles: - - FloorSnow - divisions: 2 - threshold: -0.50 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - decals: - - grasssnowa1 - - grasssnowa2 - - grasssnowa3 - - grasssnowb1 - - grasssnowb2 - - grasssnowb3 - - grasssnowc1 - - grasssnowc2 - - grasssnowc3 - # Dense, bland grass - - !type:BiomeDecalLayer - allowedTiles: - - FloorSnow - divisions: 1 - threshold: -0.35 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.2 - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - grasssnow - - grasssnow01 - - grasssnow02 - - grasssnow03 - - grasssnow04 - - grasssnow05 - - grasssnow06 - - grasssnow07 - - grasssnow08 - - grasssnow09 - - grasssnow10 - - grasssnow11 - - grasssnow12 - - grasssnow13 - # Little bit of coloured grass - - !type:BiomeDecalLayer - allowedTiles: - - FloorSnow - divisions: 1 - threshold: -0.0 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - fractalType: None - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - bushsnowa1 - - bushsnowa2 - - bushsnowa3 - - bushsnowb3 - - bushsnowb2 - - bushsnowb3 - - !type:BiomeEntityLayer - threshold: 0.5 - noise: - seed: 0 - noiseType: OpenSimplex2 - fractalType: FBm - frequency: 2 - allowedTiles: - - FloorSnow - entities: - - FloraTreeSnow - # Rock formations - - !type:BiomeEntityLayer - allowedTiles: - - FloorSnow - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRockSnow - # Ice tiles - - !type:BiomeTileLayer - tile: FloorIce - threshold: -0.9 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.03 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - # Liquid plasma rivers. Ice moon baby - - !type:BiomeEntityLayer - allowedTiles: - - FloorSnow - - FloorIce - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - entities: - - FloorLiquidPlasmaEntity - - !type:BiomeDummyLayer - id: Loot - - !type:BiomeTileLayer - threshold: -0.7 - tile: FloorSnow - noise: - seed: 0 - frequency: 0.02 - fractalType: None + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: SnowTiles + inheritDungeons: All + - !type:PrototypeDunGen + proto: SnowEntities + inheritDungeons: All + - !type:PrototypeDunGen + proto: SnowDecals + inheritDungeons: All + +- type: dungeonConfig + id: SnowTiles + returnReserved: false + layers: + - !type:SampleTileDunGen + threshold: -0.7 + tile: FloorSnow + noise: + seed: 0 + frequency: 0.02 + fractalType: None + - !type:SampleTileDunGen + tile: FloorIce + threshold: -0.9 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.03 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + + +- type: dungeonConfig + id: SnowEntities + reserveTiles: true + layers: + # Liquid plasma rivers. Ice moon baby + - !type:SampleEntityDunGen + allowedTiles: + - FloorSnow + - FloorIce + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + entities: + - FloorLiquidPlasmaEntity + # Rock formations + - !type:SampleEntityDunGen + allowedTiles: + - FloorSnow + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRockSnow + - !type:SampleEntityDunGen + threshold: 0.5 + noise: + seed: 0 + noiseType: OpenSimplex2 + fractalType: FBm + frequency: 2 + allowedTiles: + - FloorSnow + entities: + - FloraTreeSnow + +- type: dungeonConfig + id: SnowDecals + returnReserved: false + layers: + # Sparse vegetation + - !type:SampleDecalDunGen + allowedTiles: + - FloorSnow + divisions: 2 + threshold: -0.50 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + decals: + - grasssnowa1 + - grasssnowa2 + - grasssnowa3 + - grasssnowb1 + - grasssnowb2 + - grasssnowb3 + - grasssnowc1 + - grasssnowc2 + - grasssnowc3 + # Dense, bland grass + - !type:SampleDecalDunGen + allowedTiles: + - FloorSnow + divisions: 1 + threshold: -0.35 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.2 + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - grasssnow + - grasssnow01 + - grasssnow02 + - grasssnow03 + - grasssnow04 + - grasssnow05 + - grasssnow06 + - grasssnow07 + - grasssnow08 + - grasssnow09 + - grasssnow10 + - grasssnow11 + - grasssnow12 + - grasssnow13 + # Little bit of coloured grass + - !type:SampleDecalDunGen + allowedTiles: + - FloorSnow + divisions: 1 + threshold: -0.0 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + fractalType: None + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - bushsnowa1 + - bushsnowa2 + - bushsnowa3 + - bushsnowb3 + - bushsnowb2 + - bushsnowb3 # Shadow -> Derived from lava -- type: biomeTemplate - id: Shadow +- type: entity + id: BiomeShadow + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: ShadowTerrain + +- type: dungeonConfig + id: ShadowTerrain layers: - - !type:BiomeEntityLayer + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: ShadowTiles + inheritDungeons: All + - !type:PrototypeDunGen + proto: ShadowEntities + inheritDungeons: All + +- type: dungeonConfig + id: ShadowEntities + reserveTiles: true + layers: + - !type:SampleEntityDunGen threshold: 0.70 noise: frequency: 1 @@ -442,7 +558,7 @@ - ShadowBasaltThree - ShadowBasaltFour - ShadowBasaltFive - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.97 noise: frequency: 1 @@ -451,7 +567,7 @@ - FloorChromite entities: - CrystalPink - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.97 noise: seed: 1 @@ -462,7 +578,7 @@ entities: - ShadowTree # Rock formations - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: -0.2 invert: true noise: @@ -477,7 +593,7 @@ entities: - WallRockChromite # chasm time - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen allowedTiles: - FloorChromite threshold: 0.2 @@ -490,18 +606,43 @@ gain: 0.4 entities: - FloorChromiteChasm - - !type:BiomeDummyLayer - id: Loot - # Fill chromite - - !type:BiomeTileLayer - threshold: -1 - tile: FloorChromite + +- type: dungeonConfig + id: ShadowTiles + returnReserved: false + layers: + # Fill chromite + - !type:SampleTileDunGen + threshold: -1 + tile: FloorChromite # Caves -- type: biomeTemplate - id: Caves +- type: entity + id: BiomeCaves + categories: [ HideSpawnMenu ] + components: + - type: Biome + layers: + terrain: + dungeon: CavesTerrain + +- type: dungeonConfig + id: CavesTerrain layers: - - !type:BiomeEntityLayer + - !type:ChunkDunGen + - !type:PrototypeDunGen + proto: CavesTiles + inheritDungeons: All + - !type:RoofDunGen + - !type:PrototypeDunGen + proto: CavesEntities + inheritDungeons: All + +- type: dungeonConfig + id: CavesEntities + reserveTiles: true + layers: + - !type:SampleEntityDunGen threshold: 0.85 noise: seed: 2 @@ -517,7 +658,7 @@ - CrystalBlue - CrystalYellow - CrystalCyan - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.95 noise: seed: 1 @@ -527,7 +668,7 @@ - FloorAsteroidSand entities: - FloraStalagmite - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: -0.5 invert: true noise: @@ -541,17 +682,24 @@ - FloorAsteroidSand entities: - WallRock - - !type:BiomeDummyLayer - id: Loot - - !type:BiomeTileLayer - threshold: -1.0 - tile: FloorAsteroidSand + +- type: dungeonConfig + id: CavesTiles + returnReserved: false + layers: + - !type:SampleTileDunGen + threshold: -1.0 + tile: FloorAsteroidSand # Asteroid -- type: biomeTemplate +- type: dungeonConfig id: Asteroid layers: - - !type:BiomeEntityLayer + - !type:SampleTileDunGen + threshold: -1.0 + tile: FloorAsteroidSand + reserveTiles: false + - !type:SampleEntityDunGen threshold: 0.85 noise: seed: 2 @@ -567,7 +715,7 @@ - CrystalBlue - CrystalYellow - CrystalCyan - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen threshold: 0.95 noise: seed: 1 @@ -577,7 +725,8 @@ - FloorAsteroidSand entities: - FloraStalagmite - - !type:BiomeEntityLayer + - !type:SampleEntityDunGen + reserveTiles: false threshold: -0.6 invert: true noise: @@ -591,6 +740,3 @@ - FloorAsteroidSand entities: - AsteroidRock - - !type:BiomeTileLayer - threshold: -1.0 - tile: FloorAsteroidSand diff --git a/Resources/Prototypes/Procedural/dungeon_configs.yml b/Resources/Prototypes/Procedural/dungeon_configs.yml index 5da9592995..18d50ec6cd 100644 --- a/Resources/Prototypes/Procedural/dungeon_configs.yml +++ b/Resources/Prototypes/Procedural/dungeon_configs.yml @@ -79,6 +79,9 @@ id: Haunted layers: - !type:PrefabDunGen + roomWhitelist: + tags: + - Haunted presets: - Bucket - Wow diff --git a/Resources/Prototypes/Procedural/salvage_loot.yml b/Resources/Prototypes/Procedural/salvage_loot.yml index cf23601978..289fa5fd57 100644 --- a/Resources/Prototypes/Procedural/salvage_loot.yml +++ b/Resources/Prototypes/Procedural/salvage_loot.yml @@ -3,108 +3,108 @@ - type: salvageLoot id: SalvageLoot loots: - - !type:RandomSpawnsLoot - entries: - - proto: AdvMopItem - prob: 0.5 - - proto: AmmoTechFabCircuitboard - cost: 2 - - proto: AutolatheMachineCircuitboard - cost: 2 - - proto: BiomassReclaimerMachineCircuitboard - cost: 2 - - proto: BluespaceBeaker - cost: 2 - - proto: CyborgEndoskeleton - cost: 3 - prob: 0.5 - - proto: ChemDispenserMachineCircuitboard - cost: 2 - - proto: CircuitImprinter - cost: 2 - - proto: CloningConsoleComputerCircuitboard - cost: 2 - - proto: CloningPodMachineCircuitboard - cost: 2 - - proto: ChemistryBottleCognizine - - proto: FoodBoxDonkpocketCarp - prob: 0.5 - - proto: CrateSalvageEquipment - cost: 3 - prob: 0.5 - - proto: GasRecycler - cost: 2 - - proto: GeneratorRTG - cost: 5 - - proto: GravityGeneratorMini - cost: 2 - - proto: GyroscopeUnanchored - cost: 2 - prob: 0.1 - - proto: MedicalScannerMachineCircuitboard - cost: 2 - - proto: NuclearBombKeg - cost: 5 - - proto: ChemistryBottleOmnizine - prob: 0.5 - - proto: PortableGeneratorPacman - cost: 2 - - proto: PortableGeneratorSuperPacman - cost: 3 - - proto: PowerCellAntiqueProto - cost: 5 - prob: 0.5 - - proto: ProtolatheMachineCircuitboard - - proto: RandomArtifactSpawner - cost: 2 - - proto: RandomCargoCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomCommandCorpseSpawner - cost: 5 - prob: 0.5 - - proto: RandomEngineerCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomMedicCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomScienceCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomSecurityCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomServiceCorpseSpawner - cost: 2 - prob: 0.5 - - proto: ResearchAndDevelopmentServerMachineCircuitboard - cost: 5 - prob: 0.5 - - proto: ResearchDisk10000 - prob: 0.5 - - proto: ResearchDisk5000 - prob: 0.5 - - proto: RipleyHarness - cost: 3 - prob: 0.5 - - proto: SpaceCash1000 - - proto: SpaceCash10000 - cost: 10 - - proto: SpaceCash2500 - cost: 3 - - proto: SpaceCash5000 - cost: 5 - - proto: TechnologyDiskRare - cost: 5 - prob: 0.5 - - proto: ThrusterUnanchored - - proto: WaterTankHighCapacity - - proto: WeldingFuelTankHighCapacity - cost: 3 - - proto: WeaponTeslaGun - prob: 0.1 - cost: 2 + - !type:RandomSpawnsLoot + entries: + - proto: AdvMopItem + prob: 0.5 + - proto: AmmoTechFabCircuitboard + cost: 2 + - proto: AutolatheMachineCircuitboard + cost: 2 + - proto: BiomassReclaimerMachineCircuitboard + cost: 2 + - proto: BluespaceBeaker + cost: 2 + - proto: CyborgEndoskeleton + cost: 3 + prob: 0.5 + - proto: ChemDispenserMachineCircuitboard + cost: 2 + - proto: CircuitImprinter + cost: 2 + - proto: CloningConsoleComputerCircuitboard + cost: 2 + - proto: CloningPodMachineCircuitboard + cost: 2 + - proto: ChemistryBottleCognizine + - proto: FoodBoxDonkpocketCarp + prob: 0.5 + - proto: CrateSalvageEquipment + cost: 3 + prob: 0.5 + - proto: GasRecycler + cost: 2 + - proto: GeneratorRTG + cost: 5 + - proto: GravityGeneratorMini + cost: 2 + - proto: GyroscopeUnanchored + cost: 2 + prob: 0.1 + - proto: MedicalScannerMachineCircuitboard + cost: 2 + - proto: NuclearBombKeg + cost: 5 + - proto: ChemistryBottleOmnizine + prob: 0.5 + - proto: PortableGeneratorPacman + cost: 2 + - proto: PortableGeneratorSuperPacman + cost: 3 + - proto: PowerCellAntiqueProto + cost: 5 + prob: 0.5 + - proto: ProtolatheMachineCircuitboard + - proto: RandomArtifactSpawner + cost: 2 + - proto: RandomCargoCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomCommandCorpseSpawner + cost: 5 + prob: 0.5 + - proto: RandomEngineerCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomMedicCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomScienceCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomSecurityCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomServiceCorpseSpawner + cost: 2 + prob: 0.5 + - proto: ResearchAndDevelopmentServerMachineCircuitboard + cost: 5 + prob: 0.5 + - proto: ResearchDisk10000 + prob: 0.5 + - proto: ResearchDisk5000 + prob: 0.5 + - proto: RipleyHarness + cost: 3 + prob: 0.5 + - proto: SpaceCash1000 + - proto: SpaceCash10000 + cost: 10 + - proto: SpaceCash2500 + cost: 3 + - proto: SpaceCash5000 + cost: 5 + - proto: TechnologyDiskRare + cost: 5 + prob: 0.5 + - proto: ThrusterUnanchored + - proto: WaterTankHighCapacity + - proto: WeldingFuelTankHighCapacity + cost: 3 + - proto: WeaponTeslaGun + prob: 0.1 + cost: 2 # Mob loot table @@ -117,70 +117,70 @@ id: OreIron guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreIron + - !type:BiomeLoot + proto: OreIron - type: salvageLoot id: OreCoal guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreCoal + - !type:BiomeLoot + proto: OreCoal - type: salvageLoot id: OreQuartz guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreQuartz + - !type:BiomeLoot + proto: OreQuartz - type: salvageLoot id: OreSalt guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreSalt + - !type:BiomeLoot + proto: OreSalt # - Medium value - type: salvageLoot id: OreGold guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreGold + - !type:BiomeLoot + proto: OreGold - type: salvageLoot id: OreSilver guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreSilver + - !type:BiomeLoot + proto: OreSilver # - High value - type: salvageLoot id: OrePlasma guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OrePlasma + - !type:BiomeLoot + proto: OrePlasma - type: salvageLoot id: OreUranium guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreUranium + - !type:BiomeLoot + proto: OreUranium - type: salvageLoot id: OreDiamond guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreDiamond + - !type:BiomeLoot + proto: OreDiamond - type: salvageLoot id: OreArtifactFragment guaranteed: true loots: - - !type:BiomeMarkerLoot - proto: OreArtifactFragment + - !type:BiomeLoot + proto: OreArtifactFragment diff --git a/Resources/Prototypes/Procedural/salvage_mods.yml b/Resources/Prototypes/Procedural/salvage_mods.yml index ca64d29a52..e8b18dd14a 100644 --- a/Resources/Prototypes/Procedural/salvage_mods.yml +++ b/Resources/Prototypes/Procedural/salvage_mods.yml @@ -8,24 +8,24 @@ - type: salvageBiomeMod id: Caves desc: salvage-biome-mod-caves - biome: Caves + biome: BiomeCaves - type: salvageBiomeMod id: Grasslands desc: salvage-biome-mod-grasslands - biome: Grasslands + biome: BiomeGrasslands - type: salvageBiomeMod id: Snow desc: salvage-biome-mod-snow cost: 1 - biome: Snow + biome: BiomeSnow - type: salvageBiomeMod id: Lava desc: salvage-biome-mod-lava cost: 2 - biome: Lava + biome: BiomeLava #- type: salvageBiomeMod # id: Space diff --git a/Resources/Prototypes/Procedural/vgroid.yml b/Resources/Prototypes/Procedural/vgroid.yml index 0caa9f0e1f..ad759721cb 100644 --- a/Resources/Prototypes/Procedural/vgroid.yml +++ b/Resources/Prototypes/Procedural/vgroid.yml @@ -117,8 +117,8 @@ - type: dungeonConfig id: VGRoidSmaller - minOffset: 40 - maxOffset: 60 + minOffset: 60 + maxOffset: 80 layers: - !type:NoiseDistanceDunGen size: 150, 150 @@ -151,6 +151,7 @@ maxCount: 3 layers: - !type:ExteriorDunGen + penetration: 5,15 proto: Experiment - !type:EntityTableDunGen minCount: 25 @@ -228,5 +229,16 @@ layers: - !type:FillGridDunGen entity: IronRock + threshold: -0.95 + size: 350, 350 + distanceConfig: !type:DunGenEuclideanSquaredDistance + blendWeight: -0.50 + reservedNoise: + frequency: 0.080 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 5 + lacunarity: 1.5 + gain: 0.5 allowedTiles: - FloorAsteroidSand From 433ef5dd27181e4093ea9316145f9eff4251a403 Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Thu, 3 Jul 2025 15:10:20 +0300 Subject: [PATCH 032/105] Fix: Don't deploy foldables when clicking on items inside containers (#38709) * Fix * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Content.Shared/Foldable/DeployFoldableSystem.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Content.Shared/Foldable/DeployFoldableSystem.cs b/Content.Shared/Foldable/DeployFoldableSystem.cs index cac73f6428..c690f3d51f 100644 --- a/Content.Shared/Foldable/DeployFoldableSystem.cs +++ b/Content.Shared/Foldable/DeployFoldableSystem.cs @@ -59,6 +59,10 @@ public sealed class DeployFoldableSystem : EntitySystem if (args.Handled || !args.CanReach) return; + // Don't do anything unless you clicked on the floor. + if (args.Target.HasValue) + return; + if (!TryComp(ent, out var foldable)) return; From 10fa6ff4af32f0ae59ed01f243164fcf6b31f965 Mon Sep 17 00:00:00 2001 From: Kowlin <10947836+Kowlin@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:44:37 +0200 Subject: [PATCH 033/105] Fix world generation (#38713) * Fix world generation * Remove unused impoty --- Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 7f4bdccf2e..5d08247b56 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -110,7 +110,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem }; AddComp(mapUid, restricted); - _biome.EnsurePlanet(mapUid, _protoManager.Index("BiomeContinental"), seed); + _biome.EnsurePlanet(mapUid, _protoManager.Index("BiomeGrasslands"), seed); var grid = Comp(mapUid); From 1bc3d37d40be0cab7378a00e40ba57bfd478b358 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Thu, 3 Jul 2025 16:28:44 +0100 Subject: [PATCH 034/105] Scurrets - Audio Improvements (#38482) * Scurret audio tuning * Add new sfx * Update sneezing sfx * YAML support * Rename a folder --- Resources/Audio/Animals/attributions.yml | 3 ++ Resources/Audio/Animals/wawa_achoo.ogg | Bin 33507 -> 20250 bytes Resources/Audio/Animals/wawa_chatter.ogg | Bin 36144 -> 32829 bytes Resources/Audio/Animals/wawa_chillin.ogg | Bin 33019 -> 29014 bytes Resources/Audio/Animals/wawa_depression.ogg | Bin 36444 -> 21462 bytes Resources/Audio/Animals/wawa_despair.ogg | Bin 0 -> 36237 bytes Resources/Audio/Animals/wawa_exclaim.ogg | Bin 23074 -> 20644 bytes Resources/Audio/Animals/wawa_mock.ogg | Bin 46841 -> 30534 bytes Resources/Audio/Animals/wawa_protest.ogg | Bin 65986 -> 37543 bytes Resources/Audio/Animals/wawa_question.ogg | Bin 15319 -> 14119 bytes Resources/Audio/Animals/wawa_statement.ogg | Bin 20599 -> 18971 bytes Resources/Audio/Animals/wawa_the_end.ogg | Bin 0 -> 20165 bytes Resources/Audio/Animals/wawa_yawn.ogg | Bin 0 -> 26050 bytes Resources/Audio/Effects/attributions.yml | 5 +++ Resources/Audio/Effects/soft_thump.ogg | Bin 0 -> 16851 bytes Resources/Locale/en-US/chat/emotes.ftl | 1 + .../en-US/{scurret copy => scurret}/role.ftl | 0 .../Prototypes/Entities/Mobs/NPCs/scurret.yml | 6 ++-- .../Prototypes/SoundCollections/scurret.yml | 15 +++++++++ .../Prototypes/Voice/speech_emote_sounds.yml | 30 ++++++++++++++++++ Resources/Prototypes/Voice/speech_emotes.yml | 6 ++++ 21 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 Resources/Audio/Animals/wawa_despair.ogg create mode 100644 Resources/Audio/Animals/wawa_the_end.ogg create mode 100644 Resources/Audio/Animals/wawa_yawn.ogg create mode 100644 Resources/Audio/Effects/soft_thump.ogg rename Resources/Locale/en-US/{scurret copy => scurret}/role.ftl (100%) diff --git a/Resources/Audio/Animals/attributions.yml b/Resources/Audio/Animals/attributions.yml index 59d8bc5a6e..f91d98b974 100644 --- a/Resources/Audio/Animals/attributions.yml +++ b/Resources/Audio/Animals/attributions.yml @@ -162,11 +162,14 @@ - wawa_chatter.ogg - wawa_chillin.ogg - wawa_depression.ogg + - wawa_despair.ogg - wawa_exclaim.ogg - wawa_mock.ogg - wawa_protest.ogg - wawa_question.ogg - wawa_statement.ogg + - wawa_the_end.ogg + - wawa_yawn.ogg copyright: "created by FairlySadPanda" license: "CC-BY-4.0" source: "https://github.com/space-wizards/space-station-14/pull/37936" diff --git a/Resources/Audio/Animals/wawa_achoo.ogg b/Resources/Audio/Animals/wawa_achoo.ogg index 56670c2d05966075a6826d6c9b30afc22b162d04..411c4b5b0a94e8b593a58ff050fd287d44f3ceb8 100644 GIT binary patch delta 16146 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 oum6(x*dX-S diff --git a/Resources/Audio/Animals/wawa_chatter.ogg b/Resources/Audio/Animals/wawa_chatter.ogg index 7e2a7ec3ca0589cde9b155447840c2349e0f5692..5537611307313fdc5066ef4c4a3db69deb7ef3ea 100644 GIT binary patch delta 28863 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 e_*4U=3;KWVX$Niq delta 32204 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 RYs7hp)v&x}fdBuW{|Ao?oe%&3 diff --git a/Resources/Audio/Animals/wawa_chillin.ogg b/Resources/Audio/Animals/wawa_chillin.ogg index 5955fdf96794462d9ae50ff82a1a219c7635f121..d548f6a26f1e0a6d83a8a5ee7e7069b995dfa206 100644 GIT binary patch delta 25019 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 diff --git a/Resources/Audio/Animals/wawa_depression.ogg b/Resources/Audio/Animals/wawa_depression.ogg index 3f8167acb78072362ec3784afec2b3e650d0b953..d592654a07b343cfb2cae873486675a6687c703f 100644 GIT binary patch delta 17524 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⪻|tm{uc-wKXL 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 X8&}^kYw~X#aIbEoKQ>s126X=i%P&q@ diff --git a/Resources/Audio/Animals/wawa_despair.ogg b/Resources/Audio/Animals/wawa_despair.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ce4ecc4db2b1e0f46938a058d0cd69a7ca033762 GIT binary patch literal 36237 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

-j>wWY_^@AdonW!xk+&jeet%h-sqHG`@kfrj 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 delta 19031 zcmYJZ1yCH#*Y-V&C%6Q6m*5^e1h?S9Ew~2vSs*|N9tb43OM<(*ySqzpcioTs|GZV- z)YME*SM6*~_31uW|IU?@3CXI05UW^PssnJq|2r%c|F40gZg~_-%!c;gGvuW!*sSw+ ztcDE>%1c{PMOi~aQbPpkrL7^Sp(rKtf4xddQp*3=DCRM(-fC;kw-|PN+&42%~ zqCA010{QQN!T4Y>H5iNy2E&EHcwjI9whMa#USnWjtOPBNOrB7sz%a34DfMD+K0&UI z@AO;wYX4YIZ6ovVAY7Qo-e$D;&!^%VXG#>?xl1R9f@6h!G{Wn)BtEcv7qvR)fK!l3F)>WSXvaNDV&Gt2ajnmZ>b;9o11N!Sm&p2e?N6ob(e&%7O!Gcq1s@VIa@BA z=3TxC(V_WidGU$g7-u_Z$2VW51g@wyx+bI#k&h_vy6(?-H2%F^wbGC(>KDXE@xew9 zOwhz);!AySw!mj zCdKm3q469#_kb2RW}mWO_H17LyE@b?1%rIfV(iZ~KdPlK{&oLTa{4BUu1`O=S`r_S zcJ=s`rw)O0Z+|usnlVwFtz3zmk8Pe-uWgi0miJ^)=wOv|UjBs;Uw| z>htWGG3LjW_&cMPFA1}$G@kSRx?7vU)$i1nXi-_0b|-Q5mgut`cngC$kJ{8DNmp{~ z+7Um5ZpMZRrOm`I*3#&-!qVSW{MOqjN`)~OJO|E?tLWqWQ+Jl?2SJW8DPEaD7j464Barsf7?)XG z0fS#d?!W7%*cnp>U1^Nu48aA#&Y}d1x+zS_(uiZl-c|W?cKcAg-#| zV*ND6$bX2YGcrtLwNEA|Hz=S|N8DQ~`>C}0d?v*&j8jG6HkL?+oTT(3czfHc*1R>| zfsW#UC-fq)(w-Tsm?nV3Xr9kHsg}tCkUE3eSM=gEBBCJT$%=yP=O@nFd58<-N5}K$ z(xowY!NPQ*A3s|aF(;WCZ!c^qP{c6Rsawr{3+IS$MQZ_aQE}0=F@v;@u86oC9 zU8@Z>cRbMe8Eni5J8~~zZ*{4iF=EAx;_O{*DH^I0&0D@B*D}Su>?yQeEk05paLcLHl@Xk~5pM$AX?2*8$X zIMU&j`4IrMia@B571I27!LFn1^8@Qc8kA9d0iwgK%*W}wpZs?7G#-1rxvNKmuh z``k}h;PTt_LC2Z0y#!I1fe!khd@+SN=i^nwTc5$&{AuK?p=%cBMDMZH(e{7*oO6b{ z$wkxYjA~)-PLpRC&fCv-?;l@}pqu(1*?7;q+n}6gNUxUYg;~W19v_V!Udw#oA(`Sn z9LBy2d$NxdX`3wPwkvgMQtCdO7bGV?)$#L|0V!ZUchIotg7=FiYBYz|2FN^J!e zIu-qKqhl3lKuns6x~Ly7ikX2Vx|B}*j&m~+vl&(xf?1of;lJ^t`zN7J7u6Wg3)VC> z?

private const float RoundStartFTLDuration = 10f; - private readonly List _arrivalsBiomeOptions = new() + private readonly List> _arrivalsBiomeOptions = new() { - "BiomeGrasslands", - "BiomeLowDesert", - "BiomeSnow", + "Grasslands", + "LowDesert", + "Snow", }; public override void Initialize() diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 9e9bcb6c42..13e13bf8f3 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -1,14 +1,12 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; -using Content.Server.Decals; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Events; using Content.Shared.Body.Components; using Content.Shared.CCVar; using Content.Shared.Database; -using Content.Shared.Decals; using Content.Shared.Ghost; using Content.Shared.Maps; using Content.Shared.Parallax; @@ -958,7 +956,6 @@ public sealed partial class ShuttleSystem var transform = _physics.GetRelativePhysicsTransform((uid, xform), xform.MapUid.Value); var aabbs = new List(manager.Fixtures.Count); var tileSet = new List<(Vector2i, Tile)>(); - TryComp(xform.MapUid.Value, out DecalGridComponent? decalGrid); foreach (var fixture in manager.Fixtures.Values) { @@ -972,15 +969,9 @@ public sealed partial class ShuttleSystem aabb = aabb.Enlarged(0.2f); aabbs.Add(aabb); - if (decalGrid != null) - { - foreach (var decal in _decals.GetDecalsIntersecting(xform.MapUid.Value, aabb)) - { - _decals.RemoveDecal(xform.MapUid.Value, decal.Index, decalGrid); - } - } - + // Handle clearing biome stuff as relevant. tileSet.Clear(); + _biomes.ReserveTiles(xform.MapUid.Value, aabb, tileSet); _lookupEnts.Clear(); _immuneEnts.Clear(); // TODO: Ideally we'd query first BEFORE moving grid but needs adjustments above. diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 525e16ae1a..cea7fbfc09 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Administration.Logs; using Content.Server.Body.Systems; using Content.Server.Buckle.Systems; -using Content.Server.Decals; using Content.Server.Parallax; using Content.Server.Procedural; using Content.Server.Shuttles.Components; @@ -42,12 +41,10 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly BiomeSystem _biomes = default!; [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly BuckleSystem _buckle = default!; [Dependency] private readonly DamageableSystem _damageSys = default!; - [Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; diff --git a/Content.Server/Station/Components/StationBiomeComponent.cs b/Content.Server/Station/Components/StationBiomeComponent.cs index a2105d6cef..0eb64aaff8 100644 --- a/Content.Server/Station/Components/StationBiomeComponent.cs +++ b/Content.Server/Station/Components/StationBiomeComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Station.Systems; +using Content.Shared.Parallax.Biomes; using Robust.Shared.Prototypes; namespace Content.Server.Station.Components; @@ -10,7 +11,7 @@ namespace Content.Server.Station.Components; public sealed partial class StationBiomeComponent : Component { [DataField(required: true)] - public EntProtoId Biome = "BiomeGrasslands"; + public ProtoId Biome = "Grasslands"; // If null, its random [DataField] diff --git a/Content.Server/Station/Systems/StationBiomeSystem.cs b/Content.Server/Station/Systems/StationBiomeSystem.cs index c0777f6052..c12e2f47e4 100644 --- a/Content.Server/Station/Systems/StationBiomeSystem.cs +++ b/Content.Server/Station/Systems/StationBiomeSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Parallax; -using Content.Server.Procedural; using Content.Server.Station.Components; using Content.Server.Station.Events; using Robust.Shared.Prototypes; diff --git a/Content.Server/Tabletop/TabletopSystem.cs b/Content.Server/Tabletop/TabletopSystem.cs index 3c3065c95a..e771add0e4 100644 --- a/Content.Server/Tabletop/TabletopSystem.cs +++ b/Content.Server/Tabletop/TabletopSystem.cs @@ -191,7 +191,7 @@ namespace Content.Server.Tabletop if (!TryComp(uid, out ActorComponent? actor)) { RemComp(uid); - continue; + return; } if (actor.PlayerSession.Status != SessionStatus.InGame || !CanSeeTable(uid, gamer.Tabletop)) diff --git a/Content.Shared/CCVar/CCVars.Biome.cs b/Content.Shared/CCVar/CCVars.Biome.cs deleted file mode 100644 index 13c6cd548e..0000000000 --- a/Content.Shared/CCVar/CCVars.Biome.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.Configuration; - -namespace Content.Shared.CCVar; - -public sealed partial class CCVars -{ - /// - /// Load range for biomes. Set this higher than PVS so server can have some time to load in before the client arrives. - /// - public static readonly CVarDef BiomeLoadRange = - CVarDef.Create("biome.load_range", 20f, CVar.SERVERONLY); - - /// - /// Time allocation (ms) for how long biomes are allowed to load. - /// - public static readonly CVarDef BiomeLoadTime = - CVarDef.Create("biome.load_time", 0.03f, CVar.SERVERONLY); -} diff --git a/Content.Shared/Parallax/Biomes/BiomeComponent.cs b/Content.Shared/Parallax/Biomes/BiomeComponent.cs new file mode 100644 index 0000000000..af8eb88683 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/BiomeComponent.cs @@ -0,0 +1,87 @@ +using Content.Shared.Parallax.Biomes.Layers; +using Content.Shared.Parallax.Biomes.Markers; +using Robust.Shared.GameStates; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Parallax.Biomes; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedBiomeSystem))] +public sealed partial class BiomeComponent : Component +{ + /// + /// Do we load / deload. + /// + [DataField, ViewVariables(VVAccess.ReadWrite), Access(Other = AccessPermissions.ReadWriteExecute)] + public bool Enabled = true; + + [ViewVariables(VVAccess.ReadWrite), DataField("seed")] + [AutoNetworkedField] + public int Seed = -1; + + /// + /// The underlying entity, decal, and tile layers for the biome. + /// + [DataField("layers")] + [AutoNetworkedField] + public List Layers = new(); + + /// + /// Templates to use for . + /// If this is set on mapinit, it will fill out layers automatically. + /// If not set, use BiomeSystem to do it. + /// Prototype reloading will also use this. + /// + [DataField] + public ProtoId? Template; + + /// + /// If we've already generated a tile and couldn't deload it then we won't ever reload it in future. + /// Stored by [Chunkorigin, Tiles] + /// + [DataField("modifiedTiles")] + public Dictionary> ModifiedTiles = new(); + + /// + /// Decals that have been loaded as a part of this biome. + /// + [DataField("decals")] + public Dictionary> LoadedDecals = new(); + + [DataField("entities")] + public Dictionary> LoadedEntities = new(); + + /// + /// Currently active chunks + /// + [DataField("loadedChunks")] + public HashSet LoadedChunks = new(); + + #region Markers + + /// + /// Work out entire marker tiles in advance but only load the entities when in range. + /// + [DataField("pendingMarkers")] + public Dictionary>> PendingMarkers = new(); + + /// + /// Track what markers we've loaded already to avoid double-loading. + /// + [DataField("loadedMarkers", customTypeSerializer:typeof(PrototypeIdDictionarySerializer, BiomeMarkerLayerPrototype>))] + public Dictionary> LoadedMarkers = new(); + + [DataField] + public HashSet> MarkerLayers = new(); + + /// + /// One-tick forcing of marker layers to bulldoze any entities in the way. + /// + [DataField] + public HashSet> ForcedMarkerLayers = new(); + + #endregion +} diff --git a/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs b/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs new file mode 100644 index 0000000000..437ead63a7 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/BiomeTemplatePrototype.cs @@ -0,0 +1,16 @@ +using Content.Shared.Parallax.Biomes.Layers; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Parallax.Biomes; + +/// +/// A preset group of biome layers to be used for a +/// +[Prototype] +public sealed partial class BiomeTemplatePrototype : IPrototype +{ + [IdDataField] public string ID { get; private set; } = default!; + + [DataField("layers")] + public List Layers = new(); +} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs new file mode 100644 index 0000000000..5e31e513a9 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/BiomeDecalLayer.cs @@ -0,0 +1,34 @@ +using Content.Shared.Decals; +using Content.Shared.Maps; +using Robust.Shared.Noise; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Parallax.Biomes.Layers; + +[Serializable, NetSerializable] +public sealed partial class BiomeDecalLayer : IBiomeWorldLayer +{ + /// + [DataField("allowedTiles", customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List AllowedTiles { get; private set; } = new(); + + /// + /// Divide each tile up by this amount. + /// + [DataField("divisions")] + public float Divisions = 1f; + + [DataField("noise")] + public FastNoiseLite Noise { get; private set; } = new(0); + + /// + [DataField("threshold")] + public float Threshold { get; private set; } = 0.8f; + + /// + [DataField("invert")] public bool Invert { get; private set; } = false; + + [DataField("decals", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List Decals = new(); +} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs new file mode 100644 index 0000000000..2beeba6e03 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/BiomeDummyLayer.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Noise; +using Robust.Shared.Serialization; + +namespace Content.Shared.Parallax.Biomes.Layers; + +/// +/// Dummy layer that specifies a marker to be replaced by external code. +/// For example if they wish to add their own layers at specific points across different templates. +/// +[Serializable, NetSerializable] +public sealed partial class BiomeDummyLayer : IBiomeLayer +{ + [DataField("id", required: true)] public string ID = string.Empty; + + public FastNoiseLite Noise { get; } = new(); + public float Threshold { get; } + public bool Invert { get; } +} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs new file mode 100644 index 0000000000..21ffdd96e5 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/BiomeEntityLayer.cs @@ -0,0 +1,27 @@ +using Content.Shared.Maps; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Parallax.Biomes.Layers; + +[Serializable, NetSerializable] +public sealed partial class BiomeEntityLayer : IBiomeWorldLayer +{ + /// + [DataField("allowedTiles", customTypeSerializer:typeof(PrototypeIdListSerializer))] + public List AllowedTiles { get; private set; } = new(); + + [DataField("noise")] public FastNoiseLite Noise { get; private set; } = new(0); + + /// + [DataField("threshold")] + public float Threshold { get; private set; } = 0.5f; + + /// + [DataField("invert")] public bool Invert { get; private set; } = false; + + [DataField("entities", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List Entities = new(); +} diff --git a/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs new file mode 100644 index 0000000000..51231405a8 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/BiomeMetaLayer.cs @@ -0,0 +1,27 @@ +using Robust.Shared.Noise; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Parallax.Biomes.Layers; + +/// +/// Contains more biome layers recursively via a biome template. +/// Can be used for sub-biomes. +/// +[Serializable, NetSerializable] +public sealed partial class BiomeMetaLayer : IBiomeLayer +{ + [DataField("noise")] + public FastNoiseLite Noise { get; private set; } = new(0); + + /// + [DataField("threshold")] + public float Threshold { get; private set; } = -1f; + + /// + [DataField("invert")] + public bool Invert { get; private set; } + + [DataField("template", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string Template = string.Empty; +} diff --git a/Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs b/Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs similarity index 66% rename from Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs rename to Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs index 6d23d201f5..9dee35da4e 100644 --- a/Content.Shared/Procedural/DungeonLayers/SampleTileDunGen.cs +++ b/Content.Shared/Parallax/Biomes/Layers/BiomeTileLayer.cs @@ -2,26 +2,20 @@ using Content.Shared.Maps; using Robust.Shared.Noise; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Shared.Procedural.DungeonLayers; +namespace Content.Shared.Parallax.Biomes.Layers; -/// -/// Samples noise and spawns the specified tile in the dungeon area. -/// [Serializable, NetSerializable] -public sealed partial class SampleTileDunGen : IDunGenLayer +public sealed partial class BiomeTileLayer : IBiomeLayer { - /// - /// Reserve any tiles we update. - /// - [DataField] - public bool ReserveTiles = true; - [DataField] public FastNoiseLite Noise { get; private set; } = new(0); + /// [DataField] public float Threshold { get; private set; } = 0.5f; + /// [DataField] public bool Invert { get; private set; } = false; /// diff --git a/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs b/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs new file mode 100644 index 0000000000..3b1ad5c76c --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/IBiomeLayer.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Noise; + +namespace Content.Shared.Parallax.Biomes.Layers; + +[ImplicitDataDefinitionForInheritors] +public partial interface IBiomeLayer +{ + /// + /// Seed is used an offset from the relevant BiomeComponent's seed. + /// + FastNoiseLite Noise { get; } + + /// + /// Threshold for this layer to be present. If set to 0 forces it for every tile. + /// + float Threshold { get; } + + /// + /// Is the thresold inverted so we need to be lower than it. + /// + public bool Invert { get; } +} diff --git a/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs b/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs new file mode 100644 index 0000000000..e04db913b7 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Layers/IBiomeWorldLayer.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Parallax.Biomes.Layers; + +/// +/// Handles actual objects such as decals and entities. +/// +public partial interface IBiomeWorldLayer : IBiomeLayer +{ + /// + /// What tiles we're allowed to spawn on, real or biome. + /// + List AllowedTiles { get; } +} diff --git a/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs b/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs new file mode 100644 index 0000000000..fbc3a04eb4 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Markers/BiomeMarkerLayerPrototype.cs @@ -0,0 +1,53 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Parallax.Biomes.Markers; + +/// +/// Spawns entities inside of the specified area with the minimum specified radius. +/// +[Prototype] +public sealed partial class BiomeMarkerLayerPrototype : IBiomeMarkerLayer +{ + [IdDataField] public string ID { get; private set; } = default!; + + /// + /// Checks for the relevant entity for the tile before spawning. Useful for substituting walls with ore veins for example. + /// + [DataField] + public Dictionary EntityMask { get; private set; } = new(); + + /// + /// Default prototype to spawn. If null will fall back to entity mask. + /// + [DataField] + public string? Prototype { get; private set; } + + /// + /// Minimum radius between 2 points + /// + [DataField("radius")] + public float Radius = 32f; + + /// + /// Maximum amount of group spawns + /// + [DataField("maxCount")] + public int MaxCount = int.MaxValue; + + /// + /// Minimum entities to spawn in one group. + /// + [DataField] + public int MinGroupSize = 1; + + /// + /// Maximum entities to spawn in one group. + /// + [DataField] + public int MaxGroupSize = 1; + + /// + [DataField("size")] + public int Size { get; private set; } = 128; +} diff --git a/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs b/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs new file mode 100644 index 0000000000..de2913bb09 --- /dev/null +++ b/Content.Shared/Parallax/Biomes/Markers/IBiomeMarkerLayer.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Parallax.Biomes.Markers; + +/// +/// Specifies one-off marker points to be used. This could be for dungeon markers, mob markers, etc. +/// These are run outside of the tile / decal / entity layers. +/// +public interface IBiomeMarkerLayer : IPrototype +{ + /// + /// Biome template to use as a mask for this layer. + /// + public Dictionary EntityMask { get; } + + public string? Prototype { get; } + + /// + /// How large the pre-generated points area is. + /// + public int Size { get; } +} diff --git a/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs b/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs new file mode 100644 index 0000000000..a5238e8c6e --- /dev/null +++ b/Content.Shared/Parallax/Biomes/SharedBiomeSystem.cs @@ -0,0 +1,386 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using Content.Shared.Maps; +using Content.Shared.Parallax.Biomes.Layers; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Utility; + +namespace Content.Shared.Parallax.Biomes; + +public abstract class SharedBiomeSystem : EntitySystem +{ + [Dependency] protected readonly IPrototypeManager ProtoManager = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] protected readonly ITileDefinitionManager TileDefManager = default!; + [Dependency] private readonly TileSystem _tile = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + + protected const byte ChunkSize = 8; + + private T Pick(List collection, float value) + { + // Listen I don't need this exact and I'm too lazy to finetune just for random ent picking. + value %= 1f; + value = Math.Clamp(value, 0f, 1f); + + if (collection.Count == 1) + return collection[0]; + + var randValue = value * collection.Count; + + foreach (var item in collection) + { + randValue -= 1f; + + if (randValue <= 0f) + { + return item; + } + } + + throw new ArgumentOutOfRangeException(); + } + + private int Pick(int count, float value) + { + value %= 1f; + value = Math.Clamp(value, 0f, 1f); + + if (count == 1) + return 0; + + value *= count; + + for (var i = 0; i < count; i++) + { + value -= 1f; + + if (value <= 0f) + { + return i; + } + } + + throw new ArgumentOutOfRangeException(); + } + + public bool TryGetBiomeTile(EntityUid uid, MapGridComponent grid, Vector2i indices, [NotNullWhen(true)] out Tile? tile) + { + if (_map.TryGetTileRef(uid, grid, indices, out var tileRef) && !tileRef.Tile.IsEmpty) + { + tile = tileRef.Tile; + return true; + } + + if (!TryComp(uid, out var biome)) + { + tile = null; + return false; + } + + return TryGetBiomeTile(indices, biome.Layers, biome.Seed, (uid, grid), out tile); + } + + /// + /// Tries to get the tile, real or otherwise, for the specified indices. + /// + public bool TryGetBiomeTile(Vector2i indices, List layers, int seed, Entity? grid, [NotNullWhen(true)] out Tile? tile) + { + if (grid is { } gridEnt && _map.TryGetTileRef(gridEnt, gridEnt.Comp, indices, out var tileRef) && !tileRef.Tile.IsEmpty) + { + tile = tileRef.Tile; + return true; + } + + return TryGetTile(indices, layers, seed, grid, out tile); + } + + /// + /// Tries to get the tile, real or otherwise, for the specified indices. + /// + [Obsolete("Use the Entity? overload")] + public bool TryGetBiomeTile(Vector2i indices, List layers, int seed, MapGridComponent? grid, [NotNullWhen(true)] out Tile? tile) + { + return TryGetBiomeTile(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out tile); + } + + /// + /// Gets the underlying biome tile, ignoring any existing tile that may be there. + /// + public bool TryGetTile(Vector2i indices, List layers, int seed, Entity? grid, [NotNullWhen(true)] out Tile? tile) + { + for (var i = layers.Count - 1; i >= 0; i--) + { + var layer = layers[i]; + var noiseCopy = GetNoise(layer.Noise, seed); + + var invert = layer.Invert; + var value = noiseCopy.GetNoise(indices.X, indices.Y); + value = invert ? value * -1 : value; + + if (value < layer.Threshold) + continue; + + // Check if the tile is from meta layer, otherwise fall back to default layers. + if (layer is BiomeMetaLayer meta) + { + if (TryGetBiomeTile(indices, ProtoManager.Index(meta.Template).Layers, seed, grid, out tile)) + { + return true; + } + + continue; + } + + if (layer is not BiomeTileLayer tileLayer) + continue; + + if (TryGetTile(indices, noiseCopy, tileLayer.Invert, tileLayer.Threshold, ProtoManager.Index(tileLayer.Tile), tileLayer.Variants, out tile)) + { + return true; + } + } + + tile = null; + return false; + } + + /// + /// Gets the underlying biome tile, ignoring any existing tile that may be there. + /// + [Obsolete("Use the Entity? overload")] + public bool TryGetTile(Vector2i indices, List layers, int seed, MapGridComponent? grid, [NotNullWhen(true)] out Tile? tile) + { + return TryGetTile(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out tile); + } + + /// + /// Gets the underlying biome tile, ignoring any existing tile that may be there. + /// + private bool TryGetTile(Vector2i indices, FastNoiseLite noise, bool invert, float threshold, ContentTileDefinition tileDef, List? variants, [NotNullWhen(true)] out Tile? tile) + { + var found = noise.GetNoise(indices.X, indices.Y); + found = invert ? found * -1 : found; + + if (found < threshold) + { + tile = null; + return false; + } + + byte variant = 0; + var variantCount = variants?.Count ?? tileDef.Variants; + + // Pick a variant tile if they're available as well + if (variantCount > 1) + { + var variantValue = (noise.GetNoise(indices.X * 8, indices.Y * 8, variantCount) + 1f) * 100; + variant = _tile.PickVariant(tileDef, (int)variantValue); + } + + tile = new Tile(tileDef.TileId, variant); + return true; + } + + /// + /// Tries to get the relevant entity for this tile. + /// + public bool TryGetEntity(Vector2i indices, BiomeComponent component, Entity? grid, + [NotNullWhen(true)] out string? entity) + { + if (!TryGetBiomeTile(indices, component.Layers, component.Seed, grid, out var tile)) + { + entity = null; + return false; + } + + return TryGetEntity(indices, component.Layers, tile.Value, component.Seed, grid, out entity); + } + + /// + /// Tries to get the relevant entity for this tile. + /// + [Obsolete("Use the Entity? overload")] + public bool TryGetEntity(Vector2i indices, BiomeComponent component, MapGridComponent grid, + [NotNullWhen(true)] out string? entity) + { + return TryGetEntity(indices, component, grid == null ? null : (grid.Owner, grid), out entity); + } + + public bool TryGetEntity(Vector2i indices, List layers, Tile tileRef, int seed, Entity? grid, + [NotNullWhen(true)] out string? entity) + { + var tileId = TileDefManager[tileRef.TypeId].ID; + + for (var i = layers.Count - 1; i >= 0; i--) + { + var layer = layers[i]; + + switch (layer) + { + case BiomeDummyLayer: + continue; + case IBiomeWorldLayer worldLayer: + if (!worldLayer.AllowedTiles.Contains(tileId)) + continue; + + break; + case BiomeMetaLayer: + break; + default: + continue; + } + + var noiseCopy = GetNoise(layer.Noise, seed); + + var invert = layer.Invert; + var value = noiseCopy.GetNoise(indices.X, indices.Y); + value = invert ? value * -1 : value; + + if (value < layer.Threshold) + continue; + + if (layer is BiomeMetaLayer meta) + { + if (TryGetEntity(indices, ProtoManager.Index(meta.Template).Layers, tileRef, seed, grid, out entity)) + { + return true; + } + + continue; + } + + // Decals might block entity so need to check if there's one in front of us. + if (layer is not BiomeEntityLayer biomeLayer) + { + entity = null; + return false; + } + + var noiseValue = noiseCopy.GetNoise(indices.X, indices.Y, i); + entity = Pick(biomeLayer.Entities, (noiseValue + 1f) / 2f); + return true; + } + + entity = null; + return false; + } + + [Obsolete("Use the Entity? overload")] + public bool TryGetEntity(Vector2i indices, List layers, Tile tileRef, int seed, MapGridComponent grid, + [NotNullWhen(true)] out string? entity) + { + return TryGetEntity(indices, layers, tileRef, seed, grid == null ? null : (grid.Owner, grid), out entity); + } + + /// + /// Tries to get the relevant decals for this tile. + /// + public bool TryGetDecals(Vector2i indices, List layers, int seed, Entity? grid, + [NotNullWhen(true)] out List<(string ID, Vector2 Position)>? decals) + { + if (!TryGetBiomeTile(indices, layers, seed, grid, out var tileRef)) + { + decals = null; + return false; + } + + var tileId = TileDefManager[tileRef.Value.TypeId].ID; + + for (var i = layers.Count - 1; i >= 0; i--) + { + var layer = layers[i]; + + // Entities might block decal so need to check if there's one in front of us. + switch (layer) + { + case BiomeDummyLayer: + continue; + case IBiomeWorldLayer worldLayer: + if (!worldLayer.AllowedTiles.Contains(tileId)) + continue; + + break; + case BiomeMetaLayer: + break; + default: + continue; + } + + var invert = layer.Invert; + var noiseCopy = GetNoise(layer.Noise, seed); + var value = noiseCopy.GetNoise(indices.X, indices.Y); + value = invert ? value * -1 : value; + + if (value < layer.Threshold) + continue; + + if (layer is BiomeMetaLayer meta) + { + if (TryGetDecals(indices, ProtoManager.Index(meta.Template).Layers, seed, grid, out decals)) + { + return true; + } + + continue; + } + + // Check if the other layer should even render, if not then keep going. + if (layer is not BiomeDecalLayer decalLayer) + { + decals = null; + return false; + } + + decals = new List<(string ID, Vector2 Position)>(); + + for (var x = 0; x < decalLayer.Divisions; x++) + { + for (var y = 0; y < decalLayer.Divisions; y++) + { + var index = new Vector2(indices.X + x * 1f / decalLayer.Divisions, indices.Y + y * 1f / decalLayer.Divisions); + var decalValue = noiseCopy.GetNoise(index.X, index.Y); + decalValue = invert ? decalValue * -1 : decalValue; + + if (decalValue < decalLayer.Threshold) + continue; + + decals.Add((Pick(decalLayer.Decals, (noiseCopy.GetNoise(indices.X, indices.Y, x + y * decalLayer.Divisions) + 1f) / 2f), index)); + } + } + + // Check other layers + if (decals.Count == 0) + continue; + + return true; + } + + decals = null; + return false; + } + + /// + /// Tries to get the relevant decals for this tile. + /// + [Obsolete("Use the Entity? overload")] + public bool TryGetDecals(Vector2i indices, List layers, int seed, MapGridComponent grid, + [NotNullWhen(true)] out List<(string ID, Vector2 Position)>? decals) + { + return TryGetDecals(indices, layers, seed, grid == null ? null : (grid.Owner, grid), out decals); + } + + private FastNoiseLite GetNoise(FastNoiseLite seedNoise, int seed) + { + var noiseCopy = new FastNoiseLite(); + _serManager.CopyTo(seedNoise, ref noiseCopy, notNullableOverride: true); + noiseCopy.SetSeed(noiseCopy.GetSeed() + seed); + // Ensure re-calculate is run. + noiseCopy.SetFractalOctaves(noiseCopy.GetFractalOctaves()); + return noiseCopy; + } +} diff --git a/Content.Shared/Procedural/Components/BiomeComponent.cs b/Content.Shared/Procedural/Components/BiomeComponent.cs deleted file mode 100644 index f79a31c414..0000000000 --- a/Content.Shared/Procedural/Components/BiomeComponent.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared.Procedural.Components; - -/// -/// A layer inside of -/// -[DataRecord] -public sealed record BiomeMetaLayer -{ - /// - /// Chunk dimensions for this meta layer. Will try to infer it from the first layer of the dungeon if null. - /// - [DataField] - public int? Size; - - /// - /// Meta layers that this one requires to be loaded first. - /// Will ensure all of the chunks for our corresponding area are loaded. - /// - public List? DependsOn; - - /// - /// Can this layer be unloaded if no one is in range. - /// - public bool CanUnload = true; - - /// - /// Dungeon config to load inside the specified area. - /// - [DataField(required: true)] - public ProtoId Dungeon = new(); -} - -[RegisterComponent] -public sealed partial class BiomeComponent : Component -{ - /// - /// Can we load / unload chunks. - /// - [DataField] - public bool Enabled = true; - - /// - /// Areas queued for preloading. Will add these during and then flag as modified so they retain. - /// - [DataField] - public List PreloadAreas = new(); - - /// - /// Is there currently a job that's loading. - /// - public bool Loading = false; - - [DataField] - public int Seed; - - /// - /// Layer key and associated data. - /// - [DataField(required: true)] - public Dictionary Layers = new(); - - /// - /// Layer removals that are pending. - /// - [DataField] - public List PendingRemovals = new(); - - /// - /// Data that is currently loaded. - /// - [DataField] - public Dictionary> LoadedData = new(); - - /// - /// Flag modified tiles so we don't try and unload / reload them. - /// - [DataField] - public HashSet ModifiedTiles = new(); - - /// - /// Bounds loaded by players for this tick. - /// - public List LoadedBounds = new(); -} diff --git a/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs b/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs deleted file mode 100644 index 215a8f345d..0000000000 --- a/Content.Shared/Procedural/Components/BiomeForceUnloadComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Procedural.Components; - -/// -/// Will forcibly unload an entity no matter what. Useful if you have consistent entities that will never be default or the likes. -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class BiomeForceUnloadComponent : Component; diff --git a/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs b/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs deleted file mode 100644 index 813f5fc1d4..0000000000 --- a/Content.Shared/Procedural/Distance/DunGenDistanceSquared.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Shared.Procedural.Distance; - -public sealed partial class DunGenDistanceSquared : IDunGenDistance -{ - [DataField] - public float BlendWeight { get; set; } = 0.50f; -} diff --git a/Content.Shared/Procedural/DungeonConfig.cs b/Content.Shared/Procedural/DungeonConfig.cs index 56131e5b28..7c84b1a6a3 100644 --- a/Content.Shared/Procedural/DungeonConfig.cs +++ b/Content.Shared/Procedural/DungeonConfig.cs @@ -12,18 +12,11 @@ public partial class DungeonConfig public List Layers = new(); /// - /// Should we reserve the tiles generated by this config so no other layers at the same level can spawn on this tile? + /// Should we reserve the tiles generated by this config so no other dungeons can spawn on it within the same job? /// [DataField] public bool ReserveTiles; - /// - /// Should we return the reserved tiles to the upper level. - /// Set to false if you don't care if this dungeon has its tiles overwritten at higher levels. - /// - [DataField] - public bool ReturnReserved = true; - /// /// Minimum times to run the config. /// diff --git a/Content.Shared/Procedural/DungeonData.cs b/Content.Shared/Procedural/DungeonData.cs deleted file mode 100644 index a0209f91a6..0000000000 --- a/Content.Shared/Procedural/DungeonData.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Linq; -using System.Numerics; -using Robust.Shared.Map; - -namespace Content.Shared.Procedural; - -/// -/// Contains the loaded data for a dungeon. -/// -[DataDefinition] -public sealed partial class DungeonData -{ - [DataField] - public Dictionary Decals = new(); - - [DataField] - public Dictionary Entities = new(); - - [DataField] - public Dictionary Tiles = new(); - - public static DungeonData Empty = new(); - - public void Merge(DungeonData data) - { - foreach (var did in data.Decals) - { - Decals[did.Key] = did.Value; - } - - foreach (var ent in data.Entities) - { - Entities[ent.Key] = ent.Value; - } - - foreach (var tile in data.Tiles) - { - Tiles[tile.Key] = tile.Value; - } - } -} diff --git a/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs deleted file mode 100644 index b48a1b3fd6..0000000000 --- a/Content.Shared/Procedural/DungeonGenerators/ChunkDunGen.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Robust.Shared.Noise; - -namespace Content.Shared.Procedural.DungeonGenerators; - -/// -/// Turns a chunked area into a dungeon for layer purposes. Assumes the position is the BL origin. -/// -public sealed partial class ChunkDunGen : IDunGenLayer -{ - [DataField] - public int Size = 16; - - /// - /// Noise to apply for each tile conditionally. - /// - [DataField] - public FastNoiseLite? Noise; - - /// - /// Threshold for noise. Does nothing if is null. - /// - [DataField] - public float Threshold = -1f; -} diff --git a/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs index 2ece880851..e9a5181f8d 100644 --- a/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs @@ -10,10 +10,4 @@ public sealed partial class ExteriorDunGen : IDunGenLayer { [DataField(required: true)] public ProtoId Proto; - - /// - /// Minimum and maximum penetration. - /// - [DataField] - public Vector2i Penetration = new Vector2i(5, 15); } diff --git a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs index c3f7ae3f33..89a4ab216a 100644 --- a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs @@ -14,12 +14,6 @@ public sealed partial class PrototypeDunGen : IDunGenLayer [DataField] public DungeonInheritance InheritDungeons = DungeonInheritance.None; - /// - /// Should we pass in the current level's reserved tiles to the prototype. - /// - [DataField] - public ReservedInheritance InheritReserved = ReservedInheritance.All; - [DataField(required: true)] public ProtoId Proto; } @@ -41,16 +35,3 @@ public enum DungeonInheritance : byte /// All, } - -public enum ReservedInheritance : byte -{ - /// - /// Don't inherit any reserved tiles. - /// - None, - - /// - /// Inherit reserved tiles, - /// - All, -} diff --git a/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs index e2506298fd..363de0a511 100644 --- a/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/FillGridDunGen.cs @@ -1,7 +1,4 @@ -using System.Numerics; using Content.Shared.Maps; -using Content.Shared.Procedural.Distance; -using Robust.Shared.Noise; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; @@ -9,6 +6,10 @@ namespace Content.Shared.Procedural.DungeonLayers; /// /// Fills unreserved tiles with the specified entity prototype. /// +/// +/// DungeonData keys are: +/// - Fill +/// public sealed partial class FillGridDunGen : IDunGenLayer { /// @@ -19,29 +20,4 @@ public sealed partial class FillGridDunGen : IDunGenLayer [DataField(required: true)] public EntProtoId Entity; - - #region Noise - - [DataField] - public bool Invert; - - /// - /// Optionally don't spawn entities if the noise value matches. - /// - [DataField] - public FastNoiseLite? ReservedNoise; - - /// - /// Noise threshold for . Does nothing without it. - /// - [DataField] - public float Threshold = -1f; - - [DataField] - public IDunGenDistance? DistanceConfig; - - [DataField] - public Vector2 Size; - - #endregion } diff --git a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs index 1b754d3778..5525341eb9 100644 --- a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs @@ -1,8 +1,10 @@ using Content.Shared.EntityTable; +using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; + /// /// Spawns mobs inside of the dungeon randomly. /// diff --git a/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs b/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs deleted file mode 100644 index fbb174dc14..0000000000 --- a/Content.Shared/Procedural/DungeonLayers/RoofDunGen.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Robust.Shared.Noise; - -namespace Content.Shared.Procedural.DungeonLayers; - -/// -/// Sets tiles as rooved. -/// -public sealed partial class RoofDunGen : IDunGenLayer -{ - [DataField] - public float Threshold = -1f; - - [DataField] - public FastNoiseLite? Noise; -} diff --git a/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs b/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs deleted file mode 100644 index 616e643b52..0000000000 --- a/Content.Shared/Procedural/DungeonLayers/SampleDecalDunGen.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Decals; -using Content.Shared.Maps; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.DungeonLayers; - -public sealed partial class SampleDecalDunGen : IDunGenLayer -{ - /// - /// Reserve any tiles we update. - /// - [DataField] - public bool ReserveTiles = true; - - [DataField(customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List AllowedTiles { get; private set; } = new(); - - /// - /// Divide each tile up by this amount. - /// - [DataField] - public float Divisions = 1f; - - [DataField] - public FastNoiseLite Noise { get; private set; } = new(0); - - [DataField] - public float Threshold { get; private set; } = 0.8f; - - [DataField] public bool Invert { get; private set; } = false; - - [DataField(required: true)] - public List> Decals = new(); -} diff --git a/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs b/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs deleted file mode 100644 index 2daf7e7aa7..0000000000 --- a/Content.Shared/Procedural/DungeonLayers/SampleEntityDunGen.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.DungeonLayers; - -/// -/// Samples noise to spawn the specified entity -/// -public sealed partial class SampleEntityDunGen : IDunGenLayer -{ - /// - /// Reserve any tiles we update. - /// - [DataField] - public bool ReserveTiles = true; - - [DataField(customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List AllowedTiles { get; private set; } = new(); - - [DataField] public FastNoiseLite Noise { get; private set; } = new(0); - - [DataField] - public float Threshold { get; private set; } = 0.5f; - - [DataField] public bool Invert { get; private set; } = false; - - [DataField] - public List Entities = new(); -} diff --git a/Content.Shared/Procedural/Loot/BiomeLoot.cs b/Content.Shared/Procedural/Loot/BiomeLoot.cs deleted file mode 100644 index 1330043493..0000000000 --- a/Content.Shared/Procedural/Loot/BiomeLoot.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared.Procedural.Loot; - -/// -/// Adds the prototype as a biome layer. -/// -public sealed partial class BiomeLoot : IDungeonLoot -{ - [DataField(required: true)] - public ProtoId Proto; -} diff --git a/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs b/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs new file mode 100644 index 0000000000..2eda4b059c --- /dev/null +++ b/Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs @@ -0,0 +1,15 @@ +using Content.Shared.Parallax.Biomes.Markers; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; + +namespace Content.Shared.Procedural.Loot; + +/// +/// Adds a biome marker layer for dungeon loot. +/// +public sealed partial class BiomeMarkerLoot : IDungeonLoot +{ + [DataField("proto", required: true)] + public ProtoId Prototype = new(); +} diff --git a/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs b/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs new file mode 100644 index 0000000000..e4968b6e42 --- /dev/null +++ b/Content.Shared/Procedural/Loot/BiomeTemplateLoot.cs @@ -0,0 +1,14 @@ +using Content.Shared.Parallax.Biomes; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Procedural.Loot; + +/// +/// Adds a biome template layer for dungeon loot. +/// +public sealed partial class BiomeTemplateLoot : IDungeonLoot +{ + [DataField("proto", required: true)] + public ProtoId Prototype = string.Empty; +} diff --git a/Content.Shared/Procedural/DungeonLayers/AutoCablingDunGen.cs b/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/AutoCablingDunGen.cs rename to Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs diff --git a/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs new file mode 100644 index 0000000000..e21e582211 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs @@ -0,0 +1,21 @@ +using Content.Shared.Maps; +using Content.Shared.Parallax.Biomes; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Generates a biome on top of valid tiles, then removes the biome when done. +/// Only works if no existing biome is present. +/// +public sealed partial class BiomeDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId BiomeTemplate; + + /// + /// creates a biome only on the specified tiles + /// + [DataField] + public HashSet>? TileMask; +} diff --git a/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs new file mode 100644 index 0000000000..af5d7c5d8f --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs @@ -0,0 +1,19 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Spawns the specified marker layer on top of the dungeon rooms. +/// +public sealed partial class BiomeMarkerLayerDunGen : IDunGenLayer +{ + /// + /// How many times to spawn marker layers; can duplicate. + /// + [DataField] + public int Count = 6; + + [DataField(required: true)] + public ProtoId MarkerTemplate; +} diff --git a/Content.Shared/Procedural/DungeonLayers/BoundaryWallDunGen.cs b/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/BoundaryWallDunGen.cs rename to Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/CornerClutterDunGen.cs b/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/CornerClutterDunGen.cs rename to Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/CorridorClutterDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/CorridorClutterDunGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/CorridorDecalSkirtingDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/CorridorDecalSkirtingDunGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/CorridorDunGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/CorridorDunGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/DungeonEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/DungeonEntranceDunGen.cs rename to Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs similarity index 93% rename from Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs rename to Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs index cd6cf169fc..f9be6caf6a 100644 --- a/Content.Shared/Procedural/DungeonLayers/EntranceFlankDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs @@ -1,6 +1,5 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; -using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs similarity index 94% rename from Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs rename to Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs index 30b8302263..fc992ea7b8 100644 --- a/Content.Shared/Procedural/DungeonLayers/ExternalWindowDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs @@ -1,5 +1,6 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; +using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/DungeonLayers/InternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/InternalWindowDunGen.cs rename to Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/JunctionDunGen.cs b/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/JunctionDunGen.cs rename to Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/MiddleConnectionDunGen.cs b/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/MiddleConnectionDunGen.cs rename to Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs similarity index 93% rename from Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs rename to Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs index f0fea57588..1436f7473d 100644 --- a/Content.Shared/Procedural/DungeonLayers/RoomEntranceDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs @@ -1,5 +1,6 @@ using Content.Shared.EntityTable; using Content.Shared.Maps; +using Content.Shared.Storage; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; diff --git a/Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs similarity index 83% rename from Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs rename to Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs index 4a4bc0b36a..d2f5a2126a 100644 --- a/Content.Shared/Procedural/DungeonLayers/SplineDungeonConnectorDunGen.cs +++ b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs @@ -1,7 +1,7 @@ using Content.Shared.Maps; using Robust.Shared.Prototypes; -namespace Content.Shared.Procedural.DungeonLayers; +namespace Content.Shared.Procedural.PostGeneration; /// /// Connects dungeons via points that get subdivided. @@ -18,11 +18,11 @@ public sealed partial class SplineDungeonConnectorDunGen : IDunGenLayer /// Will divide the distance between the start and end points so that no subdivision is more than these metres away. /// [DataField] - public int DivisionDistance = 20; + public int DivisionDistance = 10; /// /// How much each subdivision can vary from the middle. /// [DataField] - public float VarianceMax = 0.15f; + public float VarianceMax = 0.35f; } diff --git a/Content.Shared/Procedural/DungeonLayers/WallMountDunGen.cs b/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/WallMountDunGen.cs rename to Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs diff --git a/Content.Shared/Procedural/DungeonLayers/WormCorridorDunGen.cs b/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs similarity index 100% rename from Content.Shared/Procedural/DungeonLayers/WormCorridorDunGen.cs rename to Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs diff --git a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs index 10106cd666..e84223ed1f 100644 --- a/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs +++ b/Content.Shared/Salvage/Expeditions/Modifiers/SalvageBiomeModPrototype.cs @@ -1,4 +1,6 @@ +using Content.Shared.Parallax.Biomes; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Salvage.Expeditions.Modifiers; @@ -24,6 +26,6 @@ public sealed partial class SalvageBiomeModPrototype : IPrototype, ISalvageMod [DataField("weather")] public bool Weather = true; - [DataField("biome", required: true)] - public EntProtoId? BiomePrototype; + [DataField("biome", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] + public string? BiomePrototype; } diff --git a/Resources/Locale/en-US/procedural/biome.ftl b/Resources/Locale/en-US/procedural/biome.ftl index 7c2a88a696..d24ec7d72e 100644 --- a/Resources/Locale/en-US/procedural/biome.ftl +++ b/Resources/Locale/en-US/procedural/biome.ftl @@ -1,2 +1,6 @@ +cmd-biome_clear-desc = Clears a biome entirely +cmd-biome_clear-help = biome_clear cmd-biome_addlayer-desc = Adds another biome layer cmd-biome_addlayer-help = biome_addlayer [seed offset] +cmd-biome_addmarkerlayer-desc = Adds another biome marker layer +cmd-biome_addmarkerlayer-help = biome_addmarkerlayer diff --git a/Resources/Prototypes/Entities/Tiles/water.yml b/Resources/Prototypes/Entities/Tiles/water.yml index 357bc9f98c..c488df231b 100644 --- a/Resources/Prototypes/Entities/Tiles/water.yml +++ b/Resources/Prototypes/Entities/Tiles/water.yml @@ -17,14 +17,10 @@ drawdepth: BelowFloor layers: - state: shoreline_water - - type: BiomeForceUnload - #- type: ContainerContainer - # containers: - # solution@pool: !type:ContainerSlot - type: SolutionContainerManager solutions: pool: - maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable. + maxVol: 9999999 #.inf seems to break the whole yaml file, but would definitely be preferable. reagents: - ReagentId: Water Quantity: 9999999 diff --git a/Resources/Prototypes/Procedural/Magnet/asteroid.yml b/Resources/Prototypes/Procedural/Magnet/asteroid.yml index f838104f3c..a77a6b287b 100644 --- a/Resources/Prototypes/Procedural/Magnet/asteroid.yml +++ b/Resources/Prototypes/Procedural/Magnet/asteroid.yml @@ -18,9 +18,8 @@ lacunarity: 2 # Generate biome - - !type:PrototypeDunGen - proto: Asteroid - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: Asteroid - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -48,9 +47,8 @@ lacunarity: 2 # Generate biome - - !type:PrototypeDunGen - proto: Asteroid - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: Asteroid - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -78,9 +76,8 @@ cellularDistanceFunction: Euclidean # Generate biome - - !type:PrototypeDunGen - proto: Asteroid - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: Asteroid - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite @@ -107,9 +104,8 @@ lacunarity: 2 # Generate biome - - !type:PrototypeDunGen - proto: Asteroid - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: Asteroid - !type:OreDunGen replacement: AsteroidRock entity: AsteroidRockGibtonite diff --git a/Resources/Prototypes/Procedural/Magnet/space_debris.yml b/Resources/Prototypes/Procedural/Magnet/space_debris.yml index a9bd823e6b..11c1afdabe 100644 --- a/Resources/Prototypes/Procedural/Magnet/space_debris.yml +++ b/Resources/Prototypes/Procedural/Magnet/space_debris.yml @@ -36,9 +36,8 @@ gain: 0.5 # Generate biome - - !type:PrototypeDunGen - proto: SpaceDebris - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: SpaceDebris - type: dungeonConfig id: ChunkDebrisSmall @@ -78,6 +77,5 @@ gain: 0.5 # Generate biome - - !type:PrototypeDunGen - proto: SpaceDebris - inheritDungeons: All + - !type:BiomeDunGen + biomeTemplate: SpaceDebris diff --git a/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml b/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml index e181f89268..47aa47fce4 100644 --- a/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml +++ b/Resources/Prototypes/Procedural/Magnet/space_debris_templates.yml @@ -1,8 +1,8 @@ # Asteroid -- type: dungeonConfig +- type: biomeTemplate id: SpaceDebris layers: - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.20 noise: seed: 0 @@ -23,7 +23,7 @@ - WallReinforced - WallSolid - WallSolid - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.5 noise: seed: 0 @@ -41,7 +41,7 @@ - Grille - Grille - GrilleBroken - - !type:SampleDecalDunGen + - !type:BiomeDecalLayer allowedTiles: - FloorSteel threshold: -0.5 @@ -56,7 +56,7 @@ - DirtMedium - DirtMedium - DirtLight - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.45 noise: seed: 1 @@ -71,7 +71,7 @@ - FloorSteel entities: - SalvageSpawnerStructuresVarious - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer allowedTiles: - FloorSteel - Plating @@ -85,7 +85,7 @@ - SalvageSpawnerScrapCommon - SalvageSpawnerScrapCommon - SalvageSpawnerScrapCommon75 - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer allowedTiles: - FloorSteel - Plating @@ -97,7 +97,7 @@ - SalvageSpawnerTreasure - SalvageSpawnerTreasure - SalvageSpawnerTreasureValuable - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer allowedTiles: - FloorSteel - Plating diff --git a/Resources/Prototypes/Procedural/biome_markers.yml b/Resources/Prototypes/Procedural/biome_markers.yml index ef28b314ca..5c4fdeb178 100644 --- a/Resources/Prototypes/Procedural/biome_markers.yml +++ b/Resources/Prototypes/Procedural/biome_markers.yml @@ -1,122 +1,67 @@ -- type: dungeonConfig +- type: biomeMarkerLayer id: Lizards - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobLizard - amount: !type:RangeNumberSelector - range: 3, 5 + prototype: MobLizard + minGroupSize: 3 + maxGroupSize: 5 - -- type: dungeonConfig +- type: biomeMarkerLayer id: WatchersLavaland - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobWatcherLavaland - amount: !type:RangeNumberSelector - range: 3, 3 + prototype: MobWatcherLavaland + minGroupSize: 3 + maxGroupSize: 3 -- type: dungeonConfig +- type: biomeMarkerLayer id: WatchersIcewing - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobWatcherIcewing - amount: !type:RangeNumberSelector - range: 3, 3 + prototype: MobWatcherIcewing + minGroupSize: 3 + maxGroupSize: 3 -- type: dungeonConfig +- type: biomeMarkerLayer id: WatchersMagmawing - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobWatcherMagmawing - amount: !type:RangeNumberSelector - range: 3, 3 + prototype: MobWatcherMagmawing + minGroupSize: 3 + maxGroupSize: 3 -- type: dungeonConfig +- type: biomeMarkerLayer id: Cows - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobCow - amount: !type:RangeNumberSelector - range: 1, 2 + prototype: MobCow + minGroupSize: 1 + maxGroupSize: 2 -- type: dungeonConfig +- type: biomeMarkerLayer id: Chickens - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobChicken - amount: !type:RangeNumberSelector - range: 1, 2 + prototype: MobChicken + minGroupSize: 1 + maxGroupSize: 2 -- type: dungeonConfig +- type: biomeMarkerLayer id: Pigs - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobPig - amount: !type:RangeNumberSelector - range: 1, 2 + prototype: MobPig + minGroupSize: 1 + maxGroupSize: 2 -- type: dungeonConfig +- type: biomeMarkerLayer id: Foxes - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobFox - amount: !type:RangeNumberSelector - range: 1, 1 + prototype: MobFox + minGroupSize: 1 + maxGroupSize: 1 -- type: dungeonConfig +- type: biomeMarkerLayer id: Goats - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobGoat - amount: !type:RangeNumberSelector - range: 1, 1 + prototype: MobGoat + minGroupSize: 1 + maxGroupSize: 1 -- type: dungeonConfig - id: Carps - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobCarp - amount: !type:RangeNumberSelector - range: 1, 2 - -- type: dungeonConfig +# TODO: Needs to be more robust +- type: biomeMarkerLayer id: Xenos - layers: - - !type:ChunkDunGen - size: 128 - - !type:EntityTableDunGen - table: !type:EntSelector - id: MobXeno - amount: !type:RangeNumberSelector - range: 1, 2 + prototype: MobXeno +- type: biomeMarkerLayer + id: Carps + prototype: MobCarpDungeon + + +#- type: biomeMarkerLayer +# id: Experiment +# proto: DungeonMarkerExperiment diff --git a/Resources/Prototypes/Procedural/biome_ore_templates.yml b/Resources/Prototypes/Procedural/biome_ore_templates.yml index 16b2c7e64f..ae033230b6 100644 --- a/Resources/Prototypes/Procedural/biome_ore_templates.yml +++ b/Resources/Prototypes/Procedural/biome_ore_templates.yml @@ -1,127 +1,146 @@ # Low value -- type: dungeonConfig +- type: biomeMarkerLayer id: OreIron - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockTin - count: 30 - minGroupSize: 10 - maxGroupSize: 15 + entityMask: + AsteroidRock: AsteroidRockTin + WallRock: WallRockTin + WallRockBasalt: WallRockBasaltTin + WallRockChromite: WallRockChromiteTin + WallRockSand: WallRockSandTin + WallRockSnow: WallRockSnowTin + maxCount: 30 + minGroupSize: 10 + maxGroupSize: 15 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreQuartz - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockQuartz - count: 30 - minGroupSize: 10 - maxGroupSize: 15 + entityMask: + AsteroidRock: AsteroidRockQuartz + WallRock: WallRockQuartz + WallRockBasalt: WallRockBasaltQuartz + WallRockChromite: WallRockChromiteQuartz + WallRockSnow: WallRockSnowQuartz + maxCount: 30 + minGroupSize: 10 + maxGroupSize: 15 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreCoal - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockCoal - count: 30 - minGroupSize: 8 - maxGroupSize: 12 + entityMask: + AsteroidRock: AsteroidRockCoal + WallRock: WallRockCoal + WallRockBasalt: WallRockBasaltCoal + WallRockChromite: WallRockChromiteCoal + WallRockSand: WallRockSandCoal + WallRockSnow: WallRockSnowCoal + maxCount: 30 + minGroupSize: 8 + maxGroupSize: 12 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreSalt - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockSalt - count: 30 - minGroupSize: 8 - maxGroupSize: 12 + entityMask: + AsteroidRock: AsteroidRockSalt + WallRock: WallRockSalt + WallRockBasalt: WallRockBasaltSalt + WallRockChromite: WallRockChromiteSalt + WallRockSand: WallRockSandSalt + WallRockSnow: WallRockSnowSalt + maxCount: 30 + minGroupSize: 8 + maxGroupSize: 12 + radius: 4 # Medium value # Gold -- type: dungeonConfig +- type: biomeMarkerLayer id: OreGold - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockGold - count: 20 - minGroupSize: 5 - maxGroupSize: 10 + entityMask: + AsteroidRock: AsteroidRockGold + WallRock: WallRockGold + WallRockBasalt: WallRockBasaltGold + WallRockChromite: WallRockChromiteGold + WallRockSand: WallRockSandGold + WallRockSnow: WallRockSnowGold + maxCount: 20 + minGroupSize: 5 + maxGroupSize: 10 + radius: 4 # Silver -- type: dungeonConfig +- type: biomeMarkerLayer id: OreSilver - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockSilver - count: 20 - minGroupSize: 5 - maxGroupSize: 10 + entityMask: + AsteroidRock: AsteroidRockSilver + WallRock: WallRockSilver + WallRockBasalt: WallRockBasaltSilver + WallRockChromite: WallRockChromiteSilver + WallRockSand: WallRockSandSilver + WallRockSnow: WallRockSnowSilver + maxCount: 20 + minGroupSize: 5 + maxGroupSize: 10 + radius: 4 # High value # Plasma -- type: dungeonConfig +- type: biomeMarkerLayer id: OrePlasma - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockPlasma - count: 12 - minGroupSize: 4 - maxGroupSize: 8 + entityMask: + AsteroidRock: AsteroidRockPlasma + WallRock: WallRockPlasma + WallRockBasalt: WallRockBasaltPlasma + WallRockChromite: WallRockChromitePlasma + WallRockSand: WallRockSandPlasma + WallRockSnow: WallRockSnowPlasma + maxCount: 12 + minGroupSize: 4 + maxGroupSize: 8 + radius: 4 # Uranium -- type: dungeonConfig +- type: biomeMarkerLayer id: OreUranium - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockUranium - count: 15 - minGroupSize: 4 - maxGroupSize: 8 + entityMask: + AsteroidRock: AsteroidRockUranium + WallRock: WallRockUranium + WallRockBasalt: WallRockBasaltUranium + WallRockChromite: WallRockChromiteUranium + WallRockSand: WallRockSandUranium + WallRockSnow: WallRockSnowUranium + maxCount: 15 + minGroupSize: 4 + maxGroupSize: 8 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreDiamond - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockDiamond - count: 6 - minGroupSize: 1 - maxGroupSize: 2 + entityMask: + AsteroidRock: AsteroidRockDiamond + WallRock: WallRockDiamond + WallRockBasalt: WallRockBasaltDiamond + WallRockChromite: WallRockChromiteDiamond + WallRockSand: WallRockSandDiamond + WallRockSnow: WallRockSnowDiamond + maxCount: 6 + minGroupSize: 1 + maxGroupSize: 2 + radius: 4 # Artifact Fragment -- type: dungeonConfig +- type: biomeMarkerLayer id: OreArtifactFragment - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockArtifactFragment - count: 6 - minGroupSize: 1 - maxGroupSize: 2 + entityMask: + AsteroidRock: AsteroidRockArtifactFragment + WallRock: WallRockArtifactFragment + WallRockBasalt: WallRockBasaltArtifactFragment + WallRockChromite: WallRockChromiteArtifactFragment + WallRockSand: WallRockSandArtifactFragment + WallRockSnow: WallRockSnowArtifactFragment + maxCount: 6 + minGroupSize: 1 + maxGroupSize: 2 + radius: 4 diff --git a/Resources/Prototypes/Procedural/biome_ore_templates_low.yml b/Resources/Prototypes/Procedural/biome_ore_templates_low.yml index 9af10e3c2b..3b0e242446 100644 --- a/Resources/Prototypes/Procedural/biome_ore_templates_low.yml +++ b/Resources/Prototypes/Procedural/biome_ore_templates_low.yml @@ -1,127 +1,146 @@ # Low value -- type: dungeonConfig +- type: biomeMarkerLayer id: OreIronLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockTin - count: 20 - minGroupSize: 4 - maxGroupSize: 8 + entityMask: + AsteroidRock: AsteroidRockTin + WallRock: WallRockTin + WallRockBasalt: WallRockBasaltTin + WallRockChromite: WallRockChromiteTin + WallRockSand: WallRockSandTin + WallRockSnow: WallRockSnowTin + maxCount: 20 + minGroupSize: 4 + maxGroupSize: 8 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreQuartzLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockQuartz - count: 20 - minGroupSize: 4 - maxGroupSize: 8 + entityMask: + AsteroidRock: AsteroidRockQuartz + WallRock: WallRockQuartz + WallRockBasalt: WallRockBasaltQuartz + WallRockChromite: WallRockChromiteQuartz + WallRockSnow: WallRockSnowQuartz + maxCount: 20 + minGroupSize: 4 + maxGroupSize: 8 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreCoalLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockCoal - count: 20 - minGroupSize: 4 - maxGroupSize: 6 + entityMask: + AsteroidRock: AsteroidRockCoal + WallRock: WallRockCoal + WallRockBasalt: WallRockBasaltCoal + WallRockChromite: WallRockChromiteCoal + WallRockSand: WallRockSandCoal + WallRockSnow: WallRockSnowCoal + maxCount: 20 + minGroupSize: 4 + maxGroupSize: 6 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreSaltLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockSalt - count: 15 - minGroupSize: 4 - maxGroupSize: 6 + entityMask: + AsteroidRock: AsteroidRockSalt + WallRock: WallRockSalt + WallRockBasalt: WallRockBasaltSalt + WallRockChromite: WallRockChromiteSalt + WallRockSand: WallRockSandSalt + WallRockSnow: WallRockSnowSalt + maxCount: 15 + minGroupSize: 4 + maxGroupSize: 6 + radius: 4 # Medium value # Gold -- type: dungeonConfig +- type: biomeMarkerLayer id: OreGoldLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockGold - count: 12 - minGroupSize: 2 - maxGroupSize: 5 + entityMask: + AsteroidRock: AsteroidRockGold + WallRock: WallRockGold + WallRockBasalt: WallRockBasaltGold + WallRockChromite: WallRockChromiteGold + WallRockSand: WallRockSandGold + WallRockSnow: WallRockSnowGold + maxCount: 10 + minGroupSize: 2 + maxGroupSize: 5 + radius: 4 # Silver -- type: dungeonConfig +- type: biomeMarkerLayer id: OreSilverLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockSilver - count: 12 - minGroupSize: 2 - maxGroupSize: 5 + entityMask: + AsteroidRock: AsteroidRockSilver + WallRock: WallRockSilver + WallRockBasalt: WallRockBasaltSilver + WallRockChromite: WallRockChromiteSilver + WallRockSand: WallRockSandSilver + WallRockSnow: WallRockSnowSilver + maxCount: 10 + minGroupSize: 2 + maxGroupSize: 5 + radius: 4 # High value # Plasma -- type: dungeonConfig +- type: biomeMarkerLayer id: OrePlasmaLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockPlasma - count: 6 - minGroupSize: 2 - maxGroupSize: 4 + entityMask: + AsteroidRock: AsteroidRockPlasma + WallRock: WallRockPlasma + WallRockBasalt: WallRockBasaltPlasma + WallRockChromite: WallRockChromitePlasma + WallRockSand: WallRockSandPlasma + WallRockSnow: WallRockSnowPlasma + maxCount: 6 + minGroupSize: 2 + maxGroupSize: 4 + radius: 4 # Uranium -- type: dungeonConfig +- type: biomeMarkerLayer id: OreUraniumLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockUranium - count: 7 - minGroupSize: 2 - maxGroupSize: 4 + entityMask: + AsteroidRock: AsteroidRockUranium + WallRock: WallRockUranium + WallRockBasalt: WallRockBasaltUranium + WallRockChromite: WallRockChromiteUranium + WallRockSand: WallRockSandUranium + WallRockSnow: WallRockSnowUranium + maxCount: 7 + minGroupSize: 2 + maxGroupSize: 4 + radius: 4 -- type: dungeonConfig +- type: biomeMarkerLayer id: OreDiamondLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockDiamond - count: 3 - minGroupSize: 1 - maxGroupSize: 2 + entityMask: + AsteroidRock: AsteroidRockDiamond + WallRock: WallRockDiamond + WallRockBasalt: WallRockBasaltDiamond + WallRockChromite: WallRockChromiteDiamond + WallRockSand: WallRockSandDiamond + WallRockSnow: WallRockSnowDiamond + maxCount: 3 + minGroupSize: 1 + maxGroupSize: 2 + radius: 4 # Artifact Fragment -- type: dungeonConfig +- type: biomeMarkerLayer id: OreArtifactFragmentLow - layers: - - !type:ChunkDunGen - size: 128 - - !type:OreDunGen - replacement: WallRock - entity: WallRockArtifactFragment - count: 3 - minGroupSize: 1 - maxGroupSize: 2 + entityMask: + AsteroidRock: AsteroidRockArtifactFragment + WallRock: WallRockArtifactFragment + WallRockBasalt: WallRockBasaltArtifactFragment + WallRockChromite: WallRockChromiteArtifactFragment + WallRockSand: WallRockSandArtifactFragment + WallRockSnow: WallRockSnowArtifactFragment + maxCount: 3 + minGroupSize: 1 + maxGroupSize: 2 + radius: 4 diff --git a/Resources/Prototypes/Procedural/biome_templates.yml b/Resources/Prototypes/Procedural/biome_templates.yml index 747660dc8f..d630ebad48 100644 --- a/Resources/Prototypes/Procedural/biome_templates.yml +++ b/Resources/Prototypes/Procedural/biome_templates.yml @@ -1,551 +1,435 @@ +# Contains several biomes +- type: biomeTemplate + id: Continental + layers: + - !type:BiomeMetaLayer + template: Lava + - !type:BiomeMetaLayer + template: Caves + threshold: -0.5 + noise: + frequency: 0.001 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 2 + lacunarity: 2 + - !type:BiomeMetaLayer + template: Grasslands + threshold: 0 + noise: + frequency: 0.001 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 2 + lacunarity: 2 + - !type:BiomeMetaLayer + template: Snow + threshold: 0.5 + noise: + frequency: 0.001 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 2 + lacunarity: 2 + # Desert -- type: entity - id: BiomeLowDesert - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: LowDesertTerrain - -- type: dungeonConfig - id: LowDesertTerrain +# TODO: Water in desert +- type: biomeTemplate + id: LowDesert layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: LowDesertTiles - inheritDungeons: All - - !type:PrototypeDunGen - proto: LowDesertEntities - inheritDungeons: All + - !type:BiomeEntityLayer + threshold: 0.95 + noise: + seed: 0 + frequency: 2 + noiseType: OpenSimplex2 + allowedTiles: + - FloorAsteroidSand + entities: + - FloraRockSolid + # Large rock areas + - !type:BiomeEntityLayer + threshold: -0.20 + noise: + seed: 0 + frequency: 0.04 + noiseType: Cellular + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + allowedTiles: + - FloorAsteroidSand + entities: + - WallRockSand + - !type:BiomeDummyLayer + id: Loot + # Fill layer + - !type:BiomeTileLayer + threshold: -1 + tile: FloorAsteroidSand -- type: dungeonConfig - id: LowDesertTiles - returnReserved: false +# Grass +- type: biomeTemplate + id: Grasslands layers: - - !type:SampleTileDunGen - threshold: -1 - tile: FloorAsteroidSand - -- type: dungeonConfig - id: LowDesertEntities - reserveTiles: true - layers: - - !type:SampleEntityDunGen - threshold: 0.95 - noise: - seed: 0 - frequency: 2 - noiseType: OpenSimplex2 - allowedTiles: - - FloorAsteroidSand - entities: - - FloraRockSolid - # Large rock areas - - !type:SampleEntityDunGen - threshold: -0.20 - noise: - seed: 0 - frequency: 0.04 - noiseType: Cellular - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - allowedTiles: - - FloorAsteroidSand - entities: - - WallRockSand - - -- type: entity - id: BiomeGrasslands - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: GrasslandsTerrain - -- type: dungeonConfig - id: GrasslandsTerrain - layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: GrasslandsTiles - inheritDungeons: All - - !type:PrototypeDunGen - proto: GrasslandsEntities - inheritDungeons: All - - !type:PrototypeDunGen - proto: GrasslandsDecals - inheritDungeons: All - -- type: dungeonConfig - id: GrasslandsTiles - returnReserved: false - layers: - # Water sand - - !type:SampleTileDunGen - tile: FloorPlanetDirt - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - # Rock formation sand - - !type:SampleTileDunGen - tile: FloorPlanetDirt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - - !type:SampleTileDunGen - threshold: -0.80 - tile: FloorPlanetGrass - noise: - seed: 0 - noiseType: OpenSimplex2 - lacunarity: 1.50 - frequency: 0.02 - fractalType: None - octaves: 1 - # Fill remainder with dirt. - - !type:SampleTileDunGen - threshold: -1.0 - tile: FloorPlanetDirt - -- type: dungeonConfig - id: GrasslandsEntities - reserveTiles: true - layers: - # Water - - !type:SampleEntityDunGen - allowedTiles: - - FloorPlanetGrass - - FloorPlanetDirt - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - entities: - - FloorWaterEntity - # Rock formations - - !type:SampleEntityDunGen - allowedTiles: - - FloorPlanetGrass - - FloorPlanetDirt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRock - - !type:SampleEntityDunGen - threshold: 0.5 - noise: - seed: 0 - noiseType: OpenSimplex2 - fractalType: FBm - frequency: 2 - allowedTiles: - - FloorPlanetGrass - entities: - - FloraTree - - FloraTreeLarge - -- type: dungeonConfig - id: GrasslandsDecals - returnReserved: false - layers: - # Dense vegetation - - !type:SampleDecalDunGen - allowedTiles: - - FloorPlanetGrass - divisions: 1 - threshold: -0.35 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.2 - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - BushAOne - - BushATwo - - BushAThree - - BushCOne - - BushCTwo - - BushCThree - - !type:SampleDecalDunGen - allowedTiles: - - FloorPlanetGrass - noise: - seed: 0 - noiseType: OpenSimplex2 - frequency: 1 - divisions: 1 - threshold: 0.8 - decals: - - FlowersBROne - - FlowersBRTwo - - FlowersBRThree - # Sparse vegetation - - !type:SampleDecalDunGen - allowedTiles: - - FloorPlanetGrass - divisions: 2 - threshold: -0.50 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - decals: - - BushDOne - - BushDTwo - - BushDThree + # Sparse vegetation + - !type:BiomeDecalLayer + allowedTiles: + - FloorPlanetGrass + divisions: 2 + threshold: -0.50 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + decals: + - BushDOne + - BushDTwo + - BushDThree + - !type:BiomeDecalLayer + allowedTiles: + - FloorPlanetGrass + noise: + seed: 0 + noiseType: OpenSimplex2 + frequency: 1 + divisions: 1 + threshold: 0.8 + decals: + - FlowersBROne + - FlowersBRTwo + - FlowersBRThree + # Dense vegetation + - !type:BiomeDecalLayer + allowedTiles: + - FloorPlanetGrass + divisions: 1 + threshold: -0.35 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.2 + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - BushAOne + - BushATwo + - BushAThree + - BushCOne + - BushCTwo + - BushCThree + - !type:BiomeEntityLayer + threshold: 0.5 + noise: + seed: 0 + noiseType: OpenSimplex2 + fractalType: FBm + frequency: 2 + allowedTiles: + - FloorPlanetGrass + entities: + - FloraTree + - FloraTreeLarge + # Rock formations + - !type:BiomeEntityLayer + allowedTiles: + - FloorPlanetGrass + - FloorPlanetDirt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRock + - !type:BiomeDummyLayer + id: Loot + # Water + - !type:BiomeEntityLayer + allowedTiles: + - FloorPlanetGrass + - FloorPlanetDirt + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + entities: + - FloorWaterEntity + # Fill remainder with dirt. + - !type:BiomeTileLayer + threshold: -1.0 + tile: FloorPlanetDirt + - !type:BiomeTileLayer + threshold: -0.90 + tile: FloorPlanetGrass + noise: + seed: 0 + frequency: 0.02 + fractalType: None + # Water sand + - !type:BiomeTileLayer + tile: FloorPlanetDirt + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + # Rock formation sand + - !type:BiomeTileLayer + tile: FloorPlanetDirt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 # Lava -- type: entity - id: BiomeLava - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: LavaTerrain - -- type: dungeonConfig - id: LavaTerrain +- type: biomeTemplate + id: Lava layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: LavaTiles - inheritDungeons: All - - !type:PrototypeDunGen - proto: LavaEntities - inheritDungeons: All - - !type:PrototypeDunGen - proto: LavaDecals - inheritDungeons: All - - !type:PrototypeDunGen - proto: LavaBasalt - inheritDungeons: All - -- type: dungeonConfig - id: LavaTiles - returnReserved: false - layers: - # Fill basalt - - !type:SampleTileDunGen - threshold: -1 - tile: FloorBasalt - -- type: dungeonConfig - id: LavaEntities - reserveTiles: true - layers: - - !type:SampleEntityDunGen - threshold: 0.2 - noise: - seed: 0 - frequency: 0.02 - fractalType: FBm - octaves: 5 - lacunarity: 2 - gain: 0.4 - allowedTiles: - - FloorBasalt - entities: - - FloorLavaEntity - # Rock formations - - !type:SampleEntityDunGen - allowedTiles: - - FloorBasalt - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRockBasalt - - !type:SampleEntityDunGen - threshold: 0.95 - noise: - seed: 0 - noiseType: OpenSimplex2 - frequency: 1 - allowedTiles: - - FloorBasalt - entities: - - FloraRockSolid - -- type: dungeonConfig - id: LavaDecals - returnReserved: false - layers: - - !type:SampleDecalDunGen - allowedTiles: - - FloorBasalt - threshold: 0.9 - divisions: 1 - noise: - seed: 1 - frequency: 1 - decals: - - Basalt1 - - Basalt2 - - Basalt3 - - Basalt4 - - Basalt5 - - Basalt6 - - Basalt7 - - Basalt8 - - Basalt9 - -- type: dungeonConfig - id: LavaBasalt - returnReserved: false - layers: - - !type:SampleEntityDunGen - threshold: 0.9 - noise: - frequency: 1 - seed: 2 - allowedTiles: - - FloorBasalt - entities: - - BasaltOne - - BasaltTwo - - BasaltThree - - BasaltFour - - BasaltFive + - !type:BiomeEntityLayer + threshold: 0.9 + noise: + frequency: 1 + seed: 2 + allowedTiles: + - FloorBasalt + entities: + - BasaltOne + - BasaltTwo + - BasaltThree + - BasaltFour + - BasaltFive + - !type:BiomeDecalLayer + allowedTiles: + - FloorBasalt + threshold: 0.9 + divisions: 1 + noise: + seed: 1 + frequency: 1 + decals: + - Basalt1 + - Basalt2 + - Basalt3 + - Basalt4 + - Basalt5 + - Basalt6 + - Basalt7 + - Basalt8 + - Basalt9 + - !type:BiomeEntityLayer + threshold: 0.95 + noise: + seed: 0 + noiseType: OpenSimplex2 + frequency: 1 + allowedTiles: + - FloorBasalt + entities: + - FloraRockSolid + - !type:BiomeEntityLayer + threshold: 0.2 + noise: + seed: 0 + frequency: 0.02 + fractalType: FBm + octaves: 5 + lacunarity: 2 + gain: 0.4 + allowedTiles: + - FloorBasalt + entities: + - FloorLavaEntity + # Rock formations + - !type:BiomeEntityLayer + allowedTiles: + - FloorBasalt + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRockBasalt + - !type:BiomeDummyLayer + id: Loot + # Fill basalt + - !type:BiomeTileLayer + threshold: -1 + tile: FloorBasalt # Snow -- type: entity - id: BiomeSnow - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: SnowTerrain - -- type: dungeonConfig - id: SnowTerrain +- type: biomeTemplate + id: Snow # Similar to Grasslands... but snow layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: SnowTiles - inheritDungeons: All - - !type:PrototypeDunGen - proto: SnowEntities - inheritDungeons: All - - !type:PrototypeDunGen - proto: SnowDecals - inheritDungeons: All - -- type: dungeonConfig - id: SnowTiles - returnReserved: false - layers: - - !type:SampleTileDunGen - threshold: -0.7 - tile: FloorSnow - noise: - seed: 0 - frequency: 0.02 - fractalType: None - - !type:SampleTileDunGen - tile: FloorIce - threshold: -0.9 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.03 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - - -- type: dungeonConfig - id: SnowEntities - reserveTiles: true - layers: - # Liquid plasma rivers. Ice moon baby - - !type:SampleEntityDunGen - allowedTiles: - - FloorSnow - - FloorIce - threshold: 0.95 - noise: - seed: 3 - noiseType: OpenSimplex2 - frequency: 0.003 - lacunarity: 1.50 - fractalType: Ridged - octaves: 1 - entities: - - FloorLiquidPlasmaEntity - # Rock formations - - !type:SampleEntityDunGen - allowedTiles: - - FloorSnow - threshold: -0.30 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.05 - lacunarity: 2 - fractalType: FBm - octaves: 5 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - entities: - - WallRockSnow - - !type:SampleEntityDunGen - threshold: 0.5 - noise: - seed: 0 - noiseType: OpenSimplex2 - fractalType: FBm - frequency: 2 - allowedTiles: - - FloorSnow - entities: - - FloraTreeSnow - -- type: dungeonConfig - id: SnowDecals - returnReserved: false - layers: - # Sparse vegetation - - !type:SampleDecalDunGen - allowedTiles: - - FloorSnow - divisions: 2 - threshold: -0.50 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - decals: - - grasssnowa1 - - grasssnowa2 - - grasssnowa3 - - grasssnowb1 - - grasssnowb2 - - grasssnowb3 - - grasssnowc1 - - grasssnowc2 - - grasssnowc3 - # Dense, bland grass - - !type:SampleDecalDunGen - allowedTiles: - - FloorSnow - divisions: 1 - threshold: -0.35 - noise: - seed: 0 - noiseType: Cellular - frequency: 0.2 - fractalType: FBm - octaves: 5 - lacunarity: 2 - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - grasssnow - - grasssnow01 - - grasssnow02 - - grasssnow03 - - grasssnow04 - - grasssnow05 - - grasssnow06 - - grasssnow07 - - grasssnow08 - - grasssnow09 - - grasssnow10 - - grasssnow11 - - grasssnow12 - - grasssnow13 - # Little bit of coloured grass - - !type:SampleDecalDunGen - allowedTiles: - - FloorSnow - divisions: 1 - threshold: -0.0 - noise: - seed: 0 - noiseType: Cellular - frequency: 1 - fractalType: None - cellularDistanceFunction: Euclidean - cellularReturnType: Distance2 - decals: - - bushsnowa1 - - bushsnowa2 - - bushsnowa3 - - bushsnowb3 - - bushsnowb2 - - bushsnowb3 + # Sparse vegetation + - !type:BiomeDecalLayer + allowedTiles: + - FloorSnow + divisions: 2 + threshold: -0.50 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + decals: + - grasssnowa1 + - grasssnowa2 + - grasssnowa3 + - grasssnowb1 + - grasssnowb2 + - grasssnowb3 + - grasssnowc1 + - grasssnowc2 + - grasssnowc3 + # Dense, bland grass + - !type:BiomeDecalLayer + allowedTiles: + - FloorSnow + divisions: 1 + threshold: -0.35 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.2 + fractalType: FBm + octaves: 5 + lacunarity: 2 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - grasssnow + - grasssnow01 + - grasssnow02 + - grasssnow03 + - grasssnow04 + - grasssnow05 + - grasssnow06 + - grasssnow07 + - grasssnow08 + - grasssnow09 + - grasssnow10 + - grasssnow11 + - grasssnow12 + - grasssnow13 + # Little bit of coloured grass + - !type:BiomeDecalLayer + allowedTiles: + - FloorSnow + divisions: 1 + threshold: -0.0 + noise: + seed: 0 + noiseType: Cellular + frequency: 1 + fractalType: None + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + decals: + - bushsnowa1 + - bushsnowa2 + - bushsnowa3 + - bushsnowb3 + - bushsnowb2 + - bushsnowb3 + - !type:BiomeEntityLayer + threshold: 0.5 + noise: + seed: 0 + noiseType: OpenSimplex2 + fractalType: FBm + frequency: 2 + allowedTiles: + - FloorSnow + entities: + - FloraTreeSnow + # Rock formations + - !type:BiomeEntityLayer + allowedTiles: + - FloorSnow + threshold: -0.30 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.05 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + entities: + - WallRockSnow + # Ice tiles + - !type:BiomeTileLayer + tile: FloorIce + threshold: -0.9 + noise: + seed: 0 + noiseType: Cellular + frequency: 0.03 + lacunarity: 2 + fractalType: FBm + octaves: 5 + cellularDistanceFunction: Euclidean + cellularReturnType: Distance2 + # Liquid plasma rivers. Ice moon baby + - !type:BiomeEntityLayer + allowedTiles: + - FloorSnow + - FloorIce + threshold: 0.95 + noise: + seed: 3 + noiseType: OpenSimplex2 + frequency: 0.003 + lacunarity: 1.50 + fractalType: Ridged + octaves: 1 + entities: + - FloorLiquidPlasmaEntity + - !type:BiomeDummyLayer + id: Loot + - !type:BiomeTileLayer + threshold: -0.7 + tile: FloorSnow + noise: + seed: 0 + frequency: 0.02 + fractalType: None # Shadow -> Derived from lava -- type: entity - id: BiomeShadow - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: ShadowTerrain - -- type: dungeonConfig - id: ShadowTerrain +- type: biomeTemplate + id: Shadow layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: ShadowTiles - inheritDungeons: All - - !type:PrototypeDunGen - proto: ShadowEntities - inheritDungeons: All - -- type: dungeonConfig - id: ShadowEntities - reserveTiles: true - layers: - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.70 noise: frequency: 1 @@ -558,7 +442,7 @@ - ShadowBasaltThree - ShadowBasaltFour - ShadowBasaltFive - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.97 noise: frequency: 1 @@ -567,7 +451,7 @@ - FloorChromite entities: - CrystalPink - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.97 noise: seed: 1 @@ -578,7 +462,7 @@ entities: - ShadowTree # Rock formations - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: -0.2 invert: true noise: @@ -593,7 +477,7 @@ entities: - WallRockChromite # chasm time - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer allowedTiles: - FloorChromite threshold: 0.2 @@ -606,43 +490,18 @@ gain: 0.4 entities: - FloorChromiteChasm - -- type: dungeonConfig - id: ShadowTiles - returnReserved: false - layers: - # Fill chromite - - !type:SampleTileDunGen - threshold: -1 - tile: FloorChromite + - !type:BiomeDummyLayer + id: Loot + # Fill chromite + - !type:BiomeTileLayer + threshold: -1 + tile: FloorChromite # Caves -- type: entity - id: BiomeCaves - categories: [ HideSpawnMenu ] - components: - - type: Biome - layers: - terrain: - dungeon: CavesTerrain - -- type: dungeonConfig - id: CavesTerrain +- type: biomeTemplate + id: Caves layers: - - !type:ChunkDunGen - - !type:PrototypeDunGen - proto: CavesTiles - inheritDungeons: All - - !type:RoofDunGen - - !type:PrototypeDunGen - proto: CavesEntities - inheritDungeons: All - -- type: dungeonConfig - id: CavesEntities - reserveTiles: true - layers: - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.85 noise: seed: 2 @@ -658,7 +517,7 @@ - CrystalBlue - CrystalYellow - CrystalCyan - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.95 noise: seed: 1 @@ -668,7 +527,7 @@ - FloorAsteroidSand entities: - FloraStalagmite - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: -0.5 invert: true noise: @@ -682,24 +541,17 @@ - FloorAsteroidSand entities: - WallRock - -- type: dungeonConfig - id: CavesTiles - returnReserved: false - layers: - - !type:SampleTileDunGen - threshold: -1.0 - tile: FloorAsteroidSand - -# Asteroid -- type: dungeonConfig - id: Asteroid - layers: - - !type:SampleTileDunGen + - !type:BiomeDummyLayer + id: Loot + - !type:BiomeTileLayer threshold: -1.0 tile: FloorAsteroidSand - reserveTiles: false - - !type:SampleEntityDunGen + +# Asteroid +- type: biomeTemplate + id: Asteroid + layers: + - !type:BiomeEntityLayer threshold: 0.85 noise: seed: 2 @@ -715,7 +567,7 @@ - CrystalBlue - CrystalYellow - CrystalCyan - - !type:SampleEntityDunGen + - !type:BiomeEntityLayer threshold: 0.95 noise: seed: 1 @@ -725,8 +577,7 @@ - FloorAsteroidSand entities: - FloraStalagmite - - !type:SampleEntityDunGen - reserveTiles: false + - !type:BiomeEntityLayer threshold: -0.6 invert: true noise: @@ -740,3 +591,6 @@ - FloorAsteroidSand entities: - AsteroidRock + - !type:BiomeTileLayer + threshold: -1.0 + tile: FloorAsteroidSand diff --git a/Resources/Prototypes/Procedural/dungeon_configs.yml b/Resources/Prototypes/Procedural/dungeon_configs.yml index 18d50ec6cd..5da9592995 100644 --- a/Resources/Prototypes/Procedural/dungeon_configs.yml +++ b/Resources/Prototypes/Procedural/dungeon_configs.yml @@ -79,9 +79,6 @@ id: Haunted layers: - !type:PrefabDunGen - roomWhitelist: - tags: - - Haunted presets: - Bucket - Wow diff --git a/Resources/Prototypes/Procedural/salvage_loot.yml b/Resources/Prototypes/Procedural/salvage_loot.yml index 289fa5fd57..cf23601978 100644 --- a/Resources/Prototypes/Procedural/salvage_loot.yml +++ b/Resources/Prototypes/Procedural/salvage_loot.yml @@ -3,108 +3,108 @@ - type: salvageLoot id: SalvageLoot loots: - - !type:RandomSpawnsLoot - entries: - - proto: AdvMopItem - prob: 0.5 - - proto: AmmoTechFabCircuitboard - cost: 2 - - proto: AutolatheMachineCircuitboard - cost: 2 - - proto: BiomassReclaimerMachineCircuitboard - cost: 2 - - proto: BluespaceBeaker - cost: 2 - - proto: CyborgEndoskeleton - cost: 3 - prob: 0.5 - - proto: ChemDispenserMachineCircuitboard - cost: 2 - - proto: CircuitImprinter - cost: 2 - - proto: CloningConsoleComputerCircuitboard - cost: 2 - - proto: CloningPodMachineCircuitboard - cost: 2 - - proto: ChemistryBottleCognizine - - proto: FoodBoxDonkpocketCarp - prob: 0.5 - - proto: CrateSalvageEquipment - cost: 3 - prob: 0.5 - - proto: GasRecycler - cost: 2 - - proto: GeneratorRTG - cost: 5 - - proto: GravityGeneratorMini - cost: 2 - - proto: GyroscopeUnanchored - cost: 2 - prob: 0.1 - - proto: MedicalScannerMachineCircuitboard - cost: 2 - - proto: NuclearBombKeg - cost: 5 - - proto: ChemistryBottleOmnizine - prob: 0.5 - - proto: PortableGeneratorPacman - cost: 2 - - proto: PortableGeneratorSuperPacman - cost: 3 - - proto: PowerCellAntiqueProto - cost: 5 - prob: 0.5 - - proto: ProtolatheMachineCircuitboard - - proto: RandomArtifactSpawner - cost: 2 - - proto: RandomCargoCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomCommandCorpseSpawner - cost: 5 - prob: 0.5 - - proto: RandomEngineerCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomMedicCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomScienceCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomSecurityCorpseSpawner - cost: 2 - prob: 0.5 - - proto: RandomServiceCorpseSpawner - cost: 2 - prob: 0.5 - - proto: ResearchAndDevelopmentServerMachineCircuitboard - cost: 5 - prob: 0.5 - - proto: ResearchDisk10000 - prob: 0.5 - - proto: ResearchDisk5000 - prob: 0.5 - - proto: RipleyHarness - cost: 3 - prob: 0.5 - - proto: SpaceCash1000 - - proto: SpaceCash10000 - cost: 10 - - proto: SpaceCash2500 - cost: 3 - - proto: SpaceCash5000 - cost: 5 - - proto: TechnologyDiskRare - cost: 5 - prob: 0.5 - - proto: ThrusterUnanchored - - proto: WaterTankHighCapacity - - proto: WeldingFuelTankHighCapacity - cost: 3 - - proto: WeaponTeslaGun - prob: 0.1 - cost: 2 + - !type:RandomSpawnsLoot + entries: + - proto: AdvMopItem + prob: 0.5 + - proto: AmmoTechFabCircuitboard + cost: 2 + - proto: AutolatheMachineCircuitboard + cost: 2 + - proto: BiomassReclaimerMachineCircuitboard + cost: 2 + - proto: BluespaceBeaker + cost: 2 + - proto: CyborgEndoskeleton + cost: 3 + prob: 0.5 + - proto: ChemDispenserMachineCircuitboard + cost: 2 + - proto: CircuitImprinter + cost: 2 + - proto: CloningConsoleComputerCircuitboard + cost: 2 + - proto: CloningPodMachineCircuitboard + cost: 2 + - proto: ChemistryBottleCognizine + - proto: FoodBoxDonkpocketCarp + prob: 0.5 + - proto: CrateSalvageEquipment + cost: 3 + prob: 0.5 + - proto: GasRecycler + cost: 2 + - proto: GeneratorRTG + cost: 5 + - proto: GravityGeneratorMini + cost: 2 + - proto: GyroscopeUnanchored + cost: 2 + prob: 0.1 + - proto: MedicalScannerMachineCircuitboard + cost: 2 + - proto: NuclearBombKeg + cost: 5 + - proto: ChemistryBottleOmnizine + prob: 0.5 + - proto: PortableGeneratorPacman + cost: 2 + - proto: PortableGeneratorSuperPacman + cost: 3 + - proto: PowerCellAntiqueProto + cost: 5 + prob: 0.5 + - proto: ProtolatheMachineCircuitboard + - proto: RandomArtifactSpawner + cost: 2 + - proto: RandomCargoCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomCommandCorpseSpawner + cost: 5 + prob: 0.5 + - proto: RandomEngineerCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomMedicCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomScienceCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomSecurityCorpseSpawner + cost: 2 + prob: 0.5 + - proto: RandomServiceCorpseSpawner + cost: 2 + prob: 0.5 + - proto: ResearchAndDevelopmentServerMachineCircuitboard + cost: 5 + prob: 0.5 + - proto: ResearchDisk10000 + prob: 0.5 + - proto: ResearchDisk5000 + prob: 0.5 + - proto: RipleyHarness + cost: 3 + prob: 0.5 + - proto: SpaceCash1000 + - proto: SpaceCash10000 + cost: 10 + - proto: SpaceCash2500 + cost: 3 + - proto: SpaceCash5000 + cost: 5 + - proto: TechnologyDiskRare + cost: 5 + prob: 0.5 + - proto: ThrusterUnanchored + - proto: WaterTankHighCapacity + - proto: WeldingFuelTankHighCapacity + cost: 3 + - proto: WeaponTeslaGun + prob: 0.1 + cost: 2 # Mob loot table @@ -117,70 +117,70 @@ id: OreIron guaranteed: true loots: - - !type:BiomeLoot - proto: OreIron + - !type:BiomeMarkerLoot + proto: OreIron - type: salvageLoot id: OreCoal guaranteed: true loots: - - !type:BiomeLoot - proto: OreCoal + - !type:BiomeMarkerLoot + proto: OreCoal - type: salvageLoot id: OreQuartz guaranteed: true loots: - - !type:BiomeLoot - proto: OreQuartz + - !type:BiomeMarkerLoot + proto: OreQuartz - type: salvageLoot id: OreSalt guaranteed: true loots: - - !type:BiomeLoot - proto: OreSalt + - !type:BiomeMarkerLoot + proto: OreSalt # - Medium value - type: salvageLoot id: OreGold guaranteed: true loots: - - !type:BiomeLoot - proto: OreGold + - !type:BiomeMarkerLoot + proto: OreGold - type: salvageLoot id: OreSilver guaranteed: true loots: - - !type:BiomeLoot - proto: OreSilver + - !type:BiomeMarkerLoot + proto: OreSilver # - High value - type: salvageLoot id: OrePlasma guaranteed: true loots: - - !type:BiomeLoot - proto: OrePlasma + - !type:BiomeMarkerLoot + proto: OrePlasma - type: salvageLoot id: OreUranium guaranteed: true loots: - - !type:BiomeLoot - proto: OreUranium + - !type:BiomeMarkerLoot + proto: OreUranium - type: salvageLoot id: OreDiamond guaranteed: true loots: - - !type:BiomeLoot - proto: OreDiamond + - !type:BiomeMarkerLoot + proto: OreDiamond - type: salvageLoot id: OreArtifactFragment guaranteed: true loots: - - !type:BiomeLoot - proto: OreArtifactFragment + - !type:BiomeMarkerLoot + proto: OreArtifactFragment diff --git a/Resources/Prototypes/Procedural/salvage_mods.yml b/Resources/Prototypes/Procedural/salvage_mods.yml index e8b18dd14a..ca64d29a52 100644 --- a/Resources/Prototypes/Procedural/salvage_mods.yml +++ b/Resources/Prototypes/Procedural/salvage_mods.yml @@ -8,24 +8,24 @@ - type: salvageBiomeMod id: Caves desc: salvage-biome-mod-caves - biome: BiomeCaves + biome: Caves - type: salvageBiomeMod id: Grasslands desc: salvage-biome-mod-grasslands - biome: BiomeGrasslands + biome: Grasslands - type: salvageBiomeMod id: Snow desc: salvage-biome-mod-snow cost: 1 - biome: BiomeSnow + biome: Snow - type: salvageBiomeMod id: Lava desc: salvage-biome-mod-lava cost: 2 - biome: BiomeLava + biome: Lava #- type: salvageBiomeMod # id: Space diff --git a/Resources/Prototypes/Procedural/vgroid.yml b/Resources/Prototypes/Procedural/vgroid.yml index ad759721cb..0caa9f0e1f 100644 --- a/Resources/Prototypes/Procedural/vgroid.yml +++ b/Resources/Prototypes/Procedural/vgroid.yml @@ -117,8 +117,8 @@ - type: dungeonConfig id: VGRoidSmaller - minOffset: 60 - maxOffset: 80 + minOffset: 40 + maxOffset: 60 layers: - !type:NoiseDistanceDunGen size: 150, 150 @@ -151,7 +151,6 @@ maxCount: 3 layers: - !type:ExteriorDunGen - penetration: 5,15 proto: Experiment - !type:EntityTableDunGen minCount: 25 @@ -229,16 +228,5 @@ layers: - !type:FillGridDunGen entity: IronRock - threshold: -0.95 - size: 350, 350 - distanceConfig: !type:DunGenEuclideanSquaredDistance - blendWeight: -0.50 - reservedNoise: - frequency: 0.080 - noiseType: OpenSimplex2 - fractalType: FBm - octaves: 5 - lacunarity: 1.5 - gain: 0.5 allowedTiles: - FloorAsteroidSand From 44617ae841a98ff50700ce3f3c04b264f020a655 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Thu, 3 Jul 2025 20:51:40 +0200 Subject: [PATCH 038/105] Exo - Minor balance changes and fixes (#38689) --- Resources/Maps/Shuttles/emergency_exo.yml | 38 +- Resources/Maps/exo.yml | 2784 +++++++++++------ .../Prototypes/Entities/Mobs/NPCs/xeno.yml | 4 +- .../Structures/Furniture/Tables/tables.yml | 3 + .../Structures/Machines/Medical/cryo_pod.yml | 9 +- Resources/Prototypes/Maps/exo.yml | 8 +- .../Construction/Graphs/furniture/tables.yml | 12 + 7 files changed, 1898 insertions(+), 960 deletions(-) diff --git a/Resources/Maps/Shuttles/emergency_exo.yml b/Resources/Maps/Shuttles/emergency_exo.yml index ed5b16861d..d3c34c6dc5 100644 --- a/Resources/Maps/Shuttles/emergency_exo.yml +++ b/Resources/Maps/Shuttles/emergency_exo.yml @@ -4,8 +4,8 @@ meta: engineVersion: 262.0.0 forkId: "" forkVersion: "" - time: 06/16/2025 11:37:57 - entityCount: 1017 + time: 07/01/2025 12:52:53 + entityCount: 1020 maps: [] grids: - 2 @@ -398,7 +398,7 @@ entities: 2,-2: 0: 7644 2,-3: - 0: 3584 + 2: 3584 3,-2: 0: 40951 3,-3: @@ -448,6 +448,21 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 1400.0662 + - 5266.916 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance @@ -923,6 +938,23 @@ entities: rot: 1.5707963267948966 rad pos: 17.5,1.5 parent: 2 +- proto: AtmosFixAirMarker + entities: + - uid: 1018 + components: + - type: Transform + pos: 9.5,-9.5 + parent: 2 + - uid: 1019 + components: + - type: Transform + pos: 10.5,-9.5 + parent: 2 + - uid: 1020 + components: + - type: Transform + pos: 11.5,-9.5 + parent: 2 - proto: BaseComputer entities: - uid: 639 diff --git a/Resources/Maps/exo.yml b/Resources/Maps/exo.yml index 39f16e1213..5ce2d601a4 100644 --- a/Resources/Maps/exo.yml +++ b/Resources/Maps/exo.yml @@ -1,11 +1,11 @@ meta: format: 7 category: Map - engineVersion: 262.0.0 + engineVersion: 264.0.0 forkId: "" forkVersion: "" - time: 06/19/2025 00:17:06 - entityCount: 19539 + time: 07/03/2025 16:09:47 + entityCount: 19679 maps: - 1 grids: @@ -132,11 +132,11 @@ entities: version: 7 0,-3: ind: 0,-3 - tiles: IAAAAAACAAMAAAAAAAADAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAAIAAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAAAACUAAAAAAAAlAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAcAAAAAAAADAAAAAAAAAwAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAABcAAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAAAXAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADgQAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAFwAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAAAYAAAAAAAAJAAAAAACABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAAAtAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAAAAAAAAAAAAgQAAAAAAAC0AAAAAAAAlAAAAAAIALQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAIEAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAABcAAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAKwAAAAAABy4AAAAAAAEYAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADKwAAAAACACsAAAAAAgArAAAAAAIAKwAAAAADACUAAAAAAAArAAAAAAIAGAAAAAAAACsAAAAAAAArAAAAAAEAKwAAAAADACsAAAAAAAArAAAAAAEAKwAAAAAAACsAAAAAAAArAAAAAAEAKwAAAAAAAC4AAAAAAAItAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAxgAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAG8AAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAABgAAAAAAMAYAAAAAAAAA== + tiles: IAAAAAACAAMAAAAAAAADAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAAIAAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAAAACUAAAAAAAAlAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAcAAAAAAAADAAAAAAAAAwAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAXAAAAAAAALgAAAAAAAi0AAAAAAAOBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAi4AAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAAAXAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADgQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAFwAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAAAYAAAAAAAAJAAAAAACABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAAAtAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAAAAAAAAAAAAgQAAAAAAAC0AAAAAAAAlAAAAAAIALQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAIEAAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAS4AAAAAAAOBAAAAAAAAgQAAAAAAABcAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABcAAAAAAAAuAAAAAAABLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAKwAAAAAABy4AAAAAAAEYAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADKwAAAAACACsAAAAAAgArAAAAAAIAKwAAAAADACUAAAAAAAArAAAAAAIAGAAAAAAAACsAAAAAAAArAAAAAAEAKwAAAAADACsAAAAAAAArAAAAAAEAKwAAAAAAACsAAAAAAAArAAAAAAEAKwAAAAAAAC4AAAAAAAItAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAxgAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAG8AAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAABgAAAAAAMAYAAAAAAAAA== version: 7 1,-3: ind: 1,-3 - tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAAYAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAJQAAAAAAACUAAAAAAwAlAAAAAAEAJQAAAAADACUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAFwAAAAAAAAAAAAAAAACBAAAAAAAAIAAAAAABACsAAAAAAQAgAAAAAAIAgQAAAAAAACUAAAAAAwAlAAAAAAMAJQAAAAABACUAAAAAAQAlAAAAAAIAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAABgAAAAAAAAlAAAAAAEAJQAAAAABACUAAAAAAQAlAAAAAAIAJQAAAAAAAC4AAAAAAAItAAAAAAADLgAAAAAAA4EAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAAAYAAAAAAAAJQAAAAABACUAAAAAAgAlAAAAAAEAJQAAAAACACUAAAAAAAAtAAAAAAAABAAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAACACUAAAAAAQAlAAAAAAAALgAAAAAAAS0AAAAAAAMuAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAAAlAAAAAAMAJQAAAAABACUAAAAAAAAlAAAAAAIAJQAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAJQAAAAADACUAAAAAAwAlAAAAAAMAJQAAAAABACUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAFwAAAAAAAAAAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAEAJQAAAAAAACUAAAAAAAAlAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAQAAAAAAMAEAAAAAABABAAAAAAAwAQAAAAAAEAJQAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAEAAAAAACABAAAAAAAAAQAAAAAAAAEAAAAAADACUAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMYAAAAAAAALgAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAKwAAAAACACsAAAAAAgArAAAAAAEAKwAAAAAAACsAAAAAAAArAAAAAAAAGAAAAAAAACsAAAAAAQAlAAAAAAEALQAAAAAAAC0AAAAAAACBAAAAAAAALwAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAxgAAAAAAAAuAAAAAAADKwAAAAAABy0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAOBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAeAAAAAAAAYAAAAAADAGAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAA== + tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAAYAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAADFwAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAJQAAAAAAACUAAAAAAwAlAAAAAAEAJQAAAAADACUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAS4AAAAAAAOBAAAAAAAAIAAAAAABACsAAAAAAQAgAAAAAAIAgQAAAAAAACUAAAAAAwAlAAAAAAMAJQAAAAABACUAAAAAAQAlAAAAAAIAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAABgAAAAAAAAlAAAAAAEAJQAAAAABACUAAAAAAQAlAAAAAAIAJQAAAAAAAC4AAAAAAAItAAAAAAADLgAAAAAAA4EAAAAAAACBAAAAAAAALQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAAAYAAAAAAAAJQAAAAABACUAAAAAAgAlAAAAAAEAJQAAAAACACUAAAAAAAAtAAAAAAAABAAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAACACUAAAAAAQAlAAAAAAAALgAAAAAAAS0AAAAAAAMuAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAAAlAAAAAAMAJQAAAAABACUAAAAAAAAlAAAAAAIAJQAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAJQAAAAADACUAAAAAAwAlAAAAAAMAJQAAAAABACUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALgAAAAAAAi4AAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAEAJQAAAAAAACUAAAAAAAAlAAAAAAIALQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy4AAAAAAAAXAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAQAAAAAAMAEAAAAAABABAAAAAAAwAQAAAAAAEAJQAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAEAAAAAACABAAAAAAAAAQAAAAAAAAEAAAAAADACUAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMYAAAAAAAALgAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAKwAAAAACACsAAAAAAgArAAAAAAEAKwAAAAAAACsAAAAAAAArAAAAAAAAGAAAAAAAACsAAAAAAQAlAAAAAAEALQAAAAAAAC0AAAAAAACBAAAAAAAALwAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAxgAAAAAAAAuAAAAAAADKwAAAAAABy0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAADLQAAAAAAAy0AAAAAAAOBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAALQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAeAAAAAAAAYAAAAAADAGAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAA== version: 7 -1,-3: ind: -1,-3 @@ -144,7 +144,7 @@ entities: version: 7 -2,-2: ind: -2,-2 - tiles: gQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAIAAAAAABAAEAAAAAAwAYAAAAAAAAAAAAAAAAAIEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAACAAAAAAAwABAAAAAAIAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAAYAAAAAAQAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAAAgAAAAAAMAAQAAAAACABgAAAAAAAAmAAAAAAIAJgAAAAABABgAAAAAAAAGAAAAAAIAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAABgAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAgAAAAAAEALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAADAAYAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAwCBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAACAAAAAAAAAgAAAAAAAALgAAAAAAAi0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy4AAAAAAAMgAAAAAAAALgAAAAAAA4EAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAIAAAAAACAC4AAAAAAAEtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAIAAAAAAAAC4AAAAAAAAYAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwAgAAAAAAMAIAAAAAACACAAAAAAAQAuAAAAAAADGAAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAALQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAACBAAAAAAAARAAAAAAAAEQAAAAAAAAYAAAAAAAARAAAAAAAAC0AAAAAAAAYAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAC4AAAAAAAItAAAAAAADLQAAAAAAAy4AAAAAAAMuAAAAAAAAGAAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAABgAAAAAAAAtAAAAAAAAGAAAAAAAABgAAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAACBAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAALQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGAAAAAAAAEQAAAAAAACBAAAAAAAAIAAAAAADAC0AAAAAAAArAAAAAAAHLQAAAAAAAC0AAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAABEAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAAAtAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAEAAAAAAAAGAAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAA== + tiles: gQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAIAAAAAABAAEAAAAAAwAYAAAAAAAAAAAAAAAAAIEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAACAAAAAAAwABAAAAAAIAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAAYAAAAAAQAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAAAgAAAAAAMAAQAAAAACAAEAAAAAAAAmAAAAAAIAJgAAAAABABgAAAAAAAAGAAAAAAIAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAABgAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAgAAAAAAEALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAADAAYAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAwCBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAACAAAAAAAAAgAAAAAAAALgAAAAAAAi0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy4AAAAAAAMgAAAAAAAALgAAAAAAA4EAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAIAAAAAACAC4AAAAAAAEtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAIAAAAAAAAC4AAAAAAAAYAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwAgAAAAAAMAIAAAAAACACAAAAAAAQAuAAAAAAADGAAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAALQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAACBAAAAAAAARAAAAAAAAEQAAAAAAAAYAAAAAAAARAAAAAAAAC0AAAAAAAAYAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAC4AAAAAAAItAAAAAAADLQAAAAAAAy4AAAAAAAMuAAAAAAAAGAAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAALQAAAAAAABgAAAAAAAAtAAAAAAAAGAAAAAAAABgAAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAAC0AAAAAAACBAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAA4EAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAALQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGAAAAAAAAEQAAAAAAACBAAAAAAAAIAAAAAADAC0AAAAAAAArAAAAAAAHLQAAAAAAAC0AAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAABEAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAAAtAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAAAEAAAAAAAAGAAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAA== version: 7 -2,-1: ind: -2,-1 @@ -164,11 +164,11 @@ entities: version: 7 -1,-4: ind: -1,-4 - tiles: gQAAAAAAABsAAAAAAAAbAAAAAAAAGwAAAAAAABsAAAAAAACBAAAAAAAAIAAAAAABACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwAgAAAAAAMAIAAAAAADACAAAAAAAQAgAAAAAAIAIAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAADACAAAAAAAgAgAAAAAAEAIAAAAAACACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwBgAAAAAAMAYAAAAAACAGAAAAAAAgBgAAAAAAMAYAAAAAABAIEAAAAAAAAgAAAAAAAAIAAAAAACACAAAAAAAwAgAAAAAAIAIAAAAAADACAAAAAAAAAgAAAAAAIAIAAAAAACACAAAAAAAQAgAAAAAAMAYAAAAAACAGAAAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAQCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAEAYAAAAAADAGAAAAAAAwBgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAcAAAAAAAAgAAAAAAEABwAAAAAAAAcAAAAAAAAHAAAAAAAAIAAAAAACAC0AAAAAAAMuAAAAAAADLgAAAAAAASAAAAAAAQCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAHAAAAAAAAIAAAAAACACAAAAAAAQAgAAAAAAEAIAAAAAAAACAAAAAAAwAlAAAAAAIALgAAAAAAAS4AAAAAAAOBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAABwAAAAAAACAAAAAAAgAgAAAAAAMABwAAAAAAAAcAAAAAAAAHAAAAAAAAJQAAAAACACUAAAAAAwAuAAAAAAABLgAAAAAAA4EAAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAgQAAAAAAAAcAAAAAAAAgAAAAAAEAIAAAAAAAACAAAAAAAwAgAAAAAAAAIAAAAAABAC4AAAAAAAMlAAAAAAIAJQAAAAAAACAAAAAAAQBvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAADACAAAAAAAAAgAAAAAAMAIAAAAAACACAAAAAAAQAuAAAAAAABLgAAAAAAAyUAAAAAAwAgAAAAAAEAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAIAAAAAAAAIEAAAAAAAAgAAAAAAIAgQAAAAAAAC0AAAAAAAArAAAAAAAHIAAAAAABAG8AAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAgQAAAAAAACAAAAAAAQAgAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAIAAAAAACAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAIEAAAAAAAAHAAAAAAAABwAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAgCBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAG8AAAAAAAAFAAAAAAAABQAAAAAAAAUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAADAIEAAAAAAAAgAAAAAAEAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAACAAAAAAAABvAAAAAAAABQAAAAAAAAUAAAAAAAAFAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAACACAAAAAAAAAgAAAAAAIAIAAAAAABAA== + tiles: gQAAAAAAABsAAAAAAAAbAAAAAAAAGwAAAAAAABsAAAAAAACBAAAAAAAAIAAAAAABACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwAgAAAAAAMAIAAAAAADACAAAAAAAQAgAAAAAAIAIAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAADACAAAAAAAgAgAAAAAAEAIAAAAAACACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwBgAAAAAAMAYAAAAAACAGAAAAAAAgBgAAAAAAMAYAAAAAABAIEAAAAAAAAgAAAAAAAAIAAAAAACACAAAAAAAwAgAAAAAAIAIAAAAAADACAAAAAAAAAgAAAAAAIAIAAAAAACACAAAAAAAQAgAAAAAAMAYAAAAAACAGAAAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAQCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAEAYAAAAAADAGAAAAAAAwBgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAcAAAAAAAAgAAAAAAEABwAAAAAAAAcAAAAAAAAHAAAAAAAAIAAAAAACAC0AAAAAAAMuAAAAAAADLwAAAAAAAC8AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAHAAAAAAAAIAAAAAACACAAAAAAAQAgAAAAAAEAIAAAAAAAACAAAAAAAwAlAAAAAAIALgAAAAAAAS4AAAAAAAMvAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAABwAAAAAAACAAAAAAAgAgAAAAAAMABwAAAAAAAAcAAAAAAAAHAAAAAAAAJQAAAAACACUAAAAAAwAuAAAAAAABLgAAAAAAA4EAAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAgQAAAAAAAAcAAAAAAAAgAAAAAAEAIAAAAAAAACAAAAAAAwAgAAAAAAAAIAAAAAABAC4AAAAAAAMlAAAAAAIAJQAAAAAAACAAAAAAAQBvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAADACAAAAAAAAAgAAAAAAMAIAAAAAACACAAAAAAAQAuAAAAAAABLgAAAAAAAyUAAAAAAwAgAAAAAAEAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAIAAAAAAAAIEAAAAAAAAgAAAAAAIAgQAAAAAAAC0AAAAAAAArAAAAAAAHIAAAAAABAG8AAAAAAABvAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAgQAAAAAAACAAAAAAAQAgAAAAAAAAgQAAAAAAACAAAAAAAwCBAAAAAAAAIAAAAAACAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAbwAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAIEAAAAAAAAHAAAAAAAABwAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAgCBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAG8AAAAAAAAFAAAAAAAABQAAAAAAAAUAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAIAAAAAADAIEAAAAAAAAgAAAAAAEAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAACAAAAAAAABvAAAAAAAABQAAAAAAAAUAAAAAAAAFAAAAAAAAgQAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAACACAAAAAAAAAgAAAAAAIAIAAAAAABAA== version: 7 0,-5: ind: 0,-5 - tiles: LwAAAAAAAIEAAAAAAAAbAAAAAAAAGwAAAAAAABsAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAuAAAAAAACLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy8AAAAAAACBAAAAAAAAGwAAAAAAACkAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACUAAAAAAAArAAAAAAMAKwAAAAAAACsAAAAAAAArAAAAAAAAJQAAAAACACsAAAAAAgAvAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACkAAAAAAQCBAAAAAAAAgQAAAAAAAC4AAAAAAAEtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLgAAAAAAAysAAAAAAAcuAAAAAAACgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAABsAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAMAKQAAAAABAIEAAAAAAACBAAAAAAAAJQAAAAADACUAAAAAAwAlAAAAAAIAJQAAAAACAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAEAgQAAAAAAACkAAAAAAgCBAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAIAJQAAAAAAAIEAAAAAAAAuAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAKQAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAuAAAAAAACLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy4AAAAAAAArAAAAAAAHLQAAAAAAABsAAAAAAACBAAAAAAAAKQAAAAABACkAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACUAAAAAAAArAAAAAAMAKwAAAAABACsAAAAAAAArAAAAAAIAJQAAAAADAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLgAAAAAAAi0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAALQAAAAAAAy0AAAAAAAMuAAAAAAADgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAgBgAAAAAAIAYAAAAAAAAC0AAAAAAAMuAAAAAAADLQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAAAAGAAAAAAAwAgAAAAAAEALQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAgCBAAAAAAAAIAAAAAADAC0AAAAAAAAuAAAAAAABLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAJAAAAAADACQAAAAAAAAgAAAAAAIAJAAAAAADACAAAAAAAwAtAAAAAAAAJQAAAAADACsAAAAAAgArAAAAAAAAKwAAAAACACsAAAAAAwArAAAAAAEAKwAAAAADACUAAAAAAgAtAAAAAAAAIAAAAAABACAAAAAAAgAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAMALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLgAAAAAAAIEAAAAAAAAKAAAAAAAACgAAAAAAACAAAAAAAwAgAAAAAAEAgQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAA== + tiles: LwAAAAAAAIEAAAAAAAAbAAAAAAAAGwAAAAAAABsAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAuAAAAAAACLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy8AAAAAAACBAAAAAAAAGwAAAAAAACkAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACUAAAAAAAArAAAAAAMAKwAAAAAAACsAAAAAAAArAAAAAAAAJQAAAAACACsAAAAAAgAvAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACkAAAAAAQCBAAAAAAAAgQAAAAAAAC4AAAAAAAEtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLgAAAAAAAysAAAAAAAcuAAAAAAACgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAABsAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAJQAAAAADACUAAAAAAwAlAAAAAAIAJQAAAAACAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAEAgQAAAAAAACkAAAAAAACBAAAAAAAAgQAAAAAAACUAAAAAAwAlAAAAAAIAJQAAAAAAAIEAAAAAAAAuAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAKQAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAuAAAAAAACLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy4AAAAAAAArAAAAAAAHLQAAAAAAABsAAAAAAACBAAAAAAAAKQAAAAABACkAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACUAAAAAAAArAAAAAAMAKwAAAAABACsAAAAAAAArAAAAAAIAJQAAAAADAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAApAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLgAAAAAAAi0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAALQAAAAAAAy0AAAAAAAMuAAAAAAADgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAgBgAAAAAAIAYAAAAAAAAC0AAAAAAAMuAAAAAAADLQAAAAAAAC0AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAALQAAAAAAACsAAAAAAActAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAAAAGAAAAAAAwAgAAAAAAEALQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAC0AAAAAAAArAAAAAAAHLQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAgCBAAAAAAAAIAAAAAADAC0AAAAAAAAuAAAAAAABLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAAKwAAAAAABy0AAAAAAACBAAAAAAAAJAAAAAADACQAAAAAAAAgAAAAAAIAJAAAAAADACAAAAAAAwAtAAAAAAAAJQAAAAADACsAAAAAAgArAAAAAAAAKwAAAAACACsAAAAAAwArAAAAAAEAKwAAAAADACUAAAAAAgAtAAAAAAAAIAAAAAABACAAAAAAAgAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAMALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLgAAAAAAAIEAAAAAAAAKAAAAAAAACgAAAAAAACAAAAAAAwAgAAAAAAEAgQAAAAAAAC0AAAAAAAAtAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAA== version: 7 -2,-4: ind: -2,-4 @@ -312,7 +312,7 @@ entities: version: 7 3,-3: ind: 3,-3 - tiles: gQAAAAAAAB4AAAAAAACBAAAAAAAAgQAAAAAAAB4AAAAAAAAeAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAMAYAAAAAABAIEAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAIAYAAAAAACAGAAAAAAAgCBAAAAAAAAYAAAAAAAAGAAAAAAAwAlAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAAAYAAAAAACAGAAAAAAAgBgAAAAAAIAgQAAAAAAAGAAAAAAAwBgAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAgBgAAAAAAAAYAAAAAAAAIEAAAAAAABgAAAAAAAAYAAAAAAAACUAAAAAAwCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAGAAAAAAAgAlAAAAAAEAgQAAAAAAAC8AAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAABAGAAAAAAAQBgAAAAAAIAYAAAAAAAAGAAAAAAAQBgAAAAAAMAJQAAAAABAIEAAAAAAAAvAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAARAAAAAAAAGAAAAAAAQBgAAAAAAIAYAAAAAABAGAAAAAAAQBgAAAAAAAAYAAAAAAAACUAAAAAAwCBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAgCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAABAGAAAAAAAABgAAAAAAIAgQAAAAAAAGAAAAAAAABgAAAAAAMAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAACAGAAAAAAAABgAAAAAAAAYAAAAAABAGAAAAAAAwBgAAAAAAAAYAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAACAGAAAAAAAQBgAAAAAAIAYAAAAAACAGAAAAAAAwCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAAAAGAAAAAAAABgAAAAAAMAgQAAAAAAAGAAAAAAAwBgAAAAAAEAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAbwAAAAAAAGAAAAAAAgBgAAAAAAIAbwAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAABAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAAAYAAAAAADAG8AAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAQAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAwCBAAAAAAAAgQAAAAAAAGAAAAAAAABgAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAGQAAAAACABkAAAAAAAAZAAAAAAIAGQAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAABAA== + tiles: gQAAAAAAAB4AAAAAAACBAAAAAAAAgQAAAAAAAB4AAAAAAAAeAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAMAYAAAAAABAIEAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAIAYAAAAAACAGAAAAAAAgCBAAAAAAAAYAAAAAAAAGAAAAAAAwAlAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAAAYAAAAAACAGAAAAAAAgBgAAAAAAIAgQAAAAAAAGAAAAAAAwBgAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAgBgAAAAAAAAYAAAAAAAAIEAAAAAAABgAAAAAAAAYAAAAAAAACUAAAAAAwCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAGAAAAAAAgAlAAAAAAEAgQAAAAAAAC8AAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAABAGAAAAAAAQBgAAAAAAIAYAAAAAAAAGAAAAAAAQBgAAAAAAMAJQAAAAABAIEAAAAAAAAvAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAARAAAAAAAAGAAAAAAAQBgAAAAAAIAYAAAAAABAGAAAAAAAQBgAAAAAAAAYAAAAAAAACUAAAAAAwCBAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAgCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAABAGAAAAAAAABgAAAAAAIAgQAAAAAAAGAAAAAAAABgAAAAAAMAgQAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAACAGAAAAAAAABgAAAAAAAAYAAAAAABAGAAAAAAAwBgAAAAAAAAYAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAACAGAAAAAAAQBgAAAAAAIAYAAAAAACAGAAAAAAAwCBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAAAAGAAAAAAAABgAAAAAAMAgQAAAAAAAGAAAAAAAwBgAAAAAAEAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAbwAAAAAAAGAAAAAAAgBgAAAAAAIAbwAAAAAAAIEAAAAAAABgAAAAAAIAYAAAAAABAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAAAYAAAAAADAG8AAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAQAYAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAwCBAAAAAAAAgQAAAAAAAGAAAAAAAABgAAAAAAEAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAACBAAAAAAAAGQAAAAACABkAAAAAAAAZAAAAAAIAGQAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAABAA== version: 7 4,-2: ind: 4,-2 @@ -320,7 +320,7 @@ entities: version: 7 3,-2: ind: 3,-2 - tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGQAAAAABABkAAAAAAAAZAAAAAAMAGQAAAAACAIEAAAAAAABgAAAAAAIAYAAAAAADAC8AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAvAAAAAAAALwAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAwAvAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAADAGAAAAAAAgBgAAAAAAMAYAAAAAACAGAAAAAAAQBgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAABgAAAAAAEAYAAAAAABABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAEAYAAAAAACAGAAAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAwCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAAAAGAAAAAAAABgAAAAAAIAgQAAAAAAAIEAAAAAAABHAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAABLwAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAABLQAAAAAAAS8AAAAAAAAuAAAAAAABLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAS0AAAAAAAEvAAAAAAAAIAAAAAACACAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAgAgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAARwAAAAAAACUAAAAAAAAlAAAAAAMAJQAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAAAACUAAAAAAgAlAAAAAAAAJQAAAAABACUAAAAAAwAlAAAAAAMARwAAAAAAAIEAAAAAAABHAAAAAAAAIAAAAAADACUAAAAAAABgAAAAAAAAYAAAAAACAGAAAAAAAgBgAAAAAAAAYAAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAAAAGAAAAAAAQCBAAAAAAAAIAAAAAABACAAAAAAAwAgAAAAAAMAIAAAAAADACAAAAAAAwAlAAAAAAMAIgAAAAADACIAAAAAAQAiAAAAAAMAIgAAAAADACQAAAAAAgAiAAAAAAMAIgAAAAACACIAAAAAAgBgAAAAAAEAIAAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAADACAAAAAAAgCBAAAAAAAARwAAAAAAAGAAAAAAAgBgAAAAAAIAYAAAAAABAGAAAAAAAwBgAAAAAAMAYAAAAAADAGAAAAAAAgAiAAAAAAEAYAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACUAAAAAAwAfAAAAAAIAgQAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAIEAAAAAAABgAAAAAAAAIgAAAAAAAGAAAAAAAABHAAAAAAAAJQAAAAAAACUAAAAAAwAlAAAAAAIAJQAAAAABACUAAAAAAwAlAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQAiAAAAAAMAIgAAAAAAACIAAAAAAQBgAAAAAAEAgQAAAAAAACQAAAAAAgAlAAAAAAAAJQAAAAAAACUAAAAAAQAlAAAAAAMAJQAAAAABAA== + tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAGQAAAAABABkAAAAAAAAZAAAAAAMAGQAAAAACAIEAAAAAAABgAAAAAAIAYAAAAAADAC8AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAvAAAAAAAALwAAAAAAAIEAAAAAAAAYAAAAAAAAgQAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAwAvAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAAgQAAAAAAAC8AAAAAAACBAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAMAYAAAAAADAGAAAAAAAgBgAAAAAAMAYAAAAAACAGAAAAAAAQBgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAABgAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAADAIEAAAAAAABgAAAAAAEAYAAAAAABABgAAAAAAAAYAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAABgAAAAAAAAYAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAEAYAAAAAACAGAAAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAwCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAAAIEAAAAAAABgAAAAAAEAYAAAAAAAAGAAAAAAAABgAAAAAAIAgQAAAAAAAIEAAAAAAABHAAAAAAAALQAAAAAAAy0AAAAAAAMtAAAAAAADgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAtAAAAAAABLwAAAAAAAC0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAABLQAAAAAAAS8AAAAAAAAuAAAAAAABLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMuAAAAAAAALgAAAAAAAS0AAAAAAAMtAAAAAAADLQAAAAAAAy0AAAAAAAMtAAAAAAADLQAAAAAAAS0AAAAAAAEvAAAAAAAAIAAAAAACACAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAgAgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAARwAAAAAAACUAAAAAAAAlAAAAAAMAJQAAAAAAACUAAAAAAwAlAAAAAAAAJQAAAAAAACUAAAAAAgAlAAAAAAAAJQAAAAABACUAAAAAAwAlAAAAAAMARwAAAAAAAIEAAAAAAABHAAAAAAAAgQAAAAAAACUAAAAAAABgAAAAAAAAYAAAAAACAGAAAAAAAgBgAAAAAAAAYAAAAAAAAGAAAAAAAgBgAAAAAAMAYAAAAAAAAGAAAAAAAQCBAAAAAAAAIAAAAAABACAAAAAAAwAgAAAAAAMAIAAAAAADACAAAAAAAwAlAAAAAAMAIgAAAAADACIAAAAAAQAiAAAAAAMAIgAAAAADACQAAAAAAgAiAAAAAAMAIgAAAAACACIAAAAAAgBgAAAAAAEAIAAAAAAAACAAAAAAAwAgAAAAAAIAIAAAAAADACAAAAAAAgCBAAAAAAAARwAAAAAAAGAAAAAAAgBgAAAAAAIAYAAAAAABAGAAAAAAAwBgAAAAAAMAYAAAAAADAGAAAAAAAgAiAAAAAAEAYAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACUAAAAAAwAfAAAAAAIAgQAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAIEAAAAAAABgAAAAAAAAIgAAAAAAAGAAAAAAAABHAAAAAAAAJQAAAAAAACUAAAAAAwAlAAAAAAIAJQAAAAABACUAAAAAAwAlAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQAiAAAAAAMAIgAAAAAAACIAAAAAAQBgAAAAAAEAgQAAAAAAACQAAAAAAgAlAAAAAAAAJQAAAAAAACUAAAAAAQAlAAAAAAMAJQAAAAABAA== version: 7 2,-2: ind: 2,-2 @@ -1913,6 +1913,11 @@ entities: 3720: -19,-28 3721: -18,-28 3722: -17,-28 + - node: + color: '#00000066' + id: DiagonalCheckerAOverlay + decals: + 4107: -24,-30 - node: color: '#00000067' id: DiagonalCheckerAOverlay @@ -2061,7 +2066,6 @@ entities: 1936: 41,-32 2122: -8,-7 2403: 10,-84 - 3409: 62,-22 - node: cleanable: True color: '#000000FF' @@ -3600,11 +3604,6 @@ entities: 3043: 18,-101 3044: 18,-100 3045: 18,-99 - - node: - color: '#43990996' - id: MiniTileLineOverlayW - decals: - 495: 17,-93 - node: color: '#9FED5896' id: MiniTileLineOverlayW @@ -3613,6 +3612,7 @@ entities: 1454: -15,-35 1912: 8,-71 1914: 23,-33 + 4109: 17,-93 - node: color: '#D381C926' id: MiniTileLineOverlayW @@ -3726,7 +3726,6 @@ entities: color: '#FFFFFFFF' id: MiniTileSteelLineW decals: - 494: 17,-93 1439: -35,-57 1453: -15,-35 1722: 53,-14 @@ -3742,6 +3741,7 @@ entities: 3501: 62,-42 3503: 62,-43 3504: 62,-44 + 4108: 17,-93 - node: color: '#1488C2FF' id: MiniTileWhiteInnerNe @@ -4343,6 +4343,9 @@ entities: 3242: 61,-54 3243: 59,-53 3244: 60,-53 + 4119: 58,-22 + 4120: 59,-22 + 4121: 61,-22 - node: color: '#70FFB3FF' id: WarnLineGreyscaleS @@ -4386,6 +4389,9 @@ entities: 3248: 59,-52 3249: 60,-52 3250: 61,-52 + 4122: 58,-22 + 4123: 59,-22 + 4124: 61,-22 - node: color: '#D381C9FF' id: WarnLineGreyscaleW @@ -4456,6 +4462,9 @@ entities: 3912: -19,-71 3913: -18,-71 4096: 46,-68 + 4112: 59,-22 + 4113: 58,-22 + 4114: 61,-22 - node: color: '#FFFFFFFF' id: WarnLineS @@ -4502,6 +4511,9 @@ entities: 3466: -17,-17 3467: -17,-20 4097: 46,-72 + 4110: 61,-22 + 4111: 59,-22 + 4115: 58,-22 - node: angle: 4.71238898038469 rad color: '#FFFFFFFF' @@ -4988,33 +5000,33 @@ entities: 2,-11: 0: 61166 3,-10: - 0: 61440 - 1: 4 + 0: 61638 + 1: 32 + 3,-12: + 1: 32 + 0: 9920 3,-11: - 0: 32992 + 0: 8416 3,-13: 0: 61164 - 3,-12: - 1: 1024 - 0: 32768 + 4,-12: + 0: 240 4,-11: - 0: 34679 + 0: 1911 4,-10: - 0: 61440 + 0: 61680 4,-13: 0: 15288 - 4,-12: - 0: 32768 5,-12: - 1: 256 - 0: 34952 + 0: 43928 + 1: 32 5,-10: - 1: 1 - 0: 63624 + 0: 63643 + 1: 32 5,-13: 0: 65535 5,-11: - 0: 34952 + 0: 43690 6,-12: 0: 64435 6,-11: @@ -5105,12 +5117,12 @@ entities: 0: 56799 -7,-4: 0: 65523 + -6,-8: + 0: 1800 -6,-7: 0: 65535 -6,-5: 0: 45942 - -6,-8: - 0: 1544 -6,-6: 0: 58980 -6,-9: @@ -5234,10 +5246,10 @@ entities: 0: 55551 8,-16: 0: 271 - 4: 17408 + 2: 17408 8,-15: 1: 4096 - 4: 4 + 2: 4 8,-14: 0: 32752 8,-13: @@ -5251,7 +5263,7 @@ entities: -5,-15: 0: 63949 -4,-14: - 0: 65527 + 0: 65535 -5,-14: 0: 40191 -4,-17: @@ -5289,7 +5301,7 @@ entities: 1,-20: 0: 30711 1,-19: - 0: 18023 + 0: 9831 1,-17: 0: 4095 1,-18: @@ -5932,8 +5944,8 @@ entities: 0: 65535 9,-16: 0: 15 - 5: 4352 - 2: 17408 + 3: 4352 + 4: 17408 10,-20: 0: 65280 10,-19: @@ -5944,8 +5956,8 @@ entities: 0: 65535 10,-16: 0: 15 - 2: 4352 - 6: 17408 + 4: 4352 + 5: 17408 11,-20: 0: 65024 11,-19: @@ -5957,7 +5969,7 @@ entities: 11,-16: 0: 15 1: 35840 - 2: 4352 + 4: 4352 12,-20: 0: 65280 12,-19: @@ -5990,7 +6002,7 @@ entities: 0: 61183 12,-16: 0: 3 - 2: 2184 + 4: 2184 1: 8960 13,-20: 0: 65024 @@ -6003,7 +6015,7 @@ entities: 13,-21: 1: 16177 13,-16: - 2: 819 + 4: 819 1: 8 14,-20: 0: 61704 @@ -6206,7 +6218,7 @@ entities: 0: 59392 11,-15: 1: 32904 - 2: 1 + 4: 1 12,-14: 0: 62926 11,-14: @@ -6218,7 +6230,7 @@ entities: 0: 61262 12,-12: 0: 43215 - 3: 4352 + 6: 4352 13,-15: 0: 65280 1: 4 @@ -6316,12 +6328,12 @@ entities: 1: 63624 11,-12: 0: 4508 - 3: 52224 + 6: 52224 12,-11: - 3: 4369 + 6: 4369 0: 52424 11,-11: - 3: 52428 + 6: 52428 0: 4371 12,-10: 0: 17748 @@ -6342,7 +6354,7 @@ entities: 13,-8: 0: 35768 14,-11: - 0: 20206 + 0: 52974 14,-10: 0: 61166 14,-9: @@ -6358,7 +6370,7 @@ entities: 16,-6: 0: 60967 15,-6: - 0: 65167 + 0: 64143 16,-5: 0: 1918 15,-5: @@ -6540,14 +6552,14 @@ entities: 11,-3: 1: 12288 9,-15: - 5: 1 - 2: 4 + 3: 1 + 4: 4 1: 32768 9,-14: 0: 36848 10,-15: - 2: 1 - 6: 4 + 4: 1 + 5: 4 10,-14: 0: 65520 -8,-24: @@ -6643,6 +6655,7 @@ entities: - volume: 2500 temperature: 293.15 moles: + - 6666.982 - 0 - 0 - 0 @@ -6654,6 +6667,50 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 0 + - 6666.982 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 0 + - 0 + - 0 + - 6666.982 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - 0 - volume: 2500 temperature: 235 @@ -6670,51 +6727,6 @@ entities: - 0 - 0 - 0 - - volume: 2500 - temperature: 293.15 - moles: - - 6666.982 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - volume: 2500 - temperature: 293.15 - moles: - - 0 - - 6666.982 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - volume: 2500 - temperature: 293.15 - moles: - - 0 - - 0 - - 0 - - 6666.982 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance @@ -9307,18 +9319,6 @@ entities: rot: 3.141592653589793 rad pos: -31.5,-7.5 parent: 2 - - uid: 7770 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,-9.5 - parent: 2 - - uid: 18401 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 23.5,-9.5 - parent: 2 - proto: AirlockExternalGlassShuttleEscape entities: - uid: 1106 @@ -9345,6 +9345,18 @@ entities: parent: 2 - proto: AirlockExternalGlassShuttleLocked entities: + - uid: 616 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 23.5,-9.5 + parent: 2 + - uid: 738 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,-9.5 + parent: 2 - uid: 6945 components: - type: Transform @@ -10046,7 +10058,7 @@ entities: pos: 11.5,-30.5 parent: 2 - type: Door - secondsUntilStateChange: -114584.41 + secondsUntilStateChange: -127812.8 state: Opening - type: DeviceLinkSource lastSignals: @@ -10464,11 +10476,6 @@ entities: - type: Transform pos: -8.5,-60.5 parent: 2 - - uid: 616 - components: - - type: Transform - pos: -12.5,-56.5 - parent: 2 - uid: 617 components: - type: Transform @@ -10529,11 +10536,6 @@ entities: - type: Transform pos: 6.5,-68.5 parent: 2 - - uid: 738 - components: - - type: Transform - pos: 6.5,-72.5 - parent: 2 - uid: 742 components: - type: Transform @@ -10705,6 +10707,12 @@ entities: - type: Transform pos: 65.5,-53.5 parent: 2 + - uid: 12409 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -11.5,-56.5 + parent: 2 - uid: 13804 components: - type: Transform @@ -10740,6 +10748,11 @@ entities: - type: Transform pos: 49.5,-31.5 parent: 2 + - uid: 15470 + components: + - type: Transform + pos: 5.5,-72.5 + parent: 2 - uid: 18040 components: - type: Transform @@ -11525,14 +11538,6 @@ entities: rot: 1.5707963267948966 rad pos: 57.5,-68.5 parent: 2 - - uid: 4999 - components: - - type: MetaData - name: Security Outpost APC - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,-51.5 - parent: 2 - uid: 5615 components: - type: MetaData @@ -11859,6 +11864,13 @@ entities: rot: 1.5707963267948966 rad pos: -9.5,-22.5 parent: 2 + - uid: 11956 + components: + - type: MetaData + name: Security Outpost APC + - type: Transform + pos: 9.5,-46.5 + parent: 2 - uid: 12036 components: - type: MetaData @@ -12003,7 +12015,7 @@ entities: - uid: 5641 components: - type: Transform - pos: -22.45828,-51.977993 + pos: -22.370735,-51.96643 parent: 2 - proto: ArrivalsShuttleTimer entities: @@ -12054,6 +12066,11 @@ entities: - type: Transform pos: 29.930677,-44.420216 parent: 2 + - uid: 19661 + components: + - type: Transform + pos: -48.02379,-45.496872 + parent: 2 - proto: AsimovCircuitBoard entities: - uid: 18617 @@ -12576,11 +12593,6 @@ entities: parent: 2 - proto: Beaker entities: - - uid: 3873 - components: - - type: Transform - pos: -3.5478697,-47.418797 - parent: 2 - uid: 4085 components: - type: Transform @@ -12596,16 +12608,6 @@ entities: - type: Transform pos: 44.564533,-15.393791 parent: 2 - - uid: 19022 - components: - - type: Transform - pos: -3.5270362,-47.1165 - parent: 2 - - uid: 19023 - components: - - type: Transform - pos: -3.7145362,-47.27286 - parent: 2 - proto: Bed entities: - uid: 354 @@ -12882,7 +12884,7 @@ entities: - uid: 18036 components: - type: Transform - pos: 80.17493,-26.997755 + pos: 72.49216,-25.507568 parent: 2 - proto: Biogenerator entities: @@ -12928,24 +12930,6 @@ entities: - type: Transform pos: 61.5,-53.5 parent: 2 - - uid: 5029 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -21.5,-31.5 - parent: 2 - - uid: 5030 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -21.5,-32.5 - parent: 2 - - uid: 5031 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -21.5,-33.5 - parent: 2 - uid: 13934 components: - type: Transform @@ -12958,6 +12942,12 @@ entities: parent: 2 - proto: BlastDoorXeno entities: + - uid: 313 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -21.5,-33.5 + parent: 2 - uid: 487 components: - type: Transform @@ -13028,11 +13018,134 @@ entities: - type: Transform pos: -66.5,-62.5 parent: 2 + - uid: 1341 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -21.5,-32.5 + parent: 2 + - uid: 2501 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -21.5,-31.5 + parent: 2 - uid: 7185 components: - type: Transform pos: 59.5,-78.5 parent: 2 +- proto: BlastDoorXenoOpen + entities: + - uid: 14056 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,-43.5 + parent: 2 + - uid: 16098 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,-40.5 + parent: 2 + - uid: 19556 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,-39.5 + parent: 2 + - uid: 19557 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,-39.5 + parent: 2 + - uid: 19558 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 17.5,-39.5 + parent: 2 + - uid: 19559 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 16.5,-39.5 + parent: 2 + - uid: 19560 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 15.5,-39.5 + parent: 2 + - uid: 19561 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,-42.5 + parent: 2 + - uid: 19562 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,-44.5 + parent: 2 + - uid: 19563 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,-41.5 + parent: 2 + - uid: 19564 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,-40.5 + parent: 2 + - uid: 19565 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,-44.5 + parent: 2 + - uid: 19566 + components: + - type: Transform + pos: 18.5,-45.5 + parent: 2 + - uid: 19567 + components: + - type: Transform + pos: 17.5,-45.5 + parent: 2 + - uid: 19568 + components: + - type: Transform + pos: 16.5,-45.5 + parent: 2 + - uid: 19570 + components: + - type: Transform + pos: 15.5,-45.5 + parent: 2 + - uid: 19571 + components: + - type: Transform + pos: 19.5,-45.5 + parent: 2 + - uid: 19572 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,-43.5 + parent: 2 + - uid: 19575 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,-41.5 + parent: 2 - proto: BodyBagFolded entities: - uid: 13193 @@ -13310,6 +13423,11 @@ entities: parent: 2 - proto: BoxBeaker entities: + - uid: 7456 + components: + - type: Transform + pos: -3.621653,-47.22137 + parent: 2 - uid: 7760 components: - type: Transform @@ -13402,7 +13520,7 @@ entities: - uid: 6212 components: - type: Transform - pos: 13.349184,-58.437775 + pos: 13.349543,-58.569397 parent: 2 - uid: 18168 components: @@ -13417,7 +13535,7 @@ entities: - uid: 18182 components: - type: Transform - pos: 13.424348,-58.281063 + pos: 13.42246,-58.37134 parent: 2 - uid: 18184 components: @@ -13425,6 +13543,12 @@ entities: rot: -1.5707963267948966 rad pos: 11.485994,-16.436533 parent: 2 + - uid: 19656 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -48.45786,-44.761845 + parent: 2 - proto: BoxFolderGreen entities: - uid: 18186 @@ -13620,6 +13744,11 @@ entities: - type: Transform pos: 46.49753,-47.4596 parent: 2 + - uid: 19673 + components: + - type: Transform + pos: -49.55333,-43.35533 + parent: 2 - proto: Brutepack entities: - uid: 5938 @@ -13750,6 +13879,11 @@ entities: - type: Transform pos: 36.5,-82.5 parent: 2 + - uid: 19573 + components: + - type: Transform + pos: 13.5,-41.5 + parent: 2 - proto: ButtonFrameCautionSecurity entities: - uid: 2697 @@ -14206,6 +14340,11 @@ entities: - type: Transform pos: -9.5,-22.5 parent: 2 + - uid: 3127 + components: + - type: Transform + pos: 5.5,-73.5 + parent: 2 - uid: 3183 components: - type: Transform @@ -14496,6 +14635,11 @@ entities: - type: Transform pos: 57.5,-24.5 parent: 2 + - uid: 4068 + components: + - type: Transform + pos: 9.5,-48.5 + parent: 2 - uid: 4070 components: - type: Transform @@ -14726,11 +14870,6 @@ entities: - type: Transform pos: 57.5,-64.5 parent: 2 - - uid: 5117 - components: - - type: Transform - pos: 6.5,-51.5 - parent: 2 - uid: 5181 components: - type: Transform @@ -14746,11 +14885,6 @@ entities: - type: Transform pos: -12.5,-34.5 parent: 2 - - uid: 5207 - components: - - type: Transform - pos: 5.5,-51.5 - parent: 2 - uid: 5210 components: - type: Transform @@ -21321,30 +21455,10 @@ entities: - type: Transform pos: 6.5,-77.5 parent: 2 - - uid: 12407 - components: - - type: Transform - pos: 6.5,-76.5 - parent: 2 - - uid: 12408 - components: - - type: Transform - pos: 6.5,-75.5 - parent: 2 - - uid: 12409 - components: - - type: Transform - pos: 6.5,-74.5 - parent: 2 - - uid: 12410 - components: - - type: Transform - pos: 6.5,-73.5 - parent: 2 - uid: 12411 components: - type: Transform - pos: 6.5,-72.5 + pos: 5.5,-75.5 parent: 2 - uid: 12412 components: @@ -26241,11 +26355,6 @@ entities: - type: Transform pos: 17.5,-50.5 parent: 2 - - uid: 18416 - components: - - type: Transform - pos: 10.5,-48.5 - parent: 2 - uid: 18417 components: - type: Transform @@ -26561,6 +26670,11 @@ entities: - type: Transform pos: 48.5,-56.5 parent: 2 + - uid: 19089 + components: + - type: Transform + pos: -15.5,-19.5 + parent: 2 - uid: 19091 components: - type: Transform @@ -26871,6 +26985,76 @@ entities: - type: Transform pos: 21.5,-23.5 parent: 2 + - uid: 19537 + components: + - type: Transform + pos: 5.5,-72.5 + parent: 2 + - uid: 19584 + components: + - type: Transform + pos: 5.5,-71.5 + parent: 2 + - uid: 19585 + components: + - type: Transform + pos: 5.5,-76.5 + parent: 2 + - uid: 19586 + components: + - type: Transform + pos: 5.5,-74.5 + parent: 2 + - uid: 19597 + components: + - type: Transform + pos: 46.5,-71.5 + parent: 2 + - uid: 19601 + components: + - type: Transform + pos: 46.5,-70.5 + parent: 2 + - uid: 19602 + components: + - type: Transform + pos: 46.5,-69.5 + parent: 2 + - uid: 19604 + components: + - type: Transform + pos: 14.5,-56.5 + parent: 2 + - uid: 19627 + components: + - type: Transform + pos: 9.5,-47.5 + parent: 2 + - uid: 19628 + components: + - type: Transform + pos: 9.5,-46.5 + parent: 2 + - uid: 19676 + components: + - type: Transform + pos: 94.5,-43.5 + parent: 2 + - uid: 19677 + components: + - type: Transform + pos: 95.5,-43.5 + parent: 2 + - uid: 19678 + components: + - type: Transform + pos: 94.5,-47.5 + parent: 2 + - uid: 19679 + components: + - type: Transform + pos: 95.5,-47.5 + parent: 2 - proto: CableApcStack entities: - uid: 9765 @@ -32767,8 +32951,23 @@ entities: - type: Transform pos: 37.5,-71.5 parent: 2 + - uid: 19591 + components: + - type: Transform + pos: 2.5,-75.5 + parent: 2 + - uid: 19592 + components: + - type: Transform + pos: 2.5,-76.5 + parent: 2 - proto: CableMV entities: + - uid: 185 + components: + - type: Transform + pos: 7.5,-49.5 + parent: 2 - uid: 256 components: - type: Transform @@ -32887,7 +33086,7 @@ entities: - uid: 2769 components: - type: Transform - pos: 6.5,-51.5 + pos: 5.5,-49.5 parent: 2 - uid: 2770 components: @@ -32897,7 +33096,7 @@ entities: - uid: 2771 components: - type: Transform - pos: 5.5,-51.5 + pos: 4.5,-50.5 parent: 2 - uid: 2778 components: @@ -33114,6 +33313,11 @@ entities: - type: Transform pos: 4.5,-56.5 parent: 2 + - uid: 4557 + components: + - type: Transform + pos: 6.5,-49.5 + parent: 2 - uid: 4558 components: - type: Transform @@ -33149,6 +33353,11 @@ entities: - type: Transform pos: 82.5,-45.5 parent: 2 + - uid: 4999 + components: + - type: Transform + pos: 4.5,-49.5 + parent: 2 - uid: 5009 components: - type: Transform @@ -36774,6 +36983,11 @@ entities: - type: Transform pos: 5.5,-25.5 parent: 2 + - uid: 15123 + components: + - type: Transform + pos: 8.5,-49.5 + parent: 2 - uid: 15148 components: - type: Transform @@ -37344,6 +37558,31 @@ entities: - type: Transform pos: -45.5,-35.5 parent: 2 + - uid: 19623 + components: + - type: Transform + pos: 9.5,-49.5 + parent: 2 + - uid: 19624 + components: + - type: Transform + pos: 9.5,-48.5 + parent: 2 + - uid: 19625 + components: + - type: Transform + pos: 9.5,-47.5 + parent: 2 + - uid: 19626 + components: + - type: Transform + pos: 9.5,-46.5 + parent: 2 + - uid: 19646 + components: + - type: Transform + pos: 62.5,-21.5 + parent: 2 - proto: CableTerminal entities: - uid: 3002 @@ -37462,6 +37701,24 @@ entities: - type: Transform pos: -20.522596,-33.289913 parent: 2 + - uid: 19615 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.744207,-32.486958 + parent: 2 + - uid: 19616 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.320597,-32.493908 + parent: 2 + - uid: 19617 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.52893,-32.65374 + parent: 2 - proto: CandlePurpleSmall entities: - uid: 4411 @@ -37989,6 +38246,36 @@ entities: - type: Transform pos: 52.5,-55.5 parent: 2 + - uid: 19610 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.5,-33.5 + parent: 2 + - uid: 19611 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.5,-32.5 + parent: 2 + - uid: 19612 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -20.5,-32.5 + parent: 2 + - uid: 19613 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -19.5,-31.5 + parent: 2 + - uid: 19614 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -18.5,-32.5 + parent: 2 - proto: CarpetBlue entities: - uid: 5129 @@ -38106,6 +38393,31 @@ entities: - type: Transform pos: -51.5,-60.5 parent: 2 +- proto: CarpetChapel + entities: + - uid: 5030 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -20.5,-31.5 + parent: 2 + - uid: 7206 + components: + - type: Transform + pos: -20.5,-33.5 + parent: 2 + - uid: 12850 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -18.5,-31.5 + parent: 2 + - uid: 19390 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -18.5,-33.5 + parent: 2 - proto: CarpetGreen entities: - uid: 5945 @@ -39844,6 +40156,12 @@ entities: - type: Transform pos: 56.5,-73.5 parent: 2 + - uid: 12410 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -10.5,-56.5 + parent: 2 - uid: 12854 components: - type: Transform @@ -40585,16 +40903,6 @@ entities: rot: -1.5707963267948966 rad pos: 36.5,-91.5 parent: 2 - - uid: 19537 - components: - - type: Transform - pos: -11.5,-56.5 - parent: 2 - - uid: 19538 - components: - - type: Transform - pos: -10.5,-56.5 - parent: 2 - uid: 19539 components: - type: Transform @@ -41064,6 +41372,12 @@ entities: rot: 1.5707963267948966 rad pos: 48.5,-25.5 parent: 2 + - uid: 19669 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -46.5,-44.5 + parent: 2 - proto: ChairFoldingSpawnFolded entities: - uid: 9949 @@ -41489,6 +41803,13 @@ entities: rot: 1.5707963267948966 rad pos: -21.5,-35.5 parent: 2 +- proto: Cigar + entities: + - uid: 19658 + components: + - type: Transform + pos: -48.56308,-44.345364 + parent: 2 - proto: CigaretteBanana entities: - uid: 7237 @@ -41508,6 +41829,11 @@ entities: - type: Transform pos: 68.09442,-38.40559 parent: 2 + - uid: 19660 + components: + - type: Transform + pos: -47.900097,-45.23187 + parent: 2 - proto: CigarGold entities: - uid: 4505 @@ -41524,6 +41850,13 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage +- proto: CigarSpent + entities: + - uid: 19659 + components: + - type: Transform + pos: -47.31308,-45.27867 + parent: 2 - proto: CircuitImprinter entities: - uid: 5897 @@ -41615,11 +41948,6 @@ entities: - type: Transform pos: -20.5,-30.5 parent: 2 - - uid: 313 - components: - - type: Transform - pos: -21.5,-29.5 - parent: 2 - uid: 314 components: - type: Transform @@ -41685,11 +42013,6 @@ entities: - type: Transform pos: -22.5,-28.5 parent: 2 - - uid: 1341 - components: - - type: Transform - pos: -23.5,-29.5 - parent: 2 - uid: 1429 components: - type: Transform @@ -41765,11 +42088,6 @@ entities: - type: Transform pos: -17.5,-35.5 parent: 2 - - uid: 14808 - components: - - type: Transform - pos: -22.5,-29.5 - parent: 2 - uid: 16186 components: - type: Transform @@ -42015,11 +42333,6 @@ entities: - type: Transform pos: 35.5,-78.5 parent: 2 - - uid: 18908 - components: - - type: Transform - pos: 5.5,-73.5 - parent: 2 - uid: 19187 components: - type: Transform @@ -42573,6 +42886,11 @@ entities: - type: Transform pos: 8.443563,-87.12137 parent: 2 + - uid: 19651 + components: + - type: Transform + pos: -47.73321,-44.589058 + parent: 2 - proto: ClothingEyesGlassesChemical entities: - uid: 7693 @@ -42625,12 +42943,12 @@ entities: - uid: 7938 components: - type: Transform - pos: -22.386917,-49.45568 + pos: -22.36449,-49.554092 parent: 2 - uid: 19371 components: - type: Transform - pos: -22.50776,-49.283688 + pos: -22.554304,-49.354877 parent: 2 - proto: ClothingHandsGlovesLatex entities: @@ -43020,6 +43338,13 @@ entities: - type: Transform pos: 83.44597,-72.587036 parent: 2 +- proto: ClothingMultipleHeadphones + entities: + - uid: 17553 + components: + - type: Transform + pos: -37.47268,-60.168076 + parent: 2 - proto: ClothingNeckBling entities: - uid: 18022 @@ -43107,13 +43432,6 @@ entities: - type: Transform pos: 77.515434,-20.379131 parent: 2 -- proto: ClothingNeckHeadphones - entities: - - uid: 17553 - components: - - type: Transform - pos: -37.47268,-60.168076 - parent: 2 - proto: ClothingNeckScarfStripedBlack entities: - uid: 19011 @@ -43361,6 +43679,13 @@ entities: - type: Transform pos: 35.344784,-91.27624 parent: 2 +- proto: ClothingOuterWinterHydro + entities: + - uid: 3873 + components: + - type: Transform + pos: -5.464688,-51.46298 + parent: 2 - proto: ClothingShoesBootsCowboyFancy entities: - uid: 19229 @@ -43698,12 +44023,6 @@ entities: rot: 3.141592653589793 rad pos: -40.5,-80.5 parent: 2 - - uid: 17715 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,-73.5 - parent: 2 - uid: 17722 components: - type: Transform @@ -44017,6 +44336,12 @@ entities: parent: 2 - proto: ComputerCriminalRecords entities: + - uid: 373 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-14.5 + parent: 2 - uid: 3547 components: - type: Transform @@ -44057,6 +44382,14 @@ entities: rot: -1.5707963267948966 rad pos: 72.5,-50.5 parent: 2 +- proto: ComputerFundingAllocation + entities: + - uid: 19368 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 15.5,-58.5 + parent: 2 - proto: ComputerId entities: - uid: 5510 @@ -44221,11 +44554,16 @@ entities: parent: 2 - proto: ComputerSurveillanceCameraMonitor entities: - - uid: 538 + - uid: 374 components: - type: Transform - rot: 3.141592653589793 rad - pos: -2.5,-14.5 + rot: -1.5707963267948966 rad + pos: 60.5,-45.5 + parent: 2 + - uid: 7040 + components: + - type: Transform + pos: 69.5,-45.5 parent: 2 - uid: 8248 components: @@ -44242,19 +44580,6 @@ entities: - type: Transform pos: 59.5,-26.5 parent: 2 -- proto: ComputerSurveillanceWirelessCameraMonitor - entities: - - uid: 7040 - components: - - type: Transform - pos: 69.5,-45.5 - parent: 2 - - uid: 10774 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 60.5,-45.5 - parent: 2 - proto: ComputerTelevision entities: - uid: 5478 @@ -45088,21 +45413,21 @@ entities: parent: 2 - proto: CrateCoffin entities: + - uid: 5029 + components: + - type: Transform + pos: -22.5,-29.5 + parent: 2 + - uid: 5031 + components: + - type: Transform + pos: -21.5,-29.5 + parent: 2 - uid: 10301 components: - type: Transform pos: 35.5,-25.5 parent: 2 - - uid: 17707 - components: - - type: Transform - pos: -24.5,-29.5 - parent: 2 - - uid: 19390 - components: - - type: Transform - pos: -24.5,-30.5 - parent: 2 - proto: CrateContrabandStorageSecure entities: - uid: 10331 @@ -45419,6 +45744,13 @@ entities: - 0 - 0 - 0 +- proto: CrateHydroponicsSeeds + entities: + - uid: 19590 + components: + - type: Transform + pos: 6.5,-73.5 + parent: 2 - proto: CrateLockBoxEngineering entities: - uid: 15392 @@ -45435,16 +45767,16 @@ entities: parent: 2 - proto: CrateLockBoxScience entities: + - uid: 536 + components: + - type: Transform + pos: -10.5,-15.5 + parent: 2 - uid: 4348 components: - type: Transform pos: -20.5,-27.5 parent: 2 - - uid: 7099 - components: - - type: Transform - pos: -14.5,-21.5 - parent: 2 - proto: CrateLockBoxSecurity entities: - uid: 12856 @@ -45647,7 +45979,7 @@ entities: - uid: 5592 components: - type: Transform - pos: -53.47501,-42.818943 + pos: -53.56222,-43.09171 parent: 2 - uid: 5593 components: @@ -46525,6 +46857,12 @@ entities: parent: 2 - proto: DisposalBend entities: + - uid: 377 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -14.5,-20.5 + parent: 2 - uid: 1189 components: - type: Transform @@ -46619,12 +46957,6 @@ entities: rot: 1.5707963267948966 rad pos: 56.5,-70.5 parent: 2 - - uid: 5426 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -10.5,-20.5 - parent: 2 - uid: 5730 components: - type: Transform @@ -47239,6 +47571,17 @@ entities: rot: 3.141592653589793 rad pos: 25.5,-77.5 parent: 2 + - uid: 19542 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,-28.5 + parent: 2 + - uid: 19543 + components: + - type: Transform + pos: 35.5,-28.5 + parent: 2 - proto: DisposalJunction entities: - uid: 4039 @@ -47316,6 +47659,12 @@ entities: parent: 2 - proto: DisposalJunctionFlipped entities: + - uid: 529 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 28.5,-23.5 + parent: 2 - uid: 8061 components: - type: Transform @@ -47403,6 +47752,30 @@ entities: rot: 1.5707963267948966 rad pos: 22.5,-58.5 parent: 2 + - uid: 378 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -10.5,-20.5 + parent: 2 + - uid: 379 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -11.5,-20.5 + parent: 2 + - uid: 528 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -12.5,-20.5 + parent: 2 + - uid: 533 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -13.5,-20.5 + parent: 2 - uid: 1462 components: - type: Transform @@ -47536,11 +47909,6 @@ entities: rot: 1.5707963267948966 rad pos: -9.5,-20.5 parent: 2 - - uid: 5101 - components: - - type: Transform - pos: -10.5,-19.5 - parent: 2 - uid: 5373 components: - type: Transform @@ -47553,11 +47921,6 @@ entities: rot: 3.141592653589793 rad pos: 56.5,-72.5 parent: 2 - - uid: 5460 - components: - - type: Transform - pos: -10.5,-18.5 - parent: 2 - uid: 5732 components: - type: Transform @@ -48107,11 +48470,6 @@ entities: rot: 3.141592653589793 rad pos: 4.5,-44.5 parent: 2 - - uid: 13452 - components: - - type: Transform - pos: -10.5,-17.5 - parent: 2 - uid: 13821 components: - type: Transform @@ -49430,12 +49788,6 @@ entities: rot: 1.5707963267948966 rad pos: 29.5,-23.5 parent: 2 - - uid: 15698 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 28.5,-23.5 - parent: 2 - uid: 15699 components: - type: Transform @@ -50892,11 +51244,6 @@ entities: - type: Transform pos: -47.5,-36.5 parent: 2 - - uid: 16521 - components: - - type: Transform - pos: -10.5,-16.5 - parent: 2 - uid: 16863 components: - type: Transform @@ -50961,6 +51308,12 @@ entities: - type: Transform pos: -2.5,-31.5 parent: 2 + - uid: 17213 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -20.5,-49.5 + parent: 2 - uid: 17295 components: - type: Transform @@ -51077,6 +51430,60 @@ entities: - type: Transform pos: 7.5,-58.5 parent: 2 + - uid: 19540 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,-25.5 + parent: 2 + - uid: 19541 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,-26.5 + parent: 2 + - uid: 19545 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,-27.5 + parent: 2 + - uid: 19546 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,-28.5 + parent: 2 + - uid: 19547 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 30.5,-28.5 + parent: 2 + - uid: 19548 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 31.5,-28.5 + parent: 2 + - uid: 19549 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 32.5,-28.5 + parent: 2 + - uid: 19550 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,-28.5 + parent: 2 + - uid: 19551 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,-28.5 + parent: 2 - proto: DisposalPipeBroken entities: - uid: 7201 @@ -51092,6 +51499,12 @@ entities: parent: 2 - proto: DisposalTrunk entities: + - uid: 535 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -14.5,-21.5 + parent: 2 - uid: 1459 components: - type: Transform @@ -51127,11 +51540,6 @@ entities: - type: Transform pos: 31.5,-37.5 parent: 2 - - uid: 5100 - components: - - type: Transform - pos: -10.5,-15.5 - parent: 2 - uid: 5801 components: - type: Transform @@ -51337,18 +51745,24 @@ entities: rot: 1.5707963267948966 rad pos: 19.5,-25.5 parent: 2 - - uid: 19368 + - uid: 19367 components: - type: Transform rot: -1.5707963267948966 rad - pos: -20.5,-49.5 + pos: -19.5,-49.5 + parent: 2 + - uid: 19544 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 35.5,-29.5 parent: 2 - proto: DisposalUnit entities: - - uid: 1856 + - uid: 375 components: - type: Transform - pos: -10.5,-15.5 + pos: -14.5,-21.5 parent: 2 - uid: 1883 components: @@ -51450,11 +51864,6 @@ entities: - type: Transform pos: 19.5,-25.5 parent: 2 - - uid: 7461 - components: - - type: Transform - pos: -20.5,-49.5 - parent: 2 - uid: 7755 components: - type: Transform @@ -51545,6 +51954,11 @@ entities: - type: Transform pos: 31.5,-37.5 parent: 2 + - uid: 19593 + components: + - type: Transform + pos: -19.5,-49.5 + parent: 2 - proto: DisposalXJunction entities: - uid: 7892 @@ -51653,7 +52067,7 @@ entities: - type: Transform pos: -9.316594,-6.1209764 parent: 2 -- proto: DoubleEmergencyNitrogenTank +- proto: DoubleEmergencyOxygenTankFilled entities: - uid: 4161 components: @@ -51665,8 +52079,6 @@ entities: - type: Transform pos: 80.4613,-23.302551 parent: 2 -- proto: DoubleEmergencyOxygenTankFilled - entities: - uid: 7692 components: - type: Transform @@ -51786,6 +52198,24 @@ entities: - type: Transform pos: 21.681454,-19.427164 parent: 2 +- proto: DrinkEnergyDrinkCan + entities: + - uid: 19665 + components: + - type: Transform + pos: -46.49681,-46.443466 + parent: 2 + - uid: 19667 + components: + - type: Transform + pos: -46.298893,-46.683216 + parent: 2 + - uid: 19668 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -46.486393,-46.93339 + parent: 2 - proto: DrinkEnergyDrinkJug entities: - uid: 17562 @@ -51798,7 +52228,7 @@ entities: - uid: 5481 components: - type: Transform - pos: -38.302177,-55.24425 + pos: -38.411427,-55.289524 parent: 2 - proto: DrinkFlaskBar entities: @@ -51916,6 +52346,20 @@ entities: - type: Transform pos: 21.108538,-19.239534 parent: 2 +- proto: DrinkMugBlack + entities: + - uid: 19662 + components: + - type: Transform + pos: -48.28667,-46.57887 + parent: 2 +- proto: DrinkMugBlue + entities: + - uid: 19663 + components: + - type: Transform + pos: -48.168613,-44.37595 + parent: 2 - proto: DrinkMugMetal entities: - uid: 18321 @@ -51947,6 +52391,11 @@ entities: - type: Transform pos: 32.460705,-83.503525 parent: 2 + - uid: 19664 + components: + - type: Transform + pos: -47.64084,-45.744957 + parent: 2 - proto: DrinkMugRed entities: - uid: 17563 @@ -51987,7 +52436,7 @@ entities: - uid: 19296 components: - type: Transform - pos: -5.7709203,-19.359259 + pos: -3.766451,-19.48293 parent: 2 - proto: DrinkWaterBottleFull entities: @@ -52653,11 +53102,6 @@ entities: rot: -1.5707963267948966 rad pos: 8.5,-4.5 parent: 2 - - uid: 18339 - components: - - type: Transform - pos: 11.5,-70.5 - parent: 2 - uid: 18340 components: - type: Transform @@ -52674,6 +53118,12 @@ entities: - type: Transform pos: -27.5,-62.5 parent: 2 + - uid: 19650 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 11.5,-69.5 + parent: 2 - proto: FaxMachineBase entities: - uid: 1889 @@ -58307,6 +58757,12 @@ entities: - type: Transform pos: 31.513302,-94.31904 parent: 2 + - uid: 19666 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -47.392643,-44.84861 + parent: 2 - proto: FoodDonkpocketPizza entities: - uid: 6972 @@ -58544,7 +59000,7 @@ entities: - uid: 5482 components: - type: Transform - pos: -38.651333,-55.430145 + pos: -42.49177,-52.28213 parent: 2 - proto: FoodPieXenoSlice entities: @@ -76479,6 +76935,11 @@ entities: - type: Transform pos: -42.492443,-82.46442 parent: 2 + - uid: 19670 + components: + - type: Transform + pos: -52.550312,-52.240044 + parent: 2 - proto: Girder entities: - uid: 4080 @@ -76898,36 +77359,6 @@ entities: - type: Transform pos: 16.5,-47.5 parent: 2 - - uid: 373 - components: - - type: Transform - pos: 14.5,-43.5 - parent: 2 - - uid: 374 - components: - - type: Transform - pos: 15.5,-45.5 - parent: 2 - - uid: 375 - components: - - type: Transform - pos: 18.5,-45.5 - parent: 2 - - uid: 377 - components: - - type: Transform - pos: 16.5,-45.5 - parent: 2 - - uid: 378 - components: - - type: Transform - pos: 17.5,-45.5 - parent: 2 - - uid: 379 - components: - - type: Transform - pos: 15.5,-40.5 - parent: 2 - uid: 422 components: - type: Transform @@ -76968,32 +77399,12 @@ entities: - type: Transform pos: -3.5,-23.5 parent: 2 - - uid: 528 - components: - - type: Transform - pos: 14.5,-40.5 - parent: 2 - - uid: 529 - components: - - type: Transform - pos: 14.5,-41.5 - parent: 2 - - uid: 533 - components: - - type: Transform - pos: 15.5,-41.5 - parent: 2 - - uid: 535 - components: - - type: Transform - pos: 19.5,-44.5 - parent: 2 - - uid: 536 - components: - - type: Transform - pos: 18.5,-40.5 - parent: 2 - uid: 537 + components: + - type: Transform + pos: 20.5,-43.5 + parent: 2 + - uid: 538 components: - type: Transform pos: 20.5,-41.5 @@ -77001,57 +77412,77 @@ entities: - uid: 539 components: - type: Transform - pos: 16.5,-39.5 + pos: 19.5,-43.5 parent: 2 - uid: 540 components: - type: Transform - pos: 17.5,-40.5 + pos: 20.5,-40.5 parent: 2 - uid: 541 components: - type: Transform - pos: 19.5,-39.5 + pos: 19.5,-44.5 parent: 2 - uid: 542 components: - type: Transform - pos: 20.5,-40.5 + pos: 14.5,-41.5 parent: 2 - uid: 555 components: - type: Transform - pos: 18.5,-39.5 + pos: 15.5,-41.5 parent: 2 - uid: 557 components: - type: Transform - pos: 17.5,-39.5 + pos: 15.5,-40.5 parent: 2 - uid: 558 components: - type: Transform - pos: 19.5,-40.5 + pos: 14.5,-40.5 parent: 2 - uid: 559 components: - type: Transform - pos: 20.5,-43.5 + pos: 14.5,-44.5 parent: 2 - uid: 560 components: - type: Transform - pos: 20.5,-44.5 + pos: 18.5,-39.5 + parent: 2 + - uid: 562 + components: + - type: Transform + pos: 15.5,-39.5 + parent: 2 + - uid: 563 + components: + - type: Transform + pos: 14.5,-43.5 parent: 2 - uid: 565 components: - type: Transform - pos: 16.5,-40.5 + pos: 18.5,-40.5 parent: 2 - uid: 566 components: - type: Transform - pos: 15.5,-39.5 + pos: 17.5,-39.5 + parent: 2 + - uid: 568 + components: + - type: Transform + pos: 17.5,-40.5 + parent: 2 + - uid: 581 + components: + - type: Transform + pos: 16.5,-40.5 parent: 2 - uid: 614 components: @@ -77626,17 +78057,17 @@ entities: - uid: 1558 components: - type: Transform - pos: 18.5,-44.5 + pos: 15.5,-45.5 parent: 2 - uid: 1559 components: - type: Transform - pos: 17.5,-44.5 + pos: 19.5,-40.5 parent: 2 - uid: 1560 components: - type: Transform - pos: 19.5,-45.5 + pos: 19.5,-41.5 parent: 2 - uid: 1564 components: @@ -77656,12 +78087,12 @@ entities: - uid: 1596 components: - type: Transform - pos: 14.5,-44.5 + pos: 15.5,-43.5 parent: 2 - uid: 1597 components: - type: Transform - pos: 15.5,-44.5 + pos: 16.5,-39.5 parent: 2 - uid: 1634 components: @@ -77701,12 +78132,32 @@ entities: - uid: 1642 components: - type: Transform - pos: 15.5,-43.5 + pos: 17.5,-44.5 parent: 2 - uid: 1644 components: - type: Transform - pos: 16.5,-44.5 + pos: 18.5,-45.5 + parent: 2 + - uid: 1645 + components: + - type: Transform + pos: 19.5,-42.5 + parent: 2 + - uid: 1646 + components: + - type: Transform + pos: 20.5,-42.5 + parent: 2 + - uid: 1647 + components: + - type: Transform + pos: 19.5,-45.5 + parent: 2 + - uid: 1648 + components: + - type: Transform + pos: 20.5,-44.5 parent: 2 - uid: 1659 components: @@ -77738,6 +78189,16 @@ entities: - type: Transform pos: -30.5,-46.5 parent: 2 + - uid: 1667 + components: + - type: Transform + pos: 18.5,-44.5 + parent: 2 + - uid: 1668 + components: + - type: Transform + pos: 16.5,-44.5 + parent: 2 - uid: 1671 components: - type: Transform @@ -77813,11 +78274,26 @@ entities: - type: Transform pos: -40.5,-43.5 parent: 2 + - uid: 1688 + components: + - type: Transform + pos: 19.5,-39.5 + parent: 2 + - uid: 1692 + components: + - type: Transform + pos: 16.5,-45.5 + parent: 2 - uid: 1693 components: - type: Transform pos: 26.5,-40.5 parent: 2 + - uid: 1696 + components: + - type: Transform + pos: 15.5,-44.5 + parent: 2 - uid: 1703 components: - type: Transform @@ -79093,18 +79569,6 @@ entities: - type: Transform pos: 39.5,-9.5 parent: 2 - - uid: 6244 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-43.5 - parent: 2 - - uid: 6248 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,-42.5 - parent: 2 - uid: 6302 components: - type: Transform @@ -80360,6 +80824,11 @@ entities: - type: Transform pos: 61.5,-46.5 parent: 2 + - uid: 13843 + components: + - type: Transform + pos: 62.5,-21.5 + parent: 2 - uid: 13979 components: - type: Transform @@ -80496,12 +80965,6 @@ entities: - type: Transform pos: -5.5,-18.5 parent: 2 - - uid: 16097 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-42.5 - parent: 2 - uid: 16131 components: - type: Transform @@ -80512,12 +80975,6 @@ entities: - type: Transform pos: 65.5,-44.5 parent: 2 - - uid: 16170 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-41.5 - parent: 2 - uid: 16183 components: - type: Transform @@ -80653,6 +81110,11 @@ entities: - type: Transform pos: -18.5,-88.5 parent: 2 + - uid: 16818 + components: + - type: Transform + pos: 17.5,-45.5 + parent: 2 - uid: 16865 components: - type: Transform @@ -80673,11 +81135,6 @@ entities: - type: Transform pos: 57.5,-47.5 parent: 2 - - uid: 17213 - components: - - type: Transform - pos: 59.5,-40.5 - parent: 2 - uid: 17241 components: - type: Transform @@ -81309,6 +81766,23 @@ entities: parent: 2 - proto: GrilleDiagonal entities: + - uid: 1797 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,-45.5 + parent: 2 + - uid: 1798 + components: + - type: Transform + pos: 14.5,-39.5 + parent: 2 + - uid: 1799 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 14.5,-45.5 + parent: 2 - uid: 4656 components: - type: Transform @@ -81378,29 +81852,12 @@ entities: rot: -1.5707963267948966 rad pos: 25.5,-51.5 parent: 2 - - uid: 19070 + - uid: 14429 components: - type: Transform rot: -1.5707963267948966 rad pos: 20.5,-39.5 parent: 2 - - uid: 19088 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 14.5,-45.5 - parent: 2 - - uid: 19089 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,-45.5 - parent: 2 - - uid: 19090 - components: - - type: Transform - pos: 14.5,-39.5 - parent: 2 - proto: GrilleSpawner entities: - uid: 6412 @@ -81970,7 +82427,7 @@ entities: - uid: 13879 components: - type: Transform - pos: 62.5,-40.5 + pos: 61.49383,-42.487232 parent: 2 - uid: 19346 components: @@ -82027,7 +82484,7 @@ entities: - uid: 7218 components: - type: Transform - pos: 72.516365,-25.447449 + pos: 80.20865,-27.102425 parent: 2 - proto: HappyHonkMime entities: @@ -82697,7 +83154,7 @@ entities: - uid: 5182 components: - type: Transform - pos: -3.353551,-47.34583 + pos: -3.371653,-47.471542 parent: 2 - proto: IceCrust entities: @@ -84045,21 +84502,66 @@ entities: parent: 2 - proto: MaintenancePlantSpawner entities: + - uid: 2407 + components: + - type: Transform + pos: -16.5,-46.5 + parent: 2 + - uid: 7770 + components: + - type: Transform + pos: 6.5,-74.5 + parent: 2 + - uid: 12407 + components: + - type: Transform + pos: 6.5,-75.5 + parent: 2 - uid: 17240 components: - type: Transform pos: 75.5,-59.5 parent: 2 - - uid: 17242 - components: - - type: Transform - pos: 6.5,-79.5 - parent: 2 - uid: 17243 components: - type: Transform pos: -36.5,-72.5 parent: 2 + - uid: 17715 + components: + - type: Transform + pos: 6.5,-79.5 + parent: 2 + - uid: 19577 + components: + - type: Transform + pos: -9.5,-57.5 + parent: 2 + - uid: 19578 + components: + - type: Transform + pos: -47.5,-22.5 + parent: 2 + - uid: 19579 + components: + - type: Transform + pos: 54.5,-77.5 + parent: 2 + - uid: 19580 + components: + - type: Transform + pos: 50.5,-33.5 + parent: 2 + - uid: 19581 + components: + - type: Transform + pos: 76.5,-30.5 + parent: 2 + - uid: 19582 + components: + - type: Transform + pos: 75.5,-38.5 + parent: 2 - proto: MaintenanceToolSpawner entities: - uid: 7684 @@ -84173,7 +84675,7 @@ entities: - uid: 16376 components: - type: Transform - pos: 15.404405,-58.247597 + pos: 15.45371,-59.515717 parent: 2 - proto: MaterialCloth1 entities: @@ -84201,7 +84703,7 @@ entities: - uid: 16377 components: - type: Transform - pos: 15.690466,-58.495316 + pos: 13.287043,-58.162865 parent: 2 - proto: MaterialWebSilk1 entities: @@ -84230,6 +84732,11 @@ entities: - type: Transform pos: 69.52955,-67.498146 parent: 2 + - uid: 19587 + components: + - type: Transform + pos: 5.5,-79.5 + parent: 2 - proto: MaterialWoodPlank1 entities: - uid: 7336 @@ -84237,6 +84744,13 @@ entities: - type: Transform pos: 80.49108,-26.808891 parent: 2 +- proto: MaterialWoodPlank10 + entities: + - uid: 7461 + components: + - type: Transform + pos: 6.5,-76.5 + parent: 2 - proto: MedicalBed entities: - uid: 466 @@ -84622,7 +85136,7 @@ entities: - uid: 18174 components: - type: Transform - pos: -53.444557,-43.036716 + pos: -53.37472,-43.263702 parent: 2 - proto: MysteryFigureBox entities: @@ -85039,17 +85553,39 @@ entities: - uid: 19179 components: - type: Transform - pos: -48.143295,-45.120937 + pos: -48.52036,-46.15865 parent: 2 - uid: 19180 components: - type: Transform - pos: -47.81517,-45.324207 + pos: -48.3398,-46.283733 parent: 2 - uid: 19181 components: - type: Transform - pos: -48.09642,-45.73074 + pos: -48.47175,-46.374077 + parent: 2 + - uid: 19652 + components: + - type: Transform + pos: -47.56897,-44.41438 + parent: 2 + - uid: 19653 + components: + - type: Transform + pos: -47.437027,-44.581165 + parent: 2 + - uid: 19654 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -47.39536,-45.58186 + parent: 2 + - uid: 19655 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -48.55508,-44.581165 parent: 2 - proto: PaperBin10 entities: @@ -85092,17 +85628,17 @@ entities: - uid: 5487 components: - type: Transform - pos: -44.441452,-54.403904 + pos: -44.415276,-54.439785 parent: 2 - uid: 5488 components: - type: Transform - pos: -45.003952,-54.435177 + pos: -44.545387,-54.377243 parent: 2 - uid: 5489 components: - type: Transform - pos: -45.128952,-54.403904 + pos: -45.073162,-54.39809 parent: 2 - proto: PaperCNCSheet entities: @@ -85285,7 +85821,13 @@ entities: - uid: 19182 components: - type: Transform - pos: -48.237045,-46.090363 + pos: -48.624527,-46.49916 + parent: 2 + - uid: 19657 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -47.357563,-45.783386 parent: 2 - proto: PersonalAI entities: @@ -85319,6 +85861,13 @@ entities: - type: Transform pos: 9.692059,-84.39211 parent: 2 +- proto: PillCanisterPotassiumIodide + entities: + - uid: 19671 + components: + - type: Transform + pos: -52.315937,-52.474583 + parent: 2 - proto: PillSpaceDrugs entities: - uid: 18015 @@ -85397,6 +85946,12 @@ entities: rot: -1.5707963267948966 rad pos: -61.5,-63.5 parent: 2 + - uid: 9585 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-77.5 + parent: 2 - uid: 10826 components: - type: Transform @@ -85439,6 +85994,11 @@ entities: rot: -1.5707963267948966 rad pos: -59.5,-61.5 parent: 2 + - uid: 18339 + components: + - type: Transform + pos: 58.5,-20.5 + parent: 2 - uid: 19317 components: - type: Transform @@ -85624,6 +86184,12 @@ entities: parent: 2 - proto: PlasmaWindoorSecureScienceLocked entities: + - uid: 5117 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -23.5,-29.5 + parent: 2 - uid: 11364 components: - type: Transform @@ -85660,6 +86226,12 @@ entities: rot: 3.141592653589793 rad pos: 59.5,-55.5 parent: 2 + - uid: 18316 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 62.5,-20.5 + parent: 2 - proto: PlasmaWindow entities: - uid: 4020 @@ -86718,7 +87290,7 @@ entities: - uid: 19374 components: - type: Transform - pos: -22.293167,-52.05227 + pos: -22.231848,-52.133213 parent: 2 - proto: PowerCellPotato entities: @@ -86760,6 +87332,12 @@ entities: - type: Transform pos: 77.5,-21.5 parent: 2 + - uid: 14432 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -11.5,-18.5 + parent: 2 - uid: 18523 components: - type: Transform @@ -86777,6 +87355,17 @@ entities: rot: 3.141592653589793 rad pos: 29.5,-90.5 parent: 2 + - uid: 19595 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 62.5,-40.5 + parent: 2 + - uid: 19672 + components: + - type: Transform + pos: -53.5,-42.5 + parent: 2 - proto: PowerComputerCircuitboard entities: - uid: 18307 @@ -87184,12 +87773,6 @@ entities: - type: Transform pos: 56.5,-48.5 parent: 2 - - uid: 9585 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -13.5,-55.5 - parent: 2 - uid: 9678 components: - type: Transform @@ -87315,12 +87898,6 @@ entities: rot: 3.141592653589793 rad pos: 45.5,-73.5 parent: 2 - - uid: 11956 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 62.5,-21.5 - parent: 2 - uid: 12786 components: - type: Transform @@ -88960,11 +89537,6 @@ entities: rot: -1.5707963267948966 rad pos: -27.5,-53.5 parent: 2 - - uid: 18145 - components: - - type: Transform - pos: -16.5,-52.5 - parent: 2 - uid: 18146 components: - type: Transform @@ -89186,6 +89758,22 @@ entities: rot: 3.141592653589793 rad pos: 47.5,-72.5 parent: 2 + - uid: 19538 + components: + - type: Transform + pos: -17.5,-53.5 + parent: 2 + - uid: 19576 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -14.5,-51.5 + parent: 2 + - uid: 19644 + components: + - type: Transform + pos: 62.5,-20.5 + parent: 2 - proto: PoweredlightExterior entities: - uid: 3206 @@ -89386,6 +89974,30 @@ entities: rot: -1.5707963267948966 rad pos: 7.5,-41.5 parent: 2 + - uid: 19596 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,-38.5 + parent: 2 + - uid: 19598 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,-46.5 + parent: 2 + - uid: 19599 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 21.5,-38.5 + parent: 2 + - uid: 19600 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 21.5,-46.5 + parent: 2 - proto: PoweredLightPostSmall entities: - uid: 235 @@ -90237,6 +90849,12 @@ entities: rot: 1.5707963267948966 rad pos: 8.5,-90.5 parent: 2 + - uid: 18401 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -12.5,-56.5 + parent: 2 - uid: 19030 components: - type: Transform @@ -90307,11 +90925,17 @@ entities: parent: 2 - proto: Protolathe entities: - - uid: 8016 + - uid: 19088 components: - type: Transform - pos: -3.5,-19.5 + pos: -4.5,-19.5 parent: 2 + - type: TechnologyDatabase + supportedDisciplines: + - Industrial + - Arsenal + - Experimental + - CivilianServices - proto: ProximitySensor entities: - uid: 4726 @@ -90319,13 +90943,6 @@ entities: - type: Transform pos: 69.654045,-72.594284 parent: 2 -- proto: Puddle - entities: - - uid: 16818 - components: - - type: Transform - pos: 79.5,-29.5 - parent: 2 - proto: PuddleBlood entities: - uid: 1197 @@ -90333,6 +90950,41 @@ entities: - type: Transform pos: 42.5,-28.5 parent: 2 + - uid: 1856 + components: + - type: Transform + pos: 79.5,-29.5 + parent: 2 + - uid: 5083 + components: + - type: Transform + pos: 74.5,-43.5 + parent: 2 + - uid: 5100 + components: + - type: Transform + pos: 75.5,-25.5 + parent: 2 + - uid: 5101 + components: + - type: Transform + pos: 74.5,-42.5 + parent: 2 + - uid: 5426 + components: + - type: Transform + pos: 79.5,-30.5 + parent: 2 + - uid: 5460 + components: + - type: Transform + pos: 75.5,-23.5 + parent: 2 + - uid: 6244 + components: + - type: Transform + pos: 75.5,-24.5 + parent: 2 - uid: 6711 components: - type: Transform @@ -90493,43 +91145,23 @@ entities: - type: Transform pos: 56.5,-48.5 parent: 2 -- proto: PuddleBloodSmall - entities: - - uid: 1797 + - uid: 19552 components: - type: Transform - pos: 75.5,-23.5 + pos: 74.5,-41.5 parent: 2 +- proto: PuddleBloodSmall + entities: - uid: 7101 components: - type: Transform pos: 74.5,-46.5 parent: 2 - - uid: 7264 - components: - - type: Transform - pos: 75.5,-25.5 - parent: 2 - uid: 8141 components: - type: Transform pos: 77.5,-55.5 parent: 2 - - uid: 13942 - components: - - type: Transform - pos: 74.5,-43.5 - parent: 2 - - uid: 16052 - components: - - type: Transform - pos: 74.5,-42.5 - parent: 2 - - uid: 16098 - components: - - type: Transform - pos: 74.5,-41.5 - parent: 2 - uid: 16810 components: - type: Transform @@ -90660,11 +91292,6 @@ entities: - type: Transform pos: 24.5,-27.5 parent: 2 - - uid: 17968 - components: - - type: Transform - pos: 75.5,-24.5 - parent: 2 - uid: 18023 components: - type: Transform @@ -90690,6 +91317,21 @@ entities: - type: Transform pos: 54.5,-50.5 parent: 2 + - uid: 19553 + components: + - type: Transform + pos: 76.5,-41.5 + parent: 2 + - uid: 19554 + components: + - type: Transform + pos: 76.5,-27.5 + parent: 2 + - uid: 19555 + components: + - type: Transform + pos: 74.5,-23.5 + parent: 2 - proto: PuddleFluorosulfuricAcid entities: - uid: 7934 @@ -91498,12 +92140,6 @@ entities: rot: 1.5707963267948966 rad pos: -14.5,-17.5 parent: 2 - - uid: 2501 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 17.5,-83.5 - parent: 2 - uid: 13891 components: - type: Transform @@ -91528,11 +92164,6 @@ entities: - type: Transform pos: 10.5,-40.5 parent: 2 - - uid: 14139 - components: - - type: Transform - pos: -19.5,-32.5 - parent: 2 - uid: 18376 components: - type: Transform @@ -91715,6 +92346,16 @@ entities: - type: Transform pos: -2.5,-45.5 parent: 2 + - uid: 19588 + components: + - type: Transform + pos: 4.5,-78.5 + parent: 2 + - uid: 19589 + components: + - type: Transform + pos: -0.5,-75.5 + parent: 2 - proto: RandomInstruments entities: - uid: 2249 @@ -91813,11 +92454,6 @@ entities: - type: Transform pos: 48.5,-16.5 parent: 2 - - uid: 19044 - components: - - type: Transform - pos: 9.5,-46.5 - parent: 2 - uid: 19212 components: - type: Transform @@ -91833,6 +92469,11 @@ entities: - type: Transform pos: 17.5,-14.5 parent: 2 + - uid: 19622 + components: + - type: Transform + pos: 10.5,-46.5 + parent: 2 - proto: RandomProduce entities: - uid: 3426 @@ -92162,11 +92803,6 @@ entities: - type: Transform pos: -23.5,-32.5 parent: 2 - - uid: 185 - components: - - type: Transform - pos: -23.5,-29.5 - parent: 2 - uid: 191 components: - type: Transform @@ -92212,26 +92848,6 @@ entities: - type: Transform pos: -20.5,-29.5 parent: 2 - - uid: 562 - components: - - type: Transform - pos: 14.5,-40.5 - parent: 2 - - uid: 563 - components: - - type: Transform - pos: 16.5,-39.5 - parent: 2 - - uid: 568 - components: - - type: Transform - pos: 15.5,-39.5 - parent: 2 - - uid: 581 - components: - - type: Transform - pos: 17.5,-39.5 - parent: 2 - uid: 804 components: - type: Transform @@ -92272,71 +92888,6 @@ entities: - type: Transform pos: -17.5,-31.5 parent: 2 - - uid: 1645 - components: - - type: Transform - pos: 18.5,-45.5 - parent: 2 - - uid: 1646 - components: - - type: Transform - pos: 20.5,-41.5 - parent: 2 - - uid: 1647 - components: - - type: Transform - pos: 20.5,-44.5 - parent: 2 - - uid: 1648 - components: - - type: Transform - pos: 17.5,-45.5 - parent: 2 - - uid: 1667 - components: - - type: Transform - pos: 19.5,-45.5 - parent: 2 - - uid: 1668 - components: - - type: Transform - pos: 20.5,-40.5 - parent: 2 - - uid: 1688 - components: - - type: Transform - pos: 14.5,-41.5 - parent: 2 - - uid: 1692 - components: - - type: Transform - pos: 14.5,-44.5 - parent: 2 - - uid: 1696 - components: - - type: Transform - pos: 14.5,-43.5 - parent: 2 - - uid: 1731 - components: - - type: Transform - pos: 19.5,-39.5 - parent: 2 - - uid: 1798 - components: - - type: Transform - pos: 20.5,-43.5 - parent: 2 - - uid: 1799 - components: - - type: Transform - pos: 15.5,-45.5 - parent: 2 - - uid: 1802 - components: - - type: Transform - pos: 18.5,-39.5 - parent: 2 - uid: 2617 components: - type: Transform @@ -92452,22 +93003,31 @@ entities: - type: Transform pos: -17.5,-30.5 parent: 2 + - uid: 6248 + components: + - type: Transform + pos: 17.5,-39.5 + parent: 2 - uid: 6644 components: - type: Transform pos: 8.5,-51.5 parent: 2 - - uid: 6916 + - uid: 6902 components: - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,-42.5 + pos: 19.5,-39.5 parent: 2 - uid: 7066 components: - type: Transform pos: 6.5,-48.5 parent: 2 + - uid: 7099 + components: + - type: Transform + pos: 20.5,-40.5 + parent: 2 - uid: 7444 components: - type: Transform @@ -92528,26 +93088,91 @@ entities: - type: Transform pos: -25.5,-72.5 parent: 2 - - uid: 11402 + - uid: 11403 components: - type: Transform - pos: 16.5,-45.5 + pos: 16.5,-39.5 + parent: 2 + - uid: 13942 + components: + - type: Transform + pos: 15.5,-39.5 + parent: 2 + - uid: 14024 + components: + - type: Transform + pos: 20.5,-41.5 + parent: 2 + - uid: 14053 + components: + - type: Transform + pos: 14.5,-44.5 + parent: 2 + - uid: 14241 + components: + - type: Transform + pos: 18.5,-39.5 + parent: 2 + - uid: 14435 + components: + - type: Transform + pos: 14.5,-41.5 + parent: 2 + - uid: 14436 + components: + - type: Transform + pos: 20.5,-44.5 + parent: 2 + - uid: 14437 + components: + - type: Transform + pos: 18.5,-45.5 + parent: 2 + - uid: 16052 + components: + - type: Transform + pos: 20.5,-43.5 + parent: 2 + - uid: 16097 + components: + - type: Transform + pos: 17.5,-45.5 + parent: 2 + - uid: 16170 + components: + - type: Transform + pos: 14.5,-40.5 parent: 2 - uid: 16466 components: - type: Transform pos: -17.5,-33.5 parent: 2 + - uid: 16521 + components: + - type: Transform + pos: 15.5,-45.5 + parent: 2 - uid: 16620 components: - type: Transform pos: 27.5,-65.5 parent: 2 + - uid: 16875 + components: + - type: Transform + pos: 20.5,-42.5 + parent: 2 - uid: 17373 components: - type: Transform pos: -17.5,-32.5 parent: 2 + - uid: 17968 + components: + - type: Transform + pos: 14.5,-43.5 + parent: 2 - uid: 18152 components: - type: Transform @@ -92558,6 +93183,11 @@ entities: - type: Transform pos: 44.5,-62.5 parent: 2 + - uid: 18331 + components: + - type: Transform + pos: 62.5,-21.5 + parent: 2 - uid: 18367 components: - type: Transform @@ -92583,8 +93213,24 @@ entities: - type: Transform pos: 36.5,-62.5 parent: 2 + - uid: 19070 + components: + - type: Transform + pos: 19.5,-45.5 + parent: 2 + - uid: 19569 + components: + - type: Transform + pos: 16.5,-45.5 + parent: 2 - proto: ReinforcedPlasmaWindowDiagonal entities: + - uid: 1731 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,-45.5 + parent: 2 - uid: 4654 components: - type: Transform @@ -92654,52 +93300,100 @@ entities: - type: Transform pos: 23.5,-51.5 parent: 2 - - uid: 10446 + - uid: 6916 components: - type: Transform rot: -1.5707963267948966 rad pos: 20.5,-39.5 parent: 2 - - uid: 10447 + - uid: 14034 components: - type: Transform pos: 14.5,-39.5 parent: 2 - - uid: 13978 - components: - - type: Transform - pos: 19.5,-44.5 - parent: 2 - - uid: 14025 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 15.5,-40.5 - parent: 2 - - uid: 14047 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 19.5,-40.5 - parent: 2 - - uid: 14056 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 15.5,-44.5 - parent: 2 - - uid: 14432 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,-45.5 - parent: 2 - - uid: 14433 + - uid: 14035 components: - type: Transform rot: 1.5707963267948966 rad pos: 14.5,-45.5 parent: 2 +- proto: ReinforcedUraniumWindow + entities: + - uid: 7264 + components: + - type: Transform + pos: 19.5,-41.5 + parent: 2 + - uid: 8016 + components: + - type: Transform + pos: 16.5,-40.5 + parent: 2 + - uid: 10446 + components: + - type: Transform + pos: 19.5,-40.5 + parent: 2 + - uid: 10447 + components: + - type: Transform + pos: 19.5,-43.5 + parent: 2 + - uid: 10774 + components: + - type: Transform + pos: 19.5,-42.5 + parent: 2 + - uid: 11402 + components: + - type: Transform + pos: 15.5,-40.5 + parent: 2 + - uid: 13274 + components: + - type: Transform + pos: 17.5,-44.5 + parent: 2 + - uid: 13452 + components: + - type: Transform + pos: 16.5,-44.5 + parent: 2 + - uid: 13978 + components: + - type: Transform + pos: 18.5,-40.5 + parent: 2 + - uid: 14005 + components: + - type: Transform + pos: 18.5,-44.5 + parent: 2 + - uid: 14025 + components: + - type: Transform + pos: 17.5,-40.5 + parent: 2 + - uid: 14029 + components: + - type: Transform + pos: 19.5,-44.5 + parent: 2 + - uid: 14047 + components: + - type: Transform + pos: 15.5,-41.5 + parent: 2 + - uid: 15698 + components: + - type: Transform + pos: 15.5,-44.5 + parent: 2 + - uid: 17173 + components: + - type: Transform + pos: 15.5,-43.5 + parent: 2 - proto: ReinforcedWindow entities: - uid: 79 @@ -93215,7 +93909,7 @@ entities: - uid: 6095 components: - type: Transform - pos: 60.5,-21.5 + pos: 64.5,-21.5 parent: 2 - uid: 6857 components: @@ -93267,11 +93961,6 @@ entities: - type: Transform pos: 61.5,-45.5 parent: 2 - - uid: 7206 - components: - - type: Transform - pos: 64.5,-21.5 - parent: 2 - uid: 7278 components: - type: Transform @@ -93362,11 +94051,6 @@ entities: - type: Transform pos: 61.5,-18.5 parent: 2 - - uid: 15470 - components: - - type: Transform - pos: 59.5,-40.5 - parent: 2 - uid: 16349 components: - type: Transform @@ -93855,6 +94539,13 @@ entities: - type: Transform pos: 51.5,-17.5 parent: 2 +- proto: SeedExtractorMachineCircuitboard + entities: + - uid: 19583 + components: + - type: Transform + pos: 4.635383,-79.48305 + parent: 2 - proto: ShardCrystalRandom entities: - uid: 15273 @@ -93877,7 +94568,7 @@ entities: - uid: 17021 components: - type: Transform - pos: 4.3700624,-79.34264 + pos: 4.3205686,-79.307 parent: 2 - uid: 19233 components: @@ -93957,11 +94648,11 @@ entities: - type: Transform pos: -12.6246805,-71.2753 parent: 2 - - uid: 14241 + - uid: 14433 components: - type: Transform rot: 3.141592653589793 rad - pos: -11.485548,-18.454052 + pos: -15.5,-18.5 parent: 2 - proto: SheetPlasma1 entities: @@ -94037,6 +94728,11 @@ entities: - type: Transform pos: 32.586887,-61.429493 parent: 2 + - uid: 19603 + components: + - type: Transform + pos: 45.393383,-73.1507 + parent: 2 - proto: SheetRGlass1 entities: - uid: 18778 @@ -94056,12 +94752,12 @@ entities: - uid: 1882 components: - type: Transform - pos: 46.418232,-73.38268 + pos: 46.415913,-73.32666 parent: 2 - uid: 3341 components: - type: Transform - pos: 46.615986,-73.28868 + pos: 46.594925,-73.20312 parent: 2 - uid: 6671 components: @@ -94091,12 +94787,12 @@ entities: - uid: 13337 components: - type: Transform - pos: -5.400783,-19.33013 + pos: -3.438326,-19.436022 parent: 2 - uid: 13646 components: - type: Transform - pos: 45.610485,-73.26664 + pos: 45.696777,-73.20621 parent: 2 - uid: 17911 components: @@ -95546,13 +96242,13 @@ entities: parent: 2 - type: DeviceLinkSource linkedPorts: - 5029: + 2501: - - Pressed - Toggle - 5030: + 1341: - - Pressed - Toggle - 5031: + 313: - - Pressed - Toggle - uid: 17829 @@ -95813,6 +96509,70 @@ entities: 18213: - - Pressed - Toggle + - uid: 19574 + components: + - type: Transform + pos: 13.5,-41.5 + parent: 2 + - type: DeviceLinkSource + linkedPorts: + 19575: + - - Pressed + - Toggle + 19564: + - - Pressed + - Toggle + 19560: + - - Pressed + - Toggle + 19559: + - - Pressed + - Toggle + 19558: + - - Pressed + - Toggle + 19557: + - - Pressed + - Toggle + 19556: + - - Pressed + - Toggle + 16098: + - - Pressed + - Toggle + 19563: + - - Pressed + - Toggle + 19561: + - - Pressed + - Toggle + 19572: + - - Pressed + - Toggle + 19562: + - - Pressed + - Toggle + 19571: + - - Pressed + - Toggle + 19566: + - - Pressed + - Toggle + 19567: + - - Pressed + - Toggle + 19568: + - - Pressed + - Toggle + 19570: + - - Pressed + - Toggle + 19565: + - - Pressed + - Toggle + 14056: + - - Pressed + - Toggle - proto: SignAnomaly entities: - uid: 16210 @@ -95963,6 +96723,11 @@ entities: rot: -1.5707963267948966 rad pos: 16.5,-70.5 parent: 2 + - uid: 14139 + components: + - type: Transform + pos: -0.5,-58.5 + parent: 2 - uid: 16179 components: - type: Transform @@ -95974,11 +96739,6 @@ entities: - type: Transform pos: 20.5,-25.5 parent: 2 - - uid: 18315 - components: - - type: Transform - pos: -0.5,-58.5 - parent: 2 - uid: 19281 components: - type: Transform @@ -95999,6 +96759,13 @@ entities: - type: Transform pos: 4.5,-2.5 parent: 2 +- proto: SignCryogenicsMed + entities: + - uid: 3832 + components: + - type: Transform + pos: -3.5,-50.5 + parent: 2 - proto: SignDirectionalAtmos entities: - uid: 9434 @@ -96007,18 +96774,18 @@ entities: rot: 3.141592653589793 rad pos: -15.498708,-51.71671 parent: 2 + - uid: 16151 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5008106,-33.718235 + parent: 2 - uid: 17980 components: - type: Transform rot: 1.5707963267948966 rad pos: -11.500819,-41.285877 parent: 2 - - uid: 17981 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,-33.5 - parent: 2 - uid: 17982 components: - type: Transform @@ -96035,11 +96802,11 @@ entities: rot: 1.5707963267948966 rad pos: -23.5,-54.5 parent: 2 - - uid: 17987 + - uid: 19621 components: - type: Transform rot: 1.5707963267948966 rad - pos: 6.4997983,-55.716797 + pos: 12.5,-51.5 parent: 2 - proto: SignDirectionalBar entities: @@ -96075,12 +96842,6 @@ entities: rot: -1.5707963267948966 rad pos: 18.49973,-51.71622 parent: 2 - - uid: 16180 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.4990706,-55.28383 - parent: 2 - uid: 16185 components: - type: Transform @@ -96092,6 +96853,32 @@ entities: - type: Transform pos: -30.5,-18.5 parent: 2 + - uid: 19629 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-51.5 + parent: 2 + - uid: 19631 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5013075,-33.288094 + parent: 2 +- proto: SignDirectionalBrig + entities: + - uid: 19645 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 61.5,-40.5 + parent: 2 + - uid: 19648 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 61.5,-31.5 + parent: 2 - proto: SignDirectionalChapel entities: - uid: 12824 @@ -96124,16 +96911,16 @@ entities: - type: Transform pos: 22.5,-59.5 parent: 2 + - uid: 16127 + components: + - type: Transform + pos: 6.5,-55.5 + parent: 2 - uid: 16134 components: - type: Transform pos: 2.498827,-33.284237 parent: 2 - - uid: 16151 - components: - - type: Transform - pos: 7.5,-51.5 - parent: 2 - proto: SignDirectionalCryo entities: - uid: 16159 @@ -96142,6 +96929,12 @@ entities: rot: 3.141592653589793 rad pos: 22.5,-47.5 parent: 2 + - uid: 16180 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.50015,-51.284824 + parent: 2 - uid: 17820 components: - type: Transform @@ -96186,6 +96979,12 @@ entities: rot: 1.5707963267948966 rad pos: -26.501791,-54.716873 parent: 2 + - uid: 14808 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,-33.5 + parent: 2 - uid: 15613 components: - type: Transform @@ -96218,11 +97017,16 @@ entities: rot: -1.5707963267948966 rad pos: 17.5,-80.5 parent: 2 - - uid: 17984 + - uid: 19632 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5003753,-33.716583 + pos: -15.5013685,-35.71809 + parent: 2 + - uid: 19633 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.50085,-51.716766 parent: 2 - proto: SignDirectionalEvac entities: @@ -96238,36 +97042,18 @@ entities: rot: -1.5707963267948966 rad pos: 62.5,-22.5 parent: 2 - - uid: 4068 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 51.5,-25.5 - parent: 2 - uid: 4358 components: - type: Transform rot: 3.141592653589793 rad pos: 64.5,-54.5 parent: 2 - - uid: 4557 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,-29.5 - parent: 2 - uid: 5213 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5015326,-8.71623 parent: 2 - - uid: 6847 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,-55.5 - parent: 2 - uid: 7888 components: - type: Transform @@ -96361,17 +97147,23 @@ entities: rot: 3.141592653589793 rad pos: -30.5,-15.5 parent: 2 + - uid: 16155 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 37.5,-32.5 + parent: 2 - uid: 16162 components: - type: Transform rot: -1.5707963267948966 rad pos: 18.49889,-51.283894 parent: 2 - - uid: 16163 + - uid: 16168 components: - type: Transform - rot: 3.141592653589793 rad - pos: 22.500296,-33.285934 + rot: -1.5707963267948966 rad + pos: 22.50092,-33.28325 parent: 2 - uid: 16174 components: @@ -96379,11 +97171,11 @@ entities: rot: 3.141592653589793 rad pos: 10.5,-64.5 parent: 2 - - uid: 16178 + - uid: 16177 components: - type: Transform rot: 3.141592653589793 rad - pos: 26.5,-75.5 + pos: 26.501543,-75.28514 parent: 2 - uid: 17221 components: @@ -96397,6 +97189,12 @@ entities: rot: -1.5707963267948966 rad pos: -15.499661,-41.28664 parent: 2 + - uid: 17707 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5012491,-29.285704 + parent: 2 - uid: 17809 components: - type: Transform @@ -96420,6 +97218,11 @@ entities: - type: Transform pos: -5.5,-4.5 parent: 2 + - uid: 18315 + components: + - type: Transform + pos: 43.5,-27.5 + parent: 2 - uid: 19406 components: - type: Transform @@ -96437,6 +97240,23 @@ entities: rot: -1.5707963267948966 rad pos: 7.5003424,-8.714865 parent: 2 + - uid: 19630 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.498548,-51.284073 + parent: 2 + - uid: 19637 + components: + - type: Transform + pos: -5.5,-0.5 + parent: 2 + - uid: 19642 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 57.5,-25.5 + parent: 2 - proto: SignDirectionalFood entities: - uid: 5177 @@ -96456,17 +97276,23 @@ entities: rot: 1.5707963267948966 rad pos: 1.4994224,-33.283478 parent: 2 - - uid: 16177 + - uid: 16176 components: - type: Transform rot: 3.141592653589793 rad - pos: 26.499176,-75.28583 + pos: 26.5,-75.5 parent: 2 - uid: 18204 components: - type: Transform pos: 22.498983,-37.717163 parent: 2 + - uid: 19636 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 12.499051,-51.286167 + parent: 2 - proto: SignDirectionalHop entities: - uid: 16132 @@ -96517,10 +97343,10 @@ entities: rot: -1.5707963267948966 rad pos: 3.500022,-33.28552 parent: 2 - - uid: 16168 + - uid: 17078 components: - type: Transform - pos: -1.5000485,-12.718935 + pos: -1.4999341,-15.283161 parent: 2 - proto: SignDirectionalLibrary entities: @@ -96529,10 +97355,10 @@ entities: - type: Transform pos: 3.4989862,-33.716446 parent: 2 - - uid: 16155 + - uid: 16163 components: - type: Transform - pos: 7.500051,-51.71732 + pos: 6.499085,-55.716106 parent: 2 - proto: SignDirectionalMed entities: @@ -96553,11 +97379,6 @@ entities: rot: 1.5707963267948966 rad pos: -26.499496,-33.717285 parent: 2 - - uid: 16127 - components: - - type: Transform - pos: -1.500161,-15.284051 - parent: 2 - uid: 16160 components: - type: Transform @@ -96570,17 +97391,34 @@ entities: rot: -1.5707963267948966 rad pos: 22.5,-33.5 parent: 2 + - uid: 16178 + components: + - type: Transform + pos: -1.4999341,-12.716049 + parent: 2 - uid: 17821 components: - type: Transform pos: 22.5,-27.5 parent: 2 + - uid: 17984 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,-51.5 + parent: 2 - uid: 18201 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5010014,-69.072586 parent: 2 + - uid: 19639 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -22.499754,-10.717974 + parent: 2 - proto: SignDirectionalSalvage entities: - uid: 16209 @@ -96601,7 +97439,13 @@ entities: components: - type: Transform rot: 3.141592653589793 rad - pos: 1.5014317,-29.285109 + pos: 7.50015,-51.71722 + parent: 2 + - uid: 16156 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-29.5 parent: 2 - uid: 16157 components: @@ -96657,20 +97501,32 @@ entities: - type: Transform pos: -1.5,-15.5 parent: 2 - - uid: 16176 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.499176,-75.71822 - parent: 2 - uid: 17813 components: - type: Transform rot: 1.5707963267948966 rad pos: -11.499488,-41.71687 parent: 2 + - uid: 17922 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.500002,-75.714455 + parent: 2 + - uid: 19635 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 12.499051,-51.718567 + parent: 2 - proto: SignDirectionalSolar entities: + - uid: 6847 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,-32.5 + parent: 2 - uid: 6964 components: - type: Transform @@ -96748,12 +97604,6 @@ entities: rot: 3.141592653589793 rad pos: 45.5,-30.5 parent: 2 - - uid: 17078 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 46.5,-24.5 - parent: 2 - uid: 17814 components: - type: Transform @@ -96793,6 +97643,12 @@ entities: rot: -1.5707963267948966 rad pos: -30.500843,-58.713875 parent: 2 + - uid: 19643 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 45.5,-24.5 + parent: 2 - proto: SignDirectionalSupply entities: - uid: 16112 @@ -96816,11 +97672,6 @@ entities: rot: 1.5707963267948966 rad pos: -26.501286,-54.50067 parent: 2 - - uid: 16156 - components: - - type: Transform - pos: 7.49974,-51.2822 - parent: 2 - uid: 17364 components: - type: Transform @@ -96844,6 +97695,11 @@ entities: - type: Transform pos: 12.5,-75.5 parent: 2 + - uid: 19634 + components: + - type: Transform + pos: 6.499085,-55.283707 + parent: 2 - proto: SignDisposalSpace entities: - uid: 15409 @@ -96956,6 +97812,19 @@ entities: - type: Transform pos: 3.5,-17.5 parent: 2 +- proto: SignExamroom + entities: + - uid: 5207 + components: + - type: Transform + pos: 11.5,-70.5 + parent: 2 + - uid: 19649 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 57.5,-30.5 + parent: 2 - proto: SignGravity entities: - uid: 16203 @@ -96980,16 +97849,16 @@ entities: parent: 2 - proto: SignHydro1 entities: + - uid: 17987 + components: + - type: Transform + pos: 38.5,-47.5 + parent: 2 - uid: 18313 components: - type: Transform pos: 14.5,-64.5 parent: 2 - - uid: 18331 - components: - - type: Transform - pos: 38.5,-47.5 - parent: 2 - proto: SignInterrogation entities: - uid: 6125 @@ -97008,7 +97877,7 @@ entities: parent: 2 - proto: SignKitchen entities: - - uid: 18316 + - uid: 18300 components: - type: Transform pos: 1.5,-51.5 @@ -97058,11 +97927,6 @@ entities: parent: 2 - proto: SignMedical entities: - - uid: 17922 - components: - - type: Transform - pos: 6.5,-33.5 - parent: 2 - uid: 17923 components: - type: Transform @@ -97073,6 +97937,11 @@ entities: - type: Transform pos: 18.5,-64.5 parent: 2 + - uid: 19638 + components: + - type: Transform + pos: 7.5,-29.5 + parent: 2 - proto: SignMorgue entities: - uid: 924 @@ -97316,6 +98185,18 @@ entities: rot: 3.141592653589793 rad pos: 41.5,-22.5 parent: 2 + - uid: 17981 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 60.5,-22.5 + parent: 2 + - uid: 18145 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -11.5,-55.5 + parent: 2 - uid: 18361 components: - type: Transform @@ -97361,6 +98242,20 @@ entities: - type: Transform pos: 64.5,-26.5 parent: 2 +- proto: SignShipDock + entities: + - uid: 19640 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -30.5,-9.5 + parent: 2 + - uid: 19641 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -38.5,-9.5 + parent: 2 - proto: SignShock entities: - uid: 11726 @@ -97534,6 +98429,12 @@ entities: rot: 3.141592653589793 rad pos: -6.5,-26.5 parent: 2 + - uid: 19090 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,-25.5 + parent: 2 - proto: SmartFridge entities: - uid: 13948 @@ -98346,6 +99247,11 @@ entities: - type: Transform pos: 18.5,-66.5 parent: 2 + - uid: 19620 + components: + - type: Transform + pos: 19.5,-66.5 + parent: 2 - proto: SpawnPointChiefEngineer entities: - uid: 15316 @@ -98590,6 +99496,11 @@ entities: - type: Transform pos: -21.5,-25.5 parent: 2 + - uid: 19618 + components: + - type: Transform + pos: -12.5,-26.5 + parent: 2 - proto: SpawnPointSecurityCadet entities: - uid: 19059 @@ -98673,6 +99584,11 @@ entities: - type: Transform pos: -14.5,-59.5 parent: 2 + - uid: 19619 + components: + - type: Transform + pos: -15.5,-60.5 + parent: 2 - proto: SpawnPointTechnicalAssistant entities: - uid: 15320 @@ -100143,6 +101059,28 @@ entities: - SurveillanceCameraEngineering nameSet: True id: Singularity Chamber, South + - uid: 19607 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 53.5,-65.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraEngineering + nameSet: True + id: Burn Chamber Entrance + - uid: 19609 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -14.5,-70.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraEngineering + nameSet: True + id: Singularity Chamber, Entrance - proto: SurveillanceCameraGeneral entities: - uid: 3912 @@ -100521,6 +101459,17 @@ entities: - SurveillanceCameraGeneral nameSet: True id: Engineering Hallway + - uid: 19608 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-55.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraGeneral + nameSet: True + id: HoP Hallway - proto: SurveillanceCameraMedical entities: - uid: 17592 @@ -100618,6 +101567,27 @@ entities: - SurveillanceCameraMedical nameSet: True id: Medical Outpost + - uid: 19022 + components: + - type: Transform + pos: 31.5,-29.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraMedical + nameSet: True + id: Morgue + - uid: 19606 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,-30.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraMedical + nameSet: True + id: Medical Bay - proto: SurveillanceCameraRouterCommand entities: - uid: 15917 @@ -100951,16 +101921,6 @@ entities: - SurveillanceCameraService nameSet: True id: Freezer - - uid: 17476 - components: - - type: Transform - pos: -55.5,-63.5 - parent: 2 - - type: SurveillanceCamera - setupAvailableNetworks: - - SurveillanceCameraService - nameSet: True - id: Clown & Mime Rooms - uid: 17596 components: - type: Transform @@ -101057,19 +102017,19 @@ entities: - SurveillanceCameraService nameSet: True id: Chaplain's Room -- proto: SurveillanceCameraSupply - entities: - - uid: 3832 + - uid: 19605 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 17.5,-98.5 + rot: 3.141592653589793 rad + pos: -58.5,-61.5 parent: 2 - type: SurveillanceCamera setupAvailableNetworks: - - SurveillanceCameraSupply + - SurveillanceCameraService nameSet: True - id: Cargo Dock, West + id: Clown & Mime Rooms +- proto: SurveillanceCameraSupply + entities: - uid: 4688 components: - type: Transform @@ -101156,6 +102116,17 @@ entities: - SurveillanceCameraSupply nameSet: True id: Cargo Employee Entrance + - uid: 19023 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 17.5,-92.5 + parent: 2 + - type: SurveillanceCamera + setupAvailableNetworks: + - SurveillanceCameraSupply + nameSet: True + id: Cargo Delivery Conveyors - uid: 19092 components: - type: Transform @@ -101217,6 +102188,11 @@ entities: - type: Transform pos: 83.72667,-72.569664 parent: 2 + - uid: 19675 + components: + - type: Transform + pos: -42.356354,-52.532303 + parent: 2 - proto: Syringe entities: - uid: 5220 @@ -101276,6 +102252,12 @@ entities: - type: Transform pos: 57.5,-28.5 parent: 2 + - uid: 1802 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,-19.5 + parent: 2 - uid: 2533 components: - type: Transform @@ -101406,11 +102388,6 @@ entities: - type: Transform pos: 32.5,-41.5 parent: 2 - - uid: 5083 - components: - - type: Transform - pos: -5.5,-19.5 - parent: 2 - uid: 5116 components: - type: Transform @@ -101902,11 +102879,6 @@ entities: - type: Transform pos: 11.5,-77.5 parent: 2 - - uid: 19367 - components: - - type: Transform - pos: -19.5,-49.5 - parent: 2 - proto: TableCarpet entities: - uid: 4876 @@ -102601,12 +103573,6 @@ entities: - type: Transform pos: -56.5,-28.5 parent: 2 - - uid: 7456 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 15.5,-58.5 - parent: 2 - uid: 7658 components: - type: Transform @@ -102717,6 +103683,12 @@ entities: - type: Transform pos: -56.5,-29.5 parent: 2 + - uid: 17476 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 59.5,-40.5 + parent: 2 - uid: 17662 components: - type: Transform @@ -102907,6 +103879,11 @@ entities: - type: Transform pos: -21.5,-46.5 parent: 2 + - uid: 19674 + components: + - type: Transform + pos: -42.5,-52.5 + parent: 2 - proto: TableXeno entities: - uid: 486 @@ -103607,7 +104584,7 @@ entities: - uid: 19370 components: - type: Transform - pos: -19.419056,-49.5568 + pos: -22.592426,-51.68456 parent: 2 - proto: ToolboxElectricalFilled entities: @@ -103663,7 +104640,7 @@ entities: - uid: 5738 components: - type: Transform - pos: -19.65343,-49.29099 + pos: -22.350601,-49.183464 parent: 2 - uid: 17023 components: @@ -103697,12 +104674,12 @@ entities: - uid: 5642 components: - type: Transform - pos: -22.663105,-51.29238 + pos: -22.536871,-51.17958 parent: 2 - uid: 5643 components: - type: Transform - pos: -22.350605,-51.495647 + pos: -22.379463,-51.43902 parent: 2 - uid: 5912 components: @@ -103781,7 +104758,7 @@ entities: - uid: 19391 components: - type: Transform - pos: -21.504704,-26.468311 + pos: -18.517744,-31.41124 parent: 2 - proto: ToyFigurineQueen entities: @@ -104213,92 +105190,6 @@ entities: - type: Transform pos: 9.660529,-25.157125 parent: 2 -- proto: UraniumWindow - entities: - - uid: 6902 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-42.5 - parent: 2 - - uid: 11403 - components: - - type: Transform - pos: 16.5,-40.5 - parent: 2 - - uid: 13274 - components: - - type: Transform - pos: 15.5,-41.5 - parent: 2 - - uid: 14005 - components: - - type: Transform - pos: 15.5,-43.5 - parent: 2 - - uid: 14024 - components: - - type: Transform - pos: 17.5,-40.5 - parent: 2 - - uid: 14029 - components: - - type: Transform - pos: 16.5,-44.5 - parent: 2 - - uid: 14034 - components: - - type: Transform - pos: 17.5,-44.5 - parent: 2 - - uid: 14035 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-41.5 - parent: 2 - - uid: 14053 - components: - - type: Transform - pos: 18.5,-44.5 - parent: 2 - - uid: 16875 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-43.5 - parent: 2 - - uid: 17173 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,-40.5 - parent: 2 -- proto: UraniumWindowDiagonal - entities: - - uid: 14429 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 15.5,-44.5 - parent: 2 - - uid: 14435 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,-44.5 - parent: 2 - - uid: 14436 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 19.5,-40.5 - parent: 2 - - uid: 14437 - components: - - type: Transform - pos: 15.5,-40.5 - parent: 2 - proto: Vaccinator entities: - uid: 7778 @@ -104710,6 +105601,11 @@ entities: - type: Transform pos: -8.5,-28.5 parent: 2 + - uid: 17242 + components: + - type: Transform + pos: -20.5,-49.5 + parent: 2 - proto: VendingMachineViroDrobe entities: - uid: 7781 @@ -117606,11 +118502,6 @@ entities: - type: Transform pos: 4.5,-74.5 parent: 2 - - uid: 2407 - components: - - type: Transform - pos: 5.5,-72.5 - parent: 2 - uid: 2408 components: - type: Transform @@ -117886,11 +118777,6 @@ entities: - type: Transform pos: -43.5,-64.5 parent: 2 - - uid: 3127 - components: - - type: Transform - pos: -12.5,-55.5 - parent: 2 - uid: 3141 components: - type: Transform @@ -119752,6 +120638,11 @@ entities: - type: Transform pos: 65.5,-67.5 parent: 2 + - uid: 12408 + components: + - type: Transform + pos: 6.5,-72.5 + parent: 2 - uid: 12473 components: - type: Transform @@ -120925,6 +121816,11 @@ entities: rot: -1.5707963267948966 rad pos: 62.5,-57.5 parent: 2 + - uid: 18908 + components: + - type: Transform + pos: 59.5,-40.5 + parent: 2 - proto: WindoorSecureAtmosphericsLocked entities: - uid: 8009 @@ -121148,11 +122044,17 @@ entities: rot: 1.5707963267948966 rad pos: 61.5,-42.5 parent: 2 - - uid: 13843 + - uid: 19594 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 62.5,-20.5 + rot: 3.141592653589793 rad + pos: 59.5,-40.5 + parent: 2 + - uid: 19647 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 61.5,-27.5 parent: 2 - proto: WindoorSecureServiceLocked entities: @@ -121372,12 +122274,6 @@ entities: rot: 3.141592653589793 rad pos: 61.5,-67.5 parent: 2 - - uid: 15123 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 62.5,-21.5 - parent: 2 - uid: 15384 components: - type: Transform @@ -121421,11 +122317,6 @@ entities: - type: Transform pos: 58.5,-56.5 parent: 2 - - uid: 18300 - components: - - type: Transform - pos: 58.5,-20.5 - parent: 2 - uid: 19483 components: - type: Transform @@ -121503,7 +122394,7 @@ entities: - uid: 18303 components: - type: Transform - pos: -15.501174,-18.454052 + pos: -13.546322,-21.423643 parent: 2 - uid: 18373 components: @@ -123337,15 +124228,10 @@ entities: - type: Transform pos: 49.5,-62.5 parent: 2 - - uid: 12850 - components: - - type: Transform - pos: 59.5,-22.5 - parent: 2 - uid: 12851 components: - type: Transform - pos: 58.5,-22.5 + pos: 59.5,-22.5 parent: 2 - uid: 13647 components: @@ -123434,6 +124320,11 @@ entities: - type: Transform pos: 63.5,-63.5 parent: 2 + - uid: 18416 + components: + - type: Transform + pos: 58.5,-22.5 + parent: 2 - uid: 18467 components: - type: Transform @@ -123470,6 +124361,11 @@ entities: - type: Transform pos: -16.5,-70.5 parent: 2 + - uid: 19044 + components: + - type: Transform + pos: 60.5,-21.5 + parent: 2 - uid: 19193 components: - type: Transform diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index fd298463d3..8c3b0521be 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -458,8 +458,8 @@ # Mob mapped to Xeno Station that can not be ghostrole / pry - type: entity - name: lone praetorian - description: The last of its kind. + name: '"Dale"' + description: A praetorian left over from the station's initial security sweep. Has a pair of bloodied dog tags engraved with the name "Pvt. Dale" stuck in its maw. parent: SimpleSpaceMobBase id: MobXenoLonePraetorianNoGhost components: diff --git a/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml b/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml index 7df0ba8c63..132d87a969 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml @@ -643,6 +643,9 @@ - type: FootstepModifier footstepSoundCollection: collection: FootstepFloor + - type: Construction + graph: Table + node: TableXeno # Fancy tables diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml index ae1490c951..7bcb9fc3c6 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml @@ -117,7 +117,7 @@ - Cryogenics - type: entity - parent: BaseStructure + parent: BaseMachine id: CryoPodDestroyed name: destroyed cryo pod description: A cryo pod that has seen better days. It's entirely inoperable; not good for anything but scrap. @@ -128,22 +128,17 @@ noRot: true offset: 0, 0.5 state: pod-cracked - - type: Transform - noRot: true - type: Fixtures fixtures: fix1: shape: !type:PhysShapeAabb - bounds: "-0.5,-0.5,0.5,0.90" + bounds: "-0.5,-0.5,0.5,0.5" density: 200 mask: - MachineMask layer: - MachineLayer - - type: Damageable - damageContainer: StructuralInorganic - damageModifierSet: StructuralMetallic - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Maps/exo.yml b/Resources/Prototypes/Maps/exo.yml index df36be5370..5026d68c44 100644 --- a/Resources/Prototypes/Maps/exo.yml +++ b/Resources/Prototypes/Maps/exo.yml @@ -2,8 +2,8 @@ id: Exo mapName: 'Exo' mapPath: /Maps/exo.yml - minPlayers: 30 - maxPlayers: 70 + minPlayers: 40 + maxPlayers: 80 stations: Exo: stationProto: StandardNanotrasenStation @@ -25,7 +25,7 @@ Bartender: [ 2, 2 ] Botanist: [ 2, 2 ] Chef: [ 2, 2 ] - Janitor: [ 1, 2 ] + Janitor: [ 2, 2 ] Chaplain: [ 1, 1 ] Librarian: [ 1, 1 ] ServiceWorker: [ 2, 2 ] @@ -54,7 +54,7 @@ #supply Quartermaster: [ 1, 1 ] SalvageSpecialist: [ 3, 3 ] - CargoTechnician: [ 3, 3 ] + CargoTechnician: [ 4, 4 ] #civilian Passenger: [ -1, -1 ] Clown: [ 1, 1 ] diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml index 4cee536bf9..37c94f0b39 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml @@ -404,3 +404,15 @@ steps: - tool: Prying doAfter: 1 + + - node: TableXeno + entity: TableXeno + edges: + - to: TableFrame + completed: + - !type:SpawnPrototype + prototype: SheetSteel1 + amount: 1 + steps: + - tool: Anchoring + doAfter: 1 From f6946f1db7c833baf71dda4b3e8402dff697f0d0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Jul 2025 18:52:49 +0000 Subject: [PATCH 039/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 19 +++++++++---------- Resources/Changelog/Maps.yml | 11 +++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c39c60116c..cf05e28dbe 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: mjarduk - changes: - - message: Torches can now be refueled. - type: Tweak - - message: Burnt torches/glowsticks names' can now display if they're glued, cluwnified, - etc. - type: Fix - id: 8220 - time: '2025-04-18T01:59:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36209 - author: lzk228 changes: - message: Borgs, clowns and mimes now can choose a custom name in loadouts. @@ -3887,3 +3877,12 @@ id: 8732 time: '2025-07-03T16:00:35.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36708 +- author: SlamBamActionman + changes: + - message: Xeno tables can now be dismantled. + type: Fix + - message: Broken cryo pods can now be unanchored, allowing them to be scrapped. + type: Fix + id: 8733 + time: '2025-07-03T18:51:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38689 diff --git a/Resources/Changelog/Maps.yml b/Resources/Changelog/Maps.yml index ea755b5405..b938873843 100644 --- a/Resources/Changelog/Maps.yml +++ b/Resources/Changelog/Maps.yml @@ -394,4 +394,15 @@ id: 48 time: '2025-07-02T03:14:37.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/37494 +- author: SlamBamActionman + changes: + - message: Exo station has had several minor changes and fixes, including a change + to the Nuke vault to allow it to be anchored in its center and its windows blocked + with blastdoors. + type: Fix + - message: Exo station's playercap has been increased from 30-70 to 40-80. + type: Tweak + id: 49 + time: '2025-07-03T18:51:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38689 Order: 1 From 32f0ba340a809b8fed2c2408d840d70a969b9083 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Fri, 4 Jul 2025 07:11:21 +1200 Subject: [PATCH 040/105] Fix TextLinkTag (#32203) --- Content.Client/Guidebook/Richtext/KeyBindTag.cs | 2 +- Content.Client/Guidebook/Richtext/ProtodataTag.cs | 2 +- Content.Client/Guidebook/Richtext/TextLinkTag.cs | 15 ++++++--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Content.Client/Guidebook/Richtext/KeyBindTag.cs b/Content.Client/Guidebook/Richtext/KeyBindTag.cs index 478f1b9bf6..ab74ddf1a0 100644 --- a/Content.Client/Guidebook/Richtext/KeyBindTag.cs +++ b/Content.Client/Guidebook/Richtext/KeyBindTag.cs @@ -6,7 +6,7 @@ using Robust.Shared.Utility; namespace Content.Client.Guidebook.Richtext; [UsedImplicitly] -public sealed class KeyBindTag : IMarkupTag +public sealed class KeyBindTag : IMarkupTagHandler { [Dependency] private readonly IInputManager _inputManager = default!; diff --git a/Content.Client/Guidebook/Richtext/ProtodataTag.cs b/Content.Client/Guidebook/Richtext/ProtodataTag.cs index a725fd4e4b..2a6eca4e48 100644 --- a/Content.Client/Guidebook/Richtext/ProtodataTag.cs +++ b/Content.Client/Guidebook/Richtext/ProtodataTag.cs @@ -9,7 +9,7 @@ namespace Content.Client.Guidebook.RichText; /// In order to be accessed by this tag, the desired field/property must /// be tagged with . /// -public sealed class ProtodataTag : IMarkupTag +public sealed class ProtodataTag : IMarkupTagHandler { [Dependency] private readonly ILogManager _logMan = default!; [Dependency] private readonly IEntityManager _entMan = default!; diff --git a/Content.Client/Guidebook/Richtext/TextLinkTag.cs b/Content.Client/Guidebook/Richtext/TextLinkTag.cs index 27aaa71939..a551b18473 100644 --- a/Content.Client/Guidebook/Richtext/TextLinkTag.cs +++ b/Content.Client/Guidebook/Richtext/TextLinkTag.cs @@ -10,16 +10,14 @@ using Content.Client.UserInterface.ControlExtensions; namespace Content.Client.Guidebook.RichText; [UsedImplicitly] -public sealed class TextLinkTag : IMarkupTag +public sealed class TextLinkTag : IMarkupTagHandler { public static Color LinkColor => Color.CornflowerBlue; public string Name => "textlink"; - public Control? Control; - /// - public bool TryGetControl(MarkupNode node, [NotNullWhen(true)] out Control? control) + public bool TryCreateControl(MarkupNode node, [NotNullWhen(true)] out Control? control) { if (!node.Value.TryGetString(out var text) || !node.Attributes.TryGetValue("link", out var linkParameter) @@ -38,22 +36,21 @@ public sealed class TextLinkTag : IMarkupTag label.OnMouseEntered += _ => label.FontColorOverride = Color.LightSkyBlue; label.OnMouseExited += _ => label.FontColorOverride = Color.CornflowerBlue; - label.OnKeyBindDown += args => OnKeybindDown(args, link); + label.OnKeyBindDown += args => OnKeybindDown(args, link, label); control = label; - Control = label; return true; } - private void OnKeybindDown(GUIBoundKeyEventArgs args, string link) + private void OnKeybindDown(GUIBoundKeyEventArgs args, string link, Control? control) { if (args.Function != EngineKeyFunctions.UIClick) return; - if (Control == null) + if (control == null) return; - if (Control.TryGetParentHandler(out var handler)) + if (control.TryGetParentHandler(out var handler)) handler.HandleClick(link); else Logger.Warning("Warning! No valid ILinkClickHandler found."); From c6739b2c89517361cd44ecdc0c1e82e9d8ad24a2 Mon Sep 17 00:00:00 2001 From: Mora <46364955+TrixxedHeart@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:49:27 -0500 Subject: [PATCH 041/105] Adjust uplink buy button to be under item icon (#38596) * Adjusted uplink buy button to be under item icon * Put the discount subtext under the icon * Indent fixes, added margin --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> --- .../Store/Ui/StoreListingControl.xaml | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Content.Client/Store/Ui/StoreListingControl.xaml b/Content.Client/Store/Ui/StoreListingControl.xaml index 3142f1cb06..b779672726 100644 --- a/Content.Client/Store/Ui/StoreListingControl.xaml +++ b/Content.Client/Store/Ui/StoreListingControl.xaml @@ -1,24 +1,28 @@ - +
public sealed class AmbientOcclusionOverlay : Overlay { + private static readonly ProtoId UnshadedShader = "unshaded"; + private static readonly ProtoId StencilMaskShader = "StencilMask"; + private static readonly ProtoId StencilEqualDrawShader = "StencilEqualDraw"; + [Dependency] private readonly IClyde _clyde = default!; [Dependency] private readonly IConfigurationManager _cfgManager = default!; [Dependency] private readonly IEntityManager _entManager = default!; @@ -87,7 +91,7 @@ public sealed class AmbientOcclusionOverlay : Overlay args.WorldHandle.RenderInRenderTarget(_aoTarget, () => { - worldHandle.UseShader(_proto.Index("unshaded").Instance()); + worldHandle.UseShader(_proto.Index(UnshadedShader).Instance()); var invMatrix = _aoTarget.GetWorldToLocalMatrix(viewport.Eye!, scale); foreach (var entry in query.QueryAabb(mapId, worldBounds)) @@ -110,7 +114,7 @@ public sealed class AmbientOcclusionOverlay : Overlay () => { // Don't want lighting affecting it. - worldHandle.UseShader(_proto.Index("unshaded").Instance()); + worldHandle.UseShader(_proto.Index(UnshadedShader).Instance()); foreach (var grid in _mapManager.FindGridsIntersecting(mapId, worldBounds)) { @@ -131,11 +135,11 @@ public sealed class AmbientOcclusionOverlay : Overlay }, Color.Transparent); // Draw the stencil texture to depth buffer. - worldHandle.UseShader(_proto.Index("StencilMask").Instance()); + worldHandle.UseShader(_proto.Index(StencilMaskShader).Instance()); worldHandle.DrawTextureRect(_aoStencilTarget!.Texture, worldBounds); // Draw the Blurred AO texture finally. - worldHandle.UseShader(_proto.Index("StencilEqualDraw").Instance()); + worldHandle.UseShader(_proto.Index(StencilEqualDrawShader).Instance()); worldHandle.DrawTextureRect(_aoTarget!.Texture, worldBounds, color); args.WorldHandle.SetTransform(Matrix3x2.Identity); diff --git a/Content.Client/Light/SunShadowOverlay.cs b/Content.Client/Light/SunShadowOverlay.cs index a296f95479..f30f4c0409 100644 --- a/Content.Client/Light/SunShadowOverlay.cs +++ b/Content.Client/Light/SunShadowOverlay.cs @@ -11,6 +11,8 @@ namespace Content.Client.Light; public sealed class SunShadowOverlay : Overlay { + private static readonly ProtoId MixShader = "Mix"; + public override OverlaySpace Space => OverlaySpace.BeforeLighting; [Dependency] private readonly IClyde _clyde = default!; @@ -150,7 +152,7 @@ public sealed class SunShadowOverlay : Overlay viewport.LightRenderTarget.GetWorldToLocalMatrix(eye, scale); worldHandle.SetTransform(invMatrix); - var maskShader = _protoManager.Index("Mix").Instance(); + var maskShader = _protoManager.Index(MixShader).Instance(); worldHandle.UseShader(maskShader); worldHandle.DrawTextureRect(_target.Texture, worldBounds, Color.Black.WithAlpha(alpha)); diff --git a/Content.Client/Mapping/MappingOverlay.cs b/Content.Client/Mapping/MappingOverlay.cs index ed44b43d52..e461440996 100644 --- a/Content.Client/Mapping/MappingOverlay.cs +++ b/Content.Client/Mapping/MappingOverlay.cs @@ -11,6 +11,8 @@ namespace Content.Client.Mapping; public sealed class MappingOverlay : Overlay { + private static readonly ProtoId UnshadedShader = "unshaded"; + [Dependency] private readonly IEntityManager _entities = default!; [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPrototypeManager _prototypes = default!; @@ -35,7 +37,7 @@ public sealed class MappingOverlay : Overlay _sprite = _entities.System(); _state = state; - _shader = _prototypes.Index("unshaded").Instance(); + _shader = _prototypes.Index(UnshadedShader).Instance(); } protected override void Draw(in OverlayDrawArgs args) diff --git a/Content.Client/Movement/Systems/FloorOcclusionSystem.cs b/Content.Client/Movement/Systems/FloorOcclusionSystem.cs index 44573f8e08..6520d98ac9 100644 --- a/Content.Client/Movement/Systems/FloorOcclusionSystem.cs +++ b/Content.Client/Movement/Systems/FloorOcclusionSystem.cs @@ -8,6 +8,8 @@ namespace Content.Client.Movement.Systems; public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem { + private static readonly ProtoId HorizontalCut = "HorizontalCut"; + [Dependency] private readonly IPrototypeManager _proto = default!; private EntityQuery _spriteQuery; @@ -48,7 +50,7 @@ public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem if (!_spriteQuery.Resolve(sprite.Owner, ref sprite.Comp, false)) return; - var shader = _proto.Index("HorizontalCut").Instance(); + var shader = _proto.Index(HorizontalCut).Instance(); if (sprite.Comp.PostShader is not null && sprite.Comp.PostShader != shader) return; diff --git a/Content.Client/Outline/TargetOutlineSystem.cs b/Content.Client/Outline/TargetOutlineSystem.cs index 0d9b9787ae..73d45a17a9 100644 --- a/Content.Client/Outline/TargetOutlineSystem.cs +++ b/Content.Client/Outline/TargetOutlineSystem.cs @@ -15,6 +15,9 @@ namespace Content.Client.Outline; ///
public sealed class TargetOutlineSystem : EntitySystem { + private static readonly ProtoId ShaderTargetValid = "SelectionOutlineInrange"; + private static readonly ProtoId ShaderTargetInvalid = "SelectionOutline"; + [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; @@ -70,12 +73,6 @@ public sealed class TargetOutlineSystem : EntitySystem private Vector2 LookupVector => new(LookupSize, LookupSize); - [ValidatePrototypeId] - private const string ShaderTargetValid = "SelectionOutlineInrange"; - - [ValidatePrototypeId] - private const string ShaderTargetInvalid = "SelectionOutline"; - private ShaderInstance? _shaderTargetValid; private ShaderInstance? _shaderTargetInvalid; @@ -85,8 +82,8 @@ public sealed class TargetOutlineSystem : EntitySystem { base.Initialize(); - _shaderTargetValid = _prototypeManager.Index(ShaderTargetValid).InstanceUnique(); - _shaderTargetInvalid = _prototypeManager.Index(ShaderTargetInvalid).InstanceUnique(); + _shaderTargetValid = _prototypeManager.Index(ShaderTargetValid).InstanceUnique(); + _shaderTargetInvalid = _prototypeManager.Index(ShaderTargetInvalid).InstanceUnique(); } public void Disable() diff --git a/Content.Client/Overlays/BlackAndWhiteOverlay.cs b/Content.Client/Overlays/BlackAndWhiteOverlay.cs index 785d1dad7f..251a9534a2 100644 --- a/Content.Client/Overlays/BlackAndWhiteOverlay.cs +++ b/Content.Client/Overlays/BlackAndWhiteOverlay.cs @@ -6,6 +6,8 @@ namespace Content.Client.Overlays; public sealed partial class BlackAndWhiteOverlay : Overlay { + private static readonly ProtoId Shader = "GreyscaleFullscreen"; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override OverlaySpace Space => OverlaySpace.WorldSpace; @@ -15,7 +17,7 @@ public sealed partial class BlackAndWhiteOverlay : Overlay public BlackAndWhiteOverlay() { IoCManager.InjectDependencies(this); - _greyscaleShader = _prototypeManager.Index("GreyscaleFullscreen").InstanceUnique(); + _greyscaleShader = _prototypeManager.Index(Shader).InstanceUnique(); ZIndex = 10; // draw this over the DamageOverlay, RainbowOverlay etc. } diff --git a/Content.Client/Overlays/NoirOverlay.cs b/Content.Client/Overlays/NoirOverlay.cs index d2a6cbe8b3..f9e468f995 100644 --- a/Content.Client/Overlays/NoirOverlay.cs +++ b/Content.Client/Overlays/NoirOverlay.cs @@ -6,6 +6,8 @@ namespace Content.Client.Overlays; public sealed partial class NoirOverlay : Overlay { + private static readonly ProtoId Shader = "Noir"; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override OverlaySpace Space => OverlaySpace.WorldSpace; @@ -15,7 +17,7 @@ public sealed partial class NoirOverlay : Overlay public NoirOverlay() { IoCManager.InjectDependencies(this); - _noirShader = _prototypeManager.Index("Noir").InstanceUnique(); + _noirShader = _prototypeManager.Index(Shader).InstanceUnique(); ZIndex = 9; // draw this over the DamageOverlay, RainbowOverlay etc, but before the black and white shader } diff --git a/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs b/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs index d29564caa9..a5efacc16c 100644 --- a/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs +++ b/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs @@ -45,13 +45,13 @@ public sealed partial class StencilOverlay }, Color.Transparent); worldHandle.SetTransform(Matrix3x2.Identity); - worldHandle.UseShader(_protoManager.Index("StencilMask").Instance()); + worldHandle.UseShader(_protoManager.Index(StencilMask).Instance()); worldHandle.DrawTextureRect(_blep!.Texture, worldBounds); var curTime = _timing.RealTime; var sprite = _sprite.GetFrame(new SpriteSpecifier.Texture(new ResPath("/Textures/Parallaxes/noise.png")), curTime); // Draw the rain - worldHandle.UseShader(_protoManager.Index("StencilDraw").Instance()); + worldHandle.UseShader(_protoManager.Index(StencilDraw).Instance()); _parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, new Vector2(0.5f, 0f)); } } diff --git a/Content.Client/Overlays/StencilOverlay.Weather.cs b/Content.Client/Overlays/StencilOverlay.Weather.cs index b1a521433a..509b946ad4 100644 --- a/Content.Client/Overlays/StencilOverlay.Weather.cs +++ b/Content.Client/Overlays/StencilOverlay.Weather.cs @@ -55,13 +55,13 @@ public sealed partial class StencilOverlay }, Color.Transparent); worldHandle.SetTransform(Matrix3x2.Identity); - worldHandle.UseShader(_protoManager.Index("StencilMask").Instance()); + worldHandle.UseShader(_protoManager.Index(StencilMask).Instance()); worldHandle.DrawTextureRect(_blep!.Texture, worldBounds); var curTime = _timing.RealTime; var sprite = _sprite.GetFrame(weatherProto.Sprite, curTime); // Draw the rain - worldHandle.UseShader(_protoManager.Index("StencilDraw").Instance()); + worldHandle.UseShader(_protoManager.Index(StencilDraw).Instance()); _parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, Vector2.Zero, modulate: (weatherProto.Color ?? Color.White).WithAlpha(alpha)); worldHandle.SetTransform(Matrix3x2.Identity); diff --git a/Content.Client/Overlays/StencilOverlay.cs b/Content.Client/Overlays/StencilOverlay.cs index e8461ae5a3..0796be08e1 100644 --- a/Content.Client/Overlays/StencilOverlay.cs +++ b/Content.Client/Overlays/StencilOverlay.cs @@ -17,6 +17,10 @@ namespace Content.Client.Overlays; /// public sealed partial class StencilOverlay : Overlay { + private static readonly ProtoId CircleShader = "WorldGradientCircle"; + private static readonly ProtoId StencilMask = "StencilMask"; + private static readonly ProtoId StencilDraw = "StencilDraw"; + [Dependency] private readonly IClyde _clyde = default!; [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IGameTiming _timing = default!; @@ -43,7 +47,7 @@ public sealed partial class StencilOverlay : Overlay _sprite = sprite; _weather = weather; IoCManager.InjectDependencies(this); - _shader = _protoManager.Index("WorldGradientCircle").InstanceUnique(); + _shader = _protoManager.Index(CircleShader).InstanceUnique(); } protected override void Draw(in OverlayDrawArgs args) diff --git a/Content.Client/Paper/UI/StampLabel.xaml.cs b/Content.Client/Paper/UI/StampLabel.xaml.cs index be6d52baea..1750110c4c 100644 --- a/Content.Client/Paper/UI/StampLabel.xaml.cs +++ b/Content.Client/Paper/UI/StampLabel.xaml.cs @@ -10,6 +10,8 @@ namespace Content.Client.Paper.UI; [GenerateTypedNameReferences] public sealed partial class StampLabel : Label { + private static readonly ProtoId PaperStamp = "PaperStamp"; + /// A scale that's applied to the text to ensure it /// fits in the allowed space. private Vector2 _textScaling = Vector2.One; @@ -26,7 +28,7 @@ public sealed partial class StampLabel : Label RobustXamlLoader.Load(this); var prototypes = IoCManager.Resolve(); - _stampShader = prototypes.Index("PaperStamp").InstanceUnique(); + _stampShader = prototypes.Index(PaperStamp).InstanceUnique(); } protected override Vector2 MeasureOverride(Vector2 availableSize) diff --git a/Content.Client/Paper/UI/StampWidget.xaml.cs b/Content.Client/Paper/UI/StampWidget.xaml.cs index 487e0732b4..a462d40e69 100644 --- a/Content.Client/Paper/UI/StampWidget.xaml.cs +++ b/Content.Client/Paper/UI/StampWidget.xaml.cs @@ -12,6 +12,8 @@ namespace Content.Client.Paper.UI; [GenerateTypedNameReferences] public sealed partial class StampWidget : PanelContainer { + private static readonly ProtoId PaperStamp = "PaperStamp"; + private StyleBoxTexture _borderTexture; private ShaderInstance? _stampShader; @@ -42,7 +44,7 @@ public sealed partial class StampWidget : PanelContainer PanelOverride = _borderTexture; var prototypes = IoCManager.Resolve(); - _stampShader = prototypes.Index("PaperStamp").InstanceUnique(); + _stampShader = prototypes.Index(PaperStamp).InstanceUnique(); } protected override void Draw(DrawingHandleScreen handle) diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml.cs index cc5016c4a7..27a585119e 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml.cs @@ -262,6 +262,7 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow public sealed class PASegmentControl : Control { + private static readonly ProtoId GreyscaleShaderId = "Greyscale"; private readonly ShaderInstance _greyScaleShader; private readonly TextureRect _base; private readonly TextureRect _unlit; @@ -272,7 +273,7 @@ public sealed class PASegmentControl : Control public PASegmentControl() { - _greyScaleShader = IoCManager.Resolve().Index("Greyscale").Instance(); + _greyScaleShader = IoCManager.Resolve().Index(GreyscaleShaderId).Instance(); AddChild(_base = new TextureRect()); AddChild(_unlit = new TextureRect()); diff --git a/Content.Client/Popups/PopupOverlay.cs b/Content.Client/Popups/PopupOverlay.cs index cf22c8bbd5..3b3e9cd463 100644 --- a/Content.Client/Popups/PopupOverlay.cs +++ b/Content.Client/Popups/PopupOverlay.cs @@ -16,6 +16,8 @@ namespace Content.Client.Popups; /// public sealed class PopupOverlay : Overlay { + private static readonly ProtoId UnshadedShader = "unshaded"; + private readonly IConfigurationManager _configManager; private readonly IEntityManager _entManager; private readonly IPlayerManager _playerMgr; @@ -48,7 +50,7 @@ public sealed class PopupOverlay : Overlay _popup = popup; _controller = controller; - _shader = protoManager.Index("unshaded").Instance(); + _shader = protoManager.Index(UnshadedShader).Instance(); } protected override void Draw(in OverlayDrawArgs args) diff --git a/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs b/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs index d6e36dd0ad..4cbeaa52f5 100644 --- a/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs +++ b/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs @@ -13,6 +13,8 @@ namespace Content.Client.Radiation.Overlays { public sealed class RadiationPulseOverlay : Overlay { + private static readonly ProtoId RadiationShader = "Radiation"; + [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; @@ -29,7 +31,7 @@ namespace Content.Client.Radiation.Overlays public RadiationPulseOverlay() { IoCManager.InjectDependencies(this); - _baseShader = _prototypeManager.Index("Radiation").Instance().Duplicate(); + _baseShader = _prototypeManager.Index(RadiationShader).Instance().Duplicate(); } protected override bool BeforeDraw(in OverlayDrawArgs args) diff --git a/Content.Client/Shuttles/FtlArrivalOverlay.cs b/Content.Client/Shuttles/FtlArrivalOverlay.cs index f24a1e9648..185d26f333 100644 --- a/Content.Client/Shuttles/FtlArrivalOverlay.cs +++ b/Content.Client/Shuttles/FtlArrivalOverlay.cs @@ -14,6 +14,8 @@ namespace Content.Client.Shuttles; /// public sealed class FtlArrivalOverlay : Overlay { + private static readonly ProtoId UnshadedShader = "unshaded"; + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities; private EntityLookupSystem _lookups; @@ -36,7 +38,7 @@ public sealed class FtlArrivalOverlay : Overlay _maps = _entManager.System(); _sprites = _entManager.System(); - _shader = _protos.Index("unshaded").Instance(); + _shader = _protos.Index(UnshadedShader).Instance(); } protected override bool BeforeDraw(in OverlayDrawArgs args) diff --git a/Content.Client/Silicons/StationAi/StationAiOverlay.cs b/Content.Client/Silicons/StationAi/StationAiOverlay.cs index 15a8a3a63f..5c84ce0c93 100644 --- a/Content.Client/Silicons/StationAi/StationAiOverlay.cs +++ b/Content.Client/Silicons/StationAi/StationAiOverlay.cs @@ -12,6 +12,10 @@ namespace Content.Client.Silicons.StationAi; public sealed class StationAiOverlay : Overlay { + private static readonly ProtoId CameraStaticShader = "CameraStatic"; + private static readonly ProtoId StencilMaskShader = "StencilMask"; + private static readonly ProtoId StencilDrawShader = "StencilDraw"; + [Dependency] private readonly IClyde _clyde = default!; [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IGameTiming _timing = default!; @@ -91,7 +95,7 @@ public sealed class StationAiOverlay : Overlay () => { worldHandle.SetTransform(invMatrix); - var shader = _proto.Index("CameraStatic").Instance(); + var shader = _proto.Index(CameraStaticShader).Instance(); worldHandle.UseShader(shader); worldHandle.DrawRect(worldBounds, Color.White); }, @@ -114,11 +118,11 @@ public sealed class StationAiOverlay : Overlay } // Use the lighting as a mask - worldHandle.UseShader(_proto.Index("StencilMask").Instance()); + worldHandle.UseShader(_proto.Index(StencilMaskShader).Instance()); worldHandle.DrawTextureRect(_stencilTexture!.Texture, worldBounds); // Draw the static - worldHandle.UseShader(_proto.Index("StencilDraw").Instance()); + worldHandle.UseShader(_proto.Index(StencilDrawShader).Instance()); worldHandle.DrawTextureRect(_staticTexture!.Texture, worldBounds); worldHandle.SetTransform(Matrix3x2.Identity); diff --git a/Content.Client/Singularity/SingularityOverlay.cs b/Content.Client/Singularity/SingularityOverlay.cs index e71b6e96b8..39b0758bf1 100644 --- a/Content.Client/Singularity/SingularityOverlay.cs +++ b/Content.Client/Singularity/SingularityOverlay.cs @@ -9,6 +9,8 @@ namespace Content.Client.Singularity { public sealed class SingularityOverlay : Overlay, IEntityEventSubscriber { + private static readonly ProtoId Shader = "Singularity"; + [Dependency] private readonly IEntityManager _entMan = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private SharedTransformSystem? _xformSystem = null; @@ -29,7 +31,7 @@ namespace Content.Client.Singularity public SingularityOverlay() { IoCManager.InjectDependencies(this); - _shader = _prototypeManager.Index("Singularity").Instance().Duplicate(); + _shader = _prototypeManager.Index(Shader).Instance().Duplicate(); _shader.SetParameter("maxDistance", MaxDistance * EyeManager.PixelsPerMeter); _entMan.EventBus.SubscribeEvent(EventSource.Local, this, OnProjectFromScreenToMap); ZIndex = 101; // Should be drawn after the placement overlay so admins placing items near the singularity can tell where they're going. diff --git a/Content.Client/StatusIcon/StatusIconOverlay.cs b/Content.Client/StatusIcon/StatusIconOverlay.cs index aff450e657..4d3be5439c 100644 --- a/Content.Client/StatusIcon/StatusIconOverlay.cs +++ b/Content.Client/StatusIcon/StatusIconOverlay.cs @@ -11,6 +11,8 @@ namespace Content.Client.StatusIcon; public sealed class StatusIconOverlay : Overlay { + private static readonly ProtoId UnshadedShader = "unshaded"; + [Dependency] private readonly IEntityManager _entity = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IGameTiming _timing = default!; @@ -29,7 +31,7 @@ public sealed class StatusIconOverlay : Overlay _sprite = _entity.System(); _transform = _entity.System(); _statusIcon = _entity.System(); - _unshadedShader = _prototype.Index("unshaded").Instance(); + _unshadedShader = _prototype.Index(UnshadedShader).Instance(); } protected override void Draw(in OverlayDrawArgs args) diff --git a/Content.Client/Stealth/StealthSystem.cs b/Content.Client/Stealth/StealthSystem.cs index 940f8f154d..5810b9bc85 100644 --- a/Content.Client/Stealth/StealthSystem.cs +++ b/Content.Client/Stealth/StealthSystem.cs @@ -10,6 +10,8 @@ namespace Content.Client.Stealth; public sealed class StealthSystem : SharedStealthSystem { + private static readonly ProtoId Shader = "Stealth"; + [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SpriteSystem _sprite = default!; @@ -20,7 +22,7 @@ public sealed class StealthSystem : SharedStealthSystem { base.Initialize(); - _shader = _protoMan.Index("Stealth").InstanceUnique(); + _shader = _protoMan.Index(Shader).InstanceUnique(); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnStartup); diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs index 0fbaf858da..ac82fbff59 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorWindow.xaml.cs @@ -17,6 +17,8 @@ namespace Content.Client.SurveillanceCamera.UI; [GenerateTypedNameReferences] public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow { + private static readonly ProtoId CameraStaticShader = "CameraStatic"; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; @@ -53,7 +55,7 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow // This could be done better. I don't want to deal with stylesheets at the moment. var texture = _resourceCache.GetTexture("/Textures/Interface/Nano/square_black.png"); - var shader = _prototypeManager.Index("CameraStatic").Instance().Duplicate(); + var shader = _prototypeManager.Index(CameraStaticShader).Instance().Duplicate(); CameraView.ViewportSize = new Vector2i(500, 500); CameraView.Eye = _defaultEye; // sure diff --git a/Content.Client/UserInterface/Systems/DamageOverlays/Overlays/DamageOverlay.cs b/Content.Client/UserInterface/Systems/DamageOverlays/Overlays/DamageOverlay.cs index de70fe16f8..3eef88f19b 100644 --- a/Content.Client/UserInterface/Systems/DamageOverlays/Overlays/DamageOverlay.cs +++ b/Content.Client/UserInterface/Systems/DamageOverlays/Overlays/DamageOverlay.cs @@ -9,6 +9,8 @@ namespace Content.Client.UserInterface.Systems.DamageOverlays.Overlays; public sealed class DamageOverlay : Overlay { + private static readonly ProtoId CircleMaskShader = "GradientCircleMask"; + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; @@ -49,9 +51,9 @@ public sealed class DamageOverlay : Overlay { // TODO: Replace IoCManager.InjectDependencies(this); - _oxygenShader = _prototypeManager.Index("GradientCircleMask").InstanceUnique(); - _critShader = _prototypeManager.Index("GradientCircleMask").InstanceUnique(); - _bruteShader = _prototypeManager.Index("GradientCircleMask").InstanceUnique(); + _oxygenShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique(); + _critShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique(); + _bruteShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique(); } protected override void Draw(in OverlayDrawArgs args) From 71d839fec4818453c7ab2a8f04a928fe8bbeee31 Mon Sep 17 00:00:00 2001 From: Tiniest Shark Date: Thu, 3 Jul 2025 22:02:35 -0400 Subject: [PATCH 047/105] Janitor Tool: Wire Brush (#38667) * Wow! It's -brush- * spacing. * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * fixed changes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Audio/Items/attributions.yml | 5 +++ Resources/Audio/Items/wirebrushing.ogg | Bin 0 -> 19141 bytes .../Locale/en-US/tools/tool-qualities.ftl | 5 ++- .../Catalog/Fills/Crates/service.yml | 4 +- .../Prototypes/Catalog/Fills/Items/belt.yml | 1 + .../Catalog/Fills/Lockers/service.yml | 2 + .../Entities/Clothing/Belt/belts.yml | 1 + .../Objects/Specific/Janitorial/janitor.yml | 36 ++++++++++++++++++ .../Construction/Graphs/structures/girder.yml | 8 ++++ .../Recipes/Lathes/Packs/service.yml | 1 + .../Prototypes/Recipes/Lathes/janitorial.yml | 8 ++++ Resources/Prototypes/tags.yml | 3 ++ Resources/Prototypes/tool_qualities.yml | 7 ++++ .../Guidebook/Service/Janitorial.xml | 1 + .../Janitorial/wirebrush.rsi/icon.png | Bin 0 -> 546 bytes .../Janitorial/wirebrush.rsi/inhand-left.png | Bin 0 -> 511 bytes .../Janitorial/wirebrush.rsi/inhand-right.png | Bin 0 -> 509 bytes .../Janitorial/wirebrush.rsi/meta.json | 25 ++++++++++++ .../Janitorial/wirebrush.rsi/storage.png | Bin 0 -> 449 bytes 19 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 Resources/Audio/Items/wirebrushing.ogg create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/icon.png create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/storage.png diff --git a/Resources/Audio/Items/attributions.yml b/Resources/Audio/Items/attributions.yml index 52f0a6c9a2..5a5927c878 100644 --- a/Resources/Audio/Items/attributions.yml +++ b/Resources/Audio/Items/attributions.yml @@ -169,3 +169,8 @@ license: "CC-BY-NC-4.0" copyright: "Original sound by QEDionium on freesound.org. Coverted to ogg and edited by Prole0 (GitHub)" source: "https://freesound.org/s/489803/" + +- files: ["wirebrushing.ogg"] + license: "CC0-1.0" + copyright: "Created by romulofs, converted to OGG, and edited by TiniestShark (Github)" + source: "https://freesound.org/s/127541/" diff --git a/Resources/Audio/Items/wirebrushing.ogg b/Resources/Audio/Items/wirebrushing.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4e54033b4c7073b6f020f490877a00a654ee889c GIT binary patch literal 19141 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 Ywdkp(e^B4c9e^U=7}oRi{Y*|(0RM + diff --git a/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/icon.png b/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd46d03a5c86679e31e11b22762ee53323f12a0a GIT binary patch literal 546 zcmV+-0^R+IP)Px$+(|@1R9J=Ol}$?mQ51$>O`L) z`UU-i{y-5ZZCbR7h{}W(sndrxlU5X`O}9)(!aH*d>MZZv;d$P<_nZO#L&=gtvZRpF zGrMTG-xs904{;Ng=Nz#LF`$z}k*gyEZ<{d;Sw#M45DCUr*5{--#1o@JzB` z2+xk~L)SGdF0F7~#G3wHjU`CU=Wu&-jqaT&7@VcAPM*tNp;UT6S9cHk2L`dZv1V=* zpBx|I_U0P*g+k3{qvSokeMs%?+SGimVYs2daBu{kj!wAT?vFJ!t<@xVx!q9nIq15E z)mVa3d%M<*;_5GuNfv}8XZ7uivZPR}-DBCAbJdJ9PU90%nw?)DcH1M9Q{3aXvKq3F kOis~{Ca)*)E8ss{Z+P5fja9?0{r~^~07*qoM6N<$f-VL9mjD0& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..0f0cb615daf09e117efba0a74ac4eabd2fc04d09 GIT binary patch literal 511 zcmVPx$xk*GpRCt{2+OcZFP!tB>lMY7cBew+t>NE}F&7r0tL~!|l=(2Mfu~JwfaLjS`Oc{`Wuv=Mn(`000000001FGAPVN zz19>eYu0N`F(}NH){Nb76y5GN+Bw(DP1a6O-ASjgbO8M zIn7So~vp)G=NN!|PU^tx1BjOC8)9s0sz0``M1G$k+ z&SFnQM4unQ$>-zWoyDHq$fn}xKr4Hxb-F$FHvyaYv^(8i;t!cYVJ_lL|J5xQMfLegOGL&U3o;Q{NvW~@*s@Iz0?*1WD&}_3onXz~p@db*n zz|T~NEr7IRaTzKuP_P7$W-Km42KRRHRv?@P&d13%l$ig}l9t3#U)m{ejD>Y%))tWQui922CwBN-ldV6IWuC9Htj) zo4)t+rwc_}1(=q0MP^j~HJRxW_i26&b4p<1&Kkw7s#Cl}r=1q}5EH%rXPtfHqdoI> zU7sJlPRyw=&i?nEi%dXeTf0PD*WI|PHR*M9K>&mOp3EB)+q;`HZ>&?z;eNs2<|8J0 zO?K-^lblPkQ*}JMO>=JOcq-ow1PZ+ByQR|2^_st}zUzkAhrg+Uf)mXmC%;=U0%~MbHCoI01WL&D1QY{VCzUAbsjOTOIf$l%XzxRIFtq*^C(@y`F-?`=9pMBAm z>@ZIk%U@f7M+vfRVr7f8VvhrVmE1_PH!zs?(XgM@NxG@aqb@0LHlK z0(zpySJ+L-Kd@7kW&b0YtL;HxR*>nc=Zl|j|IPpH->;K>x{5Jc9~b|+Td;>EGUP__ rZ`CUsI`>rST@X67*5eB=sd+Tap4RVF2tDnm{r-UW|9iiMG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/meta.json b/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/meta.json new file mode 100644 index 0000000000..4a9131da5e --- /dev/null +++ b/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/meta.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "license": "CC-BY-SA-4.0", + "copyright": "Sprites by TiniestShark (Github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "storage" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/storage.png b/Resources/Textures/Objects/Specific/Janitorial/wirebrush.rsi/storage.png new file mode 100644 index 0000000000000000000000000000000000000000..36997e2cd84887c65d61ada15d6daff9e4ae43d3 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T<)t)YnArY;~ z2@-w^+jl&&Us*L{MQUYE(5?UK{qjZ;5jQ72;czR`=}vs_w6VqT7vJIO`tv2{*;gJa zcyuFi(wP)Rw~4c->)$!#FK=gHFef!ZAaz>ugOn%f2EEf$Bdp7%4;Mc^s}g*M#T+!pGRbj^|Td(Q)-N$zfvat6i;gQu&X%Q~loCIEmJz1;u+ literal 0 HcmV?d00001 From a2ac401db3053122512700a53652c4402231605d Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Jul 2025 02:03:42 +0000 Subject: [PATCH 048/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 815a1d9317..7a02e80d6d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: slarticodefast - changes: - - message: Fire extinguishers and sprays now allow you to push the grids you are - standing on when you have magboots on. - type: Add - id: 8224 - time: '2025-04-18T03:41:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31754 - author: aada changes: - message: Filter categories added to the security techfab. @@ -3887,3 +3879,11 @@ id: 8735 time: '2025-07-04T00:04:27.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38699 +- author: TiniestShark + changes: + - message: Added a Wire Brush to the Janitor's tool kit for scrubbing unsightly + rust off of the station's walls! + type: Add + id: 8736 + time: '2025-07-04T02:02:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38667 From e82064916a891f835bc09269c721c1e22112ef8c Mon Sep 17 00:00:00 2001 From: Velken <8467292+Velken@users.noreply.github.com> Date: Fri, 4 Jul 2025 02:08:45 -0300 Subject: [PATCH 049/105] [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664) * fixed * clean up * orks fix smart * review fix 1 * more requested changes * less cursed * more descriptive description * better wording --- .../EntitySystems/RevenantSystem.Abilities.cs | 4 ++-- Content.Shared/Emag/Systems/EmagSystem.cs | 15 +++++++++------ .../Prototypes/Entities/Mobs/NPCs/revenant.yml | 2 ++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index 51cbb6d4d5..0ef7b8f533 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -35,6 +35,7 @@ namespace Content.Server.Revenant.EntitySystems; public sealed partial class RevenantSystem { + [Dependency] private readonly EmagSystem _emagSystem = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -345,8 +346,7 @@ public sealed partial class RevenantSystem _whitelistSystem.IsBlacklistPass(component.MalfunctionBlacklist, ent)) continue; - var ev = new GotEmaggedEvent(uid, EmagType.Interaction | EmagType.Access); - RaiseLocalEvent(ent, ref ev); + _emagSystem.TryEmagEffect(uid, uid, ent); } } } diff --git a/Content.Shared/Emag/Systems/EmagSystem.cs b/Content.Shared/Emag/Systems/EmagSystem.cs index 7aa4303471..912c4bdaea 100644 --- a/Content.Shared/Emag/Systems/EmagSystem.cs +++ b/Content.Shared/Emag/Systems/EmagSystem.cs @@ -51,9 +51,9 @@ public sealed class EmagSystem : EntitySystem } /// - /// Does the emag effect on a specified entity + /// Does the emag effect on a specified entity with a specified EmagType. The optional field customEmagType can be used to override the emag type defined in the component. /// - public bool TryEmagEffect(Entity ent, EntityUid user, EntityUid target) + public bool TryEmagEffect(Entity ent, EntityUid user, EntityUid target, EmagType? customEmagType = null) { if (!Resolve(ent, ref ent.Comp, false)) return false; @@ -68,7 +68,9 @@ public sealed class EmagSystem : EntitySystem return false; } - var emaggedEvent = new GotEmaggedEvent(user, ent.Comp.EmagType); + var typeToUse = customEmagType ?? ent.Comp.EmagType; + + var emaggedEvent = new GotEmaggedEvent(user, typeToUse); RaiseLocalEvent(target, ref emaggedEvent); if (!emaggedEvent.Handled) @@ -78,7 +80,7 @@ public sealed class EmagSystem : EntitySystem _audio.PlayPredicted(ent.Comp.EmagSound, ent, ent); - _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(user):player} emagged {ToPrettyString(target):target} with flag(s): {ent.Comp.EmagType}"); + _adminLogger.Add(LogType.Emag, LogImpact.High, $"{ToPrettyString(user):player} emagged {ToPrettyString(target):target} with flag(s): {typeToUse}"); if (emaggedEvent.Handled) _sharedCharges.TryUseCharge(chargesEnt); @@ -87,7 +89,7 @@ public sealed class EmagSystem : EntitySystem { EnsureComp(target, out var emaggedComp); - emaggedComp.EmagType |= ent.Comp.EmagType; + emaggedComp.EmagType |= typeToUse; Dirty(target, emaggedComp); } @@ -129,9 +131,10 @@ public sealed class EmagSystem : EntitySystem [Flags] [Serializable, NetSerializable] -public enum EmagType : byte +public enum EmagType { None = 0, + All = ~None, Interaction = 1 << 1, Access = 1 << 2 } diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml index 1c70e55d66..13bce86b06 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml @@ -6,6 +6,8 @@ name: revenant description: A spooky ghostie. components: + - type: Emag + emagType: All - type: Input context: "ghost" - type: Spectral From 7b6cc535dd5318c66e2ed5014ae033b34aeb65af Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Jul 2025 05:09:52 +0000 Subject: [PATCH 050/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7a02e80d6d..705d1e7d4f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: aada - changes: - - message: Filter categories added to the security techfab. - type: Add - id: 8225 - time: '2025-04-18T03:52:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35594 - author: Fildrance changes: - message: returned deconstruct to the top level option on RCD @@ -3887,3 +3880,11 @@ id: 8736 time: '2025-07-04T02:02:35.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38667 +- author: Velken + changes: + - message: Revenants' malfunction ability now properly works on MediBots and Stasis + Beds again. + type: Fix + id: 8737 + time: '2025-07-04T05:08:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38664 From 4e73c67d1b277cc5fe857aa865044bdbb520af8a Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Fri, 4 Jul 2025 02:58:56 -0400 Subject: [PATCH 051/105] Tiny Tiny Cleanup of the EyeClosingSystem. (#38734) Update EyeClosingSystem.cs --- Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs b/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs index 1b62c45af4..68ccf4a6b8 100644 --- a/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs @@ -15,7 +15,6 @@ public sealed class EyeClosingSystem : EntitySystem [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly ISharedPlayerManager _playerManager = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; public override void Initialize() { @@ -120,7 +119,7 @@ public sealed class EyeClosingSystem : EntitySystem var ev = new GetBlurEvent(blindable.Comp.EyeDamage); RaiseLocalEvent(blindable.Owner, ev); - if (_entityManager.TryGetComponent(blindable, out var eyelids) && !eyelids.NaturallyCreated) + if (EntityManager.TryGetComponent(blindable, out var eyelids) && !eyelids.NaturallyCreated) return; if (ev.Blur < BlurryVisionComponent.MaxMagnitude || ev.Blur >= blindable.Comp.MaxDamage) @@ -135,6 +134,4 @@ public sealed class EyeClosingSystem : EntitySystem } } -public sealed partial class ToggleEyesActionEvent : InstantActionEvent -{ -} +public sealed partial class ToggleEyesActionEvent : InstantActionEvent; From d5d386478401baf8dc83d4298662780f93632a41 Mon Sep 17 00:00:00 2001 From: Minerva <218184747+mnva0@users.noreply.github.com> Date: Fri, 4 Jul 2025 12:46:23 +0000 Subject: [PATCH 052/105] Typofixes for figurine dialogue (#38737) * Typofixes for figurine dialogue * Forgot two --- Resources/Locale/en-US/datasets/figurines.ftl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Locale/en-US/datasets/figurines.ftl b/Resources/Locale/en-US/datasets/figurines.ftl index 6d66566c20..c000c37c1e 100644 --- a/Resources/Locale/en-US/datasets/figurines.ftl +++ b/Resources/Locale/en-US/datasets/figurines.ftl @@ -134,9 +134,9 @@ figurines-ce-6 = Power's out again. figurines-engineer-1 = SINGULOOSE! figurines-engineer-2 = TESLOOSE! figurines-engineer-3 = What is AME? -figurines-engineer-4 = Free insuls at engineering +figurines-engineer-4 = Free insuls at Engineering! figurines-engineer-5 = Where'd the power go? -figurines-engineer-6 = Someone bombed medbay... again... +figurines-engineer-6 = Someone bombed the medbay... again... figurines-engineer-7 = Well, why don't you come and fix it? figurines-atmostech-1 = I put plasma in distro. @@ -148,7 +148,7 @@ figurines-atmostech-6 = Distro? That's short for disposal. figurines-atmostech-7 = TEG: Thermal Energy? Gone! figurines-rd-1 = Blowing up all of the borgs! -figurines-rd-2 = Tier 3 arsenal? No way. +figurines-rd-2 = Tier 3 Arsenal? No way. figurines-rd-3 = Now where did I leave my hardsuit...? figurines-rd-4 = Now you're thinking with portals! figurines-rd-5 = The cake is a lie! @@ -245,22 +245,22 @@ figurines-nukie-3 = The nuke makes boom. figurines-nukie-4 = What's the code? figurines-nukie-5 = Commander...? ...That's a balloon... -figurines-nukie-elite-1 = Not a word in nanotrasen. +figurines-nukie-elite-1 = Not a word in Nanotrasen. figurines-nukie-elite-2 = THAT'S A KEG! -figurines-nukie-elite-3 = Guys are you alive? +figurines-nukie-elite-3 = Guys, are you alive? figurines-nukie-elite-4 = Breach and clear! figurines-nukie-elite-5 = Leave no survivors. figurines-nukie-elite-6 = Good work, team. figurines-nukie-commander-1 = GET DAT FUKKEN DISK! figurines-nukie-commander-2 = Fuckin' flukies. -figurines-nukie-commander-3 = The syndicate sends its regards. +figurines-nukie-commander-3 = The Syndicate sends its regards. figurines-nukie-commander-4 = Failure is not an option. figurines-nukie-commander-5 = Whoops. figurines-footsoldier-1 = I'm an evil boy. Less boy every day, more evil every day. figurines-footsoldier-2 = Who will you choose? Them or us? Us or them? -figurines-footsoldier-3 = Glory to the syndicate! +figurines-footsoldier-3 = Glory to the Syndicate! figurines-footsoldier-4 = Down with Nanotrasen! figurines-footsoldier-5 = I'd rather die than join Nanotrasen. From 1a2e827674e173a1f0ba9cee9358f925e2e17858 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Fri, 4 Jul 2025 08:48:16 -0400 Subject: [PATCH 053/105] fix: Use PredictedQueueDel for gib spell (#38729) --- Content.Shared/Gibbing/Systems/GibbingSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Gibbing/Systems/GibbingSystem.cs b/Content.Shared/Gibbing/Systems/GibbingSystem.cs index 8c83de0cf2..9eaadbb970 100644 --- a/Content.Shared/Gibbing/Systems/GibbingSystem.cs +++ b/Content.Shared/Gibbing/Systems/GibbingSystem.cs @@ -187,7 +187,7 @@ public sealed class GibbingSystem : EntitySystem } if (gibType == GibType.Gib) - QueueDel(gibbable); + PredictedQueueDel(gibbable.Owner); return true; } @@ -292,7 +292,7 @@ public sealed class GibbingSystem : EntitySystem var gibbedEvent = new EntityGibbedEvent(gibbable, localGibs); RaiseLocalEvent(gibbable, ref gibbedEvent); if (deleteTarget) - QueueDel(gibbable); + PredictedQueueDel(gibbable.Owner); return localGibs; } From d0c067f006cc2f2f63b1bcadb65fbb6bd639d232 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Fri, 4 Jul 2025 09:22:26 -0400 Subject: [PATCH 054/105] Fix human skin tone distribution (#38701) --- Content.Shared/Humanoid/HumanoidCharacterAppearance.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index 05bebea075..7d4a17b337 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -153,8 +153,7 @@ public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance, switch (skinType) { case HumanoidSkinColor.HumanToned: - var tone = Math.Round(Humanoid.SkinColor.HumanSkinToneFromColor(newSkinColor)); - newSkinColor = Humanoid.SkinColor.HumanSkinTone((int)tone); + newSkinColor = Humanoid.SkinColor.HumanSkinTone(random.Next(0, 101)); break; case HumanoidSkinColor.Hues: break; From bfb73a1aad4f40d40fbdcd0facba155641da32e8 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Fri, 4 Jul 2025 12:15:24 -0400 Subject: [PATCH 055/105] fix: don't default to uncharged sprite state for cells (#38730) --- Content.Client/PowerCell/PowerCellSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Client/PowerCell/PowerCellSystem.cs b/Content.Client/PowerCell/PowerCellSystem.cs index fb40b911d1..8d9dd5ebdd 100644 --- a/Content.Client/PowerCell/PowerCellSystem.cs +++ b/Content.Client/PowerCell/PowerCellSystem.cs @@ -48,8 +48,9 @@ public sealed class PowerCellSystem : SharedPowerCellSystem if (!_sprite.LayerExists((uid, args.Sprite), PowerCellVisualLayers.Unshaded)) return; + // If no appearance data is set, rely on whatever existing sprite state is set being correct. if (!_appearance.TryGetData(uid, PowerCellVisuals.ChargeLevel, out var level, args.Component)) - level = 0; + return; var positiveCharge = level > 0; _sprite.LayerSetVisible((uid, args.Sprite), PowerCellVisualLayers.Unshaded, positiveCharge); From c3267c6db03b99017b96c0dfdf4afe3b30a82950 Mon Sep 17 00:00:00 2001 From: Arthur Fiorese de Andrade <170277843+ADM2PLAY@users.noreply.github.com> Date: Fri, 4 Jul 2025 17:41:49 -0300 Subject: [PATCH 056/105] Fix Hristov description - remove inaccurate technical specs (#38746) - Removes inaccurate 'armor piercing 14.5mm shells' reference - Replaces it with a more funny description, matching the style of the other snipers and guns - Keeps ammunition type '.60 anti-materiel ammo' specification - Fixes issue #38590 Co-authored-by: Arthur Fiorese de Andrade --- .../Entities/Objects/Weapons/Guns/Snipers/snipers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index 420650afc1..5514db42e6 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -54,7 +54,7 @@ name: Hristov parent: [BaseWeaponSniper, BaseGunWieldable, BaseSyndicateContraband] id: WeaponSniperHristov - description: A portable anti-materiel rifle. Fires armor piercing 14.5mm shells. Uses .60 anti-materiel ammo. + description: For when you absolutely, positively need to make someone regret their life choices from a safe distance. Uses .60 anti-materiel ammo. components: - type: Sprite sprite: Objects/Weapons/Guns/Snipers/heavy_sniper.rsi From 3a278bca8bf690d8e2b8553773ac8e7c5b2f544f Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Fri, 4 Jul 2025 16:48:55 -0400 Subject: [PATCH 057/105] Validate `ProtoId`s in tests (#38745) * Convert string literals to protoids in Content.Tests * Convert string literals to protoids or consts in Content.IntegrationTests * Fix linter failures Tricksy static using misled me --- .../Tests/Atmos/AlarmThresholdTest.cs | 8 +- .../Tests/Commands/RejuvenateTest.cs | 4 +- .../Tests/Commands/SuicideCommandTests.cs | 4 +- .../Construction/Interaction/WindowRepair.cs | 4 +- .../Tests/Damageable/DamageableTest.cs | 75 +++++++++++-------- .../DestructibleDamageGroupTest.cs | 4 +- .../DestructibleDamageTypeTest.cs | 4 +- .../DestructibleDestructionTest.cs | 2 +- .../DestructibleTestPrototypes.cs | 44 ++++++----- .../DestructibleThresholdActivationTest.cs | 2 +- .../Tests/Minds/MindTests.cs | 4 +- .../Tests/PostMapInitTest.cs | 4 +- .../Tests/Station/StationJobsTest.cs | 14 ++-- .../Tests/Vending/VendingInteractionTest.cs | 4 +- .../Tests/VendingMachineRestockTest.cs | 4 +- Content.Tests/Shared/DamageTest.cs | 23 ++++-- .../Shared/LocalizedDatasetPrototypeTest.cs | 8 +- 17 files changed, 129 insertions(+), 83 deletions(-) diff --git a/Content.IntegrationTests/Tests/Atmos/AlarmThresholdTest.cs b/Content.IntegrationTests/Tests/Atmos/AlarmThresholdTest.cs index 064b4f9a2d..b74c35ba11 100644 --- a/Content.IntegrationTests/Tests/Atmos/AlarmThresholdTest.cs +++ b/Content.IntegrationTests/Tests/Atmos/AlarmThresholdTest.cs @@ -7,10 +7,12 @@ namespace Content.IntegrationTests.Tests.Atmos [TestOf(typeof(AtmosAlarmThreshold))] public sealed class AlarmThresholdTest { + private const string AlarmThresholdTestDummyId = "AlarmThresholdTestDummy"; + [TestPrototypes] - private const string Prototypes = @" + private const string Prototypes = $@" - type: alarmThreshold - id: AlarmThresholdTestDummy + id: {AlarmThresholdTestDummyId} upperBound: !type:AlarmThresholdSetting threshold: 5 lowerBound: !type:AlarmThresholdSetting @@ -30,7 +32,7 @@ namespace Content.IntegrationTests.Tests.Atmos var prototypeManager = server.ResolveDependency(); AtmosAlarmThreshold threshold = default!; - var proto = prototypeManager.Index("AlarmThresholdTestDummy"); + var proto = prototypeManager.Index(AlarmThresholdTestDummyId); threshold = new(proto); await server.WaitAssertion(() => diff --git a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs index cfc8007306..e4ec7e907a 100644 --- a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs @@ -15,6 +15,8 @@ namespace Content.IntegrationTests.Tests.Commands [TestOf(typeof(RejuvenateSystem))] public sealed class RejuvenateTest { + private static readonly ProtoId TestDamageGroup = "Toxin"; + [TestPrototypes] private const string Prototypes = @" - type: entity @@ -62,7 +64,7 @@ namespace Content.IntegrationTests.Tests.Commands }); // Kill the entity - DamageSpecifier damage = new(prototypeManager.Index("Toxin"), FixedPoint2.New(10000000)); + DamageSpecifier damage = new(prototypeManager.Index(TestDamageGroup), FixedPoint2.New(10000000)); damSystem.TryChangeDamage(human, damage, true); diff --git a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs index b53b87dd5c..61b8d54448 100644 --- a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs +++ b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs @@ -53,6 +53,8 @@ public sealed class SuicideCommandTests components: - type: MaterialReclaimer"; private static readonly ProtoId CannotSuicideTag = "CannotSuicide"; + private static readonly ProtoId DamageType = "Slash"; + /// /// Run the suicide command in the console /// Should successfully kill the player and ghost them @@ -144,7 +146,7 @@ public sealed class SuicideCommandTests mobThresholdsComp = entManager.GetComponent(player); damageableComp = entManager.GetComponent(player); - if (protoMan.TryIndex("Slash", out var slashProto)) + if (protoMan.TryIndex(DamageType, out var slashProto)) damageableSystem.TryChangeDamage(player, new DamageSpecifier(slashProto, FixedPoint2.New(46.5))); }); diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs index 6eea519af3..192604edfd 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs @@ -8,6 +8,8 @@ namespace Content.IntegrationTests.Tests.Construction.Interaction; public sealed class WindowRepair : InteractionTest { + private static readonly ProtoId BluntDamageType = "Blunt"; + [Test] public async Task RepairReinforcedWindow() { @@ -16,7 +18,7 @@ public sealed class WindowRepair : InteractionTest // Damage the entity. var sys = SEntMan.System(); var comp = Comp(); - var damageType = Server.ResolveDependency().Index("Blunt"); + var damageType = Server.ProtoMan.Index(BluntDamageType); var damage = new DamageSpecifier(damageType, FixedPoint2.New(10)); Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero)); await Server.WaitPost(() => sys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true)); diff --git a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs index 69069fc82f..f610ab732e 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs @@ -1,9 +1,7 @@ -using System.Linq; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -14,66 +12,79 @@ namespace Content.IntegrationTests.Tests.Damageable [TestOf(typeof(DamageableSystem))] public sealed class DamageableTest { + private const string TestDamageableEntityId = "TestDamageableEntityId"; + private const string TestGroup1 = "TestGroup1"; + private const string TestGroup2 = "TestGroup2"; + private const string TestGroup3 = "TestGroup3"; + private const string TestDamage1 = "TestDamage1"; + private const string TestDamage2a = "TestDamage2a"; + private const string TestDamage2b = "TestDamage2b"; + + private const string TestDamage3a = "TestDamage3a"; + + private const string TestDamage3b = "TestDamage3b"; + private const string TestDamage3c = "TestDamage3c"; + [TestPrototypes] - private const string Prototypes = @" + private const string Prototypes = $@" # Define some damage groups - type: damageType - id: TestDamage1 + id: {TestDamage1} name: damage-type-blunt - type: damageType - id: TestDamage2a + id: {TestDamage2a} name: damage-type-blunt - type: damageType - id: TestDamage2b + id: {TestDamage2b} name: damage-type-blunt - type: damageType - id: TestDamage3a + id: {TestDamage3a} name: damage-type-blunt - type: damageType - id: TestDamage3b + id: {TestDamage3b} name: damage-type-blunt - type: damageType - id: TestDamage3c + id: {TestDamage3c} name: damage-type-blunt # Define damage Groups with 1,2,3 damage types - type: damageGroup - id: TestGroup1 + id: {TestGroup1} name: damage-group-brute damageTypes: - - TestDamage1 + - {TestDamage1} - type: damageGroup - id: TestGroup2 + id: {TestGroup2} name: damage-group-brute damageTypes: - - TestDamage2a - - TestDamage2b + - {TestDamage2a} + - {TestDamage2b} - type: damageGroup - id: TestGroup3 + id: {TestGroup3} name: damage-group-brute damageTypes: - - TestDamage3a - - TestDamage3b - - TestDamage3c + - {TestDamage3a} + - {TestDamage3b} + - {TestDamage3c} # This container should not support TestDamage1 or TestDamage2b - type: damageContainer id: testDamageContainer supportedGroups: - - TestGroup3 + - {TestGroup3} supportedTypes: - - TestDamage2a + - {TestDamage2a} - type: entity - id: TestDamageableEntityId - name: TestDamageableEntityId + id: {TestDamageableEntityId} + name: {TestDamageableEntityId} components: - type: Damageable damageContainer: testDamageContainer @@ -113,20 +124,20 @@ namespace Content.IntegrationTests.Tests.Damageable { var coordinates = map.MapCoords; - sDamageableEntity = sEntityManager.SpawnEntity("TestDamageableEntityId", coordinates); + sDamageableEntity = sEntityManager.SpawnEntity(TestDamageableEntityId, coordinates); sDamageableComponent = sEntityManager.GetComponent(sDamageableEntity); sDamageableSystem = sEntitySystemManager.GetEntitySystem(); - group1 = sPrototypeManager.Index("TestGroup1"); - group2 = sPrototypeManager.Index("TestGroup2"); - group3 = sPrototypeManager.Index("TestGroup3"); + group1 = sPrototypeManager.Index(TestGroup1); + group2 = sPrototypeManager.Index(TestGroup2); + group3 = sPrototypeManager.Index(TestGroup3); - type1 = sPrototypeManager.Index("TestDamage1"); - type2a = sPrototypeManager.Index("TestDamage2a"); - type2b = sPrototypeManager.Index("TestDamage2b"); - type3a = sPrototypeManager.Index("TestDamage3a"); - type3b = sPrototypeManager.Index("TestDamage3b"); - type3c = sPrototypeManager.Index("TestDamage3c"); + type1 = sPrototypeManager.Index(TestDamage1); + type2a = sPrototypeManager.Index(TestDamage2a); + type2b = sPrototypeManager.Index(TestDamage2b); + type3a = sPrototypeManager.Index(TestDamage3a); + type3b = sPrototypeManager.Index(TestDamage3b); + type3c = sPrototypeManager.Index(TestDamage3c); }); await server.WaitRunTicks(5); diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs index d37de7a504..0da07ad5a1 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs @@ -54,8 +54,8 @@ namespace Content.IntegrationTests.Tests.Destructible await server.WaitAssertion(() => { - var bruteDamageGroup = sPrototypeManager.Index("TestBrute"); - var burnDamageGroup = sPrototypeManager.Index("TestBurn"); + var bruteDamageGroup = sPrototypeManager.Index(TestBruteDamageGroupId); + var burnDamageGroup = sPrototypeManager.Index(TestBurnDamageGroupId); DamageSpecifier bruteDamage = new(bruteDamageGroup, FixedPoint2.New(5)); DamageSpecifier burnDamage = new(burnDamageGroup, FixedPoint2.New(5)); diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageTypeTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageTypeTest.cs index 69891cbd89..ccd459668b 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleDamageTypeTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleDamageTypeTest.cs @@ -49,8 +49,8 @@ namespace Content.IntegrationTests.Tests.Destructible await server.WaitAssertion(() => { - var bluntDamageType = protoManager.Index("TestBlunt"); - var slashDamageType = protoManager.Index("TestSlash"); + var bluntDamageType = protoManager.Index(TestBluntDamageTypeId); + var slashDamageType = protoManager.Index(TestSlashDamageTypeId); var bluntDamage = new DamageSpecifier(bluntDamageType, 5); var slashDamage = new DamageSpecifier(slashDamageType, 5); diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs index a50238d8f5..4e169e7dfa 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs @@ -39,7 +39,7 @@ namespace Content.IntegrationTests.Tests.Destructible await server.WaitAssertion(() => { var coordinates = sEntityManager.GetComponent(sDestructibleEntity).Coordinates; - var bruteDamageGroup = sPrototypeManager.Index("TestBrute"); + var bruteDamageGroup = sPrototypeManager.Index(TestBruteDamageGroupId); DamageSpecifier bruteDamage = new(bruteDamageGroup, 50); #pragma warning disable NUnit2045 // Interdependent assertions. diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs index 7ff9242398..872e414ac3 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs @@ -7,48 +7,56 @@ namespace Content.IntegrationTests.Tests.Destructible public const string DestructibleDestructionEntityId = "DestructibleTestsDestructibleDestructionEntity"; public const string DestructibleDamageTypeEntityId = "DestructibleTestsDestructibleDamageTypeEntity"; public const string DestructibleDamageGroupEntityId = "DestructibleTestsDestructibleDamageGroupEntity"; + public const string TestBruteDamageGroupId = "TestBrute"; + public const string TestBurnDamageGroupId = "TestBurn"; + public const string TestBluntDamageTypeId = "TestBlunt"; + public const string TestSlashDamageTypeId = "TestSlash"; + public const string TestPiercingDamageTypeId = "TestPiercing"; + public const string TestHeatDamageTypeId = "TestHeat"; + public const string TestShockDamageTypeId = "TestShock"; + public const string TestColdDamageTypeId = "TestCold"; [TestPrototypes] public const string DamagePrototypes = $@" - type: damageType - id: TestBlunt + id: {TestBluntDamageTypeId} name: damage-type-blunt - type: damageType - id: TestSlash + id: {TestSlashDamageTypeId} name: damage-type-slash - type: damageType - id: TestPiercing + id: {TestPiercingDamageTypeId} name: damage-type-piercing - type: damageType - id: TestHeat + id: {TestHeatDamageTypeId} name: damage-type-heat - type: damageType - id: TestShock + id: {TestShockDamageTypeId} name: damage-type-shock - type: damageType - id: TestCold + id: {TestColdDamageTypeId} name: damage-type-cold - type: damageGroup - id: TestBrute + id: {TestBruteDamageGroupId} name: damage-group-brute damageTypes: - - TestBlunt - - TestSlash - - TestPiercing + - {TestBluntDamageTypeId} + - {TestSlashDamageTypeId} + - {TestPiercingDamageTypeId} - type: damageGroup - id: TestBurn + id: {TestBurnDamageGroupId} name: damage-group-burn damageTypes: - - TestHeat - - TestShock - - TestCold + - {TestHeatDamageTypeId} + - {TestShockDamageTypeId} + - {TestColdDamageTypeId} - type: entity id: {SpawnedEntityId} @@ -114,10 +122,10 @@ namespace Content.IntegrationTests.Tests.Destructible !type:AndTrigger triggers: - !type:DamageTypeTrigger - damageType: TestBlunt + damageType: {TestBluntDamageTypeId} damage: 10 - !type:DamageTypeTrigger - damageType: TestSlash + damageType: {TestSlashDamageTypeId} damage: 10 - type: entity @@ -131,10 +139,10 @@ namespace Content.IntegrationTests.Tests.Destructible !type:AndTrigger triggers: - !type:DamageGroupTrigger - damageGroup: TestBrute + damageGroup: {TestBruteDamageGroupId} damage: 10 - !type:DamageGroupTrigger - damageGroup: TestBurn + damageGroup: {TestBurnDamageGroupId} damage: 10"; } } diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs index 80f750c715..af86e406ef 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleThresholdActivationTest.cs @@ -61,7 +61,7 @@ namespace Content.IntegrationTests.Tests.Destructible await server.WaitAssertion(() => { - var bluntDamage = new DamageSpecifier(sPrototypeManager.Index("TestBlunt"), 10); + var bluntDamage = new DamageSpecifier(sPrototypeManager.Index(TestBluntDamageTypeId), 10); sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true); diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.cs b/Content.IntegrationTests/Tests/Minds/MindTests.cs index d4d551f4e0..60e98b69fe 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.cs @@ -24,6 +24,8 @@ namespace Content.IntegrationTests.Tests.Minds; [TestFixture] public sealed partial class MindTests { + private static readonly ProtoId BluntDamageType = "Blunt"; + [TestPrototypes] private const string Prototypes = @" - type: entity @@ -144,7 +146,7 @@ public sealed partial class MindTests await server.WaitAssertion(() => { var damageable = entMan.GetComponent(entity); - if (!protoMan.TryIndex("Blunt", out var prototype)) + if (!protoMan.TryIndex(BluntDamageType, out var prototype)) { return; } diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 97be2b8705..a7a50a5270 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -77,6 +77,8 @@ namespace Content.IntegrationTests.Tests "Exo", }; + private static readonly ProtoId DoNotMapCategory = "DoNotMap"; + /// /// Asserts that specific files have been saved as grids and not maps. /// @@ -254,7 +256,7 @@ namespace Content.IntegrationTests.Tests return; var yamlEntities = node["entities"]; - if (!protoManager.TryIndex("DoNotMap", out var dnmCategory)) + if (!protoManager.TryIndex(DoNotMapCategory, out var dnmCategory)) return; Assert.Multiple(() => diff --git a/Content.IntegrationTests/Tests/Station/StationJobsTest.cs b/Content.IntegrationTests/Tests/Station/StationJobsTest.cs index d68fdafb76..3fee4a146c 100644 --- a/Content.IntegrationTests/Tests/Station/StationJobsTest.cs +++ b/Content.IntegrationTests/Tests/Station/StationJobsTest.cs @@ -17,8 +17,10 @@ namespace Content.IntegrationTests.Tests.Station; [TestOf(typeof(StationJobsSystem))] public sealed class StationJobsTest { + private const string StationMapId = "FooStation"; + [TestPrototypes] - private const string Prototypes = @" + private const string Prototypes = $@" - type: playTimeTracker id: PlayTimeDummyAssistant @@ -35,13 +37,13 @@ public sealed class StationJobsTest id: PlayTimeDummyChaplain - type: gameMap - id: FooStation + id: {StationMapId} minPlayers: 0 - mapName: FooStation + mapName: {StationMapId} mapPath: /Maps/Test/empty.yml stations: Station: - mapNameTemplate: FooStation + mapNameTemplate: {StationMapId} stationProto: StandardNanotrasenStation components: - type: StationJobs @@ -87,7 +89,7 @@ public sealed class StationJobsTest var server = pair.Server; var prototypeManager = server.ResolveDependency(); - var fooStationProto = prototypeManager.Index("FooStation"); + var fooStationProto = prototypeManager.Index(StationMapId); var entSysMan = server.ResolveDependency().EntitySysManager; var stationJobs = entSysMan.GetEntitySystem(); var stationSystem = entSysMan.GetEntitySystem(); @@ -161,7 +163,7 @@ public sealed class StationJobsTest var server = pair.Server; var prototypeManager = server.ResolveDependency(); - var fooStationProto = prototypeManager.Index("FooStation"); + var fooStationProto = prototypeManager.Index(StationMapId); var entSysMan = server.ResolveDependency().EntitySysManager; var stationJobs = entSysMan.GetEntitySystem(); var stationSystem = entSysMan.GetEntitySystem(); diff --git a/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs b/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs index bcaf4343b6..3645667737 100644 --- a/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs +++ b/Content.IntegrationTests/Tests/Vending/VendingInteractionTest.cs @@ -5,6 +5,7 @@ using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Content.Shared.VendingMachines; +using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests.Vending; @@ -17,6 +18,7 @@ public sealed class VendingInteractionTest : InteractionTest private const string RestockBoxProtoId = "InteractionTestRestockBox"; private const string RestockBoxOtherProtoId = "InteractionTestRestockBoxOther"; + private static readonly ProtoId TestDamageType = "Blunt"; [TestPrototypes] private const string TestPrototypes = $@" @@ -196,7 +198,7 @@ public sealed class VendingInteractionTest : InteractionTest Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage."); // Damage the vending machine to the point that it breaks - var damageType = ProtoMan.Index("Blunt"); + var damageType = ProtoMan.Index(TestDamageType); var damage = new DamageSpecifier(damageType, FixedPoint2.New(100)); await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true)); await RunTicks(5); diff --git a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs index 4644768901..f30eed0651 100644 --- a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs @@ -20,6 +20,8 @@ namespace Content.IntegrationTests.Tests [TestOf(typeof(VendingMachineSystem))] public sealed class VendingMachineRestockTest : EntitySystem { + private static readonly ProtoId TestDamageType = "Blunt"; + [TestPrototypes] private const string Prototypes = @" - type: entity @@ -293,7 +295,7 @@ namespace Content.IntegrationTests.Tests "Did not start with zero ramen."); restock = entityManager.SpawnEntity("TestRestockExplode", coordinates); - var damageSpec = new DamageSpecifier(prototypeManager.Index("Blunt"), 100); + var damageSpec = new DamageSpecifier(prototypeManager.Index(TestDamageType), 100); var damageResult = damageableSystem.TryChangeDamage(restock, damageSpec); #pragma warning disable NUnit2045 diff --git a/Content.Tests/Shared/DamageTest.cs b/Content.Tests/Shared/DamageTest.cs index 58fa8fbde3..27543e6533 100644 --- a/Content.Tests/Shared/DamageTest.cs +++ b/Content.Tests/Shared/DamageTest.cs @@ -15,6 +15,11 @@ namespace Content.Tests.Shared [TestOf(typeof(DamageGroupPrototype))] public sealed class DamageTest : ContentUnitTest { + private static readonly ProtoId BruteDamageGroup = "Brute"; + private static readonly ProtoId RadiationDamageType = "Radiation"; + private static readonly ProtoId SlashDamageType = "Slash"; + private static readonly ProtoId PiercingDamageType = "Piercing"; + private IPrototypeManager _prototypeManager; private DamageSpecifier _damageSpec; @@ -29,9 +34,9 @@ namespace Content.Tests.Shared _prototypeManager.ResolveResults(); // Create a damage data set - _damageSpec = new(_prototypeManager.Index("Brute"), 6); - _damageSpec += new DamageSpecifier(_prototypeManager.Index("Radiation"), 3); - _damageSpec += new DamageSpecifier(_prototypeManager.Index("Slash"), -1); // already exists in brute + _damageSpec = new(_prototypeManager.Index(BruteDamageGroup), 6); + _damageSpec += new DamageSpecifier(_prototypeManager.Index(RadiationDamageType), 3); + _damageSpec += new DamageSpecifier(_prototypeManager.Index(SlashDamageType), -1); // already exists in brute } //Check that DamageSpecifier will split groups and can do arithmetic operations @@ -100,7 +105,7 @@ namespace Content.Tests.Shared Assert.That(damage, Is.EqualTo(FixedPoint2.New(3))); // Lets also test the constructor with damage types and damage groups works properly. - damageSpec = new(_prototypeManager.Index("Brute"), 4); + damageSpec = new(_prototypeManager.Index(BruteDamageGroup), 4); Assert.That(damageSpec.DamageDict.TryGetValue("Blunt", out damage)); Assert.That(damage, Is.EqualTo(FixedPoint2.New(1.33))); Assert.That(damageSpec.DamageDict.TryGetValue("Slash", out damage)); @@ -108,7 +113,7 @@ namespace Content.Tests.Shared Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage)); Assert.That(damage, Is.EqualTo(FixedPoint2.New(1.34))); // doesn't divide evenly, so the 0.01 goes to the last one - damageSpec = new(_prototypeManager.Index("Piercing"), 4); + damageSpec = new(_prototypeManager.Index(PiercingDamageType), 4); Assert.That(damageSpec.DamageDict.TryGetValue("Piercing", out damage)); Assert.That(damage, Is.EqualTo(FixedPoint2.New(4))); } @@ -121,7 +126,7 @@ namespace Content.Tests.Shared DamageSpecifier damageSpec = 10 * new DamageSpecifier(_damageSpec); // Create a modifier set - var modifierSet = _prototypeManager.Index("ModifierTestSet"); + var modifierSet = _prototypeManager.Index(ModifierTestSetId); //damage is initially 20 / 20 / 10 / 30 //Each time we subtract -5 / 0 / 8 / 0.5 @@ -142,8 +147,10 @@ namespace Content.Tests.Shared Assert.That(damageSpec.DamageDict["Radiation"], Is.EqualTo(FixedPoint2.New(65.62))); } + private const string ModifierTestSetId = "ModifierTestSet"; + // Default damage Yaml - private string _damagePrototypes = @" + private readonly string _damagePrototypes = $@" - type: damageType id: Blunt name: damage-type-blunt @@ -268,7 +275,7 @@ namespace Content.Tests.Shared Blunt: 5 - type: damageModifierSet - id: ModifierTestSet + id: {ModifierTestSetId} coefficients: Piercing: -2 Slash: 3 diff --git a/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs index b07b18efa0..77f001bfe1 100644 --- a/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs +++ b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs @@ -12,6 +12,8 @@ namespace Content.Tests.Shared; [TestOf(typeof(LocalizedDatasetPrototype))] public sealed class LocalizedDatasetPrototypeTest : ContentUnitTest { + private const string TestDatasetId = "Test"; + private IPrototypeManager _prototypeManager; [OneTimeSetUp] @@ -24,9 +26,9 @@ public sealed class LocalizedDatasetPrototypeTest : ContentUnitTest _prototypeManager.ResolveResults(); } - private const string TestPrototypes = @" + private const string TestPrototypes = $@" - type: localizedDataset - id: Test + id: {TestDatasetId} values: prefix: test-dataset- count: 4 @@ -35,7 +37,7 @@ public sealed class LocalizedDatasetPrototypeTest : ContentUnitTest [Test] public void LocalizedDatasetTest() { - var testPrototype = _prototypeManager.Index("Test"); + var testPrototype = _prototypeManager.Index(TestDatasetId); var values = new ValueList(); foreach (var value in testPrototype.Values) { From f09bade8e783bf36bb94718759d5b427ae07bec3 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Fri, 4 Jul 2025 16:55:45 -0400 Subject: [PATCH 058/105] Validate remaining `ProtoId` strings (#38747) Validate remaining ProtoId strings --- .../Access/UI/GroupedAccessLevelChecklist.xaml.cs | 4 +++- Content.Client/Delivery/DeliveryVisualizerSystem.cs | 2 +- Content.Server/Botany/Systems/MutationSystem.cs | 4 +++- Content.Server/Cluwne/CluwneSystem.cs | 4 +++- .../Behaviors/WeightedSpawnEntityBehavior.cs | 4 +++- Content.Server/EntityEffects/EntityEffectSystem.cs | 4 +++- .../Gateway/Systems/GatewayGeneratorSystem.cs | 11 ++++++----- Content.Server/Ghost/GhostSystem.cs | 3 ++- .../Salvage/SalvageSystem.ExpeditionConsole.cs | 6 +++--- Content.Server/Salvage/SpawnSalvageMissionJob.cs | 2 +- .../StationEvents/Events/RandomSentienceRule.cs | 7 +++++-- Content.Shared/Body/Systems/SharedBodySystem.Parts.cs | 4 +++- Content.Shared/Chat/SharedSuicideSystem.cs | 6 ++++-- Content.Shared/Humanoid/NamingSystem.cs | 6 ++++-- 14 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Content.Client/Access/UI/GroupedAccessLevelChecklist.xaml.cs b/Content.Client/Access/UI/GroupedAccessLevelChecklist.xaml.cs index da68653ce5..4f07c31009 100644 --- a/Content.Client/Access/UI/GroupedAccessLevelChecklist.xaml.cs +++ b/Content.Client/Access/UI/GroupedAccessLevelChecklist.xaml.cs @@ -15,6 +15,8 @@ namespace Content.Client.Access.UI; [GenerateTypedNameReferences] public sealed partial class GroupedAccessLevelChecklist : BoxContainer { + private static readonly ProtoId GeneralAccessGroup = "General"; + [Dependency] private readonly IPrototypeManager _protoManager = default!; private bool _isMonotone; @@ -63,7 +65,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer // Ensure that the 'general' access group is added to handle // misc. access levels that aren't associated with any group - if (_protoManager.TryIndex("General", out var generalAccessProto)) + if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto)) _groupedAccessLevels.TryAdd(generalAccessProto, new()); // Assign known access levels with their associated groups diff --git a/Content.Client/Delivery/DeliveryVisualizerSystem.cs b/Content.Client/Delivery/DeliveryVisualizerSystem.cs index 846688149f..d5afd34533 100644 --- a/Content.Client/Delivery/DeliveryVisualizerSystem.cs +++ b/Content.Client/Delivery/DeliveryVisualizerSystem.cs @@ -24,7 +24,7 @@ public sealed class DeliveryVisualizerSystem : VisualizerSystem(job, out var icon)) { - SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index("JobIconUnknown"))); + SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index(UnknownIcon).Icon)); return; } diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index 37b68d9475..ee35db48e3 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -9,13 +9,15 @@ namespace Content.Server.Botany; public sealed class MutationSystem : EntitySystem { + private static ProtoId RandomPlantMutations = "RandomPlantMutations"; + [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private RandomPlantMutationListPrototype _randomMutations = default!; public override void Initialize() { - _randomMutations = _prototypeManager.Index("RandomPlantMutations"); + _randomMutations = _prototypeManager.Index(RandomPlantMutations); } /// diff --git a/Content.Server/Cluwne/CluwneSystem.cs b/Content.Server/Cluwne/CluwneSystem.cs index 73476ece17..2bad4e0b96 100644 --- a/Content.Server/Cluwne/CluwneSystem.cs +++ b/Content.Server/Cluwne/CluwneSystem.cs @@ -21,6 +21,8 @@ namespace Content.Server.Cluwne; public sealed class CluwneSystem : EntitySystem { + private static readonly ProtoId GeneticDamageGroup = "Genetic"; + [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; @@ -53,7 +55,7 @@ public sealed class CluwneSystem : EntitySystem RemComp(uid); RemComp(uid); RemComp(uid); - var damageSpec = new DamageSpecifier(_prototypeManager.Index("Genetic"), 300); + var damageSpec = new DamageSpecifier(_prototypeManager.Index(GeneticDamageGroup), 300); _damageableSystem.TryChangeDamage(uid, damageSpec); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs index e02ed87322..96fa4dd438 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs @@ -19,6 +19,8 @@ namespace Content.Server.Destructible.Thresholds.Behaviors; [DataDefinition] public sealed partial class WeightedSpawnEntityBehavior : IThresholdBehavior { + private static readonly EntProtoId TempEntityProtoId = "TemporaryEntityForTimedDespawnSpawners"; + /// /// A table of entities with assigned weights to randomly pick from /// @@ -64,7 +66,7 @@ public sealed partial class WeightedSpawnEntityBehavior : IThresholdBehavior if (SpawnAfter != 0) { // if it fails to get the spawner, this won't ever work so just return - if (!system.PrototypeManager.TryIndex("TemporaryEntityForTimedDespawnSpawners", out var tempSpawnerProto)) + if (!system.PrototypeManager.TryIndex(TempEntityProtoId, out var tempSpawnerProto)) return; // spawn the spawner, assign it a lifetime, and assign the entity that it will spawn when despawned diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs index e18b3b1470..54270ca53d 100644 --- a/Content.Server/EntityEffects/EntityEffectSystem.cs +++ b/Content.Server/EntityEffects/EntityEffectSystem.cs @@ -48,6 +48,8 @@ namespace Content.Server.EntityEffects; public sealed class EntityEffectSystem : EntitySystem { + private static readonly ProtoId RandomPickBotanyReagent = "RandomPickBotanyReagent"; + [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly BloodstreamSystem _bloodstream = default!; [Dependency] private readonly ChatSystem _chat = default!; @@ -854,7 +856,7 @@ public sealed class EntityEffectSystem : EntitySystem return; var chemicals = plantholder.Seed.Chemicals; - var randomChems = _protoManager.Index("RandomPickBotanyReagent").Fills; + var randomChems = _protoManager.Index(RandomPickBotanyReagent).Fills; // Add a random amount of a random chemical to this set of chemicals if (randomChems != null) diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 83471cdbc1..a88cf6b428 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -36,8 +36,9 @@ public sealed class GatewayGeneratorSystem : EntitySystem [Dependency] private readonly SharedSalvageSystem _salvage = default!; [Dependency] private readonly TileSystem _tile = default!; - [ValidatePrototypeId] - private const string PlanetNames = "NamesBorer"; + private static readonly ProtoId PlanetNames = "NamesBorer"; + private static readonly ProtoId BiomeTemplate = "Continental"; + private static readonly ProtoId DungeonConfig = "Experiment"; // TODO: // Fix shader some more @@ -101,7 +102,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem var random = new Random(seed); var mapUid = _maps.CreateMap(); - var gatewayName = _salvage.GetFTLName(_protoManager.Index(PlanetNames), seed); + var gatewayName = _salvage.GetFTLName(_protoManager.Index(PlanetNames), seed); _metadata.SetEntityName(mapUid, gatewayName); var origin = new Vector2i(random.Next(-MaxOffset, MaxOffset), random.Next(-MaxOffset, MaxOffset)); @@ -111,7 +112,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem }; AddComp(mapUid, restricted); - _biome.EnsurePlanet(mapUid, _protoManager.Index("Continental"), seed); + _biome.EnsurePlanet(mapUid, _protoManager.Index(BiomeTemplate), seed); var grid = Comp(mapUid); @@ -183,7 +184,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem var dungeonRotation = _dungeon.GetDungeonRotation(seed); var dungeonPosition = (origin + dungeonRotation.RotateVec(new Vector2i(0, dungeonDistance))).Floored(); - _dungeon.GenerateDungeon(_protoManager.Index("Experiment"), args.MapUid, grid, dungeonPosition, seed); + _dungeon.GenerateDungeon(_protoManager.Index(DungeonConfig), args.MapUid, grid, dungeonPosition, seed); // TODO: Dungeon mobs + loot. diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 33de2c6f39..3e09d86189 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -74,6 +74,7 @@ namespace Content.Server.Ghost private EntityQuery _physicsQuery; private static readonly ProtoId AllowGhostShownByEventTag = "AllowGhostShownByEvent"; + private static readonly ProtoId AsphyxiationDamageType = "Asphyxiation"; public override void Initialize() { @@ -585,7 +586,7 @@ namespace Content.Server.Ghost dealtDamage = playerDeadThreshold - damageable.TotalDamage; } - DamageSpecifier damage = new(_prototypeManager.Index("Asphyxiation"), dealtDamage); + DamageSpecifier damage = new(_prototypeManager.Index(AsphyxiationDamageType), dealtDamage); _damageable.TryChangeDamage(playerEntity, damage, true); } diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs index a9d8314f57..aa501368de 100644 --- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs +++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs @@ -8,8 +8,8 @@ namespace Content.Server.Salvage; public sealed partial class SalvageSystem { - [ValidatePrototypeId] - public const string CoordinatesDisk = "CoordinatesDisk"; + public static readonly EntProtoId CoordinatesDisk = "CoordinatesDisk"; + public static readonly ProtoId PlanetNames = "NamesBorer"; private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleComponent component, ClaimSalvageMessage args) { @@ -28,7 +28,7 @@ public sealed partial class SalvageSystem var mission = GetMission(_prototypeManager.Index(missionparams.Difficulty), missionparams.Seed); data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1); - _labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index("NamesBorer"), missionparams.Seed)); + _labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index(PlanetNames), missionparams.Seed)); _audio.PlayPvs(component.PrintSound, uid); UpdateConsoles((station.Value, data)); diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index cbce4dc692..8b5e9898ad 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -100,7 +100,7 @@ public sealed class SpawnSalvageMissionJob : Job destComp.Enabled = true; _metaData.SetEntityName( mapUid, - _entManager.System().GetFTLName(_prototypeManager.Index("NamesBorer"), _missionParams.Seed)); + _entManager.System().GetFTLName(_prototypeManager.Index(SalvageSystem.PlanetNames), _missionParams.Seed)); _entManager.AddComponent(mapUid); // Saving the mission mapUid to a CD is made optional, in case one is somehow made in a process without a CD entity diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs index 3d2e457a34..359c3edae4 100644 --- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs @@ -11,6 +11,9 @@ namespace Content.Server.StationEvents.Events; public sealed class RandomSentienceRule : StationEventSystem { + private static readonly ProtoId DataSourceNames = "RandomSentienceEventData"; + private static readonly ProtoId IntelligenceLevelNames = "RandomSentienceEventStrength"; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) @@ -72,8 +75,8 @@ public sealed class RandomSentienceRule : StationEventSystem("RandomSentienceEventData"))), - ("strength", _random.Pick(_prototype.Index("RandomSentienceEventStrength"))) + ("data", _random.Pick(_prototype.Index(DataSourceNames))), + ("strength", _random.Pick(_prototype.Index(IntelligenceLevelNames))) ), playDefaultSound: false, colorOverride: Color.Gold diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index 0917197e29..78d270ddc9 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -8,12 +8,14 @@ using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Movement.Components; using Robust.Shared.Containers; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.Body.Systems; public partial class SharedBodySystem { + private static readonly ProtoId BloodlossDamageType = "Bloodloss"; private void InitializeParts() { // TODO: This doesn't handle comp removal on child ents. @@ -178,7 +180,7 @@ public partial class SharedBodySystem ) { // TODO BODY SYSTEM KILL : remove this when wounding and required parts are implemented properly - var damage = new DamageSpecifier(Prototypes.Index("Bloodloss"), 300); + var damage = new DamageSpecifier(Prototypes.Index(BloodlossDamageType), 300); Damageable.TryChangeDamage(bodyEnt, damage); } } diff --git a/Content.Shared/Chat/SharedSuicideSystem.cs b/Content.Shared/Chat/SharedSuicideSystem.cs index d341ea89a8..4b9eaf24b7 100644 --- a/Content.Shared/Chat/SharedSuicideSystem.cs +++ b/Content.Shared/Chat/SharedSuicideSystem.cs @@ -8,6 +8,8 @@ namespace Content.Shared.Chat; public sealed class SharedSuicideSystem : EntitySystem { + private static readonly ProtoId FallbackDamageType = "Blunt"; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -57,8 +59,8 @@ public sealed class SharedSuicideSystem : EntitySystem // We don't want structural damage for the same reasons listed above if (!_prototypeManager.TryIndex(damageType, out var damagePrototype) || damagePrototype.ID == "Structural") { - Log.Error($"{nameof(SharedSuicideSystem)} could not find the damage type prototype associated with {damageType}. Falling back to Blunt"); - damagePrototype = _prototypeManager.Index("Blunt"); + Log.Error($"{nameof(SharedSuicideSystem)} could not find the damage type prototype associated with {damageType}. Falling back to {FallbackDamageType}"); + damagePrototype = _prototypeManager.Index(FallbackDamageType); } var damage = new DamageSpecifier(damagePrototype, lethalAmountOfDamage); diff --git a/Content.Shared/Humanoid/NamingSystem.cs b/Content.Shared/Humanoid/NamingSystem.cs index a2085c6692..98afb34015 100644 --- a/Content.Shared/Humanoid/NamingSystem.cs +++ b/Content.Shared/Humanoid/NamingSystem.cs @@ -12,6 +12,8 @@ namespace Content.Shared.Humanoid /// public sealed class NamingSystem : EntitySystem { + private static readonly ProtoId FallbackSpecies = "Human"; + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -21,8 +23,8 @@ namespace Content.Shared.Humanoid // Some downstream is probably gonna have this eventually but then they can deal with fallbacks. if (!_prototypeManager.TryIndex(species, out SpeciesPrototype? speciesProto)) { - speciesProto = _prototypeManager.Index("Human"); - Log.Warning($"Unable to find species {species} for name, falling back to Human"); + speciesProto = _prototypeManager.Index(FallbackSpecies); + Log.Warning($"Unable to find species {species} for name, falling back to {FallbackSpecies}"); } switch (speciesProto.Naming) From 4905e097c8947e2384b0243d920567e08f0e6c3c Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Fri, 4 Jul 2025 17:50:44 -0400 Subject: [PATCH 059/105] feat: allow mopping evaporating puddles (#38743) --- .../Fluids/EntitySystems/AbsorbentSystem.cs | 20 ++++++++++++------- .../EntitySystems/PuddleSystem.Evaporation.cs | 1 + .../fluids/components/absorbent-component.ftl | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs index 1177c24304..28c36602e1 100644 --- a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs +++ b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs @@ -277,17 +277,22 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem if (!_solutionContainerSystem.ResolveSolution(target, puddle.SolutionName, ref puddle.Solution, out var puddleSolution) || puddleSolution.Volume <= 0) return false; - // Check if the puddle has any non-evaporative reagents - if (_puddleSystem.CanFullyEvaporate(puddleSolution)) - { - _popups.PopupEntity(Loc.GetString("mopping-system-puddle-evaporate", ("target", target)), user, user); - return true; - } - Solution puddleSplit; var isRemoved = false; if (absorber.UseAbsorberSolution) { + // No reason to mop something that 1) can evaporate, 2) is an absorber, and 3) is being mopped with + // something that uses absorbers. + var puddleAbsorberVolume = + puddleSolution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(puddleSolution)); + if (puddleAbsorberVolume == puddleSolution.Volume) + { + _popups.PopupEntity(Loc.GetString("mopping-system-puddle-already-mopped", ("target", target)), + user, + user); + return true; + } + // Check if we have any evaporative reagents on our absorber to transfer var absorberSolution = absorberSoln.Comp.Solution; var available = absorberSolution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(absorberSolution)); @@ -317,6 +322,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem } else { + // Note: arguably shouldn't this get all solutions? puddleSplit = puddleSolution.SplitSolutionWithout(absorber.PickupAmount, _puddleSystem.GetAbsorbentReagents(puddleSolution)); // Despawn if we're done if (puddleSolution.Volume == FixedPoint2.Zero) diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs index f92504e74c..245ab8308f 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs @@ -46,6 +46,7 @@ public sealed partial class PuddleSystem if (!_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution, out var puddleSolution)) continue; + // Yes, this means that 50u water + 50u holy water evaporates twice as fast as 100u water. foreach ((string evaporatingReagent, FixedPoint2 evaporatingSpeed) in GetEvaporationSpeeds(puddleSolution)) { var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds * evaporatingSpeed; diff --git a/Resources/Locale/en-US/fluids/components/absorbent-component.ftl b/Resources/Locale/en-US/fluids/components/absorbent-component.ftl index 51e500a6fe..d6cb60e25e 100644 --- a/Resources/Locale/en-US/fluids/components/absorbent-component.ftl +++ b/Resources/Locale/en-US/fluids/components/absorbent-component.ftl @@ -1,7 +1,7 @@ mopping-system-target-container-empty = { CAPITALIZE(THE($target)) } is empty! mopping-system-target-container-empty-water = { CAPITALIZE(THE($target)) } has no water! -mopping-system-puddle-space = { CAPITALIZE(THE($used)) } is full of water -mopping-system-puddle-evaporate = { CAPITALIZE(THE($target)) } is evaporating +mopping-system-puddle-space = { CAPITALIZE(THE($used)) } is full of water. +mopping-system-puddle-already-mopped = { CAPITALIZE(THE($target)) } is already mopped. mopping-system-no-water = { CAPITALIZE(THE($used)) } has no water! mopping-system-no-hands = You have no hands! From a4ac8eec82728f636fbf77db7e6931f6dfe71551 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Jul 2025 21:51:51 +0000 Subject: [PATCH 060/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 705d1e7d4f..3ea47a96ae 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Fildrance - changes: - - message: returned deconstruct to the top level option on RCD - type: Fix - id: 8226 - time: '2025-04-18T04:50:15.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36486 - author: ciaran changes: - message: Added a button to scroll back to the bottom of the chat box @@ -3888,3 +3881,11 @@ id: 8737 time: '2025-07-04T05:08:45.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38664 +- author: perryprog + changes: + - message: You can now mop space lube, letting it evaporate faster than it would + on its own. + type: Tweak + id: 8738 + time: '2025-07-04T21:50:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38743 From b36aedde6bfed7362d4119e2be23d1cf6a675c3a Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sat, 5 Jul 2025 00:19:31 +0200 Subject: [PATCH 061/105] Cleanup warning in StomachSystem (#38748) you did not see this --- Content.Shared/Body/Systems/StomachSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Shared/Body/Systems/StomachSystem.cs b/Content.Shared/Body/Systems/StomachSystem.cs index d0ecb6b93b..8b2df453a0 100644 --- a/Content.Shared/Body/Systems/StomachSystem.cs +++ b/Content.Shared/Body/Systems/StomachSystem.cs @@ -1,7 +1,6 @@ using Content.Shared.Body.Components; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; -using Content.Shared.Body.Events; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; From edbde7b7b99d0286fc01015a3a2c05491115b371 Mon Sep 17 00:00:00 2001 From: Mora <46364955+TrixxedHeart@users.noreply.github.com> Date: Fri, 4 Jul 2025 18:06:55 -0500 Subject: [PATCH 062/105] Vox scars (#38592) * Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl * Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl" This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15. * locale key fix * Changed top surgery scar names to be more generalized * Adjusted face scars * Formatting fixes --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> --- Resources/Locale/en-US/markings/vox.ftl | 47 +++++++ .../Locale/en-US/markings/vox_tattoos.ftl | 11 -- .../Mobs/Customization/Markings/vox_scars.yml | 118 ++++++++++++++++++ .../Customization/vox_scars.rsi/meta.json | 59 +++++++++ .../vox_scars.rsi/vox_scar_chest.png | Bin 0 -> 3165 bytes .../vox_scars.rsi/vox_scar_chest_bullets.png | Bin 0 -> 3065 bytes .../vox_scars.rsi/vox_scar_eye_left.png | Bin 0 -> 3011 bytes .../vox_scars.rsi/vox_scar_eye_left_small.png | Bin 0 -> 2992 bytes .../vox_scars.rsi/vox_scar_eye_right.png | Bin 0 -> 3007 bytes .../vox_scar_eye_right_small.png | Bin 0 -> 2993 bytes .../vox_scars.rsi/vox_scar_face_1.png | Bin 0 -> 3244 bytes .../vox_scars.rsi/vox_scar_face_2.png | Bin 0 -> 3126 bytes .../vox_scars.rsi/vox_scar_neck.png | Bin 0 -> 2978 bytes .../vox_scar_stomach_bullets.png | Bin 0 -> 3028 bytes .../vox_scars.rsi/vox_top_surgery_long.png | Bin 0 -> 3002 bytes .../vox_scars.rsi/vox_top_surgery_short.png | Bin 0 -> 3005 bytes 16 files changed, 224 insertions(+), 11 deletions(-) create mode 100644 Resources/Locale/en-US/markings/vox.ftl delete mode 100644 Resources/Locale/en-US/markings/vox_tattoos.ftl create mode 100644 Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_scars.yml create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest_bullets.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left_small.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_right.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_right_small.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_face_1.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_face_2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_neck.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_stomach_bullets.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_long.png create mode 100644 Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_short.png diff --git a/Resources/Locale/en-US/markings/vox.ftl b/Resources/Locale/en-US/markings/vox.ftl new file mode 100644 index 0000000000..37502bc7e0 --- /dev/null +++ b/Resources/Locale/en-US/markings/vox.ftl @@ -0,0 +1,47 @@ +marking-TattooVoxHeartLeftArm-heart_l_arm = Vox Left Arm Tattoo (Heart) +marking-TattooVoxHeartLeftArm = Vox Left Arm Tattoo (Heart) + +marking-TattooVoxHeartRightArm-heart_r_arm = Vox Right Arm Tattoo (Heart) +marking-TattooVoxHeartRightArm = Vox Right Arm Tattoo (Heart) + +marking-TattooVoxHiveChest-hive_s = Vox Chest Tattoo (hive) +marking-TattooVoxHiveChest = Vox Chest Tattoo (hive) + +marking-TattooVoxNightlingChest-nightling_s = Vox Chest Tattoo (nightling) +marking-TattooVoxNightlingChest = Vox Chest Tattoo (nightling) + +marking-VoxScarEyeRight-vox_scar_eye_right = Right Eye Scar +marking-VoxScarEyeRight = Eye Scar (Right) + +marking-VoxScarEyeLeft-vox_scar_eye_left = Left Eye Scar +marking-VoxScarEyeLeft = Eye Scar (Left) + +marking-VoxScarTopSurgeryShort-vox_scar_top_surgery_short = Thoracotomy Scar +marking-VoxScarTopSurgeryShort = Thoracotomy Scar + +marking-VoxScarTopSurgeryLong-vox_scar_top_surgery_long = Clamshell Scar +marking-VoxScarTopSurgeryLong = Clamshell Scar + +marking-VoxScarChest-vox_scar_chest = Chest Scar +marking-VoxScarChest = Chest Scar + +marking-VoxScarNeck-vox_scar_neck = Neck Scar +marking-VoxScarNeck = Neck Scar + +marking-VoxScarChestBullets-vox_scar_chest_bullets = Bullet Holes Scar +marking-VoxScarChestBullets = Chest Scar (Bullets) + +marking-VoxScarStomachBullets-vox_scar_stomach_bullets = Bullet Holes Scar +marking-VoxScarStomachBullets = Stomach Scar (Bullets) + +marking-VoxScarFace1-vox_scar_face_1 = Face Scar +marking-VoxScarFace1 = Face Scar (Large) + +marking-VoxScarFace2-vox_scar_face_2 = Face Scar +marking-VoxScarFace2 = Face Scar (Small) + +marking-VoxScarEyeRightSmall-vox_scar_eye_right_small = Right Eye Scar (Small) +marking-VoxScarEyeRightSmall = Small Eye Scar (Right) + +marking-VoxScarEyeLeftSmall-vox_scar_eye_left_small = Left Eye Scar (Small) +marking-VoxScarEyeLeftSmall = Small Eye Scar (Left) \ No newline at end of file diff --git a/Resources/Locale/en-US/markings/vox_tattoos.ftl b/Resources/Locale/en-US/markings/vox_tattoos.ftl deleted file mode 100644 index f7f3c7292c..0000000000 --- a/Resources/Locale/en-US/markings/vox_tattoos.ftl +++ /dev/null @@ -1,11 +0,0 @@ -marking-TattooVoxHeartLeftArm-heart_l_arm = Vox Left Arm Tattoo (Heart) -marking-TattooVoxHeartLeftArm = Vox Left Arm Tattoo (Heart) - -marking-TattooVoxHeartRightArm-heart_r_arm = Vox Right Arm Tattoo (Heart) -marking-TattooVoxHeartRightArm = Vox Right Arm Tattoo (Heart) - -marking-TattooVoxHiveChest-hive_s = Vox Chest Tattoo (hive) -marking-TattooVoxHiveChest = Vox Chest Tattoo (hive) - -marking-TattooVoxNightlingChest-nightling_s = Vox Chest Tattoo (nightling) -marking-TattooVoxNightlingChest = Vox Chest Tattoo (nightling) diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_scars.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_scars.yml new file mode 100644 index 0000000000..5998ddc237 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_scars.yml @@ -0,0 +1,118 @@ +- type: marking + id: VoxScarEyeRight + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_eye_right + +- type: marking + id: VoxScarEyeLeft + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_eye_left + +- type: marking + id: VoxScarTopSurgeryShort + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_top_surgery_short + +- type: marking + id: VoxScarTopSurgeryLong + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_top_surgery_long + +- type: marking + id: VoxScarChest + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_chest + +- type: marking + id: VoxScarNeck + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_neck + +- type: marking + id: VoxScarChestBullets + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_chest_bullets + +- type: marking + id: VoxScarStomachBullets + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_stomach_bullets + +- type: marking + id: VoxScarFace1 + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_face_1 + +- type: marking + id: VoxScarFace2 + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_face_2 + +- type: marking + id: VoxScarEyeRightSmall + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_eye_right_small + +- type: marking + id: VoxScarEyeLeftSmall + bodyPart: Head + markingCategory: Head + speciesRestriction: [Vox] + followSkinColor: true + sprites: + - sprite: Mobs/Customization/vox_scars.rsi + state: vox_scar_eye_left_small \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_scars.rsi/meta.json new file mode 100644 index 0000000000..7e74ffb8b6 --- /dev/null +++ b/Resources/Textures/Mobs/Customization/vox_scars.rsi/meta.json @@ -0,0 +1,59 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "vox_scar_chest, vox_scar_eye_left, vox_scar_eye_right, vox_scar_top_surgery_long and vox_scar_top_surgery_short drawn by Ubaser, vox_scar_neck, vox_scar_chest_bullets, vox_scar_stomach_bullets, vox_scar_face_1 and vox_scar_face_2 originally drawn by Ktyria(discord) edited by TrixxedHeart, vox_scar_eye_left_small and vox_scar_eye_right_small modified from vox_scar_eye_left and vox_scar_eye_right originally by Boaz1111(github) edited by TrixxedHeart.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "vox_scar_eye_left", + "directions": 4 + }, + { + "name": "vox_scar_eye_right", + "directions": 4 + }, + { + "name": "vox_top_surgery_short", + "directions": 4 + }, + { + "name": "vox_top_surgery_long", + "directions": 4 + }, + { + "name": "vox_scar_chest", + "directions": 4 + }, + { + "name": "vox_scar_neck", + "directions": 4 + }, + { + "name": "vox_scar_chest_bullets", + "directions": 4 + }, + { + "name": "vox_scar_stomach_bullets", + "directions": 4 + }, + { + "name": "vox_scar_face_1", + "directions": 4 + }, + { + "name": "vox_scar_face_2", + "directions": 4 + }, + { + "name": "vox_scar_eye_left_small", + "directions": 4 + }, + { + "name": "vox_scar_eye_right_small", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest.png new file mode 100644 index 0000000000000000000000000000000000000000..59c04641bd2ffcdbd570284357a144218536360f GIT binary patch literal 3165 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600C)9L_t(|obB47ZUR9N2H;s! zLa5@QP<8b^3FuRsATPnN8dg$&4%2%SETV?P6hDY&lS}39^d=Mj{{iM^znM!e*>lWH z&m0E;002O{2h{)o0001hb`PonfD}OMJ-=_aPNdj~&k+G=y=Nk#`|Uy$B2+QDQ`7LceCKSfBbZ_!0yF005xf zgK7W(0000$y9d<(00000fOZe60RR91008YCR09A20Khgt7XtrWuS7(Yb31JsAYIUw z)G!P1wcGK%@3W>pj7fmfwI9YDKw5jLpEAq=e6H90vEMt1_n*ihz;U(W>TqxgqO_hl zfE1}Kdb0ph0RR91008YCR09A20002mJ*Wl%&kpba+>K9=4xDnc00000NkvXXu0mjf D4e{Ne literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest_bullets.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_chest_bullets.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9bff22762fb324cac8e3d0de03c96c5c2bfe37 GIT binary patch literal 3065 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16009L_L_t(|obB2%5`r)gg<*0B zdRrSkhLy+h7#xR+V@N|w&mGn(GZc<9fh8}I|5bMT_!6+$U}nvk6951J0Cfjx00000 z0Ms3%0RR91_5n00000 z>JHKX00000s5?jl00000pza_I00000fVzV;000000O}6O@!S!p62LRn0Ti_#phz+M z0soR}0gBiWQpRg1p;`d1000000H`}i0{{R30HE$5&FKL?5^X<_rdW}T00000NkvXX Hu0mjfzrd`6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left.png new file mode 100644 index 0000000000000000000000000000000000000000..b369711f3b8808825b80ea99f40c6444c0b1feb7 GIT binary patch literal 3011 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16007TPL_t(|obB165yC(aMq#cF z8bG816b?b^h+j~1fVyd2_S#~WdOXVTQs{v_78M10CQCgz;n37raRSp0pG_xmfL;30COdP z00Ia=Z$J}3009J`H=qe1fB*u}8_)z0KmY;g4QSN^`~VSe(}65(%47fl002ovPDHLk FV1k)#kaqw8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left_small.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_left_small.png new file mode 100644 index 0000000000000000000000000000000000000000..5fc01b19b01ad5553549e93980f1175b95c49669 GIT binary patch literal 2992 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16006v6L_t(|obB165yAivL{ZWW zf(lT0s3Q`E1pzh+nL5Cur~pAXM-LgoPRRQe?7TU5O;s)CTmt|Afb@oF0EPg(Z(S{S zhh~I5KhFgW0eJSOTDNBx@DBk1002OGLo@&Y002mDhz0-v008L?(EtDd03f{~8UO$Q z0HilW0{{TP_W@q_Ypu5XNqmo8z!(6J{!*Lv=mMq?00000q&GwZ0001h^oD2v0001x m-VhA{0002e8=?W2JHQ8hlFxxd>Ki5i0000f6 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16007HLL_t(|obB1M5dmQog;86F z1_UY)$pqA~kr7D=NJU1pbr8rzDiCNu9lsuob!YAQD!6mzWv?ow4EkIJ004mWhG+mj z0eGGdWwcmVE$sPuF5nY@d$TQ*dglWEApigX07!3$1^@s60O<|U00000AiW_P00000 zq&GwZ0001h^oD2v008(tz~gc(aGC%B002ovPDHLkV1mWJ BkhcH; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_right_small.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_eye_right_small.png new file mode 100644 index 0000000000000000000000000000000000000000..76efe1412f15126f2450ffa9466407ec88f3a55f GIT binary patch literal 2993 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16006y7L_t(|obB165du*VL_sba z1QDR{5XVUr76e!n^5OuGA_4^2EJ=Kr`gQ#xnCe=$Lsc#2+yDRofb@oF09pWi?$=uG z4nu=If6oQ90C-KOT90QJ&|?4q005BQ5DfqT007b(q5%K^06=;}Gynhq07!3$1^@s6 z0O<|U0002c2f+JrtJQYj`~%$$z_02C;5l7tGag+)>i_@%03f{~8UO$Q0HilW0{{R3 nfb@oF00000klqjtz}x}8U1iUKS@@dn00000NkvXXu0mjfwF-zF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_face_1.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_face_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c19ce0cf398a692f66e7f7d234b447119f8377aa GIT binary patch literal 3244 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%0Dy!50Qvv` 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600BZtL_t(|obB2nZ^BR%#qs+L zN$u1UET091o1d>nkyO3}g~sFOs`gp1BvZ35skw;dEo6qldvIv@9|J*@(_e3kxCD2% zXHEbB007h-qyYc`002;Tkmh25UEBKmb{qct`J?Bm3Fu?=Mc4hF>{w6U?8*svnNH2j zY|(Y0kJ0n{`t@#~q6rxDmCxZJ2mk;8s5?jl00000pza_I00000fVzV;000000O}6X z000000H`}i1Hf1TJ~tcx+V8D&HCF}TW3}?P^*ZF&;sc(^u5JBwHnSlmGb>xnRslHO z5Z_~A+Q;aVrm-QV;;nQsKwg(mn#ShKG;?9zG@G_ zzyBJ!W%2~nn7GmY3e*Y!0001hx`Q+T00000>JHKX00000s5?jlz_SA!0YjxLkUXR_ QAOHXW07*qoM6N<$f|;M#g#Z8m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_neck.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_scar_neck.png new file mode 100644 index 0000000000000000000000000000000000000000..9feed1955e5c5edf9fae3a715b39f0a870ff7187 GIT binary patch literal 2978 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 F{|Ad%ob3Pr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_long.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_long.png new file mode 100644 index 0000000000000000000000000000000000000000..5624b47c8c0f778144715dd50025108e229e5ce7 GIT binary patch literal 3002 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R160072GL_t(|obB2zjsigdgwdL0 zJV7J42okrNQ?AA#xd;NiSwBgyBiIc;C3xQfx+^a&dm3ZplbZkl0MOo04FCWD0NNX> z0RR91KzlssR81;Ije#0GN){fm6lN4gdfE07*qoM6N<$g7|ii-v9sr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_short.png b/Resources/Textures/Mobs/Customization/vox_scars.rsi/vox_top_surgery_short.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa4e10d17535bc4a433067ff2749f85a026726c GIT binary patch literal 3005 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01m?d01m?e$8V@)0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R16007BJL_t(|obB2n3Iag@h2a_4 zE@lNUVlWs4v!^r*27|$i2%5#dFedG?=nMP(2bg($Oq|+UD`Tz#001DpAsPSx005*n zL<0Z-0D$y{XaE3w32@yXS~s1P*7s$;S=HO|+-ldA{_!k}-M0Q{=g;y20001x-VhA{ z0002e8=?UK002OGLo@&Y002mDhz0-v008L?(EtDd03f{~8i1hy_tWKbz(4*7y#FV> zo2{3F?(+fw005BQ5DfqT007b(q5%K^VB7#NW8T<-R) Date: Fri, 4 Jul 2025 23:08:03 +0000 Subject: [PATCH 063/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3ea47a96ae..808228d727 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: ciaran - changes: - - message: Added a button to scroll back to the bottom of the chat box - type: Add - id: 8227 - time: '2025-04-18T07:43:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35913 - author: Tayrtahn changes: - message: The popup when pointing at an item in a character's inventory now mentions @@ -3889,3 +3882,10 @@ id: 8738 time: '2025-07-04T21:50:44.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38743 +- author: TrixxedHeart + changes: + - message: Vox now have scar markings. + type: Add + id: 8739 + time: '2025-07-04T23:06:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38592 From 78e8d98137f7f362cb396700be802a9023ec50a7 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Fri, 4 Jul 2025 19:14:12 -0400 Subject: [PATCH 064/105] UnlockNode command to LEC. (#38751) * commit * Update UnlockNodeCommand.cs * commit * move command locale to its own file. * Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Artifact/UnlockNodeCommand.cs | 68 +++++++++++++++ .../Artifact/XenoArtifactUnlockNodeCommand.cs | 84 ------------------- .../en-US/commands/unlocknode-command.ftl | 4 + .../xenoarchaeology/artifact-component.ftl | 8 +- 4 files changed, 73 insertions(+), 91 deletions(-) create mode 100644 Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs delete mode 100644 Content.Server/Xenoarchaeology/Artifact/XenoArtifactUnlockNodeCommand.cs create mode 100644 Resources/Locale/en-US/commands/unlocknode-command.ftl diff --git a/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs b/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs new file mode 100644 index 0000000000..ea86186782 --- /dev/null +++ b/Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs @@ -0,0 +1,68 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.Xenoarchaeology.Artifact.Components; +using Robust.Shared.Console; + +namespace Content.Server.Xenoarchaeology.Artifact; + +/// Command for unlocking a specific node of a xeno artifact. +[AdminCommand(AdminFlags.Debug)] +public sealed class UnlockNodeCommand : LocalizedEntityCommands +{ + [Dependency] private readonly XenoArtifactSystem _artiSystem = default!; + + public override string Command => "unlocknode"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 2) + { + shell.WriteError(Loc.GetString("shell-wrong-arguments-number")); + return; + } + + if (!NetEntity.TryParse(args[1], out var netNode) || !EntityManager.TryGetEntity(netNode, out var entityUid)) + { + shell.WriteError(Loc.GetString("shell-could-not-find-entity-with-uid", ("uid", args[1]))); + return; + } + + _artiSystem.SetNodeUnlocked(entityUid.Value); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + switch (args.Length) + { + case 1: + { + var query = EntityManager.EntityQueryEnumerator(); + var completionOptions = new List(); + while (query.MoveNext(out var uid, out _)) + { + completionOptions.Add(new CompletionOption(uid.ToString())); + } + + return CompletionResult.FromHintOptions(completionOptions, Loc.GetString("cmd-unlocknode-artifact-hint")); + } + case 2 when + NetEntity.TryParse(args[0], out var netEnt) && + EntityManager.TryGetEntity(netEnt, out var artifactUid) && + EntityManager.TryGetComponent(artifactUid, out var comp): + { + var result = new List(); + foreach (var node in _artiSystem.GetAllNodes((artifactUid.Value, comp))) + { + var metaData = EntityManager.MetaQuery.Comp(artifactUid.Value); + var entityUidStr = EntityManager.GetNetEntity(node).ToString(); + var completionOption = new CompletionOption(entityUidStr, metaData.EntityName); + result.Add(completionOption); + } + + return CompletionResult.FromHintOptions(result, Loc.GetString("cmd-unlocknode-node-hint")); + } + default: + return CompletionResult.Empty; + } + } +} diff --git a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactUnlockNodeCommand.cs b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactUnlockNodeCommand.cs deleted file mode 100644 index 1782619780..0000000000 --- a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactUnlockNodeCommand.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Content.Server.Administration; -using Content.Shared.Administration; -using Content.Shared.Xenoarchaeology.Artifact.Components; -using Robust.Shared.Console; - -namespace Content.Server.Xenoarchaeology.Artifact; - -/// Command for unlocking specific node of xeno artifact. -[AdminCommand(AdminFlags.Debug)] -public sealed class XenoArtifactUnlockNodeCommand : LocalizedCommands -{ - [Dependency] private readonly EntityManager _entities = default!; - - /// - public override string Command => "unlocknode"; - - /// - public override string Description => Loc.GetString("cmd-unlocknode-desc"); - - /// - public override string Help => Loc.GetString("cmd-unlocknode-help"); - - /// - public override void Execute(IConsoleShell shell, string argStr, string[] args) - { - if (args.Length != 2) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-unlocknode-arg-num")); - return; - } - - if (!NetEntity.TryParse(args[1], out var netNode)) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-unlocknode-invalid-entity")); - return; - } - - if (!_entities.TryGetEntity(netNode, out var entityUid)) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-unlocknode-invalid-entity")); - return; - } - _entities.System() - .SetNodeUnlocked(entityUid.Value); - } - - /// - public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) - { - if (args.Length == 1) - { - var query = _entities.EntityQueryEnumerator(); - var completionOptions = new List(); - while (query.MoveNext(out var uid, out _)) - { - completionOptions.Add(new CompletionOption(uid.ToString())); - } - - return CompletionResult.FromHintOptions(completionOptions, ""); - } - - if (args.Length == 2 && - NetEntity.TryParse(args[0], out var netEnt) && - _entities.TryGetEntity(netEnt, out var artifactUid) && - _entities.TryGetComponent(artifactUid, out var comp)) - { - var artifactSystem = _entities.System(); - - var result = new List(); - foreach (var node in artifactSystem.GetAllNodes((artifactUid.Value, comp))) - { - var metaData = _entities.MetaQuery.Comp(artifactUid.Value); - var entityUidStr = _entities.GetNetEntity(node) - .ToString(); - var completionOption = new CompletionOption(entityUidStr, metaData.EntityName); - result.Add(completionOption); - } - - return CompletionResult.FromHintOptions(result, ""); - } - - return CompletionResult.Empty; - } -} diff --git a/Resources/Locale/en-US/commands/unlocknode-command.ftl b/Resources/Locale/en-US/commands/unlocknode-command.ftl new file mode 100644 index 0000000000..5a3b8259dd --- /dev/null +++ b/Resources/Locale/en-US/commands/unlocknode-command.ftl @@ -0,0 +1,4 @@ +cmd-unlocknode-desc = Unlocks a node on a given artifact +cmd-unlocknode-help = unlocknode +cmd-unlocknode-artifact-hint = +cmd-unlocknode-node-hint = diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl index 50fa136928..90029b282c 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl @@ -1,10 +1,4 @@ -### Commands -cmd-unlocknode-desc = Unlocks a node on a given artifact -cmd-unlocknode-help = unlocknode -cmd-parse-failure-unlocknode-arg-num = Incorrect number of args -cmd-parse-failure-unlocknode-invalid-entity = Provided netEntity is not valid node - -### Verbs +### Verbs artifact-verb-make-always-active = Make artifact always active artifact-verb-activate = Activate artifact From 6cefc412a3d9f7f064ddd49e2d6dc66bfee87d71 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Sat, 5 Jul 2025 02:28:56 -0400 Subject: [PATCH 065/105] fix: spellbooks can have infinite charges (#38376) * fix: spellbooks can have infinite charges * refactor: indicate infinite spellbook charges with null Not sure if I like this much better... --- .../Magic/Components/SpellbookComponent.cs | 6 ++++-- Content.Shared/Magic/SpellbookSystem.cs | 9 ++++++--- .../Entities/Objects/Magic/books.yml | 20 +++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Content.Shared/Magic/Components/SpellbookComponent.cs b/Content.Shared/Magic/Components/SpellbookComponent.cs index f1b307c245..69c2bac2a4 100644 --- a/Content.Shared/Magic/Components/SpellbookComponent.cs +++ b/Content.Shared/Magic/Components/SpellbookComponent.cs @@ -16,12 +16,14 @@ public sealed partial class SpellbookComponent : Component [ViewVariables] public readonly List Spells = new(); + // The three fields below are just used for initialization. /// - /// The three fields below is just used for initialization. + /// Dictionary of spell prototypes to charge counts. + /// If the charge count is null, it means the spell has infinite charges. /// [DataField] [ViewVariables(VVAccess.ReadWrite)] - public Dictionary SpellActions = new(); + public Dictionary SpellActions = new(); [DataField] [ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Shared/Magic/SpellbookSystem.cs b/Content.Shared/Magic/SpellbookSystem.cs index 6ef0a10b0c..ca01819bce 100644 --- a/Content.Shared/Magic/SpellbookSystem.cs +++ b/Content.Shared/Magic/SpellbookSystem.cs @@ -33,7 +33,9 @@ public sealed class SpellbookSystem : EntitySystem if (spell == null) continue; - _sharedCharges.SetCharges(spell.Value, charges); + // Null means infinite charges. + if (charges is { } count) + _sharedCharges.SetCharges(spell.Value, count); ent.Comp.Spells.Add(spell.Value); } } @@ -73,8 +75,9 @@ public sealed class SpellbookSystem : EntitySystem foreach (var (id, charges) in ent.Comp.SpellActions) { EntityUid? actionId = null; - if (_actions.AddAction(args.Args.User, ref actionId, id)) - _sharedCharges.SetCharges(actionId.Value, charges); + if (_actions.AddAction(args.Args.User, ref actionId, id) + && charges is { } count) // Null means infinite charges + _sharedCharges.SetCharges(actionId.Value, count); } } diff --git a/Resources/Prototypes/Entities/Objects/Magic/books.yml b/Resources/Prototypes/Entities/Objects/Magic/books.yml index db604f92d3..db0d3c8d51 100644 --- a/Resources/Prototypes/Entities/Objects/Magic/books.yml +++ b/Resources/Prototypes/Entities/Objects/Magic/books.yml @@ -69,7 +69,7 @@ components: - type: Spellbook spellActions: - ActionSpawnMagicarpSpell: -1 + ActionSpawnMagicarpSpell: null - type: entity id: ForceWallSpellbook @@ -92,7 +92,7 @@ color: gold - type: Spellbook spellActions: - ActionForceWall: -1 + ActionForceWall: null - type: entity id: BlinkBook @@ -113,7 +113,7 @@ color: gold - type: Spellbook spellActions: - ActionBlink: -1 + ActionBlink: null - type: entity id: SmiteBook @@ -136,7 +136,7 @@ - state: overlay_blood - type: Spellbook spellActions: - ActionSmiteNoReq: -1 + ActionSmiteNoReq: null - type: entity id: KnockSpellbook @@ -158,7 +158,7 @@ color: "#98c495" - type: Spellbook spellActions: - ActionKnock: -1 + ActionKnock: null - type: entity id: FireballSpellbook @@ -182,7 +182,7 @@ shader: unshaded - type: Spellbook spellActions: - ActionFireball: -1 + ActionFireball: null - type: entity id: ScrollRunes @@ -197,7 +197,7 @@ - state: spell_default - type: Spellbook spellActions: - ActionFlashRune: -1 - ActionExplosionRune: -1 - ActionIgniteRune: -1 - ActionStunRune: -1 + ActionFlashRune: null + ActionExplosionRune: null + ActionIgniteRune: null + ActionStunRune: null From 94fa94d4d4fdd2812c5c9f16275448917f3fd487 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 5 Jul 2025 06:30:03 +0000 Subject: [PATCH 066/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 808228d727..508bb580c8 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: The popup when pointing at an item in a character's inventory now mentions - that character. - type: Tweak - id: 8228 - time: '2025-04-18T12:09:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36252 - author: slarticodefast changes: - message: Punching lights while wearing insulated gloves will no longer electrocute @@ -3889,3 +3881,10 @@ id: 8739 time: '2025-07-04T23:06:55.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38592 +- author: perryprog + changes: + - message: Spellbooks with infinite charges work again. + type: Fix + id: 8740 + time: '2025-07-05T06:28:56.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38376 From 14668f2414281f77469175780fe61e7c08e266c2 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Sat, 5 Jul 2025 02:28:59 -0700 Subject: [PATCH 067/105] Minor escape menu UX improvements (#38650) --- Content.Client/Options/UI/EscapeMenu.xaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Content.Client/Options/UI/EscapeMenu.xaml b/Content.Client/Options/UI/EscapeMenu.xaml index 71da231f29..6aa14f27e7 100644 --- a/Content.Client/Options/UI/EscapeMenu.xaml +++ b/Content.Client/Options/UI/EscapeMenu.xaml @@ -6,13 +6,16 @@ Resizable="False"> - - [DataField] [Access(typeof(MetabolizerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public HashSet>? MetabolizerTypes = null; + public HashSet>? MetabolizerTypes; /// /// Should this metabolizer remove chemicals that have no metabolisms defined? /// As a stop-gap, basically. /// [DataField] - public bool RemoveEmpty = false; + public bool RemoveEmpty; /// /// How many reagents can this metabolizer process at once? @@ -67,7 +79,7 @@ namespace Content.Server.Body.Components /// A list of metabolism groups that this metabolizer will act on, in order of precedence. /// [DataField("groups")] - public List? MetabolismGroups = default!; + public List? MetabolismGroups; } /// @@ -78,7 +90,7 @@ namespace Content.Server.Body.Components public sealed partial class MetabolismGroupEntry { [DataField(required: true)] - public ProtoId Id = default!; + public ProtoId Id; [DataField("rateModifier")] public FixedPoint2 MetabolismRateModifier = 1.0; diff --git a/Content.Server/Body/Components/RespiratorComponent.cs b/Content.Server/Body/Components/RespiratorComponent.cs index 19585e9f00..24f4ae85e1 100644 --- a/Content.Server/Body/Components/RespiratorComponent.cs +++ b/Content.Server/Body/Components/RespiratorComponent.cs @@ -1,5 +1,4 @@ using Content.Server.Body.Systems; -using Content.Shared.Alert; using Content.Shared.Atmos; using Content.Shared.Chat.Prototypes; using Content.Shared.Damage; @@ -8,7 +7,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components { - [RegisterComponent, Access(typeof(RespiratorSystem))] + [RegisterComponent, Access(typeof(RespiratorSystem)), AutoGenerateComponentPause] public sealed partial class RespiratorComponent : Component { /// @@ -36,7 +35,7 @@ namespace Content.Server.Body.Components /// /// The next time that this body will inhale or exhale. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] public TimeSpan NextUpdate; /// @@ -46,6 +45,18 @@ namespace Content.Server.Body.Components [DataField] public TimeSpan UpdateInterval = TimeSpan.FromSeconds(2); + /// + /// Multiplier applied to for adjusting based on metabolic rate multiplier. + /// + [DataField] + public float UpdateIntervalMultiplier = 1f; + + /// + /// Adjusted update interval based off of the multiplier value. + /// + [ViewVariables] + public TimeSpan AdjustedUpdateInterval => UpdateInterval * UpdateIntervalMultiplier; + /// /// Saturation level. Reduced by UpdateInterval each tick. /// Can be thought of as 'how many seconds you have until you start suffocating' in this configuration. diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index 5577b42a06..c59f87f576 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Components; using Content.Shared.Administration.Logs; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; +using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; @@ -18,7 +19,8 @@ using Robust.Shared.Timing; namespace Content.Server.Body.Systems { - public sealed class MetabolizerSystem : EntitySystem + /// + public sealed class MetabolizerSystem : SharedMetabolizerSystem { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -45,7 +47,7 @@ namespace Content.Server.Body.Systems private void OnMapInit(Entity ent, ref MapInitEvent args) { - ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.AdjustedUpdateInterval; } private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) @@ -65,20 +67,9 @@ namespace Content.Server.Body.Systems } } - private void OnApplyMetabolicMultiplier( - Entity ent, - ref ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier(Entity ent, ref ApplyMetabolicMultiplierEvent args) { - // TODO REFACTOR THIS - // This will slowly drift over time due to floating point errors. - // Instead, raise an event with the base rates and allow modifiers to get applied to it. - if (args.Apply) - { - ent.Comp.UpdateInterval *= args.Multiplier; - return; - } - - ent.Comp.UpdateInterval /= args.Multiplier; + ent.Comp.UpdateIntervalMultiplier = args.Multiplier; } public override void Update(float frameTime) @@ -99,7 +90,7 @@ namespace Content.Server.Body.Systems if (_gameTiming.CurTime < metab.NextUpdate) continue; - metab.NextUpdate += metab.UpdateInterval; + metab.NextUpdate += metab.AdjustedUpdateInterval; TryMetabolize((uid, metab)); } } diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index bc57108720..4e21236a77 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -48,7 +48,6 @@ public sealed class RespiratorSystem : EntitySystem // We want to process lung reagents before we inhale new reagents. UpdatesAfter.Add(typeof(MetabolizerSystem)); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnApplyMetabolicMultiplier); SubscribeLocalEvent(OnGasInhaled); SubscribeLocalEvent(OnGasExhaled); @@ -56,25 +55,20 @@ public sealed class RespiratorSystem : EntitySystem private void OnMapInit(Entity ent, ref MapInitEvent args) { - ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; - } - - private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) - { - ent.Comp.NextUpdate += args.PausedTime; + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.AdjustedUpdateInterval; } public override void Update(float frameTime) { base.Update(frameTime); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var respirator, out var body)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var respirator)) { if (_gameTiming.CurTime < respirator.NextUpdate) continue; - respirator.NextUpdate += respirator.UpdateInterval; + respirator.NextUpdate += respirator.AdjustedUpdateInterval; if (_mobState.IsDead(uid)) continue; @@ -396,27 +390,9 @@ public sealed class RespiratorSystem : EntitySystem Math.Clamp(respirator.Saturation, respirator.MinSaturation, respirator.MaxSaturation); } - private void OnApplyMetabolicMultiplier( - Entity ent, - ref ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier(Entity ent, ref ApplyMetabolicMultiplierEvent args) { - // TODO REFACTOR THIS - // This will slowly drift over time due to floating point errors. - // Instead, raise an event with the base rates and allow modifiers to get applied to it. - if (args.Apply) - { - ent.Comp.UpdateInterval *= args.Multiplier; - ent.Comp.Saturation *= args.Multiplier; - ent.Comp.MaxSaturation *= args.Multiplier; - ent.Comp.MinSaturation *= args.Multiplier; - return; - } - - // This way we don't have to worry about it breaking if the stasis bed component is destroyed - ent.Comp.UpdateInterval /= args.Multiplier; - ent.Comp.Saturation /= args.Multiplier; - ent.Comp.MaxSaturation /= args.Multiplier; - ent.Comp.MinSaturation /= args.Multiplier; + ent.Comp.UpdateIntervalMultiplier = args.Multiplier; } private void OnGasInhaled(Entity entity, ref InhaledGasEvent args) diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs index 9dc0c2c498..1262e231d7 100644 --- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs @@ -45,6 +45,7 @@ namespace Content.Server.Power.EntitySystems UpdatesAfter.Add(typeof(NodeGroupSystem)); _solver = new(_cfg.GetCVar(CCVars.DebugPow3rDisableParallel)); + SubscribeLocalEvent(ApcPowerReceiverMapInit); SubscribeLocalEvent(ApcPowerReceiverInit); SubscribeLocalEvent(ApcPowerReceiverShutdown); SubscribeLocalEvent(ApcPowerReceiverRemove); @@ -74,6 +75,11 @@ namespace Content.Server.Power.EntitySystems _solver = new(val); } + private void ApcPowerReceiverMapInit(Entity ent, ref MapInitEvent args) + { + _appearance.SetData(ent, PowerDeviceVisuals.Powered, ent.Comp.Powered); + } + private void ApcPowerReceiverInit(EntityUid uid, ApcPowerReceiverComponent component, ComponentInit args) { AllocLoad(component.NetworkLoad); diff --git a/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs b/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs new file mode 100644 index 0000000000..3a1c991b1e --- /dev/null +++ b/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Bed.Components; + +/// +/// Tracking component added to entities buckled to stasis beds. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedBedSystem))] +public sealed partial class StasisBedBuckledComponent : Component; diff --git a/Content.Shared/Bed/Components/StasisBedComponent.cs b/Content.Shared/Bed/Components/StasisBedComponent.cs new file mode 100644 index 0000000000..97936261d6 --- /dev/null +++ b/Content.Shared/Bed/Components/StasisBedComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.Buckle.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Bed.Components; + +/// +/// A that modifies a strapped entity's metabolic rate by the given multiplier +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedBedSystem))] +public sealed partial class StasisBedComponent : Component +{ + /// + /// What the metabolic update rate will be multiplied by (higher = slower metabolism) + /// + [DataField, AutoNetworkedField] + public float Multiplier = 10f; +} diff --git a/Content.Shared/Bed/SharedBedSystem.cs b/Content.Shared/Bed/SharedBedSystem.cs index cdf3ffcbd4..7e798111cf 100644 --- a/Content.Shared/Bed/SharedBedSystem.cs +++ b/Content.Shared/Bed/SharedBedSystem.cs @@ -1,7 +1,12 @@ using Content.Shared.Actions; using Content.Shared.Bed.Components; using Content.Shared.Bed.Sleep; +using Content.Shared.Body.Events; +using Content.Shared.Body.Systems; using Content.Shared.Buckle.Components; +using Content.Shared.Emag.Systems; +using Content.Shared.Power; +using Content.Shared.Power.EntitySystems; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -12,6 +17,9 @@ public abstract class SharedBedSystem : EntitySystem [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly ActionContainerSystem _actConts = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly SharedMetabolizerSystem _metabolizer = default!; + [Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!; [Dependency] private readonly SleepingSystem _sleepingSystem = default!; public override void Initialize() @@ -21,6 +29,12 @@ public abstract class SharedBedSystem : EntitySystem SubscribeLocalEvent(OnHealMapInit); SubscribeLocalEvent(OnStrapped); SubscribeLocalEvent(OnUnstrapped); + + SubscribeLocalEvent(OnStasisStrapped); + SubscribeLocalEvent(OnStasisUnstrapped); + SubscribeLocalEvent(OnStasisEmagged); + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnStasisGetMetabolicMultiplier); } private void OnHealMapInit(Entity ent, ref MapInitEvent args) @@ -46,4 +60,61 @@ public abstract class SharedBedSystem : EntitySystem _sleepingSystem.TryWaking(args.Buckle.Owner); RemComp(bed); } + + private void OnStasisStrapped(Entity ent, ref StrappedEvent args) + { + EnsureComp(args.Buckle); + _metabolizer.UpdateMetabolicMultiplier(args.Buckle); + } + + private void OnStasisUnstrapped(Entity ent, ref UnstrappedEvent args) + { + RemComp(ent); + _metabolizer.UpdateMetabolicMultiplier(args.Buckle); + } + + private void OnStasisEmagged(Entity ent, ref GotEmaggedEvent args) + { + if (!_emag.CompareFlag(args.Type, EmagType.Interaction)) + return; + + if (_emag.CheckFlag(ent, EmagType.Interaction)) + return; + + ent.Comp.Multiplier = 1f / ent.Comp.Multiplier; + UpdateMetabolisms(ent.Owner); + Dirty(ent); + + args.Handled = true; + } + + private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) + { + UpdateMetabolisms(ent.Owner); + } + + private void OnStasisGetMetabolicMultiplier(Entity ent, ref GetMetabolicMultiplierEvent args) + { + if (!TryComp(ent, out var buckle) || buckle.BuckledTo is not { } buckledTo) + return; + + if (!TryComp(buckledTo, out var stasis)) + return; + + if (!_powerReceiver.IsPowered(buckledTo)) + return; + + args.Multiplier *= stasis.Multiplier; + } + + protected void UpdateMetabolisms(Entity ent) + { + if (!Resolve(ent, ref ent.Comp, false)) + return; + + foreach (var buckledEntity in ent.Comp.BuckledEntities) + { + _metabolizer.UpdateMetabolicMultiplier(buckledEntity); + } + } } diff --git a/Content.Shared/Bed/StasisBedVisuals.cs b/Content.Shared/Bed/StasisBedVisuals.cs deleted file mode 100644 index cf7bc06460..0000000000 --- a/Content.Shared/Bed/StasisBedVisuals.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Bed -{ - [Serializable, NetSerializable] - public enum StasisBedVisuals : byte - { - IsOn, - } -} diff --git a/Content.Shared/Body/Components/BloodstreamComponent.cs b/Content.Shared/Body/Components/BloodstreamComponent.cs index 7997d92066..0139932262 100644 --- a/Content.Shared/Body/Components/BloodstreamComponent.cs +++ b/Content.Shared/Body/Components/BloodstreamComponent.cs @@ -37,6 +37,18 @@ public sealed partial class BloodstreamComponent : Component [DataField, AutoNetworkedField] public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3); + /// + /// Multiplier applied to for adjusting based on metabolic rate multiplier. + /// + [DataField, AutoNetworkedField] + public float UpdateIntervalMultiplier = 1f; + + /// + /// Adjusted update interval based off of the multiplier value. + /// + [ViewVariables] + public TimeSpan AdjustedUpdateInterval => UpdateInterval * UpdateIntervalMultiplier; + /// /// How much is this entity currently bleeding? /// Higher numbers mean more blood lost every tick. diff --git a/Content.Shared/Body/Components/StomachComponent.cs b/Content.Shared/Body/Components/StomachComponent.cs index b76dff0902..1b2f587824 100644 --- a/Content.Shared/Body/Components/StomachComponent.cs +++ b/Content.Shared/Body/Components/StomachComponent.cs @@ -23,6 +23,18 @@ namespace Content.Shared.Body.Components [DataField] public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1); + /// + /// Multiplier applied to for adjusting based on metabolic rate multiplier. + /// + [DataField] + public float UpdateIntervalMultiplier = 1f; + + /// + /// Adjusted update interval based off of the multiplier value. + /// + [ViewVariables] + public TimeSpan AdjustedUpdateInterval => UpdateInterval * UpdateIntervalMultiplier; + /// /// The solution inside of this stomach this transfers reagents to the body. /// diff --git a/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs b/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs deleted file mode 100644 index 1a7b589392..0000000000 --- a/Content.Shared/Body/Events/ApplyMetabolicMultiplierEvent.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Content.Shared.Body.Events; - -// TODO REFACTOR THIS -// This will cause rates to slowly drift over time due to floating point errors. -// Instead, the system that raised this should trigger an update and subscribe to get-modifier events. -[ByRefEvent] -public readonly record struct ApplyMetabolicMultiplierEvent( - EntityUid Uid, - float Multiplier, - bool Apply) -{ - /// - /// The entity whose metabolism is being modified. - /// - public readonly EntityUid Uid = Uid; - - /// - /// What the metabolism's update rate will be multiplied by. - /// - public readonly float Multiplier = Multiplier; - - /// - /// If true, apply the multiplier. If false, revert it. - /// - public readonly bool Apply = Apply; -} diff --git a/Content.Shared/Body/Events/MetabolizerEvents.cs b/Content.Shared/Body/Events/MetabolizerEvents.cs new file mode 100644 index 0000000000..f001c83f88 --- /dev/null +++ b/Content.Shared/Body/Events/MetabolizerEvents.cs @@ -0,0 +1,26 @@ +namespace Content.Shared.Body.Events; + +/// +/// Raised on an entity to determine their metabolic multiplier. +/// +[ByRefEvent] +public record struct GetMetabolicMultiplierEvent() +{ + /// + /// What the metabolism's update rate will be multiplied by. + /// + public float Multiplier = 1f; +} + +/// +/// Raised on an entity to apply their metabolic multiplier to relevant systems. +/// Note that you should be storing this value as to not accrue precision errors when it's modified. +/// +[ByRefEvent] +public readonly record struct ApplyMetabolicMultiplierEvent(float Multiplier) +{ + /// + /// What the metabolism's update rate will be multiplied by. + /// + public readonly float Multiplier = Multiplier; +} diff --git a/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs index 3b1674cf3c..b5d5100189 100644 --- a/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs +++ b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs @@ -64,7 +64,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem if (curTime < bloodstream.NextUpdate) continue; - bloodstream.NextUpdate += bloodstream.UpdateInterval; + bloodstream.NextUpdate += bloodstream.AdjustedUpdateInterval; DirtyField(uid, bloodstream, nameof(BloodstreamComponent.NextUpdate)); // needs to be dirtied on the client so it can be rerolled during prediction if (!SolutionContainer.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) @@ -101,12 +101,12 @@ public abstract class SharedBloodstreamSystem : EntitySystem // Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out _drunkSystem.TryApplyDrunkenness( uid, - (float)bloodstream.UpdateInterval.TotalSeconds * 2, + (float)bloodstream.AdjustedUpdateInterval.TotalSeconds * 2, applySlur: false); - _stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false); + _stutteringSystem.DoStutter(uid, bloodstream.AdjustedUpdateInterval * 2, refresh: false); // storing the drunk and stutter time so we can remove it independently from other effects additions - bloodstream.StatusTime += bloodstream.UpdateInterval * 2; + bloodstream.StatusTime += bloodstream.AdjustedUpdateInterval * 2; DirtyField(uid, bloodstream, nameof(BloodstreamComponent.StatusTime)); } else if (!_mobStateSystem.IsDead(uid)) @@ -129,7 +129,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem private void OnMapInit(Entity ent, ref MapInitEvent args) { - ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.UpdateInterval; + ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.AdjustedUpdateInterval; DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.NextUpdate)); } @@ -289,15 +289,8 @@ public abstract class SharedBloodstreamSystem : EntitySystem private void OnApplyMetabolicMultiplier(Entity ent, ref ApplyMetabolicMultiplierEvent args) { - // TODO REFACTOR THIS - // This will slowly drift over time due to floating point errors. - // Instead, raise an event with the base rates and allow modifiers to get applied to it. - if (args.Apply) - ent.Comp.UpdateInterval *= args.Multiplier; - else - ent.Comp.UpdateInterval /= args.Multiplier; - - DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.UpdateInterval)); + ent.Comp.UpdateIntervalMultiplier = args.Multiplier; + DirtyField(ent, ent.Comp, nameof(BloodstreamComponent.UpdateIntervalMultiplier)); } private void OnRejuvenate(Entity ent, ref RejuvenateEvent args) diff --git a/Content.Shared/Body/Systems/SharedMetabolizerSystem.cs b/Content.Shared/Body/Systems/SharedMetabolizerSystem.cs new file mode 100644 index 0000000000..24ab438f6d --- /dev/null +++ b/Content.Shared/Body/Systems/SharedMetabolizerSystem.cs @@ -0,0 +1,20 @@ +using Content.Shared.Body.Events; + +namespace Content.Shared.Body.Systems; + +public abstract class SharedMetabolizerSystem : EntitySystem +{ + /// + /// Updates the metabolic rate multiplier for a given entity, + /// raising both to determine what the multiplier is and to update relevant components. + /// + /// + public void UpdateMetabolicMultiplier(EntityUid uid) + { + var getEv = new GetMetabolicMultiplierEvent(); + RaiseLocalEvent(uid, ref getEv); + + var applyEv = new ApplyMetabolicMultiplierEvent(getEv.Multiplier); + RaiseLocalEvent(uid, ref applyEv); + } +} diff --git a/Content.Shared/Body/Systems/StomachSystem.cs b/Content.Shared/Body/Systems/StomachSystem.cs index 8b2df453a0..3d8647b14d 100644 --- a/Content.Shared/Body/Systems/StomachSystem.cs +++ b/Content.Shared/Body/Systems/StomachSystem.cs @@ -27,7 +27,7 @@ namespace Content.Shared.Body.Systems private void OnMapInit(Entity ent, ref MapInitEvent args) { - ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.AdjustedUpdateInterval; } private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) @@ -53,7 +53,7 @@ namespace Content.Shared.Body.Systems if (_gameTiming.CurTime < stomach.NextUpdate) continue; - stomach.NextUpdate += stomach.UpdateInterval; + stomach.NextUpdate += stomach.AdjustedUpdateInterval; // Get our solutions if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) @@ -67,7 +67,7 @@ namespace Content.Shared.Body.Systems var queue = new RemQueue(); foreach (var delta in stomach.ReagentDeltas) { - delta.Increment(stomach.UpdateInterval); + delta.Increment(stomach.AdjustedUpdateInterval); if (delta.Lifetime > stomach.DigestionDelay) { if (stomachSolution.TryGetReagent(delta.ReagentQuantity.Reagent, out var reagent)) @@ -95,18 +95,9 @@ namespace Content.Shared.Body.Systems } } - private void OnApplyMetabolicMultiplier( - Entity ent, - ref ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier(Entity ent, ref ApplyMetabolicMultiplierEvent args) { - if (args.Apply) - { - ent.Comp.UpdateInterval *= args.Multiplier; - return; - } - - // This way we don't have to worry about it breaking if the stasis bed component is destroyed - ent.Comp.UpdateInterval /= args.Multiplier; + ent.Comp.UpdateIntervalMultiplier = args.Multiplier; } public bool CanTransferSolution( diff --git a/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml b/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml index 4dd1197593..999cd7bf2a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml @@ -18,8 +18,13 @@ - state: icon - state: unlit shader: unshaded - map: ["enum.StasisBedVisualLayers.IsOn"] - - type: StasisBedVisuals + map: ["unlit"] + - type: GenericVisualizer + visuals: + enum.PowerDeviceVisuals.Powered: + unlit: + True: { visible: true } + False: { visible: false } - type: Appearance - type: ApcPowerReceiver powerLoad: 1000 From 2ba10ce02c58ec145829d2a33acf62bfa622ca50 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 6 Jul 2025 01:00:41 +0000 Subject: [PATCH 076/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3235b03622..39712ab7cf 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Minemoder - changes: - - message: Rainbow Cannabis Leaves no longer emit light due to a renderer limitation. - type: Remove - id: 8230 - time: '2025-04-18T14:12:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36479 - author: IProduceWidgets changes: - message: Holobarrier projectors are now more power efficient. @@ -3887,3 +3880,10 @@ id: 8741 time: '2025-07-05T09:28:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38650 +- author: EmoGarbage404 + changes: + - message: Fixed people asphyxiating if left on a stasis bed. + type: Fix + id: 8742 + time: '2025-07-06T00:59:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38762 From 7ea3120a07733f090c3c6d691f8800957c7d51f2 Mon Sep 17 00:00:00 2001 From: B_Kirill <153602297+B-Kirill@users.noreply.github.com> Date: Sun, 6 Jul 2025 20:28:29 +1000 Subject: [PATCH 077/105] Cleanup warnings: CS0414 (#38793) Cleanup --- Content.Server/Electrocution/ElectrocutionSystem.cs | 1 - Content.Server/Spider/SpiderSystem.cs | 1 - .../Worldgen/Systems/Debris/SimpleFloorPlanPopulatorSystem.cs | 1 - Content.Shared/Actions/ActionUpgradeSystem.cs | 1 - 4 files changed, 4 deletions(-) diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index 8647f087fc..cd2b69d2ce 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -40,7 +40,6 @@ namespace Content.Server.Electrocution; public sealed class ElectrocutionSystem : SharedElectrocutionSystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly DamageableSystem _damageable = default!; diff --git a/Content.Server/Spider/SpiderSystem.cs b/Content.Server/Spider/SpiderSystem.cs index 6e2e2b59a2..e6a7dd7806 100644 --- a/Content.Server/Spider/SpiderSystem.cs +++ b/Content.Server/Spider/SpiderSystem.cs @@ -10,7 +10,6 @@ namespace Content.Server.Spider; public sealed class SpiderSystem : SharedSpiderSystem { [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly TurfSystem _turf = default!; /// diff --git a/Content.Server/Worldgen/Systems/Debris/SimpleFloorPlanPopulatorSystem.cs b/Content.Server/Worldgen/Systems/Debris/SimpleFloorPlanPopulatorSystem.cs index e936d550bb..dcb7b7fc8f 100644 --- a/Content.Server/Worldgen/Systems/Debris/SimpleFloorPlanPopulatorSystem.cs +++ b/Content.Server/Worldgen/Systems/Debris/SimpleFloorPlanPopulatorSystem.cs @@ -12,7 +12,6 @@ namespace Content.Server.Worldgen.Systems.Debris; public sealed class SimpleFloorPlanPopulatorSystem : BaseWorldSystem { [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefinition = default!; [Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly TurfSystem _turf = default!; diff --git a/Content.Shared/Actions/ActionUpgradeSystem.cs b/Content.Shared/Actions/ActionUpgradeSystem.cs index 8cddf2daeb..e2c37be6ff 100644 --- a/Content.Shared/Actions/ActionUpgradeSystem.cs +++ b/Content.Shared/Actions/ActionUpgradeSystem.cs @@ -11,7 +11,6 @@ public sealed class ActionUpgradeSystem : EntitySystem { [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly ActionContainerSystem _actionContainer = default!; - [Dependency] private readonly EntityManager _entityManager = default!; public override void Initialize() { From 8f381157b3522ff63a401565ba6f194e08b6472d Mon Sep 17 00:00:00 2001 From: poklj Date: Sun, 6 Jul 2025 09:07:55 -0300 Subject: [PATCH 078/105] Move moth movement modifiers to the Base (#38795) --- Resources/Prototypes/Entities/Mobs/Species/moth.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index adde0d88a2..baa89a86cf 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -48,8 +48,8 @@ Female: UnisexMoth Unsexed: UnisexMoth - type: MovementSpeedModifier - weightlessAcceleration: 1.5 # Move around more easily in space. - weightlessFriction: 1 + baseWeightlessAcceleration: 1.5 # Move around more easily in space. + baseWeightlessFriction: 1 baseWeightlessModifier: 1 - type: Flammable damage: From 654a459351402f9193771ec164b206ceea718c89 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sun, 6 Jul 2025 14:08:56 +0100 Subject: [PATCH 079/105] Scurrets get emergency EVA suit access (#38778) * Scurrets - spacing protection via adorable outfits * ALPHABETIZATION!! --- .../Clothing/OuterClothing/hardsuits.yml | 1 + .../Clothing/OuterClothing/softsuits.yml | 1 + .../scurret_inventory_template.yml | 10 ++++++++++ Resources/Prototypes/tags.yml | 5 +++-- .../equipped-OUTERCLOTHING-scurret.png | Bin 0 -> 1619 bytes .../Hardsuits/syndicate.rsi/meta.json | 6 +++++- .../equipped-OUTERCLOTHING-scurret.png | Bin 0 -> 1402 bytes .../Suits/eva_emergency.rsi/meta.json | 6 +++++- 8 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-scurret.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-scurret.png diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 59ee0786ed..6904727d2b 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -579,6 +579,7 @@ - Hardsuit - WhitelistChameleon - CorgiWearable + - ScurretWearable - type: StaticPrice price: 5000 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml index 574bdc2640..d5612210c6 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml @@ -62,6 +62,7 @@ - type: Tag tags: - CorgiWearable + - ScurretWearable - MonkeyWearable - WhitelistChameleon diff --git a/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml index 8433564ea6..28b95eb3d3 100644 --- a/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml @@ -59,3 +59,13 @@ dependsOnComponents: - type: AllowSuitStorage displayName: Suit Storage + - name: outerClothing + slotTexture: suit + slotFlags: OUTERCLOTHING + stripTime: 6 + uiWindowPos: 0,3 + strippingWindowPos: 1,3 + displayName: Suit + whitelist: + tags: + - ScurretWearable diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index c10eb51486..cdcd6c8afc 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -225,7 +225,6 @@ - type: Tag id: CanPilot - - type: Tag id: CaptainSabre @@ -1203,6 +1202,9 @@ - type: Tag id: Screwdriver +- type: Tag # Flags items that scurrets can wear in their back and outerwear slots. + id: ScurretWearable + - type: Tag id: SecBeltEquip @@ -1514,5 +1516,4 @@ - type: Tag id: XenoborgModuleStealth - # ALPHABETICAL diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-scurret.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-scurret.png new file mode 100644 index 0000000000000000000000000000000000000000..8125ec9e1ecb62e24ccc1428feb6c1a33b530195 GIT binary patch literal 1619 zcmV-Z2CVssP)Px*4M{{nRCt{2noUd-SscKBIE9MkQ`>4`*{1D?&5EcAB^oyCM`TUZjV9=E6T>E6 zIgyxfP!68<(fdPB1$DFb!~7Q0!rMT0SFg8_bCSkOFP zuJV_XtNe9ZZ>W;pv?n4&gE4WmCn8kIZmmP*#DLvFrQHI6$K?`buJScG;LdkVihAyG zxx}&D_0{0-J=-$mt7Yuv^jp`n#h|70rS5AqRhl?wu;NGw1vqE0(moU7Qny#Dd`%38 zN5EhO5JtasT_c*OfJ$I&6myY@z}RT6LujVAunK@@!6+Sv4RqYSO~+vafw57#=I6w9 zEoh1WfX-*rU|$S9kIO}$-=Az>Wgb?PP?>VTsT&En@imYj094v7JOp^8ZA{G(5Z+OX zxulprzaMjvDOr{j6W&p)btuhjy4A}W{}4b%1OS}z53%W1ujVl|EgQ{}q=a|W5_>U) zxulrlLK9On)1qGS*8sq(Er-Vs>{Uobz*70@%JA#WKQ+nL909QxQ=&8%nKJ4Ctsa?X zNm}vMpjncX^a!|qqLhxix4C|z6xJdFnk7jY|E3;NzkvD-P^W?V3!L!};jFOnW1nxu zBH{Rfy^3nMI(9nhyTPVgy_#iyu(SGWwt8f)#0`8~?dJE#UOFU&FAI$P`+AO33wffw zekO#o!p4N9hD+VoKH3S*lB6_MnneAa!OAaINz_$2OUYL5dsl&GNm70|a)OP~L9WCN zgnV9F=H~#|;|nlgcd#cIpv&%{Yp9>vU;tz{ghMzrnfY${s_|tz8)+Hpr#%s2IK0@W zv(Jax$5~;6lvC)wrjUgr-sym5Nm5!pGFKjZfu!*Rb_Yh=W-Jy9_tqD%=g}kXZQDk5 zbv4mwlmP&r7i2fR@fGku+S<=!Z)RQK6>UOh+)I`0Cgl6@ilHPya?%jC3-kjy@=;-L^ z=;-L^=;-L^=;-L^{2$3FKOnuHzE}TX*thEW0RVMQS?Ew33}jr>`Y*JmjgdO1tPI#4 zRLO3dDox4qWTTcLR+OfbjTyQO*c}~k?8|>uN>wg6P;Ik0C+h0oU_AYViQEwF;yM)pGdW%~A1^;{td}o5f1O$RHT3v{{nbTEC5q5lihD zuN7)mNGPGuX4?$Fg=mC=kwMyQHC(v-6fVo)OgiCxNtD6?OW*KXJ&SYc`^W+px9rrtBs3R8!bcqi+KcA8Txz~ z_Nfk8N7`1nYILhdX2Md#gr$bz@CfaR2rWbXO!oI=C{nhwk<+j8s0{{qIXk;1#sj>Z zouxJy;Pk6J%64Whhm-w1X?X-A!j5#?($jeIRO2TsHNwEoXVau-W%L$S(KSCOysXxb z<{RmnpA*J=!%x@bTfklMg#u8te!bA)Xugs9nGmG1NYd-e*`%i07yz!s4G{N&NIvi` zn{>Fe?S5eaZDpl2Og!Pp!UpP`va;GAMC!YKxAclT8?F2_Hv_3>kkD^w9p17@O{U0e zXlPL4@i^t>OVM@Q!~=0Di(>fZI3 Rm^uIe002ovPDHLkV1nP=DXahh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json index 9e60a70b9e..78875bc273 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, equipped-OUTERCLOTHING-monkey made by Dutch-VanDerLinde, vox state made by Flareguy for SS14, equipped-OUTERCLOTHING-dog modified from equipped-OUTERCLOTHING by casiliuscestus (GitHub)", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, equipped-OUTERCLOTHING-monkey made by Dutch-VanDerLinde, vox state made by Flareguy for SS14, equipped-OUTERCLOTHING-dog modified from equipped-OUTERCLOTHING by casiliuscestus (GitHub), equipped-OUTERCLOTHING-scurret modified from equipped-OUTERCLOTHING by FairlySadPanda (Github)", "size": { "x": 32, "y": 32 @@ -26,6 +26,10 @@ "name": "equipped-OUTERCLOTHING-dog", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-scurret", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-scurret.png b/Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-scurret.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf9ff02c1633e19d53c35e49ec579b315cc319b GIT binary patch literal 1402 zcmV-=1%>*FP)Px)G)Y83RCt{2nq6pAM-<0@yESbgf*(yyTcS2elNfvv_aX%oO0_6SB-jSY2Usk^ zBBjNLJP6Y0()h9#--?6?tu&BSQY*@~fl5=vtdww*NPzvkHb^!aOJ^8LvY z4u{Q`#(H!7r$S+RdwZq*OMl=>3ubW<#HJnFo+`MXf!EG2uK*(>BPPJJAJ^sh|LeUG z0P5=Mq+*b2thZsVSq0^#V9YvptDe3K+ULtB!ra`P2|y&6~ z;11xz><|E-Bt?1t)n)*OcQ@PZk2O6x5h5YXV@*zd%_>pu*WmS+odsEJ8ov8keg-Zn zKz0D*Zwvxpv%n3$k4trLw#0gcME?(2EH7*}sVagm6jxX7vB z&p2hzE5dL6X8U7iKJO-vY_O1ulYe^awX1V&mK~nl%aPyPsSqz`3WY+UP$(1%g+ifF zC=`l+8`4`w;c(dAo^t2u`}D$XK}ABCZojEe*uExvMnF1Xy$y3~wUZIXwO4rV$HEBE zS}FDjt-VJpTRonXPtQxI$1VDFu`gd%0yDphJ^4aWyV~o!PZ!(cevnR$U99RN*)hes zgQsm+O?fHyp@l-Swfgb0!WPoEKFdDtce!#3+H2+ek(vQrU0vqDB$Vy#w9f-nWJGrM z>@I)VSwEcJC45$7;`W(^vb~)QOo|v~`jQeL+275bjXOLxceb`rSiZ6|!gn_AAUQuf z^CfQqtVhq8s$o*8lzmXbO-)VBvYZWA%7CKOLzT`t%zQ5#2%e&7BX_{v0y1wL^ z;E@98ZH|hEZaVgvd){^z7@`%8x4s%;;9iZ?VEpjwty{eFTr)8=hIco62Av(7dkl|S zAgx%aF?b(sr!qR7XngR3?r~JM()%b%BofQM5= Date: Sun, 6 Jul 2025 15:20:57 +0200 Subject: [PATCH 080/105] fix centcom pda (#38796) --- Resources/Prototypes/Entities/Objects/Devices/pda.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index c5218dea9f..2bc7057b1a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -923,6 +923,7 @@ id: CentcomIDCard penSlot: startingItem: PenCentcom + priority: -1 whitelist: tags: - Write From 22e3d533d3c38597423588b9f21446d434cc3221 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 6 Jul 2025 18:54:20 +0200 Subject: [PATCH 081/105] Catchable items, playable basketball (#37702) * catching * fix * improve * fix linter * cleanup * fix prediction * do the same here * fix comment --- .../Body/Systems/SharedBloodstreamSystem.cs | 3 +- Content.Shared/Clumsy/ClumsyComponent.cs | 32 +++++-- Content.Shared/Clumsy/ClumsySystem.cs | 65 +++++++++++--- .../Random/Helpers/SharedRandomExtensions.cs | 20 +++++ Content.Shared/Throwing/CatchAttemptEvent.cs | 7 ++ Content.Shared/Throwing/CatchableComponent.cs | 39 +++++++++ Content.Shared/Throwing/CatchableSystem.cs | 84 +++++++++++++++++++ .../bonk/components/bonkable-component.ftl | 4 - .../components/hypospray-component.ftl | 1 - .../clown/components/clumsy-component.ftl | 10 +++ Resources/Locale/en-US/throwing/catchable.ftl | 4 + Resources/Locale/en-US/weapons/ranged/gun.ftl | 1 - .../Prototypes/Entities/Mobs/NPCs/animals.yml | 6 ++ .../Entities/Mobs/Player/guardian.yml | 3 + .../Prototypes/Entities/Objects/Fun/toys.yml | 46 ++++++++++ .../Prototypes/Roles/Jobs/Civilian/clown.yml | 3 + 16 files changed, 304 insertions(+), 24 deletions(-) create mode 100644 Content.Shared/Throwing/CatchAttemptEvent.cs create mode 100644 Content.Shared/Throwing/CatchableComponent.cs create mode 100644 Content.Shared/Throwing/CatchableSystem.cs delete mode 100644 Resources/Locale/en-US/bonk/components/bonkable-component.ftl create mode 100644 Resources/Locale/en-US/clown/components/clumsy-component.ftl create mode 100644 Resources/Locale/en-US/throwing/catchable.ftl diff --git a/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs index b5d5100189..ac385040a9 100644 --- a/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs +++ b/Content.Shared/Body/Systems/SharedBloodstreamSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Forensics.Components; using Content.Shared.HealthExaminable; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; +using Content.Shared.Random.Helpers; using Content.Shared.Rejuvenate; using Content.Shared.Speech.EntitySystems; using Robust.Shared.Audio.Systems; @@ -222,7 +223,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem // TODO: Replace with RandomPredicted once the engine PR is merged // Use both the receiver and the damage causing entity for the seed so that we have different results for multiple attacks in the same tick - var seed = HashCode.Combine((int)_timing.CurTick.Value, GetNetEntity(ent).Id, GetNetEntity(args.Origin)?.Id ?? 0); + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id, GetNetEntity(args.Origin)?.Id ?? 0 }); var rand = new System.Random(seed); var prob = Math.Clamp(totalFloat / 25, 0, 1); if (totalFloat > 0 && rand.Prob(prob)) diff --git a/Content.Shared/Clumsy/ClumsyComponent.cs b/Content.Shared/Clumsy/ClumsyComponent.cs index 6b013a5c2f..9e6e851c8c 100644 --- a/Content.Shared/Clumsy/ClumsyComponent.cs +++ b/Content.Shared/Clumsy/ClumsyComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.GameStates; namespace Content.Shared.Clumsy; /// -/// A simple clumsy tag-component. +/// Makes the entity clumsy, randomly failing some interactions and hurting themselves. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ClumsyComponent : Component @@ -48,11 +48,17 @@ public sealed partial class ClumsyComponent : Component public TimeSpan GunShootFailStunTime = TimeSpan.FromSeconds(3); /// - /// Stun time after failing to shoot a gun. + /// Damage taken after failing to shoot a gun. /// [DataField, AutoNetworkedField] public DamageSpecifier? GunShootFailDamage; + /// + /// Damage taken after failing to catch an item. + /// + [DataField, AutoNetworkedField] + public DamageSpecifier? CatchingFailDamage; + /// /// Noise to play after failing to shoot a gun. Boom! /// @@ -77,6 +83,12 @@ public sealed partial class ClumsyComponent : Component [DataField, AutoNetworkedField] public bool ClumsyGuns = true; + /// + /// Whether or not to apply Clumsy to catching items. + /// + [DataField, AutoNetworkedField] + public bool ClumsyCatching = true; + /// /// Whether or not to apply Clumsy to vaulting. /// @@ -87,17 +99,23 @@ public sealed partial class ClumsyComponent : Component /// Lets you define a new "failed" message for each event. /// [DataField] - public LocId HypoFailedMessage = "hypospray-component-inject-self-clumsy-message"; + public LocId HypoFailedMessage = "clumsy-hypospray-fail-message"; [DataField] - public LocId GunFailedMessage = "gun-clumsy"; + public LocId GunFailedMessage = "clumsy-gun-fail-message"; [DataField] - public LocId VaulingFailedMessageSelf = "bonkable-success-message-user"; + public LocId CatchingFailedMessageSelf = "clumsy-catch-fail-message-user"; [DataField] - public LocId VaulingFailedMessageOthers = "bonkable-success-message-others"; + public LocId CatchingFailedMessageOthers = "clumsy-catch-fail-message-others"; [DataField] - public LocId VaulingFailedMessageForced = "forced-bonkable-success-message"; + public LocId VaulingFailedMessageSelf = "clumsy-vaulting-fail-message-user"; + + [DataField] + public LocId VaulingFailedMessageOthers = "clumsy-vaulting-fail-message-others"; + + [DataField] + public LocId VaulingFailedMessageForced = "clumsy-vaulting-fail-forced-message"; } diff --git a/Content.Shared/Clumsy/ClumsySystem.cs b/Content.Shared/Clumsy/ClumsySystem.cs index 348d99182a..9e0e82364f 100644 --- a/Content.Shared/Clumsy/ClumsySystem.cs +++ b/Content.Shared/Clumsy/ClumsySystem.cs @@ -6,10 +6,14 @@ using Content.Shared.Damage; using Content.Shared.IdentityManagement; using Content.Shared.Medical; using Content.Shared.Popups; +using Content.Shared.Random.Helpers; using Content.Shared.Stunnable; +using Content.Shared.Throwing; using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; +using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -17,19 +21,20 @@ namespace Content.Shared.Clumsy; public sealed class ClumsySystem : EntitySystem { - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedStunSystem _stun = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly INetManager _net = default!; public override void Initialize() { SubscribeLocalEvent(BeforeHyposprayEvent); SubscribeLocalEvent(BeforeDefibrillatorZapsEvent); SubscribeLocalEvent(BeforeGunShotEvent); + SubscribeLocalEvent(OnCatchAttempt); SubscribeLocalEvent(OnBeforeClimbEvent); } @@ -43,12 +48,15 @@ public sealed class ClumsySystem : EntitySystem if (!ent.Comp.ClumsyHypo) return; - if (!_random.Prob(ent.Comp.ClumsyDefaultCheck)) + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id }); + var rand = new System.Random(seed); + if (!rand.Prob(ent.Comp.ClumsyDefaultCheck)) return; args.TargetGettingInjected = args.EntityUsingHypospray; - args.InjectMessageOverride = "hypospray-component-inject-self-clumsy-message"; - _audio.PlayPvs(ent.Comp.ClumsySound, ent); + args.InjectMessageOverride = Loc.GetString(ent.Comp.HypoFailedMessage); + _audio.PlayPredicted(ent.Comp.ClumsySound, ent, args.EntityUsingHypospray); } private void BeforeDefibrillatorZapsEvent(Entity ent, ref SelfBeforeDefibrillatorZapsEvent args) @@ -59,7 +67,10 @@ public sealed class ClumsySystem : EntitySystem if (!ent.Comp.ClumsyDefib) return; - if (!_random.Prob(ent.Comp.ClumsyDefaultCheck)) + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id }); + var rand = new System.Random(seed); + if (!rand.Prob(ent.Comp.ClumsyDefaultCheck)) return; args.DefibTarget = args.EntityUsingDefib; @@ -67,6 +78,37 @@ public sealed class ClumsySystem : EntitySystem } + private void OnCatchAttempt(Entity ent, ref CatchAttemptEvent args) + { + // Clumsy people sometimes fail to catch items! + + // checks if ClumsyCatching is false, if so, skips. + if (!ent.Comp.ClumsyCatching) + return; + + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(args.Item).Id }); + var rand = new System.Random(seed); + if (!rand.Prob(ent.Comp.ClumsyDefaultCheck)) + return; + + args.Cancelled = true; // fail to catch + + if (ent.Comp.CatchingFailDamage != null) + _damageable.TryChangeDamage(ent, ent.Comp.CatchingFailDamage, origin: args.Item); + + // Collisions don't work properly with PopupPredicted or PlayPredicted. + // So we make this server only. + if (_net.IsClient) + return; + + var selfMessage = Loc.GetString(ent.Comp.CatchingFailedMessageSelf, ("item", ent.Owner), ("catcher", Identity.Entity(ent.Owner, EntityManager))); + var othersMessage = Loc.GetString(ent.Comp.CatchingFailedMessageOthers, ("item", ent.Owner), ("catcher", Identity.Entity(ent.Owner, EntityManager))); + _popup.PopupEntity(selfMessage, ent.Owner, ent.Owner); + _popup.PopupEntity(othersMessage, ent.Owner, Filter.PvsExcept(ent.Owner), true); + _audio.PlayPvs(ent.Comp.ClumsySound, ent); + } + private void BeforeGunShotEvent(Entity ent, ref SelfBeforeGunShotEvent args) { // Clumsy people sometimes can't shoot :( @@ -78,7 +120,10 @@ public sealed class ClumsySystem : EntitySystem if (args.Gun.Comp.ClumsyProof) return; - if (!_random.Prob(ent.Comp.ClumsyDefaultCheck)) + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(args.Gun).Id }); + var rand = new System.Random(seed); + if (!rand.Prob(ent.Comp.ClumsyDefaultCheck)) return; if (ent.Comp.GunShootFailDamage != null) @@ -90,7 +135,7 @@ public sealed class ClumsySystem : EntitySystem _audio.PlayPvs(ent.Comp.GunShootFailSound, ent); _audio.PlayPvs(ent.Comp.ClumsySound, ent); - _popup.PopupEntity(Loc.GetString("gun-clumsy"), ent, ent); + _popup.PopupEntity(Loc.GetString(ent.Comp.GunFailedMessage), ent, ent); args.Cancel(); } @@ -100,9 +145,9 @@ public sealed class ClumsySystem : EntitySystem if (!ent.Comp.ClumsyVaulting) return; - // This event is called in shared, thats why it has all the extra prediction stuff. - var rand = new System.Random((int)_timing.CurTick.Value); - + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id }); + var rand = new System.Random(seed); if (!_cfg.GetCVar(CCVars.GameTableBonk) && !rand.Prob(ent.Comp.ClumsyDefaultCheck)) return; diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs index 42d92a9065..87e839b56f 100644 --- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs +++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs @@ -184,5 +184,25 @@ namespace Content.Shared.Random.Helpers // Shouldn't happen throw new InvalidOperationException($"Invalid weighted pick for {prototype.ID}!"); } + + /// + /// A very simple, deterministic djb2 hash function for generating a combined seed for the random number generator. + /// We can't use HashCode.Combine because that is initialized with a random value, creating different results on the server and client. + /// + /// + /// Combine the current game tick with a NetEntity Id in order to not get the same random result if this is called multiple times in the same tick. + /// + /// var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id }); + /// + /// + public static int HashCodeCombine(List values) + { + int hash = 5381; + foreach (var value in values) + { + hash = (hash << 5) + hash + value; + } + return hash; + } } } diff --git a/Content.Shared/Throwing/CatchAttemptEvent.cs b/Content.Shared/Throwing/CatchAttemptEvent.cs new file mode 100644 index 0000000000..03206bdcd9 --- /dev/null +++ b/Content.Shared/Throwing/CatchAttemptEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Throwing; + +/// +/// Raised on someone when they try to catch an item. +/// +[ByRefEvent] +public record struct CatchAttemptEvent(EntityUid Item, float CatchChance, bool Cancelled = false); diff --git a/Content.Shared/Throwing/CatchableComponent.cs b/Content.Shared/Throwing/CatchableComponent.cs new file mode 100644 index 0000000000..ce68374440 --- /dev/null +++ b/Content.Shared/Throwing/CatchableComponent.cs @@ -0,0 +1,39 @@ +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Throwing; + +/// +/// Allows this entity to be caught in your hands when someone else throws it at you. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CatchableComponent : Component +{ + /// + /// If true this item can only be caught while in combat mode. + /// + [DataField, AutoNetworkedField] + public bool RequireCombatMode; + + /// + /// The chance of successfully catching. + /// + [DataField, AutoNetworkedField] + public float CatchChance = 1.0f; + + /// + /// Optional whitelist for who can catch this item. + /// + /// + /// Example usecase: Only someone who knows martial arts can catch grenades. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? CatcherWhitelist; + + /// + /// The sound to play when successfully catching. + /// + [DataField] + public SoundSpecifier? CatchSuccessSound; +} diff --git a/Content.Shared/Throwing/CatchableSystem.cs b/Content.Shared/Throwing/CatchableSystem.cs new file mode 100644 index 0000000000..8f2fd355ba --- /dev/null +++ b/Content.Shared/Throwing/CatchableSystem.cs @@ -0,0 +1,84 @@ +using Content.Shared.CombatMode; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.IdentityManagement; +using Content.Shared.Popups; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Player; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared.Throwing; + +public sealed partial class CatchableSystem : EntitySystem +{ + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly ThrownItemSystem _thrown = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + + private EntityQuery _handsQuery; + private EntityQuery _combatModeQuery; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDoHit); + + _handsQuery = GetEntityQuery(); + _combatModeQuery = GetEntityQuery(); + } + + private void OnDoHit(Entity ent, ref ThrowDoHitEvent args) + { + if (!_handsQuery.TryGetComponent(args.Target, out var handsComp)) + return; // don't do anything for walls etc + + // Is the catcher in combat mode if required? + if (ent.Comp.RequireCombatMode && (!_combatModeQuery.TryComp(args.Target, out var combatModeComp) || !combatModeComp.IsInCombatMode)) + return; + + // Is the catcher able to catch this item? + if (!_whitelist.IsWhitelistPassOrNull(ent.Comp.CatcherWhitelist, args.Target)) + return; + + var attemptEv = new CatchAttemptEvent(ent.Owner, ent.Comp.CatchChance); + RaiseLocalEvent(args.Target, ref attemptEv); + + if (attemptEv.Cancelled) + return; + + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = HashCode.Combine((int)_timing.CurTick.Value, GetNetEntity(ent).Id); + var rand = new System.Random(seed); + if (!rand.Prob(ent.Comp.CatchChance)) + return; + + // Try to catch! + if (!_hands.TryPickupAnyHand(args.Target, ent.Owner, handsComp: handsComp, animate: false)) + return; // The hands are full! + + // Success! + + // We picked it up already but we still have to raise the throwing stop (but not the landing) events at the right time, + // otherwise it will raise the events for that later while still in your hand + _thrown.StopThrow(ent.Owner, args.Component); + + // Collisions don't work properly with PopupPredicted or PlayPredicted. + // So we make this server only. + if (_net.IsClient) + return; + + var selfMessage = Loc.GetString("catchable-component-success-self", ("item", ent.Owner), ("catcher", Identity.Entity(args.Target, EntityManager))); + var othersMessage = Loc.GetString("catchable-component-success-others", ("item", ent.Owner), ("catcher", Identity.Entity(args.Target, EntityManager))); + _popup.PopupEntity(selfMessage, args.Target, args.Target); + _popup.PopupEntity(othersMessage, args.Target, Filter.PvsExcept(args.Target), true); + _audio.PlayPvs(ent.Comp.CatchSuccessSound, args.Target); + } +} diff --git a/Resources/Locale/en-US/bonk/components/bonkable-component.ftl b/Resources/Locale/en-US/bonk/components/bonkable-component.ftl deleted file mode 100644 index 1a79da3509..0000000000 --- a/Resources/Locale/en-US/bonk/components/bonkable-component.ftl +++ /dev/null @@ -1,4 +0,0 @@ -forced-bonkable-success-message = { CAPITALIZE($bonker) } bonks {$victim}s head against { THE($bonkable) }! - -bonkable-success-message-user = You bonk your head against { THE($bonkable) }! -bonkable-success-message-others = {$victim} bonks their head against { THE($bonkable) }! diff --git a/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl b/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl index 52dbf9010e..96ebaa3ed0 100644 --- a/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl @@ -10,7 +10,6 @@ hypospray-volume-label = Volume: [color=white]{$currentVolume}/{$totalVolume}u[/ hypospray-component-inject-other-message = You inject {$other}. hypospray-component-inject-self-message = You inject yourself. -hypospray-component-inject-self-clumsy-message = Oops! You injected yourself. hypospray-component-empty-message = Nothing to inject. hypospray-component-feel-prick-message = You feel a tiny prick! hypospray-component-transfer-already-full-message = {$owner} is already full! diff --git a/Resources/Locale/en-US/clown/components/clumsy-component.ftl b/Resources/Locale/en-US/clown/components/clumsy-component.ftl new file mode 100644 index 0000000000..055b3b9c4e --- /dev/null +++ b/Resources/Locale/en-US/clown/components/clumsy-component.ftl @@ -0,0 +1,10 @@ +clumsy-vaulting-fail-forced-message = { CAPITALIZE($bonker) } bonks { $victim }s head against { THE($bonkable) }! +clumsy-vaulting-fail-message-user = You bonk your head against { THE($bonkable) }! +clumsy-vaulting-fail-message-others = { $victim } bonks their head against { THE($bonkable) }! + +clumsy-gun-fail-message = The gun blows up in your face! + +clumsy-hypospray-fail-message = Oops! You injected yourself. + +clumsy-catch-fail-message-user = { CAPITALIZE(THE($item)) } hits your head! +clumsy-catch-fail-message-others = { CAPITALIZE(THE($item)) } hits { THE($catcher) }'s head! diff --git a/Resources/Locale/en-US/throwing/catchable.ftl b/Resources/Locale/en-US/throwing/catchable.ftl new file mode 100644 index 0000000000..8db3befd68 --- /dev/null +++ b/Resources/Locale/en-US/throwing/catchable.ftl @@ -0,0 +1,4 @@ +catchable-component-success-self = You catch {THE($item)}! +catchable-component-success-others = {CAPITALIZE(THE($catcher))} catches {THE($item)}! +catchable-component-fail-self = You fail to catch {THE($item)}! +catchable-component-fail-others = {CAPITALIZE(THE($catcher))} fails to catch {THE($item)}! diff --git a/Resources/Locale/en-US/weapons/ranged/gun.ftl b/Resources/Locale/en-US/weapons/ranged/gun.ftl index 18e01e31c8..a364075be9 100644 --- a/Resources/Locale/en-US/weapons/ranged/gun.ftl +++ b/Resources/Locale/en-US/weapons/ranged/gun.ftl @@ -4,7 +4,6 @@ gun-fire-rate-examine = Fire rate is [color={$color}]{$fireRate}[/color] per sec gun-selector-verb = Change to {$mode} gun-selected-mode = Selected {$mode} gun-disabled = You can't use guns! -gun-clumsy = The gun blows up in your face! gun-set-fire-mode = Set to {$mode} gun-magazine-whitelist-fail = That won't fit into the gun! gun-magazine-fired-empty = No ammo left! diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 967dda00db..2a599d70be 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1464,6 +1464,9 @@ Piercing: 4 groups: Burn: 3 + catchingFailDamage: + types: + Blunt: 1 clumsySound: path: /Audio/Animals/monkey_scream.ogg @@ -1643,6 +1646,9 @@ Piercing: 7 groups: Burn: 3 + catchingFailDamage: + types: + Blunt: 1 clumsySound: path: /Audio/Voice/Reptilian/reptilian_scream.ogg diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index 0aee45e28e..1b81b0d099 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -239,6 +239,9 @@ Piercing: 4 groups: Burn: 3 + catchingFailDamage: + types: + Blunt: 1 - type: MeleeWeapon angle: 30 animation: WeaponArcFist diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 4daffe1c56..e9279193b7 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -396,6 +396,20 @@ - type: Sprite sprite: Objects/Fun/Balls/basketball.rsi state: icon + - type: Fixtures + fixtures: + fix1: + shape: !type:PhysShapeCircle + radius: 0.25 + density: 20 + mask: + - ItemMask + restitution: 0.8 # bouncy + friction: 0.2 + - type: Catchable + catchChance: 0.8 + catchSuccessSound: + path: /Audio/Effects/Footsteps/bounce.ogg - type: EmitSoundOnCollide sound: path: /Audio/Effects/Footsteps/bounce.ogg @@ -414,6 +428,23 @@ - type: Sprite sprite: Objects/Fun/Balls/football.rsi state: icon + - type: Fixtures + fixtures: + fix1: + shape: !type:PhysShapeCircle + radius: 0.25 + density: 20 + mask: + - ItemMask + restitution: 0.5 # a little bouncy + friction: 0.2 + - type: Catchable + catchChance: 0.8 + catchSuccessSound: + path: /Audio/Effects/Footsteps/bounce.ogg + - type: EmitSoundOnCollide + sound: + path: /Audio/Effects/Footsteps/bounce.ogg - type: Item size: Small sprite: Objects/Fun/Balls/football.rsi @@ -427,6 +458,21 @@ - type: Sprite sprite: Objects/Fun/Balls/beach_ball.rsi state: icon + - type: Fixtures + fixtures: + fix1: + shape: !type:PhysShapeCircle + radius: 0.3 + position: "0,-0.2" + density: 20 + mask: + - ItemMask + restitution: 0.1 # not bouncy + friction: 0.2 + - type: Catchable + catchChance: 0.8 + catchSuccessSound: + path: /Audio/Effects/Footsteps/bounce.ogg - type: EmitSoundOnCollide sound: path: /Audio/Effects/Footsteps/bounce.ogg diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml index 60821cfe76..c64d0550ce 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml @@ -19,6 +19,9 @@ Piercing: 4 groups: Burn: 3 + catchingFailDamage: + types: + Blunt: 1 - type: SleepEmitSound snore: /Audio/Voice/Misc/silly_snore.ogg interval: 10 From 51ccaa7ab42843264d411108f5b060de1404bfa7 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 6 Jul 2025 16:55:27 +0000 Subject: [PATCH 082/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 39712ab7cf..91a9c6a92d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: IProduceWidgets - changes: - - message: Holobarrier projectors are now more power efficient. - type: Tweak - id: 8231 - time: '2025-04-18T16:10:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34473 - author: K-Dynamic changes: - message: Removed egg-plant from MegaSeed Servitor. (Egg-plant seeds can still @@ -3887,3 +3880,11 @@ id: 8742 time: '2025-07-06T00:59:31.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38762 +- author: slarticodefast + changes: + - message: You can now catch basketballs, footballs and beach balls that are thrown + at you! + type: Add + id: 8743 + time: '2025-07-06T16:54:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37702 From b650d3298e23a3d6eb6481c5f98b7a1d25116af0 Mon Sep 17 00:00:00 2001 From: Vasilis The Pikachu Date: Mon, 7 Jul 2025 00:01:55 +0200 Subject: [PATCH 083/105] Revert "HoP's beret (#38601)" This reverts commit e9c90fe66dec0ed9579847807d9babe934a66bae. Please check the maintainer meeting for details --- .../Catalog/Fills/Lockers/dressers.yml | 1 - .../Entities/Clothing/Head/hats.yml | 17 ---------- .../Jobs/Command/head_of_personnel.yml | 5 --- .../Prototypes/Loadouts/loadout_groups.yml | 1 - .../Recipes/Lathes/Packs/clothing.yml | 1 - .../Prototypes/Recipes/Lathes/clothing.yml | 5 --- .../beret_hop.rsi/equipped-HELMET-hamster.png | Bin 861 -> 0 bytes .../Hats/beret_hop.rsi/equipped-HELMET.png | Bin 902 -> 0 bytes .../Clothing/Head/Hats/beret_hop.rsi/icon.png | Bin 415 -> 0 bytes .../Head/Hats/beret_hop.rsi/inhand-left.png | Bin 695 -> 0 bytes .../Head/Hats/beret_hop.rsi/inhand-right.png | Bin 789 -> 0 bytes .../Head/Hats/beret_hop.rsi/meta.json | 30 ------------------ 12 files changed, 60 deletions(-) delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET-hamster.png delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET.png delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/inhand-left.png delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/inhand-right.png delete mode 100644 Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/meta.json diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml index 237b8a4748..e111b51cff 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml @@ -50,7 +50,6 @@ - type: StorageFill contents: - id: ClothingHeadHatHopcap - - id: ClothingHeadHatBeretHop - id: ClothingOuterWinterHoP - id: ClothingEyesGlasses - id: ClothingNeckCloakHop diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 26e0c6aba2..ec7801802b 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -1360,20 +1360,3 @@ path: /Audio/Items/flashlight_on.ogg soundDeactivate: path: /Audio/Items/flashlight_off.ogg - -- type: entity - parent: ClothingHeadBase - id: ClothingHeadHatBeretHop - name: head of personnel's beret - description: A dark blue beret with a ruby inserted in the center, for true connoisseurs of bureaucracy! - components: - - type: Sprite - sprite: Clothing/Head/Hats/beret_hop.rsi - - type: Clothing - sprite: Clothing/Head/Hats/beret_hop.rsi - - type: Tag - tags: - - HamsterWearable - - ClothMade - - Recyclable - - WhitelistChameleon \ No newline at end of file diff --git a/Resources/Prototypes/Loadouts/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Loadouts/Jobs/Command/head_of_personnel.yml index 0855100e61..45223bea14 100644 --- a/Resources/Prototypes/Loadouts/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Loadouts/Jobs/Command/head_of_personnel.yml @@ -35,11 +35,6 @@ equipment: head: ClothingHeadHatHopcap -- type: loadout - id: HoPBeret - equipment: - head: ClothingHeadHatBeretHop - # Neck - type: loadout id: HoPCloak diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml index b3c8aa8129..39b6be2b04 100644 --- a/Resources/Prototypes/Loadouts/loadout_groups.yml +++ b/Resources/Prototypes/Loadouts/loadout_groups.yml @@ -153,7 +153,6 @@ minLimit: 0 loadouts: - HoPHead - - HoPBeret - type: loadoutGroup id: HoPJumpsuit diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/clothing.yml b/Resources/Prototypes/Recipes/Lathes/Packs/clothing.yml index 808f1c680a..aa95781729 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/clothing.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/clothing.yml @@ -33,7 +33,6 @@ - ClothingUniformJumpskirtCapFormalDress # HoP - ClothingHeadHatHopcap - - ClothingHeadHatBeretHop - ClothingUniformJumpsuitHoP - ClothingUniformJumpskirtHoP # Generic diff --git a/Resources/Prototypes/Recipes/Lathes/clothing.yml b/Resources/Prototypes/Recipes/Lathes/clothing.yml index cf6e082b64..c5f81153e2 100644 --- a/Resources/Prototypes/Recipes/Lathes/clothing.yml +++ b/Resources/Prototypes/Recipes/Lathes/clothing.yml @@ -810,11 +810,6 @@ id: ClothingHeadHatHopcap result: ClothingHeadHatHopcap -- type: latheRecipe - parent: BaseCommandHatRecipe - id: ClothingHeadHatBeretHop - result: ClothingHeadHatBeretHop - - type: latheRecipe parent: BaseCommandHatRecipe id: ClothingHeadHatQMsoft diff --git a/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET-hamster.png b/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET-hamster.png deleted file mode 100644 index b55441dd0200112d64aeb49b73363a558b8b50b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 861 zcmV-j1ETziP)Px&7fD1xRCt{2n$K<$Q543%!wd|}3>0ZF!G&V$q8mY|?yQOFLl}J$;}f`ZZ{jnk z%P#6d7fnTI#EnL2bRovZwzTw*1H)VwQ%aEN^4SXLOGEVUE{ktu(RzhnJg+s!jlfU9K1d+Fgx!CX>I`Z+OfM8jijfX zw(Wf{y8{5KmNj^QQ#l~4^|qTEz`|20Evj_nA79$xx3|jP2 zvafUo6wM?-075vvL>?Pljrp1e|KdhGMWKj}@Wd4zAKvWA^zn2RI73JsJaB#ukcJHi zT0qdS0YM808a5zk0YM{wD=dLx>Yn@9jnlgk^269?z}OpbqA8$Xz6Kn;)#>bRLD;tE zF|_1l-?r6Q|9_{}J{$_c?zEt)Q3x&WIc^tU21L?nUk7^}_IkZImAbnEinrKH4$ zULs$)I4uxQVfNQI%K!XKh#GF2PdsNp)mD1-`R;!O%me`7ac#-34r%T+*YNQ6eHg{N z*eWgHPST{;4T!SU7PDxQh#TbC~{c3Va<1qkIuvDRuri@86< zoT1U47WOrm=P6K#X@u2kui;Y(IZdH_SQ%N_e5TbrwOGDRf_W`M?+Mb55U? n8HQmPhG7_nVHk#C&Le*S@*URI3?Lay00000NkvXXu0mjfITU{1 diff --git a/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/equipped-HELMET.png deleted file mode 100644 index 1b491f4c1e01f3517a915758c74236b902386ee6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 902 zcmV;119|+3P)Px&KuJVFRCt{2noV!iMi|F`W3Sg{Hx5Z?BsK@SNgyGrSaE0&cTR{4UxjNwK(BlV zdf?Xb0Z?x}utB^@gcaSC3TdkbX+g>6#f?Xfz?7fT*sInHC)psxKNJ0UcFU%(Qg;cmf(tXf#=h;!^RA1b84KT|9tH zV0(k#?%n36KYoF!*<%-BB^=Ym2jTw3!J0lAP1<4IIDVz*#N|dy5l`sB+c&WC6o8wT zuIX#NE&#d83kUb|;&b=di95vnqCQ7;+MqCav=nx7E&|Lppyjnp4e82u$3@t;8v_vMP z++exWR(hNY6A6m10JI1Sfx!y<&-fwV6p9@D$jHw4SKwR231B+`+c*JiCtw>Vfb9fq z;{>psfNh)rwiB?8(O%$VPG49g2!f$&{Xd@-wpWSyzd^hBeva>lNGYk+#*uQPw69VE zOrE>U=XUbr)AOa0=)ZVecy6tJaLZi{M@f=Ryb|lVumImpFYXVr%skQ|#G|K=#E;BD z`DQjJ{vF^1u$_QyoB*~Hu#FSIb^^9>0@zN#HckNB2^;~ZzQ(xJW@zcum?8tR;b!cW zz`SK7dw&_ne>6F_A9$xJOQptzbYL9cSb(K!th>Y`qX+Ii_~(_n63Aoin?0JG+i%ei z)?j`D*82dw>~+-wsZo3*0S+sk!J3JyJ#G%(8O^```d5CwaZ3+IMs?hHM}(5Wwp z$CD_74^+w&e;gRU1Q*gZA%xG?=4wTFQR;i1aWVgw;vEi$!{Kl^91e%W;cz${4u`|x caGWeY0FgZS$LjglR{#J207*qoM6N<$f*Mz(od5s; diff --git a/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/icon.png b/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/icon.png deleted file mode 100644 index 09a41f29640f6515cbfa07f62c7fcb6f7970545e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 415 zcmV;Q0bu@#P)Px$SxH1eR9J=Wlg~;5Q5431cQj|h3KGUr2t-A+g}W9$LEE09hv)%%h+d+$JwfE6 zMGFlbrIkWLfu)S7b6Z%b{h51>7D4y7y@&IC=R4mX62ypjRW*^yrgFS40{@d*5ZR!>V;ycu)V;xGM~IDiw^ z>Z_H2=OiWBGHkow3&Zl{zh$5u-G=6wG4_9a#5 zAE7^(#ky!>&Hi+7RoCTow+ujO`Yh^-w#t86C>_v z$omh%bCU9-XkpS9!Nf-f6GU{Kh$RSuDKZFU@G)vg?}GQ&xDDbuI%n(cVJu&!EpWMY znQw#H#jK$2Z5PZ^Wcs?5uRL_Gv-xK5@_UZov*$I>ZO;Ec_Z(q46nKD(v24xe{U2D9L^vNOtEBX-WUB~LC?9Vt84MDl$r#XTv&{FLbN9Y-BMzZsjXVBVz$7;;oF}Et^Lhu=l4xAU&Fj)LY>gA z$X|hKmrbmdro9eb`nqA0t3mL6bq9vDh)_@Y)4jGz0wMZLr^F5}IK))Keu0+qN9(PwRi&r&X{m#%ph!d(#bz2^43>Qyy8D@6?It?M(BGerw#3d_1Eh&xUNn|v6} zI-jSDKPY&0F1;u2ysf$B@$Dn)PctbmNU&zw?D_NT0r~rK3=V<5!%8Pv9?a; z=NC-S-S{NJY{*}L-pB}+k5!OoyRO#dIv W|6@FrYYH$WGI+ZBxvXPx%&q+ioGvoZ{_ZeHs48Sl9 z!!QiPFbu;m40FaH0GOPdMlv@F0-=x|l)*tac79Xc+K1D3&YeUW5@{1wbrXiB0px&0 zKOAchB9RFt$f~S{nlFTgrL5VO!_3|v0s!gMQCwVT#&!RoLV8eQXav~Z2CP~$UIgT| zjWrUrO4Ee6vXnI?k}1IG1Jc=Myzm{;Gr^DWJ`~gEB{F%p(MbO3!UNo2d;%m>c$2@_ z=4!7Ad-s=fLvHebn?vQ7douxGXat2+dv)so@LmkM$)~gKq;d%WaQEs>cT}TYv$tSG zSOJwE@4{VRf4@C8I`yxjGkFvNiN?|g{7b-dtX#qb_DBc=cD)Kn2@)ElW5dXgg%j8T zbK(wuetg#T{Ne2~2_nO`ZOf4of&|veaPRu%*_LJPp##9Uy+xnOB?$nNR3#_!VviKd z-?*^3Lb{&7>Sx!8D`e3JUw^X##_cUKlGy~%2LZsbTds5J8QJ+pLNkDr*%B9laR>iT zQalJ6aOPkGR0~iI8=zW%YS;kP0#w5Ws1~3aHbAui)vy7_9T@e00jfBb0eWsUY8}ep zC7@b>YS;kP0#u`S9&&PCKY!TLp1pl9im&MjJ+FXZ@<+wuLQf4SzIuFQUtCQ%^UnY_ zK(zqXbo~}6IJ*)FZ@LEH0GOKxUOZ~sf(GLICg^CuVLyUO0|V~vp|_*#XKr2wO^9pq zKo=G8HkCQ_078@Xub8*L08)pgpOy!5EUfT^NW@F`LsQC=TFbu;m%nA4lk`l^Y T=SO$+00000NkvXXu0mjfLLX%( diff --git a/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/meta.json deleted file mode 100644 index b5ca3514c5..0000000000 --- a/Resources/Textures/Clothing/Head/Hats/beret_hop.rsi/meta.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Sprited by upnostnote (Discord), resprite by 96flo (Discord)", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "equipped-HELMET-hamster", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} \ No newline at end of file From 87b8f1c7df0cf73943b7e89b0defa8096308c86e Mon Sep 17 00:00:00 2001 From: Vasilis The Pikachu Date: Mon, 7 Jul 2025 00:02:16 +0200 Subject: [PATCH 084/105] Revert "Readds the Hypereutactic Blade for traitors, adds Hypereutatic blade for Nukies (#37182)" This reverts commit c03afeb29cf3ed5e751e8d206e79f9f24981484e. Please check the maintainer meeting for details --- .../Locale/en-US/store/uplink-catalog.ftl | 3 -- .../Prototypes/Catalog/uplink_catalog.yml | 46 ------------------- .../Objects/Weapons/Melee/e_sword.yml | 22 ++------- 3 files changed, 5 insertions(+), 66 deletions(-) diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 6aa07ce9da..3c7218b69c 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -23,9 +23,6 @@ uplink-esword-double-desc = A much more expensive counter part to the normal ene uplink-hypereutactic-blade-name = Hypereutactic Blade uplink-hypereutactic-blade-desc = A gigantic energy sword with power that matches its looks. Requires two hands. Slow and unwieldy, yet pretty adept at reflecting. Previously made infamous by an operative wearing a joy mask. You wouldn't want to see this coming at you down the hall! -uplink-hypereutatic-blade-name = Hypereutatic Blade -uplink-hypereutatic-blade-desc = A gigantic off-brand energy sword. Requires two hands. Slow and unwieldy, can reflect decently. Often mistaken for the Hypereutactic Blade. - uplink-edagger-name = Energy Dagger uplink-edagger-desc = A small energy blade conveniently disguised in the form of a pen. diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 653a17e5f8..2095edabff 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -66,52 +66,6 @@ categories: - UplinkWeaponry -- type: listing - id: UplinkHyperEutacticBlade - name: uplink-hypereutactic-blade-name - description: uplink-hypereutactic-blade-desc - icon: { sprite: /Textures/Objects/Weapons/Melee/hypereutactic_blade.rsi, state: icon } - discountCategory: veryRareDiscounts - discountDownTo: - Telecrystal: 15 - productEntity: HyperEutacticBlade - cost: - Telecrystal: 18 - categories: - - UplinkWeaponry - conditions: - - !type:BuyerWhitelistCondition - blacklist: - components: - - SurplusBundle - - !type:StoreWhitelistCondition - blacklist: - tags: - - NukeOpsUplink - -- type: listing - id: UplinkHyperEutaticBlade - name: uplink-hypereutatic-blade-name - description: uplink-hypereutatic-blade-desc - icon: { sprite: /Textures/Objects/Weapons/Melee/hypereutactic_blade.rsi, state: icon } - discountCategory: veryRareDiscounts - discountDownTo: - Telecrystal: 13 - productEntity: HyperEutaticBlade - cost: - Telecrystal: 16 - categories: - - UplinkWeaponry - conditions: - - !type:BuyerWhitelistCondition - blacklist: - components: - - SurplusBundle - - !type:StoreWhitelistCondition - whitelist: - tags: - - NukeOpsUplink - - type: listing id: UplinkEnergyDagger name: uplink-edagger-name diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 21554eba07..f879e2891e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -296,12 +296,11 @@ Slash: 12 Heat: 12 Structural: 15 - # Disabled until the wield active sfx no longer stacks - #- type: ItemToggleActiveSound - # activeSound: - # path: /Audio/Weapons/ebladehum.ogg - # params: - # volume: 3 + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + params: + volume: 3 - type: ComponentToggler components: - type: Sharp @@ -387,17 +386,6 @@ reflectProb: 1.0 spread: 75 -# Nukie variant, reduced reflection rate. -- type: entity - parent: HyperEutacticBlade - id: HyperEutaticBlade - name: hypereutatic-blade - description: Often mistaken for the Hypereutactic Blade. This mass produced, off-brand, knockoff gets the same job done but with less reflection. - components: - - type: Reflect - reflectProb: 0.75 - spread: 75 - # Borgs - type: entity suffix: One-Handed, For Borgs From 575694e5b5898d1ad1cfd94c1930ee5d7ccbfb96 Mon Sep 17 00:00:00 2001 From: Vasilis The Pikachu Date: Mon, 7 Jul 2025 00:10:04 +0200 Subject: [PATCH 085/105] Changelog removal --- Resources/Changelog/Changelog.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index cf05e28dbe..f0137f6dbb 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -3660,15 +3660,6 @@ id: 8704 time: '2025-06-21T22:23:39.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38486 -- author: keronshb - changes: - - message: Added the Hypereutactic Blade back to the Traitor Uplink - type: Add - - message: Added the Hypereutatic Blade to the Nukie uplink - type: Add - id: 8705 - time: '2025-06-22T16:50:59.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37182 - author: Cojoke-dot changes: - message: Pacifists can now use the Staff of Healing From f5fd2dcb761b2f48ae14aa59ae63c7276cc16a96 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sun, 6 Jul 2025 23:30:44 +0100 Subject: [PATCH 086/105] Scurret naming fixes (#38776) Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../NameIdentifier/NameIdentifierSystem.cs | 49 ++++++++++++------- .../NameIdentifier/NameIdentifierComponent.cs | 10 ++-- .../en-US/datasets/names/scurret_first.ftl | 31 ++++++++++++ .../en-US/datasets/names/scurret_last.ftl | 38 ++++++++++++-- .../Prototypes/Datasets/Names/scurret.yml | 4 +- .../Prototypes/Entities/Mobs/NPCs/scurret.yml | 10 +++- 6 files changed, 112 insertions(+), 30 deletions(-) diff --git a/Content.Server/NameIdentifier/NameIdentifierSystem.cs b/Content.Server/NameIdentifier/NameIdentifierSystem.cs index 0a9f87557a..1e5ed67a63 100644 --- a/Content.Server/NameIdentifier/NameIdentifierSystem.cs +++ b/Content.Server/NameIdentifier/NameIdentifierSystem.cs @@ -20,7 +20,7 @@ public sealed class NameIdentifierSystem : EntitySystem /// Free IDs available per . /// [ViewVariables] - public readonly Dictionary> CurrentIds = new(); + public readonly Dictionary> CurrentIds = []; public override void Initialize() { @@ -35,18 +35,22 @@ public sealed class NameIdentifierSystem : EntitySystem InitialSetupPrototypes(); } - private void OnComponentShutdown(EntityUid uid, NameIdentifierComponent component, ComponentShutdown args) + private void OnComponentShutdown(Entity ent, ref ComponentShutdown args) { - if (CurrentIds.TryGetValue(component.Group, out var ids)) + if (ent.Comp.Group is null) + return; + + if (CurrentIds.TryGetValue(ent.Comp.Group, out var ids) && ids.Count > 0) { // Avoid inserting the value right back at the end or shuffling in place: // just pick a random spot to put it and then move that one to the end. var randomIndex = _robustRandom.Next(ids.Count); var random = ids[randomIndex]; - ids[randomIndex] = component.Identifier; + ids[randomIndex] = ent.Comp.Identifier; ids.Add(random); } - _nameModifier.RefreshNameModifiers(uid); + + _nameModifier.RefreshNameModifiers(ent.Owner); } /// @@ -83,46 +87,53 @@ public sealed class NameIdentifierSystem : EntitySystem : $"{randomVal}"; } - private void OnMapInit(EntityUid uid, NameIdentifierComponent component, MapInitEvent args) + private void OnMapInit(Entity ent, ref MapInitEvent args) { - if (!_prototypeManager.TryIndex(component.Group, out var group)) + if (ent.Comp.Group is null) + return; + + if (!_prototypeManager.TryIndex(ent.Comp.Group, out var group)) return; int id; string uniqueName; // If it has an existing valid identifier then use that, otherwise generate a new one. - if (component.Identifier != -1 && - CurrentIds.TryGetValue(component.Group, out var ids) && - ids.Remove(component.Identifier)) + if (ent.Comp.Identifier != -1 && + CurrentIds.TryGetValue(ent.Comp.Group, out var ids) && + ids.Remove(ent.Comp.Identifier)) { - id = component.Identifier; + id = ent.Comp.Identifier; uniqueName = group.Prefix is not null ? $"{group.Prefix}-{id}" : $"{id}"; } else { - uniqueName = GenerateUniqueName(uid, group, out id); - component.Identifier = id; + uniqueName = GenerateUniqueName(ent, group, out id); + ent.Comp.Identifier = id; } - component.FullIdentifier = group.FullName + ent.Comp.FullIdentifier = group.FullName ? uniqueName : $"({uniqueName})"; - Dirty(uid, component); - _nameModifier.RefreshNameModifiers(uid); + Dirty(ent); + _nameModifier.RefreshNameModifiers(ent.Owner); } private void OnRefreshNameModifiers(Entity ent, ref RefreshNameModifiersEvent args) { + if (ent.Comp.Group is null) + return; + // Don't apply the modifier if the component is being removed if (ent.Comp.LifeStage > ComponentLifeStage.Running) return; - if (!_prototypeManager.TryIndex(ent.Comp.Group, out var group)) + if (!_prototypeManager.TryIndex(ent.Comp.Group, out var group)) return; + var format = group.FullName ? "name-identifier-format-full" : "name-identifier-format-append"; // We apply the modifier with a low priority to keep it near the base name // "Beep (Si-4562) the zombie" instead of "Beep the zombie (Si-4562)" @@ -188,13 +199,13 @@ public sealed class NameIdentifierSystem : EntitySystem foreach (var proto in set.Modified.Values) { - var name_proto = (NameIdentifierGroupPrototype) proto; + var name_proto = (NameIdentifierGroupPrototype)proto; // Only bother adding new ones. if (CurrentIds.ContainsKey(proto.ID)) continue; - var ids = GetOrCreateIdList(name_proto); + var ids = GetOrCreateIdList(name_proto); FillGroup(name_proto, ids); } } diff --git a/Content.Shared/NameIdentifier/NameIdentifierComponent.cs b/Content.Shared/NameIdentifier/NameIdentifierComponent.cs index 49be08a6a3..f9f9eef49b 100644 --- a/Content.Shared/NameIdentifier/NameIdentifierComponent.cs +++ b/Content.Shared/NameIdentifier/NameIdentifierComponent.cs @@ -1,5 +1,5 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; namespace Content.Shared.NameIdentifier; @@ -9,18 +9,18 @@ namespace Content.Shared.NameIdentifier; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class NameIdentifierComponent : Component { - [DataField("group", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Group = string.Empty; + [DataField] + public ProtoId? Group; /// /// The randomly generated ID for this entity. /// - [DataField("identifier"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public int Identifier = -1; /// /// The full name identifier for this entity. /// - [DataField("fullIdentifier"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public string FullIdentifier = string.Empty; } diff --git a/Resources/Locale/en-US/datasets/names/scurret_first.ftl b/Resources/Locale/en-US/datasets/names/scurret_first.ftl index 4bbbf943f0..a01a6db8bb 100644 --- a/Resources/Locale/en-US/datasets/names/scurret_first.ftl +++ b/Resources/Locale/en-US/datasets/names/scurret_first.ftl @@ -1,3 +1,19 @@ +# Scurrets from Planet Wawa have two parts to their name - a 'chosen' and 'qualitative' name. + +# The chosen name is picked by the scurret themselves, +# encompassing a trait or value they hold themselves +# to or have a high value for. Scurrets sometimes change this +# name to denote an important moment in their life. + +# It appears to be common for scurret sets to share the same +# chosen name, with the gaining of a pup's own chosen name +# signalling their transition to adulthood in the community. + +# Given the scurret language is untranslated, these names are +# usually guessed via charades or Pictionary. + +# When all else fails, to NT and her crews, Wa is as good a name as any. + names-scurret-first-dataset-1 = Wa names-scurret-first-dataset-2 = Calm names-scurret-first-dataset-3 = Contented @@ -34,3 +50,18 @@ names-scurret-first-dataset-33 = Wise names-scurret-first-dataset-34 = Alert names-scurret-first-dataset-35 = Uplifting names-scurret-first-dataset-36 = Considerate +names-scurret-first-dataset-37 = Surviving +names-scurret-first-dataset-38 = Meditating +names-scurret-first-dataset-39 = Hunting +names-scurret-first-dataset-40 = Watching +names-scurret-first-dataset-41 = Resting +names-scurret-first-dataset-42 = Delivering +names-scurret-first-dataset-43 = Swimming +names-scurret-first-dataset-44 = Swinging +names-scurret-first-dataset-45 = Exploding +names-scurret-first-dataset-46 = Romancing +names-scurret-first-dataset-47 = Far-Seeing +names-scurret-first-dataset-48 = Loyal +names-scurret-first-dataset-49 = Inquisitive +# After consulting with lawyers, NT added this one to the dictionary. +names-scurret-first-dataset-50 = Legally Distinct diff --git a/Resources/Locale/en-US/datasets/names/scurret_last.ftl b/Resources/Locale/en-US/datasets/names/scurret_last.ftl index effe2180f0..bac9b818d1 100644 --- a/Resources/Locale/en-US/datasets/names/scurret_last.ftl +++ b/Resources/Locale/en-US/datasets/names/scurret_last.ftl @@ -1,3 +1,19 @@ +# Scurrets from Planet Wawa have two parts to their name - a 'chosen' and 'qualitative' name. + +# The qualitative name is usually related to an important feature +# of Wawa's wetland habitats that the scurret is associated with +# by their community. + +# Scurret pups, due to both their quantity and complete lack +# of any survival instinct, lack a qualitative name entirely. +# Researchers believe their parents simply give them a number. + +# Given that the scurret language is untranslated, these names are +# usually deduced via the showing of photographs, annoyed and +# repeated pointing at nearby objects, or games of Pictionary. + +# When all else fails, to NT and her crews, Wa is as good a name as any. + names-scurret-last-dataset-1 = Wa names-scurret-last-dataset-2 = Trees names-scurret-last-dataset-3 = Plants @@ -6,12 +22,12 @@ names-scurret-last-dataset-5 = Rivers names-scurret-last-dataset-6 = Groves names-scurret-last-dataset-7 = Lakes names-scurret-last-dataset-8 = Marshes -names-scurret-last-dataset-9 = Spring +names-scurret-last-dataset-9 = Springs names-scurret-last-dataset-10 = Reeds names-scurret-last-dataset-11 = Sunshine names-scurret-last-dataset-12 = Rain names-scurret-last-dataset-13 = Clouds -names-scurret-last-dataset-14 = Snowfall +names-scurret-last-dataset-14 = Snowfalls names-scurret-last-dataset-15 = Stones names-scurret-last-dataset-16 = Pebbles names-scurret-last-dataset-17 = Fishes @@ -25,7 +41,7 @@ names-scurret-last-dataset-24 = Alders names-scurret-last-dataset-25 = Birches names-scurret-last-dataset-26 = Poplars names-scurret-last-dataset-27 = Marigolds -names-scurret-last-dataset-28 = Robins +names-scurret-last-dataset-28 = Rowans names-scurret-last-dataset-29 = Orchids names-scurret-last-dataset-30 = Rushes names-scurret-last-dataset-31 = Lillies @@ -33,4 +49,20 @@ names-scurret-last-dataset-32 = Violets names-scurret-last-dataset-33 = Maples names-scurret-last-dataset-34 = Oaks names-scurret-last-dataset-35 = Hazels +# AND SIR GIDEON OFNIR names-scurret-last-dataset-36 = the All-Knowing +names-scurret-last-dataset-37 = Tarns +names-scurret-last-dataset-38 = Waters +names-scurret-last-dataset-39 = Reservoirs +names-scurret-last-dataset-40 = Dams +names-scurret-last-dataset-41 = Moors +names-scurret-last-dataset-42 = Fens +names-scurret-last-dataset-43 = Temples +names-scurret-last-dataset-44 = Hills +names-scurret-last-dataset-45 = Copses +names-scurret-last-dataset-46 = Fields +names-scurret-last-dataset-47 = Ancestors +names-scurret-last-dataset-48 = Forests +names-scurret-last-dataset-49 = Secrets +# Nobody's quite sure how this one is in the dictionary. +names-scurret-last-dataset-50 = Space Ferret diff --git a/Resources/Prototypes/Datasets/Names/scurret.yml b/Resources/Prototypes/Datasets/Names/scurret.yml index b3ac08e2ad..9e23557b38 100644 --- a/Resources/Prototypes/Datasets/Names/scurret.yml +++ b/Resources/Prototypes/Datasets/Names/scurret.yml @@ -2,10 +2,10 @@ id: NamesFirstScurret values: prefix: names-scurret-first-dataset- - count: 36 + count: 50 - type: localizedDataset id: NamesLastScurret values: prefix: names-scurret-last-dataset- - count: 36 + count: 50 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml b/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml index 19ba323a0a..1f0eb0f9e2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml @@ -139,6 +139,14 @@ available: - enum.DamageStateVisualLayers.Base: scurret: ScurretColors + # They are of a mysterious gender. + - type: Grammar + attributes: + gender: epicene + proper: true + # Strips the name identifier from them, so they're just "Confident Waters" rather than "Confident Waters (123)" + - type: NameIdentifier + group: null # Emotional Support Scurrets have a ghost role and equipment. At the moment, these are intended to be used for admemes, but # feel free to hook them into random content. @@ -169,4 +177,4 @@ name: Emotional Support Scurret id: MobEmotionalSupportScurret parent: [MobScurret, MobBaseEmotionalSupportScurret] - description: Commonly known as Wawa, from the wetlands of Planet Wawa, these critters make up the bulk of Arnolds's Pizza's "loyal workforce". This one is here as a temp. + description: Commonly known as Wawa, from the wetlands of Planet Wawa, these critters make up the bulk of Arnold's Pizza's "loyal workforce". This one is here as a temp. From 5f7db3b1514e58211041ce1c9c3ed23ef889df7b Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sun, 6 Jul 2025 23:42:13 +0100 Subject: [PATCH 087/105] Scurret displacement map fixes (#38775) --- .../Prototypes/Entities/Mobs/NPCs/scurret.yml | 32 ++++++++++++++++++ .../Animals/scurret/displacement.rsi/back.png | Bin 0 -> 279 bytes .../Animals/scurret/displacement.rsi/hand.png | Bin 426 -> 382 bytes .../scurret/displacement.rsi/jumpsuit.png | Bin 329 -> 510 bytes .../scurret/displacement.rsi/meta.json | 4 +++ 5 files changed, 36 insertions(+) create mode 100644 Resources/Textures/Mobs/Animals/scurret/displacement.rsi/back.png diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml b/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml index 1f0eb0f9e2..6d328014db 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/scurret.yml @@ -104,6 +104,38 @@ 32: sprite: Mobs/Animals/scurret/displacement.rsi state: neck + ears: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: ears + eyes: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: eyes + head: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: head + mask: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: mask + back: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: back + - type: Hands + leftHandDisplacement: + sizeMaps: + 32: + sprite: Mobs/Animals/scurret/displacement.rsi + state: hand + - type: InventorySlots - type: Food - type: Hunger diff --git a/Resources/Textures/Mobs/Animals/scurret/displacement.rsi/back.png b/Resources/Textures/Mobs/Animals/scurret/displacement.rsi/back.png new file mode 100644 index 0000000000000000000000000000000000000000..110555738328a9c2754c179f5ede423c3028c6ba GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|E_%8+hE&XX zJIj%)*+7J~zU#V~2Y+6yXw1|{+I*R5VR|O@MjA>Hs>PSL#jRg0Zr^n9Z{*rlS~KTc z?0K$U{ezpwf%}3)gV+K?23?0_hNy;P3|km_88aBAm@hDyuq|NCz@=fIMY7Y zTS?b%1$*pVyDH_q==L8{jMDrkru?hlAr!#Gxq$hC2ZL;b8`BGhddnmC{#HL@TgNiR z0mwBGa$sLjsGMN+;`RAQP7W&{HM2ABJbK%7zr~cq|i4t&wuXDwCm|P|LSGYyG9Ylofi(x`WRWZ zXydWJ-#-7GF@wjE-;r}d00XjXz}8P>uwv+CxxkpA(!l4S%vi!8g`s5U9tK6dbL=7K VG^>)FyPq)tfv2mV%Q~loCICj*mka;^ delta 387 zcmeyzw2FCxK|KRYx}&cn1H;CC?mvmF3=E7`o-U3d6>)E8-sWpE5OC?<|5nxI%Wl)z zKD~h)Tb7!q`6V6u@I>y`QoX~qMf%~5x3BX4`1SCY#{XzPkEmV32C@Ib`!<%;_O4_3 zp;X@;yK7%--u4F3*Y-O^T*H~J%}VhR4i$E}q{QeErNS`t%$@p++t|wlA9SDBO?*4k zzf|BBH>U$o_JqoxfTh<8R9o+cIlOxm{Qs-&#iL>;Lib$U(=g|#bbEG_nvTn@hb$G_ zyfWe(-UaTw$E}b#kwHb*_bY>7%WE@LkQDyXISfie$VT&g3XYH1G!e5m@@fAeA$| zGfQ~*7XRDwLy&=ifiE?}GtJkR ZK?}&{0Adih6g(M3dAjDH|r(ggfD8?HcbH2L$F=0P({uM?U4}u)0=XX=*YZC@Jj)DEe`5cB~XLcI#r2WDX zkD*6vE%273|8HX@aCYcAz(>7od0K}s{D0wTg2l&-(OT5-sYrk&_7(9ibKEo&F26B N002ovPDHLkV1i8^*(3k} delta 289 zcmeyze3EH`VLh{_i(^Q|oVT~`3N Date: Sun, 6 Jul 2025 16:42:13 -0700 Subject: [PATCH 088/105] Fix storage voice control bug after handssystem refactor (#38810) --- Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs b/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs index 1755c6df08..81bbd48a0d 100644 --- a/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs +++ b/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs @@ -40,7 +40,7 @@ public sealed class StorageVoiceControlSystem : EntitySystem return; // If the player has something in their hands, try to insert it into the storage - if (_hands.TryGetActiveItem(ent.Owner, out var activeItem)) + if (_hands.TryGetActiveItem(args.Source, out var activeItem)) { // Disallow insertion and provide a reason why if the person decides to insert the item into itself if (ent.Owner.Equals(activeItem.Value)) From 2aca49bb55f2e80ab140e670066ab0dee826cc6f Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 6 Jul 2025 23:43:20 +0000 Subject: [PATCH 089/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 91a9c6a92d..95b06bfc42 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: K-Dynamic - changes: - - message: Removed egg-plant from MegaSeed Servitor. (Egg-plant seeds can still - be obtained by mutation or exotic seed crate.) - type: Remove - id: 8232 - time: '2025-04-18T16:42:50.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36579 - author: Failed, Centronias changes: - message: The drink shaker now has in-hand sprites @@ -3888,3 +3880,10 @@ id: 8743 time: '2025-07-06T16:54:20.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/37702 +- author: ArtisticRoomba + changes: + - message: The Go Go Hat now correctly retrieves and deposits items again. + type: Fix + id: 8744 + time: '2025-07-06T23:42:14.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38810 From c18345805620f9dabbfe7989584d89719bb50e00 Mon Sep 17 00:00:00 2001 From: Andrew Malcolm O'Neill <105134723+maland1@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:50:11 +0100 Subject: [PATCH 090/105] Reducing the amount of space in the gogo hat (#38808) Reducing the amount of space in the hat from 7*4 to 4*3 to make a bit more sense with the fact it is only a hat. Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> --- Resources/Prototypes/Entities/Clothing/Head/specific.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Head/specific.yml b/Resources/Prototypes/Entities/Clothing/Head/specific.yml index 1e2e55f55b..15f89da106 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/specific.yml @@ -38,7 +38,7 @@ - type: Storage showVerb: false grid: - - 0,0,6,3 + - 0,0,3,2 maxItemSize: Small blacklist: tags: From 52a8414f71878bd36aef5e3adaf4e3472257ec8f Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 6 Jul 2025 23:51:17 +0000 Subject: [PATCH 091/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 95b06bfc42..0d3009f577 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Failed, Centronias - changes: - - message: The drink shaker now has in-hand sprites - type: Tweak - id: 8233 - time: '2025-04-18T17:12:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36382 - author: IProduceWidgets changes: - message: filing cabinets no longer have whitelists. @@ -3887,3 +3880,10 @@ id: 8744 time: '2025-07-06T23:42:14.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38810 +- author: maland1 + changes: + - message: Reduced the size of the go go hat inventory + type: Tweak + id: 8745 + time: '2025-07-06T23:50:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38808 From 021551ede3276a22b64570fb71435b77def4762c Mon Sep 17 00:00:00 2001 From: AsnDen <75905158+AsnDen@users.noreply.github.com> Date: Mon, 7 Jul 2025 08:07:52 +0300 Subject: [PATCH 092/105] Golden pai (#38549) * Golden pai * Make golden PAI public and rare * Golden PAI = legendary salvage --- .../Spawners/Random/Salvage/tables_loot.yml | 1 + .../Markers/Spawners/Random/maintenance.yml | 1 + .../Prototypes/Entities/Objects/Fun/pai.yml | 17 +++++++++++++++++ .../Fun/pai.rsi/golden-icon-pai-off.png | Bin 0 -> 590 bytes .../Objects/Fun/pai.rsi/golden-pai-base.png | Bin 0 -> 551 bytes .../Textures/Objects/Fun/pai.rsi/meta.json | 8 +++++++- 6 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/golden-icon-pai-off.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/golden-pai-base.png diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Salvage/tables_loot.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Salvage/tables_loot.yml index 65f8f66106..9f952db002 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Salvage/tables_loot.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Salvage/tables_loot.yml @@ -172,6 +172,7 @@ - id: ClothingHeadHatFancyCrown - id: GoldenBikeHorn - id: ClothingHeadHatCatEars + - id: GoldenPersonalAI - id: TreasureCoinDiamond amount: !type:RangeNumberSelector range: 2, 5 diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml index 6def2009cc..b1a1c60497 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml @@ -172,6 +172,7 @@ - id: ClothingUniformJumpsuitFamilyGuy - id: WristwatchGold - id: RubberStampGreytide + - id: GoldenPersonalAI - type: entity name: Maint Loot Spawner diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 23227a65ee..8f8fd2d03c 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -130,6 +130,23 @@ - type: StaticPrice price: 500 +- type: entity + parent: PersonalAI + id: GoldenPersonalAI + name: golden personal ai device + description: Your electronic pal who's fun to be with! Special golden edition! + components: + - type: Sprite + sprite: Objects/Fun/pai.rsi + layers: + - state: golden-pai-base + - state: pai-off-overlay + shader: unshaded + map: ["screen"] + - type: Appearance + - type: StaticPrice + price: 5000 + - type: entity parent: PersonalAI id: PotatoAI diff --git a/Resources/Textures/Objects/Fun/pai.rsi/golden-icon-pai-off.png b/Resources/Textures/Objects/Fun/pai.rsi/golden-icon-pai-off.png new file mode 100644 index 0000000000000000000000000000000000000000..c267627a2180ccb0ae02ed02ba9b562c137acac7 GIT binary patch literal 590 zcmV-U0Px%2uVaiR9J=WmOp3{Q5?rVO&eoEXc4uoy{bry!K7juvq%>M>6)oR$Pfcvx_1)k zR62HXkRTnz#amrEWKm}!R;&m9xuL{Ui-V-dMPrla(A+g?BloV2pm3k%clUl@e!uVi z-tl$<%ffa8(dWO)FLTUOoxaH!$I=10NjB&eGGM=ES>-LVa{(~B=Y zmH{`&PVTQ6ki|3be;BA3yRM45(Mumh%Qsh8dUjVzS23jf%NrP*R9KccV#g*GD#ljt z4OqpCYK(>Ko38ny8e_Kag`1Mj|G@X!o-yxT(n4w869{>OV07*qoM6N<$f_>B#9RL6T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/golden-pai-base.png b/Resources/Textures/Objects/Fun/pai.rsi/golden-pai-base.png new file mode 100644 index 0000000000000000000000000000000000000000..aab9aa36570cc93b9b151aa53c435eeed5919b4a GIT binary patch literal 551 zcmV+?0@(eDP)Px$;Ymb6R9J=Wmd#5WQ5400Mq`Wwr1%vbZ7Bvr6RnzNBLN{0w^>;TS!CV4e}@|v zCAe_WO=s&yBpcD42rX@Opsllz7(Z|!f=t@fjxVOYPRpXVoyXE!%b^t&iZMcumoDgRB}R6bg}5!}kgU zObx8sDlTOJ;NE z`pcbt8@a=?1F6}aiMz$<_|28 Date: Mon, 7 Jul 2025 05:09:01 +0000 Subject: [PATCH 093/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0d3009f577..0ee9d52336 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: IProduceWidgets - changes: - - message: filing cabinets no longer have whitelists. - type: Tweak - id: 8234 - time: '2025-04-18T17:37:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36185 - author: aada changes: - message: Egg-plants now have 6 reagent per egg at 20 potency, up from 3. @@ -3887,3 +3880,11 @@ id: 8745 time: '2025-07-06T23:50:11.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38808 +- author: AsnDen + changes: + - message: Golden PAI was added. It is extremely rare and expensive. This PAI can + be found in maint lockers + type: Add + id: 8746 + time: '2025-07-07T05:07:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38549 From a03c35a9bce7b8aad2ab7760667d0eb3071959cd Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 7 Jul 2025 14:23:45 +0200 Subject: [PATCH 094/105] sanitize MIDI parser (#38806) Co-authored-by: Pieter-Jan Briers --- .../Instruments/MidiParser/MidiParser.cs | 2 ++ .../Instruments/InstrumentSystem.cs | 15 ++++++----- .../Instruments/SharedInstrumentComponent.cs | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Content.Client/Instruments/MidiParser/MidiParser.cs b/Content.Client/Instruments/MidiParser/MidiParser.cs index 937384e439..0b65e472fc 100644 --- a/Content.Client/Instruments/MidiParser/MidiParser.cs +++ b/Content.Client/Instruments/MidiParser/MidiParser.cs @@ -102,6 +102,8 @@ public static class MidiParser // 0x03 is TrackName, // 0x04 is InstrumentName + // This string can potentially contain control characters, including 0x00 which can cause problems if it ends up in database entries via admin logs + // we sanitize TrackName and InstrumentName after they have been send to the server var text = Encoding.ASCII.GetString(metaData, 0, (int)metaLength); switch (metaType) { diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index 420bd44737..f6a2162271 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -156,6 +156,15 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem return; } + + foreach (var t in msg.Tracks) + { + // Remove any control characters that may be part of the midi file so they don't end up in the admin logs. + t?.SanitizeFields(); + // Truncate any track names too long. + t?.TruncateFields(_cfg.GetCVar(CCVars.MidiMaxChannelNameLength)); + } + var tracksString = string.Join("\n", msg.Tracks .Where(t => t != null) @@ -166,12 +175,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem LogImpact.Low, $"{ToPrettyString(args.SenderSession.AttachedEntity)} set the midi channels for {ToPrettyString(uid)} to {tracksString}"); - // Truncate any track names too long. - foreach (var t in msg.Tracks) - { - t?.TruncateFields(_cfg.GetCVar(CCVars.MidiMaxChannelNameLength)); - } - activeInstrument.Tracks = msg.Tracks; Dirty(uid, activeInstrument); diff --git a/Content.Shared/Instruments/SharedInstrumentComponent.cs b/Content.Shared/Instruments/SharedInstrumentComponent.cs index 97eef752eb..41bef64902 100644 --- a/Content.Shared/Instruments/SharedInstrumentComponent.cs +++ b/Content.Shared/Instruments/SharedInstrumentComponent.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Text; using Robust.Shared.Audio.Midi; using Robust.Shared.GameStates; using Robust.Shared.Serialization; @@ -207,6 +208,18 @@ public sealed class MidiTrack ProgramName = Truncate(ProgramName, limit); } + public void SanitizeFields() + { + if (InstrumentName != null) + InstrumentName = Sanitize(InstrumentName); + + if (TrackName != null) + TrackName = Sanitize(TrackName); + + if (ProgramName != null) + ProgramName = Sanitize(ProgramName); + } + private const string Postfix = "…"; // TODO: Make a general method to use in RT? idk if we have that. private string Truncate(string input, int limit) @@ -218,4 +231,17 @@ public sealed class MidiTrack return input.Substring(0, truncatedLength) + Postfix; } + + private static string Sanitize(string input) + { + var sanitized = new StringBuilder(input.Length); + + foreach (char c in input) + { + if (!char.IsControl(c) && c <= 127) // no control characters, only ASCII + sanitized.Append(c); + } + + return sanitized.ToString(); + } } From ae3b3b6173da62bb225c0ee128c10f1d58e5e7ab Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:55:09 +0300 Subject: [PATCH 095/105] Cleanup: Remove ``TelephoneComponent.RequiresPower`` (#38823) * Cleanup * Forgot about yml --- Content.Server/Telephone/TelephoneSystem.cs | 2 +- Content.Shared/Telephone/TelephoneComponent.cs | 6 ------ Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Content.Server/Telephone/TelephoneSystem.cs b/Content.Server/Telephone/TelephoneSystem.cs index ab3026fc97..4c87707cc6 100644 --- a/Content.Server/Telephone/TelephoneSystem.cs +++ b/Content.Server/Telephone/TelephoneSystem.cs @@ -490,6 +490,6 @@ public sealed class TelephoneSystem : SharedTelephoneSystem public bool IsTelephonePowered(Entity entity) { - return this.IsPowered(entity, EntityManager) || !entity.Comp.RequiresPower; + return this.IsPowered(entity, EntityManager); } } diff --git a/Content.Shared/Telephone/TelephoneComponent.cs b/Content.Shared/Telephone/TelephoneComponent.cs index c24840ce01..89748d78a4 100644 --- a/Content.Shared/Telephone/TelephoneComponent.cs +++ b/Content.Shared/Telephone/TelephoneComponent.cs @@ -81,12 +81,6 @@ public sealed partial class TelephoneComponent : Component [DataField] public float ListeningRange = 2; - /// - /// Specifies whether this telephone require power to fucntion - /// - [DataField] - public bool RequiresPower = true; - /// /// This telephone should not appear on public telephone directories /// diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index d70c13187f..303f7dc676 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -190,6 +190,7 @@ acts: [ "Destruction" ] - type: ApcPowerReceiver powerLoad: 1000 + needsPower: false - type: StationAiCore - type: StationAiVision - type: InteractionOutline @@ -218,7 +219,6 @@ listeningRange: 0 speakerVolume: Speak unlistedNumber: true - requiresPower: false - type: Holopad - type: StationAiWhitelist - type: UserInterface From 218158503050856f586e294a797859b42160a40c Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:01:52 +0200 Subject: [PATCH 096/105] Add Breach of Permanent Confinement to Space Law (#38663) * Initial commit * Fix category in text --- .../ServerRules/SpaceLaw/SLCrimeList.xml | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLCrimeList.xml b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLCrimeList.xml index c6d29bfba9..2ea20b5a0c 100644 --- a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLCrimeList.xml +++ b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLCrimeList.xml @@ -56,7 +56,7 @@ - Refusal of Mental Shielding (E) + Breach of Permanent Confinement (E) @@ -251,8 +251,9 @@ - + + Refusal of Mental Shielding (R) @@ -752,7 +753,7 @@ - While rare, this charge can be bumped to an execution if the suspect has repeatedly attempted to break out of the permanent brig. Includes people breaking others out. + Includes breaking out other people. @@ -847,17 +848,17 @@ - Refusal of Mental Shielding + Breach of Permanent Confinement - To refuse to comply with a reasonable Mind Shielding procedure. + To break someone sentenced to Permanent Confinement out of a cell or custody with the intention of escaping. - Applies if the suspect is excessively uncooperative or the implant fails to function due to the mental state of the prisoner already being too far gone. If the implant fails execution is heavily recommended. + Includes breaking out other people sentenced to Permanent Confinement. @@ -925,5 +926,25 @@ 5-06 + + + Refusal of Mental Shielding + + + + + To refuse to comply with a reasonable Mind Shielding procedure. + + + + + Applies if the suspect is excessively uncooperative or the implant fails to function due to the mental state of the prisoner already being too far gone. If the implant fails execution is heavily recommended. + + + + + 5-07 + + From f1902ad0e2e9b9026594b6a95d8d0697432f9772 Mon Sep 17 00:00:00 2001 From: Smugman <85798843+Smugman@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:53:17 +0200 Subject: [PATCH 097/105] Branded lighters addition (#35514) * newlighters * port complete * donk pocket box addition * should fix test fail, proper credit * captalisation issue * fixed * typo corrected * removed accidental change to combat bakery * fixed lock message, made NT flippo start fueled. * Requested changes * fixed discount dan * moved matchbox * requested changes, discount dan more broken than ever (somehow) * unbungle * uhhhhh * maybe fixes? * changed inheritance * fixed enum? * nevermind * finally fixed * breaking changes * inheritance unbungled --- .../Lock/ItemToggleRequiresLockComponent.cs | 17 + Content.Shared/Lock/LockSystem.cs | 18 + .../Locale/en-US/store/uplink-catalog.ftl | 3 + .../VendingMachines/Inventories/discount.yml | 1 + .../Prototypes/Catalog/uplink_catalog.yml | 11 + .../Markers/Spawners/Random/maintenance.yml | 1 + .../Consumable/Food/Containers/box.yml | 5 +- .../Entities/Objects/Fun/figurine_boxes.yml | 59 +++ .../Entities/Objects/Tools/lighters.yml | 413 +++++++++++++++++- .../Entities/Objects/Tools/matches.yml | 40 ++ .../Objectives/stealTargetGroups.yml | 2 +- .../Tools/Lighters/centcomm.rsi/flame.png | Bin 0 -> 4304 bytes .../Tools/Lighters/centcomm.rsi/icon.png | Bin 0 -> 4533 bytes .../Lighters/centcomm.rsi/inhand-left-lit.png | Bin 0 -> 4931 bytes .../Lighters/centcomm.rsi/inhand-left.png | Bin 0 -> 5030 bytes .../centcomm.rsi/inhand-right-lit.png | Bin 0 -> 4912 bytes .../Lighters/centcomm.rsi/inhand-right.png | Bin 0 -> 4862 bytes .../Tools/Lighters/centcomm.rsi/meta.json | 45 ++ .../Tools/Lighters/centcomm.rsi/open.png | Bin 0 -> 4534 bytes .../Tools/Lighters/centcomm.rsi/top.png | Bin 0 -> 4280 bytes .../Tools/Lighters/cybersun.rsi/flame.png | Bin 0 -> 4562 bytes .../Tools/Lighters/cybersun.rsi/icon.png | Bin 0 -> 4477 bytes .../Lighters/cybersun.rsi/inhand-left-lit.png | Bin 0 -> 4922 bytes .../Lighters/cybersun.rsi/inhand-left.png | Bin 0 -> 5028 bytes .../cybersun.rsi/inhand-right-lit.png | Bin 0 -> 4915 bytes .../Lighters/cybersun.rsi/inhand-right.png | Bin 0 -> 4857 bytes .../Tools/Lighters/cybersun.rsi/meta.json | 45 ++ .../Tools/Lighters/cybersun.rsi/open.png | Bin 0 -> 4733 bytes .../Tools/Lighters/cybersun.rsi/top.png | Bin 0 -> 4273 bytes .../Tools/Lighters/donkco.rsi/flame.png | Bin 0 -> 4506 bytes .../Tools/Lighters/donkco.rsi/icon.png | Bin 0 -> 4753 bytes .../Lighters/donkco.rsi/inhand-left-lit.png | Bin 0 -> 5136 bytes .../Tools/Lighters/donkco.rsi/inhand-left.png | Bin 0 -> 5268 bytes .../Lighters/donkco.rsi/inhand-right-lit.png | Bin 0 -> 5150 bytes .../Lighters/donkco.rsi/inhand-right.png | Bin 0 -> 5087 bytes .../Tools/Lighters/donkco.rsi/meta.json | 45 ++ .../Tools/Lighters/donkco.rsi/open.png | Bin 0 -> 4770 bytes .../Objects/Tools/Lighters/donkco.rsi/top.png | Bin 0 -> 4513 bytes .../Lighters/gorlex.rsi/matchbox-open.png | Bin 0 -> 4344 bytes .../Tools/Lighters/gorlex.rsi/matchbox.png | Bin 0 -> 4657 bytes .../Tools/Lighters/gorlex.rsi/matchbox1.png | Bin 0 -> 4228 bytes .../Tools/Lighters/gorlex.rsi/matchbox2.png | Bin 0 -> 4239 bytes .../Tools/Lighters/gorlex.rsi/matchbox3.png | Bin 0 -> 4225 bytes .../Tools/Lighters/gorlex.rsi/meta.json | 26 ++ .../gorlexmatch.rsi/lit-inhand-left.png | Bin 0 -> 4324 bytes .../gorlexmatch.rsi/lit-inhand-right.png | Bin 0 -> 4311 bytes .../Lighters/gorlexmatch.rsi/match_burnt.png | Bin 0 -> 4273 bytes .../Lighters/gorlexmatch.rsi/match_lit.png | Bin 0 -> 4809 bytes .../Lighters/gorlexmatch.rsi/match_unlit.png | Bin 0 -> 4306 bytes .../Tools/Lighters/gorlexmatch.rsi/meta.json | 87 ++++ .../gorlexmatch.rsi/unlit-inhand-left.png | Bin 0 -> 4271 bytes .../gorlexmatch.rsi/unlit-inhand-right.png | Bin 0 -> 4273 bytes .../Tools/Lighters/honkco.rsi/flame.png | Bin 0 -> 4319 bytes .../Tools/Lighters/honkco.rsi/icon.png | Bin 0 -> 4935 bytes .../Lighters/honkco.rsi/inhand-left-lit.png | Bin 0 -> 5397 bytes .../Tools/Lighters/honkco.rsi/inhand-left.png | Bin 0 -> 401 bytes .../Lighters/honkco.rsi/inhand-right-lit.png | Bin 0 -> 5399 bytes .../Lighters/honkco.rsi/inhand-right.png | Bin 0 -> 417 bytes .../Tools/Lighters/honkco.rsi/meta.json | 45 ++ .../Tools/Lighters/honkco.rsi/open.png | Bin 0 -> 4989 bytes .../Objects/Tools/Lighters/honkco.rsi/top.png | Bin 0 -> 4487 bytes .../Tools/Lighters/interdyne.rsi/flame.png | Bin 0 -> 4735 bytes .../Tools/Lighters/interdyne.rsi/icon.png | Bin 0 -> 4748 bytes .../interdyne.rsi/inhand-left-lit.png | Bin 0 -> 5140 bytes .../Lighters/interdyne.rsi/inhand-left.png | Bin 0 -> 5254 bytes .../interdyne.rsi/inhand-right-lit.png | Bin 0 -> 5137 bytes .../Lighters/interdyne.rsi/inhand-right.png | Bin 0 -> 5076 bytes .../Tools/Lighters/interdyne.rsi/meta.json | 45 ++ .../Tools/Lighters/interdyne.rsi/open.png | Bin 0 -> 4761 bytes .../Tools/Lighters/interdyne.rsi/top.png | Bin 0 -> 4496 bytes .../lighters.rsi/basic_icon_base-1.png | Bin .../lighters.rsi/basic_icon_base-10.png | Bin .../lighters.rsi/basic_icon_base-11.png | Bin .../lighters.rsi/basic_icon_base-2.png | Bin .../lighters.rsi/basic_icon_base-3.png | Bin .../lighters.rsi/basic_icon_base-4.png | Bin .../lighters.rsi/basic_icon_base-5.png | Bin .../lighters.rsi/basic_icon_base-6.png | Bin .../lighters.rsi/basic_icon_base-7.png | Bin .../lighters.rsi/basic_icon_base-8.png | Bin .../lighters.rsi/basic_icon_base-9.png | Bin .../lighters.rsi/basic_icon_top.png | Bin .../lighters.rsi/cheap_icon_base.png | Bin .../lighters.rsi/cheap_icon_top.png | Bin .../lighters.rsi/discount_icon_base.png | Bin 0 -> 4315 bytes .../{ => Lighters}/lighters.rsi/icon_map.png | Bin .../lighters.rsi/inhand-left-flame.png | Bin .../lighters.rsi/inhand-left.png | Bin .../lighters.rsi/inhand-right-flame.png | Bin .../lighters.rsi/inhand-right.png | Bin .../lighters.rsi/lighter_flame.png | Bin .../{ => Lighters}/lighters.rsi/meta.json | 3 + .../lighters.rsi/zippo-inhand-left-flame.png | Bin .../lighters.rsi/zippo-inhand-left.png | Bin .../lighters.rsi/zippo-inhand-right-flame.png | Bin .../lighters.rsi/zippo-inhand-right.png | Bin .../lighters.rsi/zippo_engraved_icon_base.png | Bin .../lighters.rsi/zippo_engraved_open.png | Bin .../lighters.rsi/zippo_icon_base.png | Bin .../lighters.rsi/zippo_open.png | Bin .../{ => Lighters}/lighters.rsi/zippo_top.png | Bin .../Tools/Lighters/nanotrasen.rsi/flame.png | Bin 0 -> 4320 bytes .../Tools/Lighters/nanotrasen.rsi/icon.png | Bin 0 -> 4450 bytes .../nanotrasen.rsi/inhand-left-lit.png | Bin 0 -> 4942 bytes .../Lighters/nanotrasen.rsi/inhand-left.png | Bin 0 -> 5033 bytes .../nanotrasen.rsi/inhand-right-lit.png | Bin 0 -> 4929 bytes .../Lighters/nanotrasen.rsi/inhand-right.png | Bin 0 -> 4879 bytes .../Tools/Lighters/nanotrasen.rsi/meta.json | 45 ++ .../Tools/Lighters/nanotrasen.rsi/open.png | Bin 0 -> 4449 bytes .../Tools/Lighters/nanotrasen.rsi/top.png | Bin 0 -> 4270 bytes .../Tools/Lighters/spiderclan.rsi/flame.png | Bin 0 -> 4798 bytes .../Tools/Lighters/spiderclan.rsi/icon.png | Bin 0 -> 4443 bytes .../spiderclan.rsi/inhand-left-lit.png | Bin 0 -> 5164 bytes .../Lighters/spiderclan.rsi/inhand-left.png | Bin 0 -> 5250 bytes .../spiderclan.rsi/inhand-right-lit.png | Bin 0 -> 5131 bytes .../Lighters/spiderclan.rsi/inhand-right.png | Bin 0 -> 5085 bytes .../Tools/Lighters/spiderclan.rsi/meta.json | 47 ++ .../Tools/Lighters/spiderclan.rsi/open.png | Bin 0 -> 4484 bytes .../Tools/Lighters/spiderclan.rsi/top.png | Bin 0 -> 4492 bytes .../Lighters/syndielighter.rsi/flame.png | Bin 0 -> 228 bytes .../Tools/Lighters/syndielighter.rsi/icon.png | Bin 0 -> 4489 bytes .../syndielighter.rsi/inhand-left-lit.png | Bin 0 -> 226 bytes .../syndielighter.rsi/inhand-left.png | Bin 0 -> 174 bytes .../syndielighter.rsi/inhand-right-lit.png | Bin 0 -> 4294 bytes .../syndielighter.rsi/inhand-right.png | Bin 0 -> 172 bytes .../Lighters/syndielighter.rsi/meta.json | 45 ++ .../Tools/Lighters/syndielighter.rsi/open.png | Bin 0 -> 4496 bytes .../Tools/Lighters/syndielighter.rsi/top.png | Bin 0 -> 167 bytes .../Tools/Lighters/waffleco.rsi/flame.png | Bin 0 -> 4319 bytes .../Tools/Lighters/waffleco.rsi/icon.png | Bin 0 -> 4621 bytes .../Lighters/waffleco.rsi/inhand-left-lit.png | Bin 0 -> 5161 bytes .../Lighters/waffleco.rsi/inhand-left.png | Bin 0 -> 5252 bytes .../waffleco.rsi/inhand-right-lit.png | Bin 0 -> 5134 bytes .../Lighters/waffleco.rsi/inhand-right.png | Bin 0 -> 5085 bytes .../Tools/Lighters/waffleco.rsi/meta.json | 45 ++ .../Tools/Lighters/waffleco.rsi/open.png | Bin 0 -> 4652 bytes .../Tools/Lighters/waffleco.rsi/top.png | Bin 0 -> 4503 bytes 137 files changed, 1085 insertions(+), 8 deletions(-) create mode 100644 Content.Shared/Lock/ItemToggleRequiresLockComponent.cs create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/donkco.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox-open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox1.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox2.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox3.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/lit-inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/lit-inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_burnt.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_unlit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/unlit-inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/unlit-inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/honkco.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/top.png rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-1.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-10.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-11.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-2.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-3.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-4.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-5.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-6.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-7.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-8.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_base-9.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/basic_icon_top.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/cheap_icon_base.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/cheap_icon_top.png (100%) create mode 100644 Resources/Textures/Objects/Tools/Lighters/lighters.rsi/discount_icon_base.png rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/icon_map.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/inhand-left-flame.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/inhand-left.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/inhand-right-flame.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/inhand-right.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/lighter_flame.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/meta.json (97%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo-inhand-left-flame.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo-inhand-left.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo-inhand-right-flame.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo-inhand-right.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo_engraved_icon_base.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo_engraved_open.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo_icon_base.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo_open.png (100%) rename Resources/Textures/Objects/Tools/{ => Lighters}/lighters.rsi/zippo_top.png (100%) create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/top.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/flame.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/icon.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-left-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-right-lit.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/meta.json create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/open.png create mode 100644 Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/top.png diff --git a/Content.Shared/Lock/ItemToggleRequiresLockComponent.cs b/Content.Shared/Lock/ItemToggleRequiresLockComponent.cs new file mode 100644 index 0000000000..94b8729476 --- /dev/null +++ b/Content.Shared/Lock/ItemToggleRequiresLockComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Lock; + +/// +/// This is used for toggleable items that require the entity to have a lock in a certain state. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(LockSystem))] +public sealed partial class ItemToggleRequiresLockComponent : Component +{ + /// + /// TRUE: the lock must be locked to toggle the item. + /// FALSE: the lock must be unlocked to toggle the item. + /// + [DataField] + public bool RequireLocked; +} diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index 16d676954e..f7ebf21535 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -13,6 +13,7 @@ using Content.Shared.Storage.Components; using Content.Shared.UserInterface; using Content.Shared.Verbs; using Content.Shared.Wires; +using Content.Shared.Item.ItemToggle.Components; using JetBrains.Annotations; using Robust.Shared.Audio.Systems; using Robust.Shared.Utility; @@ -55,6 +56,8 @@ public sealed class LockSystem : EntitySystem SubscribeLocalEvent(OnUIOpenAttempt); SubscribeLocalEvent(LockToggled); + + SubscribeLocalEvent(OnActivateAttempt); } private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args) @@ -413,4 +416,19 @@ public sealed class LockSystem : EntitySystem _activatableUI.CloseAll(uid); } + private void OnActivateAttempt(EntityUid uid, ItemToggleRequiresLockComponent component, ref ItemToggleActivateAttemptEvent args) + { + if (args.Cancelled) + return; + + if (TryComp(uid, out var lockComp) && lockComp.Locked != component.RequireLocked) + { + args.Cancelled = true; + if (lockComp.Locked) + _sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-generic-fail", + ("target", Identity.Entity(uid, EntityManager))), + uid, + args.User); + } + } } diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 3c7218b69c..066ac4376d 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -487,5 +487,8 @@ uplink-business-card-desc = A business card that you can give to someone to demo uplink-fake-mindshield-name = Fake Mindshield uplink-fake-mindshield-desc = A togglable implant capable of mimicking the same transmissions a real mindshield puts out when on, tricking capable Heads-up displays into thinking you have a mindshield (Nanotrasen brand implanter not provided.) +uplink-contraband-lighter-name = Contraband Lighter box +uplink-contraband-lighter-desc = A mystery box guaranteed to contain a syndicate branded lighter. No fuel required + uplink-smuggler-satchel-name = Smuggler's Satchel uplink-smuggler-satchel-desc = A handy, suspicious looking satchel. Just flat enough to fit underneath floor tiles. diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml index 9708373dbf..fe397ea8cf 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml @@ -8,6 +8,7 @@ FoodSnackPopcorn: 3 FoodSnackEnergy: 3 CigPackMixed: 2 + DiscountDanLighter: 1 contrabandInventory: FoodSnackDanDanNoodles: 3 FoodBakedBunHoney: 3 diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 2095edabff..c94306cdc1 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -2233,6 +2233,17 @@ - Chef - Mime +- type: listing + id: UplinkContrabandLighter + name: uplink-contraband-lighter-name + description: uplink-contraband-lighter-desc + icon: { sprite: Objects/Tools/Lighters/syndielighter.rsi, state: icon} + productEntity: UplinkLighterBox + cost: + Telecrystal: 1 + categories: + - UplinkPointless + - type: listing id: UplinkSmugglerSatchel name: uplink-smuggler-satchel-name diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml index b1a1c60497..c223efe1a0 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml @@ -172,6 +172,7 @@ - id: ClothingUniformJumpsuitFamilyGuy - id: WristwatchGold - id: RubberStampGreytide + - id: MysteryLighterBox - id: GoldenPersonalAI - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index 00df6b5b68..a0cc580118 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -277,7 +277,7 @@ prob: 0.05 orGroup: Pizza - id: KnifePlastic - + - type: entity name: pizza box parent: FoodBoxPizzaFilled @@ -372,6 +372,9 @@ contents: - id: FoodDonkpocket amount: 6 + - id: DonkcoLighter + amount: 1 + prob: 0.10 - type: entity parent: FoodBoxDonkpocket diff --git a/Resources/Prototypes/Entities/Objects/Fun/figurine_boxes.yml b/Resources/Prototypes/Entities/Objects/Fun/figurine_boxes.yml index dbbe86678f..6c466ea7c0 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/figurine_boxes.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/figurine_boxes.yml @@ -133,3 +133,62 @@ - id: ToyFigurineHamlet prob: 0.20 orGroup: SpacemenFig + +- type: entity + parent: BaseItem + id: MysteryLighterBox + name: Novelty lighter mystery box + suffix: Filled + description: A box of discontinued promotional lighters, many of which have since been declared "contraband". + components: + - type: Sprite + sprite: Objects/Fun/figurines.rsi + layers: + - state: fig_box + - type: SpawnItemsOnUse + items: + - id: MysteryFigureBoxTrash + - id: CybersunFlippo + orGroup: Lighterbox + weight: 0.15 + - id: InterdyneFlippo + orGroup: Lighterbox + weight: 0.15 + - id: NanotrasenFlippo + orGroup: Lighterbox + weight: 0.25 + - id: WaffleCoFlippo + orGroup: Lighterbox + weight: 0.35 + - id: HonkCoFlippo + orGroup: Lighterbox + - id: GorlexMatchbox + orGroup: Lighterbox + weight: 0.15 + - id: DonkcoLighter + orGroup: Lighterbox + weight: 0.25 + - id: SyndicateFlippo + orGroup: Lighterbox + weight: 0.15 + +- type: entity + parent: MysteryLighterBox + id: UplinkLighterBox + suffix: Uplink + components: + - type: SpawnItemsOnUse + items: + - id: MysteryFigureBoxTrash + - id: CybersunFlippo + orGroup: Lighterbox + - id: InterdyneFlippo + orGroup: Lighterbox + - id: WaffleCoFlippo + orGroup: Lighterbox + - id: GorlexMatchbox + orGroup: Lighterbox + - id: DonkcoLighter + orGroup: Lighterbox + - id: SyndicateFlippo + orGroup: Lighterbox diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index a5e0afbc7f..a55c020825 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -20,7 +20,7 @@ activatedSize: Small - type: ItemToggleHot - type: Sprite - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi layers: - state: icon_map - state: cheap_icon_base @@ -62,7 +62,7 @@ shader: unshaded - type: Item size: Tiny - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi - type: UseDelay - type: RefillableSolution solution: Welder @@ -97,7 +97,7 @@ description: "A dangerously inexpensive plastic lighter, don't burn your thumb!" components: - type: Sprite - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi layers: - state: icon_map - state: cheap_icon_base @@ -126,7 +126,7 @@ description: "A rugged metal lighter, lasts quite a while." components: - type: Sprite - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi layers: - state: zippo_icon_base map: ["base"] @@ -159,7 +159,7 @@ - type: ItemToggleHot - type: Item size: Tiny - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi heldPrefix: zippo - type: Appearance - type: GenericVisualizer @@ -219,7 +219,7 @@ description: "A rugged golden lighter, lasts quite a while. Engravings serve no tactical advantage whatsoever." components: - type: Sprite - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi layers: - state: zippo_engraved_icon_base map: ["base"] @@ -235,3 +235,404 @@ shader: unshaded - type: StealTarget stealGroup: FlippoEngravedLighter + +- type: entity + abstract: true + parent: BaseItem + id: BaseBrandedLighter + components: + - type: ItemToggle + predictable: false + soundActivate: + path: /Audio/Items/Lighters/zippo_open.ogg + params: + volume: -5 + soundDeactivate: + path: /Audio/Items/Lighters/zippo_close.ogg + params: + volume: -5 + - type: ItemToggleMeleeWeapon + activatedDamage: + types: + Heat: 1 + - type: ItemToggleSize + activatedSize: Small + - type: ItemToggleHot + - type: Item + size: Tiny + - type: Appearance + - type: SolutionContainerManager + solutions: + Welder: + reagents: + - ReagentId: WeldingFuel + Quantity: 12 + maxVol: 12 + - type: Sprite + layers: + - state: icon + map: [ "base" ] + - state: top + map: [ "top" ] + visible: false + - state: open + map: [ "open" ] + visible: false + - state: flame + map: [ "flame" ] + visible: false + shader: unshaded + - type: GenericVisualizer + visuals: + enum.ToggleableVisuals.Enabled: + flame: + True: { visible: true } + False: { visible: false } + open: + True: { visible: true } + False: { visible: false } + top: + True: { visible: true } + False: { visible: false } + base: + True: { visible: false } + False: { visible: true } + - type: ToggleableVisuals + spriteLayer: lighter_flame + inhandVisuals: + left: + - state: inhand-left-lit + shader: unshaded + right: + - state: inhand-right-lit + shader: unshaded + - type: ItemTogglePointLight + - type: UseDelay + - type: IgnitionSource + ignited: false + +- type: entity + parent: [BaseBrandedLighter, BaseSyndicateContraband] + id: SyndicateFlippo + name: Blood-red flippo + description: "A 'Valid' choice in lighters. Contains no copper." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/syndielighter.rsi + - type: Item + sprite: Objects/Tools/Lighters/syndielighter.rsi + - type: Welder + fuelConsumption: 0.005 + fuelLitCost: 0.01 + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: green + +- type: entity + parent: Lighter + id: DiscountDanLighter + name: Discount Dan's lighter + description: "The worst lighter ever produced, lighterburn is inevitable, do not refuel while lit." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/lighters.rsi + layers: + - state: icon_map + - state: discount_icon_base + map: [ "skin" ] + - state: basic_icon_top + - state: lighter_flame + visible: false + shader: unshaded + map: [ "flame" ] + - type: Welder # the single worst lighter invented by mankind + fuelConsumption: 0.2 + fuelLitCost: 0.1 + tankSafe: false + - type: Item + sprite: Objects/Tools/Lighters/lighters.rsi + - type: ToggleableVisuals + spriteLayer: lighter_flame + inhandVisuals: + left: + - state: inhand-left-flame + shader: unshaded + right: + - state: inhand-right-flame + shader: unshaded + - type: RandomSprite + available: + - skin: + discount_icon_base: "" + - type: PointLight + enabled: false + netsync: false + radius: 1.5 + color: yellow + - type: ComponentToggler + components: + - type: DamageOnHolding + damage: + types: + Heat: 2 + - type: SolutionContainerManager + solutions: + Welder: + reagents: + - ReagentId: WeldingFuel + Quantity: 3 + maxVol: 3 + +- type: entity + parent: [BaseBrandedLighter, BaseSyndicateContraband] + id: CybersunFlippo + name: CyberSun Flippo + description: "A Sleek black and magenta flippo lighter, bearing the logo and iconography of CyberSun Industries." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/cybersun.rsi + - type: Item + sprite: Objects/Tools/Lighters/cybersun.rsi + - type: Welder # + fuelConsumption: 0.005 + fuelLitCost: 0.01 + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: magenta + +- type: entity + parent: [BaseBrandedLighter, BaseSyndicateContraband] + id: InterdyneFlippo + name: Interdyne Flippo + description: "A deep blue flippo lighter, decorated with the logo of Interdyne Pharmaceuticals' 'Gene Clean' clinics. Become the master of your own cigarette." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/interdyne.rsi + - type: Item + sprite: Objects/Tools/Lighters/interdyne.rsi + - type: Welder # + fuelConsumption: 0.005 + fuelLitCost: 0.01 + tankSafe: true + - type: ItemToggleMeleeWeapon + activatedDamage: + types: + Radiation: 1 + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: cyan + +- type: entity + parent: [BaseBrandedLighter] + id: NanotrasenFlippo + name: Nanotrasen Flippo + description: "A navy blue luxury flippo, generally handed out to loyal heads of staff instead of a payraise. Fueled with liquid plasma" + components: + - type: Sprite + sprite: Objects/Tools/Lighters/nanotrasen.rsi + - type: Item + sprite: Objects/Tools/Lighters/nanotrasen.rsi + - type: Welder # + fuelConsumption: 0.005 + fuelLitCost: 1 + fuelReagent: Plasma + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: blue + - type: RefillableSolution + solution: Welder + - type: SolutionContainerManager + solutions: + Welder: + reagents: + - ReagentId: Plasma + Quantity: 10 + maxVol: 10 + +- type: entity + parent: [BaseBrandedLighter, BaseCentcommContraband] + id: CentCommFlippo + name: Gilded CentComm Flippo + description: "An Ornate, jade embossed and gilded flippo frame containing a bluespace powered jet. The latch is secured by a miniature access reader that only responds to CentComm officials. The nicest lighter known to man." + suffix: DO NOT MAP + components: + - type: Sprite + sprite: Objects/Tools/Lighters/centcomm.rsi + - type: Item + sprite: Objects/Tools/Lighters/centcomm.rsi + - type: ItemToggleRequiresLock + requireLocked: false + - type: Welder # + fuelConsumption: 0.0 + fuelLitCost: 10 + fuelReagent: Plasma + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 4 #Excessively powerful + color: Gold + - type: RefillableSolution + solution: Welder + - type: SolutionContainerManager + solutions: + Welder: + reagents: + - ReagentId: Plasma + Quantity: 999 + maxVol: 999 + - type: Tool + useSound: + collection: Welder + qualities: Welding + - type: SolutionRegeneration + solution: Welder + generated: + reagents: + - ReagentId: Plasma + Quantity: 0.1 + - type: Lock + - type: AccessReader + access: [["CentralCommand"]] + +- type: entity + parent: [BaseBrandedLighter, BaseMajorContraband] + id: SpiderclanFlippo + name: Spider-Clan lighter + description: "A high tech jet lighter, engineered to function even in deep space. Runs on a tiny microfusion cell." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/spiderclan.rsi + - type: Item + sprite: Objects/Tools/Lighters/spiderclan.rsi + - type: Welder # + fuelConsumption: 0 + fuelLitCost: 0 + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: green + +- type: entity + parent: [BaseBrandedLighter, BaseSyndicateContraband] + id: WaffleCoFlippo + name: Waffle Co. flippo + description: "A robust mass produced lighter. The Waffle Co. logo turns the spark wheel when pushed up, minimising risk of lighter burns for even the most inept user." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/waffleco.rsi + - type: Item + sprite: Objects/Tools/Lighters/waffleco.rsi + - type: Welder # + fuelConsumption: 0.005 + fuelLitCost: 0.05 + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: brown + +- type: entity + parent: [BaseBrandedLighter] + id: HonkCoFlippo + name: Honk Co. flippo + description: "A slippery gag lighter produced by Honk Co. hidden inside of a real banana peel." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/honkco.rsi + - type: Item + sprite: Objects/Tools/Lighters/honkco.rsi + - type: ComponentToggler + components: + - type: Slippery + - type: StepTrigger + intersectRatio: 0.2 + - type: CollisionWake + enabled: false + - type: Physics + bodyType: Dynamic + - type: Fixtures + fixtures: + slips: + shape: + !type:PhysShapeAabb + bounds: "-0.4,-0.3,0.4,0.3" + layer: + - SlipLayer + hard: false + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.4,-0.3,0.4,0.3" + density: 10 + mask: + - ItemMask + - type: Welder # + fuelConsumption: 0.1 + fuelLitCost: 1 + tankSafe: true + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: yellow + +- type: entity + parent: [BaseBrandedLighter] + id: DonkcoLighter + name: Donk Co. flippo + description: "The flippo of choice for the seasoned traitor. A Breaded novelty lighter made by Donk Co. Somehow edible while lit." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/donkco.rsi + - type: Item + sprite: Objects/Tools/Lighters/donkco.rsi + - type: Welder # + fuelConsumption: 0.02 + fuelLitCost: 0.1 + tankSafe: true + - type: Tag + tags: + - DonkPocket + - Meat + - type: SolutionContainerManager + solutions: + Welder: + reagents: + - ReagentId: WeldingFuel + Quantity: 12 + maxVol: 12 + food: + maxVol: 20 + reagents: + - ReagentId: Nutriment + Quantity: 10 + - ReagentId: Omnizine + Quantity: 10 + - type: FlavorProfile + flavors: + - bread + - meaty + - cheap + - type: ComponentToggler + components: + - type: Food + - type: PointLight + enabled: false + netsync: false + radius: 2 + color: orange diff --git a/Resources/Prototypes/Entities/Objects/Tools/matches.yml b/Resources/Prototypes/Entities/Objects/Tools/matches.yml index ee5100c999..c701a400d5 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/matches.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/matches.yml @@ -108,3 +108,43 @@ tags: - Trash - type: SpaceGarbage + +- type: entity + parent: [Matchbox, BaseSyndicateContraband] + id: GorlexMatchbox + name: Gorlex match box + description: "A pneumatic match box styled after the Gorlex Marauders' equipment. Contains 24 matches." + components: + - type: Sprite + sprite: Objects/Tools/Lighters/gorlex.rsi + - type: Item + sprite: Objects/Tools/Lighters/gorlex.rsi + - type: Storage + grid: + - 0,0,11,1 + - type: StorageFill + contents: + - id: GorlexMatchstick + amount: 24 + - type: Matchbox + +- type: entity + name: match stick + parent: [Matchstick, BaseSyndicateContraband] + id: GorlexMatchstick + description: A military grade match stick, used for lighting fine smokables and noncombatants alike. + components: + - type: Sprite + sprite: Objects/Tools/Lighters/gorlexmatch.rsi + layers: + - state: match_unlit + - type: Item + sprite: Objects/Tools/Lighters/gorlexmatch.rsi + heldPrefix: unlit + size: Tiny + - type: PointLight + enabled: false + radius: 3 + color: green + - type: Matchstick + duration: 30 diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index 93a946df4a..c687c52a46 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -169,7 +169,7 @@ id: FlippoEngravedLighter name: steal-target-groups-flippo-engraved-lighter sprite: - sprite: Objects/Tools/lighters.rsi + sprite: Objects/Tools/Lighters/lighters.rsi state: zippo_engraved_icon_base - type: stealTargetGroup diff --git a/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/flame.png b/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/flame.png new file mode 100644 index 0000000000000000000000000000000000000000..8cbb46a48612cf26c9875dc66f8cbca03b0c53f1 GIT binary patch literal 4304 zcmeHLeQ?v}8F%c4q-LZ$7Dx&SQI(MZLDr`oONj%)4%k;5l3+%{NQ*4VjvCu?WF>Y& zyAZY>(C%nS2IMF!9lJtVzt}iPIF8jo=m%RNbZys?m9$$~>6Hy=2gynydu2Ppx%FA6n?xoF-^F`1+KFmpbj<=L!zZ*f?VzzKTQNE_=E?w8sAM<#~1apL{@NX*4N6 z6Rp-Nht)b-52#}IW7{nDQ;Ty>KfLlVjAYErY}#D)%PV`~t{^Oa>C688?vi+%B@{Ssgee?R!PY*`PQ%g;jWjO^iAIx1C#)@Vy zxK1_Ms*Pu|WJA&J9`lRaXElD*^%_>&zk^)6pWb-S%xyM3%)fiEL%+}_zGug`?YrH( zsr`fN``?_~)u{V<&Q~uidHmDi6C)podpu2#yyMir-to_@fjikc?Xks&0t16@9Qmj; z<(qTS?eE`QJv(}(@beo-X42ZPdpe%{;z+^Ol$|Bf{w~A)o%#P3^{3%$KUq5Xi?k_$ zj^D59>3P4bGH=7e=EI6ECrA6Yxn~~wDiW5w(#W&ojUnBJz4A->!$UrxyA~1XtJb-k z;UvF-p*cp6RVqDYYC8U+P%3tll`fv+BW4TePC0G;#SyEhZNIhuzTmFY_(3;^&83JXR2zCehHSl}2g1MXEb3PUj$rO^V{I;$Y7BnuE_pbQvN z5fNJmxJ(a~%DjiEu`NwNfF}#wpeR8GMZ@8+Axs)1*^A;dO`{lr5(EM~kWgztVIxQ& zl&?a>F>FGJlf|GSN&!g4WZhD;Vu4{W4vpsL4?3M=@PSZ*1;7UyVS^}cz)-&*O`Z`_ zDp~+YBB5`c5pscLiq;4rsafWPiWVWDqqCXfb3XnH07|)IQ1)F7G z%!lVt!6*0uXb9wokMmbV&t0;{<))6r%1KTHgd4*j=RI0`%o%t&os3Q5n$@5Vn*~<$ zWq64bc_wx%5I9K)WHDmGI2NHyCKEy%Ne@C$yoq<4FaqN}Nl=bJNMQqg%9J3T)vOqebpY;l8FyM_1sEuJj zIe=PLRVqM^*+DgoRTfx9l3kMIv%qS$kP10A>;wynXBF1QDguax5k>|h7@TrpBtw}P z(p-e$43^|C@uH{oe|f9R2P%y>-7bbe{MMK$zNS_RP4TDrqfd-2CJ2fx3x?(5C4|@( zA>J;46(8an*nn36`$s~sqjvFI#DIH9-s3i#5EdhWo^TpRXp_f-7-@nu;vRzL2s*~X z7%DsR`z!eZ^j4NnfqKEUx`-d9@wLyR~1S60n%3w56EUNApqt%w8|HVgX z%pqxu0rTQEuyui*5FOhJ6MTVOzsn=hhwm~31Wg8+5WkajP0}?X1}5Y@sjf-7Cd9ym zoF~=wf1^u(_hU*3fH$Bp_*6Qv=20GeW=(NFxXh;6r-^9t&Y!*H0+xG&_PUTpGxZ1R znWEXXI~y3&6o<1S?Q?C0)=+RfW4HPj!Fq?S+!eX-k3W@9JGnUXp8mIX9hmdI=YE}W zty*`u`rh98X(u~ozty=s{p$V0x4btC!Hm3;a|7(ipy}_{-n`@5U59R6YUf7q8POvJ zAHJCSuP1tcSl77c+R-7x(!M-3_*m-s1?%Qt9DLSyAU8Tt0;VU94U2ASzTA&xukd?u P)#RwCw7s%q-Nyd_Zp{K% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..522e8244449de43eb4f82ad6f22962fe21e43ab1 GIT binary patch literal 4533 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..9ab79bd56cc8e6d6c1509021c0aeb397f6badc58 GIT binary patch literal 5030 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..b377a18e30c3cbc496d0ddac10a3821dbf2778f2 GIT binary patch literal 4862 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 Be7pbv literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/centcomm.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2ed7245d150a8366f21bc9c322729eca4144e6 GIT binary patch literal 4280 zcmeHKeQ*1gFw=ffT^Jkwsop>v%5*xCc7cKZMMBr zDX4%rU_m|=l4ACJ9(D|%4Uu-6__9h8s+nP%E1%X@0@J#t28(N3q1BV2dmU_HVMZQ za#)NCu-X(CU_leZ5TqTA1&)pCghyVDJiENskr_63Z!Wi=>aia2_ztbQaOR!PM#t3i zmDAEem#SpYu`9 zzJp88mC=ol|8U#)EAWX06=yBq)a2}2aw_Ba;Z5C}AFVu+`=R^n(`+DidBXSWl|yIF zRWI|No_5o=tgh@1&AIWbjZ?lj>OFd3&*aCb!?T*7e=_-S&b)88Ru>fAM+PBi*i)k0 z9q_r`eF=dyHayJ^Eh}aZWGyY+W!Zi8lU?7nbx@t9HrGt^#Jt&e7bWp2cinf9 zp6{7s-9IK_nX;kX@%HM1`s1rU#;Xpjp=!1`7v7ZD>MZJEe$yu{{~UAdT7G86?rHB!$4-2@<9P9~ zt6z1jKK$>>yE@KJI(>OZo-^ae_LgO5c1%1!Z0)Z*4y>~LYUQ{eMAKg6!V{$@UKpM& zwR|+Uz5Vdivcd&L4IikPW^=~hChULol9rSs^7U85%U3cNY)ZT{uIEY=G+v_!8m!9y z0K>^K3(LzP!J@_Dpz|Q8_45-u{rm&aeYqQ8fb#npkIXgbPJJF1qQ}ed zGAHtk@hT9`kd<=qsDR@#GrPqO(9`Lyk(t;c0h9wYX)v%n1fmRnKUQQ}EhJs>Ds8Cs5 zHo{IhtvEpvl+$h{N%98hAt9lFmeW}Y+(J2w5uRg80VfMuM~tx%0gFo!V?Zwq1JVJ~ zvU;ZiX2TA$VcZFURpmrbmZL62j}6u-`-lBtLGi50dRSEe-f+^&;3PxPL7ZY}8)K!W z-~@xG;bmS7H~lZPzI@=~RMEYn0{k}_rqr6M5ay@8QlC-LSWGZ%EDMI^QYk2Gqre++ z0?moYY*t&?4ys8HWLM;{ znq(8g^a#)qXayS7&-bZXBir3H$>}f}_&O=Pxb-$E@to?3o_uO-O?Zzy9(hI3q(h$Gz1G1dX^uzlT9D zZO8}4;i}JHGW>K#ZidC`Y&(7gm_k0!^k7vdSDT;pdhO`v7PjW*@B4au;kHYK>$Tli zBhPGIzIgnL`#jq}Z{Haw>I#;1h}qfM&+K3PyYcJYJ2GdTPzZIz6N?Ux1lKKV=dosg m(4d)vn@aag&d+k^LQq@LZQJu^pPL4}LB5hQ&-NL$3;zoVDgUeh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/flame.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/flame.png new file mode 100644 index 0000000000000000000000000000000000000000..09c049be71440df46725eaf460a5d63720320dff GIT binary patch literal 4562 zcmeHLYfuzd7H+`jxRS&uD2!{{7STj|reE{u4x=K2&QvmFM2xtLF?YIqu$P(Xv8Q1M zvKqj5bhQZ4kgR!`Qe1V_N=nhviWo3tP25mmT*dXV3DIQZuBI%NO`+`V8J@MN+M*Kw z(N+CA_w;wq`ObH4&7BSI?0KVgDLMo}Mmrt$9C$B-CpuynytZP&GdZRt_yEE(OILqeyDxuJ z+k}sclV7V}x^mN3lT#-C!El#oCNOpKx{Q1B&OOchm!99Ou4}J&Y`5!XOIz(VZ_CAv zm8&D}T|%YfcwEX}`n(Jv3*6Q%~3yFe`@K1Ll~ZzGxcfW zV%4OL3x_8cESZ=;G~-r6!;)Z*S~;fk^|8Nchy?$>C4BGK;hV^N^TD1A;}UYuP|X{T zRDX70efgphBfz7!@ms6^G?gB;II{V`OYQBY$=@u#eEorb^3E5jx~XFts{?rr-#5^I z-1gU!cdVbEes#|8v(rJ-&<&H08jf{*a zPA4md>Dz0qd$*<(UaC4loW#ceSX;jF`@>J%jC=j*x~3|_gjc8hN79|bZmpbq<+b6%0_7hqtgSsa zGka3mjG{wof?gm0b=v6{Zb!m$f!z7Fbmv||*$!pjl=gc*1W8;dL3!o5p5=JiZvcYq z5e*T45b6#=(q~12fG-qP)FT#10ULJn*a-}k1RJ)<((%jMYTc0s^58@5bUgPhSA4u=h4+8`?hMv`S&BS9G{3Wpwes3f3*2p$Mc(I8?N zb}_^&Qc#uT0IFdEk6fhMFbs~P-SPQ@E>{nHAk@VIyd3(v~7n?Q`O{Z@laJnA+e%{@=N1dUU%f;DczDS$YX}4ioyqqBO zlE6hDt)ht#MBa?k9+JcvkBP=v;IZHgLwUW7hqCg3>;vTtgj5jVMGXpq8zhJWc#!~B zfxvmz%is(tcyJ(k1)Qd=1jAcAq(`LtKs={NP?f;fH!2NEfKVnzU`+&1pC08uEd4qS%YX~QT3(Q9%0fa;YMKa{!@5ae*EcPLl#iwjhs(MDQm zmSN3=nI%oE#bWJsdR|mQP;we7Nf_wZh`@7mAtr#*k^G=QGzJ3&(NDC(a4;Q6Ezpz- zk)w8)4VS5iK$VqTS@zj5Em~BA>=|~!h7y1Z>_8RaYy@TE2#O<_TzI8Oj$o$~@Y=^; z79?-U|MS+`2ThL^-64hG{3TIStfv-;%VTe`SDzGZCKQdf1*~E$g%Btfg=m}*D>lS0 z1Azh&t{+{3?Y2ulB?g8eXqGnPloh}V(v%qoR*wm1tiVF^W{<_f$HdTs9+JIk7${;! z0pt;K1qB-A3Z2$f!zcSk6J9221%i~}1chsqksL*Hq!lwh{PYM9OERp9!7XMhg)^c^ z!gkT5FPH#r7AP~+ZU1n8etKPs=uR))s4a-y#Y{K;Pq||beO6FNOUwpWX1LHBdsg}` zzF;XH=FugyhdBj`4o)&4eh29qq-#J749Iyn5X8oz9try&7 ztJ}i24xx^<)|xWQ8=tSR#A$zx6rZo{Jl?ru*8PqLtHP74No(I#?ppLOUp{d01H`v( z#jzX3N5|DZw{X;@55Gv;yG8$xFOg#QxUKUWgmHQ&)I6!1T_v=<_1VfR(^{TY&P;1* iPTKwUBQUD2BljgFOEsj}R#t1FBF?OA`~EpER{R&Us9Q1s literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e42de6708a5aa76bcfa7b947628ce6a17f31bab GIT binary patch literal 4477 zcmeHKdsGuw8XrJ}My0Lmf>o4pT%lDaGs#R|W1=Df!`eUu6mVhdWM&ekd72C)(6th@ zRTkffRcmXZRch;NyG2CLsdS;r`luGS*6Lc^qkY)g#nxJ}O5Ho*eYWT9;hgP%9L)K73k3NuIZO+pn&HT8@!I_D&wTBUd~;gc%Zb%DJ92cBM;0sAw*B4knbe+B z^UnQKXIf|1e)Q2-X5Z^yr>>0Gs|uBiS{I%yS-Ef3jFza;wdU8cs^>mTX=q45$C~R5 zN!tv2Lnb7I)IUL1=fy4FVTiYO=wrTrw=TRhtlgg%SLyxgQ3wiI$tNe9(vp*V+W}4N zShi7TXr2@M!82L)2pSbVZs}^%D>rMAb-VtYa?o^1vX9!D|I-wbH)Q6=hJRANBCc{_ zM2xjyQhs>St+18?cc!p$?8BGFEpG9<|GD0Gce1Yos#!q4_33ZJvd_rdDh_WwbzpTM zCo+z)K+RGxp`f#*6qOJhFI`|Qh~W2fv|B5z6llo2oDTm@~2IX2Oj- zhoUv1KQ#m@zd01&5%SW^rgK%&CpJyJ$4fpyZatsczByu~Gw|NRhK38X(&Ne!i|U22 z*x1l((@y^Jw%_Nnx*opD-?7y9M6m zghfo+>?#s;2m<_YZ+#B8(bxy?^!Bg-_`v+M8zIpkEx}%?7I! z%jCSSA`io*6mw2t>OhEjX+~2Yg4mLkcesO10rCbVW0}4IL=5 z2E_}!rJt-pwTYf!I|B;=>H6>oMfdg|3iWOY zCFws*aZd0L$On!}g=6Y!!7*#3dHy^-v>q};P+<2853oGqHspCBXw+}SD+JoUV>~cM z2x-QYh#R3%A(Yy7qm>6|>8H~4N!hv0-&V_>ZN|sFcx*%<=ERDIHQ_7ftqmzUJ;w7w z>}#sl4HK_JjdRy;c>3ebqvNY;HvA<^r;h(2P&t$JWL>)W{uI-)$~hTr_wTh=jfh%x z?bvzSktAC|S9HdvH$K@0?JL@~ITVg8Uz~W>3!Qw&{=3@tH>LXf@dY>Q4PkiVrm zj$(leMv`8qU;xPI@>=1!U1 z^!vL}t0PAdZ(Lom=L%6Vx~lcyyU~v~7Cf@$i;%KCS9Yc{&YbcNWPeR{nfC12{pN}H q|Iqc~a$Tx%@|0E0|2jPCJ?Q&&Htinwj5~lwC@m#jzklwM^8WyS-Caxo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-left-lit.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-left-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..fa7ec883cc325f13adc016cdebb82ab3a48141fe GIT binary patch literal 4922 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..e0d0523d19174c3e15a22d12b659d67d62342e0c GIT binary patch literal 4857 zcmeHKe{dA#8Q$ayNe_XJrb!@yESn-~*xTQCw@WT2h$D2S^Hg2YdUe2b^`qM6@Z%v!J}{hrzDURm*4-j%`f?cOtA%>DD) zs%_Tbp{p4WS-NH%V0ZoTl-z%O*2#{atUKOy$9vAhbLv-J?w#}8zPIVtySaZ1JW_I7 z@vc{OdSfi}ou!wWEk}>tW!rHLV_*B#;^~D8bM)L7R~MbMeRBPAuxMFFL2mo$FG}wF zlyjUp``}BSjy&+w?Dc&GrRTHIXWd>U&nR*4q^n*hE~xh}=%0RmTm4LD-YUo{?J>2y z+~+ATAEpCIY+cpqs_re#Kk~CB`!IZ3c2;wT@7XImunjw(sMzZ}ZGBnjTK@GMR;{jG zoYn6$p&4co!%Z@zJ1Zx7R3X?IoS-dclpcx*?juf-R)0)y#LOtY0oU^IkCw$V`JgJRO=D!vqvh={W@cE zxcyH{ySq=7)D%2Azh$3c$ zTa908Ym#^wySKzz92X!!2pA$74+Xu$HLd579 zQKMod1Q{ymrZb{`*rh}*h-xjm1S(d7uu(V~qRQj-r4UR?4QeQoAO*!6vzRQU@**vI zFp(om1PFo<1dYP_s4@AGM$OQojano%ZA^iw;RLbKB^jzRqVkwI=E!%_VVyT$VOX>T zHq7#R1-B-(nALjR!(NazNtK0EF@nspic4yh4x#Kc&Ifo3r)ietn1BN)P9*_lZlh4<^SChDMvg>$LD5h&Jp?;N z4a-_AIx^%}Ltu#^n&MFohG%&@$vGV~Npkc^(gQ$`LdTk@6lr6ei4j>6Dj}u_ou`Jx z20%o@4T*sf70b1trh7FRxUi&J=FSO_Db!vxdjKw)m;#9k?)80&6cK8G%f4N@Z)hU(ggt^{(TPKcEp zk{ZQu1Ax!5p~e}Gt2c2K!}2mu1~{B#MF-Au5`zcqB#ZO3!rGnCqY{_2LJB>qDMn1x zL0JP-9cl#|JE0YN*N_?R9$QVU5tuto(iBe7IK}%Z2Q;9-I56VY({oY^M~RFb=XeK+ z%T5-y90({l!#NZ?Ei#HMC!O@4=#`mA2I?Dr=%6%wl7BB#=rzcc_S2NWG6Ds?Mw{mN zKk%g$JHrPk8K*ds!C42z<4zVnXIPPOC{n=TKkZVG&aVapaM-)dNOgS_ zL8jbcUTMg0w&ucMhT-v6WL!?4mX;-K=zmUyp&F07%pX7f$p^1a?IAOfvIn*Y2;xGg zr*j4-UJR#~8U<-EtEXwtrQQELH@kn!M*~kBfA^~+FlK&kbCfi%cJ*KCd-<>hLFTm~ YXFWMn9(&4BX%2cSYTU0Ze0a^j0oQ(*XaE2J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/meta.json b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/meta.json new file mode 100644 index 0000000000..06feadad57 --- /dev/null +++ b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/meta.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprites Created by Smugman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flame", + "delays": [ + [ + 0.2, + 0.1 + ] + ] + }, + { + "name": "icon" + }, + { + "name": "open" + }, + { + "name": "top" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-lit", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-lit", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/open.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/open.png new file mode 100644 index 0000000000000000000000000000000000000000..3feed530a0de08d93b8be4e7c9dc3e0fdac79c17 GIT binary patch literal 4733 zcmeHLdsGuw9v+ASMrE~i#Ro3qa1>jeWHK`$nUPR|@Q5}vB39^8*Lj7^k{8KfVthia zRoO}ru=uQxR%@+~;saehiq-0hYf;y=zN&Sr$GX~8k1y7Px_1&lINNjfcuxI~oXpIf z-~Hyhzu$Midru|{EZLbol>?Lz1obp!8FRoDmXD|iaP|fQ55VP{KyIFt!}wsg$7L1m z0xV5)3$Wl9tq|nD;INF1J_JWSz0qf6Y51G5N4HF>9eBGbZH@WjgCWSif>n_Hz@5m+ zikkkr$&K$7;@fK3I^*JXjWw?~>PrUa&%AoI*U4eE%lB0cxZ_KXiyx~~Z<-sE+ zq)^S*t$pH7{cMxIo>wui_nPihkH3^xe>r+&`8NAa zWI|LF)63AWx@Kbn(LLY4XzTQ*ra;W~{L43<#SZ>_3SOV^+R++k-r-w^iRDYaoA#;x zZw-r6XJjWaC%Z0)+oRgsd}PnHZS};Vj6_3b?9jer295Ax!w0^3k1R5d)i%U~r@v{B=lWq2kZ6 z_rFN};9Aqc=Rf-DtVMr1ZB`yB`FG64XZ;l6dq-_|Uc7R2*AGcy&5iZdXCF-%Sbsa= z=EGfmsqiOtC1tmE4ZRcg$;kSXm8$-Wb2(HD?_vd&-{A(f zgP^3h{BDLT6eO4x3Ph&?xwH2G0*kx>nV>aeW_Oxk6SD#yVO$_PmkShf6py@>tW5IL zfWRS04D5Hdp#jM=Ti`U8M}SEcslw27zc>{~l9h0hhqux> z#*7vUaA!bllH{h0p!4 zCSoira44t4wJ53ASy8=4gP}Y_=}F3}V=+wAj>_cpN{o{eWGXLC`Dlm2O2z2wWoN;BLY`4_V!uHR6L+cv{EF7CsHWJVHiqka0b=0gn;Tv zjL>QsoL~ejn2kISbc)4fKyX#Nh{euGR+q;CtS&lvm(TkGoGUtnaS|iTrqK};N$Cj^ zrxLX!M!o>OD|o!Xax$w1QxW=L56{sVfRh2%5gkl{pmsY8f*tb2(4ZV3Eh9S>FbCtH z8amA*Fp|rY>vGu*h@34fQ?_-R!Ghu$i7_&g07k=bEsf!{hRg+LEd|=cF%6Bi!@GFV zI_>|V<>dn>g(f{q^n&rH1w)}VHBKlB-Gy%LVsJ6RaBx}B3>PZF%S;vcV4i?0)Wz8t zXMq6rj~2tW#>HPT1Ic0=y|=B(4jgVs|Nk24g~YY7_6bC@<)U*7B0n@`l(tnMvyZneGsv-3|(53B|z93^sao+fLu2 z7s&Nhep+nyDu;mK&Ou&E-%hzY<$5UvUJBglu1>jLN`aRGce?90lS}#HT~Tm?A9z0S zCYW5EQ3T#1BiJ#SMyMQOA*f{i`yLSK=FZCZLQwbDw>?+|>1_Q&M&>J)`@1_=B+6OM{+7 z%$&2o)MZ&2NUiNoVcCqVD z<;`d=UmJDhad%V1FlXVGs?;|=_(`u{RN2sF;oj&TXL|L%>I^hKWUBno&ds)qiK}cE ztf}Sntl}k4yFBqK>aU-V-(onCJnF*j9zPDUL4n^DH?OYxWnfh4oRR_m6wR}p{#Ea8 z?+Ll-kq1@z6W!l6Irh!&J@Z3-?LtBOeR0fnPyge!`@brSV)`9X-ra=SmUnXy=Nku1 zUK%sG+n!UIpU$XgiobLwcJ;d9my*$e)3rSb)9i30HFHAL0^8EwCzh?x|GV^2im`TY z>6YY()k4Pct!K|qIvALro4(`N$G0{$Ro*-LsJ@}A$uuk>A>qb5ccaUSipao$_2Yrk OkSRUexFvN;>3;zab*tw9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/cybersun.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..c85c170e41ae2c974ee38d8cf5c151aa5ac7079a GIT binary patch literal 4273 zcmeHKeQ*@z8Q;qp5|1HfG>{a6SvEqHu(x}AdzajLhlX6j-RPy44@$y>n)i0!y=-%L zd+csgnRGPtKomt0T3S$RZ9&V(G&*Xb4w1gQm(Qs) zoy^q#ax?q!KF@D|&-47==Y8kiO~JaAb1d^M7>3R9`@9Y4iR)MHEOb|UdcH!BbWc;W z)<CT#-d70&%T74sn>2L<~!wjRx!U(s=I3rvd&S4t`Qx(0VX*%G z7lfPS!UN9-&y1WG&y~FQk9O^)!TQe96*uf&z%D31xAeUG_ovfyLpilig`TE1-+jDh zV4!UAwJ$aP>ZyL;Ueo+C)Bf%3mX?w=eQV~34?Q=#`|PQ#E2a-lx8%2N4WnvIKbNYj zgZ}F3v2sumJJDBA$z*k=~-F4WZoSMmnG=(1xvqR z*Lmw5#|jl|`ObmL=eNx7_;B-Ubn}VF?5%rTz1Pg^_gVrjKkqzCO|)eii%oJXSLB*d!^wKc&-+40@ONE6oerakA)3~J~13B2T2R` zPDRXy9aY0sD-dY1(j?0f520s^>y+c}09sH2(0~_c5JjUI2S+oUjcr1A#>Uwk<+Ke6 zJAs!4N$mb#XnpzM?#!h7Bo)Q)HcXi{)d<&RMwwwmG8Pk#8_R+Ne5M2ybV0$0i?}i_ zz8%EE5bYnM4LfF+zM~mjpfcnXM4ogxov5E|cA5lEz>rRxJ>;x#inQGon#!)qqLu&( ztO_F?kyfZd4XyB-N9XXCsrW=Y)F%i@M$!y9Niu>OEtb-EjInCn)PL#WHUN{h81!An zhPE!W6H?<_;iz8vrt>}iM(5#sjDV|rc~VX0>~D#&te+}EOF*z6nh%Y^ONS%i!^ znmMi;zO zdi>5M%Gy^i=9|+mCvtbBQmIA9`ZV>8t_>UW%;{9QVXAVcewV*6Ls3s#Y7gC9lx?

10~| z%g*e*-S79ipZEQKzMuEz-qYTqC0Uu%GcgRyau>Qv(AbP_JR=SLo+Tm=prL!UZ>3fO z8t_O|m6agGwZ;gHr^kBNUbJxcU`xiyYqDeD!d z)9ZFR2kSvqv_8JoQP}0ZcSCXM3$wE~)=#ND?cLS4m)P<`_NJ;mZ)C5kqZ>cX<(0yc z3gg7yCt4P4DoejFQ2CvTiTPL4yDK9l+SaN4%Q8uSQ=~EXlVh=?{do(k|FHcBpP$6a zUf;Z&HC>!^z<)m5u*kRK8%xi8So+aPV_t8sqp7KL(`Vm5cjIPy zl=Z1kEaa~1^J}-4&D`)sYy7vrNO?N4R(+w>(uz@XOMBBceYStmjFYY> z-}&qPx0zGBXZ>t>`|KS1H1EdDo@*`tI?*5e-TP0?EF=F#TD%N;$KRITQ0OsUHZWJTbqCV zGPXXvZjae|G%LP#lnSiAFp(!4UAmL$H-hy}ph&52d{VXrMzl-Bg87+waRC8@pa$@GC>V|jaR-sW70|P8rU*O{qSZKvl^!qdRHG2* zO}vRF3*t&WOU%#2^P-Y0l(-fTK%h4VQLSkafub538cYqGNsR_5#%{M$G)u88i6Y2Y zV^{-mG8~(sLnJX=FeXNoh^DAvT*m}{wN7&o1oGp9`Gq1L&k%e#HoyYngNlO)#h7R+ z6rx6c5z`9l5y(J7U;9POhn6W-0%K}jRD=cfFs#iO39-cO@eU#AB?XjFBvBM1Z`5Rx zI20GDiv|-hl1RZI3?a}M%8wZpuPO2{S)+2(J&AHgCW59L!XFhqSbHKEMR`1eOBL(% zN!>07q30_|s;Edp;?V}pv;;*9$@v+Ec|U6t0W$*19gb-rEJ7U$ zftwVB!&$5{1RPIV0V9$;;As+A{XA)BEUbl-Ws4}YBOr>S3Q{Eqj?7Ajk`R=cm+WR* z&~7Jvkl-UlJy>vj;Vi5|9igFutjXb4GN2}^22Y}n;f zLaGPH@aB|MTSEJm0BNk<8R0Hh+}K*FIn zMnL5tYJsj)gq*OWY6NE#0!@wjR5j=z^lWh*a>(sL3rYeSZ~+aX*=W`*(5%4NeKapH zv|zT)p&5Z55wA*$-1y(3_2q--C7WKT#L)bW2~%=SmBQNOTk@-<=rJWq3W&O)*_fI7&r782O}W|Fr7D<@j~R;!rg zdk8(I%31@6!u$Z@5pjhCn&1k5XrPA=kItr{8tM%~l#w(`GQ1Bl#c~2;Bd9xHp3P_L`lp6_QZt2{<=s1xNp`#PeetuG-+wLZt%Xyt6WP0_cqe4NxA}Xu+`cPsReICz zy6|j9(P^#+zWTwfX&81KEW6x(^)IH*`B#mb7dE$~%st$>KU959jUUL64RPO%cUupZ k^)L6NI{QPmUw21Y$NjQ{`u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c71349d413f4d152b0fc9034ea3be04799b48fbb GIT binary patch literal 4753 zcmeHLdsGuw9v-j)qEtmeL{`Q?wO}Wi$%8zW;3EMNBoHA8Qm9U5CNN8q3CWNIWa|?} zaqaQAU8M`9*1GDtOKsJ4ExO_YWqm-^Rye-URoaScMXObIsqEef@3TE;k7u|07ddA# zbMO7;yT9M}`|drt*{n}V4Db*2haf0Gt5K(cJIq~vKH%F?Qt|}c8cPgWY#Q!@ZFa^) zn<3{Rcq&^uGIW$#l5a67m`S6akQkP`@7PRp36w|yolmW zhjPY$`Ecj2mzJvc?77$!nh=_>f!~SVjSDus?VOEYx#j<8htJZ-7hOA6wYL1>Sn&M7 z+XTjh>ZXx10YKF-+}ni#l5GbdoGFm(U>J{8~oc5y_LdSmOI*?m}Z&D@>I zwb3E+VErclGmqB)^K`el<2-z=J&ywm`|t(&=FpW2ay-U(835csK17^5XpA zSUYJ_q^T1IC_qce%V$}eLLhLtTzr>^&)D+>m|QLwphAIAhyVoQD7Lb=8?ibfIEsD_ zHRT}ew2h@1E6j1?My7~W@_1kz9*oao)9Hrjt&RZ|fF1%jZWCa9RA8|PM!w--op6(H5I0DIngc$w*=dXDhOsJs6S@ zP-e;kNF5+PY!sfQO~Yc1ij5obq%$%QFx?RUDD+_N9xy=ZbP6>?6mgSk)k+>0uYzO< znpAimWkM;1i%doY6=5VIrbrx-3&j``Ly$%^MlO}%63GZEt<}NeR)XTF06CuqJR)33 z;zp?vp-8b95lclPL}rx4AQB8CCAicmF&Rfvq}plVO58j$DvpW-R1}V47$(9HTt>ZUaRB@`RH(u-i)&*#%=*tr>!L8atsd{XbY9j z;+$-lR3w*+#4!?~R4NroK`KVacdq0_KyL>4))VOUl2o$$(@$!T%vW zxs(*+5)zSkmWvpTL5vtKM5L5hg5xrg5fc%k!~HMQ8+OECda(j-LmVt-tl;0u-47VC zg92Il`@qf&HhRI(PCuX*D8-NY8L-)pIRy-lP4Ytej>$D9*9$4|Lf|oXjmh;w3cL__ z%w7L8x%`LEij)=nz;l6&{YloD#+EU7a6h|zIj`@M1@V?c=Ouizg=4Rx_(=Edhf)r zBJDiaG1fIDGcl;}a?7b(S$FTkDNQZ6JED(hR3G+i_bY2VTli{+*38V=vMcXgv$mt^ z#5}Lq*`KYRS3XN0HKV8Q(cyE=^_6Rqj@QqhIJ5Kc89{T+8#gab@cl^r!EF;jc-`sq=Wm#*>sl1Eh^(YDpq&)u ze41Zst^K8uNRC`r2|#H{*4)f1l@pG(g#`3o$X5Az6(IZn=u?0kX@hykG8U@Q$u5|e zRe-sVmmLjW>^EiVQ)kSf)oEp)PYSDk_fC&()?z=XT%G^>J@VGGwyV8Jt@V@QEt8$c n(3TYs_r0lltNG5~i{hZ`-ydi{@Zl3s2nf=~r>JWeuUz*pgQvHQ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-left-lit.png b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-left-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..9278dc5dff8c69a7b9ec09e278c33c9da6aab041 GIT binary patch literal 5136 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..3b562db5d834c6d6c0148f35bd59c85d27a8f878 GIT binary patch literal 5087 zcmeHLYj6|S8C~pzhix1u=F!*&)^aGAu+qNt*o_1@lCjlVAdF(eB-HHVuCyR&Wod26 zq%L{XH0~r2d+3CuBv6J&lhhOfv>3((iWz84p<&ud>k!97lRzc}j6>rjK+?OCE!z_^ z8FxZ{Su-nXzx&;DzjN;Sc6YYXy{KejT22~*AQPRXj&k_BKs&~dh2O8q)m`xC_!`eL zwVaEhp|B#!et@cVA%KFIEFnm&GvHp5c^n;o>*Az`Qc~vRo!q_Rjoizh*>||!zCLr_ zlO?Z=_aC`B?kCeW-t|BwR*}ZGxBs?otL4qHvo;<}y|4M=3v6CWUE{3}UR>4qW!o#6 zPuCeY^!}yv-Tb+g$1dD`?$=AK?e)6el@kln3w9Q6$9Q@?Sv#OJc#pd?t%cq6 z*cW%Za+)ViEjf0eyZa>n&toT+SB|SJ%DRbEPu)Ce#rF2EW;RSArswtj=bg5b?>w}? zSMlPiPur14_C2fW^dI!T&Ua5vdALVFj^9W9SCokKv)5|wnNf9ho3-P{`7MIGa8pK4 zV>_`kcgnS~*Dmke5$T$hx$lkbSzEFf=cq*&N_KbXk5ucKxjm=%G`Y@Z|Dy3k`P7aT zr~kU{M^<~@63=tJ4VydCE@Ed^9XQk3_nskR%Kl$vyd|&Ce{$vnO;3%#zsBQkXqerS zQ~1Mk`)Bm^Y+%2f)GCG_IeKdE6FHvJ^)qhX^RwvcDZ6%^-@Y>MQvKeKH&mm0()Z{5 z;a0u>?UwALUu8TdPg~nE;dFg-*Ck(5!Af85!Gl+Pz0*Ujsn1$JY|dwzx9oJ!O}Xm5 z?y5u8^y|NGZ9C9c{RJYv`uh91-Q8K6W-s~l(8f%!=Tp@XYcNEkQGJxsD`BsJU>L@LlLnH+ zUbrjvPf|#Z5!Dlx6`I0_4r`K z?dMcU2?t=O$U#wwMh1sGasVt}Sg5LPRpo(_IuY_HS2yD89TH4OBkSWxj(|Q0d8lM7*vi30GRN#OI zTn8s9jKDFH@(?s@WLVntAWpG(f>SbE340X9Z_{bCQLVNlm?5M$veCvYe10 z9N}t#7_SpzC58ka7xV&n9qVtLfw+7dS5Y)0GB|ITLLQ6JED8Yc;iATcNzVTJ}|DYMRS=jmAp z$w+XN2{STg91|@xY&pP77-cj|CX%BhQA{}Lo9Gp3w+z%haM3|YcqRWqbrxuE1L_#nzlpqY>p8tD0p=BUR+5?SG z#l8PM(6azDPl*hV83~cYXpv$thNdhSMezb4Ny%v9&EF}#!3H1LJ*z>x&kppa)$q0M zO(YDtF+-OpV(^9!pC1g#2Z(ql=74-%+_nb17+ jbCds=IUPa%^(K;fZsyvuIcNW@4LXY#Id(t1@~Qs;UbE+r literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/meta.json b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/meta.json new file mode 100644 index 0000000000..06feadad57 --- /dev/null +++ b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/meta.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprites Created by Smugman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flame", + "delays": [ + [ + 0.2, + 0.1 + ] + ] + }, + { + "name": "icon" + }, + { + "name": "open" + }, + { + "name": "top" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-lit", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-lit", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/open.png b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/open.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c974dc13245d7213c1082521a384835f5d1857 GIT binary patch literal 4770 zcmeHLdsGu=79U{+8bm7!Qj0PMv?5M2lNXsO5rH5C2}D3d4p=5LlQ5DO$v^^iR|H>O zklik;buBGbi@I7}YhA624=g^acHPyLr55YqSS)H)RD9No`%QSC_MAPQUH>B|^Sa-i z-*@lt{_c13StO`*k-pHSQ7(t zB{l|TT&w|tT;G^=^F}wpKF=PFf78QbM)1j9xqDu}`8e+AmfVN_b&b+gcv9V?2$dJ= zxN`pE#XIxznB$gZWt&saHrBj>hMloK-~{K7V2!5+kg_-;>XsNOxvw(7B_V%w8zXWAn>46Ut|0k7QsC^;`V z>@u__-T%RBTut+2kGoYz*RyLD`##yfb;bRWm&+Cg{UiTiD+G;L&c?;*G;wi#`G72H zfBmj1u}L?6MQVEejDS_euNHo(`{3p#VRd~#W!}cU0og@p$@LH!o0ygpJhG*{BD!+E z_XK0^q@0m4cf60~+S0gp{X6Fh5d9KcNl3>b$AQkM+4;@u7e71>&Ht<_St9!0cZa?$ zz#}$e-l(LnE~H;P9vs!uqFS=#NaejnmmhWKG$oy*%TmLtv2S;;j$GZLKtAZ2Rk(hB z*ow!suG1flcqin5sNts*2X5|ee0$}ZoM|z^(*n<^WUX}N@$A%tPuRQzRmdi3lCA=u9MMu-eT)>a2yfIvoQ;8LXK}=SZG5 zEK-W&Qkg;~S11%Xt{8C2Wb6(gIUW^5MN*}EgrnVk!q4-z-*{QPM{J3!!uABfuV#< z9)V&6I>_HjvxbuY=FPVc9Mx0wMAiZ3FL9fCdMceM?0M>WG_mexf?;=C5G2);f`cq( zXm^|dt7nMHCoM(>tRKCC?X$DLAO_T+r1S;_(1Ae$PBaR{pg@%fqoh#@j$%?$P7XzP zSPh($v@B;1J6gSBA z2*!X;k`(^Is5^8Uy41{BekUX++$5c`T5CH`5tdmIL>pn#Sh z8(5jaLND%L>3jJCvA)btugqTN6fitI$qVs2OxG}7FT}tLIS;FAn64LM;Dwxr)%Aa) zOE9okWGvtZo)hc@>z`(ZfL)}Qer|#qD&RMi6E;2z1(#QBi3=SNITdx=jk7RCJxAMcRGoEC0htLGkGnq<5^JN){d>~Q^3r{`w!qwnOV85#h-jVbvYb9wd9au>{!1`f#A#T)cC|K`inL# z>FqJoOrrX*okd~gs}qwnu|7AV#H{Y(SsUwBIwSKfmN6;X_>=f^ovt= z{IgTsR@)Th`TR3qYE%%_R{Pz3*BE1qHmj)Z-uIIiOi0M98ZkR8Hawu2-nX*w{Mr47 zOWJ6Eb>Z36(PN*79;^7Fx$74G`)Rd%y0NS6?d@3|-Wh+`u`hLLLIhtaO?--aS8QJS Fe*kdG!@~do literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/donkco.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..d13c017afc8919f6a5fe457015cffd2a7b5bb812 GIT binary patch literal 4513 zcmeHKeNYtV8DFu2ImEU^6bXjSVbl=!_Tz5vZnqp3@6bEso-r5<{#ogjh9oN*e2=wlr;NjTs`rBx37F`tBWHPBYVC z+Vn4WX1|{I+28X#zvuV9v+qvd>Xj*m3MY+Z_Vs(bmr~hIp0V~$jLn2UUmGwfg8@Q=c}%#wso3| z(FJY84?7YG^)K%{x8bGgYS0thyy;N!`OenG#KLpRXPTk*!Q;>5{xD;3oue)BdkrmT zd)z;Mz#qwHZvE}_lDvbxy&v#j%}&W)J};cEWhEai?AU#5L1@Pf&(;_I@xi%%+hys} zrIxgNhMp~|E?U@!JXxCh*?g__!u<(DySiTcO~!?}*OcPqE6IIFADLg?H~b2MOnY2* zI(;6ebF>~<#lG+Eak#sEbG8+i9?nVI(fGCcU-|YA95n7eoYqo(;N`US4MfwGEQ{lam&_aEo+nJ)l@C0oRR-=(wkMG5^YcF;3@;gZwxhMT|TLv7|i`9$2bDr(P3XXg5L7|slB{k&_?|Lb?&e)-Zv=}G^5)PGY*m^qN}(er`FvMx2= z{L076rmtIn@lj>kCvDH!I@b5kOn)!Y)ZVf8jikz}$f4rbMfdLhBdLWCzJGhyFMonO z9^8C@w!M0uS)H{h6Z~T1^vukJR`B7;t3y{e_x<6{$={wCOxn~L{%P^g=C44I*=uE} zuL^GwD<}aICn`KJMFSxyJOs&I77cMi9ner7)W|`Haj@f*5tT)UaUJa?ydfv3mEFx@ zP};n@OlYnX7}2;a&yX8sAwU3V92yPygDM+!7-P6BeAdml5skTMbq-^N*M~ZlFhDIP zi;2JrqH-f;%rl_5VNqgBTq{N(;G4r(t7#z?$0L!5DPlG$;ToJ|7zQUOoT4!3fvHVF zjf-MIHCu;>W4M4SgyoPXD?wDpy%7t*!MBsq{ zKJg1xD`hY3K~IB%bp0a(&P1wA?PL5$bnF-C`jI2!9-!q zFVqnB$9zNq2YwKMpeoFdyvtvcrE#+E%1s}Ml`}CB7;X&zF7MIWW6sda>t$Vv(4YtP zxEw}3UshBES!836z``*Su-P%mMlzU%qU{(1D0ty0Mj&`W5(HralqaZaTu=Zy6a+WP z5XUZB%%qj)G1^91F^j}=7;ocAOtSE1$;L~7vWgQRio-HgCFh@*l@29BD1iiwRTS+Q z&2cart4Lvt4Q6AuNSvLgNh>MPF(|zcY`)LqFj6LB+~V_dnxupSQ0j6}R3hs5P?;P6 zr5dNxM%v5_W42gn+HAAY1T*eb4#FywoQ_HoCbK;@A`0vZh{-|e$N{bf;GtkmY(Q@e z3(JAja=KC>a?B2^VVz;XX-c?EQTz_0o-L|FjtzU^gc3Q8b8#Ag(FlrW35q3|GQz@= z1WVHo6C_Ja@K;1xYWh#!`t(6_<4t$VDvaM0GsWjrDX5RX#b5n$Y%-x}Y+A6K5HCUH z8bQ2W5Gy_;)N;WZ0N0NZ!H(MHFA#%`5EzPLXea@AvDhgF<0%V`QD&OtC7Kd!WL!^U z=&B-V5iSh!Yaox1D=5$ySLl+F9zGOfZOlJX3-ks-$}ob$NK2W{6vJ95BmRFV&&t`Y zj9tJ4Qs6O*4Q9Yg5|5b)fusZih&D@HG-K)hm*tHsVzj(mTwf4Jo0*IMTf5^96IM`2 zOWX!mX1LJfV=Mg#Uoh7%^B9rYml*;@r-Dq1-zmDL=$aG*lX9L?*A!ioVqj9vQ|kJk z(PbFlD}o^W!HdA1;D+s83*as?kzcjah1BUA%6SKFXT#e)A@?IHf+XLopVN@N`_iE? zN%MFMlCC7&JKbR0cKNl%&=l~v^2;i^h3fPfhpOl7+OlVM`kCH-aCSKBnH&3${3$)? zxas`C(@Xnbea%I7Itzi*k>{ZdVvo7%CnG70@wdrtTH tPIw&q=+nh-^}1-oimoLiz-x$p1o0ofFS2EQAr1p0o`Th`_T|-E{smu4LM{LR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox-open.png b/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox-open.png new file mode 100644 index 0000000000000000000000000000000000000000..2e0163da82da2aaa3c2af52c82193e41a68f4a75 GIT binary patch literal 4344 zcmeHKe^3)=8eXdnG$M-juAJwM>lzCdH`z^=B)cVGN)U1y8WA<~no3 zO#2@@v)SGEd-i$X_xYaho9y%U{M=c}`AP_aW?Azr1>g$HXS@RZ2CA!XflF(3p+hR5 zgRox|TznY^OI3aj=0dy+fghA3esZV|UPtQj?u#NPL%Gz@cL#IUV2gS|r`l{;wlmE2kAMb6w+1B`N z>Yc>BhB?RahF<7n^#eWIH?Epnp*$XfHGzcR9KT`m31BUc?q95ZIVarEMmr$2k6zfm!JcFDlGj0?kG)*mYQ^Uo6o<3C#6 z*#Gbi#f@(o-!AV>Nj&~)>b&}SkM~RFtGUNkCN`I=yT7@<&urSYKP7SQ%(lcm)ZX3F zv!ObpD(#W$o0}3Z95`i6+dY3%&#q?dmG$d8ir*ybjC)>LKKDM=U+gRHfB4*qBZrgo z+H3yUmbGzc*WX_Kbgg3XC-)t(!`(H5S>N>>UA^~ZqqR2q;;^%5;k9jBAM#v6zaIMH z`2Lh_13!De;PSnV)AtUkKJ2~pSnk=c^#1amONUKgiE+tQ9hMCzmMpXhzk|-yw;Qf+ zyYgg%@TdNxCwFwl!Py(oJ}B}=T(c` zn(F*Qrg{@YvPf2@G9yF*0xu`gaL8Nc3s4~w66U4Ay&Tpca2O(OG9eC|9nKa+4kpxu z8bfnJe5Dr2RKgh|>!J!QE20$O$%J?$$xmrC!C+7w)Tss0t-(o>)L>eTR*M1z8mRI~ zbO`kY7RwY74ht7xMBXp)f)AECX{S&jnGghw!=v?i{WjYey)O_|0qCI#(S8lC#x!29 zCiabhlv4>vq6K~L8-YTwOf>~uK&TKIE~k?7NsD7Ca;-M|7=zrBoA>&|O#$&HBx9K| zoWDXW3u9PD!y1>PrC>mL84Ba(4vHs#ZjkD>p~ftb#XYMXE2h9p?F;6fh*~<*s5eIR;DtLP8@gQ zD5ldIK{Ygql3Feul;onF=~~vQ#mF#~JP(xFZZ#oVH8vixm(h|-5WT?aypI)vf$^b2 z-pj3#XjwMgK#-)?pd)ajUT@S9c7U|B>{P%Uj)QKfY>}fSK`a!6G7}SX!bjw8VjIm^Pil^b}4M zYB4H3og(lwOiN)gc!A|zRsRnyFCRD~GU<7I0OYRPTP)y%X5NNT6DRVT}yQ z83=7e)iL&f;F5y0$eG#z=-}qRndL9b>fH z49)-Okr4*OY%$=yNDORUU?4(LueKV9kN=?g^pIHH2MBRr4PQieKn?3Bx4;N zgUgb3jwFDizGj4T+`M60ciQ3Ms#-_tMzA|6wa**7@b+%;r*H2|xLLg5Rsj0odSCxO z#rY*muI%ZnzFlWtx$2o(a9rvBy&>W2k$a6>=D(k+ZW;W0r(2Pf`IMqPYis-y`L|QI z72N}&gUjBmjyG-{Ie&I=I8CMO-2!|5of<93JPleHpGn?+^fk~51X*+PEyo@!-Tq%U Cb1L=# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox.png b/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox.png new file mode 100644 index 0000000000000000000000000000000000000000..c7a5e3adc814288b3486d611774706d6a4d744c7 GIT binary patch literal 4657 zcmeHKeNYtV8DEfq!H+1?h*f9Sm8ul?_T%o@y^{ll<4ZigM1n&Z-P?T+SGW)E7Vd|2qN6gSKNhyDnH%u0yYr@=caU(ruft%?`O5!z6oya zLw^;zB=Eae=k2JpNvej-==iAV%@qOOU-0*qUB9$+W!9;(!5Xgq$>)vjx*E&1tYbf# zySb(8>PoD58f!7scBa15=6^0VbgQ!Soq1X9oxd%tj_iK4ap9%B%da4a*U!c1=#+%$ z=#hG06$f5>Qy1T|dQsb^^?$&Aux7@Na-a8-3RCBvOKZb2SD3eFEMBJ=oU>mQ9HQ7= zmfPH1*>?2xo$uGpt}8;D~G8 zCp{UhXF`4YIb>8hY0oZv{7c7QxYC?o>{_>VH>+Ry^0iD0pFyYJ5%1I=-uf0H zWM{C}{EQ15{?@eoXB>GPfA?gPBPf3*RvN5tuQg5sndO&{zG=i_o=`6h?fEQuZ{o5p z-yls-YN`Ln4__Z@?z429{j~b+z+GMki4%jAuTNoVY{!YymFC8L?}6WyhW_#1@lQ*y zCSS?L@mGENEz{%*RhU)4S8ex~c}?en`h&wiorN@fs(%-$eEePtTfX?d$z!3kC)P`J!C zC_DrSk965MJ{L%+5#)##9oE-)8bd`vhrOaUkOo^c*doRk*}?jvq;$S0m)8hbWQ2dX zOA7(aK;lrBInUzIx^$QuR|}tIGl8LQ7b#bVWg1e@XsaEdDuqfx;xR6Qsj%8}2uh>T5F|~|G!8v*$2N<^xp0ePsSM%4&;ti= z7j2SgwV*O4XS5bbIt+v3=tzEMo53&&Z*dH>0Qn$XoQh-RC+C`jIfU;;ntXDhJhxqSql0C~U+ zK^-tZYJ$Hcn#RbQkefW>E@ylqFx)8q1n-gB-OkXI(=aTjR*!>9us9^n!UGu!f-6LbqvimkQLz+G z0+k6@X=oNVQY4KFDwUC8SS4?w$3rCBMW{+HZ+uoVlmMXsM^Y4}q;QTEG`NZcJkC-; zi8C|}NK(xRN=|TRBlkhOCM7|K(F$_Rl9Inzfj#!NC;*562M8 zGsJJn2 z;BqlCIIGl{a2_a?wA#e6yueLN_kS#JOc5jHg%k3IIMU2;;y>E$aTvFQLRvgFxHH3z zo*3Qfhxvl7c%HvunLW=CC^{8nQv6QQHAUB?7?_mvl)9$qniK<*a-LGx|BWvHv9ltu zzz;kpJPE#Uty%(4k-o;nI6YE=3?U^8w>P2C@}ez%qXR)^%#$xKWd8wp4n_Q=1VfD9 z1Mh(O!E=Xxni&aAg9-XI>6tBGR(+V%Le42Uot70<9y{|;v~N(u!yAvMVI*9{*8%> zC=-sHjBo62-T&vR_Uw}nZrq%?FLGI2^~bx;Za}g=yI*TpI~CU+Z*f= z7jiGzvu#E7Lr=UL4l-9F9$yV#{M5JT_^rc_Qi?N{H2EFf%in4Zs?{OK=CDl9&ZlB_ zZw>PHCa-$LReS1)?IZ8$XKp{O*>^MUH@$afNg(oK-1*|LEZ6#ag7^OYLB{OW m#&?_Y&ZpXAQUmX8`lm0^;fktR{PhQr2qYmUNnaPWx$NJfD3k60 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox1.png b/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox1.png new file mode 100644 index 0000000000000000000000000000000000000000..c405eefdc13000b3aee7b92f8f93b2aaef042dd0 GIT binary patch literal 4228 zcmeHKYj6`)7+tBf*hr9~5)pJ+Dj>Mo-DH#Ou8E~IeMCr&eLxYgY<6$bwMjO~Zkx1> z2tH7psz?Q)b_5l%Fv2Jg!BMADWKcnehZZch)FLWA22f|zLBzXBpCdC)XY^k)lkDzy z&pqGwoqO(`>b!k=?H?1bQL&@;1$)rBU0h7Qd|2gytLGol&M903=KzRpA-P7 zS`!8+h)X^MiMItk^E39LBmVsMddI_dIzIl`iFF+t4iKrUR=AHxhPTce{oVTCbho5D zI&9TgeAjd0%4w?`hBu54`e$$dMW6oB&ztqH&6wl8^NV6Ua=GcW)S16yYI)tSH??rO z(w6dv>bk%!6P}9eUKy7++qlR;U!F6q^!Xpgw!Y|Vk`0;M?gtN!eW7E`PZK78U)NZ- z?(>^F-!zAJY%omH)w~^f%VOAfDD`K#Fs)P9ws>B~-IqI7AjnmZNjW(lS58h(H?W7s z2cLBm?3*!ufBF1fSZVg1PcULr*P`dAb(L)?yIS|^*27yK`RLX1!y6~MB9ZGC==4kO zm@{EPV^vl7hO76Ex-PcYbtL!hKg)|MMxWjr$?9ld{N;No?>?1YT(@oNhNev~K6&8L zK&bS5^UG-|hL%hWGw*cPQYptTRE-){ey+uS@Y0v-Un&3e=4;Q7_~716XD44sz3}6v z&5@2N`t7Txj#)qEp0jFpSN^tH`sRqS?Z-3gvK{peQ}h|S{rWZB+STe~@#ReB^l4`n z@6aD?+|5j1J+897zL{J(cka;zud&OSH7jRi49on?lQ(>F%g!wu4FyM*9NM4tz{UEn zSAAHTI_bc$EgrOO$@#3`+qd4k_G!ko%y9UUciye1mp(MMq80z);)(4IQ$JG1nw`5WX<&TifH z%&{~yXCZzHNqhW#=d;_7FYIVP`Nhd*|9zJ(A(u}@Pnq9Yb`09CT7vc}bI;}kIcVfX z*$a&EU>N!iLF`%aFfUXB74-tY6mnqa-f6~ANpxUyEpE~s&H)utL2VQi*A|utwUq)Z zVp(^k+v6N02m+Ny!yHD4y-~|!yG}xVliXPY?PyZf?`>gAWekHghK?b)Pz(%j)#;<8by-B z2^1kJg;hxop&BRem8(<-hQV>Pr@mm=?e3)yDcveSJ%~6TCMY9G1cOBX8H$=)4N1BS zy5bC_1nyFz2q@yl4z%YAuwGp{{VDP?+GwOx!s&o7OJ$QE~f+2>g7aPkVGzV z>-ABzND5xu>g9QyHZcs&vQ`EMtUw8rjbY5RuOF2wq^NvI02&n}H%gGlYGFw)>mzZK z$XamP%+ok)wNSVfP^4%heLS$S{V48A1&H^6ocDB=-#VW7KM%ieV zHQCG-6T`9;OZ9=~fT#j3r?FC`(VWaB3S1uKAnyl6IOI=E(H4e-?LcXH&8d(% z5r^GyIZ?o?aj4@2VO kuKO1s`nVpXAiuW_XJ)0=7dCCa5za+ixrNScGZ#JlH_W}|yZ`_I literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox2.png b/Resources/Textures/Objects/Tools/Lighters/gorlex.rsi/matchbox2.png new file mode 100644 index 0000000000000000000000000000000000000000..4de5da1a84c2c929c86a77137f18f9496d1e80f9 GIT binary patch literal 4239 zcmeHKYj6`)6kc0tA!ra<$NGY0L0ZAhZZ^+d6KdP^5j7Y}3+36~?A{~`NjA-Ho3tw8 z15^eOMG=__)gme*)q#QvI;8~$9nk?))IwY3p@Sli(eXj8dN=6{b;jw8{%dA7yZ7Ah ze&?L;oO@^Yard;st2H-hFbuoeS>z~2cU--Or=Wkiw)RJKYppFQQ;I(}LzVzJDvXdk=oN>g>i{Z9k3uq6576d|HEk z`z6daE#=(W^ppE?JI>YlQr}+o9C@m9gLY49+kx5Xoxhwuh+$VO74!1k&b++dY)}q$ z_djVb+Iz=M`^)FM=hanJg|EG`Wz;p%7U$voJAW%L_K!Z+RmPSF2}xReWrHI$o<;2+`4C!rLkq!iBl$@ zzIVI!gSt1ZQ=YkDQTv)^diAVXN9MiEF0-y(eaD!jiJ!O&hD~a1+OjF5=b^5whR_B8mhq^tp$DLgAz;*tku4dg;S6 zTX#J1aVnlSpX|g^AKl}4a@%L~JKB$Zaje-lr@I^bqchTJ*!|$gsO_pn)Lvz-yE$G8 z>VP15pe_~+qrSs1TXrlA_(f2`J*tAc4C&vMZ3az&@UF%M&OLvX(fE^ zBAyk9?5P@Cj6(!Lr~o_`41{DZW+&pj9C}vG6oJPf$|5^a=5phCQUu~gol!@V`7yDY zA*O0@TSV}3#g2j=3N*44enkm$6cvp|by0&(iufo!%d!;BPz*yN1S!{q6c8gr@&uJ4 z!Qp^19}&ZfD1~s96L_R5#ZC}t9`B7W7G}3X!6k30aVVAtbh;?RVqZT6A=$EdRea* zdPv4<1f-GH8%Wk_0i;I{c!t+oy?UcCfa0Erh`JI421cb)35d#S@i08?HIN2iX4Pm| z5*QE_&l_2b0eDyw1aT_04qT4gX(t#R-EVORfZ~-RLDcGENRXm(|5S+>gfkSN%BHs% zS(dRF%vQ6BHZbOX&`cPSQOl{UdRk{lWG?Vr0pbLxb;Ka>K`I>b#h0js;ZQnATA+3+ zVvgHUHe6l=0!50HNK(K~sL|poW#6<5Z72aKzyTD9ywQw_qs^S&Si;bp$;{D~DKx{; z1Mrd{dTag-t!^LOmMD6WC?o$haZ_SX&487OQDPVn?6Txlq96iu zd`L&66>8A9R(MuV4R4LB))!6G57h!8$w(UU_DN2{|hr=)BzUy(7ap(1_7L(^$ZK?{~#FehVu{noB>*PYA1 tx^L3Bz2DYEy(iSK}ue_VQX#=~-Hc7kN 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_burnt.png b/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_burnt.png new file mode 100644 index 0000000000000000000000000000000000000000..6ad8d07b4f824d210dd85b7a23b3743893fddd71 GIT binary patch literal 4273 zcmeHKeQ*@z9o_)>Xq;#WAqkeix-c5Rz5TeoFmKq25LMogqwv{X~*P#GU;&*PDqt&$H7I>|FCWL~jFXxA zUvB1ZcYp7*&+qqp-sgSi-iQ5*=B1_HoeDuvn%Cnl0aw`grX+!1t*PlcxV+X>R<4(@ z5m-@WQK}PQy-^WhAu5Rw6#X#dcV=|MDTn)8XFC(p3O7=H3s=AW&+H9+;Jx~)mindB zuXNs+K=tl4&d=jFc4SLfH>*YqZOb?R5@-QVoa zI=yN999MbJnRoNQZ{#h1{rr-xhw$xqk+OSz%eRNr3Cp`yl;0>^*Zj<)9_^z;zdg_w zI(^=`Cif1JbAO$*|603$-c$E(s{VWd8sv&ntiL?|3Z3g&@!^b$@kg6Gav>;Tz2tKF zy)M^aH=u`I&20`(_pc@&TTy!Ku9<7IGFKh5@xsAU(>sh^Ki$x zgZiod9_P|WGB0Wuz3VKVo5$;WKP@=f2Efw$h9}Yg`YTdWw z$hK7#7Y-k*K$lf~*>Q72%dQu;Ut~@$>Dj;Do{@gfp4N;v_owfDVA?VF_OJI$`F{Kx zo$zA|yE1aJTiJS8YJMZa^FIR zlS3Akmji+&8d8AmAgFLoRAIT5f({3SpcHl>*Z%ej0!zFDS!VO$KE)-}N}eWFC~aC) z#x{Pf=JxCM<}$K?v*9;wk2Nef}W^qotq}Qp~1+c(*0vxgnfVuhy9u zp2LJXAp}S@P#j52+(m<-ms>#VNNip0J%j1JVb!v zcwD4W!p4y(Wy{A=J6FJ>JSFDatTf4rlr@fGu_^&qvUTxQ8B{!=;_Vb}4Nw7;U|9~O zXo5p&mJ?B{EuXWAA_d5JlggL}#_9Ju5YmDVNBniHF3M^MSX~P9azq;*Dw9G&sm>a* z5d~J7CJ8G^S_|j`D>V#SDySN;oWV-q7OUMH;W=h5;ADYyq!1evFeMx`2aJhfKs!KM z)^I9dHshch#-$3ZE~{m-T<1WHYGH$NXxIl96wm6co7Dx74JU03PBH{thT{xrXDD(O zPB3^JUgjmS@u$$n@_`FulkSl;kiXFk#nx1*uqyTxd#sbp#RS9VvS3&))`G@12r-QT zS8Rx@Wy3)M>>mS$9gIsqVg?Rp2?{50l+PD_CpuF0Yv zVO7By1Udq(fI&^I;Jkr3oMEaqgpbq;#smS$P@F{LBtx))W-(*O80@wX`+**XCLnH$ z0q@0PVCw=qAvUxX4(J7P|D2zJdH6X~!0>325$QWB*Qi`0QeZ^jQFo2XH6jH@1RizQ z|4pvc;lq>=2LFH};HcC=ecua?SxJEf^V|>xA<*=FdGCQkJ@gC3Q=vi79TSXi0@S`M z2LzLKudg_{Z%jt^bV`(OU*TboxT+g83fvEat)og1F6oIerLpg*knJUyLb*&KiJeu7AQZtORI?@j(7 gVUT8S!e1fiPmkX@apT!7-5?X>EnejADymugKg<99SO5S3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_lit.png b/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_lit.png new file mode 100644 index 0000000000000000000000000000000000000000..fc9082ef63d6ccf3176037a160f5ea7c88088176 GIT binary patch literal 4809 zcmeHLdsGuw8Xw+BMFCkJYIO{*McqkeCX>fR!ZQeIjYdQTmEvS(5~k*5GLnF{RkT&n z7NKfAtfITRXjzuUXKkgn3NA&fyY22)Q4#TRq_v8>xT`H%_f7%`r#)wn=hXkmIg>kc zzi)ou_x--#y(c&8^)oX-{5EQD-)MSA%S-64&!FLU}^a>c7inDY0EXoDj9X2Cp zW?{a_&cdvlGeVI2qD4P@L?ayh_*Ue!65lCfo9prpjQQ@N-yd|B?#G5-kuSEP99~;{0VyZG%=lt`#@MTyYLDNu2Ny)PY7cH6{lJwtKCruU>z4P*8`5&> zO8)XfykfU|T|?X4_r*oubM_Xc!OV2<=;m<^t=9UZp^e|%M=LmS;M8J>9uKTef5AU zw!dDk&TLE`dn$j$m4fAuHVkvW-8j*@JNsT_09GH|~_C;=jAc{TSZ76Mlb2T|^8S zrC$}&@~_oTPIOt%KDxj8w~_07cSw#r#sc{}zVB38-W-3a@VfuKB)|C!&g6gK=iIsH z{DK9Y!JX}a;<|;E4MB_ULXERNW-{Nsv3K%~?$3H+U!M~d(-2U6{_>T|9_8!MSO56u zzeDZz;EmDo%iFHEwcYvT@$%}{_K|;edXw8sA!u-OffbCD|TD# zKzI<8kmR;g^b(eb4XlZ?szqJLJ{7?nqZZAV=}?_LjV<6ZiyiEo;+ffW@e-P3L`jJu z32qetu&_J@yDes`Q{`5RJh&=wFHB2Bu*Zd8q88=o^l+NZ!NP=?5Ti)Cn=8aci6L-; zgE6YIG}C(_z>`{3!1H#MMB;L}#4f4W<}gVxk|ZT4F2QjGcp%OqD^Ix*t20i3@M36K zC+*W`kua$zq+hWe%E6FJ!HJ+(3v7txn&MAe3a{EOt*(fV@G$7`orjzRY3v_%O7D zHM14~>IC^=gZz2U_>`wA6eNQXBq5j4n2{w6iUCkstCOd!G%G*>a4`pPl$cD0 z;y8mSNP`?97@R~%T%kl1EQ87kMxnrH`2dJn4i2c2G7rp3fMNg?Nivv`#%KfpDiK17 z5eP*}NraY>D63QuawTT)KnZ8vALX2P1&42Max#7gW|lgA)5Mg__N z)KY>{0kUTvRHI6BuoQ1|WZP_JwMfVo79ji0Ioen3L~>oRE6Ox zTs9TOROkSI8^alk{-3w7eBcCc(=$0Ih+pKH@~){l>{9QO_tDIG784A6mW7Ia`x!BS#El+2)F_Q^>78p_x5n|;A~t4tk57p8G_=7momVej1Wnle|b`x!HrT( zhA2=92$VJu2+5EHB2~zwM#{*ra=C19y1ztu9!2z(mmm=~#J*-GNPg08ufu>H6wuh2E3@Yr0)~fzJQKe|bPdtMgUB4Jz zAy3bWtQGvgbAglKLG#gb;1n5XcqKyvO%e{2AD*Nxfnk_EGuH`0FN_i{AE6OL$zfYX@p@Hcdg=bGJu#&dqc7y%Y;JjTN1ogG>HCm;w{&M+s0#~4z9Ex-SO#>k8`hfEbqyQ zQ?D)Akvw{XIe*H9VH3l{sssP%DjQ#R$+dPAO#8MxehE$}YySFF@E5mQ_6Jq@zmfm) ziY;sNA61E`&q(d~;qBW|F^7?=nuQm&V6@7|+}(NA6u$4yXJgvuCN-X!y7=%OBr#*f z{D9i|uUsA}De%3qt}9~KhVZ1@NtFsnhZHt6eXDnAE<+$MLZHlPKuwUxVy*Ctm#Sd#E^|{+3^- kZ~vD%`Nsw!tfuVyAgE@?nZ5Qzwa`#)`bf)0B0pLE(EC2ui literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_unlit.png b/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/match_unlit.png new file mode 100644 index 0000000000000000000000000000000000000000..03cf76dc9509e0a43da82897214b7568f09146b5 GIT binary patch literal 4306 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/unlit-inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/gorlexmatch.rsi/unlit-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..93f169c701e3f8a0269d15d4a968ddb32d56c567 GIT binary patch literal 4273 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left-lit.png b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..933b7799c6d5cabef2810af1b60af0820ce852e9 GIT binary patch literal 5397 zcmeHLdsGzH8DDG!f}#cx4H{WT(Rl3a&U1HWWFsq!K$67`Y=TsCbRKtLBD=Hf4(x(8 z5mPi&Ll4rt6cdvpmXowMK-fZBDelil*YJy|cU%PgBoP{{nV) zneTr0cfa3vf8V#4sdnXL#>OPY7z~Ek>?}tv{7loY=t%hfu2OOue(b7n&((7IpwZ`7 zWu+JxwQ?UYf{-E`458y5*Sry}#^{^p5*9x&)SWuwR9W4QmI*IBRrIB0UF%;dH?1={N>tF z!8z;Xqj|)Xxa6gKrloQ5bitmCl}YoX#khIeUt(2-ne8TwaXHV_edum2n(KBy6cdga%^aran z#Ps(o?+IEM=H=i&Gj)w^@Y9C-HN=gS{YO&|Z1 z`{gTD^#@|kp@*K^dg%D|cJuJW4__I6OsSbznKHR{S@grDZdX;tlBd_#3W&3_WaO>J zvvX>nn36wq)%anJ_Nw;pT5h!ko8*#;&z&)QDo>9&@t?6#L$;;8$DjCm??nfX{uYKVgX9-#5Ykf+!i;6gSejLX5lb+Z{UhF!EpHe{~TWlUH7z(|=W z6NYAllrjQ&EXJ7Xmt-#2F}oWA-r0~MP4jVPb1)b*1xb_YFEryU%bGF5Ob{saKm+Ao zjSr#Tz$6`_3&Q~dqF?c8it07$n7p8tYBmIc>Umh>mQP)$bDHJFh?Kxfjf-z z_AB%xEsPDloKDW6ilutA*^VA9NUEqvTyHQOX`uiR1sY`-D~S?TNoam++A;SovXWBcFJW;x0-9V0oci&L++>UXPZu?^8_8}-@ZB#|b0?i6m5v5s@K`F|@K#9r#1u`QLRx8T_{(I;F zRn~&MAJ_|F)?uz-VTW^Ne6(8((*{NpECTvYV+4-k1d6k6+{$4zN3e+b-qT}fL1smY zLM^yOLajIjPywnDWhIGbWQ@T9pazEfJ$iQiE5qpOX*xy%cJd!(3bh8A61q4@hNJ1} zP%BVt_kk}C1c{Ld2_;#HLMf|6q6~pckgtr<1cOoZUE59?#UM$_4eN-qz}NktC-IB` zDA-0xjMaM}DWU=pt*9&!KoWq3w2<`w+|K`BtzGnJH->Q}%~8btpl2biI7TxP{BDp* zNDr0_OEDPAGbF%BmLx>$-KE#pzk2AUn)PEuPwPoF|DZW_IrKYsz#{Il!Sf6}9+`X3 zN8Qz}pG5BAPj^$ihbutn!A0&Uzk}%-OxGP{;EtRJ)is!|JIcTvIS;DquB9uc?+FX= z!hc7C@cBt-p?3j%_7W*Pk?AnZ(tok-`yJ5opf9T+U@#1e*RKe}n)B^vS-oaIX5;h{VHqi^AEzQ219do?7F|LF1|Q!?c!CLbsJK4*}Uh^T>bQo$$!jK zuO7M8Vf)p%iQC_ds@u>RdcVQCM%z)3eij>^8GgGk?AXZm)d!b*JM3?FR&wvw{44R3 z;M1& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..2136e549954953272ab271edea30d593fd632fcd GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TS8 zr;B4q#hkad)@L;Z${hRnyur1*Bk`iijocTf99Cc5w|hqT#=O|j4J)=Q&gfwi>^^jA zV)LE^!IJ88-JfjkZ!7rs;~`J;ey$_N3^>tgrVFp@j(kj!k}KVRdIiJgpV2k%bq;^X zZv5D?J%3~TM*EIH#!FAP?ao^B=iA2n3fJP@68HY=3U6&|}W4#I!|2Ld7WAe$v2Bh9Xv!3Nusu>}z*Mqp^5Fw2uYU}AXI zr8AP|y*uB#-@V_x^E4~mlL~s9hL{ip>Fq3Z6v6Kt<9M(K{Cra_KL@|+7J8=ZMPe8Y z1U0W(22g!L0H7eEdJ!bj;B!CS=P;Vm+MG5fF*D&%`Gp4O{@SW>_ET@}n%lEkR0%gH~F+%f8DZd{O*M-~Jo;|csuwbL&-rpu<`YfoQE^9z1e(Oit;v4Rf#8 zAyeO5t(z@>zxI~Y_)y~V)V#FA{i&}NFVXA7)r!99vs<=g9dA9eNzQp}eae*;b;R~Z z243xP_44*@p>reqy!Y57Be~TJZL9%LnBa{)sCey|c!3V!-n&>Wc;)pY_qP z zk@wFE3E!NkdF8XKpKq)=GxFk#RRj6N9{ZN8x>PlyC1Kr|nh#&H3|^aYQ#I9_uPh$_ z#mmWg`*Ln?JpJ@D={x%7y!!i}{2`%FpCv2$gWb;@*uQ)KzGqMDX>Cn7Ix=_^9JsU> zLHeyyp}wZOo)l!wXAu=m0+xs`0ELGjS>qxBQJx2MR01WcKik~0{{u6sD%s{@#)Z2A zc2KGoE)0Sx3nzKxh4W-yF^?N-%8CdOzz1{@jrhv^At91&j^YaNw=rxrqfrxmUbcC< z%Z=K#AV6sgZNahph&rD%k2RrLLB%T+ImWj^z_V;~sjdeEt2G=BTf&q@3zk?3p69JN zX(dSvT413CeqD@U{!oSi5yNnRkQ`J4x~ln615=c=3O(CwhVy8 zyIf<;e9IjAdFK_{gBHbxRxX#|(BulkTc@L43yLPIiV$~3V0lSWYz)AFO;Iq8qiIaE z@e0P%GAnV4Oh^pf3DD^e>7ri-1|VF*qCzl6^fIL6B{72K0Y(Fw#W*h~V+sjKLZ)Qa zOR=3GCI?k0YO$=dZw8bCp>W>D;JD0U3Snb0nqx_fmv{mrNg8J;$p*ZfHwtB>QOI>W zv(2Oh?-+5HiMm${`e3D~enkt1I;K3T4@}WTBY1?3;(46sSc<1PiXl3Trh#AxD%L3ikJk=+b0BgWs5}oLXqFpP~f-X$~*=8y_Wn@l(OkwOrqXyuj(Q!yr zum^#t0|z|dIygyT1dfrEhoA+97ie}gP6>F7Q`}k$dNi#p+icKA4d3EmE?C%#sEctp zM!-pd;5;ND5H^9PM&m?hIOwG6UGRO@Mj4}7aCxYqLN%mo!3EKwSZz-M<*~EaX_*== zY7~u@ry$BP!Xa@!P@;Z9tk{%XD*8(R>||`=K~)sZD?BbS7*2~ejAmpClUSU_ zc+yL=oWzJS6O%$5J*0W{uowinB{1qRRjS&3DnuHEtQGyS?e4B<$qh z%M@x2G9?Xh(4;_fqoG!y*6sseN|Yp#1A1sZA5$P z$+CW{ImHY*?K@x*$Hw4(25yh6@%>R-b;DHL%U4@dyq8O$X!jy_72ob~b%*P&B5+s6 z-RkNN*Ih;6u8h0Y^@D}W)bWG`_~GA?FnoT}f0(-xK6~jQO)PLAdBz(*aMS@udIkz- zgb<|H0OLqNHda3j2a|QDD?j;SV*j*$qcPa3O*nS-_?jwHvjKB>W^iF=af^t@Enx_jx_M=!2@-f!v2M3PC1vCeb;{!zGVB>&<&mc+9sU3 z>Ffy!Hr+d^$4cAp-l^WzI>ejhhIood;gLS51y^U^?xbN)WUgGaJRQ~(B z=C9`eJ&$yEx-Yo<)AwBWHRnUA^Ys4P?8$H3;%2RovS*zmUiTp!-pX?1owSB>oFe1K z-)v6z{?>Ae3GB{)P_^f`?G-lej=SaoWqW4#IlS4|X!KZgA8XQg-jF2rKk9JL7PCaJ Wnpu`_@|YbM<_w;$elF{r5}E*f(WX2A literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/meta.json b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/meta.json new file mode 100644 index 0000000000..131fb44e54 --- /dev/null +++ b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/meta.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Banana sprites Taken from tgstation at https://github.com/tgstation/tgstation/commit/6be7633abca9f1a51cab1020500cf0776ce78e5c, modified by smugman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flame", + "delays": [ + [ + 0.2, + 0.1 + ] + ] + }, + { + "name": "icon" + }, + { + "name": "open" + }, + { + "name": "top" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-lit", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-lit", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/open.png b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/open.png new file mode 100644 index 0000000000000000000000000000000000000000..6cdfc629afcf14487a9841ced23ed9a928d74899 GIT binary patch literal 4989 zcmeHLdsGu=7LOi$L4yx`pmKB=RID<|%w&?xjD&{?l2n5c*n&lC=M|Wm7s)^Zd$fqw z^|4#4tkwtGLd%NV#iLNWYPEomT2{AR6x&^0EmgO&uF6q4;N&_9yKf~XxuB|l^ZtiaK&%fXL}fYzhq9`?GIb0wQoOccUH}T z>sAk{Niy6Y>?+-E$u6I!BCGCKo|)db7P%(QpLKTf!ncwDs_q`mrN(zqIVUSq{Hbu`X$!-!}LFNgYMvqIbKhWHK zialR{a$&}hjKmR7WVz!?M=$>9#IvbykHscMv|qh+^wgzU2|2HBd-MJY*)M8-Ey0Q( z?taX+&J21faupLa#d@RR3_Et$)qhQj`}}fJ!It(z@u!MX(ece;Yq@#am@D!te>2a$ zeq?@xRWL=yMeib7icf4<^xop-R~NZ6o3}AhJ9b5fhOMtqZ24^KX8C5{YO=g?!aqW& z_r`pcReJu-od;SQmW0RT%pAY>T!en$Tq8VaBz~jvgW!+_uc=e#eI&-;{(f@alb78M z*M48LksF|{d^aNg!Q>~mzllkif5=o%j_~cjwITNd@38L2B2ZVRc^=IvVy{A zcLCYSWU=u+7sD+TB#0HVMTZV<{j3&-L|zAHsLiO^r5AEUW1(9}D@;k}3YT&e568y^ z$NFdhU>76?^4V<;5AD;z0bClK`^`!i3b;s1b#SKH0_mM@0U{KH0!5O1Vm=PX1w*lJ z-b$w$=5#`UD;=C8NiJHc^m@GtuS(%`XDcy^qLe7E#Bl_8Af5t;#P|@0C&~}efng9l zoLh8BqSFESF&WmGC+T1qj6+@V*0?|%23}?}ZE$jV{zXj&9qf;n=AE3# z(}7c*VQ{Mor4WHpQ3xTBJVNm}gJ2q7!)rAfPQ&rNpiB;r#5g#?4+X##BEVrOl@{eu z6v2572OuyUVKG!dG**nESS`;Iq`DWxe76Wx$=G^F<%i+{6spBZHKwHyR;?Bg0w*bi z;y3~!teBO@IkkpGRRJh}9q2@hNeAN!w8vtxF_P8kwgah)4&LeY^bDnob|Fn-{Ip?O z6-A+1l%hzSP^risr&k5H2T0D3ilK_m5uT&x089o*N3=89g3{&44ovYEh6d>XY8k&$ z0dl|&vZ3{Efsvfmo_obOb`@k3!33NQt&YOLPx~` zR>u&R!#J`9aR2BOY?od92{8z2N`s?>7NH0Yh7cSM^rU7mgt79hN~6+{EXxI0=tlQA zt&*2<3yIl)N5B;jXn-qddS?w^?(6T(5&Q)Llp!dNU_?5qq6rPH*1*aapB_r8d6uOx zgr%%N>negp7=Z)bgW(uYVx&N*e%|!d=_pEL1g%#6KhjfUYJ$ReHG*3i&~;i;Ku9ft zAvlJ!jD{jWTjG7I@jq6tNAO+g#VY;x`!21x9S*%V2vGG78`yZjKBny6$U5Z! zl=dQDon7=Imw=%DMV^b_e!BYUdM*Z@%eh}&{d7GS1JC8$udbhsuHc?WVZi}@zk0!g z?$gMGFz}E(n4Oz!kj?hL(IX88U>W8zF7(J`Az(BlY=CTgX*e(rkxb^KA^#jWDr|Ce z$Xn}XgFixSCPQL+=J8u4m~r-k(W`5tx1lxD-u_(9K~cY`Vj`wpr2xV7jCi-l~24|QGEL87asEZv#)j6iw*Ebqt&Rm zHS*9W$xn8FLC<80d`&4adm3-F87lHC&NS7vHmuvN{1f!~wdzrA7g3xE9qy=X+BK$T z*_fIucPf`n$uD>sTJ&vI`QxTCGNJYO;JW39)SuR#{KLVG!|pv2lZR8`vD%{BX^r~O zM>`d=#MOB8CP@f+r$|q zum4!LYLdHo?ZX!D;ixOt{qr6V+Ie{58}OZN;ag`uv?UN9ubw^zX7^6}-JbV-gZ8Y7 rlsU3a-^)sz!K_&^a;*X0_FHAc2(SFYx~k=%6f#p%iec~UH;VraIIjKE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/honkco.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..c512c689ff820379882fc12a260eba6a2635e3f4 GIT binary patch literal 4487 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 YysdBHU#@@p$5_B!P?+DkbVKcb0KwFO)Bpeg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..24e9fd559fee87e64c265aeed77ff4a2a6c3acae GIT binary patch literal 4748 zcmeHLeNYo;9uDdi1wjiU_<7rSbM=Ewb~hW6tOVuT6oU~EsoKhB_f1&yNwSatejq9q zbmTy(qE@5`w$)aowxxK-o!VZtevDPrDrZH;M67&L9%GuUK>~e#elJ&y2;JT7%R7{)TpX)|yRA*L*Ow$PuvegRCDDTRNU< z4tPar%J#jV>Jzd@Q*B*cP(5!0az0U~dw=PjHsttQ=3VLw0bO~MMtQleez-i~oNM&S z@{E8dxq-zc?zv=bTJ%TjMsE%b8FKYf!MQ`b7N&(YM0M5B4NvYIKCa%n?9$@TgDNr@ z7CX5=LR7Lf@X@%=`E_w6t1pC}N$p${ewB-VGW6=&w}aOGynCxiA5!@H;L>NIr=sc`e9d){_050MRGbR|b@q-)vgUu78eM;!kN{?a>qe%o z?x4X$@7r=exqe~lH*t+kGMRky#^k*ZI(I#2T5-)a`{drxmVFb3ww!1v)#)lr(A$2} zjA8i^i~LR|tT(<{o$^kltNEh`*|WidRgZ2hD>~pF+kE>dlX~U!aH(&JnLSthXzkF8 zpS&I%5!mjknSI^6W=HJG1v^9QYKfs%l924D&TbAer`COO=gQGzN3UkKlrFb49nbuB zNAca1i_=Y({P zRxiBRII7Cxd*;CR+rRb=ZaMp(ZDC8Qkqh5n3>e{_S#B$ieCkJ{V{fH4-nu#YLt z>Bm|5KkZ?q3)&7JbXcD^O*`G;z3!0Xv(C=8(}>$*wmK=dTI}Ja;I$BziV+WlH>t&GS{)K?a{z>tkP-}yb#vK-IKl@Bcd!O3 zDJHIm0^X^`89Z;Nq*9m5C2`3lHiuD)t5hl}Mo0+)g$UG{W94Z#YIRN#D7raffRk}> zcAm3Y5rLD|+p>7ISPaLJ-ux_ft+tQe>g-Vg>LGR0b}25wq!x>`|1X?;Y&In6N$6L9 z;Y@*RRGI{wwk!t&VzYsjpVFTqUZd6ZF$g6YIg8y>6clg3WGvH%vu8QX9t_J!ff-mJ zsT1ah55V)B;e}WOauY^8<@8SkPS?jj0Nq==2MkeKEfr&9vV=)BF>0}pFU8szj-@=8 zNnL&?YGMq(8z|yFSAaOK|Vf9#;N};6X@_tkrtCOd#3=pUwxrBo}Dgz)$1yG<0 z(m9X0FB`|F2hk;$*NEi0}QIf zfecj;1i&!4f|b#%hf3%J6{*vx#e@WV5z(1x-e7ZBpw&4mYjZhY45e@ukj&G9Y`B8N zFkBXZjB*V z_YjjoTa5tjA3cWcjdQ!_GE515pdj@qsbVoyNiaAH&BUlMIZ!er@Tkzo?z9}41qy!UZaim zZW}VjYj}XZ@P-_|C|InCiA+g5cDMXs!Vo%SedUa*!X&&ZHhK#(y#8Tp^QV_TuJR9! z9QoBR#k*_JF~Pqp%DA%>8?~rBuFc11I(EW5RcC&Ds!ZIlW@bVA<@UUe_PqAIr7OMt z{r#U$I&phwDa+kk+;yK%sGp0Jh58wu(V4hh@$T}xVXZYa6UyursxKSIzj^cS5c~4X zA^H1jiww&OuYo1$kN??pKTxE)_)X)J`RCEGA?FfvzMGeS=wWn7+2_?>;cvB>w|pDU zkE%b_J~r;rJC(tqJ6HcaZ1O5m&a^WZCeImheN5U>6%!_tk`hgq6WR$PCUmQ2{tK$VvH#Lsm zd+CR}rX!nb-wQvxy;7BaYvj!!zx;>gmV@^;s#Rxq`1?5LJzi`QEjgelbo}k!wR@(J juC=A7Crz9<@t0v83&t@)HG5|W?GR~V6JtJ$N-y{?_=v*y literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left-lit.png b/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..b3ce960417a49713f90e21018ed235ce4db8e3c5 GIT binary patch literal 5140 zcmeHLeNYtV9bPmE0^&zaqSc!2oUwl3-hSWRE}#$&fw5;UaDuirWk23MHr(AFcPn>b z@GII>YlBpsh|*e$A8E7%9cd#bG?=u;5L1&HCqPWp644~qHacTFO6?C&s*vj_U1sFm=s{*^eA+Gi53-BLAw?e(`O ztp4)GinHvhn$-n0OM_z)8HNYjjP>t#m^sV{a4d{t_{~7O__e9_nGSU*Ph$6 zg#YgGu637ZyH>`1qI8da_u?qF!J(PJdyS<_D`0^S2roG(MRrAi7my9kBZ`y<)ack79 zEN5O;RzDlap{}aNG1LCUq@R6%V$IDtZ$EbM zV9ElJ3eLHurltc*sjzR$7X=543g4LD(n{0p=8Xk=uU`Aj)z+$yLmBOR=XC9xGP3LV z%Qa5t&T8ypGG21us<}T(ZeQ@Mdq#unCp$x@UbtGG0T!*i-t*M@m%^w0F zPpbCF?`^ogcI4?7$4{I);h&-18Rz16@5o-UsBTWv9%`hIq0IaFlbav%6gD+~+IjT# zqi4#xYM%DCzFGE{9UCsYPS1Y-_q^xHvJ1*q^O0YSD_C2bdF;{l$+M`@Z(jQO`SCS3 ziXU3(ZkspFT(Gos@%e4VQ>QeX&FO8s(owm-zD>*zj{9_H)vZ_KCzqd1?YZ&OoYq@a zqnjW1U)s|9S;eH@ap^^;TgKLVliqpht?h@CCU%|t_cqJY2K4>6PJbsMoVr!pka;7S z!5;1@Z0YHKK z1eP6E%PG^`L^LfRD}26vejfz9OE;D1x}V4KP$*;$(Pk~+#z~IjaDu`q3WE_?u)?Pc zVayktW>wxwRKKojKGeVzL~WU#ZZg4sv_C(u-{FYC`+|KcKt1rV;KxZbfqT99 z;1NMRyBvb_C3M#jK^H7hJRbzLWdR9fmjj+2+~%y&!9nD)X^qc-q1MAc-tyvsr13vN9qja)N>htRyLtBy&I% z2La~!g1X?7fB^`nFsl#@FcL{Hq6JeVj=&hJOkp<3!eSPMqivE+w2)SL5X9pF6`ES` z49?Afk|C5V1HjTOhmpX5A_0pDq@rM~M2I56*%Yf{jX)X8$Y(n9(oK|^7-(^N1YOYr zURWurPu4=gfi9Qo1qHfbh(}r(f*@&|g|brcG6=B{1cK191}aIIX2#lRe}uw_9PVsI=^P&`Gr;F%=h{}ckA z2gPf$s#JVkv{A-r8k`<_C|3>YTA(7*6s_$7P!_$5-g?wXQKM+2Jb6Ki5)KOGAiC}l zE7~QM2tGG}`&eJ$^tY>baTTSAEGJqejD;@37{+3Q7F7TS6q`s{tsDo0JJ5rgqKAY4 z$aF*1p;oZ4BU+&|`^+#aqFOAQPzf+rnxIIGq%e|mkyf5yd5SaP_nw}O6%|fm7|cRi zWXwu3028egi*d5d+7!Y@0>Ip!?j7_pjYkIR?B8@y3hv}z%M^MIGNoJ;$wERTf=$27vuC=(otHZgj6X_@zTY|h*oY1^W!JO` zyT`Dpl>LJ&*A}KYzUPZ4@n3geJ^bJ2;1Fb{r|$U=8!r5~s`;JT4tw>=+SAyvisR~; zz~4IeG=7OEy)w3K+6W^ML3$QZ^yk$?ch3FiuP)eH-_p46@OA&IIreV<^1n7Te|EU& mj~{!UUh$vmWCVF_)+P literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..be1974a6ad2dd63662787eb6be0f4f4835e71ec2 GIT binary patch literal 5254 zcmeHLeNYtV89&5`Ku91a(P(3L&ZI_gZ$EGEb^+z%5Qsf<;ZD$wZQYM|kCnUI<96i^ zTH;4Fsm3W`jMMlrv1p=cOcAY4BTlJkGA1ErOloMACe_pwNo$GGsnbDf-@W4wFwR(J zV*cW0cJKCmp7-}Yzvulu&+hF8*P_ylwCQOklPROT%uxZq3yfp(BzS&Zsr?jwooMhZ z(JS~c5)7%b;sc0Y9|Q=9D6+{EIp=phecuUW@?h_Sxoan6&pg>`Ih#>;qs8?{rg6c# z>+erl^WTAI&RbVEuW>go)9y=aU3Ne*cb=9vt?}+y{>wuhU$#y3Y`peZ&f^1vKWpkb z_KQ7BxkujZS${d(vnuIx`QrT_UYcw@`^jtVSuLp_W^8NBxtRU=jrG5IF6S*~Qvqne zHvi;Q$==`1emwPn`;}icm%WiRJvZs_)naUUzgndde+o=Q~nixwctX^tJ_PSS-fLz+a5AGK$Dg?xYL^-@>RAS z{^H#66URTP?P>n0zvG?Sx3_P+?CH+__}858N40;Kw^)uopXpw=weaL)UDM}~_rBBj z^Ut!H2bMpy%G)`Amc_lSX31wSEq`>z?(?OCo&9GUHnemK6AZTX;zofF!!`s{oq1G9-eMIuOujjf5yIce)Y?1|_fJ4@ODB0EA0e6bL5pye!Z>fs#0lqckD0C`$c?85$Aq9$> z_l=CrfRZ4TBmrQhtSm|Z)_?+5lqX~vwTieP;H+J?$+jqzv5j1zt32OKTJYf!myg$F zHROktq68#0tPPtyiXXUj-bfx{qj8*|>2qZUcz7C=lM zDo^qAUVsGy-l$4LMZ_T`qR*q!N*xjcG2$_;e*g);P z-HOr_O`&#ywxR;C%Q#O;j7=a%hkFaXLgSW!xZ+I*Az>%KBU7j~$dvSu1V^zPN#;P6 zKyiE;Bk6+m~o$t*Jd8}_3F(V zZdmc=TL^o(QQq2!@-E`NqxC<}xJPoaJ4f^<4I8KxK%$aprBPZIB-D=E;AXNEYol0J zU_~Mpj!zi^js_P;&cp5yNo?|nX9$QA8-vd#@KFa#JnIZa3e$QwKSK@fZZ3f!*kzbyd)_}3x~--Q&VWS)fYQ6>osOC2V{ zRBQTMD!Kiia3nQYwp25j(x(_ll4;wHX>c$_FL#!t^i6m$DSeW=7CaA!+~tl!PvqR? zvq!RyA(_bqPqy4slx^N4r?G!J&pvzQx7%}GsMstsaks*>sqy9 tqA?0T56ryz9q;}tRZYQNdGNhr_dUf+&5!)YF?+LNEH7E)Xf0a4_J6S;9v%Py literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right-lit.png b/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..d1fb5e1cbd8b4f958b565dee9d038949e56a155e GIT binary patch literal 5137 zcmeHLeQ*@z9ln4iArK%4LZRS#RKAkE{l5Jm2MM_lZo-i>IRZKq+1q{hvgGdea<}9z zu>nL|6SN~SSW%c#ib5+41Pay$1qpE^pdFxyHGB!!LTrIiQfNV>@7^VsM44Kq;$PXB zy}fd+c;DD!Qa=_^3(9LzsfyNFA^h2 zFr+D}43F(~{bf*7%Fz1%Iv@D}H=#_@W8Vy|cLL!SUDU zPk!SMO3kdD<>zV+Y`K;+c0%&y`u2x@eS~`~ow_nke5mk=*7UE=-gq?qsRPaXOs1se zYHqH}k(=8|2a;G@UFV!=e`Ms(9~@ElW#;?Scf2{k*O0U0*hXE1SIWfAtG+1SF}I|7M&lleV(OnO-gLG7S6BB`pNV82+LU=>^XR@O zTHdU4xz;_8UQEME?^`zYv9v=4&v++naQ|doQc3Fv zDcFGLee%&2*Prft{Ppw^Q}4eVc`f^F@@s4Imdsh3*|3r98=y(c7U6LHa9>HouFqPV z_BWj>KT-En|DFTo@2**K$$fnChrbhi3(EhdylC0|?2zK8U(R{&$A?BuA_pF5t2vim zcXQ$JrQUth##xHzm(4r3df}MS8$QXuweQNuRkiE)d5XeAK3i9P`|adW6`xGGaP#r} zJ-4d|?kWtnt-AI1%8|E**ybK@9K7B?;7{8QzVgQbBTgLte6@A{2IRwo$A|WhPI*yV zk#jSRMjyCP(s<$1vA-cVx0U^6+OpHH%GjK?-P=Qf+j}N`a3%R?J40LB+ZU}jnTBjp zp}FQcX9<$#w}`Ul0hXvg2wi6~Wlf6)MX3zvhzEGpfX#em_g*ui$~N;{#)&(Fxu8^? zSrr1sRkPhvRhh)g=4n$?v!Vh7@B>{$qJCc>EJSVQ7_I>S8_k#*iG}E8HuF5E3(3_& z0HH0k1xNFuY6WSYnu=tFWJM^l&**@FcQ$jWt_KASi$o%p2xZYiUX0**9>YnDBvBZF zhARWQ7)1l&aRx*j!w$kyNDb<$7C;P4(W5QaZDup_NK2c6CYd?4JR0@MSGib0I9 z;F#Z!bsrJd^C}=nM?!ZT5q85G#fm^!TO5)=UIhr~T;`oP^^oFcmzx1I6-j?gKDBL3kJNgjxH5*HJ=u8YBI2ysaTh>asp%uwHJ*VfRo1BAyFYW1VkO!;R)x# zNeU%!l%(7QEik-5TQhJ#sK<)aC{HT1mGdy7#Kf(T zKo4t*9uY$z#|u@5TEW7OX@yMeFvFyt*+fc#vC=q6pah8$yqjR50R@URWA~mO3q)KY zSPr$4B8gHW&7r)k5U6P7IAEnDMpCRj)BPH~9OIFJxH>l-goHc!w=#uZgG@;`NeDD4 z&|C&|3G~|cz}LzskRQjPxCE)vI1f;cB^XpR==NZSE|0gt2R?j%z!EPI9rlMyaW9XKUE^L(fgrt;+?Bq)a`nn}R|?!!aId?1 z<+>{c?kc#~UEi5psa>BSKmfk4N8kqr^H9fN_;I42ry$>MB249`^Zm&+|9~z1gEJou zn@j`lH_jx}D{Du>#$?^$%u8^bge>!sH1X-(M!f8eUOt=uvF z;H*_bW>e|Fq$gI7ACo$CdXD$<+t>6LF4b>dnhwWg+naZu{{2e}o;g+j{@x!paoE3) zm;xVNRU5NTFUUN*CO`Acmv0UEfmS mueb90oza`or;<&k$yI&&Hgg}P1eUZJv5vgi_N~(wF8>eCTL@7A literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/interdyne.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..606715232336d352a8764478a7c6122f3f8dfb84 GIT binary patch literal 5076 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-1.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-1.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-1.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-1.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-10.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-10.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-10.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-10.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-11.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-11.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-11.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-11.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-2.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-2.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-2.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-2.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-3.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-3.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-3.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-3.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-4.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-4.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-4.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-4.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-5.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-5.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-5.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-5.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-6.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-6.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-6.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-6.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-7.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-7.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-7.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-7.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-8.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-8.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-8.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-8.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-9.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-9.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_base-9.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_base-9.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_top.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_top.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/basic_icon_top.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/basic_icon_top.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/cheap_icon_base.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/cheap_icon_base.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/cheap_icon_base.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/cheap_icon_base.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/cheap_icon_top.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/cheap_icon_top.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/cheap_icon_top.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/cheap_icon_top.png diff --git a/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/discount_icon_base.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/discount_icon_base.png new file mode 100644 index 0000000000000000000000000000000000000000..43c9a0d692b39cc708c3bf06a79470cc12ba8aa1 GIT binary patch literal 4315 zcmeH~eNYtV9mf}6cuTPwP4ETDb}_9=_I7XYbyrS-JK!$%gdWsf1jc)AZ|~T6cf0H@ z+;N%sf=P#%OoEAH(`aZ-W6~rww=6+tg^P%T{nULx$UtTshr+;>9x#*C0-+%Adi#D}J#O@cv!|CBZN8OH7Bp6?U7h1_<}O`QSO2LcrOH|N>7m_jZ2cYE zkGFLV_|883^5OXW7v^ezmn;4I^0xjDN{?nO55HV%bM>EoZ{6$JuGH)A`0w25dT-6o zw%=Rwen<3f{<2r@toZP=^H@Rib-h@5@%$CjWhr6twvLC*(u#HV17-0&?brA1YVN|x zlUM)Qd9m%r?E1Hw_6pl~nq5b7FMO5Wm)_fV>yqZ;-L1%_sMOKg&~OO$T{RE;%W3~P z!wLZv@Ca^B6$yy2@em|yT|@-z7EVUpoR1Hhu)YsI!cg90!XDGvNxNv~DtK#D;)zM zi}2MHwl*2fl006+yA&4qW;1;T66NbTYbS%GsXt$5!gP~CupdUm8h=f{25`h3Q`H7I6 zR}CSf34QMqp%S=F2?rMvsw9@ntLB1o#$-f+&0aK4P)hRg0Wnq-G;hje9(G(OR!RPt z#={bvp9?@}2=mQ{Y;`{95yGK~p%Om870W=e zO>NMUI*pn%(nh^br#DQ9HgZx3wwyv$lPZldHsWEKe8>c_b@%}AafBH3#RimxVPHAX zTA*|)B*)^g8pbSfKo+DDLGYU}C0kTMjt|@6hVlRzSb)sI*+@#qkQ77dOGq`NQ!|ty z6JC&$^n!=?*8DHEvVG93kwv%iAvk|cEHtvGin+>>yOCQzAKOeQ8rv2OU`I*_fojeZ z%M-FjhS&-a^l|X~7;V_GIR8D(-~~YM*0C&3dz60CXh__xqgY&{;V7B~UO*eDsq~QG zmBT>da(vK7=oM_xm{;h^(KTE(RUfY4lm&v8;UtAmSVm*SXt9KHVvJRrMf{f^Suw$+ zBL+S<5`#wMqj1zO<JUqE5_s`PHrat6L;#kO zyt;oe3?|4ndtSngSxXVka$;}FD=_pcndZzZznySJ^z`%y_M!{n^$@cB%SF5 zDV?sQjjjh$(}b_c4r|830&(u8RMpM?mSzOQ2CJXBR-6dvXyK~Y8iohf|QS?Ey#xu@yD->#9ryS8!T9>_j7K&O_w4w6>E+{b b5S5tu$v@J&uSN^9VMd58Z-b>N*H!x;c{Lo3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/icon_map.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/icon_map.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/icon_map.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/icon_map.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/inhand-left-flame.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-left-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/inhand-left-flame.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-left-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/inhand-left.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/inhand-right-flame.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-right-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/inhand-right-flame.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-right-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/inhand-right.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/lighter_flame.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/lighter_flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/lighter_flame.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/lighter_flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/meta.json b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/meta.json similarity index 97% rename from Resources/Textures/Objects/Tools/lighters.rsi/meta.json rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/meta.json index dc7218c024..acda832cd7 100644 --- a/Resources/Textures/Objects/Tools/lighters.rsi/meta.json +++ b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/meta.json @@ -55,6 +55,9 @@ { "name": "basic_icon_base-11" }, + { + "name": "discount_icon_base" + }, { "name": "basic_icon_top" }, diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-left-flame.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-left-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-left-flame.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-left-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-left.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-left.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-right-flame.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-right-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-right-flame.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-right-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-right.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo-inhand-right.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo-inhand-right.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo_engraved_icon_base.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_engraved_icon_base.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo_engraved_icon_base.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_engraved_icon_base.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo_engraved_open.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_engraved_open.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo_engraved_open.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_engraved_open.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo_icon_base.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_icon_base.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo_icon_base.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_icon_base.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo_open.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_open.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo_open.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_open.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/zippo_top.png b/Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_top.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/zippo_top.png rename to Resources/Textures/Objects/Tools/Lighters/lighters.rsi/zippo_top.png diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/flame.png b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/flame.png new file mode 100644 index 0000000000000000000000000000000000000000..672b227a33aefd52a85500fa301c05ea4e7fc0cd GIT binary patch literal 4320 zcmeHKeRR{-6?bexQd3xz2Cd{ckg@0YVeoN9&R3IHW&=Uy&iWtxGn=HlsOdqUVvkhz@;q_s8Gsj z6^cnBFN8Trsf%$C7Z-SgA$}p^FB@?J%Dj7P^faUKkqN8zFZk8?j!xI{y$f!R+R^&r z0S{GlV_xF^MOWMQc&|4vub-v{h7HM~NYk9{6&tR!Bz`+-=cd!qHQ!kB*?~mS@UHT; zXHI&yPYkQODGZTgJ}n@4_$CZ++{0=J}nQUz8sU4!hm5Z{=s{S8i5j=Ni?O21DA@ zg3IOix?DZ^fGoB>+356~n2~dG;oN2z8Ie7@dbR(Bj@|J3J!^^&`Y)J&Nj1&CGtnk^ z%ID{#zrB1#?%KyQ#)K9;I6r;n$ELOgv2vwx)V(dEzuy**z59%MYl3>iu&a#z`Cq?j z3j7W~*YIl7n+I0c&&$lDvz%i$HN7;M7*-iye_&~6XJX8i%J=^HMb5-Mi}2RTquywW zRI;VfN1l>&;W$!e2br#=Uo6 zUG>yEpX@t5X=9aXUCyUJo3-+T&g1v~rnd0aOV0Vsr|Lf%bMcF@Cgaf=zm8tK{Knx+ zg=t-XXx()F=DhK(9h0wpemI*n-f5{{+kW`r8);jnwVvH*`PPQK+k*Kd{PB-UEYqjo5g0q zkm9&di^D}`s8C{gs@z?YqySG&c(J0yC=^vy)uIv>Q3|0}k|a?KM{yhh2t=-nDs&u) z%6S?^H;0>(8A*sKf*6G~PC6*oC{7p#eyAtDNX+N!rH{%<6@VUSoQ|PZ3x-A_XzB=A zDXs-1$$-9cgd70N6fNguu|{IJ;#w}M#KfEIFePZ>CP4npKqy_?}>*eo4F0>9-h57U1@v72#Q)MriTwtO77;d}v4kho5z)q$Gn_c~$Rg7sPaVOrruDFRwuh_a$8_qhT>gqy3- znrv1(LE1>tZo^5;PFQVypzm>#3|dZOwPF^+p?g?{Dgm4{XdNL!hd4AA4e1W8Fce4! zNK0#-3Yc{}$cA!B9Ic2_KorAHSc?|YD0|&Lu%K94q208?f!Q!TAIL~qZ2^p+a2$N6 zU{(rC!HcZG*ZnWFwtS$%?xK4H8O&d&o4VK3T&}wNsrxZ3=!*%0^kqTOOm_-0UCXh0 zoPev_#Vn?yAr9;x$%gH*3t!O;1)PIqS)K&N%Ln~L({_X=95fPiFkHTkC@8?}WPf&9 zyheRu~rwzNxpIyR^7;@hu`ysW-weED)3ph+HG ahjM?s|Dpc`od;hFO%l`{6u@(OS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..69bc5a430d69457ba74b254878a009181fac9fcb GIT binary patch literal 4450 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 CY|%0R literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-right-lit.png b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/inhand-right-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..764a11d2e7b7645a4edbf11bb5f10be6e521adbd GIT binary patch literal 4929 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 Dd_kvH literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/meta.json b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/meta.json new file mode 100644 index 0000000000..06feadad57 --- /dev/null +++ b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/meta.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprites Created by Smugman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "flame", + "delays": [ + [ + 0.2, + 0.1 + ] + ] + }, + { + "name": "icon" + }, + { + "name": "open" + }, + { + "name": "top" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-lit", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-lit", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/open.png b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/open.png new file mode 100644 index 0000000000000000000000000000000000000000..ba402299de9102f37b29b7c11bd2173d937734d3 GIT binary patch literal 4449 zcmeH~e^eCL6~`A)A-iBBB47X+hZ1RZc4vREyE9=?U_mx^ab2)tY8qx|-mVkaAM6h7 zf-(G(Ry0+Siq>M922CUyAyq+RQpo{hj`<nLVgii?t0zr^2U2BAQg#QN2g1@ff;(x*0nc}Q$&Pcft zhtqCm^8msXIRFAYtXUxNT(ugm1+^i8gO)AZa+-YPvsq(91UIy>*&`7-p~Wi7`KD&Fp#*IaSeuz?Cc(mW9S@Y4fd6>mtZ z&Lq{c4`hdeTED*8x^Y(2vDd0QI;us7d*6Lx_Whm=QJ3iYvulH6u{WL*2z)lNDJceB zO3GM5Fpav6)tdCSWszrI$UKf>vqMAjHyieS^E$fiz?Re|!&Twi*Z#c2$W;eF+8y#-yT|dxcK3q??jFG(S5a?$KF=@fQ`v>8 z6MH^x++4OMAb@&O6TWLt!y>t8t!G=~hW`HIu$yad+!~HtcpyjCx+wVU9$R+%op$-} zYdsr)@c0HAQz2-EY-BBxF_a;$3BeYs8M45|CWx^#|_ENgE`i-Fzzb?6Q@6C^5 zYjXWwiR?R=T-n|K!K1&rTg>?{UeF6aEV~<1(d}=WLkZu3ma?sPnxF3R+5JpwM~!&?&X|X+@C@4fa@v=_^`B)c`}69SmdlA5 z(WOfYj&pvIk-lHYp8I8=$8ERRAHB+c`@paCb?4!j{s(!m@CsR2VA=Ygk+j_^rWm^k zh&@&ZtUQ4rVX4PK(Yb&_Ou)k0G-%JM(4+#NQz)^_DnrCy79u4Z{lJJ=~OHjn?!sTkvY`p(WoV)h zNpLb|(x^=vMZh-=x}M`4q(tI&yTxv~*zUAQqy#}oaG69V!=MM|Dzb5u2eY|ic*F=p z3tY65b#ScRhVV?vWG~<}C<@z=vG}YGy?z{TbB(G1^^kZdheRsIC046sVhz@s2s%tDS55VX<+ z`zUY*B50`!BUDl)Mp5yM378m#%tTB;taP%lDyh7QQSm4SqEsrWN+|_2MyNqNrjXGl z%w&=Q%xqH7YB^9bfRcMr{5+6J2Au|#iSfr4LmtJM?M^E!b=Jn%-LA(?S*#UgauhF{ zR3#@A1ff>rYK2lE8_Ca0{5f#CV9D`RDK3_)z1u@ zC@sZTDkOXDFdH((2`J9)%(C0_G$_wTc;tAq9xf<`;wUY}0XP~iizjgzDOF_Qa#E%s z75HLYO5zjz?F?%!`d{As@<9?tCOw^X!SRc{rja$33GzqYMqcw+?_xp_@3J5%dL#uG zRR|bwoRBrrM6ai876A8;(SjYbv)@w;YFv(+)C|B>xQxIQKuKWmO^(GYR0<-VP~teD zoJ@Dw&77NZf+P#n5o!es)T1D_*XR-R~;JK{z=Ku zz1X&ocOMOJxGe~MsaDh{k`MMjtSGD4SJ8F$d~{&rQsdGY*}b}9XiQ4Z^8Ku&_x^%Q zQLUR+?u0IXV@se zRD?CYfG2p0w*T0FN1f?&MCu^wA%WU zemgeK?>ZWMW)3IvVV>+dy0Z*k)PPC#r{vOZ?MLTh+h1$gU$%O9;Qffe=+p1lThaDg zE1b!tm0u`&hx`0bRN_j4E$zPin-iX^B`?lPuFna1rF<10ClJ(2EG7S((YGHeCD5g2 KXpbc4l>Y|}fL3b& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/nanotrasen.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..b077dc0c542bbb7b707cc03e024acd9775d6ec67 GIT binary patch literal 4270 zcmeHKeQ*cDuW6 z(kMzf(H0oAARlUvuNlQpz&W8h%-AZea2z6s@}V5~h37bm;3`|R`k{hs%E-^sRm%jTw=CYcZfNq3jJ%HbI`jz$=BC__PE6}Eo#UO9fI^Ta#Zi+AK4%*|dh z`=y%J89R2`vah!6ckwHZEq`JRbwgXtmQxE~VqX00`t|tTTfcjQtO;IRbavCco{Ps< zVH1Mw_BZI~)4M+Tv}?(zDKBrKwr$PHtP=n4Rvz6x`&`-sr zm3m^?->0s;V|1o}(Uh9hf(t3#i6UU~R| zlV5K?Fnw)Z%Brkyo+(^@_VVjjKMZ$>^?y6+F}>ORRpzOmCZ;6sz4f1=Qy=W#b2>k% z_wBBA$G=-Jx$Dc^&oA!Da3ufG(Y*4DJu}WHZJ6D4WUcvzH96l)rXK9V{UskfHhNU3 z`L#PbI*!jNo4RyX!)`q#D=Ybv=?CxrCK8tY^3_e!#Y-tmx2Z4WT)q^5#%q+I!KysB zv%DNMbAs#x=15S1&O?y=TOta_*8v^%0lyS-V(0gEVyGlIu?1ES=~0S6tyCISK}EEz zl8@H$4gtGmjwwIFLV_UBIW!Usgfuqd#A3WGyf(rFhQ=UzofE6_c+nzR1t?=?%p_hM zks4`ijtR|I1(7XxmGn`-J117F>k3N{;c(a-wwPtrPf!krgCJ>wrg4bCwWg5HMevZ8 zV^G97TtMShNzo-agc_WjPj1ki7zW4D{`!K7$1^}5()v_@dJqv#At*CR1cOB46PjM! z2ub=1`qd}2O1Msma-hi#Di4YqK}gR@q?qgWcn27ami$ssi8Teq8%!A+;GJv33#*f$0YLhoJj=kAWe|<6&Jg-(VzlyPTL&FDuBr zB(SkdhG85wk|c2(#fdm$Ap!0qc^}S^90~F`k+xZ>1S)q()43223@S)&mLLxeNFdNY zJ5G}{gEJ0`19xyf5vO>Dr0rHKlgA4Q6n|AE=t?e-Sd~E~Kq`<&i4^0r;CVn4aK>t- zaE_xG+{!Ul%Hb1vE8~b!8S}svc->BnHj{%9Z-CQ9Sq(y~OCdoHYlB0TQV>+=oFN-! zvp5)s!)~J)yWL9J2SIlNRfCo@SSiwMiH`_8TLL*bXdNlY`2nGX{IN%jiD6+oP+HD# zDrAnuVK;1%3OHR>D`h$0#EfcDgK}Wl0~eIQ>70wx0nA3yR+gk$im44IGG zA-uUW#_G5WjBCw`$vehiSX#lYv{ zF}QWXosbyV3j6eewf>QxzIpf~Q=sTbl40pPBG-sq!%|>a;1PF?$Tchlh6NsR*Y75m zY4BwVgy27*Fnm?|>Y->he9ao=n>W{mWWukwes*&Mj9jCXR%-|{W`c1fAy2eVgu&6e z+fzLH^W<^K6VcQ4&y>JWmD^QNS+(!n(d_YEWSZ+go6Az$+WvLr?T30kUU=912{qe) zoMxFd6S=mnvu@q=aOau-@nfUs?|R(7`}_8_hq@0PxE)*8a`Ld_xztVj-x|Ag_nq%l gw6?Ug+;=$r!P_#X9WLx$4s#&x;xgBc!o|ye1~m8qAOHXW literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/flame.png b/Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/flame.png new file mode 100644 index 0000000000000000000000000000000000000000..d5fcd20d70d2f2f5a064994f835800c7b677f3f8 GIT binary patch literal 4798 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/spiderclan.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..bec9ed6658b06d4e486888dcd6026698253701e8 GIT binary patch literal 4492 zcmeHKeQ*M~(l$X-LK~qd%(2;h)2<}hu)A&2 zA_D_gwcxc>Z-x&M?y8K+Ne71y0jtPB2W!FJm%st1z240^ca>|ef&z!L@@#TnZvc{BqcLCH*uy`A+$kdgN$|DMKoGYo>N*)+Lwc)0ca@-#%Ss z&FfhnpX_@HJ^qZe&-M5&=I?3DjN6Cje|$LeFIjz0J9dx%<(b~lTMzX7H;^R+u(bQ^yiK2WynLbu_{)E?hDKD+to?fY+?-`7>M zuCTE#qd14(`DtqBKb6kB%^4?}sCUrd&H9Qzj-Pld_C{^*gwN7eOgr***;fdX@>9v_ z^m&}lfr4NeyVo~5+^2n6wM$C(VF$3P`__Ksd-cmEtbX5?f`h)xh6CJ=mg`e?F^|kQ z)^A#K>eSxW{hPNQYR+ihgx^x+}a1Iykjj5Uwvk~8k>zWzglcw7udLe zMIkqJx_awLs@IU>Ok0}nKKJ{Vcedu*FJ5#!`|QcBeYrjBHZ*T5As_6_tP>Wqxn1d9 zfABu>Maz<$An?q|`_Ufe&HS#S=62)BwMJWR@417G-j2-Y>sm{ux34<)@pFsp&YY$G zpY_%5ZZ~{^fAY+cPcEj4{8$JzCfvSw z_4tvFwYL#bTGq~fcxn#0wCT&rhS)ci9oIhp@wHpuBCCF@>>0Oz`y&XF@uUO|R_0yI z33AxTi*f)M z3pHy5n}{vQGuY!CBnShIN8{m8MCIZREWyjc-+Gw9&;&$VOsW$C_x!XA{-`$&rr33 zDoE0w(D%+z{cxWWB|w!c6#*1ffr$3-aEc<2*Eh(ZmsBo=qlu!Rcq0}Qg+W}jQVAt6 zqCkKU2t!g8=0}adYf^AXtP#2CBZ+c`Cjyrn z6CMDp84t3wS)fVEL{U_NO78=g@AEh?+DHyXd?8*7%1RhoU5bcuOdT5XOJPu|@w#jj zYqGI68%2^9)=bjYA<#0QsL*mcD@7Vj$q`ZD3Lz&Cts{l`azI2Q<%ubJV>nn2l$O_> z3YimeSPkb?0I$i4UzS4-OwSh8DF=tWa6^f_#=Ce8z|~0F%#k!lv3`o-OcckEkC7Bd z4#Uf$6s-PVXnp&j_GHuDk_y+aPK1(ssuZkE-X(8CQercqXkuG%ypSwG<*R_0$P;oU zhlC0~QV!tx(Qnv+xb!_{2#~-U5Mc*dvq0gDEx^JK3M@`rOct{x$ii+iBiU6ssKs~% z3I7#Ca<0nlVW8usujJW&d@m3ztA}!z~MF*il z;l{BA0SgV!iy~__n^{ZJG=t*(pXCiXVxT-bp&y6?&9oE$)$Sx<*a-?{NygyG3=eu@ z@TBk83+8$^U;Q?_n@gbR*dn9ScTBD^xkjbHsK8_H8k1{O3XBRo=B^)1F2m5XB8b30 zcro}S$Tw!$;ZtO4;E5s^vQU4MEp09snG|)eP!Z(bO#PFB?Ao0TgA+B6w_xJm#!XG1 zJ#X*%qeU>Z+~dmkmz@??XHR%-b=HfU8Z)xnek1;T?v2^6+&nIIxGfE}E4R-)(?++v z|J}~~vc~Oyy7q0yjmLj6_?Wvk{a9FVdQ&MBb@05xA&3IG5A literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/icon.png b/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ada45562e8cb93541627a7f19961a033d71ca773 GIT binary patch literal 4489 zcmeHKYfuzd7H&j^1$8Y^ND#F%Cb|ke)6?^AXCNa3&M1RC1_gzJrXSeKJe+Qr0SST{ zO2IWoDxe9gK_uB_HEN=(1XhTEXx0#jMomhSl%l&Vi|DQivCz1;2Sli(YRjt4Kc=du zyU+dZchC9Gxu^Q>h>Kk|)i2l&f}p7;qagv@Vd3(f4F0+N{0HFHl5a`o69^aVaM~F* zn}+#32MyD1mVqGm*VZ`wj276paj-O8?=>~NUEUM3x%2O?S$lSvUD2t@Ow`$*@|w=p zY~3^QLRrO{&aauDpM(J(IC%?YSi}C%Bv2 z&mUGo1LfYQ^ud&#q`W>qA6(bXB%g26&GAjY)|KMdn|j~~1bJ;^BO~KXk&#cs0YOx~ z_NLC*@@hz1dSY!t-L%~48_&o6A#8i8x?*wQCrjDT6aUO`_5{gUV?t`kq^n!D&MQmu z3Cc>FlR8O%&$~6vk-)z><4NVrHLY&P^*3Atb6x#VbqZbgRe-nUGwh2Ur}zHtXle0k z-xrGJmHRHgc)5IETbQ=}s;;2muVw!Z>*qG_Dy+@GnitM!-)l>5o!$D;I~5&y2h`mo#+t;`>uJ8sZh7206u{Rj1T{ z{u1BtZFv)F>0E`SzON~rSh3sSC!#LL>t_WXJhA@JUgM?0>n#yCe@yJ&b0NuVe*1*= zaW82K??wE0<48)?erNg8jqeV${UzdDQM0&n{k0zkj$2Q~LQiCl+MGux7oY>C{F<7m zT}7W*zq|Qy&4o?Px2K_x4y`EZHWt3U^tf;1fiBhU;_9{V={rAM`KGDjsM!%ouVan*PC79^)DB2jKO7ZZj1!CEK9;0cE4 zVG8i36RqQU2QHDgTrROoCbm1XBvOq=BSA3qH_j4nOtJ>M)x}=xyAv3P2Bun{Y^^VpL+aN=DD%_^4b!GVIVV&fqLy zmr4?7&Yt5W>8M=V#?K#3vCL$S8(|Pa%3`e!Pf$R-F^f^;2+on?%=Ta?QbK3bRzS)D z|D|~CxsL7xc3I5`gon$H8^QctP zYDS}wB1(e95V=C7M$~d8g9;`gtDH(4I=9Hx9iGy=JqX%>=`qZGjWyPzW56OH&>{ z0oTwFxsI@9(V%|}7wl6z`wPV&BQS>0faEC|Qh~^ogcMOzN(~}oXp+V>l#HavvFx0k z;a!B2)@K17fmWbEJzBxP8_waPv3S=yT1XI(3_&qulw=~waIg}gV?2#kEBTooS`T1U zivjb7Y@l_4PAC~^g~NIYP3Kqq4d>xkTmevzFY;Xaj>|PJ*K;ZGT;TEQ8kg(26nHN1 zcy;~Xuly`+h*FALJErv(48An3q% zYw*SC&8IqpjvcHysqFGOUh@U)`;R%A39iGh&%N&(TuD_snrvAg4nEnp@8XuW%!mEH zH~fqFnXk4S?Y{Z>Efr+D^g7DGyLaJXZ>jI4b{Jl&?ETX#AGtf^r6*!$=7jFvF_>^C zV9^6@C3|RKe?@UgdUd@iB%EAyx^PlSOGH!3wSnpDli-GEgJK zipLd}Q*={mF0Yw(XS?CEn023Jo@d_Dm6Q$AioNXeG8`?JHg0(Q&l>|D4KH zkR~AbvsLPA<=3(w;&cB^2$C$;Gkx{>*ViAP;}1-@lqJ6L<*%AEKR;Rl)k&AJPq5Is TuWcNi2h!&0>gTe~DWM4fdRtr! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..eac5453ddc95cde782022ba4a5b5194bc6fd1459 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|GCW-zLn`LH zy|t0|fC3N80Tt_j3Y%vMGk9hwdbr99xQLYhjox(odm&IM!vPc3MbD;Wn+a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-right-lit.png b/Resources/Textures/Objects/Tools/Lighters/syndielighter.rsi/inhand-right-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..5803b6ac4d75a6214a70a04ae5ce06f52b5b03a7 GIT binary patch literal 4294 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-left-lit.png b/Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/inhand-left-lit.png new file mode 100644 index 0000000000000000000000000000000000000000..babefd898d4039c757ce44d95dcacfd84cb0004c GIT binary patch literal 5161 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 kXL}^6Q$3-+!9j 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/top.png b/Resources/Textures/Objects/Tools/Lighters/waffleco.rsi/top.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0bae895aa181d4856a4f77a6f7ff5058f25939 GIT binary patch literal 4503 zcmeHKYj6|S6<%zxg$N=9JD9W+){6_cWVI`;o{NNoB|j995w;-2A;J5&Yj2UX%I?~d zZD=!i@^H*R%w*b$2PSdtwvZ;CfYUr|+L+jswm?%iP$w}iO#(@nkjH>i%ut%%mHeD$ zCgYj#&pWf)z2~0&&N<)t?j7C6KuOVj{atzlLFW64y`}JpYPT*8{wj5K!|>5p7u=$j zGBGqNOM(~zs9GBZD2R&!g2dks2R0gdQQggJ8LLxLeth>69Svg5bTGZ3}j_@yW1-Y_`xUSw_m3!nDu4nH0x_-^ll>Z*A zy_l2pCHnJK{m$Ww%QKete_Ev;emt-sJAZ|&JGghw@7Ar}`*JAy*oeP3aJ4_yTz~5H ztFPU;?v4)&pY6G)Ii6~X_}bsu*w&P}r)~3Wis)~|FNhmf|9$DXkp~w31%3Xn2r{cd z^mqb3k7ukNSjGOG&F$Re-wu*zFF%#? zg0SRJeEq49Hy`g=HG7!TDUbH8cQ-$Lsz=!|)O%u}Tle;rHP=4*wCu|A)E(F(&s=)E z;OJUcr+8`qwMNg2Ik|nG^eswz=;@K>&yJjw_BR>kxhS45z1o+}9)9VXR%GY@w(zOOjL%QF z{(Io%ch+0wz9tFyn# zOTE8*a9bGZe6D?9uzW<9^=_K6W3c6D`qnRy-VI%R@tzC6$<5IB+*q=+%#d|-PTjz{ zf0o~H>_p6G&R&@xjp}wU&aEH%Xvlrw_c!Z*efIo z3L6<-Vu3LpjzZlbh$}B1Ww`A?MOjcOM%>t!-EU&3$h)!ot$xxU^?)j|xK0LTbtOTr zZae4XvAi{USDc0bVW2W-JRFKBbli<4aB29inF$O{xTxFR*cN{P^++;6Ek=ux#0%nL zjTu{`M_n>6(52qOQ3yD4V^yjer3oSyiy32-QIabOlhf%WNHbwJuc zfgqy^ed`xW5Ux_96ev=)%z=U$5K)&+hA8s+1LFuJ>}C^gvD&Oo#!A{*2R{j7gDgT-GNH*?X;3_b;z*VPl--7#d6NaV z*en#z0=pF#ATnnrO_a%GN^XCoF*wqY9E7hEf+JycAO=rh;M^l&OqH zo5@Z&t#+$}bU2)p-D;k2+6-g`N=`#Hkw(gqnBh6P5MnY=I%1fq1Vl7anV8TTL&I_) zwTz}zh@7y)YG{uP7*&#kk`!`dTDGVLIX>-&3yNn{#>=PxMkCEunl#fUYmg*qilj-$ zD$+!gll&!K6l%ZATU$P;E7|m7QGxMm6Q<;vDg%!sN6BGGOe`i8O)LwV;gTgNObtl3 z3t}awxGE-63E=)QD%df*_$^{!N#J04*g?CMgA#DEcGyAAj+#4RV&fT{HQAs*84GLY1iQ^ie!t~SC}ONU7oly4W6g9C|JUxM!=xP)(vq~nof&TQ z#Q07>$`@?Kt-MBMb}K`m=uD7l@jFA;3|-S=U|P;I>YAZzS`19fc}88|8(sQ|vm%JV zKX@^C5eF(Bjtzx?>?JpaF!H@uFlNQGDL$pz<^ z2=2|5Uom-az5KzI75h%{*uX{dWb=Cu{`CE)Lx%SZ@#`O~PP_5;OX1yZjX!}n8%cfP fv6UL=pJpLf8!~simVd4r#zTAsCEkwwie3K$Hv>C= literal 0 HcmV?d00001 From 1c59e087d5e5c30e6423cd3e31cb8f06654f1290 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 7 Jul 2025 18:54:25 +0000 Subject: [PATCH 098/105] Automatic changelog update --- Resources/Changelog/Admin.yml | 7 +++++++ Resources/Changelog/Changelog.yml | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index 62c8d88d0d..0862424ba8 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -1240,5 +1240,12 @@ Entries: id: 150 time: '2025-06-30T21:09:16.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38531 +- author: Smugman + changes: + - message: Added the ID locked CentComm flippo for admeme use + type: Add + id: 151 + time: '2025-07-07T18:53:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35514 Name: Admin Order: 2 diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 5dcafecdd1..9aacfae3e2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -3879,3 +3879,11 @@ id: 8746 time: '2025-07-07T05:07:52.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38549 +- author: Smugman + changes: + - message: Many new lighters can now be found in both Maints loot and the Syndicate + Uplink. + type: Add + id: 8747 + time: '2025-07-07T18:53:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35514 From bb02be1dc7e77b39b41c074e396aa22bb5cbdc05 Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Mon, 7 Jul 2025 22:13:35 +0300 Subject: [PATCH 099/105] Cleanup: Remove ``TryInsert`` method from the ``DisposableSystem`` and use event subscriptions instead (#38819) Cleanup --- .../Disposal/Tube/DisposalTubeSystem.cs | 2 +- .../Disposal/Unit/DisposableSystem.cs | 32 +++++-------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 24653ce8d4..7e63bc4e23 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -428,7 +428,7 @@ namespace Content.Server.Disposal.Tube foreach (var entity in from.Container.ContainedEntities.ToArray()) { - _disposableSystem.TryInsert(holder, entity, holderComponent); + _containerSystem.Insert(entity, holderComponent.Container); } _atmosSystem.Merge(holderComponent.Air, from.Air); diff --git a/Content.Server/Disposal/Unit/DisposableSystem.cs b/Content.Server/Disposal/Unit/DisposableSystem.cs index 091a91c14e..d307488110 100644 --- a/Content.Server/Disposal/Unit/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/DisposableSystem.cs @@ -43,6 +43,8 @@ namespace Content.Server.Disposal.Unit _xformQuery = GetEntityQuery(); SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(CanInsert); + SubscribeLocalEvent(OnInsert); } private void OnComponentStartup(EntityUid uid, DisposalHolderComponent holder, ComponentStartup args) @@ -50,34 +52,16 @@ namespace Content.Server.Disposal.Unit holder.Container = _containerSystem.EnsureContainer(uid, nameof(DisposalHolderComponent)); } - public bool TryInsert(EntityUid uid, EntityUid toInsert, DisposalHolderComponent? holder = null) + private void CanInsert(Entity ent, ref ContainerIsInsertingAttemptEvent args) { - if (!Resolve(uid, ref holder)) - return false; - if (!CanInsert(uid, toInsert, holder)) - return false; - - if (!_containerSystem.Insert(toInsert, holder.Container)) - return false; - - if (_physicsQuery.TryGetComponent(toInsert, out var physBody)) - _physicsSystem.SetCanCollide(toInsert, false, body: physBody); - - return true; + if (!HasComp(args.EntityUid) && !HasComp(args.EntityUid)) + args.Cancel(); } - private bool CanInsert(EntityUid uid, EntityUid toInsert, DisposalHolderComponent? holder = null) + private void OnInsert(Entity ent, ref EntInsertedIntoContainerMessage args) { - if (!Resolve(uid, ref holder)) - return false; - - if (!_containerSystem.CanInsert(toInsert, holder.Container)) - { - return false; - } - - return HasComp(toInsert) || - HasComp(toInsert); + if (_physicsQuery.TryGetComponent(args.Entity, out var physBody)) + _physicsSystem.SetCanCollide(args.Entity, false, body: physBody); } public void ExitDisposals(EntityUid uid, DisposalHolderComponent? holder = null, TransformComponent? holderTransform = null) From 114ec579f53f1430102f3bd6c9aa6784ba1c1b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=BE=D0=BB=D1=83=D0=B1=D1=8C?= <124601871+Golubgik@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:19:28 +0700 Subject: [PATCH 100/105] =?UTF-8?q?JumpBoots=20Attempt=20=E2=84=962=20(#36?= =?UTF-8?q?862)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Co-authored-by: unknown Co-authored-by: ScarKy0 --- Content.Shared/Actions/ActionGrantSystem.cs | 6 +++ .../Actions/ItemActionGrantComponent.cs | 6 +++ .../Components/JumpAbilityComponent.cs | 36 ++++++++++++++++++ .../Systems/SharedJumpAbilitySystem.cs | 35 +++++++++++++++++ Resources/Audio/Effects/attributions.yml | 5 +++ Resources/Audio/Effects/stealthoff.ogg | Bin 0 -> 6727 bytes Resources/Prototypes/Actions/types.yml | 14 +++++++ .../Entities/Clothing/Shoes/misc.yml | 27 +++++++++++++ .../Recipes/Lathes/Packs/science.yml | 1 + Resources/Prototypes/Recipes/Lathes/misc.yml | 13 ++++++- Resources/Prototypes/Research/industrial.yml | 1 + .../Boots/jumpboots.rsi/equipped-FEET-vox.png | Bin 0 -> 3030 bytes .../Boots/jumpboots.rsi/equipped-FEET.png | Bin 0 -> 2611 bytes .../Shoes/Boots/jumpboots.rsi/icon.png | Bin 0 -> 2378 bytes .../Shoes/Boots/jumpboots.rsi/inhand-left.png | Bin 0 -> 2473 bytes .../Boots/jumpboots.rsi/inhand-right.png | Bin 0 -> 2544 bytes .../Shoes/Boots/jumpboots.rsi/meta.json | 30 +++++++++++++++ .../Interface/Actions/jump.rsi/icon.png | Bin 0 -> 1673 bytes .../Interface/Actions/jump.rsi/meta.json | 14 +++++++ 19 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 Content.Shared/Movement/Components/JumpAbilityComponent.cs create mode 100644 Content.Shared/Movement/Systems/SharedJumpAbilitySystem.cs create mode 100644 Resources/Audio/Effects/stealthoff.ogg create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/equipped-FEET.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/meta.json create mode 100644 Resources/Textures/Interface/Actions/jump.rsi/icon.png create mode 100644 Resources/Textures/Interface/Actions/jump.rsi/meta.json diff --git a/Content.Shared/Actions/ActionGrantSystem.cs b/Content.Shared/Actions/ActionGrantSystem.cs index f73ecf8a46..e5b737f28f 100644 --- a/Content.Shared/Actions/ActionGrantSystem.cs +++ b/Content.Shared/Actions/ActionGrantSystem.cs @@ -1,3 +1,5 @@ +using Content.Shared.Inventory; + namespace Content.Shared.Actions; ///

@@ -17,9 +19,13 @@ public sealed class ActionGrantSystem : EntitySystem private void OnItemGet(Entity ent, ref GetItemActionsEvent args) { + if (!TryComp(ent.Owner, out ActionGrantComponent? grant)) return; + if (ent.Comp.ActiveIfWorn && (args.SlotFlags == null || args.SlotFlags == SlotFlags.POCKET)) + return; + foreach (var action in grant.ActionEntities) { args.AddAction(action); diff --git a/Content.Shared/Actions/ItemActionGrantComponent.cs b/Content.Shared/Actions/ItemActionGrantComponent.cs index d1769b51a2..db722d0c46 100644 --- a/Content.Shared/Actions/ItemActionGrantComponent.cs +++ b/Content.Shared/Actions/ItemActionGrantComponent.cs @@ -11,4 +11,10 @@ public sealed partial class ItemActionGrantComponent : Component { [DataField(required: true), AutoNetworkedField, AlwaysPushInheritance] public List Actions = new(); + + /// + /// Actions will only be available if the item is in the clothing slot. + /// + [DataField, AutoNetworkedField] + public bool ActiveIfWorn; } diff --git a/Content.Shared/Movement/Components/JumpAbilityComponent.cs b/Content.Shared/Movement/Components/JumpAbilityComponent.cs new file mode 100644 index 0000000000..6da9161578 --- /dev/null +++ b/Content.Shared/Movement/Components/JumpAbilityComponent.cs @@ -0,0 +1,36 @@ +using Content.Shared.Actions; +using Content.Shared.Movement.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Components; + +/// +/// A component for configuring the settings for the jump action. +/// To give the jump action to an entity use and . +/// The basic action prototype is "ActionGravityJump". +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedJumpAbilitySystem))] +public sealed partial class JumpAbilityComponent : Component +{ + /// + /// How far you will jump (in tiles). + /// + [DataField, AutoNetworkedField] + public float JumpDistance = 5f; + + /// + /// Basic “throwing” speed for TryThrow method. + /// + [DataField, AutoNetworkedField] + public float JumpThrowSpeed = 10f; + + /// + /// This gets played whenever the jump action is used. + /// + [DataField, AutoNetworkedField] + public SoundSpecifier? JumpSound; +} + +public sealed partial class GravityJumpEvent : InstantActionEvent; + diff --git a/Content.Shared/Movement/Systems/SharedJumpAbilitySystem.cs b/Content.Shared/Movement/Systems/SharedJumpAbilitySystem.cs new file mode 100644 index 0000000000..ac720cae68 --- /dev/null +++ b/Content.Shared/Movement/Systems/SharedJumpAbilitySystem.cs @@ -0,0 +1,35 @@ +using Content.Shared.Gravity; +using Content.Shared.Movement.Components; +using Content.Shared.Throwing; +using Robust.Shared.Audio.Systems; + +namespace Content.Shared.Movement.Systems; + +public sealed partial class SharedJumpAbilitySystem : EntitySystem +{ + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGravityJump); + } + + private void OnGravityJump(Entity entity, ref GravityJumpEvent args) + { + if (_gravity.IsWeightless(args.Performer)) + return; + + var xform = Transform(args.Performer); + var throwing = xform.LocalRotation.ToWorldVec() * entity.Comp.JumpDistance; + var direction = xform.Coordinates.Offset(throwing); // to make the character jump in the direction he's looking + + _throwing.TryThrow(args.Performer, direction, entity.Comp.JumpThrowSpeed); + + _audio.PlayPredicted(entity.Comp.JumpSound, args.Performer, args.Performer); + args.Handled = true; + } +} diff --git a/Resources/Audio/Effects/attributions.yml b/Resources/Audio/Effects/attributions.yml index f330220421..3a7f18c7a3 100644 --- a/Resources/Audio/Effects/attributions.yml +++ b/Resources/Audio/Effects/attributions.yml @@ -247,6 +247,11 @@ copyright: "Created by mattroks101 for Bee Station. cig_snuff converted to mono" source: "https://github.com/BeeStation/BeeStation-Hornet/pull/29" +- files: [stealthoff.ogg] + copyright: 'TGStation at d4f678a1772007ff8d7eddd21cf7218c8e07bfc0' + license: "CC-BY-SA-3.0" + source: https://github.com/tgstation/tgstation/commit/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0 + - files: ["soft_thump.ogg"] license: "CC-BY-4.0" copyright: "Clipped by FairlySadPanda (Github) from a sound created by CheChoDj (Freesound)" diff --git a/Resources/Audio/Effects/stealthoff.ogg b/Resources/Audio/Effects/stealthoff.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d78706e9cdcb60f5a3a3f99b1a8f796edefcbe81 GIT binary patch literal 6727 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/equipped-FEET.png b/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/equipped-FEET.png new file mode 100644 index 0000000000000000000000000000000000000000..06c62f2869a573dbcb70e9ea10ebaa832a33b4ad GIT binary patch literal 2611 zcmb_ec}x^%6klwS!+^EmRW*!b(x^B)^Ucm)BdZ`w1;ctEidIdSo%wcmgxy(Z26n-E zpQN?X)|$o`o5pzl0a9xz+7_+1wkm3h)gm@c>6MBG)S5QhZ}t+cS4cOzJKucszTf-3 z-+OQ0)=Zr|F(vu6WSvfzQjl*iLf35Vlh_-5?-3VVLzg6f{%l33OFgQ6;y%bs9ir1E z$YSvN|mW1?WgON`>ul(XWb<57Q7ir&OWZ za6~m6gV!H}^(hgZkYZ$z^OHbNX)%Qi1wLlyuaL__&IO)?<fVmh@EMQpLnn^J%MTJcr zk|4UOx|;%mvKAvdU}YK0Bc`Zk1Wx6iYb@}rOOm}D3Rv`VZb1c7#11j@x(IXZgY zF7XvwX0`L-DiZ! z+3b-6l(T$Mi>4~#cRE}UV}OO~o#l9~k8L=w6)+U=$hP=|T)&X2k@Eo$M4-B@tAJR!iW74>4A=K%5xeM$$#lbCqZmySJoi_AD(}$}k-0C-K z*dYd-uQ|4CQqnq8sl0>D-ZIqRbxu|n(DN>NaQl#gITsHvTbCm@rxM=a+8oE$6`MA; zJ8#r(X|pf>DCI`5t#8{u`t@H7q>qU`g;J(!>1}1&F*!OY$zKlKTojaJ4+~042txZ>sooVRE%{kS3LxX~+yl!vH{CCin_#S5l!8AFk79p4|m`|`;C_uaqr+G1HaGkf>m zjtYHO;;#9LeVP+DCMQ(t57ktEOHW$0#9cy~f?wU~-7=}cfj6#PHg0fJV7BAI+@)zd z-SKDL85zTz4Y!XgpLMkU*z8$Z_}%iNx6dC)*goJE*HP2<^ISeK_VZ~$%h^i@60Tmm b^W`;ibyd5enZDdt`&(C#H`!i0p>+AbCG?0G literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/icon.png b/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8a548ba6a4b6b27c53b801232ffd33ca5617cda9 GIT binary patch literal 2378 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/inhand-right.png b/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ee26e9a8609042ad5d7ad2572141fefed9a538 GIT binary patch literal 2544 zcmb_eYitx%7@d-!P$VX5kW{h5;sZkO&YkDZOjz2|E$s%jly(W_)i87CZgKFhm5S5)4H61A&APsuEBziWn6_Q$>UE&b}yE3L$QGc3$5- z-#O>|?!Eh3b5q0E@``ebqQ-_BLoMW7;~k?OBEP%MW#`FhbgFTILs4TM_l`1Z%hvG} zHLBcclRs;|?g23!oBZc~vAemTn6rJ!5FDcF$k~sWHn=Xhg7?&^j=aN_P0@l8tJe)n(ZvF=5B& zSVSUfIO(`r65((t=p&l_rfH~(BE?t(${--}GSHyF0bQ46fO%cS*btB|$~^BFj+Hk=M<)G8a*5i9UxE(kaZA8Cpl-s>_@{G-+0Z zJXQ=H@RGy<(GYZ?@Wc^O3~)T5fn%I9jqxT5fymFnyJ8sX0?U%N;#t-J9P+R@Q3R|Y$20-6F*$($i&eBxFc1{<7zd!vvOr+H z!m^|kl0+2pnk*}U!K!ll@@6r^yGjy}UT8EumwO6+wBltYXXxBKR5j$SFF_yjCKfh) zg~#R)J$PT$E{xB_F##QB!sW9&R?N+4Hm>a;{d&&{&D@Q=qje8Yoh;je#t9h67zscU zN$+S#=YfO+oMs3C7K=(z`t8(NDatA;Sp%S4TmT+~dchVH*ODEW>{g8L!NuI)T99Ws zSj>>C+5aad*P8hbWA1Fe+`B>h87XA$5!ocY%hL8tZb}xFtRpq!8&+@Zwp$ur_^N)w)_v}VS3m8Wm%7?}x$?{>bmOs$A8y`JxBblp zPrQESy(3CvU1Uf9+CS}q6{qJ`WLMSgIk#$~)3pBhW1t3=#mg$j)QmaRMlD=(bi}C< z!nif#w(X_%Q5!~X8yT;nKuzn^zpj3f{-Jw+puhXzp7S5PyZ&SJ-2ACmHmIK+T>ZvB z3+?uu?=Pypap7EWwYS|V>Azog zm!wzT?EHG&r6X;dgr}$P`nK|NPn9?zold_s#DS=hSCwZCaPJMp_; zDo;GKzF{uDU>%w{P_gv;1GU2w9zxTXf0X^S_&0l^QEsg}ga+1~d}{lZ1CjQ!ov*0X z&7ob?_LGkuzc_*JzwuI4d)bWM%E^aUJUMFBi}bAi-u?TyzRHPrm~-Oc&Dq_H4)k4r Q$NNtfu5SwMnXz>3zx@4BMF0Q* literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/meta.json new file mode 100644 index 0000000000..faaa2fe6bb --- /dev/null +++ b/Resources/Textures/Clothing/Shoes/Boots/jumpboots.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/cd6ba31a1b5891133c14b9ebba4a4479143b5167", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-FEET", + "directions": 4 + }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Interface/Actions/jump.rsi/icon.png b/Resources/Textures/Interface/Actions/jump.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..46af10ae2797f666b4de8fc9677a0b2ea289b816 GIT binary patch literal 1673 zcmbVNZA{!`9PcS^aEzDjoYA?sTFipt_3aLitE+%_OwO!G;LL8BL3-`eyUMjsX$yA{ z7IC@+qFG{ChMSm7MU0DK;y1z;r!i&*KkN%L;&3=IktL!=qoQ%~>2Y`247#|c?eo&# z^ZUR5JKWmxSebj98^f@&NOQOijkxm^Z$NLWzyB9Blo-wXEDS64IFAcEK6WRD6|Jbz zm>m=La1zu=QHF6qW;6q#F>F_T#t@}0VB>L+P<5X8Vdet@S7n~qTPx6l5dulIx!(ls z{Vh?cze@_rMExW9t_+6=G+>K(MoZ}ym*I&lFNfyNHbvlBh~32#jgCM(CbZ%qXaYPy zGG2+MX*>`lfh@9dpYkBi(kw$U==OUVmh;h^pT%<*fy9}z!nK8W=Y*jZPb6*I;3z7c zPLpXL3C#q>1cO0}W+|5SB81oK(`_;1)vc;LLl{_+sT#Hlb=+YTL22|&IT zgo2E9bF}RQkL>rn>2vhk;wdPgE zSs%&Z)q7Q4hH2~mYYu?0Xak-=QA6>fy-XlV*KxHhSL?5#{TxlNK?NwQO5eKBAjh!R zK~c`gqAlJKEK8gMO-)1wtD2Yql%XdGyx>MI1XIvNf{}K?lqVN z6+11OpfQ2Gb;ER`kn)sMhii6F|1>fC?V6g+!%-t}riB)S7KJ7Tbkw;_)S@0Pe_#m1 zT#b=%V>EW?`%$LiAYFNA$0t*s^7|%>c1qh9ifdkcez<;a?!DE!@ppHY*G+x?;q9*< z{q>nw>&^+|;|DIy%yi(3W8aKU{r=7$o9J7y*vUI)-?zCVhc<5+bxnW9!M6hRpHEXRd)Gv+jl$#!4C%N-rOq_sCe#Gtp65$#riT{B)W;{Z#0+pTC|D zgpyktzTI~I(zB;VTIW{VYj-?!F;F?aX;05gMX|J@dIZ)DomS2+jk%L$txJCnUb)z` r{rrHZt-N>Z#=*|3zT>W|_bis^FE3A4zxCDI&d(y!)DoV2wDaKKom(`< literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Actions/jump.rsi/meta.json b/Resources/Textures/Interface/Actions/jump.rsi/meta.json new file mode 100644 index 0000000000..7a2119f3fb --- /dev/null +++ b/Resources/Textures/Interface/Actions/jump.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/a373b4cb08298523d40acc14f9c390a0c403fc31", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] +} From 41f737e8f39001f02829851b5ee09df44b143221 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 7 Jul 2025 19:20:35 +0000 Subject: [PATCH 101/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9aacfae3e2..ac4094f69e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: aada - changes: - - message: Egg-plants now have 6 reagent per egg at 20 potency, up from 3. - type: Tweak - id: 8235 - time: '2025-04-18T19:52:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36693 - author: Nox38 changes: - message: Nuclear operative agent is renamed to nuclear operative corpsman. @@ -3887,3 +3880,10 @@ id: 8747 time: '2025-07-07T18:53:17.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/35514 +- author: Jopaglazik, Golub + changes: + - message: Added Jump Boots In T1 "Salvage Equipment" technology. + type: Add + id: 8748 + time: '2025-07-07T19:19:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36862 From c565b4496571dc7056f9fb6e179bd2f12a56da25 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Mon, 7 Jul 2025 15:57:05 -0400 Subject: [PATCH 102/105] Replace `ValidatePrototypeId` uses with `ProtoId` or `EntProtoId` (#38814) * The easy ones * For certain values of easy * Easy test * Hair * Fix sandbox violations * Sort usings --- .../EntitySystems/ChemistryGuideDataSystem.cs | 12 ++--- .../UI/FlatpackCreatorMenu.xaml.cs | 3 +- .../CriminalRecordsConsoleWindow.xaml.cs | 5 +- .../Controls/GuideReagentReaction.xaml.cs | 5 +- .../Lobby/UI/HumanoidProfileEditor.xaml.cs | 23 ++++---- .../Systems/NetworkConfiguratorSystem.cs | 3 +- Content.Client/Overlays/ShowJobIconsSystem.cs | 5 +- Content.Client/Parallax/ParallaxSystem.cs | 3 +- .../Power/Generation/Teg/TegSystem.cs | 3 +- .../Silicons/Borgs/BorgSelectTypeMenu.xaml.cs | 1 - .../Silicons/Laws/Ui/LawDisplay.xaml.cs | 11 ++-- .../UserInterface/RichText/MonoTag.cs | 2 +- .../Systems/Chat/ChatUIController.cs | 5 +- .../Systems/Info/InfoUIController.cs | 5 +- .../Weapons/Ranged/Systems/GunSystem.cs | 3 +- .../Tests/Linter/StaticFieldValidationTest.cs | 9 ++-- .../Systems/AdminVerbSystem.Antags.cs | 27 +++------- Content.Server/Anomaly/AnomalySystem.cs | 5 +- .../Body/Commands/AddHandCommand.cs | 3 +- .../Cargo/Systems/CargoSystem.Bounty.cs | 3 +- .../Cartridges/CrewManifestCartridgeSystem.cs | 3 +- Content.Server/Chat/Systems/ChatSystem.cs | 3 +- .../EntitySystems/ChemMasterSystem.cs | 3 +- .../Construction/Commands/TileWallsCommand.cs | 10 ++-- .../Electrocution/ElectrocuteCommand.cs | 4 +- .../Electrocution/ElectrocutionSystem.cs | 10 ++-- .../EntitySystems/ExplosionSystem.cs | 5 +- .../Fluids/EntitySystems/PuddleSystem.cs | 17 +++--- .../GameTicking/GameTicker.Spawning.cs | 7 +-- Content.Server/GameTicking/GameTicker.cs | 2 +- .../GameTicking/Rules/NukeopsRuleSystem.cs | 10 ++-- .../Kitchen/EntitySystems/MicrowaveSystem.cs | 3 +- Content.Server/Mapping/MappingCommand.cs | 2 +- .../BiomassReclaimerSystem.cs | 6 +-- Content.Server/Medical/VomitSystem.cs | 3 +- Content.Server/Procedural/DungeonSystem.cs | 3 +- .../Revenant/EntitySystems/RevenantSystem.cs | 3 +- .../Salvage/SalvageSystem.Magnet.cs | 4 +- .../Salvage/SpawnSalvageMissionJob.cs | 2 +- .../Shuttles/Commands/FTLDiskCommand.cs | 7 +-- .../Systems/EmergencyShuttleSystem.Console.cs | 6 +-- .../Systems/EmergencyShuttleSystem.cs | 6 +-- Content.Server/Silicons/Borgs/BorgSystem.cs | 10 ++-- .../Silicons/Laws/IonStormSystem.cs | 54 +++++++------------ .../EntitySystems/RatvarianLanguageSystem.cs | 5 +- .../Speech/EntitySystems/SlurredSystem.cs | 6 +-- Content.Server/Spreader/KudzuSystem.cs | 4 +- .../Systems/StoreDiscountSystem.cs | 3 +- .../Temperature/Systems/TemperatureSystem.cs | 3 +- Content.Server/Traitor/Uplink/UplinkSystem.cs | 11 ++-- .../Artifact/XenoArtifactCommands.cs | 3 +- Content.Shared/Chat/SharedChatSystem.cs | 17 +++--- .../SharedTypingIndicatorSystem.cs | 4 +- .../Doors/Systems/SharedDoorSystem.cs | 5 +- Content.Shared/Drunk/DrunkSystem.cs | 4 +- .../Systems/TemporaryBlindnessSystem.cs | 4 +- .../Fluids/Components/DrainComponent.cs | 4 +- .../GameTicking/SharedGameTicker.cs | 3 +- Content.Shared/Gravity/SharedGravitySystem.cs | 4 +- Content.Shared/Humanoid/HairStyles.cs | 7 ++- .../Humanoid/HumanoidCharacterAppearance.cs | 4 +- .../SharedHumanoidAppearanceSystem.cs | 3 +- .../Inventory/InventorySystem.Equip.cs | 4 +- .../VirtualItem/SharedVirtualItemSystem.cs | 3 +- Content.Shared/Maps/ContentTileDefinition.cs | 3 +- .../Nutrition/EntitySystems/HungerSystem.cs | 11 ++-- .../Nutrition/EntitySystems/ThirstSystem.cs | 11 ++-- .../PlayTimeTrackingShared.cs | 7 ++- .../Preferences/HumanoidCharacterProfile.cs | 8 ++- .../Salvage/Fulton/SharedFultonSystem.cs | 2 +- Content.Shared/Salvage/SharedSalvageSystem.cs | 3 +- .../Silicons/Borgs/BorgTypePrototype.cs | 1 - .../Borgs/SharedBorgSwitchableTypeSystem.cs | 3 +- .../StationAi/SharedStationAiSystem.cs | 1 - .../EntitySystems/SharedStutteringSystem.cs | 4 +- .../SprayPainter/SharedSprayPainterSystem.cs | 5 +- .../EntitySystems/SharedStorageSystem.cs | 5 +- 77 files changed, 187 insertions(+), 297 deletions(-) diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs index 374b00aa6e..3392545be8 100644 --- a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs +++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -18,14 +18,10 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem { [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; - [ValidatePrototypeId] - private const string DefaultMixingCategory = "DummyMix"; - [ValidatePrototypeId] - private const string DefaultGrindCategory = "DummyGrind"; - [ValidatePrototypeId] - private const string DefaultJuiceCategory = "DummyJuice"; - [ValidatePrototypeId] - private const string DefaultCondenseCategory = "DummyCondense"; + private static readonly ProtoId DefaultMixingCategory = "DummyMix"; + private static readonly ProtoId DefaultGrindCategory = "DummyGrind"; + private static readonly ProtoId DefaultJuiceCategory = "DummyJuice"; + private static readonly ProtoId DefaultCondenseCategory = "DummyCondense"; private readonly Dictionary> _reagentSources = new(); diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs index 81410dc7e6..8ee8df48fd 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs @@ -27,8 +27,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow private EntityUid _owner; - [ValidatePrototypeId] - public const string NoBoardEffectId = "FlatpackerNoBoardEffect"; + public static readonly EntProtoId NoBoardEffectId = "FlatpackerNoBoardEffect"; private EntityUid? _currentBoard = EntityUid.Invalid; diff --git a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs index 5eaed77041..33b4fbc335 100644 --- a/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs +++ b/Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs @@ -33,8 +33,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow public readonly EntityUid Console; - [ValidatePrototypeId] - private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders"; + private static readonly ProtoId ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders"; public Action? OnKeySelected; public Action? OnFiltersChanged; @@ -296,7 +295,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow var field = "reason"; var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower()); - var placeholders = _proto.Index(ReasonPlaceholders); + var placeholders = _proto.Index(ReasonPlaceholders); var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used var prompt = Loc.GetString("criminal-records-console-reason"); var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder); diff --git a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs index 29ed124422..66d3f693b8 100644 --- a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs +++ b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs @@ -21,8 +21,7 @@ namespace Content.Client.Guidebook.Controls; [UsedImplicitly, GenerateTypedNameReferences] public sealed partial class GuideReagentReaction : BoxContainer, ISearchableControl { - [ValidatePrototypeId] - private const string DefaultMixingCategory = "DummyMix"; + private static readonly ProtoId DefaultMixingCategory = "DummyMix"; private readonly IPrototypeManager _protoMan; @@ -55,7 +54,7 @@ public sealed partial class GuideReagentReaction : BoxContainer, ISearchableCont } else { - mixingCategories.Add(protoMan.Index(DefaultMixingCategory)); + mixingCategories.Add(protoMan.Index(DefaultMixingCategory)); } SetMixingCategory(mixingCategories, prototype, sysMan); } diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index f22d1416ca..12eb7ffc23 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -103,8 +103,7 @@ namespace Content.Client.Lobby.UI private bool _isDirty; - [ValidatePrototypeId] - private const string DefaultSpeciesGuidebook = "Species"; + private static readonly ProtoId DefaultSpeciesGuidebook = "Species"; public event Action>>? OnOpenGuidebook; @@ -809,9 +808,9 @@ namespace Content.Client.Lobby.UI var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies; var page = DefaultSpeciesGuidebook; if (_prototypeManager.HasIndex(species)) - page = species; + page = new ProtoId(species.Id); // Gross. See above todo comment. - if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot)) + if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot)) { var dict = new Dictionary, GuideEntry>(); dict.Add(DefaultSpeciesGuidebook, guideRoot); @@ -1434,17 +1433,13 @@ namespace Content.Client.Lobby.UI { return; } - var hairMarking = Profile.Appearance.HairStyleId switch - { - HairStyles.DefaultHairStyle => new List(), - _ => new() { new(Profile.Appearance.HairStyleId, new List() { Profile.Appearance.HairColor }) }, - }; + var hairMarking = Profile.Appearance.HairStyleId == HairStyles.DefaultHairStyle + ? new List() + : new() { new(Profile.Appearance.HairStyleId, new List() { Profile.Appearance.HairColor }) }; - var facialHairMarking = Profile.Appearance.FacialHairStyleId switch - { - HairStyles.DefaultFacialHairStyle => new List(), - _ => new() { new(Profile.Appearance.FacialHairStyleId, new List() { Profile.Appearance.FacialHairColor }) }, - }; + var facialHairMarking = Profile.Appearance.FacialHairStyleId == HairStyles.DefaultFacialHairStyle + ? new List() + : new() { new(Profile.Appearance.FacialHairStyleId, new List() { Profile.Appearance.FacialHairColor }) }; HairStylePicker.UpdateData( hairMarking, diff --git a/Content.Client/NetworkConfigurator/Systems/NetworkConfiguratorSystem.cs b/Content.Client/NetworkConfigurator/Systems/NetworkConfiguratorSystem.cs index 8f519e61ac..9828222447 100644 --- a/Content.Client/NetworkConfigurator/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Client/NetworkConfigurator/Systems/NetworkConfiguratorSystem.cs @@ -23,8 +23,7 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem [Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly IInputManager _inputManager = default!; - [ValidatePrototypeId] - private const string Action = "ActionClearNetworkLinkOverlays"; + private static readonly EntProtoId Action = "ActionClearNetworkLinkOverlays"; public override void Initialize() { diff --git a/Content.Client/Overlays/ShowJobIconsSystem.cs b/Content.Client/Overlays/ShowJobIconsSystem.cs index e5ba9b813f..d0d14449f6 100644 --- a/Content.Client/Overlays/ShowJobIconsSystem.cs +++ b/Content.Client/Overlays/ShowJobIconsSystem.cs @@ -13,8 +13,7 @@ public sealed class ShowJobIconsSystem : EquipmentHudSystem] - private const string JobIconForNoId = "JobIconNoId"; + private static readonly ProtoId JobIconForNoId = "JobIconNoId"; public override void Initialize() { @@ -52,7 +51,7 @@ public sealed class ShowJobIconsSystem : EquipmentHudSystem(iconId, out var iconPrototype)) + if (_prototype.TryIndex(iconId, out var iconPrototype)) ev.StatusIcons.Add(iconPrototype); else Log.Error($"Invalid job icon prototype: {iconPrototype}"); diff --git a/Content.Client/Parallax/ParallaxSystem.cs b/Content.Client/Parallax/ParallaxSystem.cs index 465bc9cef4..7fed53782a 100644 --- a/Content.Client/Parallax/ParallaxSystem.cs +++ b/Content.Client/Parallax/ParallaxSystem.cs @@ -14,8 +14,7 @@ public sealed class ParallaxSystem : SharedParallaxSystem [Dependency] private readonly IParallaxManager _parallax = default!; [Dependency] private readonly SharedMapSystem _map = default!; - [ValidatePrototypeId] - private const string Fallback = "Default"; + private static readonly ProtoId Fallback = "Default"; public const int ParallaxZIndex = 0; diff --git a/Content.Client/Power/Generation/Teg/TegSystem.cs b/Content.Client/Power/Generation/Teg/TegSystem.cs index 92b5062b6d..0ae1b5e496 100644 --- a/Content.Client/Power/Generation/Teg/TegSystem.cs +++ b/Content.Client/Power/Generation/Teg/TegSystem.cs @@ -15,8 +15,7 @@ namespace Content.Client.Power.Generation.Teg; /// public sealed class TegSystem : EntitySystem { - [ValidatePrototypeId] - private const string ArrowPrototype = "TegCirculatorArrow"; + private static readonly EntProtoId ArrowPrototype = "TegCirculatorArrow"; public override void Initialize() { diff --git a/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs index e1fbd376b5..be59b07b65 100644 --- a/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs @@ -25,7 +25,6 @@ public sealed partial class BorgSelectTypeMenu : FancyWindow public event Action>? ConfirmedBorgType; - [ValidatePrototypeId] private static readonly List> GuidebookEntries = new() { "Cyborgs", "Robotics" }; public BorgSelectTypeMenu() diff --git a/Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs b/Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs index bb0dba2f57..245ea194f0 100644 --- a/Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs +++ b/Content.Client/Silicons/Laws/Ui/LawDisplay.xaml.cs @@ -84,12 +84,13 @@ public sealed partial class LawDisplay : Control radioChannelButton.OnPressed += _ => { - switch (radioChannel) + if (radioChannel == SharedChatSystem.CommonChannel) { - case SharedChatSystem.CommonChannel: - _chatManager.SendMessage($"{SharedChatSystem.RadioCommonPrefix} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break; - default: - _chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break; + _chatManager.SendMessage($"{SharedChatSystem.RadioCommonPrefix} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); + } + else + { + _chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); } _nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown; }; diff --git a/Content.Client/UserInterface/RichText/MonoTag.cs b/Content.Client/UserInterface/RichText/MonoTag.cs index aee41c324a..d97997dc83 100644 --- a/Content.Client/UserInterface/RichText/MonoTag.cs +++ b/Content.Client/UserInterface/RichText/MonoTag.cs @@ -12,7 +12,7 @@ namespace Content.Client.UserInterface.RichText; /// public sealed class MonoTag : IMarkupTag { - [ValidatePrototypeId] public const string MonoFont = "Monospace"; + public static readonly ProtoId MonoFont = "Monospace"; [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 13c6ff4a2a..e324429859 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -67,8 +67,7 @@ public sealed partial class ChatUIController : UIController [UISystemDependency] private readonly MindSystem? _mindSystem = default!; [UISystemDependency] private readonly RoleCodewordSystem? _roleCodewordSystem = default!; - [ValidatePrototypeId] - private const string ChatNamePalette = "ChatNames"; + private static readonly ProtoId ChatNamePalette = "ChatNames"; private string[] _chatNameColors = default!; private bool _chatNameColorsEnabled; @@ -232,7 +231,7 @@ public sealed partial class ChatUIController : UIController gameplayStateLoad.OnScreenLoad += OnScreenLoad; gameplayStateLoad.OnScreenUnload += OnScreenUnload; - var nameColors = _prototypeManager.Index(ChatNamePalette).Colors.Values.ToArray(); + var nameColors = _prototypeManager.Index(ChatNamePalette).Colors.Values.ToArray(); _chatNameColors = new string[nameColors.Length]; for (var i = 0; i < nameColors.Length; i++) { diff --git a/Content.Client/UserInterface/Systems/Info/InfoUIController.cs b/Content.Client/UserInterface/Systems/Info/InfoUIController.cs index 9f3461eadd..692ee26774 100644 --- a/Content.Client/UserInterface/Systems/Info/InfoUIController.cs +++ b/Content.Client/UserInterface/Systems/Info/InfoUIController.cs @@ -19,8 +19,7 @@ public sealed class InfoUIController : UIController, IOnStateExited] - private const string DefaultRuleset = "DefaultRuleset"; + private static readonly ProtoId DefaultRuleset = "DefaultRuleset"; public ProtoId RulesEntryId = DefaultRuleset; @@ -92,7 +91,7 @@ public sealed class InfoUIController : UIController, IOnStateExited(DefaultRuleset); + guideEntryPrototype = _prototype.Index(DefaultRuleset); Log.Error($"Couldn't find the following prototype: {RulesEntryId}. Falling back to {DefaultRuleset}, please check that the server has the rules set up correctly"); return guideEntryPrototype; } diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs index dd26effb33..6abebda6ee 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs @@ -39,8 +39,7 @@ public sealed partial class GunSystem : SharedGunSystem [Dependency] private readonly SharedTransformSystem _xform = default!; [Dependency] private readonly SpriteSystem _sprite = default!; - [ValidatePrototypeId] - public const string HitscanProto = "HitscanEffect"; + public static readonly EntProtoId HitscanProto = "HitscanEffect"; public bool SpreadOverlay { diff --git a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs index 90bf82e8f1..b75b81ab3c 100644 --- a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs +++ b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs @@ -4,7 +4,6 @@ using Content.Shared.Tag; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Reflection; -using Robust.Shared.Serialization.Manager.Attributes; namespace Content.IntegrationTests.Tests.Linter; @@ -66,25 +65,25 @@ public sealed class StaticFieldValidationTest [Reflect(false)] private sealed class StringValid { - [ValidatePrototypeId] public static string Tag = "StaticFieldTestTag"; + public static readonly ProtoId Tag = "StaticFieldTestTag"; } [Reflect(false)] private sealed class StringInvalid { - [ValidatePrototypeId] public static string Tag = string.Empty; + public static readonly ProtoId Tag = string.Empty; } [Reflect(false)] private sealed class StringArrayValid { - [ValidatePrototypeId] public static string[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; + public static readonly ProtoId[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } [Reflect(false)] private sealed class StringArrayInvalid { - [ValidatePrototypeId] public static string[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; + public static readonly ProtoId[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } [Reflect(false)] diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs index 6c7727ab4e..672ae695bf 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs @@ -22,25 +22,14 @@ public sealed partial class AdminVerbSystem [Dependency] private readonly GameTicker _gameTicker = default!; [Dependency] private readonly OutfitSystem _outfit = default!; - [ValidatePrototypeId] - private const string DefaultTraitorRule = "Traitor"; + private static readonly EntProtoId DefaultTraitorRule = "Traitor"; + private static readonly EntProtoId DefaultInitialInfectedRule = "Zombie"; + private static readonly EntProtoId DefaultNukeOpRule = "LoneOpsSpawn"; + private static readonly EntProtoId DefaultRevsRule = "Revolutionary"; + private static readonly EntProtoId DefaultThiefRule = "Thief"; + private static readonly ProtoId PirateGearId = "PirateGear"; - [ValidatePrototypeId] - private const string DefaultInitialInfectedRule = "Zombie"; - - [ValidatePrototypeId] - private const string DefaultNukeOpRule = "LoneOpsSpawn"; - - [ValidatePrototypeId] - private const string DefaultRevsRule = "Revolutionary"; - - [ValidatePrototypeId] - private const string DefaultThiefRule = "Thief"; - - [ValidatePrototypeId] - private const string PirateGearId = "PirateGear"; - - private readonly EntProtoId _paradoxCloneRuleId = "ParadoxCloneSpawn"; + private static readonly EntProtoId ParadoxCloneRuleId = "ParadoxCloneSpawn"; // All antag verbs have names so invokeverb works. private void AddAntagVerbs(GetVerbsEvent args) @@ -172,7 +161,7 @@ public sealed partial class AdminVerbSystem Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "ParadoxClone"), Act = () => { - var ruleEnt = _gameTicker.AddGameRule(_paradoxCloneRuleId); + var ruleEnt = _gameTicker.AddGameRule(ParadoxCloneRuleId); if (!TryComp(ruleEnt, out var paradoxCloneRuleComp)) return; diff --git a/Content.Server/Anomaly/AnomalySystem.cs b/Content.Server/Anomaly/AnomalySystem.cs index b0de3de8f3..9ac0ce7c94 100644 --- a/Content.Server/Anomaly/AnomalySystem.cs +++ b/Content.Server/Anomaly/AnomalySystem.cs @@ -44,8 +44,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem public const float MinParticleVariation = 0.8f; public const float MaxParticleVariation = 1.2f; - [ValidatePrototypeId] - const string WeightListProto = "AnomalyBehaviorList"; + private static readonly ProtoId WeightListProto = "AnomalyBehaviorList"; /// public override void Initialize() @@ -189,7 +188,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem #region Behavior private string GetRandomBehavior() { - var weightList = _prototype.Index(WeightListProto); + var weightList = _prototype.Index(WeightListProto); return weightList.Pick(_random); } diff --git a/Content.Server/Body/Commands/AddHandCommand.cs b/Content.Server/Body/Commands/AddHandCommand.cs index 3e006c539c..a28b07ef57 100644 --- a/Content.Server/Body/Commands/AddHandCommand.cs +++ b/Content.Server/Body/Commands/AddHandCommand.cs @@ -17,8 +17,7 @@ namespace Content.Server.Body.Commands [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - [ValidatePrototypeId] - public const string DefaultHandPrototype = "LeftHandHuman"; + private static readonly EntProtoId DefaultHandPrototype = "LeftHandHuman"; public string Command => "addhand"; public string Description => "Adds a hand to your entity."; diff --git a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs index 456d979959..934517eadc 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs @@ -29,8 +29,7 @@ public sealed partial class CargoSystem [Dependency] private readonly NameIdentifierSystem _nameIdentifier = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSys = default!; - [ValidatePrototypeId] - private const string BountyNameIdentifierGroup = "Bounty"; + private static readonly ProtoId BountyNameIdentifierGroup = "Bounty"; private EntityQuery _stackQuery; private EntityQuery _containerQuery; diff --git a/Content.Server/CartridgeLoader/Cartridges/CrewManifestCartridgeSystem.cs b/Content.Server/CartridgeLoader/Cartridges/CrewManifestCartridgeSystem.cs index 5247aafbd5..b1b23b2732 100644 --- a/Content.Server/CartridgeLoader/Cartridges/CrewManifestCartridgeSystem.cs +++ b/Content.Server/CartridgeLoader/Cartridges/CrewManifestCartridgeSystem.cs @@ -16,8 +16,7 @@ public sealed class CrewManifestCartridgeSystem : EntitySystem [Dependency] private readonly CrewManifestSystem _crewManifest = default!; [Dependency] private readonly StationSystem _stationSystem = default!; - [ValidatePrototypeId] - private const string CartridgePrototypeName = "CrewManifestCartridge"; + private static readonly EntProtoId CartridgePrototypeName = "CrewManifestCartridge"; /// /// Flag that shows that if crew manifest is allowed to be viewed from 'unsecure' entities, diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 2d6fb3c275..f21c3f78aa 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -809,8 +809,7 @@ public sealed partial class ChatSystem : SharedChatSystem return message; } - [ValidatePrototypeId] - public const string ChatSanitize_Accent = "chatsanitize"; + public static readonly ProtoId ChatSanitize_Accent = "chatsanitize"; public string SanitizeMessageReplaceWords(string message) { diff --git a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs index 6e2e2a91bc..64350cbda1 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs @@ -39,8 +39,7 @@ namespace Content.Server.Chemistry.EntitySystems [Dependency] private readonly LabelSystem _labelSystem = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [ValidatePrototypeId] - private const string PillPrototypeId = "Pill"; + private static readonly EntProtoId PillPrototypeId = "Pill"; public override void Initialize() { diff --git a/Content.Server/Construction/Commands/TileWallsCommand.cs b/Content.Server/Construction/Commands/TileWallsCommand.cs index a27caec423..ca87795b06 100644 --- a/Content.Server/Construction/Commands/TileWallsCommand.cs +++ b/Content.Server/Construction/Commands/TileWallsCommand.cs @@ -6,6 +6,7 @@ using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Server.GameObjects; using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Construction.Commands; @@ -20,12 +21,9 @@ public sealed class TileWallsCommand : IConsoleCommand public string Description => "Puts an underplating tile below every wall on a grid."; public string Help => $"Usage: {Command} | {Command}"; - [ValidatePrototypeId] - public const string TilePrototypeId = "Plating"; - - [ValidatePrototypeId] - public const string WallTag = "Wall"; - public const string DiagonalTag = "Diagonal"; + public static readonly ProtoId TilePrototypeId = "Plating"; + public static readonly ProtoId WallTag = "Wall"; + public static readonly ProtoId DiagonalTag = "Diagonal"; public void Execute(IConsoleShell shell, string argStr, string[] args) { diff --git a/Content.Server/Electrocution/ElectrocuteCommand.cs b/Content.Server/Electrocution/ElectrocuteCommand.cs index c0d0ecf740..6bc3977544 100644 --- a/Content.Server/Electrocution/ElectrocuteCommand.cs +++ b/Content.Server/Electrocution/ElectrocuteCommand.cs @@ -2,6 +2,7 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.StatusEffect; using Robust.Shared.Console; +using Robust.Shared.Prototypes; namespace Content.Server.Electrocution; @@ -13,8 +14,7 @@ public sealed class ElectrocuteCommand : LocalizedEntityCommands public override string Command => "electrocute"; - [ValidatePrototypeId] - private const string ElectrocutionStatusEffect = "Electrocution"; + private static readonly ProtoId ElectrocutionStatusEffect = "Electrocution"; public override void Execute(IConsoleShell shell, string argStr, string[] args) { diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index cd2b69d2ce..18a4d52ac2 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -58,12 +58,8 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly TurfSystem _turf = default!; - [ValidatePrototypeId] - private const string StatusEffectKey = "Electrocution"; - - [ValidatePrototypeId] - private const string DamageType = "Shock"; - + private static readonly ProtoId StatusEffectKey = "Electrocution"; + private static readonly ProtoId DamageType = "Shock"; private static readonly ProtoId WindowTag = "Window"; // Multiply and shift the log scale for shock damage. @@ -408,7 +404,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem if (shockDamage is { } dmg) { var actual = _damageable.TryChangeDamage(uid, - new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid); + new DamageSpecifier(_prototypeManager.Index(DamageType), dmg), origin: sourceUid); if (actual != null) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index 0cdc6d6b23..c50b1e53fa 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -70,14 +70,13 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem /// find errors. However some components, like rogue arrows, or some commands like the admin-smite need to have /// a "default" option specified outside of yaml data-fields. Hence this const string. /// - [ValidatePrototypeId] - public const string DefaultExplosionPrototypeId = "Default"; + public static readonly ProtoId DefaultExplosionPrototypeId = "Default"; public override void Initialize() { base.Initialize(); - DebugTools.Assert(_prototypeManager.HasIndex(DefaultExplosionPrototypeId)); + DebugTools.Assert(_prototypeManager.HasIndex(DefaultExplosionPrototypeId)); // handled in ExplosionSystem.GridMap.cs SubscribeLocalEvent(OnGridRemoved); diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs index ca2a2a64f3..44bbfe2450 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs @@ -60,16 +60,11 @@ public sealed partial class PuddleSystem : SharedPuddleSystem [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly TurfSystem _turf = default!; - [ValidatePrototypeId] - private const string Blood = "Blood"; + private static readonly ProtoId Blood = "Blood"; + private static readonly ProtoId Slime = "Slime"; + private static readonly ProtoId CopperBlood = "CopperBlood"; - [ValidatePrototypeId] - private const string Slime = "Slime"; - - [ValidatePrototypeId] - private const string CopperBlood = "CopperBlood"; - - private static string[] _standoutReagents = [Blood, Slime, CopperBlood]; + private static readonly string[] StandoutReagents = [Blood, Slime, CopperBlood]; // Using local deletion queue instead of the standard queue so that we can easily "undelete" if a puddle // loses & then gains reagents in a single tick. @@ -362,10 +357,10 @@ public sealed partial class PuddleSystem : SharedPuddleSystem // Kinda EH // Could potentially do alpha per-solution but future problem. - color = solution.GetColorWithout(_prototypeManager, _standoutReagents); + color = solution.GetColorWithout(_prototypeManager, StandoutReagents); color = color.WithAlpha(0.7f); - foreach (var standout in _standoutReagents) + foreach (var standout in StandoutReagents) { var quantity = solution.GetTotalPrototypeQuantity(standout); if (quantity <= FixedPoint2.Zero) diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index c59028e69b..194f6c4997 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -36,11 +36,8 @@ namespace Content.Server.GameTicking [Dependency] private readonly SharedJobSystem _jobs = default!; [Dependency] private readonly AdminSystem _admin = default!; - [ValidatePrototypeId] - public const string ObserverPrototypeName = "MobObserver"; - - [ValidatePrototypeId] - public const string AdminObserverPrototypeName = "AdminObserver"; + public static readonly EntProtoId ObserverPrototypeName = "MobObserver"; + public static readonly EntProtoId AdminObserverPrototypeName = "AdminObserver"; /// /// How many players have joined the round through normal methods. diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index fa8314cd27..55bf51db02 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -93,7 +93,7 @@ namespace Content.Server.GameTicking InitializePlayer(); InitializeLobbyBackground(); InitializeGamePreset(); - DebugTools.Assert(_prototypeManager.Index(FallbackOverflowJob).Name == FallbackOverflowJobName, + DebugTools.Assert(_prototypeManager.Index(FallbackOverflowJob).Name == FallbackOverflowJobName, "Overflow role does not have the correct name!"); InitializeGameRules(); InitializeReplays(); diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 616a1e48ff..f687c9dcc7 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -25,6 +25,7 @@ using Robust.Shared.Random; using Robust.Shared.Utility; using System.Linq; using Content.Shared.Store.Components; +using Robust.Shared.Prototypes; namespace Content.Server.GameTicking.Rules; @@ -38,11 +39,8 @@ public sealed class NukeopsRuleSystem : GameRuleSystem [Dependency] private readonly StoreSystem _store = default!; [Dependency] private readonly TagSystem _tag = default!; - [ValidatePrototypeId] - private const string TelecrystalCurrencyPrototype = "Telecrystal"; - - [ValidatePrototypeId] - private const string NukeOpsUplinkTagPrototype = "NukeOpsUplink"; + private static readonly ProtoId TelecrystalCurrencyPrototype = "Telecrystal"; + private static readonly ProtoId NukeOpsUplinkTagPrototype = "NukeOpsUplink"; public override void Initialize() @@ -485,7 +483,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem SetWinType(ent, WinType.CrewMajor, false); - if (nukeops.RoundEndBehavior == RoundEndBehavior.Nothing) // It's still worth checking if operatives have all died, even if the round-end behaviour is nothing. + if (nukeops.RoundEndBehavior == RoundEndBehavior.Nothing) // It's still worth checking if operatives have all died, even if the round-end behaviour is nothing. return; // Shouldn't actually try to end the round in the case of nothing though. _roundEndSystem.DoRoundEndBehavior(nukeops.RoundEndBehavior, diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 07ced93085..f5c8c4d0d8 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -70,8 +70,7 @@ namespace Content.Server.Kitchen.EntitySystems [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedSuicideSystem _suicide = default!; - [ValidatePrototypeId] - private const string MalfunctionSpark = "Spark"; + private static readonly EntProtoId MalfunctionSpark = "Spark"; private static readonly ProtoId MetalTag = "Metal"; private static readonly ProtoId PlasticTag = "Plastic"; diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs index 96a21573f6..8081b8e45f 100644 --- a/Content.Server/Mapping/MappingCommand.cs +++ b/Content.Server/Mapping/MappingCommand.cs @@ -146,7 +146,7 @@ namespace Content.Server.Mapping // map successfully created. run misc helpful mapping commands if (player.AttachedEntity is { Valid: true } playerEntity && - EntityManager.GetComponent(playerEntity).EntityPrototype?.ID != GameTicker.AdminObserverPrototypeName) + (EntityManager.GetComponent(playerEntity).EntityPrototype is not { } proto || proto != GameTicker.AdminObserverPrototypeName)) { shell.ExecuteCommand("aghost"); } diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs index 42e455a47f..e029071574 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs @@ -17,9 +17,9 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Jittering; +using Content.Shared.Materials; using Content.Shared.Medical; using Content.Shared.Mind; -using Content.Shared.Materials; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Nutrition.Components; @@ -30,6 +30,7 @@ using Robust.Server.Player; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Medical.BiomassReclaimer @@ -53,8 +54,7 @@ namespace Content.Server.Medical.BiomassReclaimer [Dependency] private readonly SharedMindSystem _minds = default!; [Dependency] private readonly InventorySystem _inventory = default!; - [ValidatePrototypeId] - public const string BiomassPrototype = "Biomass"; + public static readonly ProtoId BiomassPrototype = "Biomass"; public override void Update(float frameTime) { diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index 66cc9bf5f6..7b8be07a15 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -32,8 +32,7 @@ namespace Content.Server.Medical [Dependency] private readonly ForensicsSystem _forensics = default!; [Dependency] private readonly BloodstreamSystem _bloodstream = default!; - [ValidatePrototypeId] - private const string VomitCollection = "Vomit"; + private static readonly ProtoId VomitCollection = "Vomit"; private readonly SoundSpecifier _vomitSound = new SoundCollectionSpecifier(VomitCollection, AudioParams.Default.WithVariation(0.2f).WithVolume(-4f)); diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index 3a0a7ab2cd..aac620acc0 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -54,8 +54,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem private readonly JobQueue _dungeonJobQueue = new(DungeonJobTime); private readonly Dictionary _dungeonJobs = new(); - [ValidatePrototypeId] - public const string FallbackTileId = "FloorSteel"; + public static readonly ProtoId FallbackTileId = "FloorSteel"; public override void Initialize() { diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs index 0501f5afc3..2d38aee6ea 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs @@ -47,8 +47,7 @@ public sealed partial class RevenantSystem : EntitySystem [Dependency] private readonly VisibilitySystem _visibility = default!; [Dependency] private readonly TurfSystem _turf = default!; - [ValidatePrototypeId] - private const string RevenantShopId = "ActionRevenantShop"; + private static readonly EntProtoId RevenantShopId = "ActionRevenantShop"; public override void Initialize() { diff --git a/Content.Server/Salvage/SalvageSystem.Magnet.cs b/Content.Server/Salvage/SalvageSystem.Magnet.cs index 41d4c2e755..ee5cd792c6 100644 --- a/Content.Server/Salvage/SalvageSystem.Magnet.cs +++ b/Content.Server/Salvage/SalvageSystem.Magnet.cs @@ -8,6 +8,7 @@ using Content.Shared.Radio; using Content.Shared.Salvage.Magnet; using Robust.Shared.Exceptions; using Robust.Shared.Map; +using Robust.Shared.Prototypes; namespace Content.Server.Salvage; @@ -15,8 +16,7 @@ public sealed partial class SalvageSystem { [Dependency] private readonly IRuntimeLog _runtimeLog = default!; - [ValidatePrototypeId] - private const string MagnetChannel = "Supply"; + private static readonly ProtoId MagnetChannel = "Supply"; private EntityQuery _salvMobQuery; private EntityQuery _mobStateQuery; diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 8b5e9898ad..75b22598f9 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -255,7 +255,7 @@ public sealed class SpawnSalvageMissionJob : Job } } - var allLoot = _prototypeManager.Index(SharedSalvageSystem.ExpeditionsLootProto); + var allLoot = _prototypeManager.Index(SharedSalvageSystem.ExpeditionsLootProto); var lootBudget = difficultyProto.LootBudget; foreach (var rule in allLoot.LootRules) diff --git a/Content.Server/Shuttles/Commands/FTLDiskCommand.cs b/Content.Server/Shuttles/Commands/FTLDiskCommand.cs index 63d45e2364..5d7c108e5d 100644 --- a/Content.Server/Shuttles/Commands/FTLDiskCommand.cs +++ b/Content.Server/Shuttles/Commands/FTLDiskCommand.cs @@ -25,11 +25,8 @@ public sealed class FTLDiskCommand : LocalizedCommands public override string Command => "ftldisk"; - [ValidatePrototypeId] - public const string CoordinatesDisk = "CoordinatesDisk"; - - [ValidatePrototypeId] - public const string DiskCase = "DiskCase"; + public static readonly EntProtoId CoordinatesDisk = "CoordinatesDisk"; + public static readonly EntProtoId DiskCase = "DiskCase"; public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0) diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index 95c6ab5a1b..e07b522c5a 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -6,6 +6,7 @@ using Content.Shared.Access; using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; using Content.Shared.Popups; using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Events; @@ -13,7 +14,7 @@ using Content.Shared.Shuttles.Systems; using Content.Shared.UserInterface; using Robust.Shared.Map; using Robust.Shared.Player; -using Content.Shared.DeviceNetwork.Components; +using Robust.Shared.Prototypes; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Shuttles.Systems; @@ -65,8 +66,7 @@ public sealed partial class EmergencyShuttleSystem private CancellationTokenSource? _roundEndCancelToken; - [ValidatePrototypeId] - private const string EmergencyRepealAllAccess = "EmergencyShuttleRepealAll"; + private static readonly ProtoId EmergencyRepealAllAccess = "EmergencyShuttleRepealAll"; private static readonly Color DangerColor = Color.Red; /// diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 94e028b402..9eff1455f9 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -21,6 +21,7 @@ using Content.Shared.Access.Systems; using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; using Content.Shared.GameTicking; using Content.Shared.Localizations; using Content.Shared.Shuttles.Components; @@ -33,10 +34,10 @@ using Robust.Shared.Configuration; using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.Map.Components; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Shuttles.Systems; @@ -73,8 +74,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem private bool _emergencyShuttleEnabled; - [ValidatePrototypeId] - private const string DockTag = "DockEmergency"; + private static readonly ProtoId DockTag = "DockEmergency"; public override void Initialize() { diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index fd40aa8816..0cd407000f 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -1,12 +1,14 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Server.Actions; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; -using Content.Shared.Body.Events; using Content.Server.DeviceNetwork.Systems; using Content.Server.Explosion.EntitySystems; using Content.Server.Hands.Systems; using Content.Server.PowerCell; using Content.Shared.Alert; +using Content.Shared.Body.Events; using Content.Shared.Database; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; @@ -29,10 +31,9 @@ using Robust.Server.GameObjects; using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; -using System.Diagnostics.CodeAnalysis; -using System.Linq; namespace Content.Server.Silicons.Borgs; @@ -61,8 +62,7 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [Dependency] private readonly ISharedPlayerManager _player = default!; - [ValidatePrototypeId] - public const string BorgJobId = "Borg"; + public static readonly ProtoId BorgJobId = "Borg"; /// public override void Initialize() diff --git a/Content.Server/Silicons/Laws/IonStormSystem.cs b/Content.Server/Silicons/Laws/IonStormSystem.cs index 7b848a0ea6..249813edc1 100644 --- a/Content.Server/Silicons/Laws/IonStormSystem.cs +++ b/Content.Server/Silicons/Laws/IonStormSystem.cs @@ -22,42 +22,24 @@ public sealed class IonStormSystem : EntitySystem [Dependency] private readonly IRobustRandom _robustRandom = default!; // funny - [ValidatePrototypeId] - private const string Threats = "IonStormThreats"; - [ValidatePrototypeId] - private const string Objects = "IonStormObjects"; - [ValidatePrototypeId] - private const string Crew = "IonStormCrew"; - [ValidatePrototypeId] - private const string Adjectives = "IonStormAdjectives"; - [ValidatePrototypeId] - private const string Verbs = "IonStormVerbs"; - [ValidatePrototypeId] - private const string NumberBase = "IonStormNumberBase"; - [ValidatePrototypeId] - private const string NumberMod = "IonStormNumberMod"; - [ValidatePrototypeId] - private const string Areas = "IonStormAreas"; - [ValidatePrototypeId] - private const string Feelings = "IonStormFeelings"; - [ValidatePrototypeId] - private const string FeelingsPlural = "IonStormFeelingsPlural"; - [ValidatePrototypeId] - private const string Musts = "IonStormMusts"; - [ValidatePrototypeId] - private const string Requires = "IonStormRequires"; - [ValidatePrototypeId] - private const string Actions = "IonStormActions"; - [ValidatePrototypeId] - private const string Allergies = "IonStormAllergies"; - [ValidatePrototypeId] - private const string AllergySeverities = "IonStormAllergySeverities"; - [ValidatePrototypeId] - private const string Concepts = "IonStormConcepts"; - [ValidatePrototypeId] - private const string Drinks = "IonStormDrinks"; - [ValidatePrototypeId] - private const string Foods = "IonStormFoods"; + private static readonly ProtoId Threats = "IonStormThreats"; + private static readonly ProtoId Objects = "IonStormObjects"; + private static readonly ProtoId Crew = "IonStormCrew"; + private static readonly ProtoId Adjectives = "IonStormAdjectives"; + private static readonly ProtoId Verbs = "IonStormVerbs"; + private static readonly ProtoId NumberBase = "IonStormNumberBase"; + private static readonly ProtoId NumberMod = "IonStormNumberMod"; + private static readonly ProtoId Areas = "IonStormAreas"; + private static readonly ProtoId Feelings = "IonStormFeelings"; + private static readonly ProtoId FeelingsPlural = "IonStormFeelingsPlural"; + private static readonly ProtoId Musts = "IonStormMusts"; + private static readonly ProtoId Requires = "IonStormRequires"; + private static readonly ProtoId Actions = "IonStormActions"; + private static readonly ProtoId Allergies = "IonStormAllergies"; + private static readonly ProtoId AllergySeverities = "IonStormAllergySeverities"; + private static readonly ProtoId Concepts = "IonStormConcepts"; + private static readonly ProtoId Drinks = "IonStormDrinks"; + private static readonly ProtoId Foods = "IonStormFoods"; /// /// Randomly alters the laws of an individual silicon. diff --git a/Content.Server/Speech/EntitySystems/RatvarianLanguageSystem.cs b/Content.Server/Speech/EntitySystems/RatvarianLanguageSystem.cs index baa4f6f347..508f85aac2 100644 --- a/Content.Server/Speech/EntitySystems/RatvarianLanguageSystem.cs +++ b/Content.Server/Speech/EntitySystems/RatvarianLanguageSystem.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using Content.Shared.Speech.Components; using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; +using Robust.Shared.Prototypes; namespace Content.Server.Speech.EntitySystems; @@ -10,9 +11,7 @@ public sealed class RatvarianLanguageSystem : SharedRatvarianLanguageSystem { [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; - - [ValidatePrototypeId] - private const string RatvarianKey = "RatvarianLanguage"; + private static readonly ProtoId RatvarianKey = "RatvarianLanguage"; // This is the word of Ratvar and those who speak it shall abide by His rules: /* diff --git a/Content.Server/Speech/EntitySystems/SlurredSystem.cs b/Content.Server/Speech/EntitySystems/SlurredSystem.cs index e396cd0b18..fbfe72f17f 100644 --- a/Content.Server/Speech/EntitySystems/SlurredSystem.cs +++ b/Content.Server/Speech/EntitySystems/SlurredSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Speech.Components; using Content.Shared.Drunk; using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -14,10 +15,7 @@ public sealed class SlurredSystem : SharedSlurredSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; - - - [ValidatePrototypeId] - private const string SlurKey = "SlurredSpeech"; + private static readonly ProtoId SlurKey = "SlurredSpeech"; public override void Initialize() { diff --git a/Content.Server/Spreader/KudzuSystem.cs b/Content.Server/Spreader/KudzuSystem.cs index 92e6609fd7..fbc809c15b 100644 --- a/Content.Server/Spreader/KudzuSystem.cs +++ b/Content.Server/Spreader/KudzuSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage; using Content.Shared.Spreader; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -14,8 +15,7 @@ public sealed class KudzuSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [ValidatePrototypeId] - private const string KudzuGroup = "Kudzu"; + private static readonly ProtoId KudzuGroup = "Kudzu"; /// public override void Initialize() diff --git a/Content.Server/StoreDiscount/Systems/StoreDiscountSystem.cs b/Content.Server/StoreDiscount/Systems/StoreDiscountSystem.cs index c993c14694..dc72a08499 100644 --- a/Content.Server/StoreDiscount/Systems/StoreDiscountSystem.cs +++ b/Content.Server/StoreDiscount/Systems/StoreDiscountSystem.cs @@ -14,8 +14,7 @@ namespace Content.Server.StoreDiscount.Systems; /// public sealed class StoreDiscountSystem : EntitySystem { - [ValidatePrototypeId] - private const string DiscountedStoreCategoryPrototypeKey = "DiscountedItems"; + private static readonly ProtoId DiscountedStoreCategoryPrototypeKey = "DiscountedItems"; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs index d2f6baf6f9..6290e8231a 100644 --- a/Content.Server/Temperature/Systems/TemperatureSystem.cs +++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs @@ -36,8 +36,7 @@ public sealed class TemperatureSystem : EntitySystem private float _accumulatedFrametime; - [ValidatePrototypeId] - public const string TemperatureAlertCategory = "Temperature"; + public static readonly ProtoId TemperatureAlertCategory = "Temperature"; public override void Initialize() { diff --git a/Content.Server/Traitor/Uplink/UplinkSystem.cs b/Content.Server/Traitor/Uplink/UplinkSystem.cs index f30d2d7b4c..f4a9ca75fd 100644 --- a/Content.Server/Traitor/Uplink/UplinkSystem.cs +++ b/Content.Server/Traitor/Uplink/UplinkSystem.cs @@ -22,10 +22,9 @@ public sealed class UplinkSystem : EntitySystem [Dependency] private readonly SharedSubdermalImplantSystem _subdermalImplant = default!; [Dependency] private readonly SharedMindSystem _mind = default!; - [ValidatePrototypeId] - public const string TelecrystalCurrencyPrototype = "Telecrystal"; - private const string FallbackUplinkImplant = "UplinkImplant"; - private const string FallbackUplinkCatalog = "UplinkUplinkImplanter"; + public static readonly ProtoId TelecrystalCurrencyPrototype = "Telecrystal"; + private static readonly EntProtoId FallbackUplinkImplant = "UplinkImplant"; + private static readonly ProtoId FallbackUplinkCatalog = "UplinkUplinkImplanter"; /// /// Adds an uplink to the target @@ -89,8 +88,6 @@ public sealed class UplinkSystem : EntitySystem /// private bool ImplantUplink(EntityUid user, FixedPoint2 balance, bool giveDiscounts) { - var implantProto = new string(FallbackUplinkImplant); - if (!_proto.TryIndex(FallbackUplinkCatalog, out var catalog)) return false; @@ -102,7 +99,7 @@ public sealed class UplinkSystem : EntitySystem else balance = balance - cost; - var implant = _subdermalImplant.AddImplant(user, implantProto); + var implant = _subdermalImplant.AddImplant(user, FallbackUplinkImplant); if (!HasComp(implant)) return false; diff --git a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs index 31d079e3ad..7fd7acca4b 100644 --- a/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs +++ b/Content.Server/Xenoarchaeology/Artifact/XenoArtifactCommands.cs @@ -14,8 +14,7 @@ namespace Content.Server.Xenoarchaeology.Artifact; [ToolshedCommand, AdminCommand(AdminFlags.Debug)] public sealed class XenoArtifactCommand : ToolshedCommand { - [ValidatePrototypeId] - public const string ArtifactPrototype = "BaseXenoArtifact"; + public static readonly EntProtoId ArtifactPrototype = "BaseXenoArtifact"; /// List existing artifacts. [CommandImplementation("list")] diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index e5f3d46997..967980302d 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -24,13 +24,10 @@ public abstract class SharedChatSystem : EntitySystem public const char WhisperPrefix = ','; public const char DefaultChannelKey = 'h'; - [ValidatePrototypeId] - public const string CommonChannel = "Common"; + public static readonly ProtoId CommonChannel = "Common"; - public static string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}"; - - [ValidatePrototypeId] - public const string DefaultSpeechVerb = "Default"; + public static readonly string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}"; + public static readonly ProtoId DefaultSpeechVerb = "Default"; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; @@ -43,7 +40,7 @@ public abstract class SharedChatSystem : EntitySystem public override void Initialize() { base.Initialize(); - DebugTools.Assert(_prototypeManager.HasIndex(CommonChannel)); + DebugTools.Assert(_prototypeManager.HasIndex(CommonChannel)); SubscribeLocalEvent(OnPrototypeReload); CacheRadios(); } @@ -67,13 +64,13 @@ public abstract class SharedChatSystem : EntitySystem public SpeechVerbPrototype GetSpeechVerb(EntityUid source, string message, SpeechComponent? speech = null) { if (!Resolve(source, ref speech, false)) - return _prototypeManager.Index(DefaultSpeechVerb); + return _prototypeManager.Index(DefaultSpeechVerb); // check for a suffix-applicable speech verb SpeechVerbPrototype? current = null; foreach (var (str, id) in speech.SuffixSpeechVerbs) { - var proto = _prototypeManager.Index(id); + var proto = _prototypeManager.Index(id); if (message.EndsWith(Loc.GetString(str)) && proto.Priority >= (current?.Priority ?? 0)) { current = proto; @@ -81,7 +78,7 @@ public abstract class SharedChatSystem : EntitySystem } // if no applicable suffix verb return the normal one used by the entity - return current ?? _prototypeManager.Index(speech.SpeechVerb); + return current ?? _prototypeManager.Index(speech.SpeechVerb); } /// diff --git a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs index bc5c95c8ab..20f2741f0b 100644 --- a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs +++ b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Clothing; using Content.Shared.Inventory; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Shared.Chat.TypingIndicator; @@ -18,8 +19,7 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem /// /// Default ID of /// - [ValidatePrototypeId] - public const string InitialIndicatorId = "default"; + public static readonly ProtoId InitialIndicatorId = "default"; public override void Initialize() { diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index a0dba80bd9..7914a38334 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -23,6 +23,7 @@ using Robust.Shared.Timing; using Robust.Shared.Audio.Systems; using Robust.Shared.Network; using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; namespace Content.Shared.Doors.Systems; @@ -46,9 +47,7 @@ public abstract partial class SharedDoorSystem : EntitySystem [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!; - - [ValidatePrototypeId] - public const string DoorBumpTag = "DoorBumpOpener"; + public static readonly ProtoId DoorBumpTag = "DoorBumpOpener"; /// /// A set of doors that are currently opening, closing, or just queued to open/close after some delay. diff --git a/Content.Shared/Drunk/DrunkSystem.cs b/Content.Shared/Drunk/DrunkSystem.cs index 4f9429b6a6..236ce2dcd3 100644 --- a/Content.Shared/Drunk/DrunkSystem.cs +++ b/Content.Shared/Drunk/DrunkSystem.cs @@ -1,13 +1,13 @@ using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; using Content.Shared.Traits.Assorted; +using Robust.Shared.Prototypes; namespace Content.Shared.Drunk; public abstract class SharedDrunkSystem : EntitySystem { - [ValidatePrototypeId] - public const string DrunkKey = "Drunk"; + public static readonly ProtoId DrunkKey = "Drunk"; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly SharedSlurredSystem _slurredSystem = default!; diff --git a/Content.Shared/Eye/Blinding/Systems/TemporaryBlindnessSystem.cs b/Content.Shared/Eye/Blinding/Systems/TemporaryBlindnessSystem.cs index aa3ff9fdc3..34680b12ef 100644 --- a/Content.Shared/Eye/Blinding/Systems/TemporaryBlindnessSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/TemporaryBlindnessSystem.cs @@ -1,12 +1,12 @@ using Content.Shared.Eye.Blinding.Components; using Content.Shared.StatusEffect; +using Robust.Shared.Prototypes; namespace Content.Shared.Eye.Blinding.Systems; public sealed class TemporaryBlindnessSystem : EntitySystem { - [ValidatePrototypeId] - public const string BlindingStatusEffect = "TemporaryBlindness"; + public static readonly ProtoId BlindingStatusEffect = "TemporaryBlindness"; [Dependency] private readonly BlindableSystem _blindableSystem = default!; diff --git a/Content.Shared/Fluids/Components/DrainComponent.cs b/Content.Shared/Fluids/Components/DrainComponent.cs index 305ed00b14..a7d7bbb3ad 100644 --- a/Content.Shared/Fluids/Components/DrainComponent.cs +++ b/Content.Shared/Fluids/Components/DrainComponent.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Tag; using Robust.Shared.Audio; +using Robust.Shared.Prototypes; namespace Content.Shared.Fluids.Components; @@ -17,8 +18,7 @@ public sealed partial class DrainComponent : Component { public const string SolutionName = "drainBuffer"; - [ValidatePrototypeId] - public const string PlungerTag = "Plunger"; + public static readonly ProtoId PlungerTag = "Plunger"; [ViewVariables] public Entity? Solution = null; diff --git a/Content.Shared/GameTicking/SharedGameTicker.cs b/Content.Shared/GameTicking/SharedGameTicker.cs index 050d4826cb..6b8bc8685b 100644 --- a/Content.Shared/GameTicking/SharedGameTicker.cs +++ b/Content.Shared/GameTicking/SharedGameTicker.cs @@ -18,8 +18,7 @@ namespace Content.Shared.GameTicking // See ideally these would be pulled from the job definition or something. // But this is easier, and at least it isn't hardcoded. //TODO: Move these, they really belong in StationJobsSystem or a cvar. - [ValidatePrototypeId] - public const string FallbackOverflowJob = "Passenger"; + public static readonly ProtoId FallbackOverflowJob = "Passenger"; public const string FallbackOverflowJobName = "job-name-passenger"; diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs index 3ff9792e86..e20771d603 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Movement.Components; using Robust.Shared.GameStates; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Timing; @@ -14,8 +15,7 @@ namespace Content.Shared.Gravity [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly AlertsSystem _alerts = default!; - [ValidatePrototypeId] - public const string WeightlessAlert = "Weightless"; + public static readonly ProtoId WeightlessAlert = "Weightless"; private EntityQuery _gravityQuery; diff --git a/Content.Shared/Humanoid/HairStyles.cs b/Content.Shared/Humanoid/HairStyles.cs index cb4befd85a..543a0de817 100644 --- a/Content.Shared/Humanoid/HairStyles.cs +++ b/Content.Shared/Humanoid/HairStyles.cs @@ -1,14 +1,13 @@ using Content.Shared.Humanoid.Markings; +using Robust.Shared.Prototypes; namespace Content.Shared.Humanoid { public static class HairStyles { - [ValidatePrototypeId] - public const string DefaultHairStyle = "HairBald"; + public static readonly ProtoId DefaultHairStyle = "HairBald"; - [ValidatePrototypeId] - public const string DefaultFacialHairStyle = "FacialHairShaved"; + public static readonly ProtoId DefaultFacialHairStyle = "FacialHairShaved"; public static readonly IReadOnlyList RealisticHairColors = new List { diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index 7d4a17b337..66f9108365 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -131,10 +131,10 @@ public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance, var newHairStyle = hairStyles.Count > 0 ? random.Pick(hairStyles) - : HairStyles.DefaultHairStyle; + : HairStyles.DefaultHairStyle.Id; var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female - ? HairStyles.DefaultFacialHairStyle + ? HairStyles.DefaultFacialHairStyle.Id : random.Pick(facialHairStyles); var newHairColor = random.Pick(HairStyles.RealisticHairColors); diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index 2669089650..3d3af84a30 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -41,8 +41,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem [Dependency] private readonly GrammarSystem _grammarSystem = default!; [Dependency] private readonly SharedIdentitySystem _identity = default!; - [ValidatePrototypeId] - public const string DefaultSpecies = "Human"; + public static readonly ProtoId DefaultSpecies = "Human"; public override void Initialize() { diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index de24a64a1c..3ed068070a 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -15,6 +15,7 @@ using Content.Shared.Strip.Components; using Content.Shared.Whitelist; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -35,8 +36,7 @@ public abstract partial class InventorySystem [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [Dependency] private readonly SharedStrippableSystem _strippable = default!; - [ValidatePrototypeId] - private const string PocketableItemSize = "Small"; + private static readonly ProtoId PocketableItemSize = "Small"; private void InitializeEquip() { diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index d76a4a3415..8842223afc 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -30,8 +30,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [ValidatePrototypeId] - private const string VirtualItem = "VirtualItem"; + private static readonly EntProtoId VirtualItem = "VirtualItem"; public override void Initialize() { diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index 9fc4bee481..64975b5616 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -15,8 +15,7 @@ namespace Content.Shared.Maps [Prototype("tile")] public sealed partial class ContentTileDefinition : IPrototype, IInheritingPrototype, ITileDefinition { - [ValidatePrototypeId] - public const string PryingToolQuality = "Prying"; + public static readonly ProtoId PryingToolQuality = "Prying"; public const string SpaceID = "Space"; diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index be8f19f98c..bd869c6415 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -25,14 +25,9 @@ public sealed class HungerSystem : EntitySystem [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; - [ValidatePrototypeId] - private const string HungerIconOverfedId = "HungerIconOverfed"; - - [ValidatePrototypeId] - private const string HungerIconPeckishId = "HungerIconPeckish"; - - [ValidatePrototypeId] - private const string HungerIconStarvingId = "HungerIconStarving"; + private static readonly ProtoId HungerIconOverfedId = "HungerIconOverfed"; + private static readonly ProtoId HungerIconPeckishId = "HungerIconPeckish"; + private static readonly ProtoId HungerIconStarvingId = "HungerIconStarving"; public override void Initialize() { diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index 052e73cd1b..808337639a 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -23,14 +23,9 @@ public sealed class ThirstSystem : EntitySystem [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; - [ValidatePrototypeId] - private const string ThirstIconOverhydratedId = "ThirstIconOverhydrated"; - - [ValidatePrototypeId] - private const string ThirstIconThirstyId = "ThirstIconThirsty"; - - [ValidatePrototypeId] - private const string ThirstIconParchedId = "ThirstIconParched"; + private static readonly ProtoId ThirstIconOverhydratedId = "ThirstIconOverhydrated"; + private static readonly ProtoId ThirstIconThirstyId = "ThirstIconThirsty"; + private static readonly ProtoId ThirstIconParchedId = "ThirstIconParched"; public override void Initialize() { diff --git a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs index ccaf9c17dd..d02a22171a 100644 --- a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs +++ b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs @@ -1,4 +1,5 @@ using Content.Shared.Dataset; +using Robust.Shared.Prototypes; namespace Content.Shared.Players.PlayTimeTracking; @@ -7,12 +8,10 @@ public static class PlayTimeTrackingShared /// /// The prototype ID of the play time tracker that represents overall playtime, i.e. not tied to any one role. /// - [ValidatePrototypeId] - public const string TrackerOverall = "Overall"; + public static readonly ProtoId TrackerOverall = "Overall"; /// /// The prototype ID of the play time tracker that represents admin time, when a player is in game as admin. /// - [ValidatePrototypeId] - public const string TrackerAdmin = "Admin"; + public static readonly ProtoId TrackerAdmin = "Admin"; } diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 616b213194..845e359564 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -198,8 +198,10 @@ namespace Content.Shared.Preferences /// /// The species to use in this default profile. The default species is . /// Humanoid character profile with default settings. - public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) + public static HumanoidCharacterProfile DefaultWithSpecies(string? species = null) { + species ??= SharedHumanoidAppearanceSystem.DefaultSpecies; + return new() { Species = species, @@ -221,8 +223,10 @@ namespace Content.Shared.Preferences return RandomWithSpecies(species); } - public static HumanoidCharacterProfile RandomWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) + public static HumanoidCharacterProfile RandomWithSpecies(string? species = null) { + species ??= SharedHumanoidAppearanceSystem.DefaultSpecies; + var prototypeManager = IoCManager.Resolve(); var random = IoCManager.Resolve(); diff --git a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs index b4b383d800..0b091d3a61 100644 --- a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs +++ b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs @@ -33,7 +33,7 @@ public abstract partial class SharedFultonSystem : EntitySystem [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - [ValidatePrototypeId] public const string EffectProto = "FultonEffect"; + public static readonly EntProtoId EffectProto = "FultonEffect"; protected static readonly Vector2 EffectOffset = Vector2.Zero; public override void Initialize() diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 12d0a26449..6e596449b4 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -23,8 +23,7 @@ public abstract partial class SharedSalvageSystem : EntitySystem /// /// Main loot table for salvage expeditions. /// - [ValidatePrototypeId] - public const string ExpeditionsLootProto = "SalvageLoot"; + public static readonly ProtoId ExpeditionsLootProto = "SalvageLoot"; public string GetFTLName(LocalizedDatasetPrototype dataset, int seed) { diff --git a/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs b/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs index 2f47dd4cea..a45e2aa1d1 100644 --- a/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs +++ b/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs @@ -15,7 +15,6 @@ namespace Content.Shared.Silicons.Borgs; [Prototype] public sealed partial class BorgTypePrototype : IPrototype { - [ValidatePrototypeId] private static readonly ProtoId DefaultFootsteps = new("FootstepBorg"); [IdDataField] diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs index 55287e4d23..914470e3c9 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs @@ -21,8 +21,7 @@ public abstract class SharedBorgSwitchableTypeSystem : EntitySystem [Dependency] protected readonly IPrototypeManager Prototypes = default!; [Dependency] private readonly InteractionPopupSystem _interactionPopup = default!; - [ValidatePrototypeId] - public const string ActionId = "ActionSelectBorgType"; + public static readonly EntProtoId ActionId = "ActionSelectBorgType"; public override void Initialize() { diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs index 1615ab0fa3..72374a8a30 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs @@ -69,7 +69,6 @@ public abstract partial class SharedStationAiSystem : EntitySystem private EntityQuery _broadphaseQuery; private EntityQuery _gridQuery; - [ValidatePrototypeId] private static readonly EntProtoId DefaultAi = "StationAiBrain"; private const float MaxVisionMultiplier = 5f; diff --git a/Content.Shared/Speech/EntitySystems/SharedStutteringSystem.cs b/Content.Shared/Speech/EntitySystems/SharedStutteringSystem.cs index 1a5a4daeec..05358a04bb 100644 --- a/Content.Shared/Speech/EntitySystems/SharedStutteringSystem.cs +++ b/Content.Shared/Speech/EntitySystems/SharedStutteringSystem.cs @@ -1,11 +1,11 @@ using Content.Shared.StatusEffect; +using Robust.Shared.Prototypes; namespace Content.Shared.Speech.EntitySystems; public abstract class SharedStutteringSystem : EntitySystem { - [ValidatePrototypeId] - public const string StutterKey = "Stutter"; + public static readonly ProtoId StutterKey = "Stutter"; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; diff --git a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs index 48a941d598..1b58381675 100644 --- a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs +++ b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs @@ -28,8 +28,7 @@ public abstract class SharedSprayPainterSystem : EntitySystem public List Styles { get; private set; } = new(); public List Groups { get; private set; } = new(); - [ValidatePrototypeId] - private const string Departments = "Departments"; + private static readonly ProtoId Departments = "Departments"; public override void Initialize() { @@ -180,7 +179,7 @@ public abstract class SharedSprayPainterSystem : EntitySystem } // get their department ids too for the final style list - var departments = Proto.Index(Departments); + var departments = Proto.Index(Departments); Styles.Capacity = names.Count; foreach (var name in names) { diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index adba19e047..f3c9055910 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -83,8 +83,7 @@ public abstract class SharedStorageSystem : EntitySystem /// public bool NestedStorage = true; - [ValidatePrototypeId] - public const string DefaultStorageMaxItemSize = "Normal"; + public static readonly ProtoId DefaultStorageMaxItemSize = "Normal"; public const float AreaInsertDelayPerItem = 0.075f; private static AudioParams _audioParams = AudioParams.Default @@ -254,7 +253,7 @@ public abstract class SharedStorageSystem : EntitySystem private void UpdatePrototypeCache() { - _defaultStorageMaxItemSize = _prototype.Index(DefaultStorageMaxItemSize); + _defaultStorageMaxItemSize = _prototype.Index(DefaultStorageMaxItemSize); _sortedSizes.Clear(); _sortedSizes.AddRange(_prototype.EnumeratePrototypes()); _sortedSizes.Sort(); From 366b623cd0ff48deb3a33a1f2d9377b7ab4538ba Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Mon, 7 Jul 2025 23:09:50 +0200 Subject: [PATCH 103/105] Fix SSD sleep misprediction (#38831) init --- Content.Shared/SSDIndicator/SSDIndicatorComponent.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Shared/SSDIndicator/SSDIndicatorComponent.cs b/Content.Shared/SSDIndicator/SSDIndicatorComponent.cs index cef8bd15e3..9547b6ce4e 100644 --- a/Content.Shared/SSDIndicator/SSDIndicatorComponent.cs +++ b/Content.Shared/SSDIndicator/SSDIndicatorComponent.cs @@ -12,17 +12,18 @@ namespace Content.Shared.SSDIndicator; [AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class SSDIndicatorComponent : Component { - [ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadOnly)] [AutoNetworkedField] public bool IsSSD = true; - [ViewVariables(VVAccess.ReadWrite)] [DataField] public ProtoId Icon = "SSDIcon"; /// /// When the entity should fall asleep /// - [DataField, AutoPausedField, Access(typeof(SSDIndicatorSystem))] + [DataField] + [AutoNetworkedField, AutoPausedField] + [Access(typeof(SSDIndicatorSystem))] public TimeSpan FallAsleepTime = TimeSpan.Zero; } From 46ec3b402afffc6123cbc15ecc9d87aeae960b4d Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 7 Jul 2025 23:43:33 +0200 Subject: [PATCH 104/105] New science unlock: the H.A.R.M.P.A.C.K (#38824) --- .../ExtraHandsEquipmentComponent.cs | 18 ++++++++ .../ExtraHandsEquipmentSystem.cs | 43 ++++++++++++++++++ .../Locale/en-US/research/technologies.ftl | 1 + .../Entities/Clothing/Back/specific.yml | 22 +++++++++ .../Recipes/Lathes/Packs/science.yml | 1 + .../Recipes/Lathes/Packs/security.yml | 1 + .../Prototypes/Recipes/Lathes/security.yml | 12 +++++ Resources/Prototypes/Research/arsenal.yml | 12 +++++ .../harmpack.rsi/equipped-BACKPACK.png | Bin 0 -> 1521 bytes .../Back/Specific/harmpack.rsi/icon.png | Bin 0 -> 657 bytes .../Specific/harmpack.rsi/inhand-left.png | Bin 0 -> 487 bytes .../Specific/harmpack.rsi/inhand-right.png | Bin 0 -> 521 bytes .../Back/Specific/harmpack.rsi/meta.json | 26 +++++++++++ 13 files changed, 136 insertions(+) create mode 100644 Content.Shared/Hands/Components/ExtraHandsEquipmentComponent.cs create mode 100644 Content.Shared/Hands/EntitySystems/ExtraHandsEquipmentSystem.cs create mode 100644 Resources/Textures/Clothing/Back/Specific/harmpack.rsi/equipped-BACKPACK.png create mode 100644 Resources/Textures/Clothing/Back/Specific/harmpack.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Back/Specific/harmpack.rsi/meta.json diff --git a/Content.Shared/Hands/Components/ExtraHandsEquipmentComponent.cs b/Content.Shared/Hands/Components/ExtraHandsEquipmentComponent.cs new file mode 100644 index 0000000000..fb3685c386 --- /dev/null +++ b/Content.Shared/Hands/Components/ExtraHandsEquipmentComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; +using Content.Shared.Hands.EntitySystems; + +namespace Content.Shared.Hands.Components; + +/// +/// An entity with this component will give you extra hands when you equip it in your inventory. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(ExtraHandsEquipmentSystem))] +public sealed partial class ExtraHandsEquipmentComponent : Component +{ + /// + /// Dictionary relating a unique hand ID corresponding to a container slot on the attached entity to a struct containing information about the Hand itself. + /// + [DataField] + public Dictionary Hands = new(); +} diff --git a/Content.Shared/Hands/EntitySystems/ExtraHandsEquipmentSystem.cs b/Content.Shared/Hands/EntitySystems/ExtraHandsEquipmentSystem.cs new file mode 100644 index 0000000000..4b96f89d81 --- /dev/null +++ b/Content.Shared/Hands/EntitySystems/ExtraHandsEquipmentSystem.cs @@ -0,0 +1,43 @@ +using Content.Shared.Hands.Components; +using Content.Shared.Inventory.Events; + +namespace Content.Shared.Hands.EntitySystems; + +public sealed class ExtraHandsEquipmentSystem : EntitySystem +{ + [Dependency] private readonly SharedHandsSystem _hands = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + } + + private void OnEquipped(Entity ent, ref GotEquippedEvent args) + { + if (!TryComp(args.Equipee, out var handsComp)) + return; + + foreach (var (handName, hand) in ent.Comp.Hands) + { + // add the NetEntity id to the container name to prevent multiple items with this component from conflicting + var handId = $"{GetNetEntity(ent.Owner).Id}-{handName}"; + _hands.AddHand((args.Equipee, handsComp), handId, hand.Location); + } + } + + private void OnUnequipped(Entity ent, ref GotUnequippedEvent args) + { + if (!TryComp(args.Equipee, out var handsComp)) + return; + + foreach (var handName in ent.Comp.Hands.Keys) + { + // add the NetEntity id to the container name to prevent multiple items with this component from conflicting + var handId = $"{GetNetEntity(ent.Owner).Id}-{handName}"; + _hands.RemoveHand((args.Equipee, handsComp), handId); + } + } +} diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index 876579eea5..62432b8dd6 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -39,6 +39,7 @@ research-technology-kinetic-modifications = Kinetic Modifications research-technology-basic-shuttle-armament = Shuttle Basic Armament research-technology-advanced-shuttle-weapon = Advanced Shuttle Weapons research-technology-thermal-weaponry = Thermal Weaponry +research-technology-dual-wielding-technology = Dual Wielding Technology research-technology-basic-robotics = Basic Robotics research-technology-basic-anomalous-research = Basic Anomalous Research diff --git a/Resources/Prototypes/Entities/Clothing/Back/specific.yml b/Resources/Prototypes/Entities/Clothing/Back/specific.yml index ff06b93bbf..d303aa166c 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/specific.yml @@ -98,3 +98,25 @@ - type: Construction graph: ClothingBagPet node: bagPet + +- type: entity + parent: Clothing + id: ClothingBackpackHarmpack + name: H.A.R.M.P.A.C.K. + description: Now you can reload, punch, and eat a snack - simultaneously. + components: + - type: Sprite + sprite: Clothing/Back/Specific/harmpack.rsi + state: icon + - type: Item + size: Ginormous + - type: Clothing + slots: BACK + - type: ExtraHandsEquipment + hands: + # middle hands to prevent overlapping inhand sprites + # This can be changed once we have per-hand displacement maps + extra_hand_1: + location: Middle + extra_hand_2: + location: Middle diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/science.yml b/Resources/Prototypes/Recipes/Lathes/Packs/science.yml index 6308570e6f..164a85dc44 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/science.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/science.yml @@ -30,6 +30,7 @@ - SignallerAdvanced - DeviceQuantumSpinInverter - DeviceDesynchronizer + - ClothingBackpackHarmpack - type: latheRecipePack id: ScienceClothing diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/security.yml b/Resources/Prototypes/Recipes/Lathes/Packs/security.yml index 4beee0f9d1..f3e8891b25 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/security.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/security.yml @@ -75,6 +75,7 @@ - PowerCageMedium - PowerCageSmall - TelescopicShield + - ClothingBackpackHarmpack - type: latheRecipePack id: SecurityBoards diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml index 606e628669..71f815e5aa 100644 --- a/Resources/Prototypes/Recipes/Lathes/security.yml +++ b/Resources/Prototypes/Recipes/Lathes/security.yml @@ -84,6 +84,18 @@ Plasma: 500 Glass: 500 +- type: latheRecipe + id: ClothingBackpackHarmpack + result: ClothingBackpackHarmpack + categories: + - Clothing + completetime: 15 + materials: + Steel: 2000 + Plastic: 1000 + Plasma: 500 + Gold: 500 + # Shields - type: latheRecipe parent: BaseShieldRecipe diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml index 7ba7cea9da..bb12a2c25f 100644 --- a/Resources/Prototypes/Research/arsenal.yml +++ b/Resources/Prototypes/Research/arsenal.yml @@ -191,6 +191,18 @@ technologyPrerequisites: - SalvageWeapons +- type: technology + id: DualWieldingTechnology + name: research-technology-dual-wielding-technology + icon: + sprite: Clothing/Back/Specific/harmpack.rsi + state: icon + discipline: Arsenal + tier: 2 + cost: 10000 + recipeUnlocks: + - ClothingBackpackHarmpack + # Tier 3 - type: technology diff --git a/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/equipped-BACKPACK.png b/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f9e5aff718d17e8f3168c5a6efda1ca5745cf2 GIT binary patch literal 1521 zcmVPx)t4TybRCt{2nm=gUSRBW{3L$iCgUrzk(Pb#ck-&s#%`$>9hn5r>zP7f~#vHJHM?;rxWGe^zKp3w<9j zw)KAceSh!i_ax)r58!Y(91e%`qavgYl*?tRC<;u|1OOw*}w#>E7O6Fir@8=Xuok zeU!^(dVYQ`7={rGB#%A-Wa%Fr9l`f~FemrvJBg{(dl$3Aq4Ez>2#=V+mL1XTKZrafKmE<`0xS!en0UF zF=x82L)Ue>ySp0*>AFtYc-nb{5Mh3Po~2^!3Qp1|gupNi;pF6m0>Ja<&&N_)6h+*> ze?M`rXX#Hf=bEOm)C;amQXsp#y8@eV^mvkZ_$te?jM>@Qv19CWUVQ*~^ym>B$HCpZ zcZ2sgZ{8%@PST$OfJUQ1mzI`LsZ+dx&6wGofT1BHBsRRJ{>)ud}nWOntVvE1RFj^rrwoRaL=t-CXG( zo;)MZB4lZ(sw!BPHBq14d{UaQrpVHlbJ z^M5JKKhp}wfYCy*xY;<1JI!b67BEc{7Z(@7_vPhfEG#UHUG>AmLxBabwY8O4Hos|f zT@N}$*4NkR;o)HrPrKa~78Vw;yu2LPUtC-SeMU*7E&%J+s8*|#RZ(8Nco9pZ;cz%s zlKPqzm#}YL*XeLLjM=al2_dLft2C`Mgps-c`}_MsrBXqqQi;{`!$cb+vTVPUsPD9< z3}(yX&w2_>Cmm$_=XK)>tZyI-+qThcHmM{@5JeG|Hp0CKY(7cxBxV3>KEkMPpin5FR4S$3;99Mg(ChW!I8I=T35CzRFdwB-357xd zj^hNq32FAs*8Zr*<`X3|1G?QVL{Y?G09Lxr47S(nVK5lvvb`>rWkD20^m@JAw#C)| zV=;b9&w#`QV5q7pbh};3K5uMnBzAbQo&iD#c6N4x<2Ut490eZe8itYBrvLyO8yocP z+qYwJXZg-tfT)9+nVHylQXn_|TOerPx%OG!jQR9J=Wma%IhK@`S+dmP&&jq9Yau{+czOBA~+Y=wZ3<^<0o&1Jbl2-seA zrTzhOl@bD}0)d01v|mzWQFbk@wKM?BvJ^nMT-FMO!s`mKEK7|>BYfXS*L8rPpGYJEQLiGP zR4OUo_mNTpAcO!|`qy=xtE;QXcHcxHnWm|d$z6Bb97sXzH+uK_V!{Ge|I(9w!e=-1vSM!w_qCVPy`yEA+@@GPo{` z$7A4EyDGA8Ut0lZv3>vH2d?YF_YDQq>vgT!Y$_o{P-qqnhe1k-5CYeAsn_c(k78&Y zXf~UQ2-*A`rfI@cAnSM=mEwFpuhQu>sZ{F4`N3d-=Xuz+9ocSZ9aw}A0?+eS&U>D> zbY%a!0A1G+LU49=rsebbrOdW%TPqfeYJNjTMWj0L9K~W$@w6lJi05OQV&nHfsZ>%t ry#cPTueG`JdE}d1#anE##eadHM6BcFo<#(600000NkvXXu0mjf5+*j> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-left.png b/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3dfd73ed24ebb3ad7f1718bebb25cb3b80b577 GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z7kaulhE&XX zduyZLAqN?@5B!g%FPyd5WngjQ$hED9uFPH8S@Maqz$kAIlPB-`gy3V-o0d3`#JtN}I>|_w{OvD>Fkblvr);d;I4|Tvo4H z2Ty|8>_~RB!hc2DWUUmaX-M48^mChGutSz*bQR+*sE-cR6 zdhNt#nb}jjPi92^WIi?X=^C>+=Da(K?lUmFU*BNJc0Q0rqIvmmcZp;MhP&CVdJKE6 zoYqPAeC^SqvD9Gx`S1S@I|`JbxB>(^b literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-right.png b/Resources/Textures/Clothing/Back/Specific/harmpack.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..224065dc6856518f2f49b18bddba4bf7e041ce41 GIT binary patch literal 521 zcmV+k0`~ohP)Px$!%0LzRCt{2+ObN*Ko|$`f5kU2n>f03uwbWd2c4=;*$ah$&E(YaoW!lKP*Cy; zhPo8)2?`PE9uRH_eTH+Yq^4l%^konP-Fq#Ykj`8t>*?={^iO5qFu-j4Z{!=y8#MAp`>L!}gEvsrG}JkM(hAuL6$>RmdRz5vDAj Date: Mon, 7 Jul 2025 21:44:41 +0000 Subject: [PATCH 105/105] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ac4094f69e..1ba3ce520c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Nox38 - changes: - - message: Nuclear operative agent is renamed to nuclear operative corpsman. - type: Tweak - id: 8236 - time: '2025-04-18T19:56:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34627 - author: Ilya246 changes: - message: The actions hotbar now has up to 10 more hotkeys accessible through the @@ -3887,3 +3880,12 @@ id: 8748 time: '2025-07-07T19:19:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36862 +- author: slarticodefast, EmoGarbage404 + changes: + - message: 'Added a new science gadget: The H.A.R.M.P.A.C.K., a backpack that gives + you two extra hands when worn. Unlocked with a T2 arsenal research and printable + at the protolathe and secfab.' + type: Fix + id: 8749 + time: '2025-07-07T21:43:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38824