From 6c620f45dc2ceeea71fed82efdc17467e37603ef Mon Sep 17 00:00:00 2001 From: PHCodes <47927305+PHCodes@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:04:34 -0400 Subject: [PATCH 1/2] Butlertron, the Roboisseur (#193) * Butlertron, the Robossieur "Greetings meatbags! This is Butlertron_Durandal, the latest in entrepreneurship technology! I have heard word that you all staff an exorbiant number of fleshlings to prepare food and drink aboard your stations. With my latest contract with your station owners, I am prepared and willing to deploy terminals to every station in the cosmos! I hope you all are ready, because there is a great deal of money to be made if you can source the dishes my discerning clientele desire." Implements the new entity type 'Mr. Butlertron'. Mr. Butlertron requests specific foods from players, using the list of recipes available to the game. He has a blacklist of items he will not request, which fundamentally make up three categories: Simple, Disgusting, and Cannibalistic. He also has 3 tiers of foods he can request, and could be iterated upon in the future to add more tiers. Each tier increases the amount of zorkmids he will give in payment, and from the 2nd tier of food onward, he will dispense ice cream along with his dough. Take too long, however, and this affable automaton will begin to become upset, and may even lose his temper entirely, changing his request to something new. This change occurs after 10 minutes, and he begins getting impatient after 8 minutes have passed. I reused several of the scripts used by the Oracle to create Mr. Butlertron, and am hoping in the future to make him a roaming NPC, perhaps by splitting up his responsibilities into different chunks and having different 'styles' of Mr. Butlertron being able to spawn on different stations. Given that Delta-V does not have a significant amount of its own unique content and folders to support that unique content, I placed most of his files within Nyano's files. Maybe this is not how it should be structure, and I open to suggestions. * Changed a folder name. I spelled my funny made up french word wrong on one folder name. Shouldn't affect anything anywhere, since .ftl folders aren't used anywhere either way. * Update Content.Server/Nyanotrasen/Roboisseur/RoboisseurComponent.cs Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> * Update Content.Server/Nyanotrasen/Roboisseur/RoboisseurComponent.cs Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> * Apply line breaks and code from Death's code review Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> * Code review comment addressing. All code review comments addressed. * Apply suggestions from code review relating to spacing, again, and indefinite tagging. Very cool. Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> * Butlertron Testing and Data Field Addition Done. --------- Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> --- .../NPC/Roboisseur/RoboisseurComponent.cs | 223 ++++++++++++++++++ .../DeltaV/NPC/Roboisseur/RoboisseurSystem.cs | 186 +++++++++++++++ .../en-US/deltav/roboisseur/roboisseur.ftl | 25 ++ .../Prototypes/DeltaV/NPC/roboisseur.yml | 20 ++ .../Machines/roboisseur.rsi/meta.json | 29 +++ .../Machines/roboisseur.rsi/roboisseur-1.png | Bin 0 -> 687 bytes .../Machines/roboisseur.rsi/roboisseur-2.png | Bin 0 -> 677 bytes .../Machines/roboisseur.rsi/roboisseur-3.png | Bin 0 -> 686 bytes .../Machines/roboisseur.rsi/roboisseur-4.png | Bin 0 -> 680 bytes .../roboisseur.rsi/roboisseur-impatient1.png | Bin 0 -> 749 bytes .../roboisseur.rsi/roboisseur-impatient2.png | Bin 0 -> 739 bytes 11 files changed, 483 insertions(+) create mode 100644 Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs create mode 100644 Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs create mode 100644 Resources/Locale/en-US/deltav/roboisseur/roboisseur.ftl create mode 100644 Resources/Prototypes/DeltaV/NPC/roboisseur.yml create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/meta.json create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-1.png create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-2.png create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-3.png create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-4.png create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-impatient1.png create mode 100644 Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-impatient2.png diff --git a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs new file mode 100644 index 00000000000..97fde3f70dd --- /dev/null +++ b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs @@ -0,0 +1,223 @@ +using Robust.Shared.Prototypes; + +namespace Content.Server.Roboisseur.Roboisseur +{ + [RegisterComponent] + public sealed class RoboisseurComponent : Component + { + [ViewVariables] + [DataField("accumulator")] + public float Accumulator = 0f; + + [ViewVariables(VVAccess.ReadOnly)] + [DataField("impatient")] + public Boolean Impatient { get; set; } = false; + + [ViewVariables] + [DataField("resetTime")] + public TimeSpan ResetTime = TimeSpan.FromMinutes(10); + + [DataField("barkAccumulator")] + public float BarkAccumulator = 0f; + + [DataField("barkTime")] + public TimeSpan BarkTime = TimeSpan.FromMinutes(1); + + [ViewVariables(VVAccess.ReadWrite)] + public EntityPrototype DesiredPrototype = default!; + + [DataField("demandMessages")] + public IReadOnlyList DemandMessages = new[] + { + "roboisseur-request-1", + "roboisseur-request-2", + "roboisseur-request-3", + "roboisseur-request-4", + "roboisseur-request-5", + "roboisseur-request-6" + }; + + [DataField("impatientMessages")] + public IReadOnlyList ImpatientMessages = new[] + { + "roboisseur-request-impatient-1", + "roboisseur-request-impatient-2", + "roboisseur-request-impatient-3", + }; + + [DataField("demandMessagesTier2")] + public IReadOnlyList DemandMessagesTier2 = new[] + { + "roboisseur-request-second-1", + "roboisseur-request-second-2", + "roboisseur-request-second-3" + }; + + [DataField("rewardMessages")] + public IReadOnlyList RewardMessages = new[] + { + "roboisseur-thanks-1", + "roboisseur-thanks-2", + "roboisseur-thanks-3", + "roboisseur-thanks-4", + "roboisseur-thanks-5" + }; + + [DataField("rewardMessagesTier2")] + public IReadOnlyList RewardMessagesTier2 = new[] + { + "roboisseur-thanks-second-1", + "roboisseur-thanks-second-2", + "roboisseur-thanks-second-3", + "roboisseur-thanks-second-4", + "roboisseur-thanks-second-5" + }; + + [DataField("rejectMessages")] + public IReadOnlyList RejectMessages = new[] + { + "roboisseur-deny-1", + "roboisseur-deny-2", + "roboisseur-deny-3" + }; + + [DataField("tier2Protos")] + public List Tier2Protos = new() + { + "FoodBurgerEmpowered", + "FoodSoupClown", + "FoodSoupChiliClown", + "FoodBurgerSuper", + "FoodNoodlesCopy", + "FoodMothMallow", + "FoodPizzaCorncob", + "FoodPizzDonkpocket", + "FoodSoupMonkey", + "FoodMothSeedSoup", + "FoodTartGrape", + "FoodMealCubancarp", + "FoodMealSashimi", + "FoodBurgerCarp", + "FoodMealTaco", + "FoodMothMacBalls", + "FoodSoupNettle", + "FoodBurgerDuck", + "FoodBurgerBaseball" + }; + + [DataField("tier3Protos")] + public List Tier3Protos = new() + { + "FoodBurgerGhost", + "FoodSaladWatermelonFruitBowl", + "FoodBakedCannabisBrownieBatch", + "FoodPizzaDank", + "FoodBurgerBear", + "FoodBurgerMime", + "FoodCakeSuppermatter", + "FoodSoupChiliCold", + "FoodSoupBisque", + "FoodCakeSlime", + "FoodBurgerCrazy" + }; + + [DataField("robossuierRewards")] + public IReadOnlyList RobossuierRewards = new[] + { + "DrinkIceCreamGlass", + "FoodFrozenPopsicleOrange", + "FoodFrozenPopsicleBerry", + "FoodFrozenPopsicleJumbo", + "FoodFrozenSnowconeBerry", + "FoodFrozenSnowconeFruit", + "FoodFrozenSnowconeClown", + "FoodFrozenSnowconeMime", + "FoodFrozenSnowconeRainbow", + "FoodFrozenCornuto", + "FoodFrozenSundae", + "FoodFrozenFreezy", + "FoodFrozenSandwichStrawberry", + "FoodFrozenSandwich", + }; + + [DataField("blacklistedProtos")] + public IReadOnlyList BlacklistedProtos = new[] + { + "FoodMothPesto", + "FoodBurgerSpell", + "FoodBreadBanana", + "FoodMothSqueakingFry", + "FoodMothFleetSalad", + "FoodBreadMeatSpider", + "FoodBurgerHuman", + "FoodNoodlesBoiled", + "FoodMothOatStew", + "FoodMeatLizardtailKebab", + "FoodSoupTomato", + "FoodDonkpocketGondolaWarm", + "FoodDonkpocketBerryWarm", + "LockboxDecloner", + "FoodBreadButteredToast", + "FoodMothCottonSoup", + "LeavesTobaccoDried", + "FoodSoupEyeball", + "FoodMothKachumbariSalad", + "FoodMeatHumanKebab", + "FoodMeatRatdoubleKebab", + "FoodBurgerCorgi", + "FoodBreadPlain", + "FoodMeatKebab", + "FoodBreadBun", + "FoodBurgerCat", + "FoodSoupTomatoBlood", + "FoodMothSaladBase", + "FoodPieXeno", + "FoodDonkpocketTeriyakiWarm", + "FoodMothBakedCheese", + "FoodMothTomatoSauce", + "FoodMothPizzaCotton", + "AloeCream", + "FoodSnackPopcorn", + "FoodBurgerSoy", + "FoodMothToastedSeeds", + "FoodMothCornmealPorridge", + "FoodMothBakedCorn", + "FoodBreadMoldySlice", + "FoodRiceBoiled", + "FoodMothEyeballSoup", + "FoodMeatRatKebab", + "FoodBreadCreamcheese", + "FoodSoupOnion", + "FoodBurgerAppendix", + "FoodBurgerRat", + "RegenerativeMesh", + "FoodCheeseCurds", + "FoodDonkpocketHonkWarm", + "FoodOatmeal", + "FoodBreadJellySlice", + "FoodMothCottonSalad", + "FoodBreadMoldy", + "FoodDonkpocketSpicyWarm", + "FoodCannabisButter", + "FoodNoodles", + "FoodBreadMeat", + "LeavesCannabisDried", + "FoodBurgerCheese", + "FoodDonkpocketDankWarm", + "FoodSpaceshroomCooked", + "FoodMealFries", + "MedicatedSuture", + "FoodDonkpocketWarm", + "FoodCakePlain", + "DisgustingSweptSoup", + "FoodBurgerPlain", + "FoodBreadGarlicSlice", + "FoodSoupMushroom", + "FoodSoupWingFangChu", + "FoodBreadMeatXeno", + "FoodCakeBrain", + "FoodBurgerBrain", + "FoodSaladCaesar" + }; + } +} diff --git a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs new file mode 100644 index 00000000000..40d49fc4c05 --- /dev/null +++ b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs @@ -0,0 +1,186 @@ +using Content.Shared.Interaction; +using Content.Shared.Mobs.Components; +using Content.Server.Chat.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Content.Shared.Random.Helpers; +using Content.Shared.Kitchen; +using Robust.Server.GameObjects; +using Content.Server.Materials; + +namespace Content.Server.Roboisseur.Roboisseur +{ + public sealed partial class RoboisseurSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly MaterialStorageSystem _material = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + + + public override void Initialize() + { + base.Initialize(); + + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnInteractUsing); + } + + + private void OnInit(EntityUid uid, RoboisseurComponent component, ComponentInit args) + { + NextItem(component); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + + foreach (var roboisseur in EntityQuery()) + { + roboisseur.Accumulator += frameTime; + roboisseur.BarkAccumulator += frameTime; + if (roboisseur.BarkAccumulator >= roboisseur.BarkTime.TotalSeconds) + { + roboisseur.BarkAccumulator = 0; + string message = Loc.GetString(_random.Pick(roboisseur.DemandMessages), ("item", roboisseur.DesiredPrototype.Name)); + if (roboisseur.ResetTime.TotalSeconds - roboisseur.Accumulator < 120) + { + roboisseur.Impatient = true; + message = Loc.GetString(_random.Pick(roboisseur.ImpatientMessages), ("item", roboisseur.DesiredPrototype.Name)); + } + else if (CheckTier(roboisseur.DesiredPrototype.ID, roboisseur) > 2) + message = Loc.GetString(_random.Pick(roboisseur.DemandMessagesTier2), ("item", roboisseur.DesiredPrototype.Name)); + _chat.TrySendInGameICMessage(roboisseur.Owner, message, InGameICChatType.Speak, false); + } + + if (roboisseur.Accumulator >= roboisseur.ResetTime.TotalSeconds) + { + roboisseur.Impatient = false; + NextItem(roboisseur); + } + } + } + + private void RewardServicer(EntityUid uid, RoboisseurComponent component, int tier) + { + var r = new Random(); + int rewardToDispense = r.Next(100, 350) + 250 * tier; + + _material.SpawnMultipleFromMaterial(rewardToDispense, "Credit", Transform(uid).Coordinates); + if(tier > 1) + { + while (tier != 0) + { + EntityManager.SpawnEntity(_random.Pick(component.RobossuierRewards), Transform(uid).Coordinates); + tier--; + } + } + return; + } + + private void OnInteractHand(EntityUid uid, RoboisseurComponent component, InteractHandEvent args) + { + if (!TryComp(args.User, out var actor)) + return; + + string message = Loc.GetString(_random.Pick(component.DemandMessages), ("item", component.DesiredPrototype.Name)); + if (CheckTier(component.DesiredPrototype.ID, component) > 1) + message = Loc.GetString(_random.Pick(component.DemandMessagesTier2), ("item", component.DesiredPrototype.Name)); + + _chat.TrySendInGameICMessage(component.Owner, message, InGameICChatType.Speak, false); + } + + private void OnInteractUsing(EntityUid uid, RoboisseurComponent component, InteractUsingEvent args) + { + if (HasComp(args.Used) || + MetaData(args.Used)?.EntityPrototype == null) + return; + + var validItem = CheckValidity(MetaData(args.Used).EntityName, component.DesiredPrototype); + var nextItem = true; + + if (!validItem) + { + _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(component.RejectMessages)), InGameICChatType.Speak, true); + return; + } + + component.Impatient = false; + EntityManager.QueueDeleteEntity(args.Used); + + int tier = CheckTier(component.DesiredPrototype.ID, component); + + string message = Loc.GetString(_random.Pick(component.RewardMessages)); + if (tier > 1) + message = Loc.GetString(_random.Pick(component.RewardMessagesTier2)); + _chat.TrySendInGameICMessage(uid, message, InGameICChatType.Speak, true); + + RewardServicer(args.User, component, tier); + + if (nextItem) + NextItem(component); + } + + private bool CheckValidity(String name, EntityPrototype target) + { + // 1: directly compare Names + // name instead of ID because the oracle asks for them by name + // this could potentially lead to like, labeller exploits maybe but so far only mob names can be fully player-set. + if (name == target.Name) + return true; + + return false; + } + + private int CheckTier(String target, RoboisseurComponent component) + { + if (component.Tier2Protos.Contains(target)) + return 2; + if (component.Tier3Protos.Contains(target)) + return 3; + return 1; + } + + private void NextItem(RoboisseurComponent component) + { + component.Accumulator = 0; + component.BarkAccumulator = 0; + var protoString = GetDesiredItem(component); + + if (_prototypeManager.TryIndex(protoString, out var proto)) + component.DesiredPrototype = proto; + else + Log.Error("Roboisseur can't index prototype " + protoString); + } + + private string GetDesiredItem(RoboisseurComponent component) + { + return _random.Pick(GetAllProtos(component)); + } + + public List GetAllProtos(RoboisseurComponent component) + { + + var allRecipes = _prototypeManager.EnumeratePrototypes(); + var allProtos = new List(); + + foreach (var recipe in allRecipes) + allProtos.Add(recipe.Result); + + foreach (var proto in component.BlacklistedProtos) + allProtos.Remove(proto); + + return allProtos; + } + } + + public enum RobossieurVisualLayers : byte + { + Angry + } +} diff --git a/Resources/Locale/en-US/deltav/roboisseur/roboisseur.ftl b/Resources/Locale/en-US/deltav/roboisseur/roboisseur.ftl new file mode 100644 index 00000000000..c24c3dc2599 --- /dev/null +++ b/Resources/Locale/en-US/deltav/roboisseur/roboisseur.ftl @@ -0,0 +1,25 @@ +roboisseur-request-1 = I humbly request one {$item} for my wealthiest client. +roboisseur-request-2 = Oodles of dough await you, for a nice {$item}! +roboisseur-request-3 = There may be an exorbitantly affluent personage in this sector looking for {INDEFINITE($item)} {$item}. +roboisseur-request-4 = My more... Adventurous Clients require {INDEFINITE($item)} {$item}. +roboisseur-request-5 = {$item}. It's rare. It's valuable. You can make it, yes? +roboisseur-request-6 = Local changes in this quadrant's stock exchange decteted. Seeking {INDEFINITE($item)} {$item}. +roboisseur-request-impatient-1 = There is no time left! Bring me {THE($item)}, immediately! +roboisseur-request-impatient-2 = My market opportunity is dwindling! Quickly, you fools, {THE($item)}! +roboisseur-request-impatient-3 = Damn you all! Deliver me {INDEFINITE($item)} {$item} already! +roboisseur-request-second-1 = I humbly request one {$item} for one of my snowbound clients. +roboisseur-request-second-2 = The frozen planet in this sector requests {INDEFINITE($item)} {$item}! +roboisseur-request-second-3 = A local ice cream vendor is looking to trade for {INDEFINITE($item)} {$item}. +roboisseur-thanks-1 = Mmm, I'm sure my client will be most pleased. +roboisseur-thanks-2 = I cannot believe you were able to source it, but I suppose you are the best. +roboisseur-thanks-3 = When I first heard there were such skilled creatives on this station, I was shocked. My thanks. +roboisseur-thanks-4 = Unlike... most of your coworkers, my clients can afford these delicacies! +roboisseur-thanks-5 = You have my word, my nominal fees are... more than reasonable. +roboisseur-thanks-second-1 = You shared your hopsitality, now they share their frozen delights. +roboisseur-thanks-second-2 = A cold, sweet treat should be reward enough, but have some cold, hard cash too. +roboisseur-thanks-second-3 = While the iced delicacy alone is currency to them, they understand your needs. +roboisseur-thanks-second-4 = Summer on their planet lasts for only two weeks. You have their thanks. +roboisseur-thanks-second-5 = My client's pockets are as deep as their world is cold. +roboisseur-deny-1 = Kindly prepare the correct item. +roboisseur-deny-2 = This is not what we agreed. +roboisseur-deny-3 = Not what the client's looking for. diff --git a/Resources/Prototypes/DeltaV/NPC/roboisseur.yml b/Resources/Prototypes/DeltaV/NPC/roboisseur.yml new file mode 100644 index 00000000000..2c0b3aee8a0 --- /dev/null +++ b/Resources/Prototypes/DeltaV/NPC/roboisseur.yml @@ -0,0 +1,20 @@ +- type: entity + parent: BaseStructure + id: Roboisseur + name: Mr. Butlertron + description: It asks for food to deliver to exotic customers across the cosmos. Powered by the latest technology in bluespace food delivery. + components: + - type: Sprite + noRot: true + drawdepth: Mobs + sprite: DeltaV/Structures/Machines/roboisseur.rsi + layers: + - state: roboisseur-1 + - type: Roboisseur + - type: Speech + speechSounds: Pai + - type: Appearance + - type: Grammar + attributes: + gender: male + proper: true diff --git a/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/meta.json b/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/meta.json new file mode 100644 index 00000000000..97d0e5f4bac --- /dev/null +++ b/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "JustAnOrange", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "roboisseur-1" + }, + { + "name": "roboisseur-2" + }, + { + "name": "roboisseur-3" + }, + { + "name": "roboisseur-4" + }, + { + "name": "roboisseur-impatient1" + }, + { + "name": "roboisseur-impatient2" + } + ] +} diff --git a/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-1.png b/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-1.png new file mode 100644 index 0000000000000000000000000000000000000000..454e6dd065a045adb6ba99d392fdff75e1f3c4c6 GIT binary patch literal 687 zcmV;g0#N;lP)Px%Pf0{UR9J=WmOp3{VHn1LN{=KCnbj0pQ2oE6de|xiv5AoE8zUudZmxTv3xtwRFE>bzyEzF4fY> zTv1zJUD3P*aUH<;ESGBOWGbg6Q#nm8)zZT>ZkX^I=BNW}gWV8C=oSnzuKCyjjC+4< z0seaj6s1l+lQkzjw6Rr4=878V!G+aZLPR@rK199u5F-{+wjdefio0;8Uyn#~M2aDo;MX8R{i81B2%CvY&a`Z>brY ze)CZ{9z;6_DrYBsY#&BAvnKf)|f#VF^zkFQ-_}udootg#Us!txOHO%Y#O)g5m zEZ6L2KPx%MM*?KR9J=Wlrd-%Q5eU6l^#i!Hl@o!!^H&@F`3pq_Mh z0NW5iOXxyN=#JW731HK&?Xm%+uArCRs~Cl`0@!!|&jK7q2PS32hEXA%Oo?bT!p+-v zCN#Yuc=iDxm(ON|VN@`Tid29JDfI#AWJ&-;qmfQ9fO`+_kF?*&q?0LOhZz;m#CMl3 zISgW<005^>Dh}P3uWbN6)my*qv9)LN=;Q0YUQ$EYYrd%ZSycUwnyu+JAB5)+ZtaXW+)Uivr+t+fQVA9)R;cwXfDTuk6-1qx^KNxy^voJ5brJ z5t*Lv7`bU=kP0AcaAD;#a0oNd&DB>=Ah7~-@qx8rk(z-Hb8*-%IfXs7?ir}JOkS4W zjsFgG=rwn%9heWoa|Y@ylTg4%yKTL6ilVr;db`xop?I6akR7PEOd8E9fMwv)0o%OM ztPW)kl7B&?S!FgDwv4_NT{SXD|AyTLv%&B{)9bgc0r2$U^YH`3W`cdHKdc~q*M>v7 z12Whr4+VUG(&mWq_yx~O0t`D>tQ`OV01jnXNoGw=04e|g00;m8000000Mb*F00000 LNkvXXu0mjfL%=jR literal 0 HcmV?d00001 diff --git a/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-3.png b/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-3.png new file mode 100644 index 0000000000000000000000000000000000000000..fbcb190fba52f1abd8ee6e2db6745c1508d4fa09 GIT binary patch literal 686 zcmV;f0#W^mP)Px%PDw;TR9J=WmOp3{VHn1LYLBE#+n}_x7)y!P8;o7*pE#-za8q0ybi2;U7KBXh zRp^#1ML{zZhk}Db1;N4Akflq|9zjzRB8{e9;*r8RBwx&(N$$Q&wM&0f?#pxE^W1yy zy?1cLA#=>@iE6f>1yXSv}i^W8B@&`v`)kP{7hQS7PLqr zV=gZ(nqGpq4j_K3*@6~{Cd^1QVXE1J)=lGvA+KRt6-e8wA&b;4ursLnzyZX)KePb< zy#l&kBpHjhJ3X+no{A(gCN!Hb8H<~`UX%*pX$~Y~aT6dE3bum*JbLoj^IY*nG8Q*Q z7_T@cet7ei#b9<~7=Yeu$fnyImxO~F|_}uUl9GwKDqrEXBImHrsm&0B$ld9_w@We$>0LA6%mPx%NJ&INR9J=Wls{+_Q5?rVl^#i!{-Ki4V3ZOKw}dWLyj2SU9Yi;Wic8&u#OV++ zxkn+JS%QLQ5Ql<;f`Z_nQnGXj+M{S{LZp$jgYih=IV2Zz@shijR7L1#yWjirzTfwI zzk6`V|A@N2wF;o=1)=E$(OZ+{h>SR&%?M2|h|__(MUHKz@2+{N7`>>(#e#t!iv?~*oA$y-WjMhO`dPO z8UG#V(r-Sf)-fN3>kQPICZT|jR;&HeDN5%B>~D7`fTcrmHwTX$s5MRMjmj?rr@Icu zyXN&q#gjQm{sr|$g}Iq9tuMu)8X2U2!(M~Aneb54t2eFy@c91I@dLzWXB?{E+d&-H zydm8I8LX3s0=_?KbI5r71ToP46AI%3@&Et;4rN$LW=%~1DgXcg2mk;800000(o>TF O0000Px%jY&j7R9J=WmQP4jQ5431mBWlh+E5@y8ag#S0-cTh8OV(ZMg>8*D57@Hg{v9d z48p8}mKF%Ja5hpzvyc`-P>Y1Hg~lM5Bvbhua%2XRN7=g8y`z|Zb0J+Zc?u$4H6%{UJa4yfKhM3tg(c_(44 zttl);f3JX|BnbNaxlVVEOb&Si5f!xN3;O)3q9jZSuyhXueSQ_dRzyi-~LufDb9no*Gq{8dY?2!lzv30%d#P(dFwZ!1qlD4Yl-o~%2SBDz=JrE_8%-S?7!SI;OqO7mxnYk-wYyX#FN!%4A8e zCIMKS9xUl6*3zrVvY88*>H#6**vVD^HqxI9Y~f=RrjKEIHJKx6blm`8L3vx$_kPb^ z0A3Bfu3UiId7^M~Wuo+&L0JAPHUg1(UA28LX%0{s{sIxf3kQZ6=`H{O01jnXNoGw= f04e|g00;m8000000Mb*F00000NkvXXu0mjf(H=yB literal 0 HcmV?d00001 diff --git a/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-impatient2.png b/Resources/Textures/DeltaV/Structures/Machines/roboisseur.rsi/roboisseur-impatient2.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6e6ee2521bd57b47df543cd7d73352138b20ce GIT binary patch literal 739 zcmV<90v!E`P)Px%gGod|R9J=Wl|e|8VHn4MmSb9^Nr4#6(A64&da>w(b}?a5K@c5^D7vhJ5X`)M z2s;HGEg0<3E~AKchz>$fhlH?$g$O3eDnBJRHUuXs*cuvdhxrb_xw*ZY7J>iM`#j&D z=l_46_xZjLcJV*LIXdG3(Dbm-^sv~NQ^g(?a>zd*G(9XLoh`wQg3i$yPo%RYsOe!5 z@(+k|jFfCZ3Ib?uU1)CIl=~|NB=U`2)qv6!1KTlyY8A3!MDclh zh23uB&b|9pnjRLs{0I;X`3HnyL@|u0l7T8E_BwptUIAdY+p@+09z1?jR=u*}^Y#j9 zrd$+t+~0lCB;aVQ1>jh-#l-tDy9&U!xzwf_vE?*RKfTMVrL=^(;vLQ!I-E78oaAg2 z-wH*SFt(iLXq}a*wIdv!cLLC6u>#O=+73Wn!T?}lJ|i}@7U6hx9LJSz9Kg`C*9GgB zGy&PgNIC+*`$Q%l8#EXjG)y_kDb~3}(H*#b=DYy-zFLE=z6pS{*32ZvA6^Hbqd#mC zk1i!RVfkgMQ)ma2z5~&v1h)DnzFg}AAl2vLz|CMb=DCOHQbMJqngIYyyN}7h((V;8+KqPp)`S3S0LMMzIb}L$CQ(u&!q}4WW^I`bp@hTxfg(wT|raVxn{l&WqyvQ_Wd@Azn%C{{+Dnrl_t3u2Ou`?FUXV6 zl8f=8ol7X~fHblHP&)uC$P6_}3 literal 0 HcmV?d00001 From bb7b6855f1696311316102e3d37e20485f5c40c2 Mon Sep 17 00:00:00 2001 From: Debug Date: Fri, 29 Sep 2023 13:51:55 +0200 Subject: [PATCH 2/2] Make RoboisseurComponent partial --- Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs index 97fde3f70dd..5fcb2601e1f 100644 --- a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs +++ b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurComponent.cs @@ -3,7 +3,7 @@ namespace Content.Server.Roboisseur.Roboisseur { [RegisterComponent] - public sealed class RoboisseurComponent : Component + public sealed partial class RoboisseurComponent : Component { [ViewVariables] [DataField("accumulator")]