Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Playable Species: Lamia #479

Closed
wants to merge 64 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
3a39c93
Noodle Begins
VMSolidus Nov 25, 2023
66261be
Starting the process of moving this code to Shared & Client
VMSolidus Nov 26, 2023
167e817
Adding lamia unique melee
VMSolidus Nov 26, 2023
e18792c
Update lamia.yml
VMSolidus Nov 26, 2023
fdcec2b
Making a pass at their YAML
VMSolidus Nov 27, 2023
c5b74c9
More lamia updating
VMSolidus Nov 27, 2023
1f43f42
LamiaSystem is returning to the server again
VMSolidus Dec 12, 2023
bfcc825
More in progress stuff
VMSolidus Dec 15, 2023
1d43bb8
Create LamiaSegmentVisuals.cs
VMSolidus Dec 15, 2023
4343a59
Update visualizer
VMSolidus Dec 15, 2023
30b2913
Update lamia.yml
VMSolidus Dec 15, 2023
29aaeee
Revert "Update lamia.yml"
VMSolidus Dec 17, 2023
2d5907f
Revert "Update visualizer"
VMSolidus Dec 17, 2023
9791058
Revert "Create LamiaSegmentVisuals.cs"
VMSolidus Dec 17, 2023
6b2178b
Revert "More in progress stuff"
VMSolidus Dec 17, 2023
b02baa8
Revert "LamiaSystem is returning to the server again"
VMSolidus Dec 17, 2023
328dd81
Reverting to the last state where we could spawn a Lamia
VMSolidus Dec 17, 2023
2ef3922
We can now spawn the noodles again
VMSolidus Dec 17, 2023
1afed6c
Update reptilian.yml
VMSolidus Dec 19, 2023
75ebdfb
We were missing the SegmentSpawnedEvent
VMSolidus Dec 20, 2023
2ae540e
Update lamia.yml
VMSolidus Dec 21, 2023
ac26da0
Now requires engine changes.
VMSolidus Dec 21, 2023
1de4898
Markings but not colors
VMSolidus Dec 23, 2023
75592e7
This is the closest we have so far
VMSolidus Dec 24, 2023
4a8e58c
Marking parity!
VMSolidus Dec 28, 2023
7d61b90
Update LamiaSystem.cs
VMSolidus Dec 28, 2023
88acba9
Blacklisting Lamia from Storage Containers
VMSolidus Dec 28, 2023
e06a24e
I promise you debug this isn't abandoned
VMSolidus Jan 29, 2024
dbe3f73
I finally return to this after a hiatus to finish Harpies
VMSolidus Feb 14, 2024
1260a49
Hardsuit Sprite Transfer
VMSolidus Feb 14, 2024
f336925
prevent snakes from wearing pants
VMSolidus Feb 14, 2024
7623b91
Masking helpers are no longer needed, 1984 anytaur mask
VMSolidus Feb 14, 2024
ea7e989
Lamia can no longer hurt themselves
VMSolidus Feb 14, 2024
66a7155
Lamia can now shoot over tail
VMSolidus Feb 14, 2024
7617e5c
Update LamiaSystem.cs
VMSolidus Feb 14, 2024
95861db
Update lamia.yml
VMSolidus Feb 14, 2024
8451fb8
Yee
VMSolidus Feb 14, 2024
d306080
New working version
VMSolidus Feb 16, 2024
ff47568
damage system refactor
VMSolidus Feb 17, 2024
5570b5f
more equation fine tuning
VMSolidus Feb 17, 2024
e104a47
Update LamiaSystem.cs
VMSolidus Feb 17, 2024
42626e1
Update lamia.yml
VMSolidus Feb 17, 2024
fe2da01
Fixing the portal bug
VMSolidus Feb 17, 2024
556ed46
Segment system refactor complete
VMSolidus Feb 17, 2024
2948ff4
Beeg final push for Beta
VMSolidus Feb 20, 2024
7b15fb6
RSI fixes
VMSolidus Feb 20, 2024
05e3581
APGLv3
VMSolidus Feb 20, 2024
f77370f
Update lamia.yml
VMSolidus Feb 20, 2024
16e5c2c
send it
VMSolidus Feb 20, 2024
dbfc60d
More small fixes
VMSolidus Feb 20, 2024
0bcf28c
guh
VMSolidus Feb 20, 2024
d94f992
more
VMSolidus Feb 20, 2024
0945487
A bunch of placeholders needed to pass tests
VMSolidus Feb 20, 2024
54dd099
1984 the onhitself subscription
VMSolidus Mar 6, 2024
4f5846c
Update LamiaSystem.cs
VMSolidus Mar 11, 2024
9895f41
Rules Update (#952)
GreggTheFather Mar 12, 2024
3b76403
Automatic changelog update
DeltaV-Bot Mar 12, 2024
4f3cdc3
Update submodule to 212.0.2 (#959)
DebugOk Mar 12, 2024
fab4443
Automatic changelog update
DeltaV-Bot Mar 12, 2024
2e8fabc
Fix Edge Boxer room access (#960)
Colin-Tel Mar 13, 2024
4a75faf
pebble hotfix two, eletric boogaloo (#943)
UnicornOnLSD Mar 13, 2024
0d6350f
Automatic changelog update
DeltaV-Bot Mar 13, 2024
0292d4e
Update toys.yml
DebugOk Mar 14, 2024
a3b4ca5
Map Edits: Arena (#964)
IamVelcroboy Mar 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions Content.Client/DeltaV/Lamiae/ClientLamiaVisuals.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Delta-V - This file is licensed under AGPLv3
* Copyright (c) 2024 Delta-V Contributors
* See AGPLv3.txt for details.
*/

using Robust.Client.GameObjects;
using System.Numerics;
using Content.Shared.DeltaV.Lamiae;

namespace Content.Client.DeltaV.Lamiae;

public sealed class ClientLamiaVisualSystem : VisualizerSystem<LamiaSegmentVisualsComponent>
{

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

SubscribeLocalEvent<LamiaSegmentComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(EntityUid uid, LamiaSegmentComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null) return;

if (AppearanceSystem.TryGetData<float>(uid, ScaleVisuals.Scale, out var scale) && TryComp<SpriteComponent>(uid, out var sprite))
{
sprite.Scale = (new Vector2(scale, scale));
}

if (AppearanceSystem.TryGetData<bool>(uid, LamiaSegmentVisualLayers.Armor, out var worn)
&& AppearanceSystem.TryGetData<string>(uid, LamiaSegmentVisualLayers.ArmorRsi, out var path))
{
var valid = !string.IsNullOrWhiteSpace(path);
if (valid)
{
args.Sprite.LayerSetRSI(LamiaSegmentVisualLayers.Armor, path);
}
args.Sprite.LayerSetVisible(LamiaSegmentVisualLayers.Armor, worn);
}
}
}
11 changes: 11 additions & 0 deletions Content.Client/DeltaV/Lamiae/LamiaSegmentVisualsComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Delta-V - This file is licensed under AGPLv3
* Copyright (c) 2024 Delta-V Contributors
* See AGPLv3.txt for details.
*/

namespace Content.Client.DeltaV.Lamiae;

[RegisterComponent]
public sealed partial class LamiaSegmentVisualsComponent : Component
{}
283 changes: 283 additions & 0 deletions Content.Server/DeltaV/Lamiae/LamiaSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
/*
* Delta-V - This file is licensed under AGPLv3
* Copyright (c) 2024 Delta-V Contributors
* See AGPLv3.txt for details.
*/

using Robust.Shared.Physics;
using Content.Shared.Damage;
using Content.Shared.Explosion;
using Content.Shared.Clothing.Components;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Server.Humanoid;
using Content.Shared.Inventory.Events;
using Content.Shared.Tag;
using Content.Shared.Teleportation.Components;
using Content.Shared.Standing;
using Content.Shared.Storage.Components;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Physics.Components;
using System.Numerics;
using Content.Shared.DeltaV.Lamiae;

namespace Content.Server.DeltaV.Lamiae
{
public sealed partial class LamiaSystem : EntitySystem
{
[Dependency] private readonly SharedJointSystem _jointSystem = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;

[ValidatePrototypeId<TagPrototype>]
private const string LamiaHardsuitTag = "AllowLamiaHardsuit";

Queue<(LamiaSegmentComponent segment, EntityUid lamia)> _segments = new();
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var segment in _segments)
{
var segmentUid = segment.segment.Owner;
var attachedUid = segment.segment.AttachedToUid;
if (!Exists(segmentUid) || !Exists(attachedUid)
|| MetaData(segmentUid).EntityLifeStage > EntityLifeStage.MapInitialized
|| MetaData(attachedUid).EntityLifeStage > EntityLifeStage.MapInitialized
|| Transform(segmentUid).MapID == MapId.Nullspace
|| Transform(attachedUid).MapID == MapId.Nullspace)
continue;

EnsureComp<PhysicsComponent>(segmentUid);
EnsureComp<PhysicsComponent>(attachedUid); // Hello I hate tests

var ev = new SegmentSpawnedEvent(segment.lamia);
RaiseLocalEvent(segmentUid, ev, false);

if (segment.segment.SegmentNumber == 1)
{
Transform(segmentUid).Coordinates = Transform(attachedUid).Coordinates;
var revoluteJoint = _jointSystem.CreateWeldJoint(attachedUid, segmentUid, id: ("Segment" + segment.segment.SegmentNumber + segment.segment.Lamia));
revoluteJoint.CollideConnected = false;
}
if (segment.segment.SegmentNumber < segment.segment.MaxSegments)
Transform(segmentUid).Coordinates = Transform(attachedUid).Coordinates.Offset(new Vector2(0, segment.segment.OffsetSwitching));
else
Transform(segmentUid).Coordinates = Transform(attachedUid).Coordinates.Offset(new Vector2(0, segment.segment.OffsetSwitching));

var joint = _jointSystem.CreateDistanceJoint(attachedUid, segmentUid, id: ("Segment" + segment.segment.SegmentNumber + segment.segment.Lamia));
joint.CollideConnected = false;
joint.Stiffness = 0.2f;
}
_segments.Clear();
}
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LamiaComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<LamiaComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<LamiaComponent, JointRemovedEvent>(OnJointRemoved);
SubscribeLocalEvent<LamiaComponent, EntGotRemovedFromContainerMessage>(OnRemovedFromContainer);
SubscribeLocalEvent<LamiaSegmentComponent, SegmentSpawnedEvent>(OnSegmentSpawned);
SubscribeLocalEvent<LamiaSegmentComponent, DamageChangedEvent>(HandleDamageTransfer);
SubscribeLocalEvent<LamiaSegmentComponent, DamageModifyEvent>(HandleSegmentDamage);
SubscribeLocalEvent<LamiaComponent, InsertIntoEntityStorageAttemptEvent>(OnLamiaStorageInsertAttempt);
SubscribeLocalEvent<LamiaSegmentComponent, InsertIntoEntityStorageAttemptEvent>(OnSegmentStorageInsertAttempt);
SubscribeLocalEvent<LamiaComponent, DidEquipEvent>(OnDidEquipEvent);
SubscribeLocalEvent<LamiaComponent, DidUnequipEvent>(OnDidUnequipEvent);
SubscribeLocalEvent<LamiaSegmentComponent, StandAttemptEvent>(TailCantStand);
SubscribeLocalEvent<LamiaSegmentComponent, GetExplosionResistanceEvent>(OnSnekBoom);
}

/// <summary>
/// Handles transferring marking selections to the tail segments. Every tail marking must be repeated 2 times in order for this script to work.
/// </summary>
/// <param name="uid"></param>
/// <param name="component"></param>
/// <param name="args"></param>
// TODO: Please for the love of god don't make me write a test to validate that every marking also has its matching segment states.
// Future contributors will just find out when their game crashes because they didn't make a marking-segment.
private void OnSegmentSpawned(EntityUid uid, LamiaSegmentComponent component, SegmentSpawnedEvent args)
{
component.Lamia = args.Lamia;
if (component.BulletPassover == true)
_standing.Down(uid, false);

if (!TryComp<HumanoidAppearanceComponent>(uid, out var species)) return;
if (!TryComp<HumanoidAppearanceComponent>(args.Lamia, out var humanoid)) return;
if (!TryComp<AppearanceComponent>(uid, out var appearance)) return;

_appearance.SetData(uid, ScaleVisuals.Scale, component.ScaleFactor, appearance);

if (humanoid.MarkingSet.TryGetCategory(MarkingCategories.Tail, out var tailMarkings))
{
foreach (var markings in tailMarkings)
{
var segmentId = species.Species;
var markingId = markings.MarkingId;
string segmentmarking = $"{markingId}-{segmentId}";
_humanoid.AddMarking(uid, segmentmarking, markings.MarkingColors);
}
}
}

private void OnInit(EntityUid uid, LamiaComponent component, ComponentInit args)
{
Math.Clamp(component.NumberOfSegments, 2, 30);
Math.Clamp(component.TaperOffset, 1, component.NumberOfSegments - 1);
SpawnSegments(uid, component);
}

private void OnShutdown(EntityUid uid, LamiaComponent component, ComponentShutdown args)
{
foreach (var segment in component.Segments)
{
QueueDel(segment);
}

component.Segments.Clear();
}

private void OnJointRemoved(EntityUid uid, LamiaComponent component, JointRemovedEvent args)
{
if (!component.Segments.Contains(args.OtherBody.Owner))
return;

if (HasComp<PortalTimeoutComponent>(uid)) return;

foreach (var segment in component.Segments)
QueueDel(segment);

component.Segments.Clear();
}

private void OnRemovedFromContainer(EntityUid uid, LamiaComponent component, EntGotRemovedFromContainerMessage args)
{
if (component.Segments.Count != 0)
{
foreach (var segment in component.Segments)
QueueDel(segment);
component.Segments.Clear();
}

SpawnSegments(uid, component);
}

private void HandleSegmentDamage(EntityUid uid, LamiaSegmentComponent component, DamageModifyEvent args)
{
if (args.Origin == component.Lamia)
args.Damage *= 0;
args.Damage = args.Damage / component.DamageModifyFactor;
}
private void HandleDamageTransfer(EntityUid uid, LamiaSegmentComponent component, DamageChangedEvent args)
{
if (args.DamageDelta == null) return;
_damageableSystem.TryChangeDamage(component.Lamia, args.DamageDelta);
}

private void TailCantStand(EntityUid uid, LamiaSegmentComponent component, StandAttemptEvent args)
{
if (component.BulletPassover == true)
args.Cancel();
}

public void SpawnSegments(EntityUid uid, LamiaComponent component)
{
int i = 1;
var addTo = uid;
while (i < component.NumberOfSegments + 1)
{
var segment = AddSegment(addTo, uid, component, i);
addTo = segment;
i++;
}
}

private EntityUid AddSegment(EntityUid uid, EntityUid lamia, LamiaComponent lamiaComponent, int segmentNumber)
{
LamiaSegmentComponent segmentComponent = new();
segmentComponent.MaxSegments = lamiaComponent.NumberOfSegments;
segmentComponent.BulletPassover = lamiaComponent.BulletPassover;
segmentComponent.Lamia = lamia;
segmentComponent.AttachedToUid = uid;
segmentComponent.DamageModifierConstant = lamiaComponent.NumberOfSegments * lamiaComponent.DamageModifierOffset;
float taperConstant = lamiaComponent.NumberOfSegments - lamiaComponent.TaperOffset;
float damageModifyCoefficient = segmentComponent.DamageModifierConstant / lamiaComponent.NumberOfSegments;
segmentComponent.DamageModifyFactor = segmentComponent.DamageModifierConstant * damageModifyCoefficient;
segmentComponent.ExplosiveModifyFactor = 1 / segmentComponent.DamageModifyFactor / (lamiaComponent.NumberOfSegments * lamiaComponent.ExplosiveModifierOffset);

EntityUid segment;
if (segmentNumber == 1)
segment = EntityManager.SpawnEntity(lamiaComponent.InitialSegmentId, Transform(uid).Coordinates);
else
segment = EntityManager.SpawnEntity(lamiaComponent.SegmentId, Transform(uid).Coordinates);
if (segmentNumber >= taperConstant && lamiaComponent.UseTaperSystem == true)
{
segmentComponent.OffsetSwitching = lamiaComponent.StaticOffset * MathF.Pow(lamiaComponent.OffsetConstant, segmentNumber - taperConstant);
segmentComponent.ScaleFactor = lamiaComponent.StaticScale * MathF.Pow(1f / lamiaComponent.OffsetConstant, segmentNumber - taperConstant);
} else
{
segmentComponent.OffsetSwitching = lamiaComponent.StaticOffset;
segmentComponent.ScaleFactor = lamiaComponent.StaticScale;
}
if (segmentNumber % 2 != 0)
{
segmentComponent.OffsetSwitching *= -1;
}

segmentComponent.Owner = segment;
segmentComponent.SegmentNumber = segmentNumber;
EntityManager.AddComponent(segment, segmentComponent, true);

_segments.Enqueue((segmentComponent, lamia));
lamiaComponent.Segments.Add(segmentComponent.Owner);
return segment;
}

private void OnLamiaStorageInsertAttempt(EntityUid uid, LamiaComponent comp, ref InsertIntoEntityStorageAttemptEvent args)
{
args.Cancelled = true;
}

private void OnSegmentStorageInsertAttempt(EntityUid uid, LamiaSegmentComponent comp, ref InsertIntoEntityStorageAttemptEvent args)
{
args.Cancelled = true;
}

private void OnDidEquipEvent(EntityUid equipee, LamiaComponent component, DidEquipEvent args)
{
if (!TryComp<ClothingComponent>(args.Equipment, out var clothing)) return;
if (args.Slot == "outerClothing" && _tagSystem.HasTag(args.Equipment, LamiaHardsuitTag))
{
foreach (var uid in component.Segments)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance)) return;
_appearance.SetData(uid, LamiaSegmentVisualLayers.Armor, true, appearance);
if (clothing.RsiPath == null) return;
_appearance.SetData(uid, LamiaSegmentVisualLayers.ArmorRsi, clothing.RsiPath, appearance);
}
}
}

private void OnSnekBoom(EntityUid uid, LamiaSegmentComponent component, ref GetExplosionResistanceEvent args)
{
args.DamageCoefficient = component.ExplosiveModifyFactor;
}

private void OnDidUnequipEvent(EntityUid equipee, LamiaComponent component, DidUnequipEvent args)
{
if (args.Slot == "outerClothing" && _tagSystem.HasTag(args.Equipment, LamiaHardsuitTag))
{
foreach (var uid in component.Segments)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance)) return;
_appearance.SetData(uid, LamiaSegmentVisualLayers.Armor, false, appearance);
}
}
}
}
}
18 changes: 17 additions & 1 deletion Content.Server/Teleportation/PortalSystem.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Content.Shared.Administration.Logs;
using Content.Server.DeltaV.Lamiae; //DeltaV
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Ghost;
using Content.Shared.Mind.Components;
using Content.Shared.DeltaV.Lamiae; //DeltaV
using Content.Shared.Teleportation.Systems;
using Robust.Shared.Map;

Expand All @@ -10,12 +12,26 @@ namespace Content.Server.Teleportation;
public sealed class PortalSystem : SharedPortalSystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly LamiaSystem _lamia = default!; //DeltaV

// TODO Move to shared
protected override void LogTeleport(EntityUid portal, EntityUid subject, EntityCoordinates source,
EntityCoordinates target)
{
if (HasComp<MindContainerComponent>(subject) && !HasComp<GhostComponent>(subject))
_adminLogger.Add(LogType.Teleport, LogImpact.Low, $"{ToPrettyString(subject):player} teleported via {ToPrettyString(portal)} from {source} to {target}");

//Start DeltaV Code, stops Lamia from crashing because they can't take their tail through a portal
if (TryComp<LamiaComponent>(subject, out var lamia))
{
foreach (var segment in lamia.Segments)
{
QueueDel(segment);
}
lamia.Segments.Clear();
_lamia.SpawnSegments(subject, lamia);
}
//End DeltaV Code
}

}
Loading
Loading