Files
wwdpublic/Content.Server/_Goobstation/Ghostbar/GhostBarSystem.cs
Skubman f4192fa06e Ghost Bar!!!! (From Goobstation) (#1675)
# Description

Adds the Ghost Bar from Goob LRP. Upon spawn, the character's loadouts
and traits will also be applied as if their job was their Ghost Bar job.

Adjusts the weights for kill objectives, re-enabling the kill objective
and reducing the weight of Teach a Lesson now that there's more things
to do after getting round removed.

Goobstation cherry-picked PRs:
- https://github.com/Goob-Station/Goob-Station/pull/454
- https://github.com/Goob-Station/Goob-Station/pull/464
- https://github.com/Goob-Station/Goob-Station/pull/689 (partially
applied to Ghost bar files only)
- https://github.com/Goob-Station/Goob-Station/pull/963
- https://github.com/Goob-Station/Goob-Station/pull/974
- https://github.com/Goob-Station/Goob-Station/pull/982 (partially
applied to Ghost bar files only)
- https://github.com/Goob-Station/Goob-Station/pull/1288 (partially
applied to Ghost bar files only)

Wizden cherry-picked PRs:
- https://github.com/space-wizards/space-station-14/pull/29103 (for the
foam force rifle that spawns in the Ghost bar)

## Media

**Ghost Bar UI**

![image](https://github.com/user-attachments/assets/e46603b9-1798-4376-8af5-3df518ede76c)

**Ghost Bar In-Game**

![image](https://github.com/user-attachments/assets/14dbdc0a-9d75-487b-994e-1b1eabe7bff3)

Notice how the Ghost Bar character has loadout items in the backpack and
the Skeleton Accent trait.

## Changelog

<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

🆑 Skubman
- add: Ghost Bar! When you die, you can now go to the Ghost Bar to chill
and talk about the round with other ghosts. (by Aidenkrz)
- add: Foam Force rifle to cargo lottery! (by IProduceWidgets)
- add: Re-enabled the Kill objective for traitors.
- tweak: Reduced the chances of traitors getting the "Teach a Lesson"
objective.

---------

Co-authored-by: Aiden <aiden@djkraz.com>
Co-authored-by: Rank #1 Jonestown partygoer <mary@thughunt.ing>
Co-authored-by: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com>
Co-authored-by: Aviu00 <93730715+Aviu00@users.noreply.github.com>
(cherry picked from commit 0b4ceb21cc406cd39b894afe79decf40c2366369)
2025-01-29 20:27:23 +03:00

133 lines
5.1 KiB
C#

using Robust.Server.GameObjects;
using Content.Server.Clothing.Systems; // Einstein Engines
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Server.Players.PlayTimeTracking; // Einstein Engines
using Content.Server.Station.Systems;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Server.Maps;
using Robust.Shared.Random;
using Content.Shared.Ghost;
using Content.Server._Goobstation.Ghostbar.Components;
using Content.Server.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Roles;
using Content.Server.Antag.Components;
using Content.Server.Traits; // Einstein Engines
using Content.Shared.Mindshield.Components;
using Content.Shared.Players;
using Content.Shared.Roles.Jobs; // Einstein Engines - use JobComponent
namespace Content.Server._Goobstation.Ghostbar;
public sealed class GhostBarSystem : EntitySystem
{
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly GameTicker _ticker = default!;
[Dependency] private readonly StationSpawningSystem _spawningSystem = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
// Einstein Engines start
[Dependency] private readonly PlayTimeTrackingManager _playTimeTracking = default!;
[Dependency] private readonly LoadoutSystem _loadout = default!;
[Dependency] private readonly TraitSystem _trait = default!;
// Einstein Engines end
[ValidatePrototypeId<JobPrototype>] // Einstein Engines - validate job prototypes
private static readonly List<ProtoId<JobPrototype>> _jobComponents = new()
{
"Passenger", "Bartender", "Botanist", "Chef", "Janitor"
};
public override void Initialize()
{
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
SubscribeNetworkEvent<GhostBarSpawnEvent>(SpawnPlayer);
SubscribeLocalEvent<GhostBarPlayerComponent, MindRemovedMessage>(OnPlayerGhosted);
}
const string MapPath = "Maps/_Goobstation/Nonstations/ghostbar.yml";
private void OnRoundStart(RoundStartingEvent ev)
{
_mapSystem.CreateMap(out var mapId);
var options = new MapLoadOptions { LoadMap = true };
if (_mapLoader.TryLoad(mapId, MapPath, out _, options))
_mapSystem.SetPaused(mapId, false);
}
public void SpawnPlayer(GhostBarSpawnEvent msg, EntitySessionEventArgs args)
{
var player = args.SenderSession;
if (!_mindSystem.TryGetMind(player, out var mindId, out var mind))
{
Log.Warning($"Failed to find mind for player {player.Name}.");
return;
}
if (!_entityManager.HasComponent<GhostComponent>(player.AttachedEntity))
{
Log.Warning($"User {player.Name} tried to spawn at ghost bar without being a ghost.");
return;
}
var spawnPoints = new List<EntityCoordinates>();
var query = EntityQueryEnumerator<GhostBarSpawnComponent>();
while (query.MoveNext(out var ent, out _))
{
spawnPoints.Add(_entityManager.GetComponent<TransformComponent>(ent).Coordinates);
}
if (spawnPoints.Count == 0)
{
Log.Warning("No spawn points found for ghost bar.");
return;
}
var data = player.ContentData();
if (data == null)
{
Log.Warning($"ContentData was null when trying to spawn {player.Name} in ghost bar.");
return;
}
var randomSpawnPoint = _random.Pick(spawnPoints);
var randomJob = _random.Pick(_jobComponents);
var profile = _ticker.GetPlayerProfile(args.SenderSession);
var mobUid = _spawningSystem.SpawnPlayerMob(randomSpawnPoint, new JobComponent { Prototype = randomJob }, profile, null); // Einstein Engines - pass in JobComponent
// Einstein Engines start - apply loadouts and traits
var playTimes = _playTimeTracking.GetTrackerTimes(player);
var whitelisted = player.ContentData()?.Whitelisted ?? false;
_loadout.ApplyCharacterLoadout(
mobUid, randomJob, profile, playTimes, whitelisted
);
_trait.ApplyTraits(
mobUid, randomJob, profile, playTimes, whitelisted, punishCheater: false
);
// Einstein Engines end - apply loadouts and traits
_entityManager.EnsureComponent<GhostBarPlayerComponent>(mobUid);
_entityManager.EnsureComponent<MindShieldComponent>(mobUid);
_entityManager.EnsureComponent<AntagImmuneComponent>(mobUid);
_entityManager.EnsureComponent<IsDeadICComponent>(mobUid);
if (mind.Objectives.Count == 0)
_mindSystem.WipeMind(player);
mindId = _mindSystem.CreateMind(data.UserId, profile.Name).Owner;
_mindSystem.TransferTo(mindId, mobUid, true);
}
private void OnPlayerGhosted(EntityUid uid, GhostBarPlayerComponent component, MindRemovedMessage args)
{
_entityManager.DeleteEntity(uid);
}
}