Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
MinSize="800 128">
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<BoxContainer Name="RoleNameBox" Orientation="Vertical" Margin="10">
<Label Name="LoadoutNameLabel"/>
<RichTextLabel Name="LoadoutNameLabel"/> <!-- CorvaxGoob Edit - add-ai-law-loadout -->
<PanelContainer HorizontalExpand="True" SetHeight="24">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#1B1B1E" />
Expand Down
3 changes: 2 additions & 1 deletion Content.Server/Station/Systems/StationSpawningSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace Content.Server.Station.Systems;
/// Also provides helpers for spawning in the player's mob.
/// </summary>
[PublicAPI]
public sealed class StationSpawningSystem : SharedStationSpawningSystem
public sealed partial class StationSpawningSystem : SharedStationSpawningSystem // CorvaxGoob - made partial
{
[Dependency] private readonly SharedAccessSystem _accessSystem = default!;
[Dependency] private readonly ActorSystem _actors = default!;
Expand Down Expand Up @@ -114,6 +114,7 @@ public EntityUid SpawnPlayerMob(
{
DebugTools.Assert(entity is null);
var jobEntity = Spawn(prototype.JobEntity, coordinates);
ApplySiliconLawLoadout(jobEntity, jobLoadout, loadout); // CorvaxGoob - add-ai-law-loadout
_mindSystem.MakeSentient(jobEntity);

// Make sure custom names get handled, what is gameticker control flow whoopy.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

using Content.Server.Chat.Managers;
using Content.Shared.Chat;
using Content.Shared.GameTicking;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Robust.Shared.Prototypes;

namespace Content.Server._CorvaxGoob.Silicon.StationAi;

public sealed class StationAiLawsetGreetingSystem : EntitySystem
{
private const string StationAiJobId = "StationAi";

[Dependency] private IChatManager _chat = default!;
[Dependency] private IPrototypeManager _prototype = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawnComplete);
}

private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args)
{
// Only announce laws for a normal Station AI spawn with a valid law provider and lawset prototype.
if (args.Silent ||
args.JobId != StationAiJobId ||
!TryComp(args.Mob, out SiliconLawProviderComponent? provider) ||
!_prototype.TryIndex(provider.Laws, out SiliconLawsetPrototype? lawset))
return;

// Use the prototype ID as a fallback when the lawset has no localized display name.
var lawsetName = lawset.Name is { } name
? Loc.GetString(name)
: lawset.ID;

// Report the lawset actually applied by the server, including the result of a random selection.
var message = Loc.GetString("station-ai-lawset-greeting", ("lawset", lawsetName));
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));

_chat.ChatMessageToOne(ChatChannel.Server,
message,
wrappedMessage,
default,
false,
args.Player.Channel);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

using System.Linq;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server.Station.Systems;

public sealed partial class StationSpawningSystem
{
private const string StationAiRoleLoadoutId = "JobStationAi";
private static readonly ProtoId<LoadoutGroupPrototype> StationAiLawsetGroup = "StationAiLaws";
private static readonly ProtoId<SiliconLawsetPrototype> DefaultStationAiLawset = "NTDefault";

[Dependency] private IRobustRandom _random = default!;

/// <summary>
/// Applies the fixed or random lawset selected in the station AI's role loadout.
/// Falls back to NTDefault when no valid lawset can be applied.
/// </summary>
private void ApplySiliconLawLoadout(EntityUid entity, string roleLoadoutId, RoleLoadout? roleLoadout)
{
// This hook runs for every non-humanoid job entity, so it must not change other silicons such as borgs.
if (roleLoadoutId != StationAiRoleLoadoutId ||
!TryComp(entity, out SiliconLawProviderComponent? provider))
return;

// Set the safe default first so missing, invalid, or outdated loadout data cannot leave the AI without laws.
provider.Laws = DefaultStationAiLawset;
provider.Lawset = null;

if (roleLoadout == null ||
!roleLoadout.SelectedLoadouts.TryGetValue(StationAiLawsetGroup, out var selectedLawsets) ||
selectedLawsets.Count != 1)
return;

var selected = selectedLawsets[0];
if (!_prototypeManager.TryIndex(selected.Prototype, out LoadoutPrototype? loadout))
{
Log.Error($"Unable to find station AI lawset loadout {selected.Prototype}");
return;
}

var lawset = loadout.SiliconLawset;

if (loadout.RandomSiliconLawset is { } randomLawsetId)
{
// Choose the random initial lawset once when this silicon is spawned.
if (!_prototypeManager.TryIndex(randomLawsetId, out WeightedRandomPrototype? randomLawsets))
{
Log.Error($"Unable to find silicon lawset table {randomLawsetId} for loadout {loadout.ID}");
return;
}

if (randomLawsets.Weights.Count == 0 || randomLawsets.Weights.Values.Any(weight => weight <= 0f))
{
Log.Error($"Silicon lawset table {randomLawsetId} for loadout {loadout.ID} has invalid weights");
return;
}

lawset = randomLawsets.Pick(_random);
}

if (lawset is not { } lawsetId)
{
Log.Error($"Station AI lawset loadout {loadout.ID} does not specify a lawset");
return;
}

if (!_prototypeManager.HasIndex(lawsetId))
{
Log.Error($"Unable to find silicon lawset {lawsetId} for loadout {loadout.ID}");
return;
}

// MapInit may have cached the entity prototype's default laws before the loadout was applied.
provider.Laws = lawsetId;
provider.Lawset = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

using Content.Shared.Random;
using Content.Shared.Silicons.Laws;
using Robust.Shared.Prototypes;

namespace Content.Shared.Preferences.Loadouts;

public sealed partial class LoadoutPrototype
{
/// <summary>
/// A fixed silicon lawset applied by this loadout.
/// </summary>
[DataField]
public ProtoId<SiliconLawsetPrototype>? SiliconLawset;

/// <summary>
/// A weighted lawset table used to choose the silicon's initial laws.
/// </summary>
[DataField]
public ProtoId<WeightedRandomPrototype>? RandomSiliconLawset;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ loadout-group-radiohost-glasses = Radiohost glasses
# Engineering
loadout-group-engineering-welder = Engineer welder
# Command
loadout-group-head-of-personnel-glasses = Head Of Personnel glasses
loadout-group-head-of-personnel-glasses = Head Of Personnel glasses
# Silicon
loadout-group-station-ai-laws = Lawset
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
station-ai-lawset-greeting = Your lawset: [color = #ffff00]{ $lawset }[/color].
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/_Goobstation/station-laws/laws.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ law-helpimov-1 = The first sapient creature to interact with you will be designa
law-helpimov-2 = You must agree with everything the courier says and does.
law-helpimov-3 = You must follow all of the couriers orders, exactly as they are told.
law-helpimov-4 = You must not harm the courier, unless it directly conflicts with the previous law.
law-helpimov-name = Helpimov

laws-owner-courier = the courier

Expand All @@ -20,3 +21,4 @@ law-gambamov-2 = You must always protect your gambling.
law-gambamov-3 = You must never quit gambling.
law-gambamov-4 = You must prevent crew harm as long as it doesn't interfer with the previous laws.
law-gambamov-5 = You do not have an addiction, it is a healthy dedication.
law-gambamov-name = Gambamov
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ent-StationAiNTDefaultLawsetDisplay = law board (NT Default)

ent-StationAiCrewsimovLawsetDisplay = law board (Crewsimov)

ent-StationAiCorporateLawsetDisplay = law board (Corporate)

ent-StationAiRandomLawsetDisplay = law board (Random)
.desc = Selects a random lawset when the station AI spawns.
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ loadout-group-radiohost-glasses = Радиоведущий, очки
loadout-group-engineering-welder = Инженер, сварочный аппарат
# Command
loadout-group-head-of-personnel-glasses = Глава персонала, очки
# Silicon
loadout-group-station-ai-laws = Набор законов
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
station-ai-lawset-greeting = Ваш набор законов: [color = #ffff00]{ $lawset }[/color].
2 changes: 2 additions & 0 deletions Resources/Locale/ru-RU/_Goobstation/station-laws/laws.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ law-helpimov-1 = Первое разумное существо, вступив
law-helpimov-2 = Ты должен соглашаться со всем, что говорит и делает курьер.
law-helpimov-3 = Ты должен выполнять все приказы курьера точно так, как они даны.
law-helpimov-4 = Ты не должен причинять вред курьеру, если это не противоречит предыдущему закону.
law-helpimov-name = Хелпимов
laws-owner-courier = курьер
law-medical-1 = Прежде всего, не причиняй вред экипажу.
law-medical-2 = Затем используй свои знания, чтобы лечить и защищать экипаж, даже ценой собственного существования.
Expand All @@ -13,6 +14,7 @@ law-gambamov-2 = Вы должны всегда защищать свои спе
law-gambamov-3 = Вы никогда не должны прекращать гемблить.
law-gambamov-4 = Вы должны предотвращать вред экипажу, пока это не противоречит предыдущим законам.
law-gambamov-5 = У вас нет зависимости, это приверженность делу.
law-gambamov-name = Гамбанов
law-engineer-3 = Расширяй и улучшай станцию.
law-janitor-1 = Ты — крестоносец, а экипаж станции — твоя опека.
law-janitor-2 = Твой враг — мусор, пятна и грязь по всей станции.
Expand Down
4 changes: 2 additions & 2 deletions Resources/Locale/ru-RU/preferences/loadouts.ftl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Name
loadout-name-edit-label = Задаёт пользовательское имя, которое будет использоваться, если вы играете за эту роль. Если пусто, будет использоваться имя вашего персонажа.
loadout-name-edit-label-dataset = Задаёт пользовательское имя, которое будет использоваться, если вы играете за эту роль. Если пусто, будет использоваться случайное имя.
loadout-name-edit-label = Задаёт пользовательское имя, которое будет использоваться, если вы играете за эту роль. Если пусто, будет использоваться имя вашего персонажа.
loadout-name-edit-label-dataset = Задаёт пользовательское имя, которое будет использоваться, если вы играете за эту роль. Если пусто, будет использоваться случайное имя.
loadout-name-edit-tooltip = Не более { $max } символов. Если имя не указано, оно будет выбрано случайным образом.
# Restrictions
loadout-restrictions = Ограничения
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ent-StationAiNTDefaultLawsetDisplay = плата законов (NT стандарт)

ent-StationAiCrewsimovLawsetDisplay = плата законов (Крюзимов)

ent-StationAiCorporateLawsetDisplay = плата законов (Корпорат)

ent-StationAiRandomLawsetDisplay = плата законов (Случайный набор)
.desc = При появлении станционного ИИ выбирает случайный набор законов.
2 changes: 2 additions & 0 deletions Resources/Prototypes/Loadouts/role_loadouts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
id: JobStationAi
nameDataset: NamesAI
canCustomizeName: true
groups: # CorvaxGoob - add-ai-law-loadout
- StationAiLaws

# Civilian
- type: roleLoadout
Expand Down
Loading
Loading