Files
Delta-v/Content.Shared/GhostTypes/GhostSpriteStateSystem.cs
T
DisposableCrewmember42andThinbug 0ce8d934f4 cherry-pick: upstream's damage-dependent ghost sprites (#5516)
Ghost types  (space-wizards/space-station-14#37949)

* Empty commit

* yeah thingi

* added a GetHighestDamageTypes thingi to the DamageableSystem

* no idea why those files names are different only in github so just in case readding them

* yeah doing that

* first steps of moving the logic somewhere nicer

* still plenty to do

* gosh such a mess but getting progress done

* small fixie push

* big mess of bunch of stuff

* dealing with a conflict and fixing the random numbers

* testing if github will update now

* dealing with the other conflict

* github please update i beg you

* dealing with more conflicts

* hopefully this fixes it

* fixing conflicts again

* cleaning up stuffies

* sprite fixie

* general cleanup

* doing the small fixies first

* getting rid of the new event, gotta handle ashing next

* adding spaces to comments before i forget

* handling ashing

* think that did it?

* small fixies

* more small fixies

* last batch of quickie fixies before i gotta handle the bigger stuff

* last bunch of fixies i do understand

* small bit of progress yknow may as well yeah

* renaming and moving stuff to shared

* comment fixiees

* saving damage in a new component instead of in MindComponent

* protoid's and dict usage instead of the previously ickier methods

* small fixie before biggie fixie

* more fixies im slepy gosh

* thinkie that should fixie it

* smoothed the damage storage systeem so its less repetitive and icki and now itss cooler and i can go eepy

* lots of stuffies x3

* first step of getting git to detect my file name changes

* thinkie that should fixie it

* fixies

* just getting rid of the merge conflict, will check damageable later

* small thingies first

* more small stuffiees

* now all of the sprites have at leeast a 0

* dirtying the lastbody comp

* more fixies

* small thingi first

* another small fixie and a minor sprite fixie

* rng fixie

* moving the damage storage system to shared

* smoothing out code thats likely to be replaced soon but its good to do for now

* just showing progress bcus yis

* general progress stuffies mhm

* pushie

* small cleanup

* general progress :3

* in progress push for helpie

* proper pushie with progress and workies

* removed unnecessary usage of the storedamage component

* minor fixiees

* extra comments

* replaced a couple strings for ProtoId's

* gibbing related fixies :3

Signed-off-by: DisposableCrewmember42 <disposablecrewmember42@proton.me>
Co-authored-by: Thinbug <101073555+Thinbug0@users.noreply.github.com>
2026-04-04 21:39:24 +02:00

71 lines
2.7 KiB
C#

using System.Linq;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.FixedPoint;
using Content.Shared.Ghost;
using Content.Shared.Mind;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Shared.GhostTypes;
public sealed class GhostSpriteStateSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
/// <summary>
/// It goes through an entity damage and assigns them a sprite according to the highest damage type/s
/// </summary>
public void SetGhostSprite(Entity<GhostSpriteStateComponent?> ent, EntityUid mind)
{
if (!Resolve(ent, ref ent.Comp))
return;
if (!TryComp<AppearanceComponent>(ent, out var appearance) || !HasComp<MindComponent>(mind))
return;
var damageTypes = new Dictionary<ProtoId<DamageTypePrototype>, FixedPoint2>();
ProtoId<SpecialCauseOfDeathPrototype>? specialCase = null;
if (!TryComp<LastBodyDamageComponent>(mind, out var storedDamage))
return;
if (storedDamage.DamagePerGroup != null && storedDamage.Damage != null)
{
damageTypes = _damageable.GetDamages(storedDamage.DamagePerGroup, storedDamage.Damage);
}
specialCase = storedDamage.SpecialCauseOfDeath;
Dirty(mind, storedDamage);
var damageTypesSorted = damageTypes.OrderByDescending(x => x.Value).ToDictionary();
if (damageTypesSorted.Count == 0)
return;
var highestType = damageTypesSorted.First().Key; // We only need 1 of the values
// TODO: Replace with RandomPredicted once the engine PR is merged
var seed = SharedRandomExtensions.HashCodeCombine((int)_timing.CurTick.Value, GetNetEntity(ent).Id);
var rand = new System.Random(seed);
ProtoId<DamageTypePrototype>? spriteState = null;
if (specialCase != null) // Possible special cases like death by an explosion
{
var prototype = _proto.Index(specialCase);
spriteState = specialCase + rand.Next(prototype.NumOfStates);
}
else if (ent.Comp.DamageMap.TryGetValue(highestType, out var spriteAmount))
{
spriteState = highestType + rand.Next(spriteAmount);
}
if (spriteState != null)
_appearance.SetData(ent, GhostVisuals.Damage, ent.Comp.Prefix + spriteState, appearance);
}
}