diff --git a/Content.Server/Holopad/HolopadSystem.cs b/Content.Server/Holopad/HolopadSystem.cs index 884fb3ae711..73f821a11f9 100644 --- a/Content.Server/Holopad/HolopadSystem.cs +++ b/Content.Server/Holopad/HolopadSystem.cs @@ -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; @@ -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; @@ -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 _aiShellHolopadCallChatNotificationPrototype = "AiShellHolopadCall"; private float _updateTimer = 1.0f; private const float UpdateTime = 1.0f; @@ -223,6 +227,15 @@ private void OnHolopadStationAiRequest(Entity entity, ref Holo reachableAiCores.Add((receiverUid, receiverTelephone)); + // Sunrise-start + var shells = EntityQueryEnumerator(); + 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; diff --git a/Content.Server/Silicons/StationAi/StationAiSystem.cs b/Content.Server/Silicons/StationAi/StationAiSystem.cs index 45b3dda4310..47acd3e75c7 100644 --- a/Content.Server/Silicons/StationAi/StationAiSystem.cs +++ b/Content.Server/Silicons/StationAi/StationAiSystem.cs @@ -77,6 +77,14 @@ private void OnAmmoShot(Entity 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(); + while (shells.MoveNext(out var shell, out _)) + { + RaiseLocalEvent(shell, ref ev); + } + // Sunrise-end } } @@ -122,6 +130,14 @@ private void AnnounceSnip(EntityUid uid) ev.SourceNameOverride = tile.ToString(); RaiseLocalEvent(ai, ref ev); + + // Sunrise-start + var shells = EntityQueryEnumerator(); + while (shells.MoveNext(out var shell, out _)) + { + RaiseLocalEvent(shell, ref ev); + } + // Sunrise-end } } diff --git a/Content.Server/_Lust/Inowe/AiShellSystem.cs b/Content.Server/_Lust/Inowe/AiShellSystem.cs new file mode 100644 index 00000000000..350c3ec0cdf --- /dev/null +++ b/Content.Server/_Lust/Inowe/AiShellSystem.cs @@ -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 _aiShellDamaged = "AiShellDamaged"; + private readonly ProtoId _aiShellCritical = "AiShellCritical"; + private readonly ProtoId _aiShellNotResponse = "AiShellNotResponse"; + private readonly ProtoId _aiShellResponding = "AiShellResponding"; + + private bool _transferInProgress; + + public override void Initialize() + { + SubscribeLocalEvent>(AddCoreVerb); + SubscribeLocalEvent>(AddShellVerb); + SubscribeLocalEvent(HandleGoToShell); + SubscribeLocalEvent(HandleReturnToCore); + SubscribeLocalEvent(OnShellStateChanged); + SubscribeLocalEvent(OnDamageChanged); + } + + private void AddCoreVerb(EntityUid uid, AiShellVerbComponent comp, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + var core = GetCoreEntity(uid); + var spawn = Transform(core).Coordinates; + + if (TryComp(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 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(); + 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(shell); + comp.CoreEntity = coreEntity; + comp.IsTaken = false; + Dirty(shell, comp); + return shell; + } + + public bool TransferMind(EntityUid shell, EntityUid mindId) + { + if (!TryComp(shell, out var shellComp) || shellComp.IsTaken) + return false; + + if (TryComp(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(core, out var coreActions) && coreActions.GoToShellActionId is { } goId && + TryComp(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(shell, out var sc)) + { + sc.IsTaken = false; + Dirty(shell, sc); + } + + if (TryComp(shell, out var shellComp) && shellComp.ReturnToCoreActionId is { } returnId && + TryComp(shell, out var shellActionsComp)) + { + _actions.RemoveAction((shell, shellActionsComp), returnId); + shellComp.ReturnToCoreActionId = null; + } + + if (!TryComp(actualCore, out var coreActions)) + coreActions = EnsureComp(actualCore); + + if (coreActions.GoToShellActionId == null && TryComp(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(entity, out var coreComp) && coreComp.RemoteEntity is { } remote) + return GetMindFromEntity(remote); + + return null; + } + + private EntityUid? GetMindFromEntity(EntityUid entity) + { + if (HasComp(entity)) + { + var m = _mind.GetMind(entity); + if (m != null) + return m.Value; + } + + if (TryComp(entity, out var contMan)) + { + foreach (var cont in contMan.Containers.Values) + foreach (var ent in cont.ContainedEntities) + if (HasComp(ent)) + { + var mc = _mind.GetMind(ent); + if (mc != null) + return mc.Value; + } + } + return null; + } + + private EntityUid GetCoreEntity(EntityUid coreEntity) + { + if (TryComp(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); + } + } +} diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs index 1c9c57dccf7..f021644bbec 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs @@ -101,6 +101,11 @@ public bool TryGetCore(EntityUid entity, out Entity cor private void OnHeldRelay(Entity ent, ref AttemptRelayActionComponentChangeEvent args) { + // Sunrise-start + if (HasComp(ent.Owner)) + return; + // Sunrise-end + if (!TryGetCore(ent.Owner, out var core)) return; @@ -121,9 +126,17 @@ private void OnMessageAttempt(Entity ent, ref Bound if (ev.Actor == ev.Target) return; - if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) && - (!TryComp(ev.Target, out StationAiWhitelistComponent? whitelistComponent) || - !ValidateAi((ev.Actor, aiComp)))) + + // Sunrise-start edit + + //if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) && + // (!TryComp(ev.Target, out StationAiWhitelistComponent? whitelistComponent) || + // !ValidateAi((ev.Actor, aiComp)))) + if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) + && !HasComp(ev.Actor) + && (!TryComp(ev.Target, out StationAiWhitelistComponent? whitelistComponent) + || !ValidateAi((ev.Actor, aiComp)))) + // Sunrise-end edit { // Don't allow the AI to interact with anything that isn't powered. if (!PowerReceiver.IsPowered(ev.Target)) @@ -144,6 +157,11 @@ private void OnMessageAttempt(Entity ent, ref Bound private void OnHeldInteraction(Entity ent, ref InteractionAttemptEvent args) { + // Sunrise-start + if (HasComp(ent.Owner)) + return; + // Sunrise-end + // Cancel if it's not us or something with a whitelist, or whitelist is disabled. args.Cancelled = (!TryComp(args.Target, out StationAiWhitelistComponent? whitelistComponent) || !whitelistComponent.Enabled) @@ -160,13 +178,22 @@ private void OnTargetVerbs(Entity ent, ref GetVerbs if (!_uiSystem.HasUi(args.Target, AiUi.Key)) return; + // Sunrise-start edit if (!args.CanComplexInteract - || !HasComp(args.User) + || (!HasComp(args.User) && !HasComp(args.User)) || !args.CanInteract) { return; } + //if (!args.CanComplexInteract + // || !HasComp(args.User) + // || !args.CanInteract) + //{ + // return; + //} + // Sunrise-end edit + var user = args.User; var target = args.Target; diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs index c23bb02e6f3..ef2a9b4b391 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs @@ -18,6 +18,7 @@ using Content.Shared.Power.EntitySystems; using Content.Shared.StationAi; using Content.Shared.Verbs; +using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -69,6 +70,7 @@ public abstract partial class SharedStationAiSystem : EntitySystem private EntityQuery _broadphaseQuery; private EntityQuery _gridQuery; + [ValidatePrototypeId] private static readonly EntProtoId DefaultAi = "StationAiBrain"; private readonly ProtoId _downloadChatNotificationPrototype = "IntellicardDownload"; @@ -168,8 +170,12 @@ private void OnAiMenu(Entity ent, ref MenuVisibilityE private void OnAiBuiCheck(Entity ent, ref BoundUserInterfaceCheckRangeEvent args) { - if (!HasComp(args.Actor)) + // Sunrise-start edit + if (!HasComp(args.Actor) && !HasComp(args.Actor)) return; + //if (!HasComp(args.Actor)) + // return; + // Sunrise-end edit args.Result = BoundUserInterfaceRangeResult.Fail; @@ -200,6 +206,11 @@ private void OnAiBuiCheck(Entity ent, ref BoundUser private void OnAiInRange(Entity ent, ref InRangeOverrideEvent args) { + // Sunrise-start-edit + if (HasComp(args.User)) + return; + //Sunrise-end-edit + args.Handled = true; // Starlight-surgery start var target = args.Target; @@ -300,6 +311,14 @@ private void OnHolderInteract(Entity ent, ref AfterInt { var ev = new ChatNotificationEvent(_downloadChatNotificationPrototype, args.Used, args.User); RaiseLocalEvent(held, ref ev); + + // Sunrise-start + var shells = EntityQueryEnumerator(); + while (shells.MoveNext(out var shell, out _)) + { + RaiseLocalEvent(shell, ref ev); + } + // Sunrise-end } var doAfterArgs = new DoAfterArgs(EntityManager, args.User, cardHasAi ? intelliComp.UploadTime : intelliComp.DownloadTime, new IntellicardDoAfterEvent(), args.Target, ent.Owner) @@ -537,6 +556,8 @@ private void UpdateAppearance(Entity entity) _appearance.SetData(entity.Owner, StationAiVisualState.Key, state); } + public virtual void AnnounceIntellicardUsage(EntityUid uid, SoundSpecifier? cue = null) { } + public virtual bool SetVisionEnabled(Entity entity, bool enabled, bool announce = false) { if (entity.Comp.Enabled == enabled) diff --git a/Content.Shared/_Lust/Inowe/AiCoreActionsComponent .cs b/Content.Shared/_Lust/Inowe/AiCoreActionsComponent .cs new file mode 100644 index 00000000000..1b4f8268189 --- /dev/null +++ b/Content.Shared/_Lust/Inowe/AiCoreActionsComponent .cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +[RegisterComponent, NetworkedComponent] +public sealed partial class AiCoreActionsComponent : Component +{ + public EntityUid? GoToShellActionId; +} diff --git a/Content.Shared/_Lust/Inowe/AiShellComponent.cs b/Content.Shared/_Lust/Inowe/AiShellComponent.cs new file mode 100644 index 00000000000..b7c6985bcf1 --- /dev/null +++ b/Content.Shared/_Lust/Inowe/AiShellComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +namespace Content.Shared._Lust.Inowe; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class AiShellComponent : Component +{ + [DataField, AutoNetworkedField, ViewVariables] + public EntityUid CoreEntity { get; set; } + + [DataField, AutoNetworkedField, ViewVariables] + public bool IsTaken; + + [DataField, AutoNetworkedField, ViewVariables] + public EntityUid? ReturnToCoreActionId; +} diff --git a/Content.Shared/_Lust/Inowe/AiShellMobileComponent.cs b/Content.Shared/_Lust/Inowe/AiShellMobileComponent.cs new file mode 100644 index 00000000000..445c8431c8c --- /dev/null +++ b/Content.Shared/_Lust/Inowe/AiShellMobileComponent.cs @@ -0,0 +1,5 @@ +using Robust.Shared.GameStates; +namespace Content.Shared.Silicons.StationAi; + +[RegisterComponent, NetworkedComponent] +public sealed partial class StationAiMobileComponent : Component { } diff --git a/Content.Shared/_Lust/Inowe/AiShellVerbComponent .cs b/Content.Shared/_Lust/Inowe/AiShellVerbComponent .cs new file mode 100644 index 00000000000..f9fb4f303d1 --- /dev/null +++ b/Content.Shared/_Lust/Inowe/AiShellVerbComponent .cs @@ -0,0 +1,6 @@ +namespace Content.Shared._Lust.Inowe; + +[RegisterComponent] +public sealed partial class AiShellVerbComponent : Component +{ +} diff --git a/Content.Shared/_Lust/Inowe/GoToShellActionEvent .cs b/Content.Shared/_Lust/Inowe/GoToShellActionEvent .cs new file mode 100644 index 00000000000..c6a154075bf --- /dev/null +++ b/Content.Shared/_Lust/Inowe/GoToShellActionEvent .cs @@ -0,0 +1,5 @@ +using Robust.Shared.GameObjects; +using Content.Shared.Actions; +namespace Content.Shared._Lust.Inowe; + +public sealed partial class GoToShellActionEvent : InstantActionEvent { } diff --git a/Content.Shared/_Lust/Inowe/ReturnToCoreActionEvent.cs b/Content.Shared/_Lust/Inowe/ReturnToCoreActionEvent.cs new file mode 100644 index 00000000000..69673986cb6 --- /dev/null +++ b/Content.Shared/_Lust/Inowe/ReturnToCoreActionEvent.cs @@ -0,0 +1,4 @@ +using Robust.Shared.GameObjects; +using Content.Shared.Actions; +namespace Content.Shared._Lust.Inowe; +public sealed partial class ReturnToCoreActionEvent : InstantActionEvent { } diff --git a/Resources/Locale/en-US/_strings/silicons/station-ai.ftl b/Resources/Locale/en-US/_strings/silicons/station-ai.ftl index 442782f9a13..412e2fa5a9c 100644 --- a/Resources/Locale/en-US/_strings/silicons/station-ai.ftl +++ b/Resources/Locale/en-US/_strings/silicons/station-ai.ftl @@ -44,4 +44,4 @@ station-ai-hologram-female = Female appearance station-ai-hologram-male = Male appearance station-ai-hologram-face = Disembodied head station-ai-hologram-cat = Cat form -station-ai-hologram-dog = Corgi form \ No newline at end of file +station-ai-hologram-dog = Corgi form diff --git a/Resources/Locale/ru-RU/_lust/ai-shell.ftl b/Resources/Locale/ru-RU/_lust/ai-shell.ftl new file mode 100644 index 00000000000..ebbb92eb0c4 --- /dev/null +++ b/Resources/Locale/ru-RU/_lust/ai-shell.ftl @@ -0,0 +1,9 @@ +ai-shell-holopad-call = Попытка соединения с ИИ по голопаду. +ai-consciousness-download-warning = Ваше сознание скачивается. +ai-shell-damaged = Оболочка ИИ была повреждена! +ai-shell-critical = Оболочка ИИ получила критические повреждения! +ai-shell-not-response = Оболочка ИИ не отвечает. +ai-shell-responding = Оболочка ИИ отвечает. +activate-body = Активировать оболочку +return-to-core = Вернуться в ядро +go-to-shell = Перейти в оболочку diff --git a/Resources/Locale/ru-RU/_strings/silicons/station-ai.ftl b/Resources/Locale/ru-RU/_strings/silicons/station-ai.ftl index 5853ad6431f..4c2873cd4ab 100644 --- a/Resources/Locale/ru-RU/_strings/silicons/station-ai.ftl +++ b/Resources/Locale/ru-RU/_strings/silicons/station-ai.ftl @@ -14,4 +14,3 @@ electrify-door-on = Включить перегрузку electrify-door-off = Выключить перегрузку toggle-light = Переключить свет ai-device-not-responding = Устройство не отвечает -ai-consciousness-download-warning = Your consciousness is being downloaded. diff --git a/Resources/Prototypes/Chat/notifications.yml b/Resources/Prototypes/Chat/notifications.yml index c1aee755c68..86aecec2716 100644 --- a/Resources/Prototypes/Chat/notifications.yml +++ b/Resources/Prototypes/Chat/notifications.yml @@ -19,3 +19,43 @@ color: Pink nextDelay: 12 notifyBySource: true + +# Sunrise-add +- type: chatNotification + id: AiShellHolopadCall + message: ai-shell-holopad-call + color: Cyan + sound: /Audio/Misc/notice2.ogg + nextDelay: 8 + +# Sunrise-add +- type: chatNotification + id: AiShellDamaged + message: ai-shell-damaged + color: Orange + sound: /Audio/Misc/notice2.ogg + nextDelay: 1 + +# Sunrise-add +- type: chatNotification + id: AiShellCritical + message: ai-shell-critical + color: Red + sound: /Audio/Misc/notice2.ogg + nextDelay: 1 + +# Sunrise-add +- type: chatNotification + id: AiShellNotResponse + message: ai-shell-not-response + color: Orange + sound: /Audio/Misc/notice2.ogg + nextDelay: 3 + +# Sunrise-add +- type: chatNotification + id: AiShellResponding + message: ai-shell-responding + color: Green + sound: /Audio/Misc/notice2.ogg + nextDelay: 1 diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 43691969346..981ea4a19bc 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -209,6 +209,10 @@ powerLoad: 1000 needsPower: false - type: StationAiCore + # Sunrise-add + - type: AiShellVerb + - type: AiCoreActions + # Sunrise-add - type: StationAiVision - type: InteractionOutline - type: Sprite diff --git a/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-actions.yml b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-actions.yml new file mode 100644 index 00000000000..99aee449b4b --- /dev/null +++ b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-actions.yml @@ -0,0 +1,21 @@ +- type: entity + id: GoToShellAction + parent: BaseAction + name: go-to-shell + components: + - type: InstantAction + icon: + sprite: + path: Interface/Actions/harm.png + event: !type:GoToShellActionEvent + +- type: entity + id: ReturnToCoreAction + parent: BaseAction + name: return-to-core + components: + - type: InstantAction + icon: + sprite: + path: Interface/Actions/harmOff.png + event: !type:ReturnToCoreActionEvent diff --git a/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-inventory-template.yml b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-inventory-template.yml new file mode 100644 index 00000000000..1e6187e9c71 --- /dev/null +++ b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell-inventory-template.yml @@ -0,0 +1,74 @@ +- type: inventoryTemplate + id: ai-shell + slots: + - name: shoes + slotTexture: shoes + slotFlags: FEET + stripTime: 3 + uiWindowPos: 1,0 + strippingWindowPos: 1,3 + displayName: Shoes + - name: jumpsuit + slotTexture: uniform + slotFlags: INNERCLOTHING + stripTime: 6 + uiWindowPos: 0,1 + strippingWindowPos: 0,2 + displayName: Jumpsuit + - name: outerClothing + slotTexture: suit + slotFlags: OUTERCLOTHING + stripTime: 6 + uiWindowPos: 1,1 + strippingWindowPos: 1,2 + displayName: Suit + - name: gloves + slotTexture: gloves + slotFlags: GLOVES + uiWindowPos: 2,1 + strippingWindowPos: 2,0 + displayName: Gloves + - name: neck + slotTexture: neck + slotFlags: NECK + uiWindowPos: 1,2 + strippingWindowPos: 0,1 + displayName: Neck + - name: eyes + slotTexture: glasses + slotFlags: EYES + stripTime: 3 + uiWindowPos: 0,2 + strippingWindowPos: 0,0 + displayName: Eyes + - name: head + slotTexture: head + slotFlags: HEAD + uiWindowPos: 2,2 + strippingWindowPos: 1,0 + displayName: Head + - name: belt + slotTexture: belt + fullTextureName: template_small + slotFlags: BELT + slotGroup: SecondHotbar + stripTime: 6 + uiWindowPos: 3,1 + strippingWindowPos: 1,5 + displayName: Belt + - name: back + slotTexture: back + fullTextureName: template_small + slotFlags: BACK + slotGroup: SecondHotbar + stripTime: 6 + uiWindowPos: 3,0 + strippingWindowPos: 0,5 + displayName: Back + - name: socks + slotTexture: socks + slotFlags: SOCKS + stripTime: 3 + uiWindowPos: 2,0 + strippingWindowPos: 2,3 + displayName: Socks diff --git a/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell.yml b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell.yml new file mode 100644 index 00000000000..3a5df5fffc3 --- /dev/null +++ b/Resources/Prototypes/_Lust/Entities/AiShell/ai-shell.yml @@ -0,0 +1,106 @@ +# доделать и затестить +- type: entity + parent: BaseBorgChassis + id: AiShell + name: AI Shell + description: Temporary mobile shell for the station AI. + components: + - type: AiShell + - type: StationAiMobile + - type: StationAiWhitelist + - type: StationAiVision + range: 11 + - type: StationAiHeld + - type: IgnoreUIRange + - type: Tag + tags: + - StationAi + + - type: BorgChassis + maxModules: 0 + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellHigh + - type: Body + prototype: Human + - type: IntrinsicRadioReceiver + - type: IntrinsicRadioTransmitter + channels: + - Binary + - Common + - Command + - Engineering + - Law + - Medical + - Science + - Security + - Service + - Supply + - type: ActiveRadio + channels: + - Binary + - Common + - Command + - Engineering + - Law + - Medical + - Science + - Security + - Service + - Supply + + - type: ComplexInteraction + - type: Interactions + - type: InteractionPopup + - type: Input + context: "human" + - type: Puller + needsHands: true + - type: Hands + - type: MeleeWeapon + damage: + types: + Blunt: 5 + - type: Actions + - type: HumanoidAppearance + species: Human + - type: DoAfter + - type: Inventory + templateId: ai-shell + - type: Clickable + - type: InteractionOutline + - type: ShowJobIcons + - type: ShowHealthBars + + - type: UserInterface + interfaces: + enum.CrewMonitoringUIKey.Key: + type: CrewMonitoringBoundUserInterface + enum.GeneralStationRecordConsoleKey.Key: + type: GeneralStationRecordConsoleBoundUserInterface + enum.SiliconLawsUiKey.Key: + type: SiliconLawBoundUserInterface + enum.CommunicationsConsoleUiKey.Key: + type: CommunicationsConsoleBoundUserInterface + - type: IntrinsicUI + uis: + enum.CrewMonitoringUIKey.Key: + toggleAction: ActionAGhostShowCrewMonitoring + enum.GeneralStationRecordConsoleKey.Key: + toggleAction: ActionAGhostShowStationRecords + enum.CommunicationsConsoleUiKey.Key: + toggleAction: ActionAGhostShowCommunications + + - type: Access + groups: + - AllAccess + - Silicon + - type: AccessReader + access: [ [ "Command" ], [ "Science" ] ] + - type: Sprite + sprite: Mobs/Species/Human/parts.rsi + noRot: true + layers: + - state: full