- add: Changeling antagonist (#2)
* Changeling WIP * UI * Pointers fix * Moved out abilities * Regenerate ability * Fixed Regenerate ability Prevent ghosting while regenerating * Cleanup * Base lesser form * Finished Lesser Form && Transform * Transform Sting * Blind Sting * Mute Sting Added OnExamine on absorbed human * Hallucination Sting Changeling Absorb and transfer absorbed entities to absorber * Cryogenic Sting * Adrenaline Sacs * Transform now uses Polymorph * Armblade, Shield, Armor * Tentacle Arm ability Tentacle Gun system * WIP with bugs * WiP bugs * fix implant transfer * Fixed bugs with shop transfer and actions transfer * Just in case * Vi sitter i ventrilo och spelar DotA * Fixes and proper LesserForm tracking * !!!!! * Fixed empty buttons * WIP Gamerule Ready - shop * nerf stun time cause its sucks * cleaning * just in case * Absorb DNA Objective. * Partial objectives with bugs * fix * fix pointer * Changeling objectives * Changeling objectives №2 * Admin verb, game rule * Fixed empty list check Icons for objectives * Changeling chat, changeling names etc. * fix some merge errors * - fix: Fixed all bugs with changeling --------- Co-authored-by: Y-Parvus <yevhen.parvus@gmail.com> Co-authored-by: Y-Parvus <61109031+Y-Parvus@users.noreply.github.com> Co-authored-by: HitPanda <104197232+EnefFlow@users.noreply.github.com> Co-authored-by: EnefFlow <regeto90@mail.ru>
This commit is contained in:
10
Content.Shared/Changeling/AbsorbedComponent.cs
Normal file
10
Content.Shared/Changeling/AbsorbedComponent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class AbsorbedComponent : Component
|
||||
{
|
||||
public EntityUid AbsorberMind;
|
||||
}
|
||||
70
Content.Shared/Changeling/ChangelingComponent.cs
Normal file
70
Content.Shared/Changeling/ChangelingComponent.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Content.Shared.Humanoid;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ChangelingComponent : Component
|
||||
{
|
||||
[DataField("chemRegenRate")]
|
||||
public int ChemicalRegenRate = 2;
|
||||
|
||||
[DataField("chemicalCap")]
|
||||
public int ChemicalCapacity = 75;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("chemicalsBalance")]
|
||||
public int ChemicalsBalance = 20;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("pointsBalance")]
|
||||
public int StartingPointsBalance = 10;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float Accumulator;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float UpdateDelay = 6f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool IsRegenerating;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool IsLesserForm;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string HiveName;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField("absorbedEntities")]
|
||||
public Dictionary<string, HumanoidData> AbsorbedEntities = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("AbsorbDNACost")]
|
||||
public int AbsorbDnaCost;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("AbsorbDNADelay")]
|
||||
public float AbsorbDnaDelay = 10f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("TransformDelay")]
|
||||
public float TransformDelay = 2f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("RegenerateDelay")]
|
||||
public float RegenerateDelay = 20f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("LesserFormDelay")]
|
||||
public float LesserFormDelay = 5f;
|
||||
|
||||
public bool IsInited;
|
||||
}
|
||||
|
||||
public struct HumanoidData
|
||||
{
|
||||
public EntityPrototype EntityPrototype;
|
||||
|
||||
public MetaDataComponent? MetaDataComponent;
|
||||
|
||||
public HumanoidAppearanceComponent AppearanceComponent;
|
||||
|
||||
public string Name;
|
||||
|
||||
public string Dna;
|
||||
}
|
||||
63
Content.Shared/Changeling/ChangelingNameGenerator.cs
Normal file
63
Content.Shared/Changeling/ChangelingNameGenerator.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Linq;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
public sealed class ChangelingNameGenerator
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private List<string> _used = new();
|
||||
|
||||
private readonly List<string> _greekAlphabet = new()
|
||||
{
|
||||
"Alpha",
|
||||
"Beta",
|
||||
"Gamma",
|
||||
"Delta",
|
||||
"Epsilon",
|
||||
"Zeta",
|
||||
"Eta",
|
||||
"Theta",
|
||||
"Iota",
|
||||
"Kappa",
|
||||
"Lambda",
|
||||
"Mu",
|
||||
"Nu",
|
||||
"Xi",
|
||||
"Omicron",
|
||||
"Pi",
|
||||
"Rho",
|
||||
"Sigma",
|
||||
"Tau",
|
||||
"Upsilon",
|
||||
"Phi",
|
||||
"Chi",
|
||||
"Psi",
|
||||
"Omega"
|
||||
};
|
||||
|
||||
private string GenWhiteLabelName()
|
||||
{
|
||||
var number = _random.Next(0,10000);
|
||||
return $"HiveMember-{number}";
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
_random.Shuffle(_greekAlphabet);
|
||||
|
||||
foreach (var selected in _greekAlphabet.Where(selected => !_used.Contains(selected)))
|
||||
{
|
||||
_used.Add(selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
return GenWhiteLabelName();
|
||||
}
|
||||
|
||||
public void ClearUsed()
|
||||
{
|
||||
_used.Clear();
|
||||
}
|
||||
}
|
||||
88
Content.Shared/Changeling/ChemicalsSystem.cs
Normal file
88
Content.Shared/Changeling/ChemicalsSystem.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
public sealed class ChemicalsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
public bool AddChemicals(EntityUid uid, ChangelingComponent component, int quantity)
|
||||
{
|
||||
if (_mobStateSystem.IsDead(uid))
|
||||
return false;
|
||||
|
||||
var toAdd = quantity;
|
||||
|
||||
if (component.ChemicalsBalance == component.ChemicalCapacity)
|
||||
return false;
|
||||
|
||||
if (component.ChemicalsBalance + toAdd > component.ChemicalCapacity)
|
||||
{
|
||||
var overflow = component.ChemicalsBalance + toAdd - component.ChemicalCapacity;
|
||||
toAdd -= overflow;
|
||||
component.ChemicalsBalance += toAdd;
|
||||
}
|
||||
|
||||
component.ChemicalsBalance += toAdd;
|
||||
Dirty(uid, component);
|
||||
|
||||
UpdateAlert(uid, component);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveChemicals(EntityUid uid, ChangelingComponent component, int quantity)
|
||||
{
|
||||
if (_mobStateSystem.IsDead(uid) && !component.IsRegenerating)
|
||||
return false;
|
||||
|
||||
var toRemove = quantity;
|
||||
|
||||
if (component.ChemicalsBalance == 0)
|
||||
return false;
|
||||
|
||||
if (component.ChemicalsBalance - toRemove < 0)
|
||||
return false;
|
||||
|
||||
component.ChemicalsBalance -= toRemove;
|
||||
Dirty(uid, component);
|
||||
|
||||
UpdateAlert(uid, component);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ChangelingComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
{
|
||||
component.Accumulator += frameTime;
|
||||
|
||||
if(component.Accumulator < component.UpdateDelay)
|
||||
continue;
|
||||
|
||||
if (component.IsRegenerating)
|
||||
continue;
|
||||
|
||||
component.Accumulator = 0;
|
||||
AddChemicals(uid, component, component.ChemicalRegenRate);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAlert(EntityUid uid, ChangelingComponent component)
|
||||
{
|
||||
if(_net.IsServer)
|
||||
{
|
||||
_alertsSystem.ShowAlert(uid, AlertType.Chemicals,
|
||||
(short) Math.Clamp(Math.Round(component.ChemicalsBalance / 10f), 0, 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class LesserFormRestrictedComponent : Component
|
||||
{
|
||||
}
|
||||
105
Content.Shared/Changeling/SharedChangeling.cs
Normal file
105
Content.Shared/Changeling/SharedChangeling.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class AbsorbDnaDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class AbsorbDnaActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class TransformDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public string SelectedDna;
|
||||
}
|
||||
|
||||
public sealed partial class TransformActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class RegenerateDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class RegenerateActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class LesserFormDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class LesserFormActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class TransformStingActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class BlindStingActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class MuteStingActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
public sealed partial class HallucinationStingActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class CryoStingActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class AdrenalineSacsActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class FleshmendActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class ArmbladeActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class OrganicShieldActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class ChitinousArmorActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class TentacleArmActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class ChangelingShopActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
33
Content.Shared/Changeling/SharedChangelingChat.cs
Normal file
33
Content.Shared/Changeling/SharedChangelingChat.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
public sealed class SharedChangelingChat : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ChangelingComponent, ComponentStartup>(OnInit);
|
||||
SubscribeLocalEvent<ChangelingComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, ChangelingComponent component, ComponentStartup args)
|
||||
{
|
||||
RaiseLocalEvent(new ChangelingUserStart(true));
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, ChangelingComponent component, ComponentShutdown args)
|
||||
{
|
||||
RaiseLocalEvent(new ChangelingUserStart(false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public sealed class ChangelingUserStart
|
||||
{
|
||||
public bool Created { get; }
|
||||
|
||||
public ChangelingUserStart(bool state)
|
||||
{
|
||||
Created = state;
|
||||
}
|
||||
}
|
||||
155
Content.Shared/Changeling/SharedTentacleGun.cs
Normal file
155
Content.Shared/Changeling/SharedTentacleGun.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Misc;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
public abstract class SharedTentacleGun : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||
[Dependency] private readonly ITimerManager _timerManager = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<TentacleGunComponent, GunShotEvent>(OnTentacleShot);
|
||||
SubscribeLocalEvent<TentacleProjectileComponent, ProjectileEmbedEvent>(OnTentacleCollide);
|
||||
}
|
||||
|
||||
private void OnTentacleShot(EntityUid uid, TentacleGunComponent component, ref GunShotEvent args)
|
||||
{
|
||||
foreach (var (shotUid, _) in args.Ammo)
|
||||
{
|
||||
if (!HasComp<TentacleProjectileComponent>(shotUid))
|
||||
continue;
|
||||
|
||||
Dirty(uid, component);
|
||||
var visuals = EnsureComp<JointVisualsComponent>(shotUid.Value);
|
||||
visuals.Sprite =
|
||||
new SpriteSpecifier.Rsi(new ResPath("Objects/Weapons/Guns/Launchers/tentacle_gun.rsi"), "frope");
|
||||
visuals.OffsetA = new Vector2(0f, 0.5f);
|
||||
visuals.Target = uid;
|
||||
Dirty(shotUid.Value, visuals);
|
||||
}
|
||||
|
||||
TryComp<AppearanceComponent>(uid, out var appearance);
|
||||
_appearance.SetData(uid, SharedTetherGunSystem.TetherVisualsStatus.Key, false, appearance);
|
||||
}
|
||||
|
||||
private void OnTentacleCollide(EntityUid uid, TentacleProjectileComponent component, ref ProjectileEmbedEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (!HasComp<TentacleGunComponent>(args.Weapon))
|
||||
{
|
||||
QueueDel(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<GunComponent>(args.Weapon, out var gun))
|
||||
{
|
||||
QueueDel(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasComp<HumanoidAppearanceComponent>(args.Embedded))
|
||||
{
|
||||
DeleteProjectile(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (gun.SelectedMode)
|
||||
{
|
||||
case SelectiveFire.PullMob when !PullMob(args):
|
||||
DeleteProjectile(uid);
|
||||
return;
|
||||
case SelectiveFire.PullMob:
|
||||
_timerManager.AddTimer(new Timer(1500, false, () =>
|
||||
{
|
||||
DeleteProjectile(uid);
|
||||
}));
|
||||
break;
|
||||
case SelectiveFire.PullItem:
|
||||
PullItem(args);
|
||||
DeleteProjectile(uid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PullItem(ProjectileEmbedEvent args)
|
||||
{
|
||||
foreach (var activeItem in _handsSystem.EnumerateHeld(args.Embedded))
|
||||
{
|
||||
if(!TryComp<PhysicsComponent>(activeItem, out var physicsComponent))
|
||||
return;
|
||||
|
||||
var coords = Transform(args.Embedded).Coordinates;
|
||||
_handsSystem.TryDrop(args.Embedded, coords);
|
||||
|
||||
var force = physicsComponent.Mass * 2.5f / 2;
|
||||
|
||||
_throwingSystem.TryThrow(activeItem, Transform(args.Shooter!.Value).Coordinates, force);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool PullMob(ProjectileEmbedEvent args)
|
||||
{
|
||||
var stunTime = _random.Next(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(8));
|
||||
|
||||
if (!_stunSystem.TryParalyze(args.Embedded, stunTime, true))
|
||||
return false;
|
||||
|
||||
_throwingSystem.TryThrow(args.Embedded, Transform(args.Shooter!.Value).Coordinates, 5f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DeleteProjectile(EntityUid projUid)
|
||||
{
|
||||
TryComp<AppearanceComponent>(projUid, out var appearance);
|
||||
|
||||
if (!Deleted(projUid))
|
||||
{
|
||||
if (_netManager.IsServer)
|
||||
{
|
||||
QueueDel(projUid);
|
||||
}
|
||||
}
|
||||
|
||||
_appearance.SetData(projUid, SharedTetherGunSystem.TetherVisualsStatus.Key, true, appearance);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed class RequestTentacleMessage : EntityEventArgs
|
||||
{
|
||||
public BoundKeyFunction Key;
|
||||
|
||||
public RequestTentacleMessage(BoundKeyFunction key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Content.Shared/Changeling/TentacleGunComponent.cs
Normal file
8
Content.Shared/Changeling/TentacleGunComponent.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class TentacleGunComponent : Component
|
||||
{
|
||||
}
|
||||
9
Content.Shared/Changeling/TentacleProjectileComponent.cs
Normal file
9
Content.Shared/Changeling/TentacleProjectileComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Changeling;
|
||||
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class TentacleProjectileComponent : Component
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user