Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
f32a40c
заготовка под создание тела для ЦИИ
InoweD Aug 11, 2025
6879b33
добавил вход-выход в оболочку через ПКМ
InoweD Aug 11, 2025
24f9798
добавил вход-выход в оболочку через кнопку действия
InoweD Aug 12, 2025
8c4afa9
подготовил оболочку ии к будущим доработкам
InoweD Aug 13, 2025
b935e23
правки в коде для работоспособности(ПОФИКСИТЬ СМЕНУ РУК)
InoweD Aug 13, 2025
7707bcf
очередные правки тела ИИ
InoweD Aug 13, 2025
e7ede59
Добавление оповещений от оффов + синхронизация с обновой
InoweD Aug 15, 2025
87dd70b
Merge branch 'space-sunrise:master' into cai-body
InoweD Aug 15, 2025
fc07985
Merge branch 'cai-body' of https://github.com/InoweD/lust-station int…
InoweD Aug 15, 2025
c1d2eed
Merge branch 'space-sunrise:master' into cai-body
InoweD Aug 15, 2025
398bf4f
Merge branch 'cai-body' of https://github.com/InoweD/lust-station int…
InoweD Aug 15, 2025
00f4b62
сообщеине при использовании интеликарда для тела
InoweD Aug 15, 2025
db5c273
оповещение при звонке ИИ + начало локализации
InoweD Aug 15, 2025
038a3d4
Темплейт инвентрая и почти готовый AiShell
InoweD Aug 15, 2025
3cddeb3
локализация и оповещения
InoweD Aug 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Content.Server/Holopad/HolopadSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Content.Server.Telephone;
using Content.Shared.Access.Systems;
using Content.Shared.Audio;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Chat.TypingIndicator;
using Content.Shared.Holopad;
using Content.Shared.IdentityManagement;
Expand All @@ -18,6 +19,7 @@
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using System.Linq;
Expand All @@ -38,6 +40,8 @@ public sealed class HolopadSystem : SharedHolopadSystem
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly PvsOverrideSystem _pvs = default!;
// Sunrise-add
private readonly ProtoId<ChatNotificationPrototype> _aiShellHolopadCallChatNotificationPrototype = "AiShellHolopadCall";

private float _updateTimer = 1.0f;
private const float UpdateTime = 1.0f;
Expand Down Expand Up @@ -223,6 +227,15 @@ private void OnHolopadStationAiRequest(Entity<HolopadComponent> entity, ref Holo

reachableAiCores.Add((receiverUid, receiverTelephone));

// Sunrise-start
var shells = EntityQueryEnumerator<StationAiMobileComponent>();
while (shells.MoveNext(out var shell, out _))
{
var ev = new ChatNotificationEvent(_aiShellHolopadCallChatNotificationPrototype, entity);
RaiseLocalEvent(shell, ref ev);
}
// Sunrise-end

if (!_stationAiSystem.TryGetHeld((receiver, receiverStationAiCore), out var insertedAi))
continue;

Expand Down
16 changes: 16 additions & 0 deletions Content.Server/Silicons/StationAi/StationAiSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ private void OnAmmoShot(Entity<StationAiTurretComponent> ent, ref AmmoShotEvent
ev.SourceNameOverride = Loc.GetString("station-ai-turret-component-name", ("name", Name(ent)), ("address", deviceNetwork.Address));

RaiseLocalEvent(ai, ref ev);

// Sunrise-start
var shells = EntityQueryEnumerator<StationAiMobileComponent>();
while (shells.MoveNext(out var shell, out _))
{
RaiseLocalEvent(shell, ref ev);
}
// Sunrise-end
}
}

Expand Down Expand Up @@ -122,6 +130,14 @@ private void AnnounceSnip(EntityUid uid)
ev.SourceNameOverride = tile.ToString();

RaiseLocalEvent(ai, ref ev);

// Sunrise-start
var shells = EntityQueryEnumerator<StationAiMobileComponent>();
while (shells.MoveNext(out var shell, out _))
{
RaiseLocalEvent(shell, ref ev);
}
// Sunrise-end
}
}

Expand Down
268 changes: 268 additions & 0 deletions Content.Server/_Lust/Inowe/AiShellSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
using Content.Shared.Verbs;
using Content.Shared.Mind;
using Content.Shared.Silicons.StationAi;
using Content.Shared._Lust.Inowe;
using Robust.Shared.Map;
using Robust.Shared.Containers;
using Content.Shared.Mind.Components;
using Content.Server.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Mobs;
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Chat.Prototypes;
using Robust.Shared.Prototypes;
using Content.Shared.Damage;
using Content.Shared.Mobs.Components;
using System.Linq;
namespace Content.Server._Lust.Inowe;

public sealed class AiShellSystem : EntitySystem
{
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly ActionsSystem _actions = default!;

private readonly ProtoId<ChatNotificationPrototype> _aiShellDamaged = "AiShellDamaged";
private readonly ProtoId<ChatNotificationPrototype> _aiShellCritical = "AiShellCritical";
private readonly ProtoId<ChatNotificationPrototype> _aiShellNotResponse = "AiShellNotResponse";
private readonly ProtoId<ChatNotificationPrototype> _aiShellResponding = "AiShellResponding";

private bool _transferInProgress;

public override void Initialize()
{
SubscribeLocalEvent<AiShellVerbComponent, GetVerbsEvent<Verb>>(AddCoreVerb);
SubscribeLocalEvent<AiShellComponent, GetVerbsEvent<Verb>>(AddShellVerb);
SubscribeLocalEvent<AiCoreActionsComponent, GoToShellActionEvent>(HandleGoToShell);
SubscribeLocalEvent<AiShellComponent, ReturnToCoreActionEvent>(HandleReturnToCore);
SubscribeLocalEvent<AiShellComponent, MobStateChangedEvent>(OnShellStateChanged);
SubscribeLocalEvent<AiShellComponent, DamageChangedEvent>(OnDamageChanged);
}

private void AddCoreVerb(EntityUid uid, AiShellVerbComponent comp, GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

var core = GetCoreEntity(uid);
var spawn = Transform(core).Coordinates;

if (TryComp<AiCoreActionsComponent>(core, out var coreAi) && coreAi.GoToShellActionId != null)
return;

args.Verbs.Add(new Verb
{
Text = Loc.GetString("activate-body"),
Act = () => EnterOrCreateShell(core, spawn)
});
}

private void AddShellVerb(EntityUid uid, AiShellComponent comp, GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

args.Verbs.Add(new Verb
{
Text = Loc.GetString("return-to-core"),
Act = () => MoveMindToCore(uid, comp.CoreEntity)
});
}

private void HandleGoToShell(EntityUid uid, AiCoreActionsComponent comp, GoToShellActionEvent args)
{
if (args.Handled)
return;

var core = GetCoreEntity(uid);
EnterOrCreateShell(core, Transform(core).Coordinates);
args.Handled = true;
}

private void HandleReturnToCore(EntityUid uid, AiShellComponent comp, ReturnToCoreActionEvent args)
{
if (args.Handled)
return;

MoveMindToCore(uid, comp.CoreEntity);
args.Handled = true;
}

public void EnterOrCreateShell(EntityUid coreEntity, EntityCoordinates spawnCoords)
{
if (_transferInProgress)
return;

try
{
_transferInProgress = true;
var mindId = GetMind(coreEntity);
if (mindId == null)
return;

var shells = EntityManager.EntityQueryEnumerator<AiShellComponent>();
while (shells.MoveNext(out var shellUid, out var comp))
{
if (comp.CoreEntity == coreEntity && !comp.IsTaken)
{
TransferMind(shellUid, mindId.Value);
return;
}
}

var newShell = SpawnShell(coreEntity, spawnCoords);
TransferMind(newShell, mindId.Value);
}
finally
{
_transferInProgress = false;
}
}

public EntityUid SpawnShell(EntityUid coreEntity, EntityCoordinates spawnCoords)
{
var shell = EntityManager.SpawnEntity("AiShell", spawnCoords);
var comp = EnsureComp<AiShellComponent>(shell);
comp.CoreEntity = coreEntity;
comp.IsTaken = false;
Dirty(shell, comp);
return shell;
}

public bool TransferMind(EntityUid shell, EntityUid mindId)
{
if (!TryComp<AiShellComponent>(shell, out var shellComp) || shellComp.IsTaken)
return false;

if (TryComp<MobStateComponent>(shell, out var mobState))
{
if (mobState.CurrentState == MobState.Critical || mobState.CurrentState == MobState.Dead)
{
var ev = new ChatNotificationEvent(_aiShellNotResponse, shell);
RaiseLocalEvent(shellComp.CoreEntity, ref ev);

return false;
}
}

var core = shellComp.CoreEntity;
if (TryComp<AiCoreActionsComponent>(core, out var coreActions) && coreActions.GoToShellActionId is { } goId &&
TryComp<ActionsComponent>(core, out var coreActComp))
{
_actions.RemoveAction((core, coreActComp), goId);
coreActions.GoToShellActionId = null;
}

_mind.TransferTo(mindId, shell);
shellComp.IsTaken = true;
Dirty(shell, shellComp);

var returnAction = _actions.AddAction(shell, "ReturnToCoreAction");
if (returnAction != null)
shellComp.ReturnToCoreActionId = returnAction.Value;

return true;
}

private void MoveMindToCore(EntityUid shell, EntityUid coreEntity)
{
var mindId = GetMind(shell);
if (mindId == null)
return;

var actualCore = GetCoreEntity(coreEntity);
_mind.TransferTo(mindId.Value, actualCore);

if (TryComp<AiShellComponent>(shell, out var sc))
{
sc.IsTaken = false;
Dirty(shell, sc);
}

if (TryComp<AiShellComponent>(shell, out var shellComp) && shellComp.ReturnToCoreActionId is { } returnId &&
TryComp<ActionsComponent>(shell, out var shellActionsComp))
{
_actions.RemoveAction((shell, shellActionsComp), returnId);
shellComp.ReturnToCoreActionId = null;
}

if (!TryComp<AiCoreActionsComponent>(actualCore, out var coreActions))
coreActions = EnsureComp<AiCoreActionsComponent>(actualCore);

if (coreActions.GoToShellActionId == null && TryComp<ActionsComponent>(actualCore, out var coreActComp))
{
var goAction = _actions.AddAction(actualCore, "GoToShellAction");
if (goAction != null)
coreActions.GoToShellActionId = goAction.Value;
}
}

public EntityUid? GetMind(EntityUid entity)
{
var mind = GetMindFromEntity(entity);
if (mind != null)
return mind;

if (TryComp<StationAiCoreComponent>(entity, out var coreComp) && coreComp.RemoteEntity is { } remote)
return GetMindFromEntity(remote);

return null;
}

private EntityUid? GetMindFromEntity(EntityUid entity)
{
if (HasComp<MindContainerComponent>(entity))
{
var m = _mind.GetMind(entity);
if (m != null)
return m.Value;
}

if (TryComp<ContainerManagerComponent>(entity, out var contMan))
{
foreach (var cont in contMan.Containers.Values)
foreach (var ent in cont.ContainedEntities)
if (HasComp<MindContainerComponent>(ent))
{
var mc = _mind.GetMind(ent);
if (mc != null)
return mc.Value;
}
}
return null;
}

private EntityUid GetCoreEntity(EntityUid coreEntity)
{
if (TryComp<StationAiHolderComponent>(coreEntity, out var holder) &&
holder.Slot?.ContainerSlot?.ContainedEntity is EntityUid contained)
return contained;

return coreEntity;
}

private void OnDamageChanged(EntityUid uid, AiShellComponent comp, ref DamageChangedEvent args)
{
if (!args.DamageIncreased)
return;

var ev = new ChatNotificationEvent(_aiShellDamaged, uid);
RaiseLocalEvent(comp.CoreEntity, ref ev);
}

private void OnShellStateChanged(EntityUid uid, AiShellComponent comp, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Critical)
{
MoveMindToCore(uid, comp.CoreEntity);

var ev = new ChatNotificationEvent(_aiShellCritical, uid);
RaiseLocalEvent(comp.CoreEntity, ref ev);
}

if (args.NewMobState == MobState.Alive)
{
var ev = new ChatNotificationEvent(_aiShellResponding, uid);
RaiseLocalEvent(comp.CoreEntity, ref ev);
}
}
}
Loading