mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-30 16:17:27 +00:00
* Merge pull request #838 from FoxxoTrystan/Shadekin Shadekin # Conflicts: # Resources/Prototypes/Body/species_base.yml # Resources/Prototypes/Entities/Mobs/Customization/Markings/tattoos.yml # Resources/Prototypes/Guidebook/species.yml # Resources/Prototypes/Species/species_weights.yml * Merge pull request #868 from FoxxoTrystan/Shadekin-Perf Shadekin Performence * Merge pull request #883 from FoxxoTrystan/Shadekin-Patch Shadekin Patch + Markings * Merge pull request #947 from RHSvenson/Shadekin_SurvivalBox Added and implemented emergency boxes for nonbreathers * Merge pull request #1861 from ilovehans10/shadekin-guidebook-typo-fixes Shadekin guidebook typo fixes * Mars -> Marrs (#2381) <!-- IT'S NOT WIZDENS REPO, IF YOU WANT TO ADD YOUR CHANGES ON ALL SERVERS, CREATE PR TO WIZDENS REPO --> <!-- What do you propose to change with your PR? --> Changes `@ mars` to `@ marr`s for Shadekin. <!-- What is the reason for adding these changes? Please post links to Discussions as well as Bug Reports here. Please describe how this will change the game balance. --> Parity with emote wheel. Also, `<PLAYERNAME> mars` feels weird. (...probably because Mars as in the planet.) <!-- If your PR contains in-game changes you must provide screenshots/videos of the changes. --> <!-- check boxes for faster reviewing of your PR --> - [X] I do not require assistance to complete the PR. - [X] Before posting/requesting review of a PR, I have verified that the changes work. - [X] I have added screenshots/videos of the changes, or this PR does not change in-game mechanics. - [X] I affirm that my changes are licensed under the [Starlight Fork License](https://github.com/ss14Starlight/space-station-14/blob/Starlight/LICENSE-Starlight.TXT) and grant permission for use in this repository under its conditions. **Changelog** 🆑 Fractalflower - tweak: Changed Mar emote text to `@ marrs`. * Fix shadekin guidebook resistance info (#2881) The shadekin guidebook currently overstates the cellular resistance by 10% and vastly underestimates the bloodloss damage. The guidebook being accurate helps guide player understanding. <img width="563" height="669" alt="image" src="https://github.com/user-attachments/assets/bece997a-5aa4-46f5-9b9f-2fe41dc98e97" /> - [X] I do not require assistance to complete the PR. - [X] Before posting/requesting review of a PR, I have verified that the changes work. - [X] I have added screenshots/videos of the changes, or this PR does not change in-game mechanics. - [X] I affirm that my changes are licensed under the [Starlight Fork License](https://github.com/ss14Starlight/space-station-14/blob/Starlight/LICENSE-Starlight.TXT) and grant permission for use in this repository under its conditions. **Changelog** 🆑 Penguinwizzard - fix: Turns out that we were issuing wildly incorrect guidebooks on Shadekin; an updated edition should now be available for crews. * New Shadekin Disabilities * Light hurts Shadekin Shadekin should get more than a mild sunburn in extreme light * Changes to make it work * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Foam Immunity Readded * Flash Modifer works now * Remove DarkLightComponent * Add missing Locale for Markings from Den * Fix Issues, Seperate from _DV namespace * Yaml Linter Fixes * ARGH * ARGHv.2 * ARGHv.3 * Nutribatard instead of Baguette * Exchange Nutribricks with PSB * Cotton Baguette * Changing away from BaseOrganic and Respirator Removal in Code * Fulfill Content Review Requests * Remove Eye Coloration - Unused * Remove ShadekinPhase entirely * Attribution correctly linked * Review Changes * done yml links correctly now * yml format in shadekin effects * Remove yml file mention and read Internal * Readd Internals * _StarLight -> _Starlight * Port to Nubody and maybe fixing some fuckups * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Shadekin Yaml Errors * Add missing markings name, add missing base_scale * Remove Internal Removal in base_species. Make it Component based * Add missing readonly * Remove Non Breahter emergency boxes, Shadekin normal box * DV Comment Fixes * Untouched File? * Use FlashMultiplierDurationEvent * Add missing attribution * Fixed scream attributions * Shadekins can now properly succumb. Starlight#4746 --------- Co-authored-by: Matthew Herber <32679887+Happyrobot33@users.noreply.github.com> Co-authored-by: FoxxoTrystan <45297731+FoxxoTrystan@users.noreply.github.com> Co-authored-by: Rinary <rinary.super@gmail.com> Co-authored-by: FoxxoTrystan <trystan.garnierhein@gmail.com> Co-authored-by: Tess_the_Evil <tessawfresh@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Tobias Berger <toby@tobot.dev> Co-authored-by: Vanessa <vanessalouwagie@gmail.com>
291 lines
11 KiB
C#
291 lines
11 KiB
C#
using Content.Shared.Humanoid;
|
|
using Content.Shared.Alert;
|
|
using Robust.Server.GameObjects;
|
|
using Content.Shared.Examine;
|
|
using Robust.Server.Containers;
|
|
using Content.Shared._Starlight;
|
|
using Content.Shared.Damage.Components;
|
|
using Content.Shared.Mobs;
|
|
using Content.Shared.Movement.Systems;
|
|
using Content.Shared.Movement.Components;
|
|
using Content.Shared.Damage;
|
|
using Content.Server.Chat.Managers;
|
|
using Content.Shared.Damage.Systems;
|
|
using Content.Shared._Goobstation.Overlays;
|
|
using Robust.Shared.Timing;
|
|
using Content.Server.Body.Components;
|
|
using System.Linq;
|
|
using Content.Shared._Goobstation.Flashbang;
|
|
using Content.Shared._Starlight.Flash.Components;
|
|
using Content.Shared.Body.Components;
|
|
using Content.Shared.Flash; // Delta V - Flash Work
|
|
|
|
|
|
namespace Content.Server._Starlight;
|
|
|
|
public sealed class ShadekinSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly IGameTiming _timing = default!;
|
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
|
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
|
[Dependency] private readonly ContainerSystem _container = default!;
|
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
[Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
|
|
[Dependency] private readonly SharedFlashSystem _flashSystem = default!;
|
|
|
|
private sealed class LightCone
|
|
{
|
|
public float Direction { get; set; }
|
|
public float InnerWidth { get; set; }
|
|
public float OuterWidth { get; set; }
|
|
}
|
|
private readonly Dictionary<string, List<LightCone>> lightMasks = new()
|
|
{
|
|
["/Textures/Effects/LightMasks/cone.png"] = new List<LightCone>
|
|
{
|
|
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 }
|
|
},
|
|
["/Textures/Effects/LightMasks/double_cone.png"] = new List<LightCone>
|
|
{
|
|
new LightCone { Direction = 0, InnerWidth = 30, OuterWidth = 60 },
|
|
new LightCone { Direction = 180, InnerWidth = 30, OuterWidth = 60 }
|
|
}
|
|
};
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
SubscribeLocalEvent<ShadekinComponent, ComponentStartup>(OnInit);
|
|
SubscribeLocalEvent<ShadekinComponent, EyeColorInitEvent>(OnEyeColorChange);
|
|
SubscribeLocalEvent<ShadekinComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
|
|
SubscribeLocalEvent<ShadekinComponent, AfterFlashedEvent>(OnShadekinFlashed); // Delta V - Prevent Chain Flashing
|
|
SubscribeLocalEvent<ShadekinComponent, FlashDurationMultiplierEvent>(GetFlashModifier); // Delta V - Flash Modifier to Shadekin
|
|
}
|
|
|
|
private void OnInit(EntityUid uid, ShadekinComponent component, ComponentStartup args)
|
|
{
|
|
UpdateAlert(uid, component, (short)component.CurrentState);
|
|
RemComp<InternalsComponent>(uid);
|
|
}
|
|
|
|
private void OnEyeColorChange(EntityUid uid, ShadekinComponent component, EyeColorInitEvent args)
|
|
{
|
|
if (!TryComp<HumanoidProfileComponent>(uid, out var humanoid))
|
|
return;
|
|
|
|
// humanoid.EyeColor = Color.Black;
|
|
Dirty(uid, humanoid);
|
|
}
|
|
|
|
public void UpdateAlert(EntityUid uid, ShadekinComponent component, short state)
|
|
{
|
|
_alerts.ShowAlert(uid, component.ShadekinAlert, state);
|
|
}
|
|
|
|
private Angle GetAngle(EntityUid lightUid, SharedPointLightComponent lightComp, EntityUid targetUid)
|
|
{
|
|
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(lightUid);
|
|
lightPos += lightRot.RotateVec(lightComp.Offset);
|
|
|
|
var (targetPos, targetRot) = _transform.GetWorldPositionRotation(targetUid);
|
|
|
|
var mapDiff = targetPos - lightPos;
|
|
|
|
var oppositeMapDiff = (-lightRot).RotateVec(mapDiff);
|
|
var angle = oppositeMapDiff.ToWorldAngle();
|
|
|
|
if (angle == double.NaN && _transform.ContainsEntity(targetUid, lightUid) || _transform.ContainsEntity(lightUid, targetUid))
|
|
{
|
|
angle = 0f;
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return an illumination float value with is how many "energy" of light is hitting our ent.
|
|
/// WARNING: This function might be expensive, Avoid calling it too much and CACHE THE RESULT!
|
|
/// </summary>
|
|
/// <param name="uid"></param>
|
|
/// <returns></returns>
|
|
public float GetLightExposure(EntityUid uid)
|
|
{
|
|
var illumination = 0f;
|
|
|
|
var lightQuery = _lookup.GetEntitiesInRange<PointLightComponent>(Transform(uid).Coordinates, 20, LookupFlags.Uncontained);
|
|
|
|
foreach (var light in lightQuery)
|
|
{
|
|
if (!light.Comp.Enabled
|
|
|| light.Comp.Radius < 1
|
|
|| light.Comp.Energy <= 0)
|
|
continue;
|
|
|
|
var (lightPos, lightRot) = _transform.GetWorldPositionRotation(light);
|
|
lightPos += lightRot.RotateVec(light.Comp.Offset);
|
|
|
|
if (!_examine.InRangeUnOccluded(light, uid, light.Comp.Radius, null))
|
|
continue;
|
|
|
|
Transform(uid).Coordinates.TryDistance(EntityManager, Transform(light).Coordinates, out var dist);
|
|
|
|
var denom = dist / light.Comp.Radius;
|
|
var attenuation = 1 - (denom * denom);
|
|
var calculatedLight = 0f;
|
|
|
|
if (light.Comp.MaskPath is not null)
|
|
{
|
|
var angleToTarget = GetAngle(light, light.Comp, uid);
|
|
foreach (var cone in lightMasks[light.Comp.MaskPath])
|
|
{
|
|
var coneLight = 0f;
|
|
var angleAttenuation = (float)Math.Min((float)Math.Max(cone.OuterWidth - angleToTarget, 0f), cone.InnerWidth) / cone.OuterWidth;
|
|
|
|
if (angleToTarget.Degrees - cone.Direction > cone.OuterWidth)
|
|
continue;
|
|
else if (angleToTarget.Degrees - cone.Direction > cone.InnerWidth
|
|
&& angleToTarget.Degrees - cone.Direction < cone.OuterWidth)
|
|
coneLight = light.Comp.Energy * attenuation * attenuation * angleAttenuation;
|
|
else
|
|
coneLight = light.Comp.Energy * attenuation * attenuation;
|
|
|
|
calculatedLight = Math.Max(calculatedLight, coneLight);
|
|
}
|
|
}
|
|
else
|
|
calculatedLight = light.Comp.Energy * attenuation * attenuation;
|
|
|
|
illumination += calculatedLight; //Math.Max(illumination, calculatedLight);
|
|
}
|
|
|
|
return illumination;
|
|
}
|
|
|
|
private void SetPassiveBuff(EntityUid uid, ShadekinState state)
|
|
{
|
|
if (!TryComp<PassiveDamageComponent>(uid, out var passive))
|
|
return;
|
|
|
|
if (state == ShadekinState.Extreme || state == ShadekinState.Annoying || state == ShadekinState.High)
|
|
{
|
|
// passive.DamageCap = 1;
|
|
}
|
|
else if (state == ShadekinState.Low)
|
|
{
|
|
// passive.DamageCap = 20;
|
|
passive.AllowedStates.Clear();
|
|
passive.AllowedStates.Add(MobState.Alive);
|
|
passive.Interval = 1f;
|
|
}
|
|
else if (state != ShadekinState.Dark)
|
|
{
|
|
// passive.DamageCap = 0;
|
|
passive.AllowedStates.Clear();
|
|
passive.AllowedStates.Add(MobState.Alive);
|
|
passive.AllowedStates.Add(MobState.Critical);
|
|
passive.AllowedStates.Add(MobState.Dead);
|
|
passive.Interval = 0.5f;
|
|
}
|
|
}
|
|
|
|
private void ToggleNightVision(EntityUid uid, ShadekinState state)
|
|
{
|
|
if (state == ShadekinState.Dark)
|
|
{
|
|
var nightVisionComponent = EnsureComp<NightVisionComponent>(uid);
|
|
nightVisionComponent.Color = Color.FromHex("#808080"); // Delta V - Change Night Vision Color
|
|
}
|
|
else
|
|
{
|
|
if (TryComp<NightVisionComponent>(uid, out var nightVision) && nightVision.IsActive)
|
|
_flashSystem.Flash(uid, uid, uid, TimeSpan.FromSeconds(0.5 * (int)state), 0.5f);
|
|
RemComp<NightVisionComponent>(uid);
|
|
}
|
|
}
|
|
|
|
private void ApplyLightDamage(EntityUid uid, float dmg)
|
|
{
|
|
var damage = new DamageSpecifier();
|
|
damage.DamageDict.Add("Heat", dmg);
|
|
_damageable.TryChangeDamage(uid, damage, true, false);
|
|
|
|
}
|
|
|
|
private void OnRefreshMovementSpeedModifiers(EntityUid uid, ShadekinComponent component, RefreshMovementSpeedModifiersEvent args)
|
|
{
|
|
if (component.CurrentState == ShadekinState.Low || component.CurrentState == ShadekinState.Annoying ||
|
|
component.CurrentState == ShadekinState.Dark || component.CurrentState == ShadekinState.Invalid)
|
|
return;
|
|
|
|
if (!TryComp<MovementSpeedModifierComponent>(uid, out var movement))
|
|
return;
|
|
|
|
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
|
|
args.ModifySpeed(1f, sprintDif);
|
|
}
|
|
|
|
private ShadekinState GetStateByThreshold(ShadekinComponent component, float lightExposure)
|
|
{
|
|
var returnState = ShadekinState.Dark;
|
|
|
|
foreach (var (threshold, shadekinState) in component.Thresholds.Reverse())
|
|
{
|
|
if (threshold <= lightExposure)
|
|
{
|
|
returnState = shadekinState;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return returnState;
|
|
}
|
|
|
|
// Delta V - Begin Shadekin Flash Changes
|
|
private void GetFlashModifier(EntityUid uid, ShadekinComponent comp, FlashDurationMultiplierEvent args)
|
|
{
|
|
if (!TryComp<FlashModifierComponent>(uid, out var flashModifier))
|
|
return;
|
|
|
|
args.Multiplier = flashModifier.Modifier;
|
|
}
|
|
|
|
private void OnShadekinFlashed(EntityUid uid, ShadekinComponent comp, AfterFlashedEvent ev)
|
|
{
|
|
RemComp<NightVisionComponent>(uid);
|
|
}
|
|
// Delta V - End
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
var query = EntityQueryEnumerator<ShadekinComponent>();
|
|
while (query.MoveNext(out var uid, out var component))
|
|
{
|
|
if (_timing.CurTime < component.NextUpdate)
|
|
continue;
|
|
|
|
component.NextUpdate = _timing.CurTime + component.UpdateCooldown;
|
|
|
|
var lightExposure = 0f;
|
|
|
|
if (!_container.IsEntityInContainer(uid))
|
|
lightExposure = GetLightExposure(uid);
|
|
|
|
component.CurrentState = GetStateByThreshold(component, lightExposure);
|
|
|
|
UpdateAlert(uid, component, (short)component.CurrentState);
|
|
|
|
SetPassiveBuff(uid, component.CurrentState);
|
|
ToggleNightVision(uid, component.CurrentState);
|
|
|
|
_speed.RefreshMovementSpeedModifiers(uid);
|
|
|
|
if (component.CurrentState == ShadekinState.Extreme)
|
|
ApplyLightDamage(uid, 5);
|
|
}
|
|
}
|
|
}
|