]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
NPC spiders sometimes spin webs 🕷️🕸️ (#38319)
authorqwerltaz <69696513+qwerltaz@users.noreply.github.com>
Thu, 17 Jul 2025 16:34:00 +0000 (18:34 +0200)
committerGitHub <noreply@github.com>
Thu, 17 Jul 2025 16:34:00 +0000 (12:34 -0400)
* NPC spiders now spin webs

* oops

* move logic to always update next spawn, to prevent rare web spam

* WebSpawnCooldown is timespan

* remove vv

* add web spawn method, no sus action event method call

* dont spin web immediately at spawn

* move NextWebSpawn value init to update

* oop

* remove unused game timing

* web spawn cooldown to 45

Content.Server/Spider/SpiderSystem.cs
Content.Shared/Spider/SpiderComponent.cs
Resources/Prototypes/Entities/Mobs/NPCs/pets.yml

index e6a7dd780646ab0c773db505a6f4bde265509fe7..33142b19b1d27bd22342dc917bb98f19a15ee12e 100644 (file)
@@ -2,8 +2,11 @@ using System.Linq;
 using Content.Server.Popups;
 using Content.Shared.Spider;
 using Content.Shared.Maps;
+using Content.Shared.Mobs.Systems;
 using Robust.Server.GameObjects;
 using Robust.Shared.Map;
+using Robust.Shared.Player;
+using Robust.Shared.Timing;
 
 namespace Content.Server.Spider;
 
@@ -11,6 +14,8 @@ public sealed class SpiderSystem : SharedSpiderSystem
 {
     [Dependency] private readonly PopupSystem _popup = default!;
     [Dependency] private readonly TurfSystem _turf = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly MobStateSystem _mobState = default!;
 
     /// <summary>
     ///     A recycled hashset used to check turfs for spiderwebs.
@@ -23,6 +28,30 @@ public sealed class SpiderSystem : SharedSpiderSystem
         SubscribeLocalEvent<SpiderComponent, SpiderWebActionEvent>(OnSpawnNet);
     }
 
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        var query = EntityQueryEnumerator<SpiderComponent>();
+        while (query.MoveNext(out var uid, out var spider))
+        {
+            spider.NextWebSpawn ??= _timing.CurTime + spider.WebSpawnCooldown;
+
+            if (_timing.CurTime < spider.NextWebSpawn)
+                continue;
+
+            spider.NextWebSpawn += spider.WebSpawnCooldown;
+
+            if (HasComp<ActorComponent>(uid)
+                || _mobState.IsDead(uid)
+                || !spider.SpawnsWebsAsNonPlayer)
+                continue;
+
+            var transform = Transform(uid);
+            SpawnWeb((uid, spider), transform.Coordinates);
+        }
+    }
+
     private void OnSpawnNet(EntityUid uid, SpiderComponent component, SpiderWebActionEvent args)
     {
         if (args.Handled)
@@ -36,38 +65,42 @@ public sealed class SpiderSystem : SharedSpiderSystem
             return;
         }
 
-        var coords = transform.Coordinates;
+        var result = SpawnWeb((uid, component), transform.Coordinates);
 
-        // TODO generic way to get certain coordinates
+        if (result)
+        {
+            _popup.PopupEntity(Loc.GetString("spider-web-action-success"), args.Performer, args.Performer);
+            args.Handled = true;
+        }
+        else
+            _popup.PopupEntity(Loc.GetString("spider-web-action-fail"), args.Performer, args.Performer);
+    }
 
+    private bool SpawnWeb(Entity<SpiderComponent> ent, EntityCoordinates coords)
+    {
         var result = false;
+
         // Spawn web in center
         if (!IsTileBlockedByWeb(coords))
         {
-            Spawn(component.WebPrototype, coords);
+            Spawn(ent.Comp.WebPrototype, coords);
             result = true;
         }
 
         // Spawn web in other directions
         for (var i = 0; i < 4; i++)
         {
-            var direction = (DirectionFlag) (1 << i);
-            coords = transform.Coordinates.Offset(direction.AsDir().ToVec());
-
-            if (!IsTileBlockedByWeb(coords))
-            {
-                Spawn(component.WebPrototype, coords);
-                result = true;
-            }
-        }
+            var direction = (DirectionFlag)(1 << i);
+            var outerSpawnCoordinates = coords.Offset(direction.AsDir().ToVec());
 
-        if (result)
-        {
-            _popup.PopupEntity(Loc.GetString("spider-web-action-success"), args.Performer, args.Performer);
-            args.Handled = true;
+            if (IsTileBlockedByWeb(outerSpawnCoordinates))
+                continue;
+
+            Spawn(ent.Comp.WebPrototype, outerSpawnCoordinates);
+            result = true;
         }
-        else
-            _popup.PopupEntity(Loc.GetString("spider-web-action-fail"), args.Performer, args.Performer);
+
+        return result;
     }
 
     private bool IsTileBlockedByWeb(EntityCoordinates coords)
@@ -82,4 +115,3 @@ public sealed class SpiderSystem : SharedSpiderSystem
         return false;
     }
 }
-
index 42213adcb10b802bdddd60f1ddc93341b7c1fd5a..3a1612fed0773bd0113c2a5ca172bd2c62a10aab 100644 (file)
@@ -18,6 +18,24 @@ public sealed partial class SpiderComponent : Component
     public string WebAction = "ActionSpiderWeb";
 
     [DataField] public EntityUid? Action;
+
+    /// <summary>
+    /// Whether the spider will spawn webs when not controlled by a player.
+    /// </summary>
+    [DataField]
+    public bool SpawnsWebsAsNonPlayer = true;
+
+    /// <summary>
+    /// The cooldown in seconds between web spawns when not controlled by a player.
+    /// </summary>
+    [DataField]
+    public TimeSpan WebSpawnCooldown = TimeSpan.FromSeconds(45f);
+
+    /// <summary>
+    /// The next time the spider can spawn a web when not controlled by a player.
+    /// </summary>
+    [DataField]
+    public TimeSpan? NextWebSpawn;
 }
 
 public sealed partial class SpiderWebActionEvent : InstantActionEvent { }
index be0ed00172fddc3b2359bbd3affc42c11bae4592..75aacadd352bc22f05308caec8ca776283796dc9 100644 (file)
       types:
         Piercing: 8
         Poison: 8
+  - type: Spider
+    spawnsWebsAsNonPlayer: false
   - type: Grammar
     attributes:
       proper: true