fish-station/Content.Server/PAI/PAISystem.cs
Fildrance d38042a0c0
3mo xeno archeology (first phase) (#33370)
* DAG Adjacency Matrix & Tests

* Fix sandbox type errors

* First pass on procgen

* Procgen adjustments

* Networking

* Cruft and god and beauty and analysis console

* convert to data types that dont make me want to kill myself

* starting work on console UI

* drawing nodes n shit

* damn that ui FUCKS

* XAT

* Add a bunch of basic triggers

* Fix trigger gen

* Add node info into the analysis console UI

* Add node unlocking

* more trigger cuz thats pretty cool

* final triggers + incorporate gnostic faith

* some ui changes, mostly

* Fix orphaned procgen segments

* its not random dipshit

* yeah... this one will make pjb happy....

* we call it a day for the UI

* imagine... shared power code...

* extraction WIP but we gotta sidequest momentarily

* oh hey would you look at that its the actual functionality

* distrotrased

* Small departure for randomness.

* ok yep yep indeed that is an effect very cool.

* thanos snap oldcode

* fuck it we ball

* feat: node scanner now displays triggered nodes. Removed unused old artifact systems and related code (most of it). xml-doc and minor fixups.

* refactor: most of preparations, cleanup and groundwork. also segment-related tests

* feature: all basic effects returning

* feat: finished effects lits, created weight lists for struct and handheld artifacts, fixed throw trigger and music ApplyComponent artifact effects not working

* feat: prevent non-first-time-predicted calls in shared artifact effect systems

* fix: remove gun effect from artifact effects - as it interferes with 'activate artefact' action

* fix: foam reagent selection, neat ApplyComponents art effect scenarios, handheld art is RadiationReceiver again

* fix: moved spawn/ pry&throw effect systems back to server part of code - entity duplication bugs were not quite fun

* refactor: fix protos

* refactor: fix linter

* fix: fix old artifact component names in yml

* fix: no more throwing error on artifact spawn with empty XAEFoamComponent.Reagents

* fix: removed old component usage in maps

* fix: remove more deleted components from map

* fix: ContainerContainer is now part of initial artifact entity, it won't be affecting UninitializedSaveTest

* refactor: fix tests, add loc description to toolshed commands

* Changed node scanner to tell the whole story about current artifact state

* refactor: remove excessive get of EntityCoordinates in XAE systems, removed Value access in NodeScannerDisplay

* fix: turned off TriggerInteraction, removed XAESpawn usage and system, EmpSystem now can use EntityCoordinates,

* fix: moved SharedXenoArtifactSystem.CancelUnlockingOnGraphStructureChange into RebuildXenoArtifactMetaData to lessen code coupling

* fix: XenoArtifactEffectJunkSpawn moved invalid rolls declaration

* refactor: set default value for XenoArtifactComponent.EffectsTable for tests

* fix: now explosions XAE can be activated for effect

* refactor: added some usedelay so artifactuse would'nt be spammed

* refactor: artifact-related hints improvements

* fix: artifact no longer spawns fauna into itself

* refactor: xml-doc and minor refactoring

* refactor: xml-doc for Xeno Artifact systems, renaming of questionable XAT systems

* map for playtest, TODO REVERT THIS

* fix: magboots trigger art from a mile

* refactor: bind artifact animation to unlocking state

* feat: radiation dmg now have reference to source (and artifacts won't irradiate themselves)

* fix: random artifact node durability now is rolled for max and not current value

* refactor: gas effects are more rare, hand-held artifact effects are filtered properly now, rad dmg trigger now requires only 20 dmg for activation

* feat: animations and sound effects for artifact force-use and failed finish of unlocking phase

* use only 1 file with art use animation

* refactor: minor artifact dmg triggers tuning

* feat: now nodes that CAN be unlocked are displayed with specific color in console.

* feat: now unlocking stage time is dynamic and it depends on amount of triggers player activated correctly. Failed one stops incrementing

* feat: now non-active unlocked nodes return more points if durability was not wasted

* feat: now puddle/foam effects change description of node

* fix: fix test failure

* refactor: renamed phasing effect, fixed failing test for elkridge

* minor balance changes

* refactor: split rare materials into separate effects

* feat: unlocked nodes without successor wont listen to unlocks, node unlock is not activating node

* fix: removed OnIrradiatedEvent duplicate c-tor

* revert changes of reach for playtest

* revert last row empty line removal on reach.yml

* fix: fix PVS bug, born from attempt to relay event to art nodes that were not synced yet to the client

* fix: fix elkridge for tests (again)

* refactor: xml-doc, more stuff predicted, allocation optimization in XAE/XAT systems

* refactor: naming

* refactor: extract variable refactor for XAEApplyComponentsSystem.OnActivated insides

* fix: duplicate xeno artifact unlocking sound fixed

* feat: CreatePuddle xeno artifact effect now can have min and max borders for chamicals to be drafted, minor XAECreatePuddleSystem refactor

* feat: networking for shared XAE components + xml-doc leftovers

* refactor: more xml-doc, fix XAEApplyComponentsComponent.Components not being serializable but trying to be

* refactor: xml-docs and XAEThrowThingsAroundSystem now uses circle and not box for prying tiles

* refactor: xml-docs, minor refactors

* revert XenoArtifactCommand.ArtifactPrototype being PrototId

* refactor: simplify the way ExtractionResearchLabel works

---------

Co-authored-by: EmoGarbage404 <retron404@gmail.com>
Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
2025-04-15 10:34:53 +10:00

124 lines
4.4 KiB
C#

using Content.Server.Ghost.Roles;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Instruments;
using Content.Server.Kitchen.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.Mind.Components;
using Content.Shared.PAI;
using Content.Shared.Popups;
using Robust.Shared.Random;
using System.Text;
using Content.Shared.Instruments;
using Robust.Shared.Player;
namespace Content.Server.PAI;
public sealed class PAISystem : SharedPAISystem
{
[Dependency] private readonly InstrumentSystem _instrumentSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ToggleableGhostRoleSystem _toggleableGhostRole = default!;
/// <summary>
/// Possible symbols that can be part of a scrambled pai's name.
/// </summary>
private static readonly char[] SYMBOLS = new[] { '#', '~', '-', '@', '&', '^', '%', '$', '*', ' '};
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PAIComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<PAIComponent, MindAddedMessage>(OnMindAdded);
SubscribeLocalEvent<PAIComponent, MindRemovedMessage>(OnMindRemoved);
SubscribeLocalEvent<PAIComponent, BeingMicrowavedEvent>(OnMicrowaved);
}
private void OnUseInHand(EntityUid uid, PAIComponent component, UseInHandEvent args)
{
// Not checking for Handled because ToggleableGhostRoleSystem already marks it as such.
if (!TryComp<MindContainerComponent>(uid, out var mind) || !mind.HasMind)
component.LastUser = args.User;
}
private void OnMindAdded(EntityUid uid, PAIComponent component, MindAddedMessage args)
{
if (component.LastUser == null)
return;
// Ownership tag
var val = Loc.GetString("pai-system-pai-name", ("owner", component.LastUser));
// TODO Identity? People shouldn't dox-themselves by carrying around a PAI.
// But having the pda's name permanently be "old lady's PAI" is weird.
// Changing the PAI's identity in a way that ties it to the owner's identity also seems weird.
// Cause then you could remotely figure out information about the owner's equipped items.
_metaData.SetEntityName(uid, val);
}
private void OnMindRemoved(EntityUid uid, PAIComponent component, MindRemovedMessage args)
{
// Mind was removed, shutdown the PAI.
PAITurningOff(uid);
}
private void OnMicrowaved(EntityUid uid, PAIComponent comp, BeingMicrowavedEvent args)
{
// name will always be scrambled whether it gets bricked or not, this is the reward
ScrambleName(uid, comp);
// randomly brick it
if (_random.Prob(comp.BrickChance))
{
_popup.PopupEntity(Loc.GetString(comp.BrickPopup), uid, PopupType.LargeCaution);
_toggleableGhostRole.Wipe(uid);
RemComp<PAIComponent>(uid);
RemComp<ToggleableGhostRoleComponent>(uid);
}
else
{
// you are lucky...
_popup.PopupEntity(Loc.GetString(comp.ScramblePopup), uid, PopupType.Large);
}
}
private void ScrambleName(EntityUid uid, PAIComponent comp)
{
// create a new random name
var len = _random.Next(6, 18);
var name = new StringBuilder(len);
for (int i = 0; i < len; i++)
{
name.Append(_random.Pick(SYMBOLS));
}
// add 's pAI to the scrambled name
var val = Loc.GetString("pai-system-pai-name-raw", ("name", name.ToString()));
_metaData.SetEntityName(uid, val);
}
public void PAITurningOff(EntityUid uid)
{
// Close the instrument interface if it was open
// before closing
if (HasComp<ActiveInstrumentComponent>(uid))
{
_instrumentSystem.ToggleInstrumentUi(uid, uid);
}
// Stop instrument
if (TryComp<InstrumentComponent>(uid, out var instrument))
_instrumentSystem.Clean(uid, instrument);
if (TryComp(uid, out MetaDataComponent? metadata))
{
var proto = metadata.EntityPrototype;
if (proto != null)
_metaData.SetEntityName(uid, proto.Name);
}
}
}