Skip to content

Commit

Permalink
Merge remote-tracking branch 'ee/master' into upstream-merge-02-07-25
Browse files Browse the repository at this point in the history
  • Loading branch information
angelofallars committed Feb 7, 2025
2 parents 4697d2e + e82ab3f commit 13204d9
Show file tree
Hide file tree
Showing 21 changed files with 439 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Threading;
using System.Threading.Tasks;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Damage;
using Content.Shared.Emag.Components;
using Content.Shared.Interaction;
using Content.Shared.Silicons.Bots;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;

namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;

public sealed partial class PickNearbyWeldableOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private EntityLookupSystem _lookup = default!;
private WeldbotSystem _weldbot = default!;
private PathfindingSystem _pathfinding = default!;
private TagSystem _tagSystem = default!;

[DataField] public string RangeKey = NPCBlackboard.WeldbotWeldRange;

/// <summary>
/// Target entity to weld
/// </summary>
[DataField(required: true)]
public string TargetKey = string.Empty;

/// <summary>
/// Target entitycoordinates to move to.
/// </summary>
[DataField(required: true)]
public string TargetMoveKey = string.Empty;

public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem<EntityLookupSystem>();
_weldbot = sysManager.GetEntitySystem<WeldbotSystem>();
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
_tagSystem = sysManager.GetEntitySystem<TagSystem>();
}

public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);

if (!blackboard.TryGetValue<float>(RangeKey, out var range, _entManager) || !_entManager.TryGetComponent<WeldbotComponent>(owner, out var weldbot))
return (false, null);

var damageQuery = _entManager.GetEntityQuery<DamageableComponent>();
var emagged = _entManager.HasComponent<EmaggedComponent>(owner);

foreach (var target in _lookup.GetEntitiesInRange(owner, range))
{
if (!damageQuery.TryGetComponent(target, out var damage))
continue;

var tagPrototype = _prototypeManager.Index<TagPrototype>(WeldbotWeldOperator.SiliconTag);

if (!_entManager.TryGetComponent<TagComponent>(target, out var tagComponent) || !_tagSystem.HasTag(tagComponent, tagPrototype) || !emagged && damage.DamagePerGroup["Brute"].Value == 0)
continue;

//Needed to make sure it doesn't sometimes stop right outside it's interaction range
var pathRange = SharedInteractionSystem.InteractionRange - 1f;
var path = await _pathfinding.GetPath(owner, target, pathRange, cancelToken);

if (path.Result == PathResult.NoPath)
continue;

return (true, new Dictionary<string, object>()
{
{TargetKey, target},
{TargetMoveKey, _entManager.GetComponent<TransformComponent>(target).Coordinates},
{NPCBlackboard.PathfindKey, path},
});
}

return (false, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using Content.Server.Chat.Systems;
using Content.Shared.Chat;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Emag.Components;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Silicons.Bots;
using Content.Shared.Tag;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;

namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;

public sealed partial class WeldbotWeldOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private ChatSystem _chat = default!;
private WeldbotSystem _weldbot = default!;
private SharedAudioSystem _audio = default!;
private SharedInteractionSystem _interaction = default!;
private SharedPopupSystem _popup = default!;
private DamageableSystem _damageableSystem = default!;
private TagSystem _tagSystem = default!;

public const string SiliconTag = "SiliconMob";

/// <summary>
/// Target entity to inject.
/// </summary>
[DataField(required: true)]
public string TargetKey = string.Empty;

public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_chat = sysManager.GetEntitySystem<ChatSystem>();
_weldbot = sysManager.GetEntitySystem<WeldbotSystem>();
_audio = sysManager.GetEntitySystem<SharedAudioSystem>();
_interaction = sysManager.GetEntitySystem<SharedInteractionSystem>();
_popup = sysManager.GetEntitySystem<SharedPopupSystem>();
_damageableSystem = sysManager.GetEntitySystem<DamageableSystem>();
_tagSystem = sysManager.GetEntitySystem<TagSystem>();
}

public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
{
base.TaskShutdown(blackboard, status);
blackboard.Remove<EntityUid>(TargetKey);
}

public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);

if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entMan) || _entMan.Deleted(target))
return HTNOperatorStatus.Failed;

var tagPrototype = _prototypeManager.Index<TagPrototype>(SiliconTag);

if (!_entMan.TryGetComponent<TagComponent>(target, out var tagComponent) || !_tagSystem.HasTag(tagComponent, tagPrototype)
|| !_entMan.TryGetComponent<WeldbotComponent>(owner, out var botComp)
|| !_entMan.TryGetComponent<DamageableComponent>(target, out var damage)
|| !_interaction.InRangeUnobstructed(owner, target)
|| (damage.DamagePerGroup["Brute"].Value == 0 && !_entMan.HasComponent<EmaggedComponent>(owner)))
return HTNOperatorStatus.Failed;

if (botComp.IsEmagged)
{
if (!_prototypeManager.TryIndex<DamageGroupPrototype>("Burn", out var prototype))
return HTNOperatorStatus.Failed;

_damageableSystem.TryChangeDamage(target, new DamageSpecifier(prototype, 10), true, false, damage);
}
else
{
if (!_prototypeManager.TryIndex<DamageGroupPrototype>("Brute", out var prototype))
return HTNOperatorStatus.Failed;

_damageableSystem.TryChangeDamage(target, new DamageSpecifier(prototype, -50), true, false, damage);
}

_audio.PlayPvs(botComp.WeldSound, target);

if(damage.DamagePerGroup["Brute"].Value == 0) //only say "all done if we're actually done!"
_chat.TrySendInGameICMessage(owner, Loc.GetString("weldbot-finish-weld"), InGameICChatType.Speak, hideChat: true, hideLog: true);

return HTNOperatorStatus.Finished;
}
}
2 changes: 2 additions & 0 deletions Content.Server/NPC/NPCBlackboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
{"InteractRange", SharedInteractionSystem.InteractionRange},
{"MaximumIdleTime", 7f},
{MedibotInjectRange, 4f},
{WeldbotWeldRange, 4f},
{MeleeMissChance, 0.3f},
{"MeleeRange", 1f},
{"MinimumIdleTime", 2f},
Expand Down Expand Up @@ -292,6 +293,7 @@ public string GetVisionRadiusKey(IEntityManager entMan)
public const string FollowTarget = "FollowTarget";
public const string Inventory = "Inventory";
public const string MedibotInjectRange = "MedibotInjectRange";
public const string WeldbotWeldRange = "WeldbotWeldRange";

public const string MeleeMissChance = "MeleeMissChance";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public sealed partial class CharacterAgeRequirement : CharacterRequirement
public int Min;

[DataField]
public int Max = 2147483647;
public int Max = Int32.MaxValue;

public override bool IsValid(
JobPrototype job,
Expand All @@ -41,8 +41,15 @@ public override bool IsValid(
int depth = 0
)
{
var localeString = "";

if (Max == Int32.MaxValue || Min <= 0)
localeString = Max == Int32.MaxValue ? "character-age-requirement-minimum-only" : "character-age-requirement-maximum-only";
else
localeString = "character-age-requirement-range";

reason = Loc.GetString(
"character-age-requirement",
localeString,
("inverted", Inverted),
("min", Min),
("max", Max));
Expand Down
26 changes: 26 additions & 0 deletions Content.Shared/Silicons/Bots/WeldbotComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Robust.Shared.Audio;

namespace Content.Shared.Silicons.Bots;

/// <summary>
/// Used by the server for NPC Weldbot welding.
/// Currently no clientside prediction done, only exists in shared for emag handling.
/// </summary>
[RegisterComponent]
[Access(typeof(WeldbotSystem))]
public sealed partial class WeldbotComponent : Component
{
/// <summary>
/// Sound played after welding a patient.
/// </summary>
[DataField]
public SoundSpecifier WeldSound = new SoundPathSpecifier("/Audio/Items/welder2.ogg");

[DataField]
public SoundSpecifier EmagSparkSound = new SoundCollectionSpecifier("sparks")
{
Params = AudioParams.Default.WithVolume(8f)
};

public bool IsEmagged = false;
}
27 changes: 27 additions & 0 deletions Content.Shared/Silicons/Bots/WeldbotSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Content.Shared.Emag.Systems;
using Robust.Shared.Audio.Systems;

namespace Content.Shared.Silicons.Bots;

/// <summary>
/// Handles emagging Weldbots
/// </summary>
public sealed class WeldbotSystem : EntitySystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<WeldbotComponent, GotEmaggedEvent>(OnEmagged);
}

private void OnEmagged(EntityUid uid, WeldbotComponent comp, ref GotEmaggedEvent args)
{
_audio.PlayPredicted(comp.EmagSparkSound, uid, args.UserUid);

comp.IsEmagged = true;
args.Handled = true;
}
}
16 changes: 16 additions & 0 deletions Resources/Changelog/Changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11306,3 +11306,19 @@ Entries:
id: 6807
time: '2025-02-06T21:05:47.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/1731
- author: sleepyyapril
changes:
- type: Fix
message: 'Loadouts will no longer show the integer limit. '
id: 6808
time: '2025-02-07T06:52:55.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/1732
- author: Timfa
changes:
- type: Add
message: >-
Added weldbot! It'll fix IPC's, Borgs and other robots. If they stay
still for long enough...
id: 6809
time: '2025-02-07T10:27:47.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/1703
12 changes: 11 additions & 1 deletion Resources/Locale/en-US/customization/character-requirements.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,21 @@ character-logic-xor-requirement = You must{$inverted ->
## Profile
character-age-requirement = You must{$inverted ->
character-age-requirement-range = You must{$inverted ->
[true]{" "}not
*[other]{""}
} be within [color=yellow]{$min}[/color] and [color=yellow]{$max}[/color] years old
character-age-requirement-minimum-only = You must{$inverted ->
[true]{" "}not
*[other]{""}
} be at least [color=yellow]{$min}[/color] years old
character-age-requirement-maximum-only = You must{$inverted ->
[true]{""}
*[other]{" "}not
} be older than [color=yellow]{$max}[/color] years old
character-backpack-type-requirement = You must {$inverted ->
[true] not use
*[other] use
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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-weldbot = You pet {THE($target)} on {POSS-ADJ($target)} stained 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.
Expand All @@ -80,6 +81,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-weldbot = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} welder nearly burns 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!
Expand Down
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/npc/weldbot.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
weldbot-start-weld = Hold still, please.
weldbot-finish-weld = All done.
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
- FootstepSound
- CanPilot
- SiliconEmotes
- SiliconMob
- type: Emoting
- type: GuideHelp
guides:
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
- type: Tag
tags:
- DoorBumpOpener
- SiliconMob
- type: MobState
allowedStates:
- Alive
Expand Down
Loading

0 comments on commit 13204d9

Please sign in to comment.