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!
This commit is contained in:
Golinth
2024-09-30 22:13:16 -05:00
committed by GitHub
parent edc110907e
commit 3b682d4d68
15 changed files with 241 additions and 15 deletions

View File

@@ -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<SprayComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<SprayComponent, UserActivateInWorldEvent>(OnActivateInWorld);
}
private void OnActivateInWorld(Entity<SprayComponent> entity, ref UserActivateInWorldEvent args)
{
if (args.Handled)
return;
args.Handled = true;
var targetMapPos = _transform.GetMapCoordinates(GetEntityQuery<TransformComponent>().GetComponent(args.Target));
Spray(entity, args.User, targetMapPos);
}
private void OnAfterInteract(Entity<SprayComponent> 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<SprayComponent> 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<UseDelayComponent>(entity, out var useDelay)
|| _useDelay.IsDelayed((entity, useDelay)))
if (TryComp<UseDelayComponent>(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<TransformComponent>();
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<PhysicsComponent>(args.User, out var body))
if (TryComp<PhysicsComponent>(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));
}
}

View File

@@ -0,0 +1,9 @@
namespace Content.Server.NPC.Queries.Considerations;
/// <summary>
/// Returns 1f if the target is on fire or 0f if not.
/// </summary>
public sealed partial class TargetOnFireCon : UtilityConsideration
{
}

View File

@@ -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();
}

View File

@@ -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!

View File

@@ -0,0 +1 @@
firebot-fire-detected = Fire detected!

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -617,6 +617,12 @@
- type: Tag
id: FirelockElectronics
- type: Tag
id: FireExtinguisher
- type: Tag
id: FireHelmet
- type: Tag
id: Flare

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -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
]
]
}
]
}