From 3b682d4d68c82b218a3727961241e519a91677f1 Mon Sep 17 00:00:00 2001 From: Golinth Date: Mon, 30 Sep 2024 22:13:16 -0500 Subject: [PATCH] Added Firebots - Real (#32482) * Add Firebots Had to add OnActivateInWorld to the spray system to get the bot to work. Checks for the flammable component and if the onFire boolean is true. * Make SpraySystem actually use useDelay got rid of that TODO * Added firebot speech Fire detected! --- .../Fluids/EntitySystems/SpraySystem.cs | 48 ++++++++++++------ .../Queries/Considerations/TargetOnFireCon.cs | 9 ++++ .../NPC/Systems/NPCUtilitySystem.cs | 7 +++ .../interaction-popup-component.ftl | 2 + Resources/Locale/en-US/npc/firebot.ftl | 1 + .../Entities/Clothing/Head/helmets.yml | 2 + .../Prototypes/Entities/Mobs/NPCs/silicon.yml | 47 +++++++++++++++++ .../Objects/Misc/fire_extinguisher.yml | 3 ++ Resources/Prototypes/NPCs/firebot.yml | 44 ++++++++++++++++ Resources/Prototypes/NPCs/utility_queries.yml | 21 ++++++++ .../Recipes/Crafting/Graphs/bots/firebot.yml | 33 ++++++++++++ .../Prototypes/Recipes/Crafting/bots.yml | 13 +++++ Resources/Prototypes/tags.yml | 6 +++ .../Mobs/Silicon/Bots/firebot.rsi/firebot.png | Bin 0 -> 4614 bytes .../Mobs/Silicon/Bots/firebot.rsi/meta.json | 20 ++++++++ 15 files changed, 241 insertions(+), 15 deletions(-) create mode 100644 Content.Server/NPC/Queries/Considerations/TargetOnFireCon.cs create mode 100644 Resources/Locale/en-US/npc/firebot.ftl create mode 100644 Resources/Prototypes/NPCs/firebot.yml create mode 100644 Resources/Prototypes/Recipes/Crafting/Graphs/bots/firebot.yml create mode 100644 Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/firebot.png create mode 100644 Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/meta.json diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs index fe179be402..a1f195bf43 100644 --- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs +++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs @@ -14,6 +14,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; using System.Numerics; +using Robust.Shared.Map; namespace Content.Server.Fluids.EntitySystems; @@ -35,6 +36,19 @@ public sealed class SpraySystem : EntitySystem base.Initialize(); SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnActivateInWorld); + } + + private void OnActivateInWorld(Entity entity, ref UserActivateInWorldEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + var targetMapPos = _transform.GetMapCoordinates(GetEntityQuery().GetComponent(args.Target)); + + Spray(entity, args.User, targetMapPos); } private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) @@ -44,29 +58,36 @@ public sealed class SpraySystem : EntitySystem args.Handled = true; + var clickPos = _transform.ToMapCoordinates(args.ClickLocation); + + Spray(entity, args.User, clickPos); + } + + public void Spray(Entity entity, EntityUid user, MapCoordinates mapcoord) + { if (!_solutionContainer.TryGetSolution(entity.Owner, SprayComponent.SolutionName, out var soln, out var solution)) return; - var ev = new SprayAttemptEvent(args.User); + var ev = new SprayAttemptEvent(user); RaiseLocalEvent(entity, ref ev); if (ev.Cancelled) return; - if (!TryComp(entity, out var useDelay) - || _useDelay.IsDelayed((entity, useDelay))) + if (TryComp(entity, out var useDelay) + && _useDelay.IsDelayed((entity, useDelay))) return; if (solution.Volume <= 0) { - _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, args.User); + _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, user); return; } var xformQuery = GetEntityQuery(); - var userXform = xformQuery.GetComponent(args.User); + var userXform = xformQuery.GetComponent(user); var userMapPos = _transform.GetMapCoordinates(userXform); - var clickMapPos = args.ClickLocation.ToMap(EntityManager, _transform); + var clickMapPos = mapcoord; var diffPos = clickMapPos.Position - userMapPos.Position; if (diffPos == Vector2.Zero || diffPos == Vector2Helpers.NaN) @@ -88,8 +109,6 @@ public sealed class SpraySystem : EntitySystem var amount = Math.Max(Math.Min((solution.Volume / entity.Comp.TransferAmount).Int(), entity.Comp.VaporAmount), 1); var spread = entity.Comp.VaporSpread / amount; - // TODO: Just use usedelay homie. - var cooldownTime = 0f; for (var i = 0; i < amount; i++) { @@ -131,20 +150,19 @@ public sealed class SpraySystem : EntitySystem // impulse direction is defined in world-coordinates, not local coordinates var impulseDirection = rotation.ToVec(); var time = diffLength / entity.Comp.SprayVelocity; - cooldownTime = MathF.Max(time, cooldownTime); - _vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, args.User); + _vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, user); - if (TryComp(args.User, out var body)) + if (TryComp(user, out var body)) { - if (_gravity.IsWeightless(args.User, body)) - _physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * entity.Comp.PushbackAmount, body: body); + if (_gravity.IsWeightless(user, body)) + _physics.ApplyLinearImpulse(user, -impulseDirection.Normalized() * entity.Comp.PushbackAmount, body: body); } } _audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f)); - _useDelay.SetLength(entity.Owner, TimeSpan.FromSeconds(cooldownTime)); - _useDelay.TryResetDelay((entity, useDelay)); + if (useDelay != null) + _useDelay.TryResetDelay((entity, useDelay)); } } diff --git a/Content.Server/NPC/Queries/Considerations/TargetOnFireCon.cs b/Content.Server/NPC/Queries/Considerations/TargetOnFireCon.cs new file mode 100644 index 0000000000..d86dbc06ec --- /dev/null +++ b/Content.Server/NPC/Queries/Considerations/TargetOnFireCon.cs @@ -0,0 +1,9 @@ +namespace Content.Server.NPC.Queries.Considerations; + +/// +/// Returns 1f if the target is on fire or 0f if not. +/// +public sealed partial class TargetOnFireCon : UtilityConsideration +{ + +} diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index 8dff93648b..60bc5cdfd8 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Atmos.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.NPC.Queries; using Content.Server.NPC.Queries.Considerations; @@ -351,6 +352,12 @@ public sealed class NPCUtilitySystem : EntitySystem return 0f; } + case TargetOnFireCon: + { + if (TryComp(targetUid, out FlammableComponent? fire) && fire.OnFire) + return 1f; + return 0f; + } default: throw new NotImplementedException(); } diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index 10773d6de8..a180b698fa 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -60,6 +60,7 @@ petting-success-honkbot = You pet {THE($target)} on {POSS-ADJ($target)} slippery petting-success-mimebot = You pet {THE($target)} on {POSS-ADJ($target)} cold metal head. petting-success-cleanbot = You pet {THE($target)} on {POSS-ADJ($target)} damp metal head. petting-success-medibot = You pet {THE($target)} on {POSS-ADJ($target)} sterile metal head. +petting-success-firebot = You pet {THE($target)} on {POSS-ADJ($target)} warm metal head. petting-success-generic-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} metal head. petting-success-salvage-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} dirty metal head. petting-success-engineer-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} reflective metal head. @@ -73,6 +74,7 @@ petting-failure-honkbot = You reach out to pet {THE($target)}, but {SUBJECT($tar petting-failure-cleanbot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy mopping! petting-failure-mimebot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy miming! petting-failure-medibot = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} syringe nearly stabs your hand! +petting-failure-firebot = You reach out to pet {THE($target)}, but {SUBJECT($target)} sprays you in the face before you can get close! petting-failure-generic-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy stating laws! petting-failure-salvage-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy drilling! petting-failure-engineer-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy repairing! diff --git a/Resources/Locale/en-US/npc/firebot.ftl b/Resources/Locale/en-US/npc/firebot.ftl new file mode 100644 index 0000000000..758874ceaa --- /dev/null +++ b/Resources/Locale/en-US/npc/firebot.ftl @@ -0,0 +1 @@ +firebot-fire-detected = Fire detected! diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 625ef7a056..11643c076d 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -249,6 +249,7 @@ - type: Tag tags: - WhitelistChameleon + - FireHelmet - type: HideLayerClothing slots: - Hair @@ -281,6 +282,7 @@ - type: Tag tags: - WhitelistChameleon + - FireHelmet - type: HideLayerClothing slots: - Hair diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index d5b4366e2b..7d988c6fe9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -108,6 +108,53 @@ - type: NoSlip - type: Insulated +- type: entity + parent: MobSiliconBase + id: MobFireBot + name: firebot + description: A little fire extinguishing bot. He looks rather anxious. + components: + - type: Sprite + sprite: Mobs/Silicon/Bots/firebot.rsi + state: firebot + - type: Construction + graph: FireBot + node: bot + - type: SentienceTarget + flavorKind: station-event-random-sentience-flavor-mechanical + - type: HTN + rootTask: + task: FirebotCompound + - type: SolutionContainerManager + solutions: + spray: + maxVol: 10 + reagents: + - ReagentId: Water + Quantity: 10 + - type: SolutionRegeneration + solution: spray + generated: + reagents: + - ReagentId: Water + Quantity: 10 + - type: Spray + transferAmount: 10 + pushbackAmount: 60 + spraySound: + path: /Audio/Effects/extinguish.ogg + sprayedPrototype: ExtinguisherSpray + vaporAmount: 1 + vaporSpread: 90 + sprayVelocity: 3.0 + - type: UseDelay + delay: 4 + - type: InteractionPopup + interactSuccessString: petting-success-firebot + interactFailureString: petting-failure-firebot + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg + - type: entity parent: MobSiliconBase id: MobHonkBot diff --git a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml index 0389db27ea..b306da6442 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml @@ -62,6 +62,9 @@ - Rolling speedModifier: 0.5 # its very big, awkward to use - type: Appearance + - type: Tag + tags: + - FireExtinguisher - type: GenericVisualizer visuals: enum.ToggleVisuals.Toggled: diff --git a/Resources/Prototypes/NPCs/firebot.yml b/Resources/Prototypes/NPCs/firebot.yml new file mode 100644 index 0000000000..acea6498bd --- /dev/null +++ b/Resources/Prototypes/NPCs/firebot.yml @@ -0,0 +1,44 @@ +- type: htnCompound + id: FirebotCompound + branches: + - tasks: + - !type:HTNCompoundTask + task: DouseFireTargetCompound + - tasks: + - !type:HTNCompoundTask + task: IdleCompound + +- type: htnCompound + id: DouseFireTargetCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:UtilityOperator + proto: NearbyOnFire + + - !type:HTNPrimitiveTask + operator: !type:SpeakOperator + speech: firebot-fire-detected + hidden: true + + - !type:HTNPrimitiveTask + operator: !type:MoveToOperator + pathfindInPlanning: true + removeKeyOnFinish: false + targetKey: TargetCoordinates + pathfindKey: TargetPathfind + rangeKey: InteractRange + + - !type:HTNPrimitiveTask + preconditions: + - !type:TargetInRangePrecondition + targetKey: Target + rangeKey: InteractRange + operator: !type:InteractWithOperator + targetKey: Target + services: + - !type:UtilityService + id: FireService + proto: NearbyOnFire + key: Target + diff --git a/Resources/Prototypes/NPCs/utility_queries.yml b/Resources/Prototypes/NPCs/utility_queries.yml index 06bc0a9a9e..e10a0ed30c 100644 --- a/Resources/Prototypes/NPCs/utility_queries.yml +++ b/Resources/Prototypes/NPCs/utility_queries.yml @@ -144,6 +144,27 @@ - !type:TargetAccessibleCon curve: !type:BoolCurve +- type: utilityQuery + id: NearbyOnFire + query: + - !type:ComponentQuery + components: + - type: Flammable + # why does Flammable even have a required damage + damage: + types: + burn: 0 + considerations: + - !type:TargetDistanceCon + curve: !type:PresetCurve + preset: TargetDistance + - !type:TargetAccessibleCon + curve: !type:BoolCurve + - !type:TargetInLOSOrCurrentCon + curve: !type:BoolCurve + - !type:TargetOnFireCon + curve: !type:BoolCurve + - type: utilityQuery id: NearbyPuddles query: diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/firebot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/firebot.yml new file mode 100644 index 0000000000..977ffd4093 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/firebot.yml @@ -0,0 +1,33 @@ +- type: constructionGraph + id: FireBot + start: start + graph: + - node: start + edges: + - to: bot + steps: + - tag: FireExtinguisher + icon: + sprite: Objects/Misc/fire_extinguisher.rsi + state: fire_extinguisher_open + name: fire extinguisher + - tag: FireHelmet + icon: + sprite: Clothing/Head/Helmets/firehelmet.rsi + state: icon + name: fire helmet + doAfter: 2 + - tag: ProximitySensor + icon: + sprite: Objects/Misc/proximity_sensor.rsi + state: icon + name: proximity sensor + doAfter: 2 + - tag: BorgArm + icon: + sprite: Mobs/Silicon/drone.rsi + state: l_hand + name: borg arm + doAfter: 2 + - node: bot + entity: MobFireBot diff --git a/Resources/Prototypes/Recipes/Crafting/bots.yml b/Resources/Prototypes/Recipes/Crafting/bots.yml index 3031f4a780..21b524a060 100644 --- a/Resources/Prototypes/Recipes/Crafting/bots.yml +++ b/Resources/Prototypes/Recipes/Crafting/bots.yml @@ -11,6 +11,19 @@ sprite: Mobs/Silicon/Bots/cleanbot.rsi state: cleanbot +- type: construction + name: firebot + id: firebot + graph: FireBot + startNode: start + targetNode: bot + category: construction-category-utilities + objectType: Item + description: This bot puts out fires wherever it goes. + icon: + sprite: Mobs/Silicon/Bots/firebot.rsi + state: firebot + - type: construction name: honkbot id: honkbot diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 2a07d061d3..86ade97d4e 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -617,6 +617,12 @@ - type: Tag id: FirelockElectronics +- type: Tag + id: FireExtinguisher + +- type: Tag + id: FireHelmet + - type: Tag id: Flare diff --git a/Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/firebot.png b/Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/firebot.png new file mode 100644 index 0000000000000000000000000000000000000000..70ee9313d2d62bc1847b1bc663f2205e85a9685e GIT binary patch literal 4614 zcmeHKdsGu=7N39u;pQeTtDFd<}2d?f*531%S`bg?p-nS@#Lo`D2WQPgUE zAU?3&F1Avu7Q3aQt754Yg!)3aYCYBZ#8yO)>uT|VT8jH6AmZ7cv&VC`|B-VhGjkum z@7~|N_dD~wr%O!=2^AAb5eH7j`hU6Z&BhVe-~Z}+W!Q$g$g#-L%h3<+iZe6Fh-rx})`R)4 zZqF-iqp4M**kM24HtJ6V>|C7fXPMWuZD!l!pg*@~tk1i+=|onms#ALQ`0d+k=E0{2 zHXmJ3#S@j_m|xkrWpjs=4)LeZQp+I0wJRTm)<`EnGtS+~ue%6Ayv2-CsnaNx&r$-3 zl+RnENN$)E_3iBREi=c2PS-h(=r;cA6Mo5-BHix)+& zc-w!lY1Zpm{U_h`ZTzubb4oq6V|H53z@O_K6E9yXytvPX@sO zzTZ2iRuIAb1)CaE6n~v@f5Wu@Qxtt)}G(ynJ=6OuX`Gt#aN1V^N!D7 z`;IMl&G1b{ku^2e+_pFD`+S2HH`m6<)_%NIH_qpd>AtogyZN<%s;~C%e&~1tQI(%> ziEM5T8zTJE!w(PF7UG4!wx@i4Alf;?xpmp_S))MfAlcaq#RB3;D3ugv(X%GqpNcX>-yrCcp$DMD1qsQT~KLSni~Z zc$zA)8v?v3_&FSB$AvX=Q+*ZbSP3tn`sL$Wx=ZA7nV%YXmvdv9tup1 z#qRY2WWQj^F~;X)y%3v6<4vb`Ai%u`_XX=`xqFR)l~#+ZY-FA%JdH}h_pFaoHj<%m z@1w+sQVAl8LQqmfBbbCXAO;epkOT~);v_UiU^289l*Y<(gq5T{Pyk%O030-d#v~$= zMo82^A{a%A5E&ImBQgR*MW~U&&;+s<#55-Zx{@&Wj>-c?0Vu*iNMvG6h8W^8DS{C) z0+C^2BSJ_}EP<4u2C+fxg`!A2(dM)epqz|_FwsK0)#O!p2*)SuGzvZ{5IvXZ%mily z4qyftD`j)B&sBQHLZ@?thflE-m7+44NFo)*qhg8VxzTjm$%0<=po&F;ILxc@6b1+B z0BQ+Orvd=49AtwloixGOoO+whtl)csf<2x+YAqNjir@$p!O;LzgkrczhNBX_I35>E z@i-|WlHj6V_BM(!7W^-3&-lRduA(P1ELgw5E9#o5blTDN*7a&;yu$>;-m$<5vMU9a z$fqf9oB*p!MdlDz6Aku{?uLCPXMU#{#4@ANh)LrRi3E!W6^us_Z+j(>vN)8EC*!49 z7fC(ntj)-|2q!(+1b75ofd=(*1&``3)#w+aaplmSIsnQLkqqfY8DH3)tkAP#Jj+%t z{4YM_UV~m+4DjocfvpSdgumT{+uEQU>1Pu2r@>2Zv(bY%SOEK_L#(mw@ zN7qX+@KVNo-SvN?EAaVYinf9;AQw0)Wsi(q0*+aJhPRSb-UAo(SXo;Ho?fvh&tM@a zw9#|%%EpF90--;r(W?D#yfXCFfg>Z@uC#))bd^RmS)X(Hc4qZdU-6L6wfBaq>@LR* z4LtZRul)QzWyRkX<(@4r;5pdAc*5Rw19Zz;it`@ykI0Z-9k%pgRYv8vjUO$&|Fpzj zn$=d+KJqc!&g*xuYSEJXh$%H#b<;xY!9zcN^ZGx2NDa6OK}jaHW3as}{N&8qrag(f zek{+BUlB(7YIcP6Pux84Sli&gj0r`@AgJo-%ea*mps7TFza1?}jjF zfwejR`h@y>uRUGCjUGKKvhzae(y;N@ zqkhAdOubf~!#_1GJ*rb3dpu@n!^!jf8p>Ro3t!27dNLceg`HCt#na ztLu(thn?B8`_95Qn!gFUf9|F`I~nbmF8= c=&I{czc!!93dg%_s;AZ(b*idrN_O#o0LjaybN~PV literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/meta.json b/Resources/Textures/Mobs/Silicon/Bots/firebot.rsi/meta.json new file mode 100644 index 0000000000..e13b42deee --- /dev/null +++ b/Resources/Textures/Mobs/Silicon/Bots/firebot.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/eba0d62005e7754dd8b1c88e45cd949c360774d5", + "states": [ + { + "name": "firebot", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + } + ] +}