Files
wwdpublic/Content.Server/Traits/TraitSystem.cs
Spatison 0f88cb6f4f Upstream 12.07-23.07 (#695)
* Make All Jetpacks Go on Suit Storage + Combat First Aid Kit Easier to Find (#2501)

make all jetpacks go on suit storage aswell

Signed-off-by: Ghost581 <85649313+Ghost581X@users.noreply.github.com>
(cherry picked from commit f3e58032028de79a9ede1171ec27b7b0dec6f087)

make combat FAK easier to find

Signed-off-by: Ghost581 <85649313+Ghost581X@users.noreply.github.com>
(cherry picked from commit d989dd1edb40837037e6eded435b66c0764bf1b3)

* Automatic Changelog Update (#2501)

(cherry picked from commit 3179e7d346aadf0735a1262d99db5c84373b4a14)

* Automatic Changelog Update (#2492)

(cherry picked from commit e113f7e9eb8d5b39b3457b9aee93e2a97505e2af)

* PDA Passport Slots (#2499)

# Description

By request from Ghost581 on behalf of Hullrot. I'll let the image speak
for itself. Your passport won't automatically spawn in the PDA, but to
be honest it's a space station 13 tradition that the ID shouldn't spawn
there either, so I don't wanna hear any complaints about it lol.

![image](https://github.com/user-attachments/assets/c22e58ef-3421-460b-a8ad-54ecdfedd3b8)

# Changelog

🆑
- add: Added a PDA slot for storing your character's passport.

Signed-off-by: VMSolidus <evilexecutive@gmail.com>

(cherry picked from commit 016768d5e66b012d17c830c12b75e1cc18f6215a)

* Automatic Changelog Update (#2499)

(cherry picked from commit 9d5ddc78a360a4418f97c472fe55228338947683)

* Fix Traits Anticheat (#2502)

# Description

Traits Anticheat was not accounting for traits having variable slot
occupancy, and was treating the "0 slot traits" as if they always had a
slot cost of 1. This PR corrects this by making it count the actual slot
costs of traits for the purpose of checking for illegal totals.

# Changelog

🆑
- fix: Fixed a bug with Traits Anticheat incorrectly triggering if the
player had selected enough 0 slot traits.

(cherry picked from commit 13eb1351b81f16fe26dc3fa14c9b05a8da600a31)

* Automatic Changelog Update (#2502)

(cherry picked from commit 3620f0ae93dae51ca425ef51802273270993ccae)

* Update Credits (#2504)

Co-authored-by: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
(cherry picked from commit d1611704b5e69e66997e62d728e8a07c61a101b4)

* Fix SpaceWindv5 Wall Smoothing (#2506)

Update AtmosphereSystem.MAS.cs

(cherry picked from commit b4c3450331e4f2b8f4f5aabb6761d6ad13ad369f)

* Automatic Changelog Update (#2506)

(cherry picked from commit b3b26a48554cb528f5f4eb43cffafd8dd2dcbdb4)

* Fix Wizden's Division By Zero Error (#2507)

Update GunComponent.cs

(cherry picked from commit f36d91391b5c5a18c2f95da0ff3c2f1ea52b6914)

* Disable Contraband Examine (#2511)

Who fucking added this?

(cherry picked from commit ce2a85ccc1ca1d146f3ed627c4483d8b3db34d90)

* fix: emergency shuttle docked announcement

(cherry picked from commit 559b37d747e14698c2e4fcf4359f45dee0ad8aea)

* fix: non-functioning mining shuttle

(cherry picked from commit 4fc049036a1a8c6839d9bfc8c35f6a8374d79059)

* Disable shadows for observer pointlight (#36897)

no shadows

(cherry picked from commit b3b6d4731078950d3e3a8b1558ec0ab7d6cbbcb1)
(cherry picked from commit 470ded5b22e7a1a8d4296ba210cd05f5c217f138)

* Fix observer pointlights being broken (#37335)

(cherry picked from commit dfc8934782045106b07ccf1de6ee4e66d4aa4cb2)
(cherry picked from commit 11e0ed317b662f80ca7e4a754e183b18cde3506b)

* Automatic Changelog Update (#2512)

(cherry picked from commit 0cc861ac096ad5005f36528b7c02c8e612f5df37)

---------

Signed-off-by: Ghost581 <85649313+Ghost581X@users.noreply.github.com>
Co-authored-by: Ghost581 <85649313+Ghost581X@users.noreply.github.com>
Co-authored-by: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
2025-07-23 15:29:58 +03:00

179 lines
7.6 KiB
C#

using System.Linq;
using Content.Shared.Administration.Logs;
using Content.Server.Administration.Systems;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Server.Chat.Managers;
using Content.Shared.Customization.Systems;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Server.Players.PlayTimeTracking;
using Content.Shared.Players;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.Traits;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Utility;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Server.Traits;
public sealed class TraitSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!;
[Dependency] private readonly PlayTimeTrackingManager _playTimeTracking = default!;
[Dependency] private readonly IConfigurationManager _configuration = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly AdminSystem _adminSystem = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
SubscribeLocalEvent<LoadProfileExtensionsEvent>(OnProfileLoad);
}
// When the player is spawned in, add all trait components selected during character creation
private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args) =>
ApplyTraits(args.Mob, args.JobId, args.Profile,
_playTimeTracking.GetTrackerTimes(args.Player), args.Player.ContentData()?.Whitelisted ?? false);
private void OnProfileLoad(LoadProfileExtensionsEvent args) =>
ApplyTraits(args.Mob, args.JobId, args.Profile,
_playTimeTracking.GetTrackerTimes(args.Player), args.Player.ContentData()?.Whitelisted ?? false);
/// <summary>
/// Adds the traits selected by a player to an entity.
/// </summary>
public void ApplyTraits(EntityUid uid, ProtoId<JobPrototype>? jobId, HumanoidCharacterProfile profile,
Dictionary<string, TimeSpan> playTimes, bool whitelisted, bool punishCheater = true)
{
var pointsTotal = _configuration.GetCVar(CCVars.GameTraitsDefaultPoints);
var traitSelections = _configuration.GetCVar(CCVars.GameTraitsMax);
if (jobId is not null && !_prototype.TryIndex(jobId, out var jobPrototype)
&& jobPrototype is not null && !jobPrototype.ApplyTraits)
return;
if (_prototype.TryIndex<SpeciesPrototype>(profile.Species, out var speciesProto))
pointsTotal += speciesProto.BonusTraitPoints;
var jobPrototypeToUse = _prototype.Index(jobId ?? _prototype.EnumeratePrototypes<JobPrototype>().First().ID);
var sortedTraits = new List<TraitPrototype>();
foreach (var traitId in profile.TraitPreferences)
{
if (_prototype.TryIndex<TraitPrototype>(traitId, out var traitPrototype))
{
sortedTraits.Add(traitPrototype);
}
else
{
DebugTools.Assert($"No trait found with ID {traitId}!");
return;
}
}
sortedTraits.Sort();
var traitsToAdd = new List<TraitPrototype>();
foreach (var traitPrototype in sortedTraits)
{
if (!traitPrototype.Enable || // WD EDIT
!_characterRequirements.CheckRequirementsValid(
traitPrototype.Requirements,
jobPrototypeToUse,
profile, playTimes, whitelisted, traitPrototype,
EntityManager, _prototype, _configuration,
out _))
continue;
// To check for cheaters. :FaridaBirb.png:
pointsTotal += traitPrototype.Points;
traitSelections -= traitPrototype.Slots;
traitsToAdd.Add(traitPrototype);
}
if (pointsTotal < 0 || traitSelections < 0)
{
_adminLogManager.Add(LogType.AdminMessage, LogImpact.Extreme, $"{ToPrettyString(uid):player} attempted to spawn with illegal trait selection total {profile.TraitPreferences.Count}, and {pointsTotal} net trait points");
if (punishCheater)
PunishCheater(uid);
if (_playerManager.TryGetSessionByEntity(uid, out var targetPlayer))
{
var feedbackMessage = "You have attempted to spawn with an illegal trait list. None of your traits will be applied. If you think this is in error, please return to the lobby and correct your trait selections.";
_chatManager.ChatMessageToOne(
ChatChannel.Emotes,
feedbackMessage,
feedbackMessage,
EntityUid.Invalid,
false,
targetPlayer.Channel);
}
return;
}
foreach (var trait in traitsToAdd)
AddTrait(uid, trait);
}
/// <summary>
/// Adds a single Trait Prototype to an Entity.
/// </summary>
public void AddTrait(EntityUid uid, TraitPrototype traitPrototype)
{
_adminLogManager.Add(LogType.Trait, LogImpact.Low,
$"Trait {traitPrototype.ID} was added to {ToPrettyString(uid)}"); // WWDP ADD
foreach (var function in traitPrototype.Functions)
function.OnPlayerSpawn(uid, _componentFactory, EntityManager, _serialization);
}
/// <summary>
/// On a non-cheating client, it's not possible to save a character with a negative number of traits. This can however
/// trigger incorrectly if a character was saved, and then at a later point in time an admin changes the traits Cvars to reduce the points.
/// Or if the points costs of traits is increased.
/// </summary>
private void PunishCheater(EntityUid uid)
{
if (!_configuration.GetCVar(CCVars.TraitsPunishCheaters)
|| !_playerManager.TryGetSessionByEntity(uid, out var targetPlayer))
return;
// For maximum comedic effect, this is plenty of time for the cheater to get on station and start interacting with people.
var timeToDestroy = _random.NextFloat(120, 360);
Timer.Spawn(TimeSpan.FromSeconds(timeToDestroy), () => VaporizeCheater(targetPlayer));
}
/// <summary>
/// https://www.youtube.com/watch?v=X2QMN0a_TrA
/// </summary>
private void VaporizeCheater (Robust.Shared.Player.ICommonSession targetPlayer)
{
_adminSystem.Erase(targetPlayer.UserId);
var feedbackMessage = $"[font size=24][color=#ff0000]{"You have spawned in with an illegal trait point total. If this was a result of cheats, then your nonexistence is a skill issue. Otherwise, feel free to click 'Return To Lobby', and fix your trait selections."}[/color][/font]";
_chatManager.ChatMessageToOne(
ChatChannel.Emotes,
feedbackMessage,
feedbackMessage,
EntityUid.Invalid,
false,
targetPlayer.Channel);
}
}