diff --git a/Content.Server/AI/EntitySystems/GoToPuddleSystem.cs b/Content.Server/AI/EntitySystems/GoToPuddleSystem.cs new file mode 100644 index 0000000000..c9816aba27 --- /dev/null +++ b/Content.Server/AI/EntitySystems/GoToPuddleSystem.cs @@ -0,0 +1,20 @@ +using Content.Server.Fluids.Components; + +namespace Content.Server.AI.EntitySystems +{ + public sealed class GoToPuddleSystem : EntitySystem + { + [Dependency] private readonly EntityLookupSystem _lookup = default!; + + public EntityUid GetNearbyPuddle(EntityUid cleanbot, float range = 10) + { + foreach (var entity in _lookup.GetEntitiesInRange(cleanbot, range)) + { + if (HasComp(entity)) + return entity; + } + + return default; + } + } +} diff --git a/Content.Server/AI/Utility/Actions/Bots/GoToPuddleAndWait.cs b/Content.Server/AI/Utility/Actions/Bots/GoToPuddleAndWait.cs new file mode 100644 index 0000000000..d9dff3f0e5 --- /dev/null +++ b/Content.Server/AI/Utility/Actions/Bots/GoToPuddleAndWait.cs @@ -0,0 +1,50 @@ +using Content.Server.AI.Operators; +using Content.Server.AI.Operators.Generic; +using Content.Server.AI.Operators.Movement; +using Content.Server.AI.WorldState; +using Content.Server.AI.Utility.Considerations.Containers; +using Content.Server.AI.Utility.Considerations; +using Content.Server.AI.Utility.Considerations.ActionBlocker; +using Content.Server.AI.WorldState.States.Movement; +using Content.Server.AI.WorldState.States; + +namespace Content.Server.AI.Utility.Actions.Bots +{ + public sealed class GoToPuddleAndWait : UtilityAction + { + public EntityUid Target { get; set; } = default!; + + public override void SetupOperators(Blackboard context) + { + MoveToEntityOperator moveOperator = new MoveToEntityOperator(Owner, Target, 0, 0); + float waitTime = 3f; + + ActionOperators = new Queue(new AiOperator[] + { + moveOperator, + new WaitOperator(waitTime), + }); + } + + protected override void UpdateBlackboard(Blackboard context) + { + base.UpdateBlackboard(context); + context.GetState().SetValue(Target); + context.GetState().SetValue(Target); + // Can just set ourselves as entity given unarmed just inherits from meleeweapon + } + + protected override IReadOnlyCollection> GetConsiderations(Blackboard context) + { + var considerationsManager = IoCManager.Resolve(); + + return new[] + { + considerationsManager.Get() + .BoolCurve(context), + considerationsManager.Get() + .BoolCurve(context), + }; + } + } +} diff --git a/Content.Server/AI/Utility/ExpendableActions/Bots/BufferNearbyPuddlesExp.cs b/Content.Server/AI/Utility/ExpendableActions/Bots/BufferNearbyPuddlesExp.cs new file mode 100644 index 0000000000..d3cff226ec --- /dev/null +++ b/Content.Server/AI/Utility/ExpendableActions/Bots/BufferNearbyPuddlesExp.cs @@ -0,0 +1,40 @@ +using Content.Server.AI.Components; +using Content.Server.AI.EntitySystems; +using Content.Server.AI.Utility.Actions; +using Content.Server.AI.Utility.Actions.Bots; +using Content.Server.AI.Utility.Considerations; +using Content.Server.AI.Utility.Considerations.Combat.Melee; +using Content.Server.AI.WorldState; +using Content.Server.AI.WorldState.States; +using Content.Server.AI.Utility.Considerations.ActionBlocker; + + + +namespace Content.Server.AI.Utility.ExpandableActions.Bots +{ + public sealed class BufferNearbyPuddlesExp : ExpandableUtilityAction + { + public override float Bonus => 30; + + protected override IReadOnlyCollection> GetCommonConsiderations(Blackboard context) + { + var considerationsManager = IoCManager.Resolve(); + + return new[] + { + considerationsManager.Get() + .BoolCurve(context), + }; + } + public override IEnumerable GetActions(Blackboard context) + { + var owner = context.GetState().GetValue(); + if (!IoCManager.Resolve().TryGetComponent(owner, out AiControllerComponent? controller)) + { + throw new InvalidOperationException(); + } + + yield return new GoToPuddleAndWait() {Owner = owner, Target = EntitySystem.Get().GetNearbyPuddle(Owner), Bonus = Bonus}; + } + } +} diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index c815ea8c96..b7fd334b12 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -128,3 +128,31 @@ makeSentient: true name: honkbot description: An artificial being of pure evil. + +- type: entity + parent: MobSiliconBase + id: MobCleanBot + name: cleanbot + description: The creep of automation now threatening space janitors. + components: + - type: Sprite + drawdepth: Mobs + sprite: Mobs/Silicon/Bots/cleanbot.rsi + state: cleanbot + - type: UtilityAI + behaviorSets: + - CleanBot + - type: Drain + range: 1 + unitsDestroyedPerSecond: 6 + - type: Construction + graph: CleanBot + node: bot + - type: SentienceTarget + flavorKind: mechanical + - type: SolutionContainerManager + solutions: + drainBuffer: + maxVol: 30 + - type: DrainableSolution + solution: drainBuffer diff --git a/Resources/Prototypes/NPCs/behavior_sets.yml b/Resources/Prototypes/NPCs/behavior_sets.yml index 481df2f256..a930c4b2fb 100644 --- a/Resources/Prototypes/NPCs/behavior_sets.yml +++ b/Resources/Prototypes/NPCs/behavior_sets.yml @@ -27,6 +27,12 @@ actions: - MoveRightAndLeftTen +- type: behaviorSet + id: CleanBot + actions: + - BufferNearbyPuddlesExp + - WanderAndWait + - type: behaviorSet id: Spirate actions: @@ -43,4 +49,4 @@ - type: behaviorSet id: UnarmedAttackHostiles actions: - - UnarmedAttackNearbyHostilesExp \ No newline at end of file + - UnarmedAttackNearbyHostilesExp diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/cleanbot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/cleanbot.yml new file mode 100644 index 0000000000..18282891a0 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/cleanbot.yml @@ -0,0 +1,27 @@ +- type: constructionGraph + id: CleanBot + start: start + graph: + - node: start + edges: + - to: bot + steps: + - prototype: Bucket + icon: + sprite: Objects/Tools/bucket.rsi + state: icon + name: bucket + - prototype: ProximitySensor + icon: + sprite: Objects/Misc/proximity_sensor.rsi + state: icon + name: promixmity sensor + doAfter: 2 + - tag: BorgArm + icon: + sprite: Mobs/Silicon/drone.rsi + state: l_hand + name: borg arm + doAfter: 2 + - node: bot + entity: MobCleanBot diff --git a/Resources/Prototypes/Recipes/Crafting/bots.yml b/Resources/Prototypes/Recipes/Crafting/bots.yml index 24d70aa503..e6abeaa012 100644 --- a/Resources/Prototypes/Recipes/Crafting/bots.yml +++ b/Resources/Prototypes/Recipes/Crafting/bots.yml @@ -1,3 +1,16 @@ +- type: construction + name: cleanbot + id: cleanbot + graph: CleanBot + startNode: start + targetNode: bot + category: Utilities + objectType: Item + description: This bot wanders around the station, mopping up any puddles it sees. + icon: + sprite: Mobs/Silicon/Bots/cleanbot.rsi + state: cleanbot + - type: construction name: honkbot id: honkbot diff --git a/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/cleanbot.png b/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/cleanbot.png new file mode 100644 index 0000000000..e64cae9af2 Binary files /dev/null and b/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/cleanbot.png differ diff --git a/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/meta.json b/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/meta.json new file mode 100644 index 0000000000..39a961b104 --- /dev/null +++ b/Resources/Textures/Mobs/Silicon/Bots/cleanbot.rsi/meta.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/commit/53d1f1477d22a11a99c6c6924977cd431075761b", + "states": [ + { + "name": "cleanbot", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + } + ] +}