mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-28 19:17:53 +03:00
Ports Blob from https://github.com/Goob-Station/Goob-Station/pull/975 that was ported from https://github.com/Rxup/space-station-14. Credit to VigersRay for original code, Roudenn and Rxup for maintaining and jorgun for the Goob port. --- - [X] Port https://github.com/Goob-Station/Goob-Station/pull/975; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/1209; - [X] Port Blob related code from https://github.com/Goob-Station/Goob-Station/pull/1262; - [X] Port Blob related code from https://github.com/Goob-Station/Goob-Station/pull/1340; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/1408; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/1419; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/1440; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/1817; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/2077; - [ ] ~Port https://github.com/Goob-Station/Goob-Station/pull/1916~; - [ ] ~Port https://github.com/Goob-Station/Goob-Station/pull/1917~; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/2077; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/2092; - [X] Port https://github.com/Goob-Station/Goob-Station/pull/2546; - [X] Port https://github.com/Rxup/space-station-14/pull/963; - [X] Port https://github.com/Rxup/space-station-14/pull/998; - [ ] ~Port https://github.com/Goob-Station/Goob-Station/pull/2563~. - [X] Enable Blob and Blob gamemode; - [X] Add `StationGlobConfig` to all stations; - [X] Use `AnnouncerSystem` in `BlobRuleSystem.cs`; - [X] Blob language and Hivemind (from https://github.com/Rxup/space-station-14/pull/176); - [x] Change CVars location; - [X] Add media. --- <details><summary><h1>Media</h1></summary> <p> https://youtu.be/-WtMQwRcmrU?si=su3An6RtiCTZg-DV </p> </details> --- 🆑 VigersRay, Roudenn, Rxup, vladospupuos, fishbait and Kyoth25f - add: Added a new antagonist: Blob --------- Co-authored-by: fishbait <gnesse@gmail.com> Co-authored-by: Fishbait <Fishbait@git.ml> Co-authored-by: Aiden <aiden@djkraz.com> Co-authored-by: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Co-authored-by: lanse12 <cloudability.ez@gmail.com> Co-authored-by: BombasterDS <deniskaporoshok@gmail.com> Co-authored-by: Aviu00 <93730715+Aviu00@users.noreply.github.com> Co-authored-by: Piras314 <p1r4s@proton.me> Co-authored-by: shibe <95730644+shibechef@users.noreply.github.com> Co-authored-by: Ilya246 <57039557+Ilya246@users.noreply.github.com> Co-authored-by: JohnOakman <sremy2012@hotmail.fr> Co-authored-by: Fat Engineer Gaming <159075414+Fat-Engineer-Gaming@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Rouden <149893554+Roudenn@users.noreply.github.com>
233 lines
8.3 KiB
C#
233 lines
8.3 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Server.Construction.Components;
|
|
using Content.Server.Destructible;
|
|
using Content.Server.Emp;
|
|
using Content.Shared._Goobstation.Blob;
|
|
using Content.Shared._Goobstation.Blob.Components;
|
|
using Content.Shared.Damage;
|
|
using Content.Shared.Destructible;
|
|
using Content.Shared.Mobs.Components;
|
|
using Content.Shared.NPC.Components;
|
|
using Content.Shared.NPC.Prototypes;
|
|
using Content.Shared.NPC.Systems;
|
|
using Robust.Server.Audio;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Random;
|
|
|
|
namespace Content.Server._Goobstation.Blob.Systems;
|
|
|
|
public sealed class BlobTileSystem : SharedBlobTileSystem
|
|
{
|
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
|
[Dependency] private readonly BlobCoreSystem _blobCoreSystem = default!;
|
|
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
|
[Dependency] private readonly EmpSystem _empSystem = default!;
|
|
[Dependency] private readonly MapSystem _mapSystem = default!;
|
|
[Dependency] private readonly TransformSystem _transform = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
[Dependency] private readonly NpcFactionSystem _npcFactionSystem = default!;
|
|
|
|
private EntityQuery<BlobCoreComponent> _blobCoreQuery;
|
|
|
|
[ValidatePrototypeId<NpcFactionPrototype>]
|
|
private const string BlobFaction = "Blob";
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<BlobTileComponent, MapInitEvent>(OnMapInit);
|
|
SubscribeLocalEvent<BlobTileComponent, DestructionEventArgs>(OnDestruction);
|
|
SubscribeLocalEvent<BlobTileComponent, BlobTileGetPulseEvent>(OnPulsed);
|
|
SubscribeLocalEvent<BlobTileComponent, EntityTerminatingEvent>(OnTerminate);
|
|
|
|
_blobCoreQuery = GetEntityQuery<BlobCoreComponent>();
|
|
}
|
|
|
|
private void OnMapInit(Entity<BlobTileComponent> ent, ref MapInitEvent args)
|
|
{
|
|
var faction = EnsureComp<NpcFactionMemberComponent>(ent);
|
|
Entity<NpcFactionMemberComponent?> factionEnt = (ent, faction);
|
|
|
|
_npcFactionSystem.ClearFactions(factionEnt, false);
|
|
_npcFactionSystem.AddFaction(factionEnt, BlobFaction);
|
|
|
|
// make alive - true for npc combat
|
|
EnsureComp<MobStateComponent>(ent);
|
|
EnsureComp<MobThresholdsComponent>(ent);
|
|
}
|
|
|
|
private void OnTerminate(EntityUid uid, BlobTileComponent component, EntityTerminatingEvent args)
|
|
{
|
|
if (TerminatingOrDeleted(component.Core))
|
|
return;
|
|
|
|
component.Core!.Value.Comp.BlobTiles.Remove(uid);
|
|
}
|
|
|
|
private void OnDestruction(EntityUid uid, BlobTileComponent component, DestructionEventArgs args)
|
|
{
|
|
if (TerminatingOrDeleted(component.Core) ||
|
|
!_blobCoreQuery.TryComp(component.Core, out var blobCoreComponent))
|
|
return;
|
|
|
|
if (blobCoreComponent.CurrentChem == BlobChemType.ElectromagneticWeb)
|
|
{
|
|
_empSystem.EmpPulse(_transform.GetMapCoordinates(uid), 3f, 50f, 3f);
|
|
}
|
|
}
|
|
|
|
private void OnPulsed(EntityUid uid, BlobTileComponent component, BlobTileGetPulseEvent args)
|
|
{
|
|
if (component.Core == null)
|
|
return;
|
|
|
|
var core = component.Core.Value;
|
|
var xform = Transform(uid);
|
|
|
|
HealTile((uid, component), core);
|
|
|
|
if (!args.Handled)
|
|
return;
|
|
|
|
if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var nearNode = _blobCoreSystem.GetNearNode(xform.Coordinates, core.Comp.TilesRadiusLimit);
|
|
|
|
if (nearNode == null)
|
|
return;
|
|
|
|
var mobTile = _mapSystem.GetTileRef(xform.GridUid.Value, grid, xform.Coordinates);
|
|
|
|
var mobAdjacentTiles = new[]
|
|
{
|
|
mobTile.GridIndices.Offset(Direction.East),
|
|
mobTile.GridIndices.Offset(Direction.West),
|
|
mobTile.GridIndices.Offset(Direction.North),
|
|
mobTile.GridIndices.Offset(Direction.South),
|
|
};
|
|
|
|
_random.Shuffle(mobAdjacentTiles);
|
|
|
|
var localPos = xform.Coordinates.Position;
|
|
|
|
var radius = 1.0f;
|
|
|
|
var innerTiles = _mapSystem.GetLocalTilesIntersecting(xform.GridUid.Value,
|
|
grid,
|
|
new Box2(localPos + new Vector2(-radius, -radius), localPos + new Vector2(radius, radius)))
|
|
.ToArray();
|
|
|
|
foreach (var innerTile in innerTiles)
|
|
{
|
|
if (!mobAdjacentTiles.Contains(innerTile.GridIndices))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var ent in _mapSystem.GetAnchoredEntities(xform.GridUid.Value, grid, innerTile.GridIndices))
|
|
{
|
|
if (!HasComp<DestructibleComponent>(ent) || !HasComp<ConstructionComponent>(ent))
|
|
continue;
|
|
|
|
DoLunge(uid, ent);
|
|
_damageableSystem.TryChangeDamage(ent, core.Comp.ChemDamageDict[core.Comp.CurrentChem]);
|
|
_audioSystem.PlayPvs(core.Comp.AttackSound, uid, AudioParams.Default);
|
|
args.Handled = true;
|
|
return;
|
|
}
|
|
|
|
var spawn = true;
|
|
foreach (var ent in _mapSystem.GetAnchoredEntities(xform.GridUid.Value, grid, innerTile.GridIndices))
|
|
{
|
|
if (!HasComp<BlobTileComponent>(ent))
|
|
continue;
|
|
spawn = false;
|
|
break;
|
|
}
|
|
|
|
if (!spawn)
|
|
continue;
|
|
|
|
var location = _mapSystem.ToCoordinates(xform.GridUid.Value, innerTile.GridIndices, grid);
|
|
|
|
if (_blobCoreSystem.TransformBlobTile(null,
|
|
core,
|
|
nearNode,
|
|
BlobTileType.Normal,
|
|
location))
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void HealTile(Entity<BlobTileComponent> ent, Entity<BlobCoreComponent> core)
|
|
{
|
|
var healCore = new DamageSpecifier();
|
|
var modifier = 1.0f;
|
|
|
|
if (core.Comp.CurrentChem == BlobChemType.RegenerativeMateria)
|
|
{
|
|
modifier = 2.0f;
|
|
}
|
|
|
|
foreach (var keyValuePair in ent.Comp.HealthOfPulse.DamageDict)
|
|
{
|
|
healCore.DamageDict.TryAdd(keyValuePair.Key, keyValuePair.Value * modifier);
|
|
}
|
|
|
|
_damageableSystem.TryChangeDamage(ent, healCore);
|
|
}
|
|
|
|
protected override void TryUpgrade(Entity<BlobTileComponent, BlobUpgradeableTileComponent> target, Entity<BlobCoreComponent> core, EntityUid observer)
|
|
{
|
|
var ev = new BlobTransformTileActionEvent(
|
|
performer: observer,
|
|
target: Transform(target).Coordinates,
|
|
transformFrom: target.Comp1.BlobTileType,
|
|
tileType: target.Comp2.TransformTo);
|
|
|
|
RaiseLocalEvent(core, ev);
|
|
}
|
|
|
|
public void SwapSpecials(Entity<BlobNodeComponent> from, Entity<BlobNodeComponent> to)
|
|
{
|
|
(from.Comp.BlobFactory, to.Comp.BlobFactory) = (to.Comp.BlobFactory, from.Comp.BlobFactory);
|
|
(from.Comp.BlobResource, to.Comp.BlobResource) = (to.Comp.BlobResource, from.Comp.BlobResource);
|
|
(from.Comp.BlobStorage, to.Comp.BlobStorage) = (to.Comp.BlobStorage, from.Comp.BlobStorage);
|
|
(from.Comp.BlobTurret, to.Comp.BlobTurret) = (to.Comp.BlobTurret, from.Comp.BlobTurret);
|
|
Dirty(from);
|
|
Dirty(to);
|
|
}
|
|
|
|
public bool IsEmptySpecial(Entity<BlobNodeComponent> node, BlobTileType tile)
|
|
{
|
|
return tile switch
|
|
{
|
|
BlobTileType.Factory => node.Comp.BlobFactory == null || TerminatingOrDeleted(node.Comp.BlobFactory),
|
|
BlobTileType.Resource => node.Comp.BlobResource == null || TerminatingOrDeleted(node.Comp.BlobResource),
|
|
BlobTileType.Storage => node.Comp.BlobStorage == null || TerminatingOrDeleted(node.Comp.BlobStorage),
|
|
BlobTileType.Turret => node.Comp.BlobTurret == null || TerminatingOrDeleted(node.Comp.BlobTurret),
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
public void DoLunge(EntityUid from, EntityUid target)
|
|
{
|
|
if(!TransformQuery.TryComp(from, out var userXform))
|
|
return;
|
|
|
|
var targetPos = _transform.GetWorldPosition(target);
|
|
var localPos = Vector2.Transform(targetPos, _transform.GetInvWorldMatrix(userXform));
|
|
localPos = userXform.LocalRotation.RotateVec(localPos);
|
|
|
|
RaiseNetworkEvent(new BlobAttackEvent(GetNetEntity(from), GetNetEntity(target), localPos), Filter.Pvs(from));
|
|
}
|
|
}
|